diff --git a/build.gradle b/build.gradle index ee9bc62782..e0bf79aefe 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ import org.gradle.plugins.ide.idea.model.IdeaLanguageLevel +import org.gradle.internal.os.OperatingSystem plugins { id 'java' @@ -9,6 +10,7 @@ plugins { // 模块参数 ext { frVersion = "" + cbbVersion = "" outputPath = "build" ignoreTestFailureSetting = true languageLevelSetting = 1.8 @@ -44,6 +46,9 @@ allprojects { repositories { mavenLocal() + maven { + url 'https://maven.ej-technologies.com/repository' + } } idea { @@ -57,18 +62,18 @@ allprojects { } dependencies { + implementation 'com.fr.essential:fine-essential:' + cbbVersion + implementation 'com.fr.cbb:fine-universal-skeleton:' + cbbVersion + implementation 'com.install4j:install4j-runtime:8.0.4' implementation 'com.fr.third:jxbrowser:6.23' - implementation 'com.fr.third:jxbrowser-mac:6.23' - implementation 'com.fr.third:jxbrowser-win64:6.23' - implementation 'com.fr.third:jxbrowser-v7:7.15' - implementation 'com.fr.third:jxbrowser-mac-v7:7.15' - implementation 'com.fr.third:jxbrowser-win64-v7:7.15' - implementation 'com.fr.third:jxbrowser-swing-v7:7.15' + implementation 'com.fr.third:jxbrowser-v7:7.22' + implementation 'com.fr.third:jxbrowser-swing-v7:7.22' implementation 'com.fr.third.server:servlet-api:3.0' implementation 'org.swingexplorer:swexpl:2.0.1' implementation 'org.swingexplorer:swag:1.0' implementation 'net.java.dev.jna:jna:5.4.0' - implementation 'org.apache.tomcat:tomcat-catalina:8.5.69' + implementation 'org.apache.tomcat:tomcat-catalina:8.5.72' + implementation 'org.apache.tomcat:tomcat-websocket:8.5.72' implementation 'io.socket:socket.io-client:0.7.0' implementation 'com.fr.third:fine-third:' + frVersion implementation 'com.fr.core:fine-core:' + frDevVersion @@ -86,4 +91,16 @@ allprojects { testImplementation 'org.powermock:powermock-api-easymock:1.7.1' testImplementation 'junit:junit:4.12' } + + if (OperatingSystem.current().isMacOsX()) { + dependencies { + implementation 'com.fr.third:jxbrowser-mac:6.23' + implementation 'com.fr.third:jxbrowser-mac-v7:7.22' + } + } else if (OperatingSystem.current().isWindows()) { + dependencies { + implementation 'com.fr.third:jxbrowser-win64:6.23' + implementation 'com.fr.third:jxbrowser-win64-v7:7.22' + } + } } diff --git a/designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java b/designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java new file mode 100644 index 0000000000..c89ad2115a --- /dev/null +++ b/designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java @@ -0,0 +1,24 @@ +package com.fr.base.function; + +import com.fr.log.FineLoggerFactory; + +/** + * 可抛出异常的 Runnable + * + * created by Harrison on 2022/05/24 + **/ +public interface ThrowableRunnable { + + void run() throws T; + + static Runnable toRunnable(ThrowableRunnable runnable) { + + return () -> { + try { + runnable.run(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + }; + } +} diff --git a/designer-base/src/main/java/com/fr/base/function/UITerminator.java b/designer-base/src/main/java/com/fr/base/function/UITerminator.java new file mode 100644 index 0000000000..1f1424936b --- /dev/null +++ b/designer-base/src/main/java/com/fr/base/function/UITerminator.java @@ -0,0 +1,24 @@ +package com.fr.base.function; + +import com.fr.design.utils.DesignUtils; +import com.fr.runtime.FineRuntime; + +/** + * UI 终止动作 + * + * created by Harrison on 2022/07/14 + **/ +public abstract class UITerminator { + + public void run() { + + // 先执行必须的逻辑 + FineRuntime.start(); + DesignUtils.initLookAndFeel(); + + // 在执行核心逻辑 + doRun(); + } + + protected abstract void doRun(); +} 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/common/exception/ThrowableHandler.java b/designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java new file mode 100644 index 0000000000..14d2dcc811 --- /dev/null +++ b/designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java @@ -0,0 +1,12 @@ +package com.fr.common.exception; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/7 + */ +public interface ThrowableHandler { + + boolean process(Throwable e); + +} diff --git a/designer-base/src/main/java/com/fr/design/DesignModelAdapter.java b/designer-base/src/main/java/com/fr/design/DesignModelAdapter.java index 3eb3b78579..bd4130a853 100644 --- a/designer-base/src/main/java/com/fr/design/DesignModelAdapter.java +++ b/designer-base/src/main/java/com/fr/design/DesignModelAdapter.java @@ -4,6 +4,7 @@ import com.fr.base.Parameter; import com.fr.base.ParameterConfig; import com.fr.base.TableData; import com.fr.base.io.BaseBook; +import com.fr.base.param.ParameterSource; import com.fr.data.TableDataSource; import com.fr.data.operator.DataOperator; import com.fr.design.file.HistoryTemplateListCache; @@ -19,8 +20,8 @@ import com.fr.stable.Filter; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; import com.fr.stable.js.WidgetName; - import com.fr.util.ParameterApplyHelper; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -275,22 +276,28 @@ public abstract class DesignModelAdapter map, Filter filter) { Iterator it = this.getBook().getTableDataNameIterator(); + List names = new ArrayList<>(); try { - // 清空下缓存 - tableDataParametersMap.clear(); + List tableDatas = new ArrayList<>(); while (it.hasNext()) { String name = it.next(); TableData tableData = this.getBook().getTableData(name); - ParameterProvider[] parameterProviders = DataOperator.getInstance().getTableDataParameters(tableData); + tableDatas.add(tableData); + names.add(name); + } + ParameterProvider[][] totalParameterProviders = DataOperator.getInstance().getTotalTableDataParameters(tableDatas); + tableDataParametersMap.clear(); + for (int i = 0; i < totalParameterProviders.length; i++) { + ParameterProvider[] parameterProviders = totalParameterProviders[i]; if (filter != null) { - ParameterApplyHelper.addPara2Map(map, parameterProviders, filter); + ParameterApplyHelper.addPara2Map(map, parameterProviders, filter, null, ParameterSource.DEFAULT_SOURCE); } else { - ParameterApplyHelper.addPara2Map(map, parameterProviders); + ParameterApplyHelper.addPara2Map(map, parameterProviders, null, ParameterSource.TEMPLATE_SOURCE); } - tableDataParametersMap.put(name, parameterProviders); + tableDataParametersMap.put(names.get(i), parameterProviders); } } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineLoggerFactory.getLogger().error(e, e.getMessage()); } } @@ -353,9 +360,9 @@ public abstract class DesignModelAdapter map, ParameterProvider[] parameterProviders, Filter filter) { if (filter != null) { - ParameterApplyHelper.addPara2Map(map, parameterProviders, filter); + ParameterApplyHelper.addPara2Map(map, parameterProviders, filter, null, ParameterSource.DEFAULT_SOURCE); } else { - ParameterApplyHelper.addPara2Map(map, parameterProviders); + ParameterApplyHelper.addPara2Map(map, parameterProviders, null, ParameterSource.DEFAULT_SOURCE); } } @@ -378,7 +385,7 @@ public abstract class DesignModelAdapter map) { // 添加全局参数 Parameter[] glbParas = ParameterConfig.getInstance().getGlobalParameters(); - ParameterApplyHelper.addPara2Map(map, glbParas); + ParameterApplyHelper.addPara2Map(map, glbParas, null, ParameterSource.GLOBAL_SOURCE); } diff --git a/designer-base/src/main/java/com/fr/design/DesignerCloudURLManager.java b/designer-base/src/main/java/com/fr/design/DesignerCloudURLManager.java new file mode 100644 index 0000000000..240733a72c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/DesignerCloudURLManager.java @@ -0,0 +1,193 @@ +package com.fr.design; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.general.CloudCenter; +import com.fr.general.CloudCenterConfig; +import com.fr.general.http.HttpToolbox; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ProductConstants; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLReaderHelper; +import com.fr.stable.xml.XMLTools; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; +import com.fr.third.javax.xml.stream.XMLStreamException; +import com.fr.third.org.apache.commons.io.FileUtils; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by kerry on 2021/10/22 + */ +public class DesignerCloudURLManager implements XMLable { + private static final String CLOUD_URL_INFO = "cloudUrl.info"; + private static final String ROOT_XML_TAG = "CloudUrlInfoList"; + private static final String CHILD_XML_TAG = "CloudUrlInfo"; + private final Map urlMap = new HashMap<>(); + + public static DesignerCloudURLManager getInstance() { + return DesignerCloudURLManager.HOLDER.singleton; + } + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(new NamedThreadFactory("TestCloudConnectThread")); + + private volatile boolean testResult; + + + private static class HOLDER { + private static final DesignerCloudURLManager singleton = new DesignerCloudURLManager(); + } + + private DesignerCloudURLManager() { + loadURLXMLFile(); + } + + public String acquireUrlByKind(String key) { + String url = urlMap.getOrDefault(key, StringUtils.EMPTY); + if (StringUtils.isEmpty(url)) { + //本地缓存中为空时,直接从云中心获取,获取完成后异步更新本地缓存文件 + String latestUrl = CloudCenter.getInstance().acquireConf(key, StringUtils.EMPTY); + executorService.submit(() -> { + updateURLXMLFile(key, latestUrl); + }); + return latestUrl; + } + //本地缓存不为空时,直接返回对应 url,同时异步更新 + executorService.submit(() -> { + String latestUrl = CloudCenter.getInstance().acquireConf(key, StringUtils.EMPTY); + updateURLXMLFile(key, latestUrl); + }); + return url; + } + + private synchronized void updateURLXMLFile(String key, String url) { + if (StringUtils.isNotEmpty(url) && (!urlMap.containsKey(key) || !url.equals(urlMap.get(key)))) { + urlMap.put(key, url); + saveURLXMLFile(); + } + } + + + public void testConnect() { + executorService.submit(() -> { + testResult = isOnline(); + }); + } + + public boolean isConnected() { + return testResult; + } + + public boolean isOnline() { + if (CloudCenterConfig.getInstance().isOnline()) { + String ping = acquireUrlByKind("ping"); + if (StringUtils.isNotEmpty(ping)) { + try { + return StringUtils.isEmpty(HttpToolbox.get(ping)); + } catch (Exception ignore) { + } + } + } + return false; + } + + + /** + * 加载本地 url 管理文件 + */ + private void loadURLXMLFile() { + if (!getInfoFile().exists()) { + return; + } + XMLableReader reader = null; + try (InputStream in = new FileInputStream(getInfoFile())) { + // XMLableReader 还是应该考虑实现 Closable 接口的,这样就能使用 try-with 语句了 + reader = XMLReaderHelper.createXMLableReader(in, XMLPrintWriter.XML_ENCODER); + if (reader == null) { + return; + } + reader.readXMLObject(this); + } catch (FileNotFoundException e) { + // do nothing + } catch (XMLStreamException | IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (XMLStreamException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + + private File getInfoFile() { + + File file = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), CLOUD_URL_INFO)); + try { + if (!file.exists()) { + file.createNewFile(); + } + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + return file; + } + + /** + * 保存到本地 URL 管理文件中,存放在 .Finereport110 中 + */ + void saveURLXMLFile() { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + XMLTools.writeOutputStreamXML(this, out); + out.flush(); + out.close(); + String fileContent = new String(out.toByteArray(), StandardCharsets.UTF_8); + FileUtils.writeStringToFile(getInfoFile(), fileContent, StandardCharsets.UTF_8); + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage()); + } + } + + + @Override + public void readXML(XMLableReader reader) { + String tagName = reader.getTagName(); + if (tagName.equals(CHILD_XML_TAG)) { + String key = reader.getAttrAsString("key", StringUtils.EMPTY); + String value = reader.getAttrAsString("url", StringUtils.EMPTY); + this.urlMap.put(key, value); + } + } + + @Override + public void writeXML(XMLPrintWriter xmlPrintWriter) { + xmlPrintWriter.startTAG(ROOT_XML_TAG); + Iterator> iterable = urlMap.entrySet().iterator(); + while (iterable.hasNext()) { + Map.Entry entry = iterable.next(); + xmlPrintWriter.startTAG(CHILD_XML_TAG).attr("key", entry.getKey()).attr("url", entry.getValue()).end(); + } + xmlPrintWriter.end(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java index f00e1a8558..199834fb77 100644 --- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java +++ b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java @@ -4,8 +4,11 @@ package com.fr.design; import com.fr.base.BaseXMLUtils; +import com.fr.base.OptimizeUtil; import com.fr.base.Utils; +import com.fr.collections.api.Callback; import com.fr.design.actions.help.alphafine.AlphaFineConfigManager; +import com.fr.design.carton.SwitchForSwingChecker; import com.fr.design.constants.UIConstants; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.ErrorDialog; @@ -19,14 +22,18 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.locale.impl.ProductImproveMark; import com.fr.design.login.DesignerLoginType; import com.fr.design.login.config.DesignerLoginConfigManager; +import com.fr.design.mainframe.ComponentReuseNotifyUtil; import com.fr.design.mainframe.reuse.ComponentReuseNotificationInfo; +import com.fr.design.mainframe.simple.SimpleDesignerConfig; import com.fr.design.mainframe.vcs.VcsConfigManager; import com.fr.design.notification.SnapChatConfig; +import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.port.DesignerPortContext; import com.fr.design.style.color.ColorSelectConfigManager; import com.fr.design.update.push.DesignerPushUpdateConfigManager; import com.fr.design.utils.DesignUtils; import com.fr.design.utils.DesignerPort; +import com.fr.env.detect.base.EnvDetectorConfig; import com.fr.exit.DesignerExiter; import com.fr.file.FILEFactory; import com.fr.general.ComparatorUtils; @@ -36,6 +43,12 @@ import com.fr.general.SupportLocale; import com.fr.general.locale.LocaleCenter; import com.fr.general.locale.LocaleMark; import com.fr.general.xml.GeneralXMLTools; +import com.fr.general.xml.async.AsyncXmlElement; +import com.fr.general.xml.async.AsyncXmlReadable; +import com.fr.general.xml.async.SimpleXmlElement; +import com.fr.general.xml.async.XmlElement; +import com.fr.general.xml.async.XmlException; +import com.fr.general.xml.async.XmlInitialFactory; import com.fr.log.FineLoggerFactory; import com.fr.log.LogHandler; import com.fr.stable.CommonUtils; @@ -52,7 +65,11 @@ import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLTools; import com.fr.stable.xml.XMLWriter; import com.fr.stable.xml.XMLableReader; -import com.fr.third.apache.log4j.FileAppender; +import com.fr.start.common.DesignerStartupConfig; +import com.fr.start.common.DesignerStartupPool; +import com.fr.third.apache.logging.log4j.core.appender.FileAppender; +import com.fr.third.apache.logging.log4j.core.layout.PatternLayout; +import com.fr.third.org.apache.commons.io.FileUtils; import com.fr.third.org.apache.commons.io.FilenameUtils; import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContextCallback; @@ -79,37 +96,50 @@ import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; /** * The manager of Designer GUI. + * 下面的作者日期都是随手写的,具体作者已经无法考究。 + * + * @author anonymous + * @version 11.0 + * created by anonymous on 2002/11/08 */ -public class DesignerEnvManager implements XMLReadable, XMLWriter { - +public class DesignerEnvManager implements XMLReadable, XMLWriter, AsyncXmlReadable { + private static final int MAX_SHOW_NUM = 10; private static final String VERSION_80 = "80"; private static final String VERSION_90 = "90"; private static final String VERSION100 = "100"; private static final int CACHINGTEMPLATE_LIMIT = 5; private static final String WEB_NAME = "webapps"; + public static final int LAYOUT_TEMPLATE_SIMPLE_STYLE = 0; + public static final int LAYOUT_TEMPLATE_REAL_STYLE = 1; /** * 指定默认工作空间 */ public static final String DEFAULT_WORKSPACE_PATH = "fr.designer.workspace.default"; - + + public static final String LAST_EAST_REGION_LAYOUT = "LastEastRegionLayout"; + public static final String LAST_WEST_REGION_LAYOUT = "LastWestRegionLayout"; + private static DesignerEnvManager designerEnvManager; // gui. private String activationKey = null; private String logLocation = null; private Rectangle windowBounds = null; // window bounds. private String DialogCurrentDirectory = null; private String CurrentDirectoryPrefix = null; + private Map> recentOpenedFileListMap = new HashMap<>(); private List tempRecentOpenedFilePathList = new ArrayList(); + private XmlElement>> recentOpenedMapping = SimpleXmlElement.of(recentOpenedFileListMap); + private boolean showPaintToolBar = true; private int maxNumberOrPreviewRow = 200; - // name和Env的键值对 - private Map nameEnvMap = new ListMap<>(); - // marks: 当前报表服务器名字 - private String curEnvName = null; + + private XmlElement envConfig = SimpleXmlElement.of(new EnvConfiguration()); + private boolean showProjectPane = true; private boolean showDataPane = true; //p:这是当前选择的数据库连接的名字,这个在新建数据源的时候用到. @@ -163,10 +193,16 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private boolean embedServerLazyStartup = false; //最近使用的颜色 private ColorSelectConfigManager configManager = new ColorSelectConfigManager(); + + /** + * 环境检测配置 + */ + private EnvDetectorConfig envDetectorConfig = EnvDetectorConfig.getInstance(); + /** * alphafine */ - private AlphaFineConfigManager alphaFineConfigManager = AlphaFineConfigManager.getInstance(); + private XmlElement alphaFineConfigManager = SimpleXmlElement.of(AlphaFineConfigManager.getInstance()); /** * 阅后即焚的配置项 @@ -176,7 +212,11 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private DesignerPushUpdateConfigManager designerPushUpdateConfigManager = DesignerPushUpdateConfigManager.getInstance(); private VcsConfigManager vcsConfigManager = VcsConfigManager.getInstance(); + + private DesignerStartupConfig designerStartupConfig = DesignerStartupConfig.getInstance(); + private SwitchForSwingChecker switchForSwingChecker = SwitchForSwingChecker.getInstance(); + public static final String CAS_CERTIFICATE_PATH = "certificatePath"; public static final String CAS_CERTIFICATE_PASSWORD = "certificatePass"; @@ -205,6 +245,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private boolean showTemplateMissingPlugin = true; + private int layoutTemplateStyle = LAYOUT_TEMPLATE_SIMPLE_STYLE; + + private boolean useOptimizedUPM4Adapter; + + private boolean propertiesUsable; + + private XmlElement fvsDesignerConfig = SimpleXmlElement.of(SimpleDesignerConfig.getInstance("FvsDesignerConfig")); + /** * DesignerEnvManager. */ @@ -217,13 +265,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { designerEnvManager = new DesignerEnvManager(); //REPORT-15332有一个国际化调用比较早,需要在这边就设置好locale,由于后台GeneralContext默认是China GeneralContext.setLocale(designerEnvManager.getLanguage()); - try { - XMLTools.readFileXML(designerEnvManager, designerEnvManager.getDesignerEnvFile()); - } catch (FileNotFoundException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - XmlHandler.Self.handle(e); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + + if (!asyncInitEnvManager()) { + // 如果异步读取失败, 则恢复原来的逻辑 + compatibleInitEnvManager(); } // james:如果没有env定义,要设置一个默认的 @@ -240,13 +285,47 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { return designerEnvManager; } + + private static void compatibleInitEnvManager() { + + try { + XMLTools.readFileXML(designerEnvManager, designerEnvManager.getDesignerEnvFile()); + } catch (FileNotFoundException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + XmlHandler.Self.handle(e); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + /** + * 异步初始化环境管理, 提供配置, 帮助处理预期外的问题 + * 1-当优化开启时,才走异步逻辑 + * 2-如果异步执行中出错,则返回异常 false, 否则返回 true + * + * @return 是/否 + */ + private static boolean asyncInitEnvManager() { + + AtomicBoolean noEx = new AtomicBoolean(false); + OptimizeUtil.open(DesignerEnvManager.class.getSimpleName().toLowerCase(), OptimizeUtil.Module.COMMON, () -> { + try { + designerEnvManager.initElements(designerEnvManager.getDesignerEnvFile()); + noEx.set(true); + } catch (Throwable retryEx) { + FineLoggerFactory.getLogger().debug("try async init DesignerEnvManager failed", retryEx); + } + }); + return noEx.get(); + } public ColorSelectConfigManager getColorConfigManager() { return this.configManager; } public static void checkNameEnvMap() { - if (designerEnvManager == null || designerEnvManager.nameEnvMap.size() > 0) { + + if (designerEnvManager == null || designerEnvManager.getNameEnvMap().size() > 0) { return; } String installHome = StableUtils.getInstallHome(); @@ -319,18 +398,18 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { if (!new File(fileName).exists()) { StableUtils.makesureFileExist(new File(fileName)); } - LogHandler handler = new LogHandler() { - final FileAppender appender = new FileAppender( - new com.fr.third.apache.log4j.PatternLayout("%d{HH:mm:ss} %t %p [%c] %m%n"), - fileName - ); + LogHandler handler = new LogHandler() { + final FileAppender appender = FileAppender.newBuilder(). + setName(FileAppender.class.getSimpleName()). + setLayout(PatternLayout.newBuilder().withPattern("%d{HH:mm:ss} %t %p [%c] %m%n").build()). + withFileName(fileName).build(); @Override public FileAppender getHandler() { return appender; } }; - + handler.getHandler().start(); FineLoggerFactory.getLogger().addLogAppender(handler); } catch (SecurityException e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); @@ -411,15 +490,21 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private void compatibilityPrevVersion(File prevEnvFile) { try { XMLTools.readFileXML(designerEnvManager, prevEnvFile); + clearOldVersionDesignerEnvProperties(); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } // 清空前一个版本中的工作目录和最近打开 - nameEnvMap = new ListMap(); - curEnvName = null; + getEnvConfig().setNameEnvMap(new ListMap<>()); + getEnvConfig().setCurEnvName(null); designerEnvManager.saveXMLFile(); } + private void clearOldVersionDesignerEnvProperties() { + SnapChatConfig snapChatConfig = designerEnvManager.getSnapChatConfig(); + snapChatConfig.resetRead(ComponentReuseNotifyUtil.COMPONENT_SNAP_CHAT_KEY); + } + public static void setEnvFile(File envFile) { DesignerEnvManager.envFile = envFile; } @@ -427,12 +512,35 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private static File envFile = null; private File getEnvFile() { + checkDebugStart(); if (envFile == null) { envFile = new File(ProductConstants.getEnvHome() + File.separator + ProductConstants.APP_NAME + "Env.xml"); } return envFile; } + /** + * 在VM options里加入-Ddebug=true激活 + */ + private static void checkDebugStart() { + + if (ComparatorUtils.equals("true", System.getProperty("debug"))) { + setDebugEnv(); + } + } + + /** + * 端口改一下,环境配置文件改一下。便于启动两个设计器,进行对比调试 + */ + private static void setDebugEnv() { + + DesignUtils.setPort(DesignerPort.getInstance().getDebugMessagePort()); + DesignerEnvManager.setEnvFile(new File(StableUtils.pathJoin( + ProductConstants.getEnvHome(), + ProductConstants.APP_NAME + "Env_debug.xml" + ))); + } + /** * 是否启用了https * @@ -550,7 +658,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { String installHome = StableUtils.getInstallHome(); String defaultenvPath = getDefaultenvPath(installHome); defaultenvPath = new File(defaultenvPath).getPath(); - Iterator> entryIt = nameEnvMap.entrySet().iterator(); + Iterator> entryIt = getNameEnvMap().entrySet().iterator(); while (entryIt.hasNext()) { Entry entry = entryIt.next(); DesignerWorkspaceInfo env = entry.getValue(); @@ -571,8 +679,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { String installHome = StableUtils.getInstallHome(); String defaultenvPath = getDefaultenvPath(installHome); defaultenvPath = new File(defaultenvPath).getPath(); - if (nameEnvMap.size() >= 0) { - Iterator> entryIt = nameEnvMap.entrySet().iterator(); + if (getNameEnvMap().size() >= 0) { + Iterator> entryIt = getNameEnvMap().entrySet().iterator(); while (entryIt.hasNext()) { Entry entry = entryIt.next(); DesignerWorkspaceInfo env = entry.getValue(); @@ -653,6 +761,22 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.showTemplateMissingPlugin = showTemplateMissingPlugin; } + public boolean isUseOptimizedUPM4Adapter() { + return useOptimizedUPM4Adapter; + } + + public void setUseOptimizedUPM4Adapter(boolean useOptimizedUPM4Adapter) { + this.useOptimizedUPM4Adapter = useOptimizedUPM4Adapter; + } + + public boolean isPropertiesUsable() { + return this.propertiesUsable; + } + + public void setPropertiesUsable(boolean propertiesUsable) { + this.propertiesUsable = propertiesUsable; + } + /** * 知否自动备份 * @@ -774,6 +898,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { designerPushUpdateConfigManager.setAutoPushUpdateEnabled(autoPushUpdateEnabled); } + public boolean isCloudAnalyticsDelay() { + return designerPushUpdateConfigManager.isCloudAnalyticsDelay(); + } + + public void setCloudAnalyticsDelay(boolean cloudAnalyticsDelay) { + designerPushUpdateConfigManager.setCloudAnalyticsDelay(cloudAnalyticsDelay); + } + /** * 设计器登录相关配置 */ @@ -881,6 +1013,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { designerLoginConfigManager.setPluginRemindOnFirstLaunch(pluginRemindOnFirstLaunch); } + public boolean isUseOldVersionLogin() { + return designerLoginConfigManager.isUseOldVersionLogin(); + } + + public void setUseOldVersionLogin(boolean useOldVersionLogin) { + designerLoginConfigManager.setUseOldVersionLogin(useOldVersionLogin); + } + /** * 内置服务器是否使用时启动 * @@ -921,19 +1061,31 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { public void setLanguage(Locale locale) { this.language = locale; } + + public boolean isStartupPageEnabled() { + return this.designerStartupConfig.isEnabled(); + } + + public void setStartupPageEnabled(boolean enabled) { + this.designerStartupConfig.setEnabled(enabled); + } + + public SimpleDesignerConfig getFvsDesignerConfig() { + return fvsDesignerConfig.getValue(); + } /** * 返回环境名称迭代器 */ public Iterator getEnvNameIterator() { - return this.nameEnvMap.keySet().iterator(); + return this.getNameEnvMap().keySet().iterator(); } /** * 根据名称返回环境 */ public DesignerWorkspaceInfo getWorkspaceInfo(String name) { - return this.nameEnvMap.get(name); + return this.getNameEnvMap().get(name); } /** @@ -944,7 +1096,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { */ public void putEnv(String name, DesignerWorkspaceInfo info) { - this.nameEnvMap.put(name, info); + this.getNameEnvMap().put(name, info); } /** @@ -953,14 +1105,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { * @param name 环境的名字 */ public void removeEnv(String name) { - this.nameEnvMap.remove(name); + this.getNameEnvMap().remove(name); } /** * 清除全部环境 */ public void clearAllEnv() { - this.nameEnvMap.clear(); + this.getNameEnvMap().clear(); } /** @@ -982,14 +1134,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { * 返回当前环境的名称. */ public String getCurEnvName() { - return this.curEnvName; + return getEnvConfig().getCurEnvName(); } /** * 设置当前环境的名称 */ public void setCurEnvName(String envName) { - this.curEnvName = envName; + getEnvConfig().setCurEnvName(envName); } /** @@ -1040,23 +1192,26 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { public void setCurrentDirectoryPrefix(String prefix) { this.CurrentDirectoryPrefix = prefix; } - - - /** - * 返回最近打开的文件路径列表 - */ - public List getRecentOpenedFilePathList() { - - if (StringUtils.isEmpty(getCurEnvName())) { + + public List getRecentOpenedFilePathList4Env(String envName) { + + if (StringUtils.isEmpty(envName)) { return tempRecentOpenedFilePathList; } else { - if (!recentOpenedFileListMap.containsKey(getCurEnvName())) { - recentOpenedFileListMap.put(getCurEnvName(), tempRecentOpenedFilePathList); + if (!recentOpenedMapping.getValue().containsKey(envName)) { + recentOpenedMapping.getValue().put(envName, tempRecentOpenedFilePathList); } } + + return recentOpenedMapping.getValue().get(envName); + } - - return recentOpenedFileListMap.get(getCurEnvName()); + /** + * 返回最近打开的文件路径列表 + */ + public List getRecentOpenedFilePathList() { + + return this.getRecentOpenedFilePathList4Env(getCurEnvName()); } /** @@ -1652,11 +1807,11 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } public AlphaFineConfigManager getAlphaFineConfigManager() { - return alphaFineConfigManager; + return alphaFineConfigManager.getValue(); } public void setAlphaFineConfigManager(AlphaFineConfigManager alphaFineConfigManager) { - this.alphaFineConfigManager = alphaFineConfigManager; + this.alphaFineConfigManager.setValue(alphaFineConfigManager); } public boolean isImageCompress() { @@ -1691,6 +1846,108 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.openDebug = openDebug; } + public int getLayoutTemplateStyle() { + return layoutTemplateStyle; + } + + public void setLayoutTemplateStyle(int layoutTemplateStyle) { + this.layoutTemplateStyle = layoutTemplateStyle; + } + + @Override + public void initElements(File xmlFile) throws XmlException { + + try { + backupOldXmlFile(); + XmlInitialFactory xmlInitialFactory = XmlInitialFactory.create(xmlFile); + xmlInitialFactory + .init("XMLVersion", DesignerEnvManager.this::readXMLVersion) + .init("Attributes", DesignerEnvManager.this::readAttributes) + .init("ReportPaneAttributions", DesignerEnvManager.this::readReportPaneAttributions) + .init("RecentOpenedFilePath", (e) -> { + this.recentOpenedMapping = AsyncXmlElement.of(DesignerStartupPool.common(), () -> { + DesignerEnvManager.this.readRecentOpenFileList0(e); + return recentOpenedFileListMap; + }).callback(new Callback>>() { + @Override + public void exec(Map> stringListMap) { + checkRecentOpenedFileNum(); + } + }); + }) + .init("EnvConfigMap", (e) -> { + + final EnvConfiguration previousConfig = this.envConfig.getValue(); + this.envConfig = AsyncXmlElement.of(DesignerStartupPool.common(), () -> { + DesignerEnvManager.this.readEnvConfigMap(e, previousConfig); + return previousConfig; + }); + }) + .init("LogLocation", DesignerEnvManager.this::readLogLocation) + .init("Language", DesignerEnvManager.this::readLanguage) + .init("JettyServerPort", DesignerEnvManager.this::readJettyPort) + .init("PLengthUnit", DesignerEnvManager.this::readPageLengthUnit) + .init("RLengthUnit", DesignerEnvManager.this::readReportLengthUnit) + .init("LastOpenFilePath", DesignerEnvManager.this::readLastOpenFile) + .init("EncryptionKey", DesignerEnvManager.this::readEncrytionKey) + .init("jdkHome", (e) -> this.jdkHome = e.getElementValue()) + .init("lastBBSTime", DesignerEnvManager.this::readLastBBSTime) + .init("lastBBSNewsTime", DesignerEnvManager.this::readLastBBSNewsTime) + .init("ActivationKey", DesignerEnvManager.this::readActiveKey) + .init("status", DesignerEnvManager.this::readActiveStatus) + .init(CAS_PARAS, DesignerEnvManager.this::readHttpsParas) + .init(EnvDetectorConfig.XML_TAG, DesignerEnvManager.this::readEnvDetectorConfig) + .init(DesignerStartupConfig.XML_TAG, DesignerEnvManager.this::readStartupConfig) + .init("AlphaFineConfigManager", (e) -> { + this.alphaFineConfigManager = AsyncXmlElement.of(DesignerStartupPool.common(), () -> { + AlphaFineConfigManager config = AlphaFineConfigManager.getInstance(); + e.readXMLObject(config); + return config; + }); + }) + .init("RecentColors", DesignerEnvManager.this::readRecentColor) + .init("OpenDebug", DesignerEnvManager.this::readOpenDebug) + .init(ComponentReuseNotificationInfo.XML_TAG, DesignerEnvManager.this::readComponentReuseNotificationInfo) + .init(DesignerPushUpdateConfigManager.XML_TAG, DesignerEnvManager.this::readDesignerPushUpdateAttr) + .init(VcsConfigManager.XML_TAG, DesignerEnvManager.this::readVcsAttr) + .init(DesignerPort.XML_TAG, DesignerEnvManager.this::readDesignerPort) + .init(SnapChatConfig.XML_TAG, DesignerEnvManager.this::readSnapChatConfig) + .init(DesignerLoginConfigManager.XML_TAG, DesignerEnvManager.this::readDesignerLoginAttr) + .init(fvsDesignerConfig.getValue().getName(), (e) -> { + SimpleDesignerConfig config = this.fvsDesignerConfig.getValue(); + this.fvsDesignerConfig = AsyncXmlElement.of(() -> { + e.readXMLObject(config); + return config; + }); + }) + .init(SwitchForSwingChecker.XML_TAG, DesignerEnvManager.this::readSwitchForSwingCheckerAttr) + .init(LAST_WEST_REGION_LAYOUT, DesignerEnvManager.this::readLastWestRegionLayout) + .init(LAST_EAST_REGION_LAYOUT, DesignerEnvManager.this::readLastEastRegionLayout); + } catch (Exception e) { + throw new XmlException(e); + } + } + + /** + * 备份老的 xml 文件, 防止第一次修改存在问题 + * 但是,只备份一次。其他都走老逻辑 + */ + private void backupOldXmlFile() { + + try { + File oldFile = getEnvFile(); + String newFilePath = ProductConstants.getEnvHome() + File.separator + ProductConstants.APP_NAME + "Env_backup.xml"; + File newFile = new File(newFilePath); + if (newFile.exists()) { + return; + } + if (oldFile.exists()) { + FileUtils.copyFile(oldFile, newFile); + } + } catch (Exception ignored) { + } + } + /** * Read XML.
* The method will be invoked when read data from XML file.
@@ -1740,6 +1997,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { readActiveStatus(reader); } else if (ComparatorUtils.equals(CAS_PARAS, name)) { readHttpsParas(reader); + } else if (name.equals(EnvDetectorConfig.XML_TAG)) { + readEnvDetectorConfig(reader); + } else if (name.equals(DesignerStartupConfig.XML_TAG)) { + readStartupConfig(reader); } else if (name.equals("AlphaFineConfigManager")) { readAlphaFineAttr(reader); } else if (name.equals("RecentColors")) { @@ -1750,7 +2011,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { readComponentReuseNotificationInfo(reader); } else if (name.equals(DesignerPushUpdateConfigManager.XML_TAG)) { readDesignerPushUpdateAttr(reader); - } else if (name.equals(vcsConfigManager.XML_TAG)) { + } else if (name.equals(VcsConfigManager.XML_TAG)) { readVcsAttr(reader); } else if (DesignerPort.XML_TAG.equals(name)) { readDesignerPort(reader); @@ -1758,6 +2019,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { readSnapChatConfig(reader); } else if (name.equals(DesignerLoginConfigManager.XML_TAG)) { readDesignerLoginAttr(reader); + } else if (name.equals(fvsDesignerConfig.getValue().getName())) { + readFvsDesignerConfig(reader); + } else if (name.equals(SwitchForSwingChecker.XML_TAG)) { + readSwitchForSwingCheckerAttr(reader); } else { readLayout(reader, name); } @@ -1774,7 +2039,18 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } private void readAlphaFineAttr(XMLableReader reader) { - reader.readXMLObject(this.alphaFineConfigManager = AlphaFineConfigManager.getInstance()); + + AlphaFineConfigManager config = AlphaFineConfigManager.getInstance(); + reader.readXMLObject(config); + this.alphaFineConfigManager = SimpleXmlElement.of(config); + } + + private void readEnvDetectorConfig(XMLableReader reader) { + reader.readXMLObject(this.envDetectorConfig); + } + + private void readStartupConfig(XMLableReader reader) { + reader.readXMLObject(this.designerStartupConfig); } private void readHttpsParas(XMLableReader reader) { @@ -1791,9 +2067,9 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private void readLayout(XMLableReader reader, String name) { - if ("LastEastRegionLayout".equals(name)) { + if (LAST_EAST_REGION_LAYOUT.equals(name)) { this.readLastEastRegionLayout(reader); - } else if ("LastWestRegionLayout".equals(name)) { + } else if (LAST_WEST_REGION_LAYOUT.equals(name)) { this.readLastWestRegionLayout(reader); } } @@ -1860,7 +2136,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } this.setEmbedServerLazyStartup(reader.getAttrAsBoolean("embedServerLazyStartup", false)); this.setShowTemplateMissingPlugin(reader.getAttrAsBoolean("showTemplateMissingPlugin", true)); + this.setUseOptimizedUPM4Adapter(reader.getAttrAsBoolean("useOptimizedUPM4Adapter", SupportOSImpl.MACOS_12_VERSION_ADAPTER.support())); + this.setPropertiesUsable(reader.getAttrAsBoolean("propertiesUsable", false)); this.setShowServerDatasetAuthTip(reader.getAttrAsBoolean("showServerDatasetAuthTip", true)); + this.setLayoutTemplateStyle(reader.getAttrAsInt("layoutTemplateStyle", LAYOUT_TEMPLATE_SIMPLE_STYLE)); } private void readReportPaneAttributions(XMLableReader reader) { @@ -1885,6 +2164,40 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.setPaginationLineColor(new Color(Integer.parseInt(tmpVal))); } } + + private void readEnvConfigMap(XMLableReader reader, EnvConfiguration envConfigs) { + + String currentEnv = reader.getAttrAsString("currentEnv", StringUtils.EMPTY); + envConfigs.setCurEnvName(currentEnv); + reader.readXMLObject(new XMLReadable() { + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + envConfigs.getNameEnvMap().clear(); + } else if (reader.isChildNode()) { + String tagName = reader.getTagName(); + if ("EnvConfigElement".equals(tagName)) { + final String name = reader.getAttrAsString("name", StringUtils.EMPTY); + reader.readXMLObject(new XMLReadable() { + @Override + public void readXML(XMLableReader reader) { + if (reader.isChildNode()) { + String tagName = reader.getTagName(); + if (DesignerWorkspaceType.Local.toString().equals(tagName)) { + LocalDesignerWorkspaceInfo envConfig = (LocalDesignerWorkspaceInfo) GeneralXMLTools.readXMLable(reader); + envConfigs.getNameEnvMap().put(name, envConfig); + } else if (DesignerWorkspaceType.Remote.toString().equals(tagName)) { + RemoteDesignerWorkspaceInfo envConfig = (RemoteDesignerWorkspaceInfo) GeneralXMLTools.readXMLable(reader); + envConfigs.getNameEnvMap().put(name, envConfig); + } + } + } + }); + } + } + } + }); + } private void readEnvConfigMap(XMLableReader reader) { String currentEnv = reader.getAttrAsString("currentEnv", StringUtils.EMPTY); @@ -1918,8 +2231,15 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } }); } - + private void readRecentOpenFileList(XMLableReader reader) { + + readRecentOpenFileList0(reader); + checkRecentOpenedFileNum(); + } + + private void readRecentOpenFileList0(XMLableReader reader) { + reader.readXMLObject(new XMLReadable() { @Override public void readXML(XMLableReader reader) { @@ -1951,7 +2271,6 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { } } }); - checkRecentOpenedFileNum(); } private void readDesignerPushUpdateAttr(XMLableReader reader) { @@ -1966,6 +2285,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { reader.readXMLObject(DesignerPort.getInstance()); } + private void readSwitchForSwingCheckerAttr(XMLableReader reader) { + reader.readXMLObject(switchForSwingChecker); + } + /** * Write XML.
* The method will be invoked when save data to XML file.
@@ -1987,6 +2310,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { writeActiveStatus(writer); writeHttpsParas(writer); writeAlphaFineAttr(writer); + writeEnvDetectorConfig(writer); + writeStartupConfig(writer); writeRecentColor(writer); writeOpenDebug(writer); writeDesignerPushUpdateAttr(writer); @@ -1995,6 +2320,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { writeSnapChatConfig(writer); writeComponentReuseNotificationInfo(writer); writeDesignerLoginAttr(writer); + writeFvsDesignerConfig(writer); + writeSwitchForSwingChecker(writer); writer.end(); } @@ -2013,7 +2340,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { private void writeAlphaFineAttr(XMLPrintWriter writer) { if (this.alphaFineConfigManager != null) { - this.alphaFineConfigManager.writeXML(writer); + this.alphaFineConfigManager.getValue().writeXML(writer); } } @@ -2030,6 +2357,18 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { writer.end(); } } + + private void writeEnvDetectorConfig(XMLPrintWriter writer) { + if (this.envDetectorConfig != null) { + this.envDetectorConfig.writeXML(writer); + } + } + + private void writeStartupConfig(XMLPrintWriter writer) { + if (this.designerStartupConfig != null) { + this.designerStartupConfig.writeXML(writer); + } + } //写入uuid private void writeUUID(XMLPrintWriter writer) { @@ -2078,10 +2417,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { writer.end(); writer.startTAG("EnvConfigMap"); - if (this.curEnvName != null) { - writer.attr("currentEnv", this.curEnvName); + if (this.getCurEnvName() != null) { + writer.attr("currentEnv", this.getCurEnvName()); } - for (Entry entry : nameEnvMap.entrySet()) { + for (Entry entry : getNameEnvMap().entrySet()) { writer.startTAG("EnvConfigElement").attr("name", entry.getKey()); DesignerWorkspaceInfo envConfig = entry.getValue(); GeneralXMLTools.writeXMLable(writer, envConfig, envConfig.getType().toString()); @@ -2134,7 +2473,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { if (!this.isShowTemplateMissingPlugin()) { writer.attr("showTemplateMissingPlugin", this.isShowTemplateMissingPlugin()); } + writer.attr("layoutTemplateStyle", this.getLayoutTemplateStyle()); writer.attr("showServerDatasetAuthTip", this.isShowServerDatasetAuthTip()); + writer.attr("useOptimizedUPM4Adapter", this.isUseOptimizedUPM4Adapter()); + writer.attr("propertiesUsable", this.isPropertiesUsable()); writer.end(); } @@ -2286,6 +2628,21 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { this.designerLoginConfigManager.writeXML(writer); } + private void readFvsDesignerConfig(XMLableReader reader) { + + SimpleDesignerConfig config = fvsDesignerConfig.getValue(); + reader.readXMLObject(config); + fvsDesignerConfig = SimpleXmlElement.of(config); + } + + private void writeFvsDesignerConfig(XMLPrintWriter writer) { + this.fvsDesignerConfig.getValue().writeXML(writer); + } + + private void writeSwitchForSwingChecker(XMLPrintWriter writer) { + this.switchForSwingChecker.writeXML(writer); + } + enum XmlHandler { Self; @@ -2310,4 +2667,43 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter { DesignerExiter.getInstance().execute(); } } + + public SnapChatConfig getSnapChatConfig() { + return snapChatConfig; + } + + private EnvConfiguration getEnvConfig() { + + return envConfig.getValue(); + } + + private Map getNameEnvMap() { + + return getEnvConfig().getNameEnvMap(); + } + + private static class EnvConfiguration { + + // name和Env的键值对 + private Map nameEnvMap = new ListMap<>(); + // marks: 当前报表服务器名字 + private String curEnvName = null; + + public Map getNameEnvMap() { + return nameEnvMap; + } + + public void setNameEnvMap(Map nameEnvMap) { + this.nameEnvMap = nameEnvMap; + } + + public String getCurEnvName() { + return curEnvName; + } + + public void setCurEnvName(String curEnvName) { + this.curEnvName = curEnvName; + } + } + } diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java index cd9c835f39..d38def2836 100644 --- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java +++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java @@ -1,7 +1,8 @@ package com.fr.design; import com.fr.common.report.ReportState; -import com.fr.decision.webservice.v10.plugin.helper.PluginErrorRemindHandler; +import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; @@ -13,6 +14,7 @@ import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.design.env.RemoteWorkspace; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.file.TemplateTreePane; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; @@ -34,7 +36,6 @@ import com.fr.process.engine.core.FineProcessContext; import com.fr.rpc.Result; import com.fr.stable.AssistUtils; import com.fr.stable.StringUtils; -import com.fr.env.PluginErrorRemindDialog; import com.fr.start.server.ServerTray; import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContextCallback; @@ -138,7 +139,7 @@ public class EnvChangeEntrance { if (template != null) { template.refreshToolArea(); } - pluginErrorRemind(); + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); } catch (Exception exception) { // 失败的处理 WorkspaceExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv); @@ -150,6 +151,8 @@ public class EnvChangeEntrance { model.envChanged(); } NotificationCenter.getInstance().clearAllNotifications(); + //切换环境后,清空粘贴板里面的内容 + TemplateTreeClipboard.getInstance().reset(); return true; } @@ -244,28 +247,6 @@ public class EnvChangeEntrance { } } - /** - * 插件启动错误信息提示 - */ - public void pluginErrorRemind() { - if (!WorkContext.getCurrent().isLocal()) { - return; - } - - String content = PluginErrorRemindHandler.pluginErrorContent(); - if (StringUtils.isNotEmpty(content)) { - // 该操作需要在当前awt操作之后执行,使用SwingUtilities.invokeLater将其置于awt操作对列末尾 - // 若使用UIUtil.invokeLaterIfNeeded,会立即执行,影响其他UI操作 - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - PluginErrorRemindDialog dialog = new PluginErrorRemindDialog(DesignerContext.getDesignerFrame(), content); - dialog.setVisible(true); - } - }); - } - } - /** * 判断是否需要做版本验证,判断依据为 * 1、选择的环境为远程环境 @@ -388,6 +369,11 @@ public class EnvChangeEntrance { @Override public void doOk() { + SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(envListPane)); + if (!saveSomeTemplatePane.showSavePane()) { + // 用户取消保存时,取消切换目录操作 + return; + } boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER); // 切换完成后清理密码 updateNotRememberPwdEnv(); @@ -427,7 +413,9 @@ public class EnvChangeEntrance { DesignerExiter.getInstance().execute(); } else { updateNotRememberPwdEnv(); - VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName()); + if (DesignerContext.getDesignerFrame().isVisible()) { + VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName()); + } } } diff --git a/designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java b/designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java index 4d1493e01b..11634c5906 100644 --- a/designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java +++ b/designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java @@ -114,7 +114,7 @@ public class ExtraDesignClassManager extends AbstractExtraClassManager implement for (ParameterWidgetOptionProvider provider : set) { WidgetOption option = WidgetOptionFactory.createByWidgetClass( provider.nameForWidget(), - IOUtils.readIcon(provider.iconPathForWidget()), + provider.iconPathForWidget(), provider.classForWidget() ); result.add(option); @@ -186,7 +186,7 @@ public class ExtraDesignClassManager extends AbstractExtraClassManager implement if (provider.isContainer() == isContainer) { WidgetOption option = WidgetOptionFactory.createByWidgetClass( provider.nameForWidget(), - BaseUtils.readIcon(provider.iconPathForWidget()), + provider.iconPathForWidget(), provider.classForWidget() ); result.add(option); diff --git a/designer-base/src/main/java/com/fr/design/RestartHelper.java b/designer-base/src/main/java/com/fr/design/RestartHelper.java index 64fdda7baa..9c14fd4157 100644 --- a/designer-base/src/main/java/com/fr/design/RestartHelper.java +++ b/designer-base/src/main/java/com/fr/design/RestartHelper.java @@ -57,10 +57,8 @@ public class RestartHelper { properties.setProperty((i + size) + "", files[i]); } } - try { - FileOutputStream file2DeleteOutputStream = new FileOutputStream(file); + try (FileOutputStream file2DeleteOutputStream = new FileOutputStream(file)) { properties.store(file2DeleteOutputStream, "save"); - file2DeleteOutputStream.close(); } catch (IOException e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } diff --git a/designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java b/designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java index 1a0509d267..546a702979 100644 --- a/designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/AllowAuthorityEditAction.java @@ -1,9 +1,9 @@ package com.fr.design.actions; -import com.fr.base.svg.IconUtils; import com.fr.base.vcs.DesignerMode; import com.fr.design.constants.UIConstants; import com.fr.design.menu.KeySetUtils; +import com.fr.design.module.DesignModuleFactory; import com.fr.design.roleAuthority.ReportAndFSManagePane; import com.fr.design.roleAuthority.RolesAlreadyEditedPane; import com.fr.design.designer.TargetComponent; @@ -61,6 +61,8 @@ public class AllowAuthorityEditAction extends TemplateComponentAction { DesignerContext.getDesignerFrame().refreshDottedLine(); EastRegionContainerPane.getInstance().replaceConfiguredRolesPane(RolesAlreadyEditedPane.getInstance()); EastRegionContainerPane.getInstance().removeParameterPane(); + //进入时要关闭查找替换面板 + DesignModuleFactory.getReplaceOperator().close(); //画虚线 return true; diff --git a/designer-base/src/main/java/com/fr/design/actions/UpdateAction.java b/designer-base/src/main/java/com/fr/design/actions/UpdateAction.java index 048f233373..d33c04eb15 100644 --- a/designer-base/src/main/java/com/fr/design/actions/UpdateAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/UpdateAction.java @@ -185,12 +185,24 @@ public abstract class UpdateAction extends ShortCut implements Action { * @param resource 图标资源路径 */ public void setSmallIcon(String resource) { + setSmallIcon(resource, true); + } + + /** + * 使用传入资源url的方式设置Icon,会自动设置_normal.svg,然后通过needDisable参数判断是否需要自动设置_disable.svg + * 因为有些地方是不需要设置灰化图标的,所以不存在灰化图标资源,这边如果一并设置,就会报错文件找不到 + * @param resource + * @param needDisable + */ + public void setSmallIcon(String resource, boolean needDisable) { if (StringUtils.equals(resource, StringUtils.EMPTY)) { this.putValue(Action.SMALL_ICON, null); return; } this.putValue(Action.SMALL_ICON, IconUtils.readIcon(resource)); - this.putValue(UpdateAction.DISABLED_ICON, IconUtils.readSVGIcon(resource, IconUtils.ICON_TYPE_DISABLED)); + if (needDisable) { + this.putValue(UpdateAction.DISABLED_ICON, IconUtils.readSVGIcon(resource, IconUtils.ICON_TYPE_DISABLED)); + } } public void setSmallIcon(Icon[] smallIcon, boolean white) { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java b/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java index a162571002..5365e556b6 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java @@ -17,7 +17,7 @@ public class BugAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.bugs", "http://bbs.fanruan.com/forum-156-1.html"); + return CloudCenter.getInstance().acquireUrlByKind("bbs.bugs", "https://service.fanruan.com/PF/FR/feedback?type=2"); } public static final MenuKeySet BUG = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java b/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java index c8b2ccdae1..62d4b9c95f 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java @@ -18,7 +18,7 @@ public class NeedAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.needs", "http://bbs.fanruan.com/forum-56-1.html"); + return CloudCenter.getInstance().acquireUrlByKind("bbs.needs", "https://service.fanruan.com/PF/FR/feedback?type=1"); } public static final MenuKeySet NEED = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java b/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java new file mode 100644 index 0000000000..d0dcc4195d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java @@ -0,0 +1,17 @@ +package com.fr.design.actions.community; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.login.AbstractDesignerSSO; +import com.fr.general.CloudCenter; + +public class StudyPlanAction extends AbstractDesignerSSO { + public StudyPlanAction() { + this.setName(Toolkit.i18nText("Fine-Design_Study_Plan")); + this.setSmallIcon("/com/fr/design/images/bbs/studyPlan"); + } + + @Override + public String getJumpUrl() { + return CloudCenter.getInstance().acquireUrlByKind("bbs.studyPlan", "https://edu.fanruan.com/studypath/finereport"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java b/designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java index 2d4554afdd..3a8137f9d0 100644 --- a/designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java +++ b/designer-base/src/main/java/com/fr/design/actions/core/ActionFactory.java @@ -6,6 +6,7 @@ import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.mainframe.JTemplate; import com.fr.design.menu.MenuKeySet; import com.fr.design.selection.QuickEditor; +import com.fr.design.ui.util.UIUtil; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; @@ -32,6 +33,7 @@ public class ActionFactory { private static Set> actionClasses = new CopyOnWriteArraySet<>(); private static Set> floatActionClasses = new CopyOnWriteArraySet<>(); private static Class chartCollectionClass = null; + /** * 无需每次实例化的悬浮元素编辑器 */ @@ -57,7 +59,6 @@ public class ActionFactory { private ActionFactory() { } - /** * 元素编辑器释放模板对象 */ @@ -69,7 +70,34 @@ public class ActionFactory { entry.getValue().release(); } } - + + /** + * 注册异步加载的单元格编辑器 + * 首先放到 classMap 中,当初始化成功后,则移除,并放到 cellEditor 中 + * 如果已经存在,则覆盖 + * + * @param keyClazz 作为 key 的类 + * @param editorClazz 作为 编辑器 的类 + */ + public static void registerAsyncInitCellEditorClass(Class keyClazz, Class editorClazz) { + + cellEditorClass.put(keyClazz, editorClazz); + // 这里直接用 invokeLater 放到 UI 线程中去调用。 + // 不阻塞主逻辑的启动 + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + + try { + QuickEditor quickEditor = editorClazz.newInstance(); + cellEditorClass.remove(keyClazz); + cellEditor.put(keyClazz, quickEditor); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + }); + } /** * 注册无需每次实例化的单元格元素编辑器 diff --git a/designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java b/designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java index 65f1361762..0505a8e140 100644 --- a/designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/edit/CopyAction.java @@ -21,7 +21,7 @@ public class CopyAction extends TemplateComponentAction { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_M_Edit_Copy")); this.setMnemonic('C'); - this.setSmallIcon("/com/fr/design/images/m_edit/copy"); + this.setSmallIcon("/com/fr/design/standard/copy/copy"); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)); this.setEnabled(!DesignModeContext.isBanCopyAndCut()); } diff --git a/designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java b/designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java index 4da98d733d..c15e962272 100644 --- a/designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/edit/CutAction.java @@ -25,7 +25,7 @@ public class CutAction extends TemplateComponentAction { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_M_Edit_Cut")); this.setMnemonic('T'); - this.setSmallIcon("/com/fr/design/images/m_edit/cut"); + this.setSmallIcon("/com/fr/design/standard/cut/cut"); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); this.setEnabled(!DesignModeContext.isBanCopyAndCut()); } diff --git a/designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java b/designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java index 22093acb7a..c14fcabf57 100644 --- a/designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/edit/PasteAction.java @@ -24,7 +24,7 @@ public class PasteAction extends TemplateComponentAction { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_M_Edit_Paste")); this.setMnemonic('P'); - this.setSmallIcon("/com/fr/design/images/m_edit/paste"); + this.setSmallIcon("/com/fr/design/standard/paste/paste"); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)); } diff --git a/designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java b/designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java index 58fe5666a4..22263a871e 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/CloseCurrentTemplateAction.java @@ -3,7 +3,7 @@ package com.fr.design.actions.file; import com.fr.design.actions.UpdateAction; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.mainframe.JTemplate; import com.fr.design.menu.KeySetUtils; @@ -28,9 +28,9 @@ public class CloseCurrentTemplateAction extends UpdateAction { * @param e 事件 */ public void actionPerformed(ActionEvent e) { - MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); - MutilTempalteTabPane.getInstance().closeFormat(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); - MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(true); + MultiTemplateTabPane.getInstance().closeFormat(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); } @Override diff --git a/designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java b/designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java new file mode 100644 index 0000000000..f7851d7af6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java @@ -0,0 +1,50 @@ +package com.fr.design.actions.file; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.FileOperations; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.utils.TemplateUtils; + +import javax.swing.JOptionPane; +import java.awt.event.ActionEvent; + +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; + +/* + * 删除指定文件 + */ +public class DelFileAction extends UpdateAction { + + public DelFileAction() { + + this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove")); + this.setSmallIcon("/com/fr/design/standard/remove/remove"); + } + + @Override + public void actionPerformed(ActionEvent evt) { + FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); + if (!selectedOperation.access()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + if (TemplateUtils.checkSelectedTemplateIsEditing()) { + if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + YES_NO_OPTION) != JOptionPane.YES_OPTION) { + return; + } + } + selectedOperation.deleteFile(); + DesignerFrameFileDealerPane.getInstance().stateChange(); + DesignerContext.getDesignerFrame().setTitle(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java b/designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java index 1ca29a0425..5925e250f4 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java @@ -3,6 +3,7 @@ */ package com.fr.design.actions.file; +import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.mainframe.TemplateSavingChecker; import java.awt.event.ActionEvent; @@ -28,9 +29,14 @@ public class ExitDesignerAction extends UpdateAction { * @param e 事件 */ public void actionPerformed(ActionEvent e) { + // 检查是否有正在保存的模板 if (!TemplateSavingChecker.check()) { return; } - DesignerContext.getDesignerFrame().exit(); + // 提示用户保存模板 + SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true); + if (saveSomeTemplatePane.showSavePane()) { + DesignerContext.getDesignerFrame().exit(); + } } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java b/designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java new file mode 100644 index 0000000000..0c039b4af7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java @@ -0,0 +1,163 @@ +package com.fr.design.actions.file; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.gui.itree.refreshabletree.RefreshableJTree; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.file.filetree.FileNode; +import com.fr.general.ComparatorUtils; +import com.fr.stable.CoreConstants; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; + +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.awt.event.ActionEvent; +import java.io.File; + +/** + * 模板定位功能 + */ +public class LocateAction extends UpdateAction { + + public LocateAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate")); + this.setSmallIcon("/com/fr/design/standard/locate/locate"); + } + + @Override + public void actionPerformed(ActionEvent e) { + JTemplate current = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + gotoEditingTemplateLeaf(current.getEditingFILE().getPath(), false); + } + + /** + * 在左侧模板树定位到指定模板 + * + * @param locatedPath + */ + public static void gotoEditingTemplateLeaf(String locatedPath) { + gotoEditingTemplateLeaf(locatedPath, true); + } + + private static void gotoEditingTemplateLeaf(String locatedPath, boolean needRefreshMode) { + if (locatedPath == null) { + return; + } + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + TemplateTreeSearchManager.getInstance().outOfSearchMode(); + } + + DefaultTreeModel model = (DefaultTreeModel) getTemplateFileTree().getModel(); + ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) model.getRoot(); + if (needRefreshMode) { + treeNode.removeAllChildren(); + ExpandMutableTreeNode[] childTreeNodes = getTemplateFileTree().loadChildTreeNodes(treeNode); + treeNode.addChildTreeNodes(childTreeNodes); + model.reload(treeNode); + } + + recursiveSelectPath(treeNode, locatedPath, model); + TreePath selectedTreePath = getTemplateFileTree().getSelectionPath(); + if (selectedTreePath != null) { + getTemplateFileTree().scrollPathToVisible(selectedTreePath); + } + } + + private static TemplateFileTree getTemplateFileTree() { + return TemplateTreePane.getInstance().getTemplateFileTree(); + } + + private static void recursiveSelectPath(TreeNode treeNode, String currentPath, DefaultTreeModel m_model) { + for (int i = 0, len = treeNode.getChildCount(); i < len; i++) { + TreeNode node = treeNode.getChildAt(i); + // 取出当前的childTreeNode,并append到searchingPath后面 + ExpandMutableTreeNode childTreeNode = (ExpandMutableTreeNode) node; + if (selectFilePath(childTreeNode, ProjectConstants.REPORTLETS_NAME, currentPath, m_model)) { + break; + } + if (!node.isLeaf()) { + for (int j = 0; j < node.getChildCount(); j++) { + recursiveSelectPath(node.getChildAt(j), currentPath, m_model); + } + } + } + } + + /* + * 在currentTreeNode下找寻filePath + * + * prefix + currentTreeNode.getName() = currentTreeNode所对应的Path + * + * 返回currentTreeNode下是否找到了filePath + */ + private static boolean selectFilePath(ExpandMutableTreeNode currentTreeNode, String prefix, String filePath, DefaultTreeModel model) { + Object userObj = currentTreeNode.getUserObject(); + if (!(userObj instanceof FileNode)) { + return false; + } + FileNode fileNode = (FileNode) userObj; + String nodePath = fileNode.getName(); + String currentTreePath = StableUtils.pathJoin(prefix, nodePath); + boolean result = false; + + // 如果equals,说明找到了,不必再找下去了 + if (ComparatorUtils.equals(new File(currentTreePath), new File(filePath))) { + getTemplateFileTree().setSelectionPath(new TreePath(model.getPathToRoot(currentTreeNode))); + result = true; + } + // 如果当前路径是currentFilePath的ParentFile,则expandTreeNode,并继续往下找 + else if (isParentFile(currentTreePath, filePath)) { + loadPendingChildTreeNode(currentTreeNode); + prefix = currentTreePath + CoreConstants.SEPARATOR; + for (int i = 0, len = currentTreeNode.getChildCount(); i < len; i++) { + ExpandMutableTreeNode childTreeNode = (ExpandMutableTreeNode) currentTreeNode.getChildAt(i); + + if (selectFilePath(childTreeNode, prefix, filePath, model)) { + result = true; + } + } + } + + return result; + } + + protected static void loadPendingChildTreeNode(ExpandMutableTreeNode currentTreeNode) { + if (currentTreeNode.isLeaf()) { + return; + } + + // 判断第一个孩子节点.UserObject是不是PENDING,如果是PENDING的话,需要重新加载这个TreeNode + ExpandMutableTreeNode flag = (ExpandMutableTreeNode) currentTreeNode.getFirstChild(); + if (flag == null || !flag.getUserObject().toString().equals(RefreshableJTree.PENDING.toString())) { + return; + } + // 删除所有的节点. + currentTreeNode.removeAllChildren(); + + ExpandMutableTreeNode[] children = getTemplateFileTree().loadChildTreeNodes(currentTreeNode); + for (ExpandMutableTreeNode c : children) { + currentTreeNode.add(c); + } + } + + private static boolean isParentFile(String var0, String var1) { + File var2 = new File(var0); + File var3 = new File(var1); + + while (!ComparatorUtils.equals(var2, var3)) { + var3 = var3.getParentFile(); + if (var3 == null) { + return false; + } + } + + return true; + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java index 08273202d1..dd48e26841 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferenceAction.java @@ -40,7 +40,10 @@ public class PreferenceAction extends UpdateAction { DesignerEnvManager.loadLogSetting(); DesignerEnvManager.getEnvManager().saveXMLFile(); JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - jt.refreshToolArea(); + //不能只单纯判断!=null,JTemplate还有可能是JNullTemplate.NULL,这个时候模板也是空内容的 + if (JTemplate.isValid(jt)) { + jt.refreshToolArea(); + } preferencePane.showRestartDialog(); DesignerFrameFileDealerPane.getInstance().refreshDockingView(); } 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 2e32eb88cb..e09d6f7a05 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 @@ -9,27 +9,31 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.DialogActionListener; import com.fr.design.editor.editor.IntegerEditor; +import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.gui.frpane.UITabbedPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UINoThemeColorButton; +import com.fr.design.gui.ibutton.UIRadioButton; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.icombobox.UIDictionaryComboBox; +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.FileSelectionMode; -import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser; import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.iprogressbar.UIProgressBarUI; import com.fr.design.gui.ispinner.UISpinner; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.jdk.JdkVersion; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.layout.VerticalFlowLayout; -import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.vcs.VcsConfigManager; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.design.os.impl.SupportOSImpl; @@ -41,31 +45,36 @@ import com.fr.general.FRFont; import com.fr.general.IOUtils; import com.fr.general.Inter; import com.fr.general.log.Log4jConfig; +import com.fr.io.attr.ImageExportAttr; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; +import com.fr.report.ReportConfigManager; import com.fr.stable.Constants; import com.fr.stable.os.OperatingSystem; -import com.fr.third.apache.log4j.Level; +import com.fr.third.apache.logging.log4j.Level; import com.fr.transaction.Configurations; import com.fr.transaction.Worker; import com.fr.workspace.WorkContext; import com.fr.workspace.server.vcs.VcsOperator; import com.fr.workspace.server.vcs.git.config.GcConfig; -import com.sun.javafx.tk.FileChooserType; -import javafx.stage.FileChooser; +import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.KeyStroke; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.Timer; import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; @@ -110,7 +119,8 @@ public class PreferencePane extends BasicPane { private static final int CACHING_DEFAULT = 5; private static final int CACHING_GAP = 5; private static final int MEMORY_TIP_LABEL_MAX_WIDTH = 230; - private static final int OFFSET_HEIGHT = 50; + private static final int PREFERENCE_LABEL_MAX_WIDTH = 460; + private static final int OFFSET_HEIGHT = 60; private static final String TYPE = "pressed"; private static final String DISPLAY_TYPE = "+"; @@ -167,15 +177,18 @@ public class PreferencePane extends BasicPane { private UICheckBox oracleSpace; private UISpinner cachingTemplateSpinner; private UICheckBox useOptimizedUPMCheckbox; + private UICheckBox useNewVersionLoginCheckbox; private UICheckBox useUniverseDBMCheckbox; private UICheckBox joinProductImproveCheckBox; private UICheckBox autoPushUpdateCheckBox; private UICheckBox embedServerLazyStartupCheckBox; private UICheckBox imageCompressPanelCheckBox; + private UICheckBox cloudAnalyticsDelayCheckBox; private UICheckBox vcsEnableCheckBox; private UICheckBox saveCommitCheckBox; private UICheckBox useIntervalCheckBox; + private UICheckBox startupPageEnabledCheckBox; private IntegerEditor saveIntervalEditor; private UICheckBox gcEnableCheckBox; private UIButton gcButton; @@ -188,6 +201,14 @@ public class PreferencePane extends BasicPane { private JProgressBar gcProgressBar; private Timer gcProgressTimer; private UIButton gcOkButton = new UIButton(i18nText("Fine-Design_Report_OK")); + + private UIRadioButton previewResolutionBtnS; + private UIRadioButton previewResolutionBtnM; + + private UIRadioButton previewRenderSpeed; + private UIRadioButton previewRenderQuality; + private static final int DPI_SCALE_S = 1; + private static final int DPI_SCALE_M = 2; public PreferencePane() { this.initComponents(); @@ -200,9 +221,13 @@ public class PreferencePane extends BasicPane { UITabbedPane jtabPane = new UITabbedPane(); JPanel generalPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); - jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalPane); + UIScrollPane generalScrollPane = patchScroll(generalPane); + jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalScrollPane); + JPanel advancePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); - jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), advancePane); + UIScrollPane adviceScrollPane = patchScroll(advancePane); + jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane); + contentPane.add(jtabPane, BorderLayout.NORTH); createFunctionPane(generalPane); @@ -217,6 +242,8 @@ public class PreferencePane extends BasicPane { createLogPane(advancePane); createLanPane(generalPane); + + createStartupPagePane(generalPane); createLengthPane(advancePane); @@ -233,6 +260,13 @@ public class PreferencePane extends BasicPane { advancePane.add(upmSelectorPane); } + if (SupportOSImpl.DESIGNER_LOGIN.support()) { + JPanel loginSelectorPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Login_Manager")); + useNewVersionLoginCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_New_Login_Manager")); + loginSelectorPane.add(useNewVersionLoginCheckbox); + advancePane.add(loginSelectorPane); + } + JPanel dbmSelectorPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Database_Manager")); useUniverseDBMCheckbox = new UICheckBox(i18nText("Fine-Design_Basic_Use_Universe_Database_Manager")); //dbmSelectorPane.add(useUniverseDBMCheckbox); @@ -266,9 +300,51 @@ public class PreferencePane extends BasicPane { JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance")); imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress")); imageCompressPanel.add(imageCompressPanelCheckBox); + imageCompressPanel.add(createImageExportSettingPane()); advancePane.add(imageCompressPanel); + + JPanel designerStartupOption = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Startup_Option")); + cloudAnalyticsDelayCheckBox = new UICheckBox(i18nText("Fine-Design_Cloud_Analytics_Delay")); + designerStartupOption.add(cloudAnalyticsDelayCheckBox); + advancePane.add(designerStartupOption); + } + + private JPanel createImageExportSettingPane() { + previewResolutionBtnS = new UIRadioButton(i18nText("Fine-Design_Image_Export_SD"), true); + previewResolutionBtnM = new UIRadioButton(i18nText("Fine-Design_Image_Export_HD")); + ButtonGroup previewResolutionBtnGroup = new ButtonGroup(); + previewResolutionBtnGroup.add(previewResolutionBtnS); + previewResolutionBtnGroup.add(previewResolutionBtnM); + + previewRenderSpeed = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Speed_Priority")); + previewRenderQuality = new UIRadioButton(Toolkit.i18nText("Fine-Design_Image_Export_Quality_First")); + ButtonGroup previewRenderGroup = new ButtonGroup(); + previewRenderGroup.add(previewRenderQuality); + previewRenderGroup.add(previewRenderSpeed); + JPanel imageExportSettingPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JComponent[][] templateComps = { + {new UILabel(Toolkit.i18nText("Fine-Design_Report_Engine_Enlarge_Or_Reduce") + ":"), this.previewResolutionBtnS, this.previewResolutionBtnM}, + {new UILabel(Toolkit.i18nText("Fine-Design_Image_Export_Rendering_Quality") + ":"), this.previewRenderQuality, this.previewRenderSpeed}, + }; + imageExportSettingPane.add( + TableLayoutHelper.createGapTableLayoutPane( + templateComps, + new double[]{TableLayout.FILL, TableLayout.FILL}, + new double[]{TableLayout.FILL, TableLayout.FILL, TableLayout.FILL}, + 20, 0), + BorderLayout.CENTER); + imageExportSettingPane.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0)); + return imageExportSettingPane; } + @NotNull + private UIScrollPane patchScroll(JPanel generalPane) { + UIScrollPane generalPanelWithScroll = new UIScrollPane(generalPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + generalPanelWithScroll.setBorder(new EmptyBorder(0, 0, 0, 0)); + generalPanelWithScroll.setPreferredSize(new Dimension(generalPane.getWidth(), 600)); + return generalPanelWithScroll; + } + private void createVcsSettingPane(JPanel generalPane) { JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Title")); generalPane.add(vcsPane); @@ -280,8 +356,6 @@ public class PreferencePane extends BasicPane { useIntervalCheckBox = new UICheckBox(); //gc面板 - JPanel gcControlPane = createGcControlPane(); - JPanel enableVcsPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); enableVcsPanel.add(vcsEnableCheckBox); enableVcsPanel.add(remindVcsLabel); @@ -314,7 +388,31 @@ public class PreferencePane extends BasicPane { vcsPane.add(enableVcsPanel); vcsPane.add(intervalPanel); vcsPane.add(saveCommitCheckBox); - vcsPane.add(gcControlPane); + + initGcControlPane(vcsPane); + } + + private void initGcControlPane(JPanel vcsPane) { + JPanel gcControlPane = createGcControlPane(); + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + return WorkContext.getCurrent().get(VcsOperator.class).isLegacyMode(); + } + + @Override + protected void done() { + try { + if (Boolean.TRUE.equals(get())) { + // 老版本时才显示gc选项 + vcsPane.add(gcControlPane); + vcsPane.updateUI(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "[Vcs] retrieve legacy mode error: {}", e.getMessage()); + } + } + }.execute(); } /** @@ -348,22 +446,20 @@ public class PreferencePane extends BasicPane { private void createFunctionPane(JPanel generalPane) { JPanel topVerticalTitledBorderPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Basic_Preference_Function")); - JPanel upper = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); - JPanel lower = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); - topVerticalTitledBorderPane.add(upper); - topVerticalTitledBorderPane.add(lower); + JPanel supportUndoPanel = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); + topVerticalTitledBorderPane.add(supportUndoPanel); generalPane.add(topVerticalTitledBorderPane); //添加supportUndo选择项 supportUndoCheckBox = new UICheckBox(i18nText("Fine-Design_Basic_Preference_Support_Undo")); - upper.add(supportUndoCheckBox); + supportUndoPanel.add(supportUndoCheckBox); //添加maxUndoLimit //String[] undoTimes = {"最大撤销次数","5次","10次","15次","20次","50次"}; String[] undoTimes = {i18nText("Fine-Design_Basic_Max_Undo_Limit"), MAX_UNDO_LIMIT_5 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_10 + i18nText("Fine-Design_Basic_Time(s)") , MAX_UNDO_LIMIT_15 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_20 + i18nText("Fine-Design_Basic_Time(s)"), MAX_UNDO_LIMIT_50 + i18nText("Fine-Design_Basic_Time(s)")}; maxUndoLimit = new UIComboBox(undoTimes); - upper.add(maxUndoLimit); + supportUndoPanel.add(maxUndoLimit); //不支持撤销则不能选择撤销可缓存,也不能设置最大撤销次数 supportUndoCheckBox.addActionListener(new ActionListener() { @@ -377,14 +473,14 @@ public class PreferencePane extends BasicPane { //添加supportDefaultParentCalculate选择项 supportDefaultParentCalculateCheckBox = new UICheckBox( i18nText("Fine-Design_Basic_Preference_Support_Default_Parent_Calculate")); - upper.add(supportDefaultParentCalculateCheckBox); + topVerticalTitledBorderPane.add(supportDefaultParentCalculateCheckBox); //添加是否展示打开模板提示缺少插件选择项 showTemplateMissingPlugin = new UICheckBox( i18nText("Fine-Design_Basic_Preference_Show-Template-Missing-Plugin")); - upper.add(showTemplateMissingPlugin); + topVerticalTitledBorderPane.add(showTemplateMissingPlugin); startWithEmptyFile = new UICheckBox(i18nText("Fine-Design_Basic_Preference_Start_Empty_File")); - lower.add(startWithEmptyFile); + topVerticalTitledBorderPane.add(startWithEmptyFile); } private void createEditPane(JPanel generalPane) { @@ -438,10 +534,10 @@ public class PreferencePane extends BasicPane { requestFocusInWindow(); label = new UILabel(text); add(GUICoreUtils.createBorderLayoutPane( - new UILabel(i18nText("Fine-Design_Basic_Support_Current_Auto_Complete_Shortcut") + ":"), - BorderLayout.WEST, - label, - BorderLayout.CENTER), + new UILabel(i18nText("Fine-Design_Basic_Support_Current_Auto_Complete_Shortcut") + ":"), + BorderLayout.WEST, + label, + BorderLayout.CENTER), BorderLayout.NORTH); addKeyListener(new KeyAdapter() { @Override @@ -508,9 +604,8 @@ public class PreferencePane extends BasicPane { @Override public void actionPerformed(ActionEvent evt) { FileChooserProvider fileChooserProvider = - new JavaFxNativeFileChooser.Builder(). - fileSelectionMode(FileSelectionMode.DIR). - build(); + FileChooserFactory.createFileChooser(FileChooserArgs.newBuilder(). + setFileSelectionMode(FileSelectionMode.DIR).build()); int saveValue = fileChooserProvider.showDialog(chooseDirBtn); if (saveValue == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooserProvider.getSelectedFile(); @@ -576,6 +671,21 @@ public class PreferencePane extends BasicPane { languageComboBox.setFont(FRFont.getInstance("Dialog", Font.PLAIN, 12));//为了在中文系统中显示韩文 return languageComboBox; } + + private void createStartupPagePane(JPanel generalPane) { + + // ben:选择版本语言; + JPanel startupPagePaneWrapper = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); + JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Startup_Page_Config")); + generalPane.add(startupPagePaneWrapper); + startupPagePaneWrapper.add(startupPane); + + startupPageEnabledCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Check_Text")); + startupPane.add(startupPageEnabledCheckBox); + UILabel descLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Desc"), PREFERENCE_LABEL_MAX_WIDTH); + descLabel.setForeground(new Color(51, 51, 52, (int)Math.round(0.5 * 255))); + startupPane.add(descLabel); + } private String getDisplayShortCut(String shotrCut) { return shotrCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH) @@ -723,7 +833,12 @@ public class PreferencePane extends BasicPane { this.portEditor.setValue(new Integer(designerEnvManager.getEmbedServerPort())); if (useOptimizedUPMCheckbox != null) { - useOptimizedUPMCheckbox.setSelected(ServerPreferenceConfig.getInstance().isUseOptimizedUPM()); + useOptimizedUPMCheckbox.setSelected(ServerPreferenceConfig.getInstance().isUseOptimizedUPM() + || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()); + } + + if (useNewVersionLoginCheckbox != null) { + useNewVersionLoginCheckbox.setSelected(!DesignerEnvManager.getEnvManager().isUseOldVersionLogin()); } useUniverseDBMCheckbox.setSelected(ServerPreferenceConfig.getInstance().isUseUniverseDBM()); @@ -740,6 +855,27 @@ public class PreferencePane extends BasicPane { this.startWithEmptyFile.setSelected(designerEnvManager.isStartWithEmptyFile()); this.imageCompressPanelCheckBox.setSelected(designerEnvManager.isImageCompress()); + + ImageExportAttr attr = ReportConfigManager.getProviderInstance().getImageExportAttr(); + if (attr.getPreviewRenderQuality() == ImageExportAttr.RENDER_SPEED) { + previewRenderSpeed.setSelected(true); + } else { + previewRenderQuality.setSelected(true); + } + + if (attr.getPreviewResolutionScale() == DPI_SCALE_S) { + previewResolutionBtnS.setSelected(true); + } else { + previewResolutionBtnM.setSelected(true); + } + boolean enabled = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot(); + previewRenderSpeed.setEnabled(enabled); + previewRenderQuality.setEnabled(enabled); + previewResolutionBtnS.setEnabled(enabled); + previewResolutionBtnM.setEnabled(enabled); + + this.cloudAnalyticsDelayCheckBox.setSelected(designerEnvManager.isCloudAnalyticsDelay()); + this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); } private int chooseCase(int sign) { @@ -799,11 +935,14 @@ public class PreferencePane extends BasicPane { designerEnvManager.setJoinProductImprove(this.joinProductImproveCheckBox.isSelected()); designerEnvManager.setEmbedServerLazyStartup(this.embedServerLazyStartupCheckBox.isSelected()); designerEnvManager.setImageCompress(this.imageCompressPanelCheckBox.isSelected()); + designerEnvManager.setUseOptimizedUPM4Adapter(this.useOptimizedUPMCheckbox != null && this.useOptimizedUPMCheckbox.isSelected()); + designerEnvManager.setCloudAnalyticsDelay(this.cloudAnalyticsDelayCheckBox.isSelected()); VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager(); vcsConfigManager.setSaveInterval(this.saveIntervalEditor.getValue()); vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected()); vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected()); + designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected()); Configurations.update(new Worker() { @Override public void run() { @@ -820,6 +959,10 @@ public class PreferencePane extends BasicPane { designerEnvManager.setAutoPushUpdateEnabled(this.autoPushUpdateCheckBox.isSelected()); } + if (useNewVersionLoginCheckbox != null) { + designerEnvManager.setUseOldVersionLogin(!this.useNewVersionLoginCheckbox.isSelected()); + } + designerEnvManager.setUndoLimit(maxUndoLimit.getSelectedIndex() * SELECTED_INDEX_5); if (maxUndoLimit.getSelectedIndex() == SELECTED_INDEX_5) { designerEnvManager.setUndoLimit(MAX_UNDO_LIMIT_50); @@ -859,6 +1002,18 @@ public class PreferencePane extends BasicPane { } }); + ImageExportAttr attr = ReportConfigManager.getProviderInstance().getImageExportAttr(); + if (previewRenderSpeed.isSelected()) { + attr.setPreviewRenderQuality(ImageExportAttr.RENDER_SPEED); + } else { + attr.setPreviewRenderQuality(ImageExportAttr.RENDER_QUALITY); + } + if (previewResolutionBtnS.isSelected()) { + attr.setPreviewResolutionScale(DPI_SCALE_S); + } else { + attr.setPreviewResolutionScale(DPI_SCALE_M); + } + } // 如果语言设置改变了,则显示重启对话框 @@ -866,6 +1021,12 @@ public class PreferencePane extends BasicPane { if (!languageChanged) { return; } + // 重启弹窗出现之前提示用户保存模板 + SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(this)); + if (!saveSomeTempaltePane.showSavePane()) { + // 保存失败时,直接返回 + return; + } int rv = JOptionPane.showOptionDialog( null, i18nText("Fine-Design_Basic_Language_Change_Successful"), diff --git a/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java b/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java new file mode 100644 index 0000000000..842292ce2a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java @@ -0,0 +1,346 @@ +package com.fr.design.actions.file; + +import com.fr.base.BaseUtils; +import com.fr.chartx.TwoTuple; +import com.fr.design.DesignerEnvManager; +import com.fr.design.actions.UpdateAction; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.FileOperations; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MultiTemplateTabPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.utils.TemplateUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.event.EventDispatcher; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.general.ComparatorUtils; +import com.fr.stable.CoreConstants; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.third.org.apache.commons.io.FilenameUtils; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JOptionPane; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.awt.Color; +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.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.regex.Pattern; + +import static javax.swing.JOptionPane.DEFAULT_OPTION; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; + +/** + * 模板/目录重命名操作 + */ +public class RenameAction extends UpdateAction { + + private FileOperations selectedOperation; + + public RenameAction() { + + this.setName(Toolkit.i18nText("Fine-Design_Basic_Rename")); + this.setSmallIcon("/com/fr/design/standard/rename/rename"); + } + + @Override + public void actionPerformed(ActionEvent evt) { + selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); + if (!selectedOperation.access()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + + FileNode node = selectedOperation.getFileNode(); + String lock = node.getLock(); + if (lock != null && !lock.equals(node.getUserID())) { + // 提醒被锁定模板无法重命名 + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Unable_Rename_Locked_File"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + + new FileRenameDialog(node); + MultiTemplateTabPane.getInstance().repaint(); + DesignerFrameFileDealerPane.getInstance().stateChange(); + } + + /** + * 重命名对话框 + * 支持快捷键Enter,ESC + */ + private class FileRenameDialog extends JDialog { + + private UITextField nameField; + + private UILabel warnLabel; + + private UIButton confirmButton; + + /** + * 操作的节点 + */ + private FileNodeFILE fnf; + + private KeyListener keyListener = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + dispose(); + } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { + if (confirmButton.isEnabled()) { + confirmClose(); + } + } + } + }; + + + private FileRenameDialog(FileNode node) { + super(DesignerContext.getDesignerFrame(), true); + if (node == null) { + return; + } + fnf = new FileNodeFILE(node); + String oldName = fnf.getName(); + String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); + oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY); + + initPane(oldName); + } + + private void initPane(String oldName) { + this.setLayout(new BorderLayout()); + + // 输入框前提示 + UILabel newNameLabel = new UILabel(Toolkit.i18nText( + fnf.isDirectory() ? + "Fine-Design_Basic_Enter_New_Folder_Name" : "Fine-Design_Basic_Enter_New_File_Name") + ); + newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT); + newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); + //newNameLabel.setPreferredSize(new Dimension(118, 15)); + + // 重命名输入框 + nameField = new UITextField(oldName); + nameField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void changedUpdate(DocumentEvent e) { + validInput(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + validInput(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + validInput(); + } + }); + nameField.selectAll(); + nameField.setPreferredSize(new Dimension(170, 20)); + + JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); + topPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 0, 15)); + topPanel.add(newNameLabel); + topPanel.add(nameField); + + // 增加enter以及esc快捷键的支持 + nameField.addKeyListener(keyListener); + // 重名提示 + warnLabel = new UILabel(); + warnLabel.setPreferredSize(new Dimension(300, 50)); + warnLabel.setHorizontalAlignment(SwingConstants.LEFT); + warnLabel.setVerticalAlignment(SwingConstants.TOP); + warnLabel.setForeground(Color.RED); + warnLabel.setVisible(false); + + JPanel midPanel = new JPanel(new BorderLayout()); + midPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15)); + midPanel.add(warnLabel, BorderLayout.WEST); + + // 确认按钮 + confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm")); + confirmButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + confirmClose(); + } + }); + + // 取消按钮 + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + + + JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); + buttonsPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10)); + buttonsPane.add(confirmButton); + buttonsPane.add(cancelButton); + + this.add( + TableLayoutHelper.createTableLayoutPane( + new Component[][]{ + new Component[]{topPanel}, + new Component[]{midPanel}, + new Component[]{buttonsPane} + }, + new double[]{TableLayout.FILL, TableLayout.PREFERRED, TableLayout.PREFERRED}, + new double[]{TableLayout.FILL} + ), + BorderLayout.CENTER); + + this.setSize(340, 200); + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename")); + this.setResizable(false); + this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png")); + this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + GUICoreUtils.centerWindow(this); + this.setVisible(true); + } + + private void confirmClose() { + + if (TemplateUtils.checkSelectedTemplateIsEditing()) { + if (FineJOptionPane.showConfirmDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + YES_NO_OPTION) != JOptionPane.YES_OPTION) { + return; + } + } + + String userInput = nameField.getText().trim(); + + String path = FilenameUtils.standard(fnf.getPath()); + + String oldName = fnf.getName(); + String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); + oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY); + + // 输入为空或者没有修改 + if (ComparatorUtils.equals(userInput, oldName)) { + this.dispose(); + return; + } + + String parentPath = FilenameUtils.standard(fnf.getParent().getPath()); + + // 简单执行old new 替换是不可行的,例如 /abc/abc/abc/abc/ + String newPath = parentPath + CoreConstants.SEPARATOR + userInput + suffix; + this.dispose(); + + //模版重命名 + boolean success = selectedOperation.rename(fnf, path, newPath); + + if (success) { + afterRename(path, newPath); + } else { + FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Rename_Failure"), + Toolkit.i18nText("Fine-Design_Basic_Error"), + DEFAULT_OPTION, + ERROR_MESSAGE); + } + } + + private void afterRename(String path, String newPath) { + EventDispatcher.fire(DesignerFrameFileDealerPane.TEMPLATE_RENAME, new TwoTuple<>(path, newPath)); + HistoryTemplateListCache.getInstance().rename(fnf, path, newPath); + DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath); + selectedOperation.refreshParent(); + if (!fnf.isDirectory()) { + //版本控制:未打开模板时重命名,是个纯文件操作 + //不借助JTemplate的事件触发机制实现(需要新创建JTemplate,并添加监听,不确定会不会有问题) + path = path.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); + VcsHelper.getInstance().moveVcs(path, newPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY)); + } + DesignerContext.getDesignerFrame().setTitle(); + LocateAction.gotoEditingTemplateLeaf(newPath); + } + + + private void validInput() { + + String userInput = nameField.getText().trim(); + + String oldName = fnf.getName(); + String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); + oldName = oldName.replaceAll(suffix, StringUtils.EMPTY); + + if (StringUtils.isEmpty(userInput)) { + confirmButton.setEnabled(false); + return; + } + + if (ComparatorUtils.equals(userInput, oldName)) { + warnLabel.setVisible(false); + confirmButton.setEnabled(true); + return; + } + + String errorMsg = doCheck(userInput, suffix, fnf.isDirectory()); + if (StringUtils.isNotEmpty(errorMsg)) { + nameField.selectAll(); + // 如果文件名已存在,则灰掉确认按钮 + warnLabel.setText(errorMsg); + warnLabel.setVisible(true); + confirmButton.setEnabled(false); + } else { + warnLabel.setVisible(false); + confirmButton.setEnabled(true); + } + } + + private String doCheck (String userInput, String suffix, boolean isDirectory) { + String errorMsg = StringUtils.EMPTY; + if (selectedOperation.duplicated(userInput, suffix, false)) { + errorMsg = Toolkit.i18nText(isDirectory ? + "Fine-Design_Basic_Folder_Name_Duplicate" : + "Fine-Design_Basic_Template_File_Name_Duplicate", + userInput); + } + if (!Pattern.compile(DesignerFrameFileDealerPane.FILE_NAME_LIMIT).matcher(userInput).matches()) { + errorMsg = Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal"); + } + return errorMsg; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java b/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java index c59a92b975..33761a92e2 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java @@ -5,6 +5,7 @@ import com.fr.design.EnvChangeEntrance; import com.fr.design.actions.UpdateAction; import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.mainframe.JTemplate; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.MenuDef; @@ -66,7 +67,11 @@ public class SwitchExistEnv extends MenuDef { // 打开配置目录面板 EnvChangeEntrance.getInstance().chooseEnv(envName); } else { - EnvChangeEntrance.getInstance().switch2Env(envName); + SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true); + if (saveSomeTemplatePane.showSavePane()) { + // 用户模板保存后,才进行切换目录操作 + EnvChangeEntrance.getInstance().switch2Env(envName); + } } } diff --git a/designer-base/src/main/java/com/fr/design/actions/help/AboutPane.java b/designer-base/src/main/java/com/fr/design/actions/help/AboutPane.java index 6158540888..dbb7798f3b 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/AboutPane.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/AboutPane.java @@ -126,8 +126,8 @@ public class AboutPane extends JPanel { if (GeneralContext.getLocale().equals(Locale.TAIWAN)) { return; } - boxCenterAlignmentPane = new BoxCenterAligmentPane("QQ: " + CloudCenter.getInstance().acquireUrlByKind("help.qq")); - contentPane.add(boxCenterAlignmentPane); + JPanel servicePlatformPane = getURLActionPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Service_Platform"), CloudCenter.getInstance().acquireUrlByKind("service.platform")); + contentPane.add(servicePlatformPane); } // 是否显示鸣谢面板 diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineCloudConstants.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineCloudConstants.java new file mode 100644 index 0000000000..9fb243d1e8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineCloudConstants.java @@ -0,0 +1,200 @@ +package com.fr.design.actions.help.alphafine; + +import com.fr.design.i18n.Toolkit; +import com.fr.general.CloudCenter; +import com.fr.json.JSONArray; + +import java.util.HashMap; +import java.util.Map; + +/** + * 云端变量统一管理 + * + * @author Link + * @version 11.0 + * Created by Link on 2022/9/21 + */ +public class AlphaFineCloudConstants { + + private static final String PLUGIN_SEARCH_API = "plugin.searchAPI"; + private static final String PLUGIN_ALL_SEARCH_API = "plugin.all.searchAPI"; + private static final String AF_PLUGIN_INFO = "af.pluginInfo"; + private static final String AF_REUSE_INFO = "af.reuseInfo"; + private static final String AF_DOC_VIEW = "af.doc_view"; + private static final String AF_DOC_SEARCH = "af.doc_search"; + private static final String AF_DOC_INFO = "af.doc_info"; + private static final String AF_PLUGIN_IMAGE = "af.plugin_image"; + private static final String AF_RECORD = "af.record"; + private static final String AF_CLOUD_SEARCH = "af.cloud_search"; + private static final String AF_SIMILAR_SEARCH = "af.similar_search"; + private static final String AF_ADVICE_SEARCH = "af.advice_search"; + private static final String AF_HOT_SEARCH = "af.hot_search"; + private static final String AF_GO_FORUM = "af.go_fourm"; + private static final String AF_GO_WEB = "af.go_web"; + private static final String AF_PREVIEW = "af.preview"; + private static final String AF_CID_NEW = "af.cid.new"; + private static final String AF_CID_USER_GROUP_INFO = "af.cid.user.group.info"; + private static final String AF_HELP_QUICK_START = "af.help.quick.start"; + private static final String AF_HELP_REPORT_LEARNING_PATH = "af.help.report.learning.path"; + private static final String AF_HELP_PARAM_LEARNING_PATH = "af.help.param.learning.path"; + private static final String AF_HELP_FILL_LEARNING_PATH = "af.help.fill.learning.path"; + private static final String AF_HELP_API_SUMMARY = "af.help.api.summary"; + private static final String AF_HELP_MONTHLY_DOCUMENT = "af.help.monthly.document"; + private static final String AF_RECOMMEND = "af.recommend"; + + private static final String LINK_NAME = "name"; + private static final String LINK_URL = "link"; + + /** + * 获取插件搜索api + */ + public static String getPluginSearchUrl() { + return CloudCenter.getInstance().acquireUrlByKind(PLUGIN_SEARCH_API); + }; + + /** + * 帆软市场里全部插件api + */ + public static String getSearchAllPluginUrl() { + return CloudCenter.getInstance().acquireUrlByKind(PLUGIN_ALL_SEARCH_API); + } + + /** + * 获取插件信息api + */ + public static String getPluginUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_PLUGIN_INFO); + } + + /** + * 获取组件信息api + */ + public static String getReuseUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_REUSE_INFO); + } + + /** + * 获取帮助文档url + */ + public static String getDocumentDocUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_VIEW); + } + + /** + * 帮助文档搜索api + */ + public static String getDocumentSearchUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_SEARCH); + } + + /** + * 帮助文档信息api + */ + public static String getDocumentInformationUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_DOC_INFO); + } + + /** + * 插件图片api + */ + public static String getPluginImageUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_PLUGIN_IMAGE); + } + + /** + * 获取云端接口,用于上传alphafine搜索记录 + */ + public static String getCloudServerUrl() { + return CloudCenter.getInstance().acquireUrlByKind(AF_RECORD); + } + + /** + * 获取搜索api,输入搜索词,返回fr的相关功能 + */ + public static String getSearchApi() { + return CloudCenter.getInstance().acquireUrlByKind(AF_CLOUD_SEARCH); + } + + /** + * 获取模糊搜索api前缀,输入搜索词,返回alphaFine相关内容,插件,文档,功能等 + */ + public static String getSimilarSearchUrlPrefix() { + return CloudCenter.getInstance().acquireUrlByKind(AF_SIMILAR_SEARCH); + } + + /** + * 补全建议搜索结果 api,与AF_SIMILAR_SEARCH接口类似,但是返回的信息更全 + */ + public static String getComplementAdviceSearchUrlPrefix() { + return CloudCenter.getInstance().acquireUrlByKind(AF_ADVICE_SEARCH); + } + + /** + * 获取热门问题 + */ + public static String getAlphaHotSearch() { + return CloudCenter.getInstance().acquireUrlByKind(AF_HOT_SEARCH); + } + + /** + * 跳转论坛url + */ + public static String getAlphaGoToForum() { + return CloudCenter.getInstance().acquireUrlByKind(AF_GO_FORUM); + } + + /** + * 推荐搜索api,输入搜索词,返回猜你想搜的内容(html格式) + */ + public static String getAlphaGoToWeb() { + return CloudCenter.getInstance().acquireUrlByKind(AF_GO_WEB); + } + + /** + * 帆软智能客服页面url + */ + public static String getAlphaPreview() { + return CloudCenter.getInstance().acquireUrlByKind(AF_PREVIEW); + } + + /** + * cid系统的产品动态api + */ + public static String getAlphaCid() { + return CloudCenter.getInstance().acquireUrlByKind(AF_CID_NEW); + } + + /** + * cid系统的 用户组信息api + */ + public static String getAlphaCidUserGroupInfo() { + return CloudCenter.getInstance().acquireUrlByKind(AF_CID_USER_GROUP_INFO); + } + + private static String getDefaultRecommend() { + String[][] links = new String[][]{ + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Quick_Start"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_QUICK_START)}, + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Report_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_REPORT_LEARNING_PATH)}, + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Parameter_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_PARAM_LEARNING_PATH)}, + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Fill_Learning"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_FILL_LEARNING_PATH)}, + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Api_Summary"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_API_SUMMARY)}, + {Toolkit.i18nText("Fine-Design_Report_AlphaFine_Doc_Monthly_Document"), CloudCenter.getInstance().acquireUrlByKind(AF_HELP_MONTHLY_DOCUMENT)} + }; + JSONArray jsonArray = new JSONArray(); + for (String[] link : links) { + Map map = new HashMap<>(); + map.put(LINK_NAME, link[0]); + map.put(LINK_URL, link[1]); + jsonArray.put(map); + } + + return jsonArray.toString(); + } + + /** + * 获取默认推荐帮助文档url + */ + public static String getAlphaHelpRecommend() { + return CloudCenter.getInstance().acquireUrlByKind(AF_RECOMMEND, getDefaultRecommend()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java index 0296327097..7d02c03864 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java @@ -1,5 +1,7 @@ package com.fr.design.actions.help.alphafine; +import com.fr.base.FRContext; +import com.fr.design.DesignerEnvManager; import com.fr.general.ComparatorUtils; import com.fr.license.function.VT4FR; import com.fr.stable.OperatingSystem; @@ -10,10 +12,14 @@ import com.fr.stable.xml.XMLable; import com.fr.stable.xml.XMLableReader; import org.jetbrains.annotations.NotNull; -import javax.swing.*; +import javax.swing.KeyStroke; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; +import java.util.Stack; /** * AlphaFine配置类 @@ -23,6 +29,7 @@ import java.util.Map; */ public class AlphaFineConfigManager implements XMLable { + public static final String COMMA = ","; private static final long serialVersionUID = -8170289826729582122L; private static AlphaFineConfigManager alphaFineConfigManager = new AlphaFineConfigManager(); /** @@ -46,13 +53,17 @@ public class AlphaFineConfigManager implements XMLable { */ private boolean containRecommend = true; /** - * 设置 + * 功能 */ private boolean containAction = true; /** * 帮助文档 */ private boolean containDocument = true; + /** + * 我的模板 + * */ + private boolean containMyTemplate = true; /** * 模板 */ @@ -62,7 +73,7 @@ public class AlphaFineConfigManager implements XMLable { */ private boolean containFileContent; /** - * 应用中心 + * 插件中心 */ private boolean containPlugin = true; /** @@ -81,10 +92,36 @@ public class AlphaFineConfigManager implements XMLable { * 是否提醒 */ private boolean needRemind = true; - + /** + * 产品动态 + */ + private boolean productDynamics = true; + /** + * 模板商城是否展示 + */ + private boolean showTemplateShop = true; + /** + * tab页排序 + * 默认排序:动态,模板商城,帮助文档,插件中心,功能,我的模板 + */ + private String[] tabOrder; private Map actionSearchTextCache = new HashMap<>(8); - private String cacheBuildNO; + + private static final String CONTAIN_TEMPLATE_SHOP = "isContainTemplateShop"; + + /** + * key: 登录的bbs用户 + * value: alphaFine历史搜索记录 + */ + private Map> historySearchMap = new LinkedHashMap<>(); + + /** + * key: 登录的bbs用户 + * value: 已读的cid的集合 + */ + private Map> readSetMap = new LinkedHashMap<>(); + /** * 直接操作菜单次数 */ @@ -115,17 +152,24 @@ public class AlphaFineConfigManager implements XMLable { this.setContainPlugin(reader.getAttrAsBoolean("isContainDocument", true)); this.setContainDocument(reader.getAttrAsBoolean("isContainDocument", true)); this.setContainRecommend(reader.getAttrAsBoolean("isContainRecommend", true)); + this.setShowTemplateShop(reader.getAttrAsBoolean(CONTAIN_TEMPLATE_SHOP, true)); this.setContainAction(reader.getAttrAsBoolean("isContainAction", true)); this.setContainTemplate(reader.getAttrAsBoolean("isContainTemplate", true)); this.setContainFileContent(reader.getAttrAsBoolean("isContainFileContent", false)); this.setNeedSegmentationCheckbox(reader.getAttrAsBoolean("needSegmentationCheckbox", true)); this.setNeedIntelligentCustomerService(reader.getAttrAsBoolean("needIntelligentCustomerService", true)); + this.setProductDynamics(reader.getAttrAsBoolean("productDynamics", true)); this.setShortcuts(reader.getAttrAsString("shortcuts", getDefaultShortCuts())); this.setNeedRemind(reader.getAttrAsBoolean("isNeedRemind", true)); this.setOperateCount(reader.getAttrAsInt("operateCount", 0)); + this.setTabOrder(reader.getAttrAsString("tabOrder", getDefaultTabOrder()).split(",")); } else if (reader.isChildNode()) { if (ComparatorUtils.equals(reader.getTagName(), "ActionSearchTextCache")) { readActionSearchTextCacheXML(reader); + } else if ("SearchHistory".equals(reader.getTagName())) { + readHistorySearch(reader); + } else if ("ReadSet".equals(reader.getTagName())) { + readReadSet(reader); } } } @@ -152,6 +196,53 @@ public class AlphaFineConfigManager implements XMLable { }); } + private void readHistorySearch(XMLableReader reader) { + reader.readXMLObject(new XMLReadable() { + @Override + public void readXML(XMLableReader xmLableReader) { + if (ComparatorUtils.equals(reader.getTagName(), "history")) { + String tmpVal = reader.getElementValue(); + if (tmpVal != null) { + tmpVal = tmpVal.replace("[", StringUtils.EMPTY).replace("]", StringUtils.EMPTY); + Stack stack = new SizedStack<>(3); + String[] historyList = tmpVal.split(","); + for (String history : historyList) { + String value = history.trim(); + if (StringUtils.isNotEmpty(value)) { + stack.add(value); + } + } + historySearchMap.put(reader.getAttrAsString("user", StringUtils.EMPTY), stack); + } + } + } + }); + } + + + private void readReadSet(XMLableReader reader) { + reader.readXMLObject(new XMLReadable() { + @Override + public void readXML(XMLableReader xmLableReader) { + if (ComparatorUtils.equals(reader.getTagName(), "readId")) { + String tmpVal = reader.getElementValue(); + if (tmpVal != null) { + tmpVal = tmpVal.replace("[", StringUtils.EMPTY).replace("]", StringUtils.EMPTY); + String[] idArr = tmpVal.split(","); + Set setId = new HashSet<>(); + for (String id : idArr) { + String value = id.trim(); + if (StringUtils.isNotEmpty(value)) { + setId.add(Long.parseLong(value)); + } + } + readSetMap.put(reader.getAttrAsString("user", StringUtils.EMPTY), setId); + } + } + } + }); + } + @Override public void writeXML(XMLPrintWriter writer) { writer.startTAG("AlphaFineConfigManager"); @@ -167,8 +258,13 @@ public class AlphaFineConfigManager implements XMLable { .attr("isNeedRemind", this.isNeedRemind()) .attr("operateCount", this.getOperateCount()) .attr("needSegmentationCheckbox", this.isNeedSegmentationCheckbox()) - .attr("needIntelligentCustomerService", this.isNeedIntelligentCustomerService()); + .attr("needIntelligentCustomerService", this.isNeedIntelligentCustomerService()) + .attr("productDynamics", this.isProductDynamics()) + .attr(CONTAIN_TEMPLATE_SHOP, this.showTemplateShop) + .attr("tabOrder", this.getTabOrderString()); writeActionSearchTextCacheXML(writer); + writeSearchHistory(writer); + writeReadSet(writer); writer.end(); } @@ -183,6 +279,22 @@ public class AlphaFineConfigManager implements XMLable { writer.end(); } + private void writeSearchHistory(XMLPrintWriter writer) { + writer.startTAG("SearchHistory"); + for (Map.Entry> entry : historySearchMap.entrySet()) { + writer.startTAG("history").attr("user", entry.getKey()).textNode(entry.getValue().toString()).end(); + } + writer.end(); + } + + private void writeReadSet(XMLPrintWriter writer) { + writer.startTAG("ReadSet"); + for (Map.Entry> entry : readSetMap.entrySet()) { + writer.startTAG("readId").attr("user", entry.getKey()).textNode(entry.getValue().toString()).end(); + } + writer.end(); + } + public boolean isSearchOnLine() { return searchOnLine; } @@ -212,6 +324,13 @@ public class AlphaFineConfigManager implements XMLable { return OperatingSystem.isMacOS() ? "meta + D" : "ctrl + D"; } + /** + * 返回默认排序 + */ + private String getDefaultTabOrder() { + return AlphaFineConstants.PRODUCT_NEWS + COMMA + AlphaFineConstants.TEMPLATE_SHOP + COMMA + AlphaFineConstants.HELP + COMMA + AlphaFineConstants.PLUGIN + COMMA + AlphaFineConstants.FUNCTION + COMMA + AlphaFineConstants.MY_TEMPLATES; + } + public boolean isContainAction() { return containAction; } @@ -228,6 +347,14 @@ public class AlphaFineConfigManager implements XMLable { this.containDocument = containDocument; } + public boolean isContainMyTemplate() { + return containMyTemplate; + } + + public void setContainMyTemplate(boolean containMyTemplate) { + this.containMyTemplate = containMyTemplate; + } + public boolean isContainTemplate() { return containTemplate; } @@ -335,4 +462,61 @@ public class AlphaFineConfigManager implements XMLable { public void setCacheBuildNO(@NotNull String cacheBuildNO) { this.cacheBuildNO = cacheBuildNO; } + + public Stack getHistorySearch() { + return historySearchMap.computeIfAbsent(DesignerEnvManager.getEnvManager().getDesignerLoginUsername(), k -> new SizedStack<>(3)); + } + + public Set getReadSet() { + return readSetMap.computeIfAbsent(DesignerEnvManager.getEnvManager().getDesignerLoginUsername(), k -> new HashSet<>()); + } + + public boolean isProductDynamics() { + return productDynamics && FRContext.isChineseEnv(); + } + + public void setProductDynamics(boolean productDynamics) { + this.productDynamics = productDynamics; + } + + public boolean hasTemplateShop() { + return showTemplateShop && FRContext.isChineseEnv(); + } + + public void setShowTemplateShop(boolean showTemplateShop) { + this.showTemplateShop = showTemplateShop; + } + + /** + * 是否展示alphafine窗口,设置-搜索范围 0勾选,则不显示 + */ + public boolean needShowAlphaFineDialog() { + return hasTemplateShop() || isContainDocument() || isContainPlugin() || + isContainAction() || isProductDynamics() || isContainMyTemplate(); + } + + /** + * 返回tab显示顺序 + */ + public String[] getTabOrder() { + if (tabOrder == null) { + tabOrder = getDefaultTabOrder().split(COMMA); + } + return tabOrder; + } + + public void setTabOrder(String[] tabOrder) { + this.tabOrder = tabOrder; + } + + /** + * getTabOrder的tostring + */ + public String getTabOrderString() { + StringBuilder sb = new StringBuilder(); + for (String s : getTabOrder()) { + sb.append(s + COMMA); + } + return sb.toString(); + } } diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java index 5bf0214e02..dcc20f6ea7 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java @@ -1,23 +1,41 @@ package com.fr.design.actions.help.alphafine; import com.fr.base.FRContext; +import com.fr.base.svg.IconUtils; import com.fr.design.DesignerEnvManager; +import com.fr.design.actions.help.alphafine.component.CustomSortPane; +import com.fr.design.constants.UIConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; -import javax.swing.*; -import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; /** * Created by XiaXiang on 2017/4/6. @@ -25,39 +43,32 @@ import java.awt.event.MouseEvent; public class AlphaFineConfigPane extends BasicPane { private static final String TYPE = "pressed"; private static final String DISPLAY_TYPE = "+"; - private static final String BACK_SLASH = "BACK_SLASH"; - private static final String DISPLAY_BACK_SLASH = "\\"; - private static final String SLASH = "SLASH"; - private static final String DISPLAY_SLASH = "/"; - private static final String CONTROL = "CONTROL"; - private static final String DISPLAY_CONTROL = "ctrl"; - private static final String OPEN_BRACKET = "OPEN_BRACKET"; - private static final String DISPLAY_OPEN_BRACKET = "{"; - private static final String CLOSE_BRACKET = "CLOSE_BRACKET"; - private static final String DISPLAY_CLOSE_BRACKET = "}"; - private static final String COMMA = "COMMA"; - private static final String DISPLAY_COMMA = ","; - private static final String PERIOD = "PERIOD"; - private static final String DISPLAY_PERIOD = "."; - private static final String SEMICOLON = "SEMICOLON"; - private static final String DISPLAY_SEMICOLON = ";"; - private static final String QUOTE = "QUOTE"; - private static final String DISPLAY_QUOTE = "'"; - private static final String EQUALS = "EQUALS"; - private static final String DISPLAY_EQUALS = "+"; - private static final String MINUS = "MINUS"; - private static final String DISPLAY_MINUS = "-"; - private static final String COMMAND = "META"; - private static final String SMALL_COMMAND = "meta"; - private static final String DISPLAY_COMMAND = "\u2318"; - - - private static final double COLUMN_GAP = 180; - private static final double ROW_GAP = 25; + private static final Color LABEL_TEXT = new Color(0x919193); + + private static final int SEARCH_CONFIG_PANE_HEIGHT = 70; + private static final int SEARCH_CONFIG_PANE_WIDTH = 87; + private static final double COLUMN_WIDTH = 150; + private static final double ROW_HEIGHT = 25; private KeyStroke shortCutKeyStore = null; - private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox, needIntelligentCustomerService, containRecommendCheckbox, containActionCheckbox, containDocumentCheckbox, containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox; + private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox; + private UICheckBox productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox, + containPluginCheckbox, containActionCheckbox, containMyTemplateCheckbox; + // 自定义排序按钮 + private ActionLabel customSortLabel; private UITextField shortcutsField; + + + // 当前tab排序。点击确定后会保存到配置文件中 + private String[] currentOrder; + + + // 搜索范围-我的模板,相关组件 + private JPanel containMyTemplatePane; + private JButton myTemplateSearchConfigButton; + private UIPopupMenu myTemplateSearchMenu; + private UICheckBox containTemplateNameSearchCheckbox, containFileContentSearchCheckbox; + public AlphaFineConfigPane() { this.initComponents(); } @@ -70,16 +81,6 @@ public class AlphaFineConfigPane extends BasicPane { createSearchConfigPane(contentPane); this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.add(contentPane, BorderLayout.NORTH); - - } - - private Component[][] initSearchRangeComponents() { - Component[][] components = new Component[][]{ - new Component[]{containRecommendCheckbox, containActionCheckbox, containDocumentCheckbox}, - new Component[]{containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox}, - new Component[]{needIntelligentCustomerService, null, null} - }; - return components; } private Component[][] initOnlineComponents() { @@ -89,24 +90,143 @@ public class AlphaFineConfigPane extends BasicPane { return components; } + // 搜索范围 private void createSearchConfigPane(JPanel contentPane) { - double[] rowSize = {ROW_GAP, ROW_GAP, ROW_GAP}; + double[] rowSize = {ROW_HEIGHT, ROW_HEIGHT, ROW_HEIGHT}; + double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH}; - double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP}; - - JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Search_Range")); - containRecommendCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Recommend")); - containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set")); + JPanel searchConfigWrapperPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Search_Range")); + // 搜索选项 + productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News")); + containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Function")); containPluginCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon")); containDocumentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help")); - containTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Templates")); - containFileContentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content")); - needIntelligentCustomerService = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Intelligent_Customer_Service")); + containMyTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_My_Templates")); + containFileContentSearchCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content")); + containTemplateShopCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Shop")); + containMyTemplateCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_My_Templates")); JPanel searchConfigPane = TableLayoutHelper.createTableLayoutPane(initSearchRangeComponents(), rowSize, columnSize); - northPane.add(searchConfigPane); - contentPane.add(northPane); + + // 自定义排序 + JPanel customSortWrapperPane = new JPanel(); + customSortWrapperPane.setPreferredSize(new Dimension(SEARCH_CONFIG_PANE_HEIGHT, SEARCH_CONFIG_PANE_WIDTH)); + customSortWrapperPane.setAlignmentY(JPanel.TOP_ALIGNMENT); + customSortLabel = new ActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Config_Custom_Sort"), false); + customSortLabel.setForeground(UIConstants.NORMAL_BLUE); + customSortLabel.addActionListener((event)->{ + if (customSortLabel.isEnabled()) { + openCustomSortMenu(); + } + }); + customSortWrapperPane.add(customSortLabel); + if (!hasSelectedSearchRangeCheckBox()) { + customSortLabel.setEnabled(false); + } + + searchConfigWrapperPane.add(searchConfigPane); + searchConfigWrapperPane.add(customSortWrapperPane); + contentPane.add(searchConfigWrapperPane); + } + + /** + * 打开自定义排序面板 + * */ + private void openCustomSortMenu() { + CustomSortPane customSortPane = new CustomSortPane(getSelectedSearchRangeCheckBox(), this); + JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.add(customSortPane); + GUICoreUtils.showPopupMenu(popupMenu, customSortLabel, 0, customSortLabel.getHeight()); + } + + + private Component[][] initSearchRangeComponents() { + // 我的模板checkbox设置,点击后 + initMyTemplateSearchPane(); + + Component[][] components = new Component[][]{ + new Component[]{productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox}, + new Component[]{containPluginCheckbox, containActionCheckbox, containMyTemplatePane}, + }; + + // 添加选项点事件,无选中选项时自定排序按钮置灰 + UICheckBox[] checkBoxes = new UICheckBox[]{productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox, containPluginCheckbox, containActionCheckbox, containMyTemplateCheckbox}; + for (UICheckBox box : checkBoxes) { + box.addActionListener((e)->{ + customSortLabel.setEnabled(hasSelectedSearchRangeCheckBox()); + }); + } + return components; + } + + /** + * 【搜索范围】中的复选框有无选中的 + * */ + private boolean hasSelectedSearchRangeCheckBox() { + return productDynamicsCheckbox.isSelected() || containTemplateShopCheckbox.isSelected() || containDocumentCheckbox.isSelected() + || containPluginCheckbox.isSelected() || containActionCheckbox.isSelected() || containMyTemplateCheckbox.isSelected(); } + /** + * 获取当前选中的搜索范围选项 + * */ + private List getSelectedSearchRangeCheckBox() { + List res = new ArrayList<>(); + UICheckBox[] checkBoxes = new UICheckBox[]{productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox, containPluginCheckbox, containActionCheckbox, containMyTemplateCheckbox}; + for (UICheckBox c : checkBoxes) { + if (c.isSelected()) { + res.add(c); + } + } + return res; + } + + /** + * 搜索范围-我的模板 + */ + private void initMyTemplateSearchPane() { + containMyTemplatePane = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 5)); + containMyTemplateCheckbox.setBorder(BorderFactory.createEmptyBorder()); + containMyTemplateCheckbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (containMyTemplateCheckbox.isSelected()) { + myTemplateSearchConfigButton.setVisible(true); + } else { + myTemplateSearchConfigButton.setVisible(false); + } + } + }); + myTemplateSearchConfigButton = new JButton(); + myTemplateSearchConfigButton.setBorder(BorderFactory.createEmptyBorder()); + myTemplateSearchConfigButton.setMargin(new Insets(0, 0, 0, 0)); + myTemplateSearchConfigButton.setIcon(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/config.svg")); + myTemplateSearchMenu = new UIPopupMenu(); + containTemplateNameSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Name_Search")); + containFileContentSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Content_Search")); + containTemplateNameSearchCheckbox.setSelected(true); + containTemplateNameSearchCheckbox.setEnabled(false); + containTemplateNameSearchCheckbox.setBackground(null); + containFileContentSearchCheckbox.setBackground(null); + myTemplateSearchMenu.add(containTemplateNameSearchCheckbox); + myTemplateSearchMenu.add(containFileContentSearchCheckbox); + myTemplateSearchConfigButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + GUICoreUtils.showPopupMenu(myTemplateSearchMenu, containMyTemplatePane, containMyTemplateCheckbox.getWidth(), containMyTemplatePane.getY()); + } + + @Override + public void mouseMoved(MouseEvent e) { + super.mouseMoved(e); + myTemplateSearchMenu.setVisible(false); + } + }); + containMyTemplatePane.add("containMyTemplateCheckbox", containMyTemplateCheckbox); + containMyTemplatePane.add("myTemplateSearchConfigButton", myTemplateSearchConfigButton); + } + + private void createShortcutsPane(JPanel contentPane) { JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Shortcut_Config")); shortcutsField = new UITextField(); @@ -117,7 +237,7 @@ public class AlphaFineConfigPane extends BasicPane { northPane.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open") + ":")); northPane.add(shortcutsField); UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_SetShortcuts")); - label.setForeground(Color.RED); + label.setForeground(LABEL_TEXT); northPane.add(label); contentPane.add(northPane); } @@ -139,7 +259,7 @@ public class AlphaFineConfigPane extends BasicPane { int keyCode = e.getKeyCode(); shortCutKeyStore = KeyStroke.getKeyStroke(keyCode, modifier); String str = shortCutKeyStore.toString(); - shortcutsField.setText(getDisplayShortCut(str)); + shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(str)); shortcutsField.selectAll(); } }); @@ -153,24 +273,24 @@ public class AlphaFineConfigPane extends BasicPane { @Override public void actionPerformed(ActionEvent e) { if (!searchOnlineCheckbox.isSelected()) { - containRecommendCheckbox.setEnabled(false); + productDynamicsCheckbox.setEnabled(false); containPluginCheckbox.setEnabled(false); containDocumentCheckbox.setEnabled(false); - needIntelligentCustomerService.setEnabled(false); - containRecommendCheckbox.setSelected(false); + containTemplateShopCheckbox.setEnabled(false); + productDynamicsCheckbox.setSelected(false); containPluginCheckbox.setSelected(false); containDocumentCheckbox.setSelected(false); - needIntelligentCustomerService.setSelected(false); + containTemplateShopCheckbox.setSelected(false); } else { - containRecommendCheckbox.setEnabled(true); + productDynamicsCheckbox.setEnabled(true); containPluginCheckbox.setEnabled(true); containDocumentCheckbox.setEnabled(true); - needIntelligentCustomerService.setEnabled(true); + containTemplateShopCheckbox.setEnabled(true); } } }); - double[] rowSize = {ROW_GAP}; - double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP}; + double[] rowSize = {ROW_HEIGHT}; + double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH}; JPanel onlinePane = TableLayoutHelper.createTableLayoutPane(initOnlineComponents(), rowSize, columnSize); northPane.add(onlinePane); contentPane.add(northPane); @@ -198,8 +318,10 @@ public class AlphaFineConfigPane extends BasicPane { this.searchOnlineCheckbox.setSelected(enabled4Locale); this.containActionCheckbox.setSelected(alphaFineConfigManager.isContainAction()); - this.containTemplateCheckbox.setSelected(alphaFineConfigManager.isContainTemplate()); - this.containFileContentCheckbox.setSelected(alphaFineConfigManager.isContainFileContent()); + + this.containMyTemplateCheckbox.setSelected(alphaFineConfigManager.isContainMyTemplate()); + this.myTemplateSearchConfigButton.setVisible(alphaFineConfigManager.isContainMyTemplate()); + this.containFileContentSearchCheckbox.setSelected(alphaFineConfigManager.isContainFileContent()); this.containDocumentCheckbox.setSelected(alphaFineConfigManager.isContainDocument() && enabled4Locale); this.containDocumentCheckbox.setEnabled(enabled4Locale); @@ -207,17 +329,25 @@ public class AlphaFineConfigPane extends BasicPane { this.containPluginCheckbox.setSelected(alphaFineConfigManager.isContainPlugin() && enabled4Locale); this.containPluginCheckbox.setEnabled(enabled4Locale); - this.containRecommendCheckbox.setSelected(alphaFineConfigManager.isContainRecommend() && enabled4Locale); - this.containRecommendCheckbox.setEnabled(enabled4Locale); + this.productDynamicsCheckbox.setSelected(alphaFineConfigManager.isProductDynamics() && enabled4Locale); + this.productDynamicsCheckbox.setEnabled(enabled4Locale); - this.shortcutsField.setText(getDisplayShortCut(alphaFineConfigManager.getShortcuts())); + this.containTemplateShopCheckbox.setSelected(alphaFineConfigManager.hasTemplateShop() && enabled4Locale); + this.containTemplateShopCheckbox.setEnabled(enabled4Locale); - this.needSegmentationCheckbox.setSelected(alphaFineConfigManager.isNeedSegmentationCheckbox()); + this.shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(alphaFineConfigManager.getShortcuts())); - this.needIntelligentCustomerService.setSelected(alphaFineConfigManager.isNeedIntelligentCustomerService() && enabled4Locale); - this.needIntelligentCustomerService.setEnabled(enabled4Locale); + this.needSegmentationCheckbox.setSelected(alphaFineConfigManager.isNeedSegmentationCheckbox()); shortCutKeyStore = convert2KeyStroke(alphaFineConfigManager.getShortcuts()); + + this.currentOrder = alphaFineConfigManager.getTabOrder().clone(); + + if (!hasSelectedSearchRangeCheckBox()) { + customSortLabel.setEnabled(false); + } else { + customSortLabel.setEnabled(true); + } } public void update() { @@ -226,14 +356,17 @@ public class AlphaFineConfigPane extends BasicPane { alphaFineConfigManager.setContainPlugin(this.containPluginCheckbox.isSelected()); alphaFineConfigManager.setContainAction(this.containActionCheckbox.isSelected()); alphaFineConfigManager.setContainDocument(this.containDocumentCheckbox.isSelected()); - alphaFineConfigManager.setContainRecommend(this.containRecommendCheckbox.isSelected()); + alphaFineConfigManager.setProductDynamics(this.productDynamicsCheckbox.isSelected()); + alphaFineConfigManager.setShowTemplateShop(this.containTemplateShopCheckbox.isSelected()); alphaFineConfigManager.setEnabled(this.enabledCheckbox.isSelected()); alphaFineConfigManager.setSearchOnLine(this.searchOnlineCheckbox.isSelected()); - alphaFineConfigManager.setContainTemplate(this.containTemplateCheckbox.isSelected()); - alphaFineConfigManager.setContainFileContent(this.containFileContentCheckbox.isSelected()); + alphaFineConfigManager.setContainMyTemplate(this.containMyTemplateCheckbox.isSelected()); + alphaFineConfigManager.setContainFileContent(this.containFileContentSearchCheckbox.isSelected()); alphaFineConfigManager.setNeedSegmentationCheckbox(this.needSegmentationCheckbox.isSelected()); - alphaFineConfigManager.setNeedIntelligentCustomerService(this.needIntelligentCustomerService.isSelected()); alphaFineConfigManager.setShortcuts(shortCutKeyStore != null ? shortCutKeyStore.toString().replace(TYPE, DISPLAY_TYPE) : this.shortcutsField.getText()); + alphaFineConfigManager.setTabOrder(currentOrder); + + designerEnvManager.setAlphaFineConfigManager(alphaFineConfigManager); try { DesignerEnvManager.loadLogSetting(); @@ -245,13 +378,6 @@ public class AlphaFineConfigPane extends BasicPane { } - private String getDisplayShortCut(String shortCut) { - return shortCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH) - .replace(CONTROL, DISPLAY_CONTROL).replace(OPEN_BRACKET, DISPLAY_OPEN_BRACKET).replace(CLOSE_BRACKET, DISPLAY_CLOSE_BRACKET) - .replace(COMMA, DISPLAY_COMMA).replace(PERIOD, DISPLAY_PERIOD).replace(SEMICOLON, DISPLAY_SEMICOLON).replace(QUOTE, DISPLAY_QUOTE) - .replace(EQUALS, DISPLAY_EQUALS).replace(MINUS, DISPLAY_MINUS).replace(COMMAND, DISPLAY_COMMAND).replace(SMALL_COMMAND, DISPLAY_COMMAND); - } - private KeyStroke convert2KeyStroke(String ks) { return KeyStroke.getKeyStroke(ks.replace(DISPLAY_TYPE, TYPE)); @@ -266,10 +392,18 @@ public class AlphaFineConfigPane extends BasicPane { } public UICheckBox getIsContainFileContentCheckbox() { - return containFileContentCheckbox; + return containFileContentSearchCheckbox; } public void setIsContainFileContentCheckbox(UICheckBox isContainFileContentCheckbox) { - this.containFileContentCheckbox = isContainFileContentCheckbox; + this.containFileContentSearchCheckbox = isContainFileContentCheckbox; + } + + public String[] getCurrentOrder() { + return currentOrder; + } + + public void setCurrentOrder(String[] currentOrder) { + this.currentOrder = currentOrder; } } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConstants.java similarity index 55% rename from designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java rename to designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConstants.java index 3946c9cbc2..b723e08b16 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConstants.java @@ -1,13 +1,19 @@ -package com.fr.design.mainframe.alphafine; +package com.fr.design.actions.help.alphafine; import com.fr.base.extension.FileExtension; +import com.fr.base.svg.IconUtils; +import com.fr.design.i18n.Toolkit; import com.fr.design.utils.DesignUtils; -import com.fr.general.CloudCenter; +import com.fr.general.IOUtils; +import javax.swing.Icon; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; /** @@ -15,6 +21,19 @@ import java.util.ArrayList; */ public class AlphaFineConstants { + + public static final String FUNCTION = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Function"); + + public static final String MY_TEMPLATES = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_My_Templates"); + + public static final String PRODUCT_NEWS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News"); + + public static final String HELP = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help"); + + public static final String PLUGIN = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon"); + + public static final String TEMPLATE_SHOP = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Shop"); + public static final int SHOW_SIZE = 5; public static final int MAX_FILE_SIZE = 1000; @@ -33,7 +52,7 @@ public class AlphaFineConstants { public static final int CONTENT_HEIGHT = 405; - public static final int CELL_HEIGHT = 32; + public static final int CELL_HEIGHT = 29; public static final int CELL_TITLE_HEIGHT = 24; @@ -41,6 +60,15 @@ public class AlphaFineConstants { public static final int HOT_ITEMS = 6; + /** + * 限制搜索字符长度 + */ + public static final int LEN_LIMIT = 50; + + /** + * 帮助文档搜索间隔(ms) api限制了1s之内只能搜索一次 + */ + public static final long DOCUMENT_SEARCH_GAP = 1000; public static final Dimension FULL_SIZE = new Dimension(680, 460); @@ -54,10 +82,17 @@ public class AlphaFineConstants { public static final Dimension HOT_ISSUES_JAPNEL_SIZE = new Dimension(213, 182); + /** + * 展示面板的尺寸 + */ + public static final Dimension PREVIEW_SIZE = new Dimension(680, 305); + public static final Dimension CLOSE_BUTTON_SIZE = new Dimension(40, 40); public static final Color WHITE = new Color(0xf9f9f9); + public static final Color LABEL_SELECTED = new Color(0x419bf9); + public static final Color GRAY = new Color(0xd2d2d2); public static final Color LIGHT_GRAY = new Color(0xcccccc); @@ -88,60 +123,65 @@ public class AlphaFineConstants { public static final String ALPHA_HOT_IMAGE_NAME = "alphafine_hot"; - public static final String PLUGIN_SEARCH_URL = CloudCenter.getInstance().acquireUrlByKind("plugin.searchAPI"); - - public static final String PLUGIN_URL = CloudCenter.getInstance().acquireUrlByKind("af.pluginInfo"); - - public static final String REUSE_URL = CloudCenter.getInstance().acquireUrlByKind("af.reuseInfo"); + public static final String SPECIAL_CHARACTER_REGEX = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】';:”“’。,、?]"; + public static final String BOTTOM_REGEX_FIRST = "
([\\s\\S]*?)class=\"jiaoyes\">YES
"; - public static final String DOCUMENT_DOC_URL = CloudCenter.getInstance().acquireUrlByKind("af.doc_view"); + public static final String BOTTOM_REGEX_SECOND = "
"; - public static final String DOCUMENT_SEARCH_URL = CloudCenter.getInstance().acquireUrlByKind("af.doc_search"); + public static final String LINK_REGEX = "javascript:;\"([\\s\\S]*?)','"; - public static final String DOCUMENT_INFORMATION_URL = CloudCenter.getInstance().acquireUrlByKind("af.doc_info"); + public static final String LINK_REGEX_ANOTHER = "javascript:([\\s\\S]*?)url=\""; - public static final String PLUGIN_IMAGE_URL = CloudCenter.getInstance().acquireUrlByKind("af.plugin_image"); + public static final String ALPHA_ROBOT_SEARCH_TOKEN = "K8dl0Np6l0gs"; - public static final String CLOUD_SERVER_URL = CloudCenter.getInstance().acquireUrlByKind("af.record"); + public static final String SEARCH_BY_ID = "?id="; - public static final String SEARCH_API = CloudCenter.getInstance().acquireUrlByKind("af.cloud_search"); + public static final String JAVASCRIPT_PREFIX = "javascript:SendJava"; - public static final String SPECIAL_CHARACTER_REGEX = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】';:”“’。,、?]"; + public static final String CHINESE_CHARACTERS = "[\\u4e00-\\u9fa5]"; - public static final String BOTTOM_REGEX_FIRST = "
([\\s\\S]*?)class=\"jiaoyes\">YES
"; + public static final String FIRST_PAGE = "-1"; - public static final String BOTTOM_REGEX_SECOND = "
"; + public static final FileExtension[] FILE_EXTENSIONS = new FileExtension[]{FileExtension.CPT, FileExtension.FRM}; - public static final String LINK_REGEX = "javascript:;\"([\\s\\S]*?)','"; + public static final int RECOMMEND_MAX_ITEM_NUM = 3; - public static final String LINK_REGEX_ANOTHER = "javascript:([\\s\\S]*?)url=\""; + public static final String BACK_ICON_NAME = "back@1x.png"; - public static final String ALPHA_ROBOT_SEARCH_TOKEN = "K8dl0Np6l0gs"; + public static final Icon NO_RESULT_ICON = IOUtils.readIcon(AlphaFineConstants.IMAGE_URL + "noresult.png"); - public static final String SIMILAR_SEARCH_URL_PREFIX = CloudCenter.getInstance().acquireUrlByKind("af.similar_search"); + public static final Color SUSPENDED_COLOR = new Color(84, 165, 249); - public static final String COMPLEMENT_ADVICE_SEARCH_URL_PREFIX = CloudCenter.getInstance().acquireUrlByKind("af.advice_search"); + public static final Color FOREGROUND_COLOR = new Color(51, 51, 52); - public static final String ALPHA_HOT_SEARCH = CloudCenter.getInstance().acquireUrlByKind("af.hot_search"); + /** + * 后面数字代表透明度 80% + */ + public static final Color FOREGROUND_COLOR_8 = new Color(51, 51, 52, 204); - public static final String ALPHA_GO_TO_FORUM = CloudCenter.getInstance().acquireUrlByKind("af.go_fourm"); + public static final Color FOREGROUND_COLOR_6 = new Color(51, 51, 52, 153); - public static final String ALPHA_GO_TO_WEB = CloudCenter.getInstance().acquireUrlByKind("af.go_web"); + public static final Color FOREGROUND_COLOR_5 = new Color(51, 51, 52, 128); - public static final String ALPHA_PREVIEW = CloudCenter.getInstance().acquireUrlByKind("af.preview"); + public static final Color BACKGROUND_COLOR = new Color(245, 245, 247); - public static final String JAVASCRIPT_PREFIX = "javascript:SendJava"; + public static final Icon BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bulb.svg"); - public static final String CHINESE_CHARACTERS = "[\\u4e00-\\u9fa5]"; + public static final Icon YELLOW_BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/yellow_bulb.svg"); - public static final String FIRST_PAGE = "-1"; + public static final Icon LIGHT_YELLOW_BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/light_yellow_bulb.svg"); - public static final FileExtension[] FILE_EXTENSIONS = new FileExtension[]{FileExtension.CPT, FileExtension.FRM}; + public static final String HOT_SEARCH = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search"); - public static final int RECOMMEND_MAX_ITEM_NUM = 3; + public static final Set HOT_SEARCH_SET = new LinkedHashSet<>( + Arrays.asList( + Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_ONE"), + Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_TWO"), + Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_THREE") + ) + ); - public static final String BACK_ICON_NAME = "back@1x.png"; public static final ArrayList CONJUNCTION = new ArrayList() {{ add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Conjunction_HE")); @@ -149,4 +189,11 @@ public class AlphaFineConstants { add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Conjunction_DE")); }}; + public static final String LOADING = "loading"; + + public static final String NETWORK_ERROR = "network error"; + + public static final String TITLE = "AlphaFine"; + + public static final int DEFAULT_CLICK_COUNT = 1; } diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineShortCutUtil.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineShortCutUtil.java new file mode 100644 index 0000000000..e21fc84ee5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineShortCutUtil.java @@ -0,0 +1,44 @@ +package com.fr.design.actions.help.alphafine; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2022/4/26 + */ +public class AlphaFineShortCutUtil { + + private static final String TYPE = "pressed"; + private static final String DISPLAY_TYPE = "+"; + private static final String BACK_SLASH = "BACK_SLASH"; + private static final String DISPLAY_BACK_SLASH = "\\"; + private static final String SLASH = "SLASH"; + private static final String DISPLAY_SLASH = "/"; + private static final String CONTROL = "CONTROL"; + private static final String DISPLAY_CONTROL = "ctrl"; + private static final String OPEN_BRACKET = "OPEN_BRACKET"; + private static final String DISPLAY_OPEN_BRACKET = "{"; + private static final String CLOSE_BRACKET = "CLOSE_BRACKET"; + private static final String DISPLAY_CLOSE_BRACKET = "}"; + private static final String COMMA = "COMMA"; + private static final String DISPLAY_COMMA = ","; + private static final String PERIOD = "PERIOD"; + private static final String DISPLAY_PERIOD = "."; + private static final String SEMICOLON = "SEMICOLON"; + private static final String DISPLAY_SEMICOLON = ";"; + private static final String QUOTE = "QUOTE"; + private static final String DISPLAY_QUOTE = "'"; + private static final String EQUALS = "EQUALS"; + private static final String DISPLAY_EQUALS = "+"; + private static final String MINUS = "MINUS"; + private static final String DISPLAY_MINUS = "-"; + private static final String COMMAND = "META"; + private static final String SMALL_COMMAND = "meta"; + private static final String DISPLAY_COMMAND = "\u2318"; + + public static String getDisplayShortCut(String shortCut) { + return shortCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH) + .replace(CONTROL, DISPLAY_CONTROL).replace(OPEN_BRACKET, DISPLAY_OPEN_BRACKET).replace(CLOSE_BRACKET, DISPLAY_CLOSE_BRACKET) + .replace(COMMA, DISPLAY_COMMA).replace(PERIOD, DISPLAY_PERIOD).replace(SEMICOLON, DISPLAY_SEMICOLON).replace(QUOTE, DISPLAY_QUOTE) + .replace(EQUALS, DISPLAY_EQUALS).replace(MINUS, DISPLAY_MINUS).replace(COMMAND, DISPLAY_COMMAND).replace(SMALL_COMMAND, DISPLAY_COMMAND); + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/SizedStack.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/SizedStack.java new file mode 100644 index 0000000000..fbc6eca00c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/SizedStack.java @@ -0,0 +1,30 @@ +package com.fr.design.actions.help.alphafine; + +import java.util.Stack; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2022/4/23 + */ +public class SizedStack extends Stack { + + private final int maxSize; + + public SizedStack(int size) { + super(); + this.maxSize = size; + } + + @Override + public T push(T object) { + while (this.size() >= maxSize) { + this.remove(0); + } + // 不重复 + if (this.contains(object)) { + return object; + } + return super.push(object); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/CustomSortPane.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/CustomSortPane.java new file mode 100644 index 0000000000..9e2af09379 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/CustomSortPane.java @@ -0,0 +1,229 @@ +package com.fr.design.actions.help.alphafine.component; + +import com.fr.base.svg.IconUtils; +import com.fr.design.actions.help.alphafine.AlphaFineConfigPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.plaf.PanelUI; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * alphafine设置 - 搜索范围 - 自定义排序 - 弹出面板 + * + * @author Link + * @version 11.0 + * Created by Link on 2022/9/18 + */ +public class CustomSortPane extends JPanel { + + + private static final int WIDTH = 147; + private static final int ITEM_HEIGHT = 23; + private static final int GAP = 1; + private static final Color BACKGROUND_COLOR = new Color(0xdadadd); + + private UIButton top; + private UIButton bottom; + private UIButton up; + private UIButton down; + private JPanel toolbarPane; + private MenuLabelPane sortItemPane; + private List sortItems; + private MenuLabel selectedLabel; + private AlphaFineConfigPane parentPane; + + public CustomSortPane(List items, AlphaFineConfigPane parentPane) { + this.sortItems = items; + this.parentPane = parentPane; + setLayout(new BorderLayout(GAP, GAP)); + int height = (sortItems.size() + 1) * (ITEM_HEIGHT + GAP) + GAP; + setPreferredSize(new Dimension(WIDTH, height)); + initComponent(); + add(toolbarPane, BorderLayout.NORTH); + add(sortItemPane, BorderLayout.CENTER); + revalidate(); + this.setVisible(true); + } + + @Override + public void setUI(PanelUI ui) { + super.setUI(ui); + setBackground(BACKGROUND_COLOR); + + } + + private void initComponent() { + createToolbarPane(); + createSortItemPane(); + } + + private void createToolbarPane() { + top = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/top.svg"), false); + bottom = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bottom.svg"), false); + up = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/up.svg"), false); + down = new UIButton(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/down.svg"), false); + top.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/top_disable.svg")); + bottom.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bottom_disable.svg")); + up.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/up_disable.svg")); + down.setDisabledIcon(IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/down_disable.svg")); + top.addActionListener(e -> { + SwingUtilities.invokeLater(() -> { + sortItemPane.setComponentZOrder(selectedLabel, 0); + setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); + CustomSortPane.this.revalidate(); + CustomSortPane.this.repaint(); + refreshCurrentOrder(); + }); + + }); + bottom.addActionListener(e -> { + SwingUtilities.invokeLater(() -> { + sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentCount() - 1); + setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); + CustomSortPane.this.revalidate(); + CustomSortPane.this.repaint(); + refreshCurrentOrder(); + }); + + }); + up.addActionListener(e -> { + SwingUtilities.invokeLater(() -> { + sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentZOrder(selectedLabel) - 1); + setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); + CustomSortPane.this.revalidate(); + CustomSortPane.this.repaint(); + refreshCurrentOrder(); + }); + + }); + down.addActionListener(e -> { + SwingUtilities.invokeLater(() -> { + sortItemPane.setComponentZOrder(selectedLabel, sortItemPane.getComponentZOrder(selectedLabel) + 1); + setToolbarEnable(sortItemPane.getComponentZOrder(selectedLabel), sortItemPane.getComponentCount()); + CustomSortPane.this.revalidate(); + CustomSortPane.this.repaint(); + refreshCurrentOrder(); + }); + + }); + toolbarPane = new JPanel(new FlowLayout(FlowLayout.TRAILING, GAP, GAP)); + toolbarPane.setBorder(BorderFactory.createEmptyBorder()); + toolbarPane.add(top); + toolbarPane.add(bottom); + toolbarPane.add(up); + toolbarPane.add(down); + } + + private void createSortItemPane() { + String[] currentTabOrder = parentPane.getCurrentOrder(); + Map sortMap = new HashMap<>(); + for (int i = 0; i < currentTabOrder.length; i++) { + sortMap.put(currentTabOrder[i], i); + } + List sortLabels = new ArrayList<>(); + for (UICheckBox item : sortItems) { + MenuLabel label = new MenuLabel(item.getText(), (Function) o -> { + selectedLabel = o; + disableButton(); + return null; + }); + sortLabels.add(label); + } + sortLabels.sort(Comparator.comparingInt(tab -> sortMap.get(tab.getText()))); + sortItemPane = new MenuLabelPane(sortLabels); + } + + /** + * 如果选中第一个和最后一个,则置灰向上和向下的按钮 + */ + private void disableButton() { + int order = sortItemPane.getComponentZOrder(selectedLabel); + if (order == 0) { + setToolbarEnable(false, false, true, true); + } else if (order == sortItemPane.getComponentCount() - 1) { + setToolbarEnable(true, true, false, false); + } else { + setToolbarEnable(true, true, true, true); + } + } + + /** + * 设置 置顶,上移,下移,置底 按钮的状态 + * true:启用 + * false:关闭 + */ + private void setToolbarEnable(boolean top, boolean up, boolean down, boolean bottom) { + this.top.setEnabled(top); + this.up.setEnabled(up); + this.down.setEnabled(down); + this.bottom.setEnabled(bottom); + } + + /** + * 根据选项当前位置以及菜单大小设置 置顶,上移,下移,置底 按钮的状态 + */ + private void setToolbarEnable(int order, int maxOrder) { + this.top.setEnabled(true); + this.up.setEnabled(true); + this.down.setEnabled(true); + this.bottom.setEnabled(true); + // 选项处于顶端,则置灰上移和置顶按钮 + if (order == 0) { + this.top.setEnabled(false); + this.up.setEnabled(false); + } + // 选项处于底端,则置灰下移和置底按钮 + if (order == maxOrder - 1) { + this.down.setEnabled(false); + this.bottom.setEnabled(false); + } + } + + private void refreshCurrentOrder() { + String[] currentTabOrder = parentPane.getCurrentOrder(); + HashSet selectedTab = new HashSet<>(); + for (UICheckBox item : sortItems) { + selectedTab.add(item.getText()); + } + + // 未选中的tab,保持原排序不变 + Map exTab = new HashMap<>(); + for (int i = 0; i < currentTabOrder.length; i++) { + if (!selectedTab.contains(currentTabOrder[i])) { + exTab.put(currentTabOrder[i], i); + } + } + + // 计算当前排序 + String[] newOrder = new String[currentTabOrder.length]; + Component[] components = sortItemPane.getComponents(); + for (String s : exTab.keySet()) { + newOrder[exTab.get(s)] = s; + } + + int t = 0; + for (int i = 0; i < newOrder.length; i++) { + if (StringUtils.isEmpty(newOrder[i])) { + newOrder[i] = ((MenuLabel) components[t++]).getText(); + } + } + parentPane.setCurrentOrder(newOrder); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabel.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabel.java new file mode 100644 index 0000000000..5f3708ed97 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabel.java @@ -0,0 +1,96 @@ +package com.fr.design.actions.help.alphafine.component; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.utils.DesignUtils; + +import javax.swing.BorderFactory; +import javax.swing.plaf.LabelUI; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.function.Function; + +/** + * 菜单选项label + * + * @author Link + * @version 11.0 + * Created by Link on 2022/9/18 + */ +public class MenuLabel extends UILabel { + + private static final Color BACKGROUND_COLOR = Color.white; + private static final Color SELECTED_COLOR = new Color(0x419BF9); + private static final Color HOVERED_COLOR = new Color(0xd9ebfe); + private static final int HEIGHT = 23; + private static final int WIDTH = 147; + + private MenuLabelPane parentMenu; + private final Function function; + private boolean selected; + + public MenuLabel(String text, Function function) { + super(text); + this.function = function; + setOpaque(true); + addMouseListener(createMouseListener()); + } + + public void setParentMenu(MenuLabelPane menu) { + this.parentMenu = menu; + } + + + @Override + public void setUI(LabelUI ui) { + super.setUI(ui); + this.setBackground(BACKGROUND_COLOR); + this.setBorder(BorderFactory.createEmptyBorder(2, 10, 1, 10)); + this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); + this.setFont(DesignUtils.getDefaultGUIFont().applySize(12)); + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + if (selected) { + parentMenu.setNoneSelected(); + setBackground(SELECTED_COLOR); + function.apply(this); + this.selected = true; + } else { + setBackground(BACKGROUND_COLOR); + this.selected = false; + } + } + + MouseListener createMouseListener() { + return new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + setSelected(true); + } + + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + if (!selected) { + setBackground(HOVERED_COLOR); + } + } + + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + if (!selected) { + setBackground(BACKGROUND_COLOR); + } + } + }; + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabelPane.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabelPane.java new file mode 100644 index 0000000000..929f54837c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/component/MenuLabelPane.java @@ -0,0 +1,34 @@ +package com.fr.design.actions.help.alphafine.component; + +import javax.swing.JPanel; +import java.awt.FlowLayout; +import java.util.List; + +/** + * 简单菜单面板 + * + * @author Link + * @version 11.0 + * Created by Link on 2022/9/18 + */ +public class MenuLabelPane extends JPanel { + + private static final int GAP = 1; + + private List labels; + + public MenuLabelPane(List labels) { + this.labels = labels; + setLayout(new FlowLayout(FlowLayout.CENTER, GAP, GAP)); + for (MenuLabel label : labels) { + label.setParentMenu(this); + add(label); + } + } + + public void setNoneSelected() { + for (MenuLabel label : labels) { + label.setSelected(false); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/actions/help/replace/ITReplaceOperator.java b/designer-base/src/main/java/com/fr/design/actions/help/replace/ITReplaceOperator.java new file mode 100644 index 0000000000..bbaaedd651 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/actions/help/replace/ITReplaceOperator.java @@ -0,0 +1,19 @@ +package com.fr.design.actions.help.replace; + + +/** + * 定义一些底层操作 + * + * @author Destiny.Lin + * @version 11.0 + * created by Destiny.Lin on 2022-09-27 + */ +public interface ITReplaceOperator { + + + /** + * 关闭面板 + */ + void close(); + +} diff --git a/designer-base/src/main/java/com/fr/design/actions/server/GlobalTableDataAction.java b/designer-base/src/main/java/com/fr/design/actions/server/GlobalTableDataAction.java index fdfdc31b5b..1457f0d111 100644 --- a/designer-base/src/main/java/com/fr/design/actions/server/GlobalTableDataAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/server/GlobalTableDataAction.java @@ -88,7 +88,6 @@ public class GlobalTableDataAction extends UpdateAction implements ResponseDataS } protected void renameConnection(final String oldName, final String newName) { - tableDataConfig.renameTableData(oldName, newName); StrategyEventsNotifier.modifyDataSet(DSMapping.ofServerDS(new DsNameTarget(oldName))); } }; diff --git a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java index 140a46579d..22fff0d178 100644 --- a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java +++ b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardFilter.java @@ -27,11 +27,7 @@ public abstract class ClipboardFilter { } public static T cut(T selection) { - - ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); - Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); - providers.addAll(clipboardHandlerProviders); - for (ClipboardHandlerProvider provider : providers) { + for (ClipboardHandlerProvider provider : getClipboardHandlerProviders()) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).cut(selection); } @@ -40,10 +36,7 @@ public abstract class ClipboardFilter { } public static T copy(T selection) { - ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); - Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); - providers.addAll(clipboardHandlerProviders); - for (ClipboardHandlerProvider provider : providers) { + for (ClipboardHandlerProvider provider : getClipboardHandlerProviders()) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).copy(selection); } @@ -52,15 +45,27 @@ public abstract class ClipboardFilter { } public static T paste(T selection) { - ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); - Set providers = manager.getArray(ClipboardHandlerProvider.XML_TAG); - providers.addAll(clipboardHandlerProviders); - - for (ClipboardHandlerProvider provider : providers) { + for (ClipboardHandlerProvider provider : getClipboardHandlerProviders()) { if (provider.support(selection)) { selection = ((ClipboardHandlerProvider) provider).paste(selection); } } return selection; } + + private static Set getClipboardHandlerProviders() { + Set providers = new HashSet<>(); + + for (ClipboardHandlerProvider clipboardHandlerProvider : clipboardHandlerProviders) { + providers.add(clipboardHandlerProvider); + } + + ExtraDesignClassManager manager = PluginModule.getAgent(PluginModule.ExtraDesign); + Set pluginProviders = manager.getArray(ClipboardHandlerProvider.XML_TAG); + for (ClipboardHandlerProvider clipboardHandlerProvider : pluginProviders) { + providers.add(clipboardHandlerProvider); + } + + return providers; + } } diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java b/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java new file mode 100644 index 0000000000..c2e39def91 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java @@ -0,0 +1,28 @@ +package com.fr.design.carton; + +import java.io.File; + +public class CartonFiles { + private File easyCheckerFile; + private File timerCheckerFile; + + public CartonFiles() { + + } + + public File getEasyCheckerFile() { + return easyCheckerFile; + } + + public void setEasyCheckerFile(File easyCheckerFile) { + this.easyCheckerFile = easyCheckerFile; + } + + public File getTimerCheckerFile() { + return timerCheckerFile; + } + + public void setTimerCheckerFile(File timerCheckerFile) { + this.timerCheckerFile = timerCheckerFile; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java new file mode 100644 index 0000000000..39525110b3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java @@ -0,0 +1,161 @@ +package com.fr.design.carton; + +import com.fr.base.SimpleDateFormatThreadSafe; +import com.fr.design.i18n.Toolkit; +import com.fr.json.JSONObject; + +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; + + +public class CartonThreadExecutorPool extends ThreadPoolExecutor { + private static final int MAX_LIVE_TIME = 3000; + private static final int MAX_WORKER_THREADS = 10; + /** + * 开启间隔检测后两次检测的相隔时间ms + */ + private static final long CHECK_INTERVAL_MS = 100; + private final ThreadLocal startReportedStack = new ThreadLocal<>(); + private volatile static CartonThreadExecutorPool cartonThreadExecutorPool; + private static final ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); + private static final SimpleDateFormatThreadSafe simpleDateFormatThreadSafe = new SimpleDateFormatThreadSafe(); + private final static AtomicLong hangCount = new AtomicLong(0); + private Timer timer; + /** + * 一个变量,用于控制easy监测模式的开关 + */ + private boolean easyWitch = false; + + public boolean isEasyWitch() { + return easyWitch; + } + + public void setEasyWitch(boolean easyWitch) { + this.easyWitch = easyWitch; + } + + private static class ThreadInfo { + private ThreadInfo () { + hangNumber = hangCount.getAndAdd(1); + } + private long hangNumber; + private final Thread eventThread = Thread.currentThread(); + private StackTraceElement[] lastReportedStack; + private final long startTime = System.currentTimeMillis(); + public void checkForHang() { + if (timeSoFar() > MAX_LIVE_TIME) { + examineHang(); + } + } + private long timeSoFar() { + return (System.currentTimeMillis() - startTime); + } + + private void examineHang() { + StackTraceElement[] currentStack = eventThread.getStackTrace(); + + if (lastReportedStack!=null && EventDispatchThreadHangMonitor.stacksEqual(currentStack, lastReportedStack)) { + return; + } + lastReportedStack = currentStack; + String stackTrace = EventDispatchThreadHangMonitor.stackTraceToString(currentStack); + JSONObject jsonObject = new JSONObject(); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormatThreadSafe.format(System.currentTimeMillis())); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + hangNumber); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms"); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace); + EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG); + EventDispatchThreadHangMonitor.checkForDeadlock(); + } + } + + /** + * 来自SwingWorker类 + */ + public static ThreadFactory threadFactory = + new ThreadFactory() { + final ThreadFactory defaultFactory = + Executors.defaultThreadFactory(); + @Override + public Thread newThread(final Runnable r) { + Thread thread = + defaultFactory.newThread(r); + thread.setName("SwingWorker-" + + thread.getName()); + thread.setDaemon(true); + return thread; + } + }; + + public static CartonThreadExecutorPool getTimerThreadExecutorPool () { + if (cartonThreadExecutorPool == null) { + synchronized (CartonThreadExecutorPool.class) { + if (cartonThreadExecutorPool == null) { + cartonThreadExecutorPool = + new CartonThreadExecutorPool(MAX_WORKER_THREADS, MAX_WORKER_THREADS, + 10L, TimeUnit.MINUTES, + new LinkedBlockingQueue(),threadFactory + ); + } + } + } + return cartonThreadExecutorPool; + } + + private CartonThreadExecutorPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + simpleDateFormatThreadSafe.applyPattern("yyyy-MM-dd HH:mm:ss"); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) { + super.beforeExecute(t, r); + startReportedStack.set(t.getStackTrace()); + concurrentHashMap.put(t.getId(), new ThreadInfo()); + } + + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + long currentThreadId = Thread.currentThread().getId(); + long runTime = (System.currentTimeMillis() - concurrentHashMap.get(currentThreadId).startTime); + //加~是为了之后输出的时候换行。 + if (isEasyWitch() && runTime > MAX_LIVE_TIME) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormatThreadSafe.format(System.currentTimeMillis())); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + concurrentHashMap.get(currentThreadId).hangNumber); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormatThreadSafe.format(concurrentHashMap.get(currentThreadId).startTime)); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), runTime + "ms"); + EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG); + + } + concurrentHashMap.remove(currentThreadId); + } + + public class Checker extends TimerTask { + @Override + public void run() { + if (cartonThreadExecutorPool == null || concurrentHashMap.isEmpty()) { + return; + } + for (Map.Entry map : concurrentHashMap.entrySet()) { + map.getValue().checkForHang(); + } + } + } + + public void initTimer() { + timer = new Timer("CheckerSwingWorker",true); + timer.schedule(new Checker(), 0, CHECK_INTERVAL_MS); + } + + public void stopTimer() { + if (timer != null) { + timer.cancel(); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java b/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java new file mode 100644 index 0000000000..2c9c2bacae --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java @@ -0,0 +1,45 @@ +package com.fr.design.carton; + + +public class CartonUploadMessage { + private String hangCount; + private String slowTime; + private String threadTime; + private String info; + + public CartonUploadMessage() { + + } + + public String getHangCount() { + return hangCount; + } + + public void setHangCount(String hangCount) { + this.hangCount = hangCount; + } + + public String getSlowTime() { + return slowTime; + } + + public void setSlowTime(String slowTime) { + this.slowTime = slowTime; + } + + public String getThreadTime() { + return threadTime; + } + + public void setThreadTime(String threadTime) { + this.threadTime = threadTime; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java new file mode 100644 index 0000000000..a7bf03b407 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java @@ -0,0 +1,408 @@ +package com.fr.design.carton; + +import com.fr.concurrent.FineExecutors; +import com.fr.design.ui.util.UIUtil; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.SwingUtilities; +import java.awt.EventQueue; +import java.awt.Toolkit; +import java.awt.AWTEvent; +import java.awt.event.WindowEvent; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.text.SimpleDateFormat; +import java.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 参考自git swinghelper + * 用于卡顿检测 + * 主要是两块内容 + * 1.获取eventQueue中每个事件的执行时间 + * 2.用一个Timer定时去检测当前执行任务的线程 + */ + +public final class EventDispatchThreadHangMonitor extends EventQueue { + /** + * 日期事件格式 + */ + private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + public static final EventDispatchThreadHangMonitor INSTANCE = new EventDispatchThreadHangMonitor(); + /** + * 一个timer + */ + private Timer timer; + /** + * 开启间隔检测后两次检测的相隔时间ms + */ + private static final long CHECK_INTERVAL_MS = 100; + /** + * 最大的事件允许执行时间,超过该时间则打印堆栈等相关信息 + */ + private static final long UNREASONABLE_DISPATCH_DURATION_MS = 1500; + /** + * 事件唯一编码,用于方便日志的查看 + */ + private static long hangCount = 0; + /** + * 输出日志所在地址 + */ + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); + /** + * 类似于一个开关,当该值为默认的false启动时,定时任务在窗口开启前都不会对执行的事件进行检查 + */ + private boolean haveShownSomeComponent = false; + /** + * 该链表为主要的实现定时任务的容器,在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表,由post方法remove + */ + private final LinkedList dispatches = new LinkedList(); + /** + * 一个变量,用于控制easy监测模式的开关 + */ + private boolean easyWitch = false; + private static ScheduledExecutorService scheduledExecutorService; + + public boolean isEasyWitch() { + return easyWitch; + } + + public void setEasyWitch(boolean easyWitch) { + this.easyWitch = easyWitch; + } + + /** + * 一个变量,用于记录Timer的开关。 + */ + + public boolean isTimerWitch() { + return timerWitch; + } + + public void setTimerWitch(boolean timerWitch) { + this.timerWitch = timerWitch; + } + + private boolean timerWitch = false; + + private synchronized static long getHangCount() { + return hangCount++; + } + + /** + * @param a can not be null + * @param b can not be null + * @return + */ + public static boolean stacksEqual(@NotNull StackTraceElement[] a, @NotNull StackTraceElement[] b) { + + if (!ArrayUtils.isSameLength(a, b)) { + return false; + } + for (int i = 0; i < a.length; ++i) { + if (!a[i].equals(b[i])) { + return false; + } + } + return true; + } + + /** + * 用于判断是不是特定的堆栈 + */ + public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) { + return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative; + } + + /** + * 用于判断某个堆栈是否在等待另一个事件 + * 取当前堆栈前三层判断是是不是匹配等待堆栈的格式 + */ + public static boolean isWaitingForNextEvent(StackTraceElement[] currentStack) { + + return currentStack != null && currentStack.length >= 3 && + stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true) + && stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false) + && stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false); + } + + /** + * event事件的包装类 + */ + public static class DispatchInfo { + // 上一次被打印的堆栈ou + private StackTraceElement[] lastReportedStack; + //获取执行该事件的线程 + private final Thread eventDispatchThread = Thread.currentThread(); + //在队列中等待执行的事件最后未执行的时间,当有一个事件执行完后就遍历dispatches给该值赋当前时间 + private long lastDispatchTimeMillis = System.currentTimeMillis(); + //事件开始的时间 + private final long startDispatchTimeMillis = System.currentTimeMillis(); + //事件编号 + private long hangNumber; + //构造函数,给当前对象赋一个递增的唯一编号 + public DispatchInfo() { + hangNumber = getHangCount(); + } + //定时调度任务检测的入口,如果执行时间大于设定的值就进入examineHang()方法 + public void checkForHang() { + if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) { + examineHang(); + } + } + //超时堆栈的具体处理 + private void examineHang() { + //获取执行线程的当前堆栈 + StackTraceElement[] currentStack = eventDispatchThread.getStackTrace(); + if (isWaitingForNextEvent(currentStack)) { + return; + } + //某个事件执行时间很长,定时处理时可能会连续打很多个堆栈,对同一个事件的相同堆栈只打一次 + if (lastReportedStack !=null && stacksEqual(lastReportedStack, currentStack)) { + return; + } + String stackTrace = stackTraceToString(currentStack); + lastReportedStack = currentStack; + JSONObject jsonObject = new JSONObject(); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis())); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms"); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace); + outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG); + checkForDeadlock(); + } + //记录连续运行了多长时间 + private long timeSoFar() { + return (System.currentTimeMillis() - lastDispatchTimeMillis); + } + //记录一个事件从被分发到结束的总运行时间 + private long totalTime() { + return (System.currentTimeMillis() - startDispatchTimeMillis); + } + //事件处理完后的时间判断 + public void dispose() { + if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) { + exportCartonLog(true); + } else if (lastReportedStack != null){ + exportCartonLog(false); + } + } + + /** + * + * @param flag 判断一下输出日志时要输出哪个时间 + */ + private void exportCartonLog(boolean flag) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis())); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormat.format(startDispatchTimeMillis)); + if (flag) { + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), timeSoFar() + "ms"); + } else { + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), totalTime() + "ms"); + } + outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG); + } + } + + public static void outPutJournalLog(String message, int flag) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(System.currentTimeMillis()); + String filename = flag == SwitchForSwingChecker.EASY_CHECK_FLAG ? SwitchForSwingChecker.EASY_CHECKER_FILE_NAME: SwitchForSwingChecker.TIMER_CHECKER_FILE_NAME; + String[] split = date.split("-"); + int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]); + String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date); + File dirFile = new File(dirPath); + File file = new File( StableUtils.pathJoin(dirPath, filename)); + try { + if (!file.exists()) { + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + file.createNewFile(); + } + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, true)); + String outputMessage = new StringBuilder(message.replaceAll("~", "\r\n")).append(",").append("\r\n").toString(); + bufferedWriter.write(outputMessage); + bufferedWriter.close(); + } catch (IOException e) { + FineLoggerFactory.getLogger().error("output fail", e); + } + } + + private EventDispatchThreadHangMonitor() { + + } + + /** + * 参考SwingExplorer,在处理模态框时没有做特殊处理,也不会输出卡顿堆栈 + * 原因是SwingExplorer窗口一直有一个监听事件,不断的add,remove。 + * 由于卡顿日志输出的是事件连续执行的时间,所以一个长时间存在的模态框被不断重复的监听事件刷新时间,就不会输出了。 + * 当检测开关打开后,在这里模拟一下监听事件,给个不耗时的任务就可以。 + */ + public void startFilterModalWindow() { + scheduledExecutorService = FineExecutors.newSingleThreadScheduledExecutor(); + scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //不用干事,切个片就可以 + } + }); + } + }, 0, 500, TimeUnit.MILLISECONDS); + } + + public void stopFilterModalWindow() { + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdown(); + } + } + /** + * Sets up a timer to check for hangs frequently. + * 初始化一个Timer + */ + public void initTimer() { + final long initialDelayMs = 0; + final boolean daemon = true; + timer = new Timer("EventDispatchThreadHangMonitor", daemon); + timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS); + } + + /** + * /消除Timer + */ + public void stopTimer() { + if (timer != null) { + timer.cancel(); + } + } + + /** + * /定时执行的任务 + */ + public class HangChecker extends TimerTask { + @Override + public void run() { + synchronized (dispatches) { + //如果链表为空或者窗口还没启开,定时检测就不进行 + if (dispatches.isEmpty() || !haveShownSomeComponent) { + return; + } + dispatches.getLast().checkForHang(); + } + } + } + + /** + * 将swing中默认的EventQueue换成自己的 + */ + public static void initMonitoring() { + UIUtil.invokeLaterIfNeeded(() -> Toolkit.getDefaultToolkit().getSystemEventQueue().push(INSTANCE)); + } + + /** + * Overrides EventQueue.dispatchEvent to call our pre and post hooks either + * side of the system's event dispatch code. + * 重写 + */ + @Override + protected void dispatchEvent(AWTEvent event) { + //如果两个开关都没开,那就不走重写方法了 + if (!isEasyWitch() && !isTimerWitch()) { + super.dispatchEvent(event); + } else { + try { + preDispatchEvent(); + super.dispatchEvent(event); + } finally { + postDispatchEvent(); + if (!haveShownSomeComponent && + event instanceof WindowEvent && event.getID() == WindowEvent.WINDOW_OPENED) { + haveShownSomeComponent = true; + } + } + } + } + + /** + * Starts tracking a dispatch. + */ + private synchronized void preDispatchEvent() { + synchronized (dispatches) { + dispatches.addLast(new DispatchInfo()); + } + } + + /** + * Stops tracking a dispatch. + */ + private synchronized void postDispatchEvent() { + synchronized (dispatches) { + DispatchInfo justFinishedDispatch = dispatches.removeLast(); + if (isEasyWitch()) { + justFinishedDispatch.dispose(); + } + //嵌套最深的事件执行完毕后刷新链表中其他事件的lastDispatchTimeMillis + Thread currentEventDispatchThread = Thread.currentThread(); + for (DispatchInfo dispatchInfo : dispatches) { + if (dispatchInfo.eventDispatchThread == currentEventDispatchThread) { + dispatchInfo.lastDispatchTimeMillis = System.currentTimeMillis(); + } + } + } + } + + /** + * 检查死锁 + */ + public static void checkForDeadlock() { + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + long[] threadIds = threadBean.findDeadlockedThreads(); + if (threadIds == null) { + return; + } + FineLoggerFactory.getLogger().warn("deadlock detected involving the following threads:"); + ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, Integer.MAX_VALUE); + for (ThreadInfo info : threadInfos) { + FineLoggerFactory.getLogger().warn("Thread # {} {} ( {} ) waiting on {} held by {} {}", info.getThreadId(), info.getThreadName(), + info.getThreadState(), info.getLockName(), info.getLockOwnerName(), stackTraceToStringForConsole(info.getStackTrace())); + } + } + + public static String stackTraceToString(StackTraceElement[] stackTrace) { + StringBuilder result = new StringBuilder(); + for (StackTraceElement stackTraceElement : stackTrace) { + String indentation = " "; + result.append("~").append(indentation).append(stackTraceElement); + } + return result.toString(); + } + + public static String stackTraceToStringForConsole(StackTraceElement[] stackTrace) { + StringBuilder result = new StringBuilder(); + for (StackTraceElement stackTraceElement : stackTrace) { + String indentation = " "; + result.append("\r\n").append(indentation).append(stackTraceElement); + } + return result.toString(); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java b/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java new file mode 100644 index 0000000000..83d6e24ac8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java @@ -0,0 +1,406 @@ +package com.fr.design.carton; + +import com.fr.decision.webservice.v10.log.download.utils.LogZipUtils; +import com.fr.design.DesignerEnvManager; +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.gui.date.UIDatePicker; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.env.detect.ui.EnvDetectorDialog; +import com.fr.file.FILE; +import com.fr.file.FILEChooserPane; +import com.fr.file.FILEFactory; +import com.fr.file.filter.ChooseFileFilter; +import com.fr.general.GeneralUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import org.jetbrains.annotations.Nullable; +import com.fr.workspace.WorkContext; + + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.filechooser.FileSystemView; +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.Frame; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.text.ParseException; +import java.util.List; +import java.util.Objects; + + +public class FeedbackToolboxDialog extends JDialog { + private UIDatePicker uiDatePicker; + private JPanel generalSettingPanel = null; + private UICheckBox easyCheckerButton = null; + private UICheckBox timerCheckerButton = null; + private UIButton uploadButton = null; + private UILabel exportLogLabel = null; + private final Color backgroundColor = new Color(240, 240, 243, 1); + private final Color lineColor = new Color(192, 192, 192, 120); + private JPanel body = null; + private static final String WORK_SPACE_PATH = "reportlets"; + private static final int BUFFER_SIZE = 2 * 1024; + + public FeedbackToolboxDialog(Frame owner) { + super(owner, Toolkit.i18nText("Fine-Design_Basic_Carton_Feedback_ToolBox")); + setResizable(false); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + createBodyPanel(); + add(body); + setSize(body.getPreferredSize()); + setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem()))); + repaint(); + GUICoreUtils.centerWindow(this); + } + + public void createBodyPanel() { + JPanel body = FRGUIPaneFactory.createBorderLayout_L_Pane(); + body.setBackground(backgroundColor); + JPanel titlePane = createTitlePane(); + JPanel tailPane = createTailPane(); + JPanel midPane = createMidPane(); + JPanel infoPane = createInfoPane(); + body.add(titlePane, BorderLayout.NORTH); + body.add(tailPane, BorderLayout.SOUTH); + body.add(midPane, BorderLayout.CENTER); + midPane.add(infoPane, BorderLayout.NORTH); + Dimension dimension = new Dimension(662, 556); + body.setPreferredSize(dimension); + this.body = body; + } + + private JPanel createInfoPane() { + JPanel northPane = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(2, 10, 10); + UILabel title = new UILabel(); + title.setText(" " + Toolkit.i18nText("Fine-Design_Basic_Carton_Record_Lag_Time") + ": "); + //判断一下当天是否有卡顿日志记录,如果有将日期设置为当天,如果没有设置为空 + boolean cartonExists = SwitchForSwingChecker.isCartonExists(); + if (cartonExists) { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, this); + } else { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, null, this); + } + Dimension dimension = new Dimension(160, 100); + uiDatePicker.setPreferredSize(dimension); + northPane.add(GUICoreUtils.createFlowPane(new Component[]{title, uiDatePicker}, FlowLayout.LEFT)); + exportLogLabel = new UILabel(); + exportLogLabel.setText(Toolkit.i18nText("Fine-Design_Basic_Carton_Export_Carton_Log")); + exportLogLabel.setForeground(UIConstants.FLESH_BLUE); + exportLogLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (exportLogLabel.isEnabled()) { + exportLogFile(); + } + } + + @Override + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + + northPane.add(GUICoreUtils.createFlowPane(exportLogLabel, FlowLayout.RIGHT)); + return northPane; + } + + private void exportLogFile() { + String selectDate = GeneralUtils.objectToString(uiDatePicker.getSelectedItem()); + FILEChooserPane fileChooserPane = FILEChooserPane.getInstance(); + StringBuilder fileName = new StringBuilder(); + fileName.append(selectDate).append(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Log")); + fileChooserPane.setFileNameTextField(fileName.toString(), " "); + fileChooserPane.removeAllFilter(); + fileChooserPane.addChooseFILEFilter(new ChooseFileFilter("zip", Toolkit.i18nText("Fine-Design_Basic_Carton_Compile_File"))); + //默认选择桌面 + FILE desktop = FILEFactory.createFILE(FILEFactory.FILE_PREFIX + FileSystemView.getFileSystemView().getHomeDirectory().getPath()); + fileChooserPane.setCurrentDirectory(desktop); + int chooseResult = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame()); + if (chooseResult == 0) { + FILE selectedFile = fileChooserPane.getSelectedFILE(); + String path = selectedFile.getPath(); + //selectDate 2002-03-09例子 + String[] split = selectDate.split("-"); + int month = Integer.parseInt(split[1]); + String sourceFilePath = StableUtils.pathJoin(SwitchForSwingChecker.JOURNAL_FILE_PATH, split[0], "month-" + month, selectDate); + File sourceFile = new File(sourceFilePath); + if (sourceFile.exists()) { + exportCartonLog(sourceFile, path, sourceFilePath); + } + fileChooserPane.removeAllFilter(); + } + } + + private JPanel createTailPane() { + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor)); + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + { + uploadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_Upload_Carton_Log")); + uploadButton.addActionListener((e) -> { + try { + List list = SwitchForSwingChecker.uploadJournalLog(uiDatePicker.getSelectedDate()); + if (list.isEmpty()) { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine_Design_Basic_Upload_Fail"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } else { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Upload_Success")); + } + } catch (ParseException parseException) { + FineLoggerFactory.getLogger().error("parse error", parseException); + } + + }); + actionsPanel.add(uploadButton, BorderLayout.WEST); + + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.addActionListener((e) -> { + setVisible(false); + EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame()); + envDetectorDialog.setVisible(true); + dispose(); + }); + actionsPanel.add(cancelButton, BorderLayout.EAST); + } + UIButton currencySetButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings")); + currencySetButton.addActionListener((e -> { + createGeneralSettingPanel(); + this.remove(body); + this.add(generalSettingPanel); + setSize(generalSettingPanel.getPreferredSize()); + repaint(); + setVisible(true); + })); + tailPanel.add(actionsPanel, BorderLayout.EAST); + tailPanel.add(currencySetButton, BorderLayout.WEST); + return tailPanel; + } + + private JPanel createTitlePane() { + JPanel titlePane = FRGUIPaneFactory.createBorderLayout_M_Pane(); + titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record")); + uiLabel.setForeground(UIConstants.FLESH_BLUE); + titlePane.add(uiLabel, BorderLayout.WEST); + return titlePane; + } + + private JPanel createMidPane() { + JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + return midPanel; + } + + /** + * 下面是通用设置的面板 + */ + private void createGeneralSettingPanel() { + JPanel generalSettingPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + JPanel tailPaneInGeneralSettings = createTailPaneInGeneralSettings(); + generalSettingPanel.add(tailPaneInGeneralSettings, BorderLayout.SOUTH); + + JPanel titlePaneInGeneralSettings = createTitlePaneInGeneralSettings(); + generalSettingPanel.add(titlePaneInGeneralSettings, BorderLayout.NORTH); + + JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + generalSettingPanel.add(midPanel, BorderLayout.CENTER); + + JPanel infoPane = createInfoPanelInGeneralSettings(); + midPanel.add(infoPane, BorderLayout.NORTH); + + Dimension dimension = new Dimension(662, 556); + generalSettingPanel.setPreferredSize(dimension); + generalSettingPanel.setBackground(backgroundColor); + this.generalSettingPanel = generalSettingPanel; + } + + private JPanel createTitlePaneInGeneralSettings() { + JPanel titlePane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record") + "/"); + uiLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + createBodyPanel(); + remove(generalSettingPanel); + add(body); + setPreferredSize(body.getPreferredSize()); + setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem()))); + repaint(); + setVisible(true); + } + + @Override + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + UILabel uiCurrentLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings")); + uiCurrentLabel.setForeground(UIConstants.FLESH_BLUE); + titlePane.add(GUICoreUtils.createFlowPane(new Component[]{uiLabel, uiCurrentLabel}, FlowLayout.LEFT)); + return titlePane; + } + + private JPanel createTailPaneInGeneralSettings() { + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor)); + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + { + UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Save")); + confirmButton.addActionListener((e) -> { + if (easyCheckerButton.isSelected()) { + SwitchForSwingChecker.startEasyChecker(); + } else { + SwitchForSwingChecker.stopEasyChecker(); + } + if (timerCheckerButton.isSelected()) { + SwitchForSwingChecker.startTimerChecker(); + } else { + SwitchForSwingChecker.stopTimerChecker(); + } + createBodyPanel(); + remove(generalSettingPanel); + add(body); + setPreferredSize(body.getPreferredSize()); + setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem()))); + repaint(); + setVisible(true); + }); + actionsPanel.add(confirmButton, BorderLayout.WEST); + + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.addActionListener((e) -> { + createBodyPanel(); + remove(generalSettingPanel); + add(body); + setPreferredSize(body.getPreferredSize()); + repaint(); + setVisible(true); + + }); + actionsPanel.add(cancelButton, BorderLayout.EAST); + } + tailPanel.add(actionsPanel, BorderLayout.EAST); + return tailPanel; + } + + private JPanel createInfoPanelInGeneralSettings() { + JPanel infoPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(1); + easyCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Operation_Time_Consuming_Detection")); + timerCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Operation_Class_Capture")); + easyCheckerButton.setSelected(SwitchForSwingChecker.isEasyChecker()); + timerCheckerButton.setSelected(SwitchForSwingChecker.isCheckerTimerSwitch()); + infoPane.add(GUICoreUtils.createFlowPane(easyCheckerButton, FlowLayout.LEFT)); + infoPane.add(GUICoreUtils.createFlowPane(timerCheckerButton, FlowLayout.LEFT)); + return infoPane; + } + + @Override + protected void processWindowEvent(WindowEvent e) { + super.processWindowEvent(e); + if (e.getID() == WindowEvent.WINDOW_CLOSING) { + EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame()); + envDetectorDialog.setVisible(true); + } + } + + /** + * 上传和导出卡顿日志的可用化处理,如果没有选择日期就不可用 + */ + public void setSwitches(boolean flag) { + uploadButton.setEnabled(flag); + exportLogLabel.setEnabled(flag); + } + + /** + * 导出卡顿日志到本地或远程服务器WEB-INF下 + * + * @param sourceFile 导出的卡顿日志所在文件夹 + * @param path 文件需要导出到的路径 + * @param sourceFilePath 导出的卡顿日志所在文件夹的路径 + */ + private void exportCartonLog(File sourceFile, String path, String sourceFilePath) { + File[] files = sourceFile.listFiles(); + if (!Objects.isNull(files)) { + try { + if (path.startsWith(WORK_SPACE_PATH)) { + if (WorkContext.getCurrent().isLocal()) { + String curEnvName = DesignerEnvManager.getEnvManager().getCurEnvName(); + DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(curEnvName); + String workspaceInfoPath = workspaceInfo.getPath(); + path = StableUtils.pathJoin(workspaceInfoPath, path); + LogZipUtils.compress(files, path, false); + } else { + String sourceFilePathZip = sourceFilePath + ".zip"; + LogZipUtils.compress(files, sourceFilePathZip, false); + byte[] bytesByFile = getBytesByFile(sourceFilePathZip); + WorkContext.getWorkResource().write(path, bytesByFile); + LogZipUtils.delDir(sourceFilePathZip); + } + } else { + LogZipUtils.compress(files, path, false); + } + FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Report_Exported_Successfully")); + } catch (Exception exception) { + FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Report_Export_Failed"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + FineLoggerFactory.getLogger().error("export file fail", exception); + } + } + } + + /** + * 根据文件地址将文件转换成byte[] + * + * @param pathStr 本地文件目录 + * @return 本地文件转成的byte[] + */ + @Nullable + private static byte[] getBytesByFile(String pathStr) { + File file = new File(pathStr); + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(BUFFER_SIZE); + byte[] b = new byte[BUFFER_SIZE]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + byte[] data = bos.toByteArray(); + bos.close(); + return data; + } catch (Exception e) { + FineLoggerFactory.getLogger().error("reading local file fail", e); + } + return null; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java b/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java new file mode 100644 index 0000000000..f9118d3e11 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java @@ -0,0 +1,36 @@ +package com.fr.design.carton; + +import java.io.File; + +public class MonthlyCartonFile { + private File currentMonthFile; + private File lastMonthFile; + private File nextMonthFile; + public MonthlyCartonFile() { + + } + + public File getCurrentMonthFile() { + return currentMonthFile; + } + + public void setCurrentMonthFile(File currentMonthFile) { + this.currentMonthFile = currentMonthFile; + } + + public File getLastMonthFile() { + return lastMonthFile; + } + + public void setLastMonthFile(File lastMonthFile) { + this.lastMonthFile = lastMonthFile; + } + + public File getNextMonthFile() { + return nextMonthFile; + } + + public void setNextMonthFile(File nextMonthFile) { + this.nextMonthFile = nextMonthFile; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java b/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java new file mode 100644 index 0000000000..683179293e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java @@ -0,0 +1,312 @@ +package com.fr.design.carton; + + +import com.fr.design.i18n.Toolkit; +import com.fr.general.GeneralUtils; +import com.fr.json.JSON; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLReadable; +import com.fr.stable.xml.XMLWriter; +import com.fr.stable.xml.XMLableReader; +import sun.awt.AppContext; + +import javax.swing.SwingWorker; +import java.io.IOException; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Date; +import java.util.Calendar; + +public class SwitchForSwingChecker implements XMLReadable, XMLWriter { + /** + * Designer4Debug类名 + */ + private static final String DEBUG_MAIN_CLASS_NAME = "com.fr.start.Designer4Debug"; + /** + * XML标签 + */ + public static final String XML_TAG = "SwitchForSwingChecker"; + /** + * 定时任务的开关 + */ + private static boolean checkerTimerSwitch = false; + /** + * 简单记录事件执行时间的开关 + */ + private static boolean easyChecker = false; + /** + * 一个标识位用于区分耗时任务时长检测(简单检测)和timer检测 + */ + public static final int TIMER_CHECK_FLAG = 0; + public static final int EASY_CHECK_FLAG = 1; + + /** + * 日志存储地址 + */ + public static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); + public static final String EASY_CHECKER_FILE_NAME = "easy_check_log.csv"; + public static final String TIMER_CHECKER_FILE_NAME = "timer_check_log.csv"; + public static boolean isCheckerTimerSwitch() { + return checkerTimerSwitch; + } + + public static boolean isEasyChecker() { + return easyChecker; + } + + public static volatile SwitchForSwingChecker switchForSwingChecker = new SwitchForSwingChecker(); + + public static SwitchForSwingChecker getInstance() { + return switchForSwingChecker; + } + + public static void startTimerChecker() { + if (!checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.initTimer(); + CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer(); + EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true); + checkerTimerSwitch = true; + if (!easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); + } + } + } + + public static void stopTimerChecker() { + if (checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.stopTimer(); + CartonThreadExecutorPool.getTimerThreadExecutorPool().stopTimer(); + EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(false); + checkerTimerSwitch = false; + if (!easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow(); + } + } + } + + public static void startEasyChecker() { + if (!easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true); + CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true); + easyChecker = true; + if (!checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); + } + } + } + + public static void stopEasyChecker() { + if (easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(false); + CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(false); + easyChecker = false; + if (!checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow(); + } + } + } + + /** + * 获取文件名字以及判断文件是否存在 + */ + private static CartonFiles getFiles(String date) { + String[] split = date.split("-"); + int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]); + String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date); + File file1 = new File(StableUtils.pathJoin(dirPath, EASY_CHECKER_FILE_NAME)); + File file2 = new File(StableUtils.pathJoin(dirPath, TIMER_CHECKER_FILE_NAME)); + File[] files = new File[2]; + files[0] = file1; + files[1] = file2; + CartonFiles cartonFiles = new CartonFiles(); + cartonFiles.setEasyCheckerFile(file1); + cartonFiles.setTimerCheckerFile(file2); + return cartonFiles; + } + + /** + *处理文件 + * 一共四种情况, + * 两个文件都不存在 + * 文件一存在,文件二不存在 + * 文件二存在,文件一不存在 + * 两个文件都存在 + */ + private static List getCartonLog(File easyFile, File timerFile) { + List res = new ArrayList<>(); + List easyFileCartonLog = getEasyFileCartonLog(easyFile); + List timerFileCartonLog = getTimerFileCartonLog(timerFile); + Map easyFileMap = new HashMap<>(); + for (CartonUploadMessage cartonUploadMessage : easyFileCartonLog) { + easyFileMap.put(cartonUploadMessage.getHangCount(), cartonUploadMessage); + res.add(cartonUploadMessage); + } + for (CartonUploadMessage cartonUploadMessage : timerFileCartonLog) { + String hangCount = cartonUploadMessage.getHangCount(); + if (easyFileMap.containsKey(hangCount)) { + cartonUploadMessage.setThreadTime(easyFileMap.get(hangCount).getThreadTime()); + } + res.add(cartonUploadMessage); + } + return res; + } + + private static List getTimerFileCartonLog(File file) { + List res = new ArrayList<>(); + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("["); + BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); + String line1; + while ((line1 = bufferedReader1.readLine()) != null) { + stringBuilder.append(line1); + } + bufferedReader1.close(); + stringBuilder.append("]"); + JSONArray easyCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); + for (Object jsonObject : easyCheckerJSON) { + CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); + JSONObject x = (JSONObject) jsonObject; + cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); + cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"))); + cartonUploadMessage.setThreadTime("undefined"); + //这个跟输出到文件中的格式匹配,参考EventDis里的stackTraceToString方法 + String indentation = " "; + String logMessage = x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info")).replaceAll(indentation, "\r\n "); + cartonUploadMessage.setInfo(logMessage); + res.add(cartonUploadMessage); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error("upload fail", e); + } + return res; + } + + private static List getEasyFileCartonLog(File file) { + List res = new ArrayList<>(); + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("["); + BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); + String line1; + while ((line1 = bufferedReader1.readLine()) != null) { + stringBuilder.append(line1); + } + bufferedReader1.close(); + stringBuilder.append("]"); + JSONArray timerCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); + for (Object jsonObject : timerCheckerJSON) { + JSONObject x = (JSONObject) jsonObject; + CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); + cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); + cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"))); + cartonUploadMessage.setThreadTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"))); + cartonUploadMessage.setInfo("undefined"); + res.add(cartonUploadMessage); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error("upload fail", e); + } + return res; + } + + /** + * /埋点方法上传卡顿信息入口 + date为 2022-09-08的格式 + */ + public static List uploadJournalLog(Date dateTime) { + List res = new ArrayList<>(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + CartonFiles files = getFiles(simpleDateFormat.format(dateTime)); + File easyCheckerFile = files.getEasyCheckerFile(); + File timerCheckerFile = files.getTimerCheckerFile(); + if (easyCheckerFile.exists() && timerCheckerFile.exists()) { + return getCartonLog(easyCheckerFile, timerCheckerFile); + } else if (easyCheckerFile.exists()) { + return getEasyFileCartonLog(easyCheckerFile); + } else if (timerCheckerFile.exists()) { + return getTimerFileCartonLog(timerCheckerFile); + } else { + return res; + } + } + + /** + * 初始化监控任务,主要是替换EventQueue以及SwingWorker执行任务的线程池 + * + */ + public static void initThreadMonitoring () { + String mainClass = System.getProperty("sun.java.command"); + //判断一下,如果是以Designer4Debug启动,就不注册代码,不然会覆盖掉SwingExplorer,导致其无法使用 + if (!StringUtils.equals(mainClass, DEBUG_MAIN_CLASS_NAME)) { + EventDispatchThreadHangMonitor.initMonitoring(); + AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool()); + } + } + + /** + * 判断是否有指定日期的卡顿日志,没有就返回false + */ + public static boolean isCartonExists(Date date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String format = simpleDateFormat.format(date); + Calendar calendar = Calendar.getInstance(); + int month = calendar.get(Calendar.MONTH) + 1; + int year = calendar.get(Calendar.YEAR); + File file = new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month, format)); + return file.exists(); + } + + public static boolean isCartonExists() { + return isCartonExists(new Date()); + } + + private void initSwitchChecker() { + if (easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true); + CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true); + } + if (checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.initTimer(); + CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer(); + EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true); + } + if (easyChecker || checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow(); + } + } + + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + checkerTimerSwitch = reader.getAttrAsBoolean("checkerTimerSwitch", false); + easyChecker = reader.getAttrAsBoolean("easyChecker", false); + } + try { + initSwitchChecker(); + } catch (Throwable t) { + FineLoggerFactory.getLogger().error("read checker attr fail", t); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.attr("checkerTimerSwitch", checkerTimerSwitch); + writer.attr("easyChecker", easyChecker); + writer.end(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/cell/CellRectangleStylePreviewPane.java b/designer-base/src/main/java/com/fr/design/cell/CellRectangleStylePreviewPane.java new file mode 100644 index 0000000000..c0b6a0bc85 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/cell/CellRectangleStylePreviewPane.java @@ -0,0 +1,180 @@ +package com.fr.design.cell; + +import com.fr.base.CellBorderSourceFlag; +import com.fr.base.CellBorderStyle; +import com.fr.base.Style; +import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase; +import com.fr.general.IOUtils; +import com.fr.report.cell.TemplateCellElement; + +import javax.swing.JPanel; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/3 + */ +public class CellRectangleStylePreviewPane extends JPanel { + + private static final BufferedImage transparentBackgroundImage = IOUtils.readImage("/com/fr/design/images/transparent_background.png"); + private final float transparentBackgroundWidth; + private final float transparentBackgroundHeight; + + private static final int ROW_COUNT = 2; + private static final int COLUMN_COUNT = 2; + + private final TemplateCellElement[][] cellElementGrid = new TemplateCellElement[ROW_COUNT][COLUMN_COUNT]; + private final int[][] borderSourceFlags = new int[ROW_COUNT][COLUMN_COUNT]; + private final CellStylePreviewPane[][] cellStylePreviewPaneGrid = new CellStylePreviewPane[ROW_COUNT][COLUMN_COUNT]; + + public CellRectangleStylePreviewPane(boolean supportInnerBorder) { + transparentBackgroundWidth = transparentBackgroundImage.getWidth(null); + transparentBackgroundHeight = transparentBackgroundImage.getHeight(null); + + setLayout(new GridLayout(2, 2)); + setOpaque(false); + setBackground(null); + + for (int r = 0; r < ROW_COUNT; r++) { + for (int c = 0; c < COLUMN_COUNT; c++) { + CellStylePreviewPane pane = new CellStylePreviewPane(c, r, COLUMN_COUNT, ROW_COUNT, false, false); + TemplateCellElement cellElement = DefaultThemedTemplateCellElementCase.createInstance(c, r); + int flags = CellBorderSourceFlag.INVALID_BORDER_SOURCE; + if (supportInnerBorder) { + flags = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r != 0) { + flags |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r != ROW_COUNT - 1) { + flags |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + if (c != 0) { + flags |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c != COLUMN_COUNT - 1) { + flags |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + } + + + pane.setStyle(cellElement.getStyle()); + add(pane); + + cellElementGrid[r][c] = cellElement; + borderSourceFlags[r][c] = flags; + cellStylePreviewPaneGrid[r][c] = pane; + } + } + } + + public void setPlainText(String text) { + cellStylePreviewPaneGrid[0][1].setPaintText(text); + cellStylePreviewPaneGrid[1][1].setPaintText(text); + repaint(); + } + + public void setStyle(Style style, CellBorderStyle borderStyle) { + for (int i = 0; i < ROW_COUNT; i++) { + for (int j = 0; j < COLUMN_COUNT; j++) { + CellStylePreviewPane pane = cellStylePreviewPaneGrid[i][j]; + TemplateCellElement cellElement = cellElementGrid[i][j]; + int flag = borderSourceFlags[i][j]; + cellElement.setStyle(CellBorderSourceFlag.deriveBorderedStyle(style, borderStyle, flag)); + + pane.setStyle(cellElement.getStyle()); + } + } + repaint(); + } + + @Override + public void setPreferredSize(Dimension preferredSize) { + super.setPreferredSize(preferredSize); + int hw = preferredSize.width / 2; + int hh = preferredSize.height / 2; + cellStylePreviewPaneGrid[0][0].setPreferredSize(new Dimension(hw, hh)); + cellStylePreviewPaneGrid[0][1].setPreferredSize(new Dimension(hw, hh)); + cellStylePreviewPaneGrid[1][0].setPreferredSize(new Dimension(hw, hh)); + cellStylePreviewPaneGrid[1][1].setPreferredSize(new Dimension(hw, hh)); + } + + @Override + public Dimension getPreferredSize() { + Dimension d00 = cellStylePreviewPaneGrid[0][0].getPreferredSize(); + Dimension d01 = cellStylePreviewPaneGrid[0][1].getPreferredSize(); + Dimension d10 = cellStylePreviewPaneGrid[1][0].getPreferredSize(); + Dimension d11 = cellStylePreviewPaneGrid[1][1].getPreferredSize(); + + int width = Math.max(d00.width + d01.width, d10.width + d11.width); + int height = Math.max(d00.height + d10.height, d01.height + d11.height); + + return new Dimension(width, height); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.clearRect(0, 0, getWidth(), getHeight()); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + paintTransparentBackground((Graphics2D) g, cellElementGrid[0][0].getStyle()); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + + super.paint(g); + } + + @Override + public Rectangle getBounds() { + return super.getBounds(); + } + + private void paintTransparentBackground(Graphics2D g2d, Style style) { + float alpha = computeTransparentBackgroundAlpha(style); + + float scaleWidth = 1.0F * getWidth() / transparentBackgroundWidth; + float scaleHeight = 1.0F * getHeight() / transparentBackgroundHeight; + float maxScale = Math.max(scaleWidth, scaleHeight); + + if (maxScale <= 1) { + scaleWidth = scaleHeight = 1; + } else { + scaleHeight = scaleWidth = maxScale; + } + + Composite oldComposite = g2d.getComposite(); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + g2d.drawImage(transparentBackgroundImage, 0, 0, (int) (transparentBackgroundWidth * scaleWidth), (int) (transparentBackgroundHeight * scaleHeight), null); + g2d.setComposite(oldComposite); + } + + private float computeTextColorBrightness(Style style) { + Color fontColor = style.getFRFont().getForeground(); + return fontColor.getRed() * 0.299F + fontColor.getGreen() * 0.587F + fontColor.getBlue() * 0.114F; + } + + private float computeTransparentBackgroundAlpha(Style style) { + float textBrightness = computeTextColorBrightness(style); + + float alpha = 1.0F; + if (textBrightness < 50) { + alpha = 0.2F; + } else if (textBrightness < 160){ + alpha = 0.5F; + } + return alpha; + } +} 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 355dca62de..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 @@ -1,18 +1,27 @@ package com.fr.design.cell; +import com.fr.base.BaseUtils; +import com.fr.base.GraphHelper; import com.fr.base.NameStyle; import com.fr.base.ScreenResolution; import com.fr.base.Style; +import com.fr.general.FRFont; import com.fr.general.IOUtils; +import com.fr.stable.Constants; +import com.fr.stable.unit.PT; import javax.swing.JPanel; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Composite; import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.RenderingHints; import java.awt.image.BufferedImage; +import java.util.List; /** * @author Starryi @@ -21,44 +30,69 @@ import java.awt.image.BufferedImage; */ public class CellStylePreviewPane extends JPanel { + public static final int MINIMUM_HEIGHT = 40; private static final BufferedImage transparentBackgroundImage = IOUtils.readImage("/com/fr/design/images/transparent_background.png"); private final float transparentBackgroundWidth; private final float transparentBackgroundHeight; private String paintText = "Report"; private Style style = Style.DEFAULT_STYLE; - public CellStylePreviewPane() { + private final int column; + private final int row; + private final int columnSpan; + private final int rowSpan; + + private final boolean autoClearCanvas; + private final boolean paintingMosaic; + + public CellStylePreviewPane(int column, int row, int columnSpan, int rowSpan, boolean autoClearCanvas, boolean paintingMosaic) { + this.column = column; + this.row = row; + this.columnSpan = columnSpan; + this.rowSpan = rowSpan; + this.autoClearCanvas = autoClearCanvas; + this.paintingMosaic = paintingMosaic; transparentBackgroundWidth = transparentBackgroundImage.getWidth(null); transparentBackgroundHeight = transparentBackgroundImage.getHeight(null); + setPreferredSize(new Dimension(0, 0)); + } + + public void setPaintText(String paintText) { + this.paintText = paintText; + repaint(); } public void setStyle(Style style) { this.style = style; - if (style instanceof NameStyle) { - paintText = ((NameStyle) style).getName(); - } repaint(); } + public void setStyle(NameStyle style) { + paintText = style.getName(); + setStyle(style.getRealStyle()); + } + @Override public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; - g.clearRect(0, 0, getWidth(), getHeight()); + if (autoClearCanvas) { + g2d.clearRect(0, 0, getWidth(), getHeight()); + } + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - paintTransparentBackground(g2d, style); + if (paintingMosaic) { + paintTransparentBackground(g2d, style); + } paintCellStyle(g2d, style); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } private void paintTransparentBackground(Graphics2D g2d, Style style) { - Color fontColor = style.getFRFont().getForeground(); - float g = fontColor.getRed() * 0.299F + fontColor.getGreen() * 0.587F * fontColor.getBlue() * 0.114F; - float alpha = 1.0F; - if (g < 50) { - alpha = 0.2F; - } else if (g < 160){ - alpha = 0.5F; - } + float alpha = computeTransparentBackgroundAlpha(style); float scaleWidth = 1.0F * getWidth() / transparentBackgroundWidth; float scaleHeight = 1.0F * getHeight() / transparentBackgroundHeight; @@ -76,6 +110,23 @@ public class CellStylePreviewPane extends JPanel { g2d.setComposite(oldComposite); } + private float computeTextColorBrightness(Style style) { + Color fontColor = style.getFRFont().getForeground(); + return fontColor.getRed() * 0.299F + fontColor.getGreen() * 0.587F + fontColor.getBlue() * 0.114F; + } + + private float computeTransparentBackgroundAlpha(Style style) { + float textBrightness = computeTextColorBrightness(style); + + float alpha = 1.0F; + if (textBrightness < 50) { + alpha = 0.2F; + } else if (textBrightness < 160){ + alpha = 0.5F; + } + return alpha; + } + private void paintCellStyle(Graphics2D g2d, Style style) { int resolution = ScreenResolution.getScreenResolution(); @@ -92,11 +143,78 @@ public class CellStylePreviewPane extends JPanel { Style.paintContent(g2d, paintText, style, width, height, resolution); - Style.paintBorder(g2d, style, width, height); + paintCellBorder(g2d, style); + } + + protected void paintCellBorder(Graphics2D g2d, Style style) { + float adjustLeft = 0; + float adjustTop = 0; + float adjustRight = 0; + float adjustBottom = 0; + if (column == 0) { + adjustLeft = computeHalfSize4StyledBorder(style.getBorderLeft()); + } + if (row == 0) { + adjustTop = computeHalfSize4StyledBorder(style.getBorderTop()); + } + if (column == columnSpan - 1) { + adjustRight = -computeHalfSize4StyledBorder(style.getBorderRight()); + } + if (row == rowSpan - 1) { + adjustBottom = -computeHalfSize4StyledBorder(style.getBorderBottom()); + } + + g2d.translate(adjustLeft, adjustTop); + Style.paintBorder(g2d, style, getWidth() - adjustLeft + adjustRight, getHeight() - adjustTop + adjustBottom); + g2d.translate(-adjustLeft, -adjustTop); + } + + 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 size; } @Override - public Dimension getMinimumSize() { - return getPreferredSize(); + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + int width = size.width; + int height = size.height; + + if (height != 0) { + // 使用者设置了一个高度 + return size; + } else if (width == 0) { + // 使用者未设置任何尺寸 + return new Dimension(width, MINIMUM_HEIGHT); + } else { + // 使用者设置了宽度,但未设置高度 + return getAutoWrapContentPreferredSize(width, height); + } + } + + private Dimension getAutoWrapContentPreferredSize(int width, int height) { + int resolution = ScreenResolution.getScreenResolution(); + + // 计算文本区域高度 + final FRFont frFont = style.getFRFont(); + final Font rfont = frFont.applyResolutionNP(resolution); + final FontMetrics metrics = GraphHelper.getFontMetrics(rfont); + final int textLineHeight = metrics.getHeight(); + final double textLineSpacing = PT.pt2pix(style.getLineSpacing(), resolution); + + List textLineList = BaseUtils.getLineTextList(paintText, style, rfont, height, width, resolution); + + double textLinesHeight = textLineList.size() * textLineHeight + Math.max(0, textLineList.size() - 1) * textLineSpacing; + + height = (int) Math.max(MINIMUM_HEIGHT, textLinesHeight); + + return new Dimension(width, height); } } diff --git a/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java b/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java new file mode 100644 index 0000000000..25b0fe1816 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/loading/LoadingPane.java @@ -0,0 +1,148 @@ +package com.fr.design.components.loading; + +import javax.swing.JComponent; +import javax.swing.Timer; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Composite; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/4/12 + */ +public class LoadingPane extends JComponent implements ActionListener { + + private AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); + private volatile boolean mIsRunning; + private volatile boolean mIsFadingOut; + private Timer mTimer; + private int mAngle; + private int mFadeCount; + private int mFadeLimit = 15; + private int lines = 12; + private int maxAngle = 360; + private int angleAdd = 30; + + public LoadingPane() { + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + }); + + setLayout(getCoverLayout()); + setBackground(null); + setOpaque(false); + } + + protected LayoutManager getCoverLayout() { + return new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return parent.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }; + } + + + @Override + public void paint(Graphics g) { + int w = this.getWidth(); + int h = this.getHeight(); + super.paint(g); + if (!mIsRunning) { + return; + } + Graphics2D g2 = (Graphics2D) g.create(); + float fade = (float) mFadeCount / (float) mFadeLimit; + Composite urComposite = g2.getComposite(); + g2.setComposite(composite); + g2.fillRect(0, 0, w, h); + g2.setComposite(urComposite); + int s = Math.min(w, h) / 50; + int cx = w / 2; + int cy = h / 2; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.BLACK); + g2.rotate(Math.PI * mAngle / 180, cx, cy); + for (int i = 0; i < lines; i++) { + float scale = (11.0f - (float) i) / 11.0f; + g2.drawLine(cx + s, cy, cx + s * 2, cy); + g2.rotate(-Math.PI / 6, cx, cy); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade)); + } + g2.dispose(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (mIsRunning) { + repaint(); + mAngle += angleAdd; + if (mAngle >= maxAngle) { + mAngle = 0; + } + if (mIsFadingOut) { + if (--mFadeCount == 0) { + mIsRunning = false; + mTimer.stop(); + } + } else if (mFadeCount < mFadeLimit) { + mFadeCount++; + } + } + } + + public void start() { + if (mIsRunning) { + return; + } + mIsRunning = true; + mIsFadingOut = false; + mFadeCount = 0; + int fps = 24; + int tick = 1000 / fps; + mTimer = new Timer(tick, this); + mTimer.start(); + } + + public void stop() { + mIsRunning = false; + mIsFadingOut = true; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java new file mode 100644 index 0000000000..d2f56976e8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java @@ -0,0 +1,21 @@ +package com.fr.design.components.notification; + +/** + * created by Harrison on 2022/05/24 + **/ +public interface NotificationAction { + + /** + * 行为名 + * + * @return 名称 + */ + String name(); + + /** + * 行为动作 + * + * @param args 参数 + */ + void run(Object... args); +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java new file mode 100644 index 0000000000..d9a1cf0c21 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java @@ -0,0 +1,391 @@ +package com.fr.design.components.notification; + +import com.fr.base.function.ThrowableRunnable; +import com.fr.base.svg.IconUtils; +import com.fr.design.components.page.PageControlModel; +import com.fr.design.components.page.PageControlPanel; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.utils.LinkStrUtils; +import com.fr.env.detect.base.EnvDetectorConfig; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Desktop; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * 右下角的提醒 异常提醒 + * 相关使用方式见 提醒组件 + * + * created by Harrison on 2022/05/24 + **/ +public class NotificationDialog extends JDialog { + + /** + * 通知框的内部高度 + */ + private static final int CONTENT_INNER_HEIGHT = 60; + /** + * 通知框如果出现滚动条后的内部宽度 + */ + private static final int CONTENT_SCROLL_WIDTH = 280; + + private static final int CONTENT_WIDTH = 300; + private static final int CONTENT_HEIGHT = 100; + /** + * 通知框的外部宽高 + */ + private static final Dimension CONTENT_SIZE = new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT); + private static final Dimension BUTTON_DIMENSION = new Dimension(68, 20); + + /** + * 标记 LABEL, 没有作用 + */ + private static final UILabel SIGN_LABEL = new UILabel("#"); + /** + * 确认一个 LABEL 的宽高 + */ + private static final Dimension SIGN_LABEL_DIMENSION = SIGN_LABEL.getPreferredSize(); + + private NotificationDialogProperties properties; + + /* 数据 model */ + + private List notificationModels; + private PageControlModel pageControlModel; + + private JPanel body; + private JPanel headerPanel; + private JPanel contentPanel; + private JPanel tailPanel; + + public NotificationDialog(NotificationDialogProperties properties, List notificationModels) { + + super(properties.getOwner()); + setTitle(properties.getTitle()); + this.properties = properties; + + this.notificationModels = notificationModels; + this.pageControlModel = new PageControlModel(0, this.notificationModels.size()); + + initComponents(); + } + + public void initComponents() { + + //UI 配置 + configProperties(); + + this.body = FRGUIPaneFactory.createBorderLayout_L_Pane(); + body.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + //首行 + layoutHeaderPanel(); + + //消息内容 + layoutContentPanel(); + + //查看详情 + layoutTailPanel(); + + add(body); + + Dimension dimension = body.getPreferredSize(); + setSize(dimension.width, dimension.height); + + Container parent = getParent(); + setLocation((parent.getWidth() - dimension.width - 30 + parent.getX()), + parent.getY() + parent.getHeight() - dimension.height - 30); + + } + + public void open() { + + setVisible(true); + } + + private void configProperties() { + + setModal(properties.isModal()); + setFocusable(false); + setAutoRequestFocus(false); + setResizable(false); + } + + protected JPanel createHeaderPanel() { + + return null; + } + + /** + * 内容 + * + * @return 内容面板 + */ + protected JPanel createContentPanel() { + + JPanel contentPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + contentPanel.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10)); + contentPanel.setName("contentPanel"); + + NotificationModel model = getCurrentModel(); + + UILabel icon = new UILabel(getIconForType(model.getType())); + icon.setPreferredSize(new Dimension(16, 16)); + JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 8)); + iconPanel.add(icon, BorderLayout.NORTH); + + contentPanel.add(iconPanel, BorderLayout.WEST); + + JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 5)); + + NotificationMessage[] messages = model.getMessages(); + List messageComponents = Arrays.stream(messages) + .map((messageModel) -> { + if (messageModel.getType() == NotificationMessage.Type.LINK) { + NotificationMessage.LinkMessage linkMessage = (NotificationMessage.LinkMessage) messageModel; + return new MessageWithLink(linkMessage.format(), ThrowableRunnable.toRunnable(() -> { + Desktop.getDesktop().browse(URI.create(linkMessage.getLink())); + })); + } + return new UILabel(LinkStrUtils.generateHtmlTag(messageModel.format())); + }) + .collect(Collectors.toList()); + + // 当高度 大于 60 时,就会出现滚动条。 + // 当出现滚动条时,需要将内部的宽度限制为 280, 否则会展示不出来 + Function calStandardWidth = height -> height > CONTENT_INNER_HEIGHT ? CONTENT_SCROLL_WIDTH : CONTENT_WIDTH; + + int widthUnit = messageComponents.stream() + .map((component) -> { + Dimension preferredSize = component.getPreferredSize(); + double width = preferredSize.getWidth(); + double widthFactor = Math.ceil(width / CONTENT_WIDTH); + // 这里的高度是没有限制宽度的,如果限制宽度,高度会变更,所以这里需要加上宽度的影响 + return preferredSize.getHeight() + widthFactor * SIGN_LABEL_DIMENSION.getHeight(); + }) + .reduce(Double::sum) + .map(calStandardWidth) + .orElse(CONTENT_WIDTH); + + messageComponents = messageComponents.stream() + .peek((component) -> { + Dimension preferredSize = component.getPreferredSize(); + double componentWidth = preferredSize.getWidth(); + double componentHeight = preferredSize.getHeight(); + double heightFactor = Math.ceil(componentHeight / SIGN_LABEL_DIMENSION.getHeight()); + double widthFactor = Math.ceil(componentWidth / widthUnit); + int realHeight = (int)Math.ceil(heightFactor + widthFactor - 1) * (int)(Math.ceil(SIGN_LABEL_DIMENSION.getHeight())); + component.setPreferredSize(new Dimension(widthUnit, realHeight)); + }) + .collect(Collectors.toList()); + + // 竖向排列 + JPanel messageSummaryPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0); + messageComponents.forEach(messageSummaryPanel::add); + + JScrollPane jScrollPane = new JScrollPane(messageSummaryPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane.setBorder(BorderFactory.createEmptyBorder()); + + centerPanel.add(jScrollPane, BorderLayout.CENTER); + centerPanel.setPreferredSize(CONTENT_SIZE); + + contentPanel.add(centerPanel, BorderLayout.CENTER); + + return contentPanel; + } + + /** + * 行动 + * + * UI布局 + * /翻页/不再提醒/提醒行为/我知道了 + * + * @return 行动面板 + */ + protected JPanel createTailPanel() { + + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + tailPanel.setName("tailPanel"); + + // 翻页按钮效果 + PageControlPanel pageControlPanel = new PageControlPanel(pageControlModel); + + pageControlPanel.actions(new Runnable() { + @Override + public void run() { + pageControlModel = pageControlPanel.performPrevious(); + refresh(); + } + }, new Runnable() { + @Override + public void run() { + pageControlModel = pageControlPanel.performNext(); + refresh(); + } + }); + + tailPanel.add(pageControlPanel, BorderLayout.WEST); + + // 行为效果 + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_M_Pane(); + + { + actionsPanel.setBorder(BorderFactory.createEmptyBorder()); + actionsPanel.setName("actionsPanel"); + + UILabel notReminder = new UILabel(); + notReminder.setText(Toolkit.i18nText("Fine-Design_Basic_Not_Reminder")); + notReminder.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // 配置处理 + EnvDetectorConfig.getInstance().setEnabled(false); + // 点击事件 + destroy(); + } + }); + Color color = new Color(65, 155, 249); + notReminder.setForeground(color); + actionsPanel.add(notReminder, BorderLayout.WEST); + + JPanel buttonPanel = FRGUIPaneFactory.createBorderLayout_M_Pane(); + buttonPanel.setBorder(BorderFactory.createEmptyBorder()); + + // real-action + NotificationModel currentModel = getCurrentModel(); + NotificationAction action = currentModel.getAction(); + if (action != null) { + UIButton actionButton = new UIButton(action.name()); + actionButton.setPreferredSize(BUTTON_DIMENSION); + actionButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + action.run(); + } + }); + buttonPanel.add(actionButton, BorderLayout.WEST); + } + + UIButton knowButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Know")); + knowButton.setPreferredSize(BUTTON_DIMENSION); + knowButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (pageControlModel.isLast()) { + destroy(); + return; + } + pageControlModel = pageControlPanel.performNext(); + refresh(); + } + }); + buttonPanel.add(knowButton, BorderLayout.EAST); + + actionsPanel.add(buttonPanel, BorderLayout.EAST); + } + + tailPanel.add(actionsPanel, BorderLayout.EAST); + + return tailPanel; + } + + private void refresh() { + + layoutContentPanel(); + + layoutTailPanel(); + + this.repaint(); + } + + private void layoutHeaderPanel() { + + this.headerPanel = layoutPanel(this.headerPanel, this::createHeaderPanel, BorderLayout.NORTH); + } + + private void layoutTailPanel() { + + this.tailPanel = layoutPanel(this.tailPanel, this::createTailPanel, BorderLayout.SOUTH); + } + + private void layoutContentPanel() { + + this.contentPanel = layoutPanel(this.contentPanel, this::createContentPanel, BorderLayout.CENTER); + } + + private JPanel layoutPanel(JPanel oldPanel, Supplier supplier, Object constraints){ + + if (oldPanel != null) { + this.body.remove(oldPanel); + } + JPanel newPanel = supplier.get(); + if (newPanel != null) { + this.body.add(newPanel, constraints); + } + return newPanel; + } + + private NotificationModel getCurrentModel() { + + int index = pageControlModel.getIndex(); + return notificationModels.get(index); + } + + protected Icon getIconForType(NotificationType type) { + + String iconPath; + switch (type) { + case ERROR: + iconPath = "/com/fr/design/standard/reminder/reminder_error.svg"; + break; + case INFO: + iconPath = "/com/fr/design/standard/reminder/reminder_success.svg"; + break; + case WARNING: + iconPath = "/com/fr/design/standard/reminder/reminder_warning.svg"; + break; + default: + return null; + } + return IconUtils.readIcon(iconPath); + } + + private void destroy() { + + setVisible(false); + dispose(); + } + + @Override + public void dispose() { + + super.dispose(); + // todo + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java new file mode 100644 index 0000000000..5bcff67150 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java @@ -0,0 +1,39 @@ +package com.fr.design.components.notification; + +import java.awt.Frame; + +/** + * 通知会话的属性 + * + * created by Harrison on 2022/05/24 + **/ +public class NotificationDialogProperties { + + private Frame owner; + + private String title; + + private boolean modal; + + public NotificationDialogProperties(Frame owner, String title) { + this.owner = owner; + this.title = title; + this.modal = false; + } + + public void setModal(boolean modal) { + this.modal = modal; + } + + public Frame getOwner() { + return owner; + } + + public String getTitle() { + return title; + } + + public boolean isModal() { + return modal; + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java new file mode 100644 index 0000000000..c107a0fb88 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java @@ -0,0 +1,88 @@ +package com.fr.design.components.notification; + +import com.fr.design.utils.LinkStrUtils; + +/** + * created by Harrison on 2022/05/24 + **/ +public interface NotificationMessage { + + /** + * 格式化 + * + * @return 通知信息 + */ + String format(); + + /** + * 类型 + * + * @return 类型 + */ + Type getType(); + + enum Type { + + /** + * 简单型 + */ + SIMPLE, + + /** + * 链接 + */ + LINK + } + + class SimpleMessage implements NotificationMessage { + + private String text; + + public SimpleMessage(String text) { + this.text = text; + } + + @Override + public String format() { + return text; + } + + @Override + public Type getType() { + return Type.SIMPLE; + } + } + + class LinkMessage implements NotificationMessage { + + private String text; + + private String link; + + public LinkMessage(String text, String link) { + + this.text = text; + this.link = link; + } + + public String getText() { + return text; + } + + public String getLink() { + return link; + } + + @Override + public String format() { + + return LinkStrUtils.generateHtmlTag(text); + } + + @Override + public Type getType() { + + return Type.LINK; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java new file mode 100644 index 0000000000..86d5a9edfd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java @@ -0,0 +1,39 @@ +package com.fr.design.components.notification; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class NotificationModel { + + private final NotificationType type; + private final NotificationMessage[] messages; + + @Nullable + private final NotificationAction action; + + public NotificationModel(NotificationType type, @Nullable NotificationAction action, List messages) { + this(type, action, messages.toArray(new NotificationMessage[0])); + } + + public NotificationModel(NotificationType type, @Nullable NotificationAction action, NotificationMessage... messages) { + + this.type = type; + this.messages = messages; + this.action = action; + } + + public NotificationType getType() { + return type; + } + + public NotificationMessage[] getMessages() { + return messages == null ? new NotificationMessage[0] : messages; + } + + public @Nullable NotificationAction getAction() { + + return action; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java b/designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java new file mode 100644 index 0000000000..0f5ab7b340 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java @@ -0,0 +1,16 @@ +package com.fr.design.components.notification; + +/** + * 提醒类型 + * 决定图标种类 + * + * created by Harrison on 2022/05/27 + **/ +public enum NotificationType { + + INFO, + + ERROR, + + WARNING +} diff --git a/designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java b/designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java new file mode 100644 index 0000000000..3d024fb052 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java @@ -0,0 +1,78 @@ +package com.fr.design.components.page; + +/** + * created by Harrison on 2022/05/26 + **/ +public class PageControlModel { + + /** + * 当前索引 + * + * = (页数-1) + */ + private int index; + + /** + * 总页数 + */ + private int summary; + + public PageControlModel(int index, int summary) { + this.index = index; + this.summary = summary; + } + + public PageControlModel() { + } + + public PageControlModel previous() { + + this.index--; + return this; + } + + public PageControlModel next() { + + this.index++; + return this; + } + + /** + * 页数 + * index+1 + * + * @return 页数 + */ + public int getNumber() { + return index + 1; + } + + public boolean isFirst() { + return getNumber() == 1; + } + + public boolean isLast() { + return getNumber() == getSummary(); + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public int getSummary() { + return summary; + } + + public void setSummary(int summary) { + this.summary = summary; + } + + public String toContent() { + + return getNumber() + "/" + this.summary; + } +} diff --git a/designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java b/designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java new file mode 100644 index 0000000000..cc85028899 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java @@ -0,0 +1,151 @@ +package com.fr.design.components.page; + +import com.fr.base.svg.IconUtils; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.function.Function; + +/** + * 翻页组件 + * 相关使用方式见 翻页组件 + * + * created by Harrison on 2022/05/26 + **/ +public class PageControlPanel extends JPanel { + + private static final long serialVersionUID = 8140501834691131305L; + + private static final Dimension PAGE_CONTROL_BUTTON_DIMENSION = new Dimension(20, 20); + + private UIButton previous; + private Runnable previousAction; + + private UILabel content; + private PageControlModel model; + + private UIButton next; + private Runnable nextAction; + + public PageControlPanel(PageControlModel model) { + + this.model = model; + setBorder(BorderFactory.createEmptyBorder()); + setLayout(new BorderLayout(6, 0)); + + this.previous = new UIButton(); + previous.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION); + previous.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_left.svg")); + previous.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_left.svg")); + previous.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + performAction(previousAction); + } + }); + + this.add(previous, BorderLayout.WEST); + + this.content = new UILabel(model.toContent()); + this.add(content, BorderLayout.CENTER); + + next = new UIButton(); + next.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION); + next.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_right.svg")); + next.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_right.svg")); + next.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + performAction(nextAction); + } + }); + this.add(next, BorderLayout.EAST); + + refresh(); + } + + public PageControlModel performPrevious() { + + update(PageControlModel::previous); + return this.model; + } + + public PageControlModel performNext() { + + update(PageControlModel::next); + return this.model; + } + + public PageControlModel getModel() { + + return this.model; + } + + public void update(PageControlModel model) { + + this.model.setIndex(model.getIndex()); + this.model.setSummary(model.getSummary()); + refresh(); + } + + public void update(Function updateAction) { + + PageControlModel newModel = updateAction.apply(this.model); + update(newModel); + refresh(); + } + + public void refresh() { + + this.content.setText(this.model.toContent()); + this.content.repaint(); + + this.previous.setEnabled(true); + this.next.setEnabled(true); + if (model.getNumber() == 1) { + // 禁用上一个 + disableButton(this.previous); + // 禁用next + if (model.getNumber() == model.getSummary()) { + disableButton(this.next); + } + return; + } + + // 禁用next + if (model.getNumber() == model.getSummary()) { + disableButton(this.next); + } + } + + private void enable(UIButton button) { + + button.setEnabled(true); + } + + private void disableButton(UIButton button) { + + button.setEnabled(false); + } + + private void performAction(Runnable action) { + + if (action != null) { + action.run(); + refresh(); + } + } + + public void actions(Runnable previousAction, Runnable nextAction) { + + this.previousAction = previousAction; + this.nextAction = nextAction; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java b/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java new file mode 100644 index 0000000000..317a171954 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java @@ -0,0 +1,184 @@ +package com.fr.design.components.table; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.utils.ColorUtils; +import com.fr.third.org.apache.commons.lang3.ArrayUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridLayout; + +/** + * 表头 + * 内容 + * + * 适用于需要一个表格的 Panel + * + * created by Harrison on 2022/05/26 + **/ +public class TablePanel extends JPanel { + + private static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233); + + private static final Color DEFAULT_ODD_ROW_COLOR = new Color(245, 245, 247); + + private static final Color DEFAULT_EVEN_ROW_COLOR = Color.WHITE; + + private JPanel headerPanel; + + private JPanel[] headerItemPanels; + + private JPanel contentPanel; + + private JPanel[][] cellPanels; + + public TablePanel(int row, int column) { + + setLayout(FRGUIPaneFactory.createBorderLayout()); + + /* header 部分 */ + + this.headerPanel = new JPanel(); + headerPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column)); + headerPanel.setName("header-panel"); + headerPanel.setPreferredSize(new Dimension(640, 24)); + + // border + headerPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221))); + syncHeaderColor(headerPanel); + + headerItemPanels = new JPanel[column]; + for (int i = 0; i < column; i++) { + JPanel headerItemWrapper = FRGUIPaneFactory.createBorderLayout_S_Pane(); + syncHeaderColor(headerItemWrapper); + headerItemWrapper.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); + + JPanel headerItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + headerItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + headerItemPanels[i] = headerItemPanel; + + UILabel label = new UILabel(); + syncHeaderColor(label); + + headerItemPanel.add(new UILabel(), BorderLayout.CENTER); + + headerItemWrapper.add(headerItemPanel, BorderLayout.WEST); + if (i != column - 1) { + JSeparator separator = new JSeparator(JSeparator.VERTICAL); + separator.setBackground(new Color(218, 218, 221)); + headerItemWrapper.add(separator, BorderLayout.EAST); + } + headerPanel.add(headerItemWrapper); + } + + /* content 部分 */ + + contentPanel = new JPanel(); + + contentPanel.setLayout(new GridLayout(row, 1)); + contentPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221))); + + cellPanels = new JPanel[row][column]; + for (int i = 0; i < row; i++) { + + JPanel rowPanel = new JPanel(); + // 获取行号 + Color rowColor = getRowColorByRowNumber(i + 1); + rowPanel.setBackground(rowColor); + rowPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column)); + rowPanel.setName("row-" + i); + rowPanel.setBorder(BorderFactory.createEmptyBorder()); + rowPanel.setPreferredSize(new Dimension(640, 24)); + + for (int j = 0; j < column; j++) { + + JPanel rowItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + rowItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + rowItemPanel.setName("rowItemPanel-"+ i + "-" + j); + final UILabel empty = new UILabel(); + empty.setPreferredSize(new Dimension(210, 24)); + rowItemPanel.setBackground(rowPanel.getBackground()); + rowItemPanel.add(empty, BorderLayout.CENTER); + + rowPanel.add(rowItemPanel); + cellPanels[i][j] = rowItemPanel; + } + + contentPanel.add(rowPanel); + } + + add(headerPanel, BorderLayout.NORTH); + add(contentPanel, BorderLayout.SOUTH); + } + + /** + * 获取行的颜色 + * + * @param row 行号 + * @return 颜色 + */ + private Color getRowColorByRowNumber(int row) { + + Color rowColor; + if (row % 2 != 0) { + rowColor = DEFAULT_EVEN_ROW_COLOR; + } else { + rowColor = DEFAULT_ODD_ROW_COLOR; + } + return rowColor; + } + + public void updateHeaders(String[] headers) { + + for (int i = 0; i < headers.length; i++) { + String header = headers[i]; + UILabel headerContent = new UILabel(header); + JPanel headerItemPanel = headerItemPanels[i]; + if (ArrayUtils.getLength(headerItemPanel.getComponents()) == 1) { + headerItemPanel.remove(0); + } + headerItemPanel.add(headerContent); + syncHeaderColor(headerItemPanel); + } + } + + public void updateCell(int row, int column, Component component) { + + int x = row - 1; + int y = column - 1; + + syncCellColor(row, component); + + JPanel cellPanel = this.cellPanels[x][y]; + if (ArrayUtils.getLength(cellPanel.getComponents()) == 1) { + cellPanel.remove(0); + } + cellPanel.add(component); + } + + public void updateCell(int row, int column, String value) { + + UILabel cellContent = new UILabel(value); + syncCellColor(row, cellContent); + this.updateCell(row, column, cellContent); + } + + private void syncHeaderColor(Component component) { + + ColorUtils.syncBackground(component, DEFAULT_HEADER_COLOR); + } + + private void syncCellColor(int row, Component component) { + + Color rowColor = getRowColorByRowNumber(row); + ColorUtils.syncBackground(component, rowColor); + component.setBackground(rowColor); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java b/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java new file mode 100644 index 0000000000..5125c00271 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java @@ -0,0 +1,105 @@ +package com.fr.design.components.tooltip; + +import com.fr.base.GraphHelper; +import com.fr.design.gui.itooltip.UIToolTip; +import com.fr.log.FineLoggerFactory; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JToolTip; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ToolTipUI; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Enumeration; +import java.util.Vector; + +/** + * 现代化的 UIToolTip + * 见 设计文档 + * + * created by Harrison on 2022/07/09 + **/ +public class ModernToolTip extends UIToolTip { + + public ModernToolTip() { + super(); + setUI(new ModernToolTipUI()); + } + + private class ModernToolTipUI extends ToolTipUI { + + private String[] strs; + private Icon icon; + private boolean needPaint; + public void paint(Graphics g, JComponent c) { + if (!needPaint) { + return; + } + FontMetrics metrics = GraphHelper.getFontMetrics(c.getFont()); + Dimension size = c.getSize(); + int width = size.width; + int height = size.height; + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(new Color(51, 51, 52, (int) Math.round(0.7 * 255))); + g2.fillRoundRect(0, 0, width, height, 4, 4); + + g2.setColor(Color.WHITE); + if (strs != null) { + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); + for (int i = 0; i < strs.length; i++) { + g2.drawString(strs[i], icon.getIconWidth() + 6, (metrics.getHeight()) * (i + 1)); + } + } + } + + @Override + public Dimension getPreferredSize(JComponent c) { + FontMetrics metrics = GraphHelper.getFontMetrics(c.getFont()); + String tipText = ((JToolTip) c).getTipText(); + icon = ((UIToolTip)c).getIcon(); + needPaint = true; + if (tipText == null) { + if(icon.getIconWidth() == -1) { + needPaint = false; + } + tipText = " "; + } + BufferedReader br = new BufferedReader(new StringReader(tipText)); + String line; + int maxWidth = 0; + Vector v = new Vector(); + try { + while ((line = br.readLine()) != null) { + int width = SwingUtilities.computeStringWidth(metrics, line); + maxWidth = (maxWidth < width) ? width : maxWidth; + v.addElement(line); + } + } catch (IOException ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + int lines = v.size(); + if (lines < 1) { + strs = null; + lines = 1; + } else { + strs = new String[lines]; + int i = 0; + for (Enumeration e = v.elements(); e.hasMoreElements(); i++) { + strs[i] = e.nextElement(); + } + } + int height = metrics.getHeight() * lines; + return new Dimension(maxWidth + icon.getIconWidth() + 10, Math.max(height, icon.getIconHeight()) + 6); + } + + } +} diff --git a/designer-base/src/main/java/com/fr/design/config/DesignerProperties.java b/designer-base/src/main/java/com/fr/design/config/DesignerProperties.java new file mode 100644 index 0000000000..d14c7938a9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/config/DesignerProperties.java @@ -0,0 +1,52 @@ +package com.fr.design.config; + +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Properties; + +public class DesignerProperties { + private static DesignerProperties holder = null; + private boolean supportLoginEntry = true; + + public DesignerProperties() { + String filePath = StableUtils.pathJoin(StableUtils.getInstallHome(), "/config/config.properties"); + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(filePath)); + Properties ps = new Properties(); + ps.load(is); + this.initProperties(ps); + } catch (FileNotFoundException e) { + // ignore + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } finally { + IOUtils.close(is); + } + } + + public static DesignerProperties getInstance() { + if (holder == null) { + holder = new DesignerProperties(); + } + return holder; + } + + private void initProperties(Properties ps) { + String supportLoginEntry = ps.getProperty("supportLoginEntry"); + if (StringUtils.isNotEmpty(supportLoginEntry)) { + this.supportLoginEntry = Boolean.valueOf(supportLoginEntry); + } + } + + public boolean isSupportLoginEntry() { + return supportLoginEntry; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java b/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java new file mode 100644 index 0000000000..0ece84cca9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/constants/DesignerColor.java @@ -0,0 +1,24 @@ +package com.fr.design.constants; + +import java.awt.Color; + +/** + * 见 设计器规范 + * 将相关的逻辑抽象过来 + * 如果后面更改的话, 可以统一修改 + * 如果换版本,可以换成 v2 这种类推 + * + * created by Harrison on 2022/05/26 + **/ +public interface DesignerColor { + + interface Button { + + interface Primary { + + Color PRESSED = new Color(29, 122, 220); + Color HOVER = new Color(84, 165, 249); + Color NORMAL = new Color(65, 155, 249); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java index 4b532b92d8..4720c8e103 100644 --- a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java +++ b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java @@ -15,7 +15,12 @@ public enum DesignerLaunchStatus implements Event { * 初始化环境完成 */ WORKSPACE_INIT_COMPLETE, - + + /** + * 设计器模块初始化开始 + */ + DESIGNER_INIT_STARTED, + /** * 设计器模块启动完成 */ diff --git a/designer-base/src/main/java/com/fr/design/constants/TableDataConstants.java b/designer-base/src/main/java/com/fr/design/constants/TableDataConstants.java new file mode 100644 index 0000000000..7d8c66c093 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/constants/TableDataConstants.java @@ -0,0 +1,5 @@ +package com.fr.design.constants; + +public class TableDataConstants { + public static final String SEPARATOR = "_"; +} diff --git a/designer-base/src/main/java/com/fr/design/constants/UIConstants.java b/designer-base/src/main/java/com/fr/design/constants/UIConstants.java index b10d3f9e52..da05a79dd5 100644 --- a/designer-base/src/main/java/com/fr/design/constants/UIConstants.java +++ b/designer-base/src/main/java/com/fr/design/constants/UIConstants.java @@ -4,14 +4,13 @@ package com.fr.design.constants; import com.fr.base.svg.IconUtils; -import com.fr.base.svg.SVGIcon; +import com.fr.base.svg.SVGLoader; import com.fr.general.IOUtils; import com.fr.stable.Constants; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; import javax.swing.Icon; -import javax.swing.ImageIcon; import javax.swing.border.Border; import java.awt.BasicStroke; import java.awt.Color; @@ -150,6 +149,7 @@ public interface UIConstants { public static final Color LIST_ITEM_SPLIT_LINE = new Color(0xf0f0f3); public static final Color DESIGNER_LOGIN_BACKGROUND = new Color(0xf1ad14); public static final Color DESIGNER_LOGIN_BACKGROUND_ONCLICK = new Color(0xd89600); + public static final Color CHECK_BOX_TIP_FONT_COLOR = new Color(51, 51, 52, (int)Math.round(0.5 * 255)); public static final BufferedImage DRAG_BAR = IOUtils.readImage("com/fr/design/images/control/bar.png"); public static final BufferedImage DRAG_BAR_LIGHT = IOUtils.readImage("com/fr/design/images/control/bar-light.png"); @@ -160,16 +160,16 @@ public interface UIConstants { public static final BufferedImage DRAG_BAR_RIGHT = IOUtils.readImage("com/fr/design/images/control/barm.png"); public static final BufferedImage DRAG_BAR_LEFT = IOUtils.readImage("com/fr/design/images/control/barl.png"); - public static final BufferedImage DRAG_UP_NORMAL = IOUtils.readImage("com/fr/design/images/control/upnor.png"); - public static final BufferedImage DRAG_UP_PRESS = IOUtils.readImage("com/fr/design/images/control/uppre.png"); - public static final BufferedImage DRAG_DOWN_NORMAL = IOUtils.readImage("com/fr/design/images/control/downnor.png"); - public static final BufferedImage DRAG_DOWN_PRESS = IOUtils.readImage("com/fr/design/images/control/downpre.png"); - public static final BufferedImage DRAG_RIGHT_NORMAL = IOUtils.readImage("com/fr/design/images/control/rightnor.png"); - public static final BufferedImage DRAG_RIGHT_PRESS = IOUtils.readImage("com/fr/design/images/control/rightpre.png"); - public static final BufferedImage DRAG_LEFT_NORMAL = IOUtils.readImage("com/fr/design/images/control/leftnor.png"); - public static final BufferedImage DRAG_LEFT_PRESS = IOUtils.readImage("com/fr/design/images/control/leftpre.png"); + public static final Image DRAG_UP_NORMAL = SVGLoader.load("/com/fr/design/standard/triangle.arrow/up_normal.svg"); + public static final Image DRAG_UP_PRESS = SVGLoader.load("/com/fr/design/standard/triangle.arrow/up_hover.svg"); + public static final Image DRAG_DOWN_NORMAL = SVGLoader.load("/com/fr/design/standard/triangle.arrow/down_normal.svg"); + public static final Image DRAG_DOWN_PRESS = SVGLoader.load("/com/fr/design/standard/triangle.arrow/down_hover.svg"); + public static final Image DRAG_RIGHT_NORMAL = SVGLoader.load("/com/fr/design/standard/drag/right_normal.svg"); + public static final Image DRAG_RIGHT_PRESS = SVGLoader.load("/com/fr/design/standard/drag/right_pressed.svg"); + public static final Image DRAG_LEFT_NORMAL = SVGLoader.load("/com/fr/design/standard/drag/left_normal.svg"); + public static final Image DRAG_LEFT_PRESS = SVGLoader.load("/com/fr/design/standard/drag/left_pressed.svg"); public static final BufferedImage DRAG_DOT = IOUtils.readImage("com/fr/design/images/control/dot.png"); - public static final BufferedImage DRAG_LINE = IOUtils.readImage("com/fr/design/images/control/dot-line.png"); + public static final Image DRAG_LINE = SVGLoader.load("/com/fr/design/standard/dot_line_normal.svg"); public static final BufferedImage ACCESSIBLE_EDITOR_DOT = IOUtils.readImage("com/fr/design/images/control/dot.png"); public static final BufferedImage DRAG_DOT_VERTICAL = IOUtils.readImage("com/fr/design/images/control/dotv.png"); public static final BufferedImage POP_BUTTON_DOWN = IOUtils.readImage("com/fr/design/images/buttonicon/popdownarrow.png"); @@ -186,20 +186,22 @@ public interface UIConstants { public static final Icon CHOOSEN_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/select_item.png"); public static final Icon PRE_WIDGET_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/prewidget.png"); public static final Icon PRE_WIDGET_NORMAL_ICON = IconUtils.readIcon("com/fr/design/images/buttonicon/prewidget"); - public static final Icon EDIT_NORMAL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/editn.png"); - public static final Icon EDIT_PRESSED_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/editp.png"); - public static final Icon HIDE_NORMAL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/hiden.png"); - public static final Icon HIDE_PRESSED_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/hidep.png"); - public static final Icon VIEW_NORMAL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/viewn.png"); - public static final Icon VIEW_PRESSED_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/viewp.png"); - public static final Icon RUN_BIG_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/run24.png"); - public static final Icon RUN_SMALL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/runs.png"); - public static final Icon PAGE_BIG_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/pageb24.png"); - public static final Icon WRITE_BIG_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/writeb24.png"); - public static final Icon ANA_BIG_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/anab24.png"); - public static final Icon PAGE_SMALL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/pages.png"); - public static final Icon WRITE_SMALL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/writes.png"); - public static final Icon ANA_SMALL_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/anas.png"); + public static final Icon EDIT_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/edit"); + public static final Icon EDIT_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/edit"); + public static final Icon HIDE_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/hide"); + public static final Icon HIDE_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/hide"); + public static final Icon VIEW_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/view"); + //public static final Icon VIEW_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/view"); + + public static final Icon RUN_BIG_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/run24.svg"); + public static final Icon RUN_SMALL_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/runs.svg"); + public static final Icon PAGE_BIG_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/pageb24.svg"); + public static final Icon WRITE_BIG_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/writeb24.svg"); + public static final Icon ANA_BIG_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/anab24.svg"); + public static final Icon PAGE_SMALL_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/pages.svg"); + public static final Icon WRITE_SMALL_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/writes.svg"); + public static final Icon ANA_SMALL_ICON = IconUtils.readIcon("/com/fr/design/standard/preview/anas.svg"); + public static final Icon REFRESH_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/refresh.png"); public static final Icon FONT_ICON = IOUtils.readIcon("/com/fr/design/images/gui/color/foreground.png"); public static final Icon AUTO_FONT_ICON = IOUtils.readIcon("/com/fr/design/images/gui/color/autoForeground.png"); diff --git a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java index b0997b7f6c..b3a076a92b 100644 --- a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java @@ -2,9 +2,9 @@ package com.fr.design.data; import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; -import com.fr.data.api.StoreProcedureAssist; -import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.design.DesignModelAdapter; import com.fr.design.actions.UpdateAction; import com.fr.design.data.datapane.TableDataCreatorProducer; @@ -13,7 +13,7 @@ import com.fr.design.data.datapane.TableDataSourceOP; import com.fr.design.data.datapane.TableDataTree; import com.fr.design.data.tabledata.ResponseDataSourceChange; import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; -import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper; +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; import com.fr.design.dialog.BasicDialog; @@ -36,8 +36,6 @@ import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; -import java.util.HashSet; -import java.util.Set; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.DefaultCellEditor; @@ -55,8 +53,10 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.EventObject; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; /** * Coder: zack @@ -83,6 +83,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp protected String[] allDSNames; protected ConnectionTableAction connectionTableAction; protected ToolBarDef toolbarDef; + protected TableDataTreePaneListener listener = null; private String type = ""; @@ -114,7 +115,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp */ @Override public Icon getViewIcon() { - return BaseUtils.readIcon(IconPathConstants.DS_ICON_PATH); + return IconUtils.readIcon(IconPathConstants.DS_ICON_PATH); } /** @@ -142,6 +143,17 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp public abstract void dgEdit(final AbstractTableDataPane uPanel, String originalName, boolean isUpdate); + public void showEditPane(final AbstractTableDataPane tableDataPane, String originalName, TableDataTreePaneListener listener) { + this.listener = listener; + dgEdit(tableDataPane, originalName); + } + + public interface TableDataTreePaneListener { + void doOk(); + + void doCancel(); + } + protected void doPropertyChange(BasicDialog dg, BasicPane.NamePane nPanel, final String oldName) { type = dg.getTitle(); nPanel.setShowText(StringUtils.BLANK); @@ -172,7 +184,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp private boolean isIncludeUnderline(String name) { - return ComparatorUtils.equals(name.indexOf(StoreProcedureAssist.GROUP_MARKER), -1) ? false : true; + return ComparatorUtils.equals(name.indexOf(MultiResultTableData.GROUP_MARKER), -1) ? false : true; } public abstract void addDataPane(final AbstractTableDataPane uPanel, String paneName); @@ -366,15 +378,9 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp } protected boolean isDsNameRepeaded(String name) { - if (allDSNames == null) { - allDSNames = DesignTableDataManager.getAllDSNames(tc.getBook()); - } - for (int i = 0; i < allDSNames.length; i++) { - if (ComparatorUtils.equals(name, allDSNames[i])) { - return true; - } - } - return false; + allDSNames = DesignTableDataManager.getAllDSNames(tc.getBook()); + Set allDSNamesWithoutPermissions = DesignTableDataManager.getAllDSNamesWithoutPermissions(tc.getBook()); + return allDSNamesWithoutPermissions.contains(name); } protected KeyAdapter getTableTreeNodeListener(final UpdateAction editAction, final UpdateAction previewTableDataAction, final UpdateAction removeAction, final TableDataSourceOP op, final TableDataTree dataTree) { @@ -419,7 +425,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp public PreviewTableDataAction(TableDataTree dataTree) { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview")); this.setMnemonic('p'); - this.setSmallIcon("/com/fr/design/images/m_file/preview"); + this.setSmallIcon("/com/fr/design/standard/previewdateset/preview"); this.dataTree = dataTree; } @@ -431,16 +437,16 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp data = selectedNO.getObject(); } try { - if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof StoreProcedure) { - ((StoreProcedure) (((TableDataWrapper) data).getTableData())).resetDataModelList(); - if (data instanceof StoreProcedureDataWrapper) { - StoreProcedureDataWrapper oldSdw = ((StoreProcedureDataWrapper) data); - StoreProcedureDataWrapper newSdw = new StoreProcedureDataWrapper((StoreProcedure) oldSdw.getTableData(), oldSdw.getStoreprocedureName(), oldSdw.getTableDataName()); - newSdw.previewData(StoreProcedureDataWrapper.PREVIEW_ONE); + if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof MultiResultTableData) { + ((MultiResultTableData) (((TableDataWrapper) data).getTableData())).resetDataModelList(); + if (data instanceof MultiResultTableDataWrapper) { + MultiResultTableDataWrapper oldSdw = ((MultiResultTableDataWrapper) data); + MultiResultTableDataWrapper newSdw = new MultiResultTableDataWrapper((MultiResultTableData) oldSdw.getTableData(), oldSdw.getMultiResultTableDataName(), oldSdw.getTableDataName()); + newSdw.previewData(MultiResultTableDataWrapper.PREVIEW_ONE); } else { - StoreProcedure storeProcedure = (StoreProcedure) ((TableDataWrapper) data).getTableData(); - StoreProcedureDataWrapper storeProcedureDataWrapper = new StoreProcedureDataWrapper(storeProcedure, StringUtils.EMPTY, StringUtils.EMPTY); - storeProcedureDataWrapper.previewData(StoreProcedureDataWrapper.PREVIEW_ALL); + MultiResultTableData tableData = (MultiResultTableData) ((TableDataWrapper) data).getTableData(); + MultiResultTableDataWrapper storeProcedureDataWrapper = new MultiResultTableDataWrapper(tableData, StringUtils.EMPTY, StringUtils.EMPTY); + storeProcedureDataWrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL); } } else { ((TableDataWrapper) data).previewData(); @@ -458,7 +464,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp public ConnectionTableAction() { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Server_Define_Data_Connection")); this.setMnemonic('D'); - this.setSmallIcon("/com/fr/design/images/m_web/connection"); + this.setSmallIcon("/com/fr/design/standard/connection", false); } @Override diff --git a/designer-base/src/main/java/com/fr/design/data/BasicTableDataUtils.java b/designer-base/src/main/java/com/fr/design/data/BasicTableDataUtils.java index 57c7e23a13..ae90c5bacc 100644 --- a/designer-base/src/main/java/com/fr/design/data/BasicTableDataUtils.java +++ b/designer-base/src/main/java/com/fr/design/data/BasicTableDataUtils.java @@ -1,6 +1,7 @@ package com.fr.design.data; import com.fr.data.TableDataSource; +import com.fr.design.constants.TableDataConstants; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.i18n.Toolkit; import com.fr.stable.StringUtils; @@ -11,8 +12,6 @@ import com.fr.stable.StringUtils; * Created by hades on 2020/4/27 */ public abstract class BasicTableDataUtils { - private static final String SEPARATOR = "-"; - private static final int LEN = 2; @@ -38,10 +37,10 @@ public abstract class BasicTableDataUtils { public static String getTableDataName(boolean isCover, TableDataSource tds, String tdName, String srcName, boolean isDsNameRepeaded) { if (isCover) { - return srcName + SEPARATOR + tdName; + return srcName + TableDataConstants.SEPARATOR + tdName; } if (tds.getTableData(tdName) != null || isDsNameRepeaded) {//如果有同名的就拼上来源名称 - tdName = srcName + SEPARATOR + tdName; + tdName = srcName + TableDataConstants.SEPARATOR + tdName; } int i = 0; while (tds.getTableData(tdName) != null) { diff --git a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java index f7eb9bacc4..5134e88c8b 100644 --- a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java +++ b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java @@ -3,19 +3,22 @@ package com.fr.design.data; import com.fr.base.StoreProcedureParameter; import com.fr.base.TableData; import com.fr.concurrent.NamedThreadFactory; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; import com.fr.data.TableDataSourceTailor; import com.fr.data.core.DataCoreXmlUtils; import com.fr.data.impl.EmbeddedTableData; +import com.fr.data.impl.NameDataModel; import com.fr.data.impl.storeproc.ProcedureDataModel; import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.data.impl.storeproc.StoreProcedureConstants; +import com.fr.data.impl.storeproc.StoreProcedureHelper; import com.fr.data.operator.DataOperator; import com.fr.design.DesignModelAdapter; import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataNameWrapper; +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper; import com.fr.design.data.tabledata.wrapper.ServerTableDataWrapper; -import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper; -import com.fr.design.data.tabledata.wrapper.StoreProcedureNameWrapper; import com.fr.design.data.tabledata.wrapper.TableDataFactory; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; @@ -45,6 +48,7 @@ import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -188,7 +192,7 @@ public abstract class DesignTableDataManager { public static void addDsChangeListener(ChangeListener l) { JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); String key = StringUtils.EMPTY; - if (template != null) { + if (JTemplate.isValid(template)) { key = template.getPath(); } List dsListeners = dsListenersMap.get(key); @@ -292,6 +296,27 @@ public abstract class DesignTableDataManager { return list.toArray(new String[0]); } + /** + * 获取所有的数据集名称,无论模板是不是有数据集的权限 + */ + public static Set getAllDSNamesWithoutPermissions(TableDataSource source) { + Set names = new HashSet<>(); + Map resMap = new HashMap<>(); + // 模板数据集 + addTemplateData(resMap, source); + // 存储过程 + addStoreProcedureData(resMap); + for (Map.Entry entry : resMap.entrySet()) { + names.add(entry.getKey()); + } + //服务器数据集 + Map tableDatas = TableDataConfig.getInstance().getTableDatas(); + for (Map.Entry entry : tableDatas.entrySet()) { + names.add(entry.getKey()); + } + return names; + } + /** * 不根据过滤设置,返回当前模板数据集、服务器数据集、存储过程本身,是有顺序的 */ @@ -308,35 +333,57 @@ public abstract class DesignTableDataManager { return resMap; } + /** + * 不根据过滤设置,返回当前模板数据集,是有顺序的 + */ + public static java.util.Map getTemplateDataSet(TableDataSource source) { + java.util.Map resMap = new java.util.LinkedHashMap(); + // 模板数据集 + addTemplateData(resMap, source); + + return resMap; + } + public static java.util.Map getAllDataSetIncludingProcedure(java.util.Map resMap) { java.util.LinkedHashMap dsMap = new java.util.LinkedHashMap(); - Iterator> entryIt = resMap.entrySet().iterator(); - while (entryIt.hasNext()) { - String key = entryIt.next().getKey(); + for (Entry entry : resMap.entrySet()) { + String key = entry.getKey(); TableDataWrapper tableDataWrapper = resMap.get(key); - if (tableDataWrapper.getTableData() instanceof StoreProcedure) { - StoreProcedure storeProcedure = (StoreProcedure) tableDataWrapper.getTableData(); - boolean hasSchemaOrResult = false; - StoreProcedureParameter[] parameters = StoreProcedure.getSortPara(storeProcedure.getParameters()); + if (tableDataWrapper.getTableData() instanceof MultiResultTableData) { + MultiResultTableData tableData = (MultiResultTableData) tableDataWrapper.getTableData(); String name = tableDataWrapper.getTableDataName(); - List resultNames = storeProcedure.getResultNames(); - TableDataWrapper tdw = new StoreProcedureNameWrapper(name + "_Table", storeProcedure); - - for (StoreProcedureParameter parameter : parameters) { - if (parameter.getSchema() != StoreProcedureConstants.IN) { - String parameterName = name + "_" + parameter.getName(); - TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false); - dsMap.put(parameterName, newTwd); - hasSchemaOrResult = true; + List resultNames = tableData.getResultNames(); + TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name + "_Table", tableData); + boolean hasSchemaOrResult = false; + + // 存储过程的特殊处理,还有其它名称 + if (tableData instanceof StoreProcedure) { + StoreProcedure storeProcedure = (StoreProcedure) tableData; + StoreProcedureParameter[] parameters = StoreProcedureHelper.getSortPara(storeProcedure.getParameters()); + + for (StoreProcedureParameter parameter : parameters) { + if (parameter.getSchema() != StoreProcedureConstants.IN) { + String parameterName = name + "_" + parameter.getName(); + TableDataWrapper newTwd = new MultiResultTableDataWrapper(storeProcedure, name, parameterName, false); + dsMap.put(parameterName, newTwd); + hasSchemaOrResult = true; + } } - } + } /*else { + // TODO getDataModelList是空的 + for (String n : tableData.getResultNames()) { + String dmName = name + "_" + n; + dsMap.put(n, new MultiResultTableDataWrapper(tableData, name, dmName, false)); + } + }*/ + if (!resultNames.isEmpty()) { hasSchemaOrResult = true; - for (int i = 0; i < resultNames.size(); i++) { - String parameterName = name + "_" + resultNames.get(i); - TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false); - dsMap.put(parameterName, newTwd); + for (String resultName : resultNames) { + String dmName = name + "_" + resultName; + TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, dmName, false); + dsMap.put(dmName, newTwd); } } @@ -418,7 +465,7 @@ public abstract class DesignTableDataManager { if (globalDsCache.containsKey(name)) { resMap.put(name, globalDsCache.get(name)); } else { - TableDataWrapper tdw = new StoreProcedureNameWrapper(name, storeProcedure); + TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name, storeProcedure); resMap.put(name, tdw); globalDsCache.put(name, tdw); } @@ -588,29 +635,39 @@ public abstract class DesignTableDataManager { * 所以用该方法,不会对一个已经计算了的存储过程重复计算.和分页预览时处理机制一样,这样对有多个返回数据集的存储过程来说很有必要 * * @param needLoadingBar 是否需要进度条 - * @param storeProcedure 存储过程 + * @param tableData 存储过程 * @return 数据 */ - public static ProcedureDataModel[] createLazyDataModel(StoreProcedure storeProcedure, boolean needLoadingBar) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - XMLPrintWriter writer = XMLPrintWriter.create(out); - // 把storeProcedure写成xml文件到out - DataCoreXmlUtils.writeXMLStoreProcedure(writer, storeProcedure, null); - if (storeProcedure.getDataModelSize() > 0 && !storeProcedure.isFirstExpand()) { - return storeProcedure.creatLazyDataModel(); - } - ParameterProvider[] inParameters = DataOperator.getInstance().getStoreProcedureParameters(storeProcedure); + public static NameDataModel[] createLazyDataModel(MultiResultTableData tableData, boolean needLoadingBar) throws Exception { Map parameterMap = new HashMap<>(); - if (inParameters.length > 0 && !ComparatorUtils.equals(threadLocal.get(), NO_PARAMETER)) {// 检查Parameter. - - showParaWindow(parameterMap, inParameters); + if (tableData instanceof StoreProcedure) { + StoreProcedure storeProcedure = (StoreProcedure) tableData; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + XMLPrintWriter writer = XMLPrintWriter.create(out); + // 把storeProcedure写成xml文件到out + DataCoreXmlUtils.writeXMLStoreProcedure(writer, storeProcedure, null); + if (storeProcedure.getDataModelList().size() > 0 && !storeProcedure.isFirstExpand()) { + // 存储过程有些特殊处理 + // 这个就简单直接获取暂存列表吧 + return storeProcedure.getDataModelList().toArray(new ProcedureDataModel[0]); + } + ParameterProvider[] inParameters = DataOperator.getInstance().getStoreProcedureParameters(storeProcedure); + if (inParameters.length > 0 && !ComparatorUtils.equals(threadLocal.get(), NO_PARAMETER)) {// 检查Parameter. + showParaWindow(parameterMap, inParameters); + } + storeProcedure.setFirstExpand(false); + } else { + ParameterProvider[] parameters = DataOperator.getInstance().getTableDataParameters(tableData); + if (parameters.length > 0) { + showParaWindow(parameterMap, parameters); + } } - storeProcedure.setFirstExpand(false); + if (needLoadingBar) { - StoreProcedureDataWrapper.loadingBar.start(); + MultiResultTableDataWrapper.loadingBar.start(); } - return DataOperator.getInstance().previewProcedureDataModel(storeProcedure, parameterMap, 0); + return DataOperator.getInstance().previewMultiResultTableData(tableData, parameterMap, 0); } private static void showParaWindow(final Map parameterMap, ParameterProvider[] inParameters) { @@ -626,4 +683,14 @@ public abstract class DesignTableDataManager { public static void setThreadLocal(String value) { threadLocal.set(value); } -} \ No newline at end of file + + /** + * 根据数据集名称判断是否为服务器数据集或服务器存储过程 + * + * @param tableDataName 数据集名称 + * @return + */ + public static boolean isGlobalTableData(String tableDataName) { + return globalDsCache.containsKey(tableDataName); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java b/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java new file mode 100644 index 0000000000..331e980834 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java @@ -0,0 +1,93 @@ +package com.fr.design.data; + +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author rinoux + * @version 10.0 + * Created by rinoux on 2022/3/28 + */ +public final class MapCompareUtils { + + + /** + * 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 + * + * 对比时默认用equals方法来判断是否为 EntryEventKind#UPDATED + * + * @param orig 原始map + * @param other 参考的新map + * @param eventHandler 有区别时的事件处理器 + * @param K + * @param V + */ + public static void contrastMapEntries(@NotNull Map orig, @NotNull Map other, @NotNull EventHandler eventHandler) { + + contrastMapEntries(orig, other, eventHandler, UpdateRule.DEFAULT); + } + + /** + * 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 + * + * 对比时用自定义的规则来判断是否为 EntryEventKind#UPDATED + * + * @param orig 原始map + * @param other 参考的新map + * @param eventHandler 有区别时的事件处理器 + * @param updateRule 自定义的Update事件判定规则 + * @param + * @param + */ + public static void contrastMapEntries(@NotNull Map orig, @NotNull Map other, @NotNull EventHandler eventHandler, @NotNull UpdateRule updateRule) { + + Map copiedOrig = new LinkedHashMap<>(orig); + + other.forEach((k, v) -> { + V existedV = copiedOrig.remove(k); + if (existedV != null) { + if (updateRule.needUpdate(existedV, v)) { + eventHandler.on(EntryEventKind.UPDATED, k, v); + } + } else { + eventHandler.on(EntryEventKind.ADDED, k, v); + } + }); + + copiedOrig.forEach((k, v) -> eventHandler.on(EntryEventKind.REMOVED, k, v)); + } + + + /** + * 事件处理器,对应比较后的三种结果的事件处理 + * @param + * @param + */ + public interface EventHandler { + void on(EntryEventKind entryEventKind, K k, V v); + } + + /** + * 数据被修改(EntryEventKind.UPDATED) 的判定规则 + * @param + * @param + */ + public interface UpdateRule { + + EntryEventKind eventKind = EntryEventKind.UPDATED; + + UpdateRule DEFAULT = new UpdateRule() {}; + + default boolean needUpdate(V origin, V v) { + return !v.equals(origin); + } + } + + public enum EntryEventKind { + ADDED, + REMOVED, + UPDATED; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java b/designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java index e2a75fc11b..a03ccc99dc 100644 --- a/designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java +++ b/designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java @@ -11,11 +11,11 @@ import com.fr.esd.event.DSMapping; import com.fr.esd.event.DsNameTarget; import com.fr.esd.event.StrategyEventsNotifier; import com.fr.esd.event.xml.XMLSavedHook; -import com.fr.file.FILE; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; +import java.nio.file.Paths; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -46,7 +46,9 @@ public class StrategyConfigAttrUtils { } //新建模版此时不存在,不需要注册钩子 - if (attr.getXmlSavedHook() == null && WorkContext.getWorkResource().exist(jTemplate.getPath())) { + //不处理外部路径,保存到设计器才处理 + String path = jTemplate.getPath(); + if (attr.getXmlSavedHook() == null && !Paths.get(path).isAbsolute() && WorkContext.getWorkResource().exist(path)) { attr.setXmlSavedHook(new StrategyConfigsAttrSavedHook(jTemplate.getPath(), attr)); } return attr; diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java index f656105265..99a294fdde 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java @@ -1,12 +1,12 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; -import com.fr.concurrent.NamedThreadFactory; import com.fr.data.core.DataCoreUtils; import com.fr.data.core.db.DBUtils; import com.fr.data.core.db.TableProcedure; import com.fr.data.core.db.dialect.Dialect; import com.fr.data.core.db.dialect.DialectFactory; +import com.fr.data.impl.Connection; import com.fr.data.impl.DBTableData; import com.fr.data.operator.DataOperator; import com.fr.design.DesignerEnvManager; @@ -19,7 +19,7 @@ import com.fr.design.data.datapane.preview.PreviewTablePane; import com.fr.design.data.tabledata.Prepare4DataSourceChange; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.icombobox.FilterableComboBoxModel; -import com.fr.design.gui.icombobox.SearchPreTaskTreeComboBox; +import com.fr.design.gui.icombobox.TableSearchTreeComboBox; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.icombobox.UIComboBoxEditor; import com.fr.design.gui.icombobox.UIComboBoxRenderer; @@ -40,11 +40,6 @@ import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; import com.fr.workspace.server.connection.DBConnectAuth; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.util.Collections; -import java.util.concurrent.CancellationException; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -58,21 +53,20 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.Collection; -import java.util.Enumeration; +import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; +import java.util.concurrent.CancellationException; /** * @author zhou @@ -97,41 +91,12 @@ public class ChoosePane extends BasicBeanPane implements Refresha /** * 表名 */ - protected SearchPreTaskTreeComboBox tableNameComboBox; - - private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(new NamedThreadFactory("ChoosePane")); + protected TableSearchTreeComboBox tableNameComboBox; private SwingWorker populateWorker; private SwingWorker, Void> initWorker; - private PopupMenuListener popupMenuListener = new PopupMenuListener() { - - @Override - public void popupMenuWillBecomeVisible(PopupMenuEvent e) { - FutureTask task = new FutureTask(new Callable() { - @Override - public Void call() throws Exception { - calculateTableDataNames(); - return null; - } - }); - tableNameComboBox.setPreSearchTask(task); - SERVICE.submit(task); - } - - @Override - public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { - // Do nothing - } - - @Override - public void popupMenuCanceled(PopupMenuEvent e) { - // Do nothing - } - }; - - private PopupMenuListener listener = new PopupMenuListener() { @Override public void popupMenuCanceled(PopupMenuEvent e) { @@ -181,7 +146,7 @@ public class ChoosePane extends BasicBeanPane implements Refresha schemaBox = new StringUIComboBox(); schemaBox.setEditor(new ComboBoxEditor()); - tableNameComboBox = new SearchPreTaskTreeComboBox(new JTree(new DefaultMutableTreeNode()), tableNameTreeRenderer, false); + tableNameComboBox = new TableSearchTreeComboBox(this, new JTree(new DefaultMutableTreeNode()), tableNameTreeRenderer); tableNameComboBox.setEditable(true); tableNameComboBox.setRenderer(listCellRenderer); registerDSChangeListener(); @@ -198,7 +163,6 @@ public class ChoosePane extends BasicBeanPane implements Refresha }); schemaBox.addPopupMenuListener(listener); addFocusListener(); - this.tableNameComboBox.addPopupMenuListener(popupMenuListener); } protected void addDSBoxListener() { @@ -355,7 +319,7 @@ public class ChoosePane extends BasicBeanPane implements Refresha GUICoreUtils.setSelectedItemQuietly(tableNameComboBox, -1); } - protected com.fr.data.impl.Connection getConnection() { + public Connection getConnection() { String selectedDSName = this.getDSName(); if (StringUtils.isEmpty(selectedDSName)) { return null; // peter:选中了当前的零长度的节点,直接返回. @@ -455,56 +419,6 @@ public class ChoosePane extends BasicBeanPane implements Refresha return "choosepane"; } - protected void calculateTableDataNames() { - JTree tree = tableNameComboBox.getTree(); - if (tree == null) { - return; - } - DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot(); - rootTreeNode.removeAllChildren(); - - String selectedDSName = this.getDSName(); - com.fr.data.impl.Connection selectedDatabase = this.getConnection(); - if (selectedDatabase == null) { - return; - } - try { - String schema = StringUtils.isEmpty(this.schemaBox.getSelectedItem()) ? null : this.schemaBox.getSelectedItem(); - TableProcedure[] sqlTableArray = DataCoreUtils.getTables(selectedDatabase, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); - if (sqlTableArray.length > 0) { - ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(selectedDSName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); - rootTreeNode.add(tableTreeNode); - for (int i = 0; i < sqlTableArray.length; i++) { - ExpandMutableTreeNode tableChildTreeNode = new ExpandMutableTreeNode(sqlTableArray[i]); - tableTreeNode.add(tableChildTreeNode); - } - } - TableProcedure[] sqlViewArray = DataCoreUtils.getTables(selectedDatabase, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); - if (sqlViewArray.length > 0) { - ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(selectedDSName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); - rootTreeNode.add(viewTreeNode); - for (int i = 0; i < sqlViewArray.length; i++) { - ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(sqlViewArray[i]); - viewTreeNode.add(viewChildTreeNode); - } - } - ((DefaultTreeModel) tree.getModel()).reload(); - // daniel 展开所有tree - TreeNode root = (TreeNode) tree.getModel().getRoot(); - TreePath parent = new TreePath(root); - TreeNode node = (TreeNode) parent.getLastPathComponent(); - for (Enumeration e = node.children(); e.hasMoreElements(); ) { - TreeNode n = (TreeNode) e.nextElement(); - TreePath path = parent.pathByAddingChild(n); - tree.expandPath(path); - } - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE); - } - } - /** * 创建选中的数据集数据 * @@ -558,22 +472,23 @@ public class ChoosePane extends BasicBeanPane implements Refresha return tableData; } - protected String getDSName() { + public String getDSName() { return this.dsNameComboBox.getSelectedItem(); } + public String getSchema() { + return this.schemaBox.getSelectedItem(); + } + protected void failedToFindTable() { // Do nothing } protected String getTableName() { String tableName = ""; - Object obj = this.tableNameComboBox.getSelectedItemObject(); + Object obj = this.tableNameComboBox.getSelectedItem(); if (obj == null) { - obj = this.tableNameComboBox.getSelectedItem(); - if (obj == null) { - obj = this.tableNameComboBox.getEditor().getItem(); - } + obj = this.tableNameComboBox.getEditor().getItem(); } if (obj instanceof TreePath) { Object tp = ((ExpandMutableTreeNode) ((TreePath) obj).getLastPathComponent()).getUserObject(); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePaneSupportFormula.java b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePaneSupportFormula.java index 14d0431e25..8fc62cd77a 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePaneSupportFormula.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePaneSupportFormula.java @@ -83,7 +83,7 @@ public class ChoosePaneSupportFormula extends ChoosePane { * * @return */ - protected String getDSName() { + public String getDSName() { String selectedDSName = null; String item = Utils.objectToString(this.dsNameComboBox.getEditor().getItem()); // 没有选中的列表项 那么看看是不是手输值 diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java index 1fd840ac78..f3df21df9c 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java @@ -15,6 +15,7 @@ import com.fr.esd.util.ESDUtils; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import com.fr.third.org.quartz.CronExpression; import javax.swing.AbstractAction; import javax.swing.JPanel; @@ -25,9 +26,11 @@ import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URI; +import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Date; /** * @author rinoux @@ -36,7 +39,6 @@ import java.util.List; */ public class ESDStrategyConfigPane extends BasicBeanPane { private static final String CRON_HELP_URL = "http://help.fanruan.com/finereport/doc-view-693.html"; - private UIRadioButton selectAutoUpdate; private UIRadioButton selectBySchema; private UICheckBox shouldEvolve; @@ -131,7 +133,6 @@ public class ESDStrategyConfigPane extends BasicBeanPane { ob = StrategyConfigHelper.createStrategyConfig(true, false, true); } this.strategyConfig = ob; - this.updateInterval.setText(ob.getUpdateInterval() <= 0 ? "0" : String.valueOf(ob.getUpdateInterval() / (double) CacheConstants.MILLIS_OF_MINUTE)); this.schemaTime.setText(StringUtils.join(",", ob.getUpdateSchema().toArray(new String[0]))); this.shouldEvolve.setSelected(ob.shouldEvolve()); @@ -177,11 +178,18 @@ public class ESDStrategyConfigPane extends BasicBeanPane { if (ESDUtils.checkUpdateTimeSchema(text)) { if (ESDUtils.isCronExpression(text)) { - schemaTimes.add(text); + if (checkCornTimeInterval(text)) { + schemaTimes.add(text); + } else { + this.schemaTimeCheckTips.setText(InterProviderFactory.getDesignI18nProvider().i18nText("Fine-Design_ESD_Error_Time_Interval_Too_Short")); + this.schemaTimeCheckTips.setVisible(true); + throw new IllegalArgumentException("[ESD]Update schema time interval is to short."); + } } else { Collections.addAll(schemaTimes, text.split(",")); } } else { + this.schemaTimeCheckTips.setText(InterProviderFactory.getDesignI18nProvider().i18nText("Fine-Design_ESD_Error_Time_Format")); this.schemaTimeCheckTips.setVisible(true); throw new IllegalArgumentException("[ESD]Update schema time format error."); } @@ -191,8 +199,15 @@ public class ESDStrategyConfigPane extends BasicBeanPane { String interval = this.updateInterval.getText(); if (checkUpdateInterval(interval)) { long intervalMillis = StringUtils.isEmpty(interval) ? 0 : (long) (Double.parseDouble(interval) * CacheConstants.MILLIS_OF_MINUTE); - config.setUpdateInterval(intervalMillis); + if (intervalMillis >= CacheConstants.MILLIS_OF_MINUTE) { + config.setUpdateInterval(intervalMillis); + } else { + this.updateIntervalCheckTips.setText(InterProviderFactory.getDesignI18nProvider().i18nText("Fine-Design_ESD_Error_Time_Interval_Too_Short")); + this.updateIntervalCheckTips.setVisible(true); + throw new IllegalArgumentException("[ESD]Update schema time interval is to short."); + } } else { + this.updateIntervalCheckTips.setText(InterProviderFactory.getDesignI18nProvider().i18nText("Fine-Design_ESD_Error_Time_Format")); this.updateIntervalCheckTips.setVisible(true); throw new IllegalArgumentException("[ESD]Error update interval format."); } @@ -220,6 +235,19 @@ public class ESDStrategyConfigPane extends BasicBeanPane { } + private boolean checkCornTimeInterval (String cronText) { + // 判断后两次更新时间间隔,如果小于1分钟就返回false + try { + CronExpression cron = new CronExpression(cronText); + Date next1 = cron.getNextValidTimeAfter(new Date()); + Date next2 = cron.getNextValidTimeAfter(next1); + return next2.getTime() - next1.getTime() >= CacheConstants.MILLIS_OF_MINUTE; + } catch (ParseException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return false; + } + protected String title4PopupWindow() { return InterProviderFactory.getDesignI18nProvider().i18nText("Fine-Design_ESD_Cache_Strategy_Config_Title"); } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java b/designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java new file mode 100644 index 0000000000..5e4cc2cd42 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java @@ -0,0 +1,73 @@ +package com.fr.design.data.datapane; + +import com.fr.data.util.function.AbstractDataFunction; +import com.fr.data.util.function.AverageFunction; +import com.fr.data.util.function.CountFunction; +import com.fr.data.util.function.MaxFunction; +import com.fr.data.util.function.MinFunction; +import com.fr.data.util.function.NoneFunction; +import com.fr.data.util.function.SumFunction; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.i18n.Toolkit; +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.chart.base.FirstFunction; + +/** + * 图表数据汇总方式下拉框 + * + * 支持首个,最后一个,求和,平均,最大值,最小值,个数 + * + */ +public class SummaryMethodComboBox extends UIComboBox { + public static final String[] CALCULATE_ARRAY = {Toolkit.i18nText("Fine-Design_Chart_Data_Function_First"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Last"), + Toolkit.i18nText("Fine-Design_Chart_Data_Function_Sum"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Average"), + Toolkit.i18nText("Fine-Design_Chart_Data_Function_Max"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Min"), + Toolkit.i18nText("Fine-Design_Chart_Data_Function_Count")}; + public static final Class[] CLASS_ARRAY = {FirstFunction.class, NoneFunction.class, SumFunction.class, AverageFunction.class, + MaxFunction.class, MinFunction.class, CountFunction.class}; + + public SummaryMethodComboBox() { + super(CALCULATE_ARRAY); + setSelectedIndex(2); + } + + public void reset() { + this.setSelectedItem(Toolkit.i18nText("Fine-Design_Chart_Data_Function_Sum")); + } + + /** + * 更新公式选择. + */ + public void populateBean(AbstractDataFunction function) { + if (function != null) { + for (int i = 0; i < CLASS_ARRAY.length; i++) { + if (this.getModel() != null && this.getModel().getSize() > i + && ComparatorUtils.equals(function.getClass(), CLASS_ARRAY[i])) { + setSelectedIndex(i); + break; + } + } + } + } + + /** + * 返回当前选择的公式 + */ + public AbstractDataFunction updateBean() { + try { + int selectIndex = getSelectedIndex(); + if (selectIndex >= 0 && selectIndex < CLASS_ARRAY.length) { + return (AbstractDataFunction) CLASS_ARRAY[selectIndex].newInstance(); + } + } catch (InstantiationException e) { + FineLoggerFactory.getLogger().error("Function Error"); + return null; + } catch (IllegalAccessException e) { + FineLoggerFactory.getLogger().error("Function Error"); + return null; + } + + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataCreatorProducer.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataCreatorProducer.java index 51bd8b49bf..8db517d614 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataCreatorProducer.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataCreatorProducer.java @@ -33,33 +33,33 @@ public class TableDataCreatorProducer { public TableDataNameObjectCreator[] createReportTableDataCreator() { TableDataNameObjectCreator dataBase = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DS_Database_Query"), "ds", - "/com/fr/design/images/data/database.png", DBTableData.class, DBTableDataPane.class); + "/com/fr/design/standard/database_normal.svg", DBTableData.class, DBTableDataPane.class); TableDataNameObjectCreator ds_Class = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Class"), "Class", - "/com/fr/design/images/data/source/classTableData.png", ClassTableData.class, ClassTableDataPane.class); + "/com/fr/design/standard/class_table_data_normal.svg", ClassTableData.class, ClassTableDataPane.class); TableDataNameObjectCreator table = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Embedded"), "Embedded", - "/com/fr/design/images/data/dataTable.png", EmbeddedTableData.class, EmbeddedTableDataPane.class); + "/com/fr/design/standard/data_table_normal.svg", EmbeddedTableData.class, EmbeddedTableDataPane.class); TableDataNameObjectCreator multiTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Relation"), "Multi", - "/com/fr/design/images/data/multi.png", ConditionTableData.class, MultiTDTableDataPane.class) { + "/com/fr/design/standard/multi_normal.svg", ConditionTableData.class, MultiTDTableDataPane.class) { public boolean isNeedParameterWhenPopulateJControlPane() { return true; } }; TableDataNameObjectCreator fileTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_File"), "File", - "/com/fr/design/images/data/file.png", FileTableData.class, FileTableDataSmallHeightPane.class); + "/com/fr/design/standard/file_normal.svg", FileTableData.class, FileTableDataSmallHeightPane.class); TableDataNameObjectCreator treeTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Tree"), "Tree", - "/com/fr/design/images/data/tree.png", RecursionTableData.class, TreeTableDataPane.class) { + "/com/fr/design/standard/tree_normal.svg", RecursionTableData.class, TreeTableDataPane.class) { public boolean isNeedParameterWhenPopulateJControlPane() { return true; } }; TableDataNameObjectCreator storeProcedure = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_Stored_Procedure"), "Proc", - "/com/fr/design/images/data/store_procedure.png", + "/com/fr/design/standard/store_procedure_normal.svg", StoreProcedure.class, ProcedureDataPane.class) { @Override public boolean shouldInsertSeparator() { @@ -72,33 +72,33 @@ public class TableDataCreatorProducer { public TableDataNameObjectCreator[] createServerTableDataCreator() { TableDataNameObjectCreator dataBase = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DS_Database_Query"), - "/com/fr/design/images/data/dock/serverdatabase.png", DBTableData.class, + "/com/fr/design/standard/server_database_normal.svg", DBTableData.class, DBTableDataPane.class); TableDataNameObjectCreator ds_Class = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Class"), - "/com/fr/design/images/data/dock/serverclasstabledata.png", ClassTableData.class, + "/com/fr/design/standard/class_table_data_normal.svg", ClassTableData.class, ClassTableDataPane.class); TableDataNameObjectCreator table = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Embedded"), - "/com/fr/design/images/data/dock/serverdatatable.png", EmbeddedTableData.class, + "/com/fr/design/standard/data_table_normal.svg", EmbeddedTableData.class, EmbeddedTableDataPane.class); TableDataNameObjectCreator fileTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_File"), - "/com/fr/design/images/data/file.png", FileTableData.class, + "/com/fr/design/standard/file_normal.svg", FileTableData.class, FileTableDataSmallPane.class); TableDataNameObjectCreator treeTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Tree"), - "/com/fr/design/images/data/tree.png", + "/com/fr/design/standard/tree_normal.svg", RecursionTableData.class, GlobalTreeTableDataPane.class) { public boolean isNeedParameterWhenPopulateJControlPane() { return true; } }; TableDataNameObjectCreator multiTable = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Relation"), - "/com/fr/design/images/data/multi.png", + "/com/fr/design/standard/multi_normal.svg", ConditionTableData.class, GlobalMultiTDTableDataPane.class) { public boolean isNeedParameterWhenPopulateJControlPane() { return true; } }; TableDataNameObjectCreator storeProcedure = new TableDataNameObjectCreator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tabledata_Type_Stored_Procedure"), - "/com/fr/design/images/data/store_procedure.png", + "/com/fr/design/standard/store_procedure_normal.svg", StoreProcedure.class, ProcedureDataPane.class) { @Override public boolean shouldInsertSeparator() { diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataNameObjectCreator.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataNameObjectCreator.java index 7dedc9f479..0ee4599159 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataNameObjectCreator.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataNameObjectCreator.java @@ -1,6 +1,8 @@ package com.fr.design.data.datapane; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; +import com.fr.base.svg.SVGLoader; import com.fr.data.impl.DBTableData; import com.fr.design.actions.tabledata.TableDataAction; import com.fr.design.beans.BasicBeanPane; @@ -39,7 +41,7 @@ public class TableDataNameObjectCreator extends NameObjectCreator { public TableDataNameObjectCreator(TableDataAction action) { super(action.getDisplayName(), action.getIconPath(), action.getTableDataClass(), action.getUpdateTableDataPaneClass()); this.iconPath = action.getIconPath(); - menuImage = BaseUtils.readImage(iconPath); + menuImage = SVGLoader.load(iconPath); isNeedInsertSeparator = action.isNeedInsertSeparator(); prefix = action.getPrefix(); } @@ -54,7 +56,7 @@ public class TableDataNameObjectCreator extends NameObjectCreator { super(menuName, iconPath, clazz, updatePane); if (iconPath != null) { this.iconPath = iconPath; - menuImage = BaseUtils.readImage(iconPath); + menuImage = SVGLoader.load(iconPath); } } @@ -62,7 +64,7 @@ public class TableDataNameObjectCreator extends NameObjectCreator { super(menuName, iconPath, clazz, updatePane); if (iconPath != null) { this.iconPath = iconPath; - menuImage = BaseUtils.readImage(iconPath); + menuImage = SVGLoader.load(iconPath); } this.prefix = prefix; } @@ -71,7 +73,7 @@ public class TableDataNameObjectCreator extends NameObjectCreator { super(menuName, iconPath, clazz, clazz4Init, updatePane); if (iconPath != null) { this.iconPath = iconPath; - menuImage = BaseUtils.readImage(iconPath); + menuImage = SVGLoader.load(iconPath); } } @@ -79,7 +81,7 @@ public class TableDataNameObjectCreator extends NameObjectCreator { super(menuName, iconPath, clazz, clazz4Init, updatePane); if (iconPath != null) { this.iconPath = iconPath; - menuImage = BaseUtils.readImage(iconPath); + menuImage = SVGLoader.load(iconPath); } this.prefix = prefix; } 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 32bd070d95..264a937999 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 @@ -3,13 +3,11 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; import com.fr.base.TableDataBean; import com.fr.config.RemoteConfigEvent; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; -import com.fr.data.api.StoreProcedureAssist; -import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.design.data.BasicTableDataUtils; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.gui.NameInspector; import com.fr.design.gui.controlpane.JListControlPane; import com.fr.design.gui.controlpane.NameableCreator; import com.fr.design.gui.ilist.ListModelElement; @@ -18,25 +16,28 @@ 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; import com.fr.stable.core.PropertyChangeAdapter; - import com.fr.third.org.apache.commons.collections4.MapUtils; import com.fr.workspace.WorkContext; -import javax.swing.*; + +import javax.swing.DefaultListModel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; /** * TableDataList Pane. @@ -52,15 +53,12 @@ public class TableDataPaneListPane extends JListControlPane implements TableData @Override public void propertyChange() { isNamePermitted = true; - String tempName = getEditingName(); - if (ComparatorUtils.equals(tempName, selectedName)) { - //说明双击之后又取消了,啥也不用做 + if (!checkName()) { + isNamePermitted = false; return; } - Set allDSNames = DesignTableDataManager.getGlobalDataSet().keySet(); - String[] allListNames = nameableList.getAllNames(); - allListNames[editingIndex] = StringUtils.EMPTY; + String tempName = getEditingName(); Object editingType = getEditingType(); if (!BasicTableDataUtils.checkName(tempName)) { @@ -70,35 +68,36 @@ public class TableDataPaneListPane extends JListControlPane implements TableData return; } - if (StringUtils.isEmpty(tempName)) { + if (editingType instanceof MultiResultTableData && isIncludeUnderline(tempName)) { isNamePermitted = false; nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), - Toolkit.i18nText("Fine-Design_Basic_Table_Data_Empty_Name_Tips"), - Toolkit.i18nText("Fine-Design_Report_Alert"), - JOptionPane.WARNING_MESSAGE); + FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips")); setIllegalIndex(editingIndex); return; } - boolean isRepeated = isNameRepeated(new Collection[]{allDSNames, Arrays.asList(allListNames)}, tempName); - if (isRepeated) { - isNamePermitted = false; - nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Table_Data_Duplicate_Name_Tips", tempName)); - setIllegalIndex(editingIndex); - } else if (editingType instanceof StoreProcedure && isIncludeUnderline(tempName)) { - isNamePermitted = false; - nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Stored_Procedure_Name_Tips")); - setIllegalIndex(editingIndex); - } + if (nameableList.getSelectedValue() instanceof ListModelElement) { - rename(selectedName, isRepeated ? NameInspector.ILLEGAL_NAME_HOLDER : tempName); + rename(selectedName, tempName); } } }); } + @Override + public String getEmptyNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Table_Data_Empty_Name_Tips"); + } + + @Override + public String getDuplicatedNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Table_Data_Duplicate_Name_Tips", getEditingName()); + } + + @Override + public Collection getExtraItemsToCheckNameRepeat() { + return DesignTableDataManager.getGlobalDataSet().keySet(); + } + @Override public void rename(String oldName, String newName) { //如果a改成了b,b又被改成了c,就认为是a改成了c @@ -137,7 +136,7 @@ public class TableDataPaneListPane extends JListControlPane implements TableData } private boolean isIncludeUnderline(String name) { - return name.contains(StoreProcedureAssist.GROUP_MARKER); + return name.contains(MultiResultTableData.GROUP_MARKER); } /** @@ -249,15 +248,30 @@ 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.class.getSimpleName()); + EventDispatcher.fire(RemoteConfigEvent.EDIT, TableDataConfig.getInstance().getNameSpace()); } } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } } + 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/TableDataSourceOP.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataSourceOP.java index 33e51100ea..61c578453c 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataSourceOP.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataSourceOP.java @@ -2,20 +2,25 @@ package com.fr.design.data.datapane; import com.fr.base.StoreProcedureParameter; import com.fr.base.TableData; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.data.impl.storeproc.StoreProcedureConstants; +import com.fr.data.impl.storeproc.StoreProcedureHelper; import com.fr.design.DesignModelAdapter; import com.fr.design.data.DesignTableDataManager; -import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper; -import com.fr.design.data.tabledata.wrapper.StoreProcedureNameWrapper; +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataNameWrapper; +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.gui.itree.refreshabletree.UserObjectOP; - import com.fr.general.NameObject; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; /** @@ -155,9 +160,9 @@ public class TableDataSourceOP implements UserObjectOP { list.add(initStoreProcedureNode(storeProcedureMap)); for (int i = 0; i < getNodeArrayFromMap(storeProcedureMap).length; i++) { ExpandMutableTreeNode tmpNode = getNodeArrayFromMap(storeProcedureMap)[i]; - if (((NameObject) tmpNode.getUserObject()).getObject() instanceof StoreProcedureNameWrapper) { - TableData tableData = ((StoreProcedureNameWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getStoreProcedure(); - setStoreProcedureTree(tableData, tmpNode); + if (((NameObject) tmpNode.getUserObject()).getObject() instanceof MultiResultTableDataNameWrapper) { + TableData tableData = ((MultiResultTableDataNameWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getTableData(); + setStoreProcedureTree((MultiResultTableData) tableData, tmpNode); serverlist.add(tmpNode); } } @@ -176,8 +181,8 @@ public class TableDataSourceOP implements UserObjectOP { for (int i = 0; i < getNodeArrayFromMap(dataMap).length; i++) { ExpandMutableTreeNode tmpNode = getNodeArrayFromMap(dataMap)[i]; TableData tableData = ((TableDataWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getTableData(); - if (tableData instanceof StoreProcedure) { - setStoreProcedureTree(tableData, tmpNode); + if (tableData instanceof MultiResultTableData) { + setStoreProcedureTree((MultiResultTableData) tableData, tmpNode); dataList.add(tmpNode); } else { dataList.add(tmpNode); @@ -185,31 +190,49 @@ public class TableDataSourceOP implements UserObjectOP { } } - protected void setStoreProcedureTree(TableData tableData, ExpandMutableTreeNode tmpNode) { + protected void setStoreProcedureTree(MultiResultTableData tableData, ExpandMutableTreeNode tmpNode) { ArrayList nodeName = new ArrayList<>(); - StoreProcedure storeProcedure = (StoreProcedure) tableData; String name = ((NameObject) tmpNode.getUserObject()).getName(); - StoreProcedureParameter[] parameters = StoreProcedure.getSortPara(storeProcedure.getParameters()); - List resultNames = storeProcedure.getResultNames(); + List resultNames = tableData.getResultNames(); boolean hasChild = false; tmpNode.remove(0); - TableDataWrapper tdw = new StoreProcedureNameWrapper(name + "_Table1", storeProcedure); + TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name + "_Table1", tableData); ExpandMutableTreeNode childNode = new ExpandMutableTreeNode(new NameObject("Table", tdw)); childNode.add(new ExpandMutableTreeNode()); tmpNode.add(childNode); - for (StoreProcedureParameter parameter : parameters) { - if (parameter.getSchema() != StoreProcedureConstants.IN) { - if (!nodeName.contains(parameter.getName())) { - nodeName.add(parameter.getName()); - hasChild = true; - String parameterName = name + "_" + parameter.getName(); - TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false); - ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(parameter.getName(), newTwd)); - newChildNode.add(new ExpandMutableTreeNode()); - tmpNode.add(newChildNode); + + if (tableData instanceof StoreProcedure) { + StoreProcedure storeProcedure = (StoreProcedure) tableData; + StoreProcedureParameter[] parameters = StoreProcedureHelper.getSortPara(storeProcedure.getParameters()); + for (StoreProcedureParameter parameter : parameters) { + if (parameter.getSchema() != StoreProcedureConstants.IN) { + if (!nodeName.contains(parameter.getName())) { + nodeName.add(parameter.getName()); + hasChild = true; + String parameterName = name + "_" + parameter.getName(); + TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false); + ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(parameter.getName(), newTwd)); + newChildNode.add(new ExpandMutableTreeNode()); + tmpNode.add(newChildNode); + } } } - } + } /*else { + if (tableData.getDataModelList().size() > 1) { + for (NameDataModel nameDataModel : tableData.getDataModelList()) { + if (!nodeName.contains(nameDataModel.getName())) { + nodeName.add(nameDataModel.getName()); + hasChild = true; + String parameterName = name + "_" + nameDataModel.getName(); + TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false); + ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(nameDataModel.getName(), newTwd)); + newChildNode.add(new ExpandMutableTreeNode()); + tmpNode.add(newChildNode); + } + } + } + }*/ + if (!resultNames.isEmpty()) { for (String resultName : resultNames) { @@ -217,7 +240,7 @@ public class TableDataSourceOP implements UserObjectOP { nodeName.add(resultName); hasChild = true; String parameterName = name + "_" + resultName; - TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false); + TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false); ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(resultName, newTwd)); newChildNode.add(new ExpandMutableTreeNode()); tmpNode.add(newChildNode); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java index 80471b9e65..ed08cffddf 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java @@ -1,7 +1,9 @@ package com.fr.design.data.datapane; -import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; +import com.fr.data.MultiResultTableData; import com.fr.design.constants.UIConstants; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.gui.itree.refreshabletree.UserObjectRefreshJTree; @@ -17,6 +19,10 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.awt.Color; import java.awt.Component; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * TableData Tree @@ -24,6 +30,10 @@ import java.awt.Component; public class TableDataTree extends UserObjectRefreshJTree { private static final long serialVersionUID = 1L; + private static final String TABLE_DATA_NODE = "tableData"; + + private static final String COLUMN_NODE = "column"; + /** * Constructor. */ @@ -44,7 +54,7 @@ public class TableDataTree extends UserObjectRefreshJTree { Object userObj = treeNode.getUserObject(); if (userObj instanceof String) { // p:这个是column field. - this.setIcon(BaseUtils.readIcon("com/fr/design/images/data/field.png")); + this.setIcon(IconUtils.readIcon("/com/fr/design/standard/field")); this.setText((String) userObj); } else if (userObj instanceof NameObject) { NameObject nameObject = (NameObject) userObj; @@ -55,14 +65,14 @@ public class TableDataTree extends UserObjectRefreshJTree { } else if (nameObject.getObject() instanceof Integer) { int num = (Integer) nameObject.getObject(); if (num == TableDataSourceOP.SERVER_TABLE_DATA) { - this.setIcon(BaseUtils.readIcon(IconPathConstants.STD_SHOW_ICON_PATH)); + this.setIcon(IconUtils.readIcon(IconPathConstants.STD_SHOW_ICON_PATH)); } else if (num == TableDataSourceOP.STORE_PRECEDURE_DATA) { - this.setIcon(BaseUtils.readIcon(IconPathConstants.SP_SHOW_ICON_PATH)); + this.setIcon(IconUtils.readIcon(IconPathConstants.SP_SHOW_ICON_PATH)); } else { - this.setIcon(BaseUtils.readIcon(IconPathConstants.DS_QUERY_ICON_PATH)); + this.setIcon(IconUtils.readIcon(IconPathConstants.DS_QUERY_ICON_PATH)); } } else { - this.setIcon(BaseUtils.readIcon("/com/fr/design/images/data/store_procedure.png")); + this.setIcon(IconUtils.readIcon("/com/fr/design/images/data/store_procedure.png")); } } else if (userObj == PENDING) { this.setIcon(null); @@ -84,12 +94,13 @@ public class TableDataTree extends UserObjectRefreshJTree { this.tableDataTreeCellRenderer = tableDataTreeCellRenderer; } + @Override protected void refreshTreeNode(ExpandMutableTreeNode eTreeNode, String childName) { if (interceptRefresh(eTreeNode)) { return; } boolean refreshall = childName.isEmpty(); - ExpandMutableTreeNode[] new_nodes = loadChildTreeNodes(eTreeNode); + ExpandMutableTreeNode[] newNodes = loadChildTreeNodes(eTreeNode); java.util.List childTreeNodeList = new java.util.ArrayList(); for (int i = 0, len = eTreeNode.getChildCount(); i < len; i++) { @@ -102,30 +113,30 @@ public class TableDataTree extends UserObjectRefreshJTree { eTreeNode.removeAllChildren(); - for (int ci = 0; ci < new_nodes.length; ci++) { - Object cUserObject = new_nodes[ci].getUserObject(); + for (int ci = 0; ci < newNodes.length; ci++) { + Object cUserObject = newNodes[ci].getUserObject(); ExpandMutableTreeNode cTreeNode = null; for (int ni = 0, nlen = childTreeNodeList.size(); ni < nlen; ni++) { cTreeNode = (ExpandMutableTreeNode) childTreeNodeList.get(ni); if (ComparatorUtils.equals(cTreeNode.getUserObject(), cUserObject)) { if (!refreshall && !ComparatorUtils.equals(childName, ((NameObject) cUserObject).getName())) { - new_nodes[ci] = cTreeNode; + newNodes[ci] = cTreeNode; break; } - new_nodes[ci].setExpanded(cTreeNode.isExpanded()); + newNodes[ci].setExpanded(cTreeNode.isExpanded()); // REPORT-41299 如果建立的是错误的数据集(没有Child的情况)且这个错误数据集处于isExpanded状态,会在后面的if语句中调用getFirstChild()产生异常,因此这里判断一下 - if (cTreeNode.isExpanded() && cTreeNode.getChildCount() == 0) { - new_nodes[ci].setExpanded(false); + if (cTreeNode.getChildCount() == 0) { + newNodes[ci].setExpanded(false); break; } if (cTreeNode.getFirstChild() instanceof ExpandMutableTreeNode && cTreeNode.isExpanded()) { - checkChildNodes(cTreeNode, new_nodes[ci]); + checkChildNodes(cTreeNode, newNodes[ci]); } break; } } - eTreeNode.add(new_nodes[ci]); + eTreeNode.add(newNodes[ci]); } } @@ -140,9 +151,7 @@ public class TableDataTree extends UserObjectRefreshJTree { for (int k = 0; k < nodes.length; k++) { newChild.add(nodes[k]); } - if (newChild.getChildCount() > 1 && ((ExpandMutableTreeNode) newChild.getFirstChild()).getUserObject() == PENDING) { - newChild.remove(0); - } + removePending(newChild); if (ComparatorUtils.equals(oldChild.getUserObject(), newChild.getUserObject())) { newChild.setExpanded(oldChild.isExpanded()); } @@ -150,9 +159,100 @@ public class TableDataTree extends UserObjectRefreshJTree { } } + private void removePending(ExpandMutableTreeNode treeNode) { + if (treeNode.getChildCount() > 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) { + treeNode.remove(0); + } + } + + @Override + public void refresh4TreeSearch() { + ExpandMutableTreeNode root = (ExpandMutableTreeNode) this.getModel().getRoot(); + refreshTreeNode4TreeSearch(root); + ((DefaultTreeModel) this.getModel()).reload(root); + root.expandCurrentTreeNode(this); + } + + /** + * 主要是处理节点是否应该添加为搜索结果,以及节点是否需要展开 + * + * @param root + */ + private void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) { + if (interceptRefresh(root)) { + return; + } + // 获取数据集子节点 + ExpandMutableTreeNode[] dsTreeNodes = loadChildTreeNodes(root); + root.removeAllChildren(); + for (ExpandMutableTreeNode dsTreeNode : dsTreeNodes) { + if (TableDataTreeSearchManager.getInstance().nodeNameMatches(dsTreeNode.getUserObject().toString())) { + // 加载数据列节点 + loadAndAddChildTreeChild(dsTreeNode); + // 处理子节点的展开 + dealWithNodeExpand(dsTreeNode); + // 添加数据集子节点 + root.add(dsTreeNode); + } + } + } + + /** + * 加载所有子节点,并添加到父节点中 + * + * @param treeNode + * @return + */ + private ExpandMutableTreeNode loadAndAddChildTreeChild(ExpandMutableTreeNode treeNode) { + if (isTreeNodeStoreProcedure(treeNode)) { + // 如果是存储过程,则再加载一次其子表节点,这里比较坑的就是存储过程不能使用loadChildTreeNodes + int tableChildCounts = treeNode.getChildCount(); + ExpandMutableTreeNode[] childs = new ExpandMutableTreeNode[tableChildCounts]; + for (int i = 0; i < tableChildCounts; i++) { + ExpandMutableTreeNode tableChild = (ExpandMutableTreeNode) treeNode.getChildAt(i); + loadAndAddChildTreeChild(tableChild); + childs[i] = tableChild; + removePending(tableChild); + } + treeNode.addChildTreeNodes(childs); + } else { + ExpandMutableTreeNode[] expandMutableTreeNodes = loadChildTreeNodes(treeNode); + treeNode.addChildTreeNodes(expandMutableTreeNodes); + } + removePending(treeNode); + return treeNode; + } + + /** + * 处理节点的展开,如果此节点是存储过程,还会处理其子表节点的展开 + * 只针对数据集节点 + * + * @param treeNode + * @return + */ + public ExpandMutableTreeNode dealWithNodeExpand(ExpandMutableTreeNode treeNode) { + String tableDataName = treeNode.getUserObject().toString(); + // 主要还是处理存储过程 + if (isTreeNodeStoreProcedure(treeNode)) { + int childCount = treeNode.getChildCount(); + for (int i = 0; i < childCount; i++) { + ExpandMutableTreeNode child = (ExpandMutableTreeNode) treeNode.getChildAt(i); + String nodeName = tableDataName + "_" + child.getUserObject().toString(); + if (TableDataTreeSearchManager.getInstance().nodeCanExpand(nodeName)) { + child.setExpanded(true); + } + } + } + if (TableDataTreeSearchManager.getInstance().nodeCanExpand(treeNode.getUserObject().toString())) { + treeNode.setExpanded(true); + } + return treeNode; + } + /* * p:获得选中的NameObject = name + tabledata. */ + @Override public NameObject getSelectedNameObject() { TreePath selectedTreePath = this.getSelectionPath(); if (selectedTreePath == null) { @@ -182,6 +282,108 @@ public class TableDataTree extends UserObjectRefreshJTree { } + /** + * 获得选中的数据集节点的NameObject的数组,只会返回数据集节点的NameObject + * 当多选了数据集或数据列时,也只返回选中的数据集 + */ + public NameObject[] getSelectedTableDataNameObjects() { + Map> tableDataNodesAndColumnNodes = getSelectedTableDataNodesAndColumnNodes(); + List tableDataNodes = tableDataNodesAndColumnNodes.get(TABLE_DATA_NODE); + if (tableDataNodes == null) { + return new NameObject[0]; + } + return tableDataNodes.stream().map(node -> (NameObject) node.getUserObject()).toArray(NameObject[]::new); + } + + /** + * 获取选中的数据集节点和列名节点 + * 其中存储过程的子表节点不计入数据集节点中,仅存储过程节点本身计入数据集节点 + * @return + */ + private Map> getSelectedTableDataNodesAndColumnNodes() { + TreePath[] selectedTreePaths = this.getSelectionPaths(); + if (selectedTreePaths == null) { + return new HashMap<>(); + } + Map> resultMap = new HashMap<>(); + List tableDataNodes = new ArrayList<>(); + List columnNodes = new ArrayList<>(); + resultMap.put(TABLE_DATA_NODE, tableDataNodes); + resultMap.put(COLUMN_NODE, columnNodes); + for (TreePath selectedTreePath : selectedTreePaths) { + if (selectedTreePath == null) { + continue; + } + ExpandMutableTreeNode selectedTreeNode = (ExpandMutableTreeNode) selectedTreePath.getLastPathComponent(); + if (isTableDataNodes(selectedTreeNode)) { + // 数据集节点 + tableDataNodes.add(selectedTreeNode); + } else { + // 列名节点 + columnNodes.add(selectedTreeNode); + } + } + return resultMap; + } + + /** + * 获取选中的数据集数量,选中数据列则不计入 + * + * @return + */ + public int getSelectedTableDataCounts() { + return getSelectedTableDataNameObjects().length; + } + + /** + * 是否存在单独选了数据列节点,但没选其对应数据集的情况 + * @return + */ + public boolean hasSelectedIndependentColumns() { + Map> tableDataNodesAndColumnNodes = getSelectedTableDataNodesAndColumnNodes(); + List tableDataNodes = tableDataNodesAndColumnNodes.get(TABLE_DATA_NODE); + List columnNodes = tableDataNodesAndColumnNodes.get(COLUMN_NODE); + if (columnNodes == null || columnNodes.size() == 0) { + // 未选中数据列 + return false; + } + if (tableDataNodes == null || tableDataNodes.size() == 0) { + // 选中数据列而未选中数据集 + return true; + } + boolean result = false; + for (ExpandMutableTreeNode columnNode : columnNodes) { + ExpandMutableTreeNode tableDataNode = getBelongedTableDataNodes(columnNode); + if (!tableDataNodes.contains(tableDataNode)) { + result = true; + } + } + return result; + } + + /** + * 获取一个节点归属的数据集层级父节点 + * @param treeNode + * @return + */ + private ExpandMutableTreeNode getBelongedTableDataNodes(ExpandMutableTreeNode treeNode) { + if (isTableDataNodes(treeNode)) { + return treeNode; + } + return getBelongedTableDataNodes((ExpandMutableTreeNode) treeNode.getParent()); + } + + private boolean isTableDataNodes(ExpandMutableTreeNode treeNode) { + if (treeNode == null) { + return false; + } + Object userObject = treeNode.getUserObject(); + if (userObject instanceof NameObject && ((NameObject) userObject).getObject() instanceof TableDataWrapper) { + return true; + } + return false; + } + public TableDataWrapper[] getSelectedDatas() { TreePath[] selectedTreePaths = this.getSelectionPaths(); if (selectedTreePaths == null || selectedTreePaths.length == 0) { @@ -247,4 +449,20 @@ public class TableDataTree extends UserObjectRefreshJTree { treeModel.reload(root); } + + /** + * 判断此节点是否为存储过程 + * + * @param treeNode + * @return + */ + public boolean isTreeNodeStoreProcedure(ExpandMutableTreeNode treeNode) { + Object userObject = treeNode.getUserObject(); + if (userObject instanceof NameObject) { + NameObject nameObject = (NameObject) userObject; + TableDataWrapper tableDataWrapper = (TableDataWrapper) nameObject.getObject(); + return tableDataWrapper.getTableData() instanceof MultiResultTableData; + } + return false; + } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index 0850cf05a1..57ad09d0e7 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -1,6 +1,7 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; import com.fr.data.impl.DBTableData; import com.fr.data.impl.TableDataSourceDependent; @@ -13,30 +14,41 @@ import com.fr.design.data.BasicTableDataTreePane; import com.fr.design.data.BasicTableDataUtils; import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.StrategyConfigAttrUtils; +import com.fr.design.data.datapane.auth.TableDataAuthHelper; +import com.fr.design.data.datapane.management.clip.TableDataTreeClipboard; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; +import com.fr.design.data.datapane.management.search.pane.TableDataSearchRemindPane; +import com.fr.design.data.datapane.management.search.pane.TreeSearchToolbarPane; +import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode; import com.fr.design.data.tabledata.StoreProcedureWorkerListener; +import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils; import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.TableDataLoadingPane; import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; import com.fr.design.dialog.BasicDialog; +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.fun.TableDataPaneProcessor; import com.fr.design.gui.ibutton.UIHeadGroup; import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ilist.CheckBoxListWithPartialSelect; +import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.i18n.Toolkit; -import com.fr.design.icon.IconPathConstants; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.LineSeparator; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.esd.core.strategy.config.StrategyConfig; import com.fr.esd.core.strategy.config.StrategyConfigHelper; import com.fr.esd.event.DSMapping; @@ -45,7 +57,6 @@ import com.fr.esd.event.StrategyEventsNotifier; import com.fr.esd.query.StrategicTableData; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralContext; -import com.fr.general.IOUtils; import com.fr.general.NameObject; import com.fr.log.FineLoggerFactory; import com.fr.plugin.context.PluginContext; @@ -53,6 +64,7 @@ import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; +import com.fr.stable.StringUtils; import com.fr.stable.core.PropertyChangeAdapter; import com.fr.workspace.WorkContext; import org.jetbrains.annotations.NotNull; @@ -60,7 +72,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -68,12 +79,17 @@ import javax.swing.ToolTipManager; import javax.swing.tree.TreePath; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Dimension; import java.awt.GridLayout; import java.awt.dnd.DnDConstants; import java.awt.event.ActionEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -103,15 +119,37 @@ public class TableDataTreePane extends BasicTableDataTreePane { return singleton; } + /** + * 获取不必每次都refreshDockingView的数据集树面板 + * 不会主动替换DesignModelAdapter,需要保证使用时没有跨模板动作,谨慎使用 + * + * @param tc + * @return + */ + public synchronized static BasicTableDataTreePane getInstanceWithoutRefreshEverytime(DesignModelAdapter tc) { + TableDataPaneProcessor treePaneProcessor = ExtraDesignClassManager.getInstance().getSingle(TableDataPaneProcessor.XML_TAG); + if (treePaneProcessor != null) { + return treePaneProcessor.createTableDataTreePane(tc); + } + return singleton.tc == null ? getInstance(tc) : singleton; + } + private TableDataSourceOP op; private TableDataTree tableDataTree; + private UIPopupMenu popupMenu; private EditAction editAction; private RemoveAction removeAction; + private CopyAction copyAction; + private PasteAction pasteAction; private EsdOnAction esdAction; private EsdOffAction esdOffAction; + private SwitchAction switchAction; private PreviewTableDataAction previewTableDataAction; private JPanel serverDatasetAuthTipJPanel = new JPanel(); + private TableDataSearchRemindPane remindPane; + private TreeSearchToolbarPane toolbarPane; + private TableDataTreePane() { initPane(); } @@ -120,76 +158,150 @@ public class TableDataTreePane extends BasicTableDataTreePane { this.setLayout(new BorderLayout(4, 0)); this.setBorder(null); - //TableDataTree - tableDataTree = new TableDataTree(); + initTableDataTree(); + toolbarPane = initToolBarPane(); + JPanel treePane = initTreePane(); + dealWithTableDataTree(); + this.add(toolbarPane, BorderLayout.NORTH); + this.add(treePane, BorderLayout.CENTER); + checkButtonEnabled(); + } + + /** + * 处理TableDataTree的监听等 + */ + private void dealWithTableDataTree() { + // tooltip ToolTipManager.sharedInstance().registerComponent(tableDataTree); ToolTipManager.sharedInstance().setDismissDelay(3000); ToolTipManager.sharedInstance().setInitialDelay(0); + // 右键菜单 + popupMenu = new UIPopupMenu(); + popupMenu.add(editAction.createMenuItem()); + popupMenu.add(previewTableDataAction.createMenuItem()); + popupMenu.addSeparator(); + popupMenu.add(copyAction.createMenuItem()); + popupMenu.add(pasteAction.createMenuItem()); + popupMenu.add(removeAction.createMenuItem()); + popupMenu.addSeparator(); + // 监听 + tableDataTree.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + // 服务器暂不支持右键菜单 + if (SwingUtilities.isRightMouseButton(e) && op.getDataMode() != TableDataSourceOP.SERVER_TABLE_DATA) { + GUICoreUtils.showPopupMenu(popupMenu, e.getComponent(), e.getX(), e.getY()); + } + checkButtonEnabled(); + } + }); + tableDataTree.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + //F2重命名先屏蔽了, 有bug没时间弄 + if (e.getKeyCode() == KeyEvent.VK_F2) { + return; + } + super.keyPressed(e); + checkButtonEnabled(); + } + @Override + public void keyReleased(KeyEvent e) { + super.keyReleased(e); + checkButtonEnabled(); + } + }); + // TreeCellEditor + tableDataTree.setEditable(true); + TableDataTreeCellEditor treeCellEditor = new TableDataTreeCellEditor(new UITextField(), tableDataTree, this); + treeCellEditor.addCellEditorListener(treeCellEditor); + tableDataTree.setCellEditor(treeCellEditor); + new TableDataTreeDragSource(tableDataTree, DnDConstants.ACTION_COPY); + } + + /** + * 工具栏面板 + * + * @return + */ + private TreeSearchToolbarPane initToolBarPane() { + // toolbar addMenuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add")); - addMenuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH); + addMenuDef.setIconPath("/com/fr/design/standard/addpopup/addPopup"); createAddMenuDef(); // 创建插件监听 createPluginListener(); editAction = new EditAction(); + copyAction = new CopyAction(); + pasteAction = new PasteAction(); removeAction = new RemoveAction(); previewTableDataAction = new PreviewTableDataAction(tableDataTree); connectionTableAction = new ConnectionTableAction(); esdAction = new EsdOnAction(); esdOffAction = new EsdOffAction(); - + switchAction = new SwitchAction(); toolbarDef = new ToolBarDef(); - toolbarDef.addShortCut(addMenuDef, SeparatorDef.DEFAULT, editAction, removeAction, SeparatorDef.DEFAULT, previewTableDataAction, connectionTableAction, esdAction, esdOffAction); + toolbarDef.addShortCut(addMenuDef, SeparatorDef.DEFAULT, editAction, removeAction, SeparatorDef.DEFAULT, previewTableDataAction, connectionTableAction, esdAction, esdOffAction, switchAction); UIToolbar toolBar = ToolBarDef.createJToolBar(); toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIConstants.TOOLBAR_BORDER_COLOR)); toolBar.setBorderPainted(true); toolbarDef.updateToolBar(toolBar); - JPanel toolbarPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - toolbarPane.add(toolBar, BorderLayout.CENTER); - this.add(toolbarPane, BorderLayout.NORTH); + TreeSearchToolbarPane searchLayerdPane = new TreeSearchToolbarPane(toolBar); + searchLayerdPane.setPreferredSize(new Dimension(this.getWidth(), 23)); - UIScrollPane scrollPane = new UIScrollPane(tableDataTree); - scrollPane.setBorder(null); + return searchLayerdPane; + } + + /** + * 数据集树面板 + * + * @return + */ + private JPanel initTreePane() { + JPanel treePane = new JPanel(new BorderLayout(0, 6)); + // north + JPanel northPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); initServerDatasetAuthTipJPanel(); initButtonGroup(); - JPanel jPanel = new JPanel(new BorderLayout(0, 0)); - JPanel buttonPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); - buttonPane.add(buttonGroup, BorderLayout.CENTER); - buttonPane.add(serverDatasetAuthTipJPanel, BorderLayout.SOUTH); - jPanel.add(buttonPane, BorderLayout.NORTH); - jPanel.add(scrollPane, BorderLayout.CENTER); - this.add(jPanel, BorderLayout.CENTER); - tableDataTree.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - checkButtonEnabled(); - } - }); - tableDataTree.addKeyListener(getTableTreeNodeListener(editAction, previewTableDataAction, removeAction, op, tableDataTree)); - // TreeCellEditor - tableDataTree.setEditable(true); - TableDataTreeCellEditor treeCellEditor = new TableDataTreeCellEditor(new UITextField(), tableDataTree, this); - treeCellEditor.addCellEditorListener(treeCellEditor); - tableDataTree.setCellEditor(treeCellEditor); - new TableDataTreeDragSource(tableDataTree, DnDConstants.ACTION_COPY); - checkButtonEnabled(); + northPane.add(buttonGroup, BorderLayout.CENTER); + northPane.add(serverDatasetAuthTipJPanel, BorderLayout.SOUTH); + // center + remindPane = new TableDataSearchRemindPane(getDataTree()); + + treePane.add(northPane, BorderLayout.NORTH); + treePane.add(remindPane, BorderLayout.CENTER); + return treePane; + } + + /** + * 初始化 TableDataTree + */ + private void initTableDataTree() { + tableDataTree = new TableDataTree(); } private void initServerDatasetAuthTipJPanel() { - String[] lineTips = Toolkit.i18nText("Fine-Design_Server_Dataset_Auth_Tip").split("\n"); + String datasetAuthTip = Toolkit.i18nText("Fine-Design_Server_Dataset_Auth_Tip"); + List lineTips = new ArrayList(Arrays.asList(datasetAuthTip.split("\n"))); + if (datasetAuthTip.endsWith("\n")) { + lineTips.add(StringUtils.EMPTY); + } serverDatasetAuthTipJPanel = new JPanel(); - serverDatasetAuthTipJPanel.setLayout(new GridLayout(lineTips.length, 1)); - for (int i = 0; i < lineTips.length; i++) { - String lineTip = lineTips[i]; + serverDatasetAuthTipJPanel.setLayout(new GridLayout(lineTips.size(), 1)); + for (int i = 0; i < lineTips.size(); i++) { + String lineTip = lineTips.get(i); List jLabels = new ArrayList<>(); - jLabels.add(new JLabel(lineTip)); - if (i == (lineTips.length - 1)) { + JLabel lineJLabel = new JLabel(lineTip); + lineJLabel.setForeground(Color.lightGray); + jLabels.add(lineJLabel); + if (i == (lineTips.size() - 1)) { JLabel jLabel = new JLabel(Toolkit.i18nText("Fine-Design_Basic_Alphafine_No_Remind")); - jLabel.setForeground(Color.lightGray); + jLabel.setForeground(Color.blue); jLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -292,6 +404,10 @@ public class TableDataTreePane extends BasicTableDataTreePane { */ @Override public void dgEdit(final AbstractTableDataPane tableDataPane, String originalName, boolean isUpdate) { + // 编辑时如果正在搜索,跳回原树 + if (TableDataTreeSearchManager.getInstance().isInSearchMode()) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); + } tableDataPane.addStoreProcedureWorkerListener(new StoreProcedureWorkerListener() { public void fireDoneAction() { if (tableDataTree.getSelectionPath() == null) { @@ -353,20 +469,59 @@ public class TableDataTreePane extends BasicTableDataTreePane { //单独编辑数据集关闭,修改缓存配置状态,刷新下一键开启/关闭按钮 checkButtonEnabled(); + + if (listener != null) { + listener.doOk(); + } } @Override public void doCancel() { super.doCancel(); + if (listener != null) { + listener.doCancel(); + } } }); tdNamePanel.addPropertyChangeListener(new PropertyChangeAdapter() { @Override public void propertyChange() { - doPropertyChange(dg, tdNamePanel, oldName); + checkNameChange(tableDataPane, dg, tdNamePanel, oldName); } }); - dg.setVisible(true); + // 有些数据集(DBTableData)面板的初始化过程中是包含了SwingWorker处理(查询数据连接、查表等)的 + // 如果这里直接setVisible,可能阻塞SwingWorker的done方法,导致面板渲染出现问题 + SwingUtilities.invokeLater(() -> { + dg.setVisible(true); + }); + } + + private void checkNameChange(AbstractTableDataPane tableDataPane, BasicDialog dg, BasicPane.NamePane nPanel, final String oldName) { + nPanel.setShowText(StringUtils.BLANK); + dg.setButtonEnabled(true); + String tempName = nPanel.getObjectName(); + if (StringUtils.isBlank(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Empty_Name_Tips")); + dg.setButtonEnabled(false); + } else if (!ComparatorUtils.equals(oldName, tempName) && isDsNameRepeaded(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Duplicate_Name_Tips", tempName)); + dg.setButtonEnabled(false); + } else if (oldName.length() >= PROCEDURE_NAME_INDEX && tableDataPane.updateBean() instanceof MultiResultTableData) { + if (isIncludeUnderline(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips")); + dg.setButtonEnabled(false); + } + } else if (!BasicTableDataUtils.checkName(tempName)) { + dg.setButtonEnabled(false); + } else { + nPanel.setShowText(StringUtils.BLANK); + dg.setButtonEnabled(true); + } + } + + + private boolean isIncludeUnderline(String name) { + return !ComparatorUtils.equals(name.indexOf(MultiResultTableData.GROUP_MARKER), -1); } @Override @@ -456,6 +611,17 @@ public class TableDataTreePane extends BasicTableDataTreePane { ((TableDataSourceDependent) td).setTableDataSource(tds); } String tdName = nPanel.getObjectName(); + + //处理缓存策略配置 + if (uPanel instanceof DBTableDataPane) { + StrategyConfig editingConfig = ((DBTableDataPane) uPanel).updateStrategyConfig(); + if (editingConfig != null) { + editingConfig.setDsName(tdName); + StrategyConfigAttrUtils.addStrategyConfig(editingConfig); + } + ((DBTableData) td).setDsName(tdName); + } + tds.putTableData(tdName, td); Map map = new HashMap(); if (!ComparatorUtils.equals(paneName, tdName)) { @@ -467,6 +633,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { int[] rows = tableDataTree.getSelectionRows(); tableDataTree.refreshChildByName(tdName); tableDataTree.setSelectionRows(rows); + FineLoggerFactory.getLogger().info("add table data succeeded for {}", tdName); } @Override @@ -486,11 +653,61 @@ public class TableDataTreePane extends BasicTableDataTreePane { this.createAddMenuDef(); } + /** + * 感觉这里,把一堆Action和Op之类的送到抽象类里去检查,很奇怪,抽象类本身定义的Action只有add和connection + * 另外因为改动了数据集树节点的选中逻辑,所以这边改成自己类内部实现 + * 不直接改抽象类是怕影响到部分插件兼容 + */ private void checkButtonEnabled() { - super.checkButtonEnabled(editAction, previewTableDataAction, removeAction, op, tableDataTree); + // 检查添加与定义数据连接操作 + this.checkAddAndConnectionEnabled(); + // 检查编辑、预览、复制、粘贴、删除等基本操作 + this.checkBasicButtonEnabled(); + // 检查esd相关操作 this.checkESDComponentsEnabled(); } + private void checkAddAndConnectionEnabled() { + connectionTableAction.setEnabled(WorkContext.getCurrent() != null && WorkContext.getCurrent().isRoot()); + addMenuDef.setEnabled(!(op == null || op.interceptButtonEnabled() || op.getDataMode() == SERVER_TABLE_DATA)); + } + + private void checkBasicButtonEnabled() { + // 设置下各个button的基本状态,避免代码重复 + editAction.setEnabled(false); + copyAction.setEnabled(false); + pasteAction.setEnabled(false); + removeAction.setEnabled(false); + previewTableDataAction.setEnabled(false); + if (op == null || op.interceptButtonEnabled()) { + // 保持false状态 + return; + } + // 获取选中的数据集数量 + int selectioncount = getDataTree().getSelectedTableDataCounts(); + if (op.getDataMode() == SERVER_TABLE_DATA) { + // 服务器数据集下,选中数据集数量为1时,可以预览 + if (selectioncount == 1 && !getDataTree().hasSelectedIndependentColumns()) { + previewTableDataAction.setEnabled(true); + } + // 其它保持false状态 + return; + } + // 模板数据集时,粘贴可用 + pasteAction.setEnabled(true); + if (selectioncount == 0 || getDataTree().hasSelectedIndependentColumns()) { + // 未选中数据集,或存在单独选中的数据列时,其它保持false状态 + return; + } + if (selectioncount == 1) { + // 仅选中单个数据集时,才可以编译、预览 + editAction.setEnabled(true); + previewTableDataAction.setEnabled(true); + } + removeAction.setEnabled(true); + copyAction.setEnabled(true); + } + private void checkESDComponentsEnabled() { if (buttonGroup.getSelectedIndex() == 1) { @@ -579,6 +796,9 @@ public class TableDataTreePane extends BasicTableDataTreePane { if (op != null) { op.setDataMode(modeArray[buttonGroup.getSelectedIndex()]); addMenuDef.setEnabled(modeArray[buttonGroup.getSelectedIndex()] == TEMPLATE_TABLE_DATA); + if (TableDataTreeSearchManager.getInstance().isInSearchMode()) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); + } refreshDockingView(); } @@ -674,8 +894,8 @@ public class TableDataTreePane extends BasicTableDataTreePane { } @Override - public Icon getIcon() { - return IOUtils.readIcon("/com/fr/design/images/control/batch_esd_on.png"); + public String getIconResource() { + return "/com/fr/design/standard/batchesdon/batch_esd_on"; } @Override @@ -721,8 +941,8 @@ public class TableDataTreePane extends BasicTableDataTreePane { } @Override - public Icon getIcon() { - return IOUtils.readIcon("/com/fr/design/images/control/batch_esd_off.png"); + public String getIconResource() { + return "/com/fr/design/standard/batchesdoff/batch_esd_off"; } @Override @@ -743,14 +963,14 @@ public class TableDataTreePane extends BasicTableDataTreePane { public abstract String getName(); - public abstract Icon getIcon(); + public abstract String getIconResource(); public abstract void doWithTableDataWrapper(TableDataWrapper tableDataWrapper); public AbstractESDAction() { this.setName(getName()); this.setMnemonic('R'); - this.setSmallIcon(getIcon()); + this.setSmallIcon(getIconResource()); } @Override @@ -816,7 +1036,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { public EditAction() { this.setName(Toolkit.i18nText("Fine-Design_Basic_Edit")); this.setMnemonic('E'); - this.setSmallIcon(IOUtils.readIcon(IconPathConstants.TD_EDIT_ICON_PATH)); + this.setSmallIcon("/com/fr/design/standard/editdataset/edit"); } @Override @@ -833,8 +1053,46 @@ public class TableDataTreePane extends BasicTableDataTreePane { AbstractTableDataPane tableDataPane = wrapper.creatTableDataPane(); - //下面创建creatTableDataPane后会直接populate,所以populate时不能用后设置的一些参数,比如name - dgEdit(tableDataPane, dsName, false); + if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) { + // 先打开一个Loading面板 + TableDataLoadingPane loadingPane = new TableDataLoadingPane(); + BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(TableDataTreePane.this), null); + // 查询权限 + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + // 获取无权限连接名称集合 + Collection noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); + // 获取当前数据集对应的数据连接名称 + String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); + return !noAuthConnections.contains(connectionName); + } + + @Override + protected void done() { + try { + Boolean hasAuth = get(); + if (hasAuth) { + // 有权限时,关闭Loading面板,打开编辑面板 + loadingDialog.setVisible(false); + dgEdit(tableDataPane, dsName, false); + } else { + // 无权限时,给出无权限提示 + loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage()); + // 查询权限失败时,给出报错提示 + loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME); + } + } + }.execute(); + loadingDialog.setVisible(true); + } else { + // 无需检查权限时,直接打开数据库查询编辑面板 + //下面创建creatTableDataPane后会直接populate,所以populate时不能用后设置的一些参数,比如name + dgEdit(tableDataPane, dsName, false); + } } } @@ -843,39 +1101,140 @@ public class TableDataTreePane extends BasicTableDataTreePane { public RemoveAction() { this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove")); this.setMnemonic('R'); - this.setSmallIcon(IOUtils.readIcon(IconPathConstants.TD_REMOVE_ICON_PATH)); + this.setSmallIcon("/com/fr/design/standard/remove/remove"); } @Override public void actionPerformed(ActionEvent e) { - NameObject selectedNO = tableDataTree.getSelectedNameObject(); - - if (selectedNO == null) { + NameObject[] selectedNameObjects = tableDataTree.getSelectedTableDataNameObjects(); + if (selectedNameObjects == null || selectedNameObjects.length == 0) { + FineLoggerFactory.getLogger().error("Table Data to remove is null or not selected"); return; } + // 可以半选的CheckBoxList + CheckBoxListWithPartialSelect tableDataCheckBoxPane = new CheckBoxListWithPartialSelect(selectedNameObjects); + UIScrollPane scrollPane = new UIScrollPane(tableDataCheckBoxPane); + UILabel tips = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Select_Source_To_Remove")); + BasicPane basicPane = new BasicPane() { + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_Remove"); + } + }; + basicPane.setLayout(new BorderLayout()); + basicPane.add(tips, BorderLayout.NORTH); + basicPane.add(scrollPane, BorderLayout.CENTER); + BasicDialog basicDialog = basicPane.showSmallWindow(SwingUtilities.getWindowAncestor(TableDataTreePane.this), new DialogActionAdapter() { + @Override + public void doOk() { + List selectedValues = tableDataCheckBoxPane.getSelectedObjects(); + // 删除时如果正在搜索,跳回原树 + if (TableDataTreeSearchManager.getInstance().isInSearchMode()) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); + } + for (Object toRemove : selectedValues) { + try { + doRemove((String) toRemove); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "remove table data failed for {}", toRemove); + } + } + } - int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + ":" + selectedNO.getName() + "?", - Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (returnVal == JOptionPane.OK_OPTION) { - // richer:这个地方为什么要在DataSourceTree里面去remove呢?多此一举吧 - op.removeAction(selectedNO.getName()); - tableDataTree.refresh(); - // Richie:默认最后一行获得焦点. - tableDataTree.requestFocus(); - tableDataTree.setSelectionRow(tableDataTree.getRowCount() - 1); - fireDSChanged(); - checkButtonEnabled(); + @Override + public void doCancel() { + super.doCancel(); + } + }); + basicDialog.setVisible(true); + } - //删掉缓存配置 - StrategyConfigAttrUtils.removeStrategyConfig(selectedNO.getName()); + private void doRemove(String toRemove) throws Exception { + // richer:这个地方为什么要在DataSourceTree里面去remove呢?多此一举吧 + op.removeAction(toRemove); + tableDataTree.refresh(); + // Richie:默认最后一行获得焦点. + tableDataTree.requestFocus(); + tableDataTree.setSelectionRow(tableDataTree.getRowCount() - 1); + fireDSChanged(); + checkButtonEnabled(); + + //删掉缓存配置 + StrategyConfigAttrUtils.removeStrategyConfig(toRemove); + + // 如果一个模版是平台开启,这个数据集的配置不会存xml,预览模版时直接从全局配置copy,这样 + // 导致删除的时候StrategyConfigsAttrSavedHook没有通过前后配置比较感知数据集被删除,因此不会发出事件让其失效 + // 这里额外发出一次数据集修改事件 + StrategyEventsNotifier.modifyDataSet(new DSMapping(getTplPath(), new DsNameTarget(toRemove))); + DesignTableDataManager.removeSelectedColumnNames(toRemove); + DesignModelAdapter.getCurrentModelAdapter().removeTableDataParameters(toRemove); + FineLoggerFactory.getLogger().info("remove table data succeeded for {}", toRemove); + } + } + + private class CopyAction extends UpdateAction { + + public CopyAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Copy")); + this.setMnemonic('C'); + this.setSmallIcon("/com/fr/design/standard/copy/copy"); + } + + @Override + public void actionPerformed(ActionEvent e) { + NameObject[] selectedNameObjects = tableDataTree.getSelectedTableDataNameObjects(); + Map dataWrapperMap = TableDataTreeClipboard.getInstance().transferNameObjectArray2Map(selectedNameObjects); + TableDataTreeClipboard.getInstance().addToClip(dataWrapperMap); + } + } - // 如果一个模版是平台开启,这个数据集的配置不会存xml,预览模版时直接从全局配置copy,这样 - // 导致删除的时候StrategyConfigsAttrSavedHook没有通过前后配置比较感知数据集被删除,因此不会发出事件让其失效 - // 这里额外发出一次数据集修改事件 - StrategyEventsNotifier.modifyDataSet(new DSMapping(getTplPath(), new DsNameTarget(selectedNO.getName()))); - DesignTableDataManager.removeSelectedColumnNames(selectedNO.getName()); - DesignModelAdapter.getCurrentModelAdapter().removeTableDataParameters(selectedNO.getName()); + private class PasteAction extends UpdateAction { + + public PasteAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Action_Paste_Name")); + this.setMnemonic('P'); + this.setSmallIcon("/com/fr/design/images/m_edit/paste"); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 粘贴时如果正在搜索,跳回原树 + if (TableDataTreeSearchManager.getInstance().isInSearchMode()) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); } + Map dataWrapperMap = TableDataTreeClipboard.getInstance().takeFromClip(); + for (Map.Entry dataWrapperEntry : dataWrapperMap.entrySet()) { + // 处理数据集名称 + String dsName = getNoRepeatedDsName4Paste(dataWrapperEntry.getKey()); + AbstractTableDataWrapper wrapper = dataWrapperEntry.getValue(); + AbstractTableDataPane tableDataPane = TableDataFollowingPasteUtils.generateTableDataPaneWhenPaste(wrapper); + if (tableDataPane != null) { + addDataPane(tableDataPane, dsName); + } + } + } + } + + public String getNoRepeatedDsName4Paste(String oldName) { + while (isDsNameRepeaded(oldName)) { + oldName = oldName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data"); + } + return oldName; + } + + private class SwitchAction extends UpdateAction { + + public SwitchAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Search")); + this.setMnemonic('S'); + this.setSmallIcon("/com/fr/design/standard/search", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 交换层级 + toolbarPane.switchPane(TreeSearchToolbarPane.SEARCH_PANE); + TableDataTreeSearchManager.getInstance().switchToSearch(TableDataSearchMode.match(buttonGroup.getSelectedIndex()), DesignTableDataManager.getEditingTableDataSource()); } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java b/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java new file mode 100644 index 0000000000..382e04dd94 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java @@ -0,0 +1,57 @@ +package com.fr.design.data.datapane.auth; + +import com.fr.base.TableData; +import com.fr.data.impl.Connection; +import com.fr.data.impl.DBTableData; +import com.fr.data.impl.NameDatabaseConnection; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.connection.DBConnectAuth; + +import java.util.Collection; +import java.util.Collections; + +/** + * 数据连接权限相关的工具类 + * @author Yvan + */ +public class TableDataAuthHelper { + + /** + * 编辑数据集时是否需要检查权限 + * @param tableData + * @return + */ + public static boolean needCheckAuthWhenEdit(TableData tableData) { + // 远程设计下,编辑DBTableData时需要判断权限 + return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData; + } + + /** + * 获取无权限数据连接集合 + * 远程下需要调用RPC,为耗时操作,谨慎使用 + * @return + */ + public static Collection getNoAuthConnections() { + // 获取无权限连接集合 + Collection noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections(); + return noAuthConnections == null ? Collections.emptyList() : noAuthConnections; + } + + /** + * 通过数据集获取其数据连接的名称 + * + * 注意: + * 1. Connection接口本身是不提供名称的,只有我们内部为了使用方便,将其包装成了NameDataBaseConnection + * 如果不是NameDataBaseConnection类型,则无名称,因此这里只能用判断类型的方式获取名称 + * 2. 仅支持DBTableData获取连接名 + * @return + */ + public static String getConnectionNameByDBTableData(DBTableData tableData) { + Connection database = tableData.getDatabase(); + if (database instanceof NameDatabaseConnection) { + return ((NameDatabaseConnection) database).getName(); + } + return StringUtils.EMPTY; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/AdvancePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/AdvancePane.java new file mode 100644 index 0000000000..7784aa5712 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/AdvancePane.java @@ -0,0 +1,145 @@ +package com.fr.design.data.datapane.connect; + +import com.fr.data.impl.JDBCDatabaseConnection; +import com.fr.data.pool.DBCPConnectionPoolAttr; +import com.fr.design.dialog.BasicPane; +import com.fr.design.editor.editor.IntegerEditor; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.stable.StringUtils; + +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +/** + * @author xiqiu + * @date 2021/11/22 + * @description + */ +public class AdvancePane extends BasicPane { + private IntegerEditor DBCP_MAX_ACTIVE = new IntegerEditor(); + private UIComboBox DBCP_TESTONBORROW = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Basic_No"), Toolkit.i18nText("Fine-Design_Basic_Yes")}); + private IntegerEditor DBCP_MAX_WAIT = new IntegerEditor(); + private SpecialUITextField DBCP_VALIDATION_QUERY = new SpecialUITextField(); + + + public AdvancePane() { + JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + DBCP_VALIDATION_QUERY.addFocusListener(new JTextFieldHintListener(DBCP_VALIDATION_QUERY)); + double p = TableLayout.PREFERRED; + DBCP_VALIDATION_QUERY.setColumns(20); + double[] rowSizeDbcp = {p, p, p, p}; + double[] columnDbcp = {190, p}; + Component[][] comps = { + {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Max_Active") + ":", SwingConstants.RIGHT), DBCP_MAX_ACTIVE}, + {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Validation_Query") + ":", SwingConstants.RIGHT), DBCP_VALIDATION_QUERY}, + {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Test_On_Borrow") + ":", SwingConstants.RIGHT), DBCP_TESTONBORROW}, + {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Connection_Pool_Max_Wait_Time") + ":", SwingConstants.RIGHT), DBCP_MAX_WAIT} + }; + + JPanel contextPane = TableLayoutHelper.createGapTableLayoutPane(comps, rowSizeDbcp, columnDbcp, 11, 11); + jPanel.add(contextPane, BorderLayout.CENTER); + this.add(jPanel); + } + + + public void populate(JDBCDatabaseConnection jdbcDatabase) { + DBCPConnectionPoolAttr dbcpAttr = jdbcDatabase.getDbcpAttr(); + if (dbcpAttr == null) { + dbcpAttr = new DBCPConnectionPoolAttr(); + jdbcDatabase.setDbcpAttr(dbcpAttr); + } + this.DBCP_MAX_ACTIVE.setValue(dbcpAttr.getMaxActive()); + this.DBCP_MAX_WAIT.setValue(dbcpAttr.getMaxWait()); + this.DBCP_VALIDATION_QUERY.setText(dbcpAttr.getValidationQuery()); + this.DBCP_TESTONBORROW.setSelectedIndex(dbcpAttr.isTestOnBorrow() ? 1 : 0); + + } + + public void update(JDBCDatabaseConnection jdbcDatabase) { + DBCPConnectionPoolAttr dbcpAttr = jdbcDatabase.getDbcpAttr(); + if (dbcpAttr == null) { + dbcpAttr = new DBCPConnectionPoolAttr(); + jdbcDatabase.setDbcpAttr(dbcpAttr); + } + dbcpAttr.setMaxActive(this.DBCP_MAX_ACTIVE.getValue().intValue()); + dbcpAttr.setMaxWait(this.DBCP_MAX_WAIT.getValue().intValue()); + dbcpAttr.setValidationQuery(this.DBCP_VALIDATION_QUERY.getText()); + dbcpAttr.setTestOnBorrow(this.DBCP_TESTONBORROW.getSelectedIndex() == 0 ? false : true); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_Advanced_Setup"); + } + + + private class JTextFieldHintListener implements FocusListener { + private SpecialUITextField textField; + + public JTextFieldHintListener(SpecialUITextField jTextField) { + this.textField = jTextField; + } + + @Override + public void focusGained(FocusEvent e) { + //获取焦点时,清空提示内容 + String temp = textField.getText(); + textField.setForeground(Color.BLACK); + textField.setTextOrigin(temp); + + } + + @Override + public void focusLost(FocusEvent e) { + //失去焦点时,没有输入内容,显示提示内容 + String temp = textField.getTextOrigin(); + textField.setText(temp); + } + } + + private class SpecialUITextField extends UITextField { + + @Override + public String getText() { + String text = super.getText(); + if (isUseless(text)) { + return StringUtils.EMPTY; + } + return text; + } + + @Override + public void setText(String text) { + if (isUseless(text)) { + this.setForeground(Color.GRAY); + super.setText(Toolkit.i18nText("Fine-Design_Dbcp_Default_Query")); + } else { + this.setForeground(Color.BLACK); + super.setText(text); + } + } + + public String getTextOrigin() { + return super.getText(); + } + + public void setTextOrigin(String text) { + super.setText(text); + } + + private boolean isUseless(String text) { + return text == null || text.isEmpty() || Toolkit.i18nText("Fine-Design_Dbcp_Default_Query").equals(text); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java index 3b5aebed9e..76f32d6f0c 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java @@ -10,11 +10,10 @@ import com.fr.design.editlock.EditLockUtils; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UILockButton; import com.fr.file.ConnectionConfig; -import com.fr.general.ComparatorUtils; +import com.fr.report.LockItem; import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; import com.fr.workspace.server.connection.DBConnectAuth; -import com.fr.report.LockItem; import javax.swing.SwingUtilities; import java.awt.Dimension; @@ -96,6 +95,7 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { continue; } Connection connection = mgr.getConnection(conName); + // nameList依赖items方法初始化,父类ItemEditableComboBoxPanel里异步执行item方法 filterConnection(connection, conName, nameList); } @@ -138,20 +138,34 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel { if (connection instanceof NameDatabaseConnection) { this.setSelectedItem(((NameDatabaseConnection) connection).getName()); } else { - String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); - if (StringUtils.isNotBlank(s)) { - for (int i = 0; i < this.getConnectionSize(); i++) { - String t = this.getConnection(i); - if (ComparatorUtils.equals(s, t)) { - this.setSelectedItem(s); - break; - } - } - } - // alex:如果这个ComboBox还是没有选中,那么选中第一个 - if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) { - this.setSelectedItem(this.getConnection(0)); + setRecentConnection(); + } + } + + /** + * 下拉框选项设置成最近选择的connection,如果最近选择不存在,则选择列表中的第一个 + */ + protected void setRecentConnection() { + String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection(); + if (StringUtils.isNotBlank(s)) { + // 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白 + // 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置 + if (nameList.contains(s)) { + this.setSelectedItem(s); } } + // alex:如果这个ComboBox还是没有选中,那么选中第一个 + if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) { + this.setSelectedItem(this.getConnection(0)); + } + } + + /** + * 是否无选中状态(空白item也视为无选中) + * @return + */ + protected boolean isSelectedItemEmpty() { + String selectedItem = this.getSelectedItem(); + return selectedItem == null || StringUtils.equals(selectedItem, EMPTY.toString()); } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListDialogActionAdapter.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListDialogActionAdapter.java index 2428c9a005..947cb6e75f 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListDialogActionAdapter.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListDialogActionAdapter.java @@ -2,11 +2,15 @@ package com.fr.design.data.datapane.connect; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.FineJOptionPane; import com.fr.design.editlock.EditLockUtils; +import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.file.ConnectionConfig; import com.fr.report.LockItem; +import javax.swing.JOptionPane; + /** * @author hades * @version 11.0 @@ -32,7 +36,13 @@ public class ConnectionListDialogActionAdapter extends DialogActionAdapter { connectionListDialog.setDoOKSucceed(false); return; } - connectionManagerPane.update(connectionConfig); + try { + connectionManagerPane.update(connectionConfig); + } catch (Exception e) { + connectionListDialog.setDoOKSucceed(false); + FineJOptionPane.showMessageDialog(connectionManagerPane, e.getMessage(), Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.ERROR_MESSAGE); + return; + } DesignerContext.getDesignerBean("databasename").refreshBeanElement(); // 关闭定义数据连接页面,为其解锁 EditLockUtils.unlock(LockItem.CONNECTION); 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 018aa8f4c8..87b1c404f3 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 @@ -1,39 +1,53 @@ package com.fr.design.data.datapane.connect; import com.fr.config.RemoteConfigEvent; +import com.fr.data.driver.DriverClassNotFoundException; import com.fr.data.impl.Connection; import com.fr.data.impl.ConnectionBean; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.impl.JNDIDatabaseConnection; +import com.fr.data.metric.utils.DatabaseConnectionMetricHandler; +import com.fr.data.operator.DataOperator; import com.fr.design.ExtraDesignClassManager; +import com.fr.design.data.MapCompareUtils; import com.fr.design.dialog.BasicDialog; -import com.fr.design.dialog.FineJOptionPane; import com.fr.design.fun.ConnectionProvider; import com.fr.design.gui.controlpane.JListControlPane; import com.fr.design.gui.controlpane.NameObjectCreator; import com.fr.design.gui.controlpane.NameableCreator; +import com.fr.design.gui.ilist.ListModelElement; import com.fr.design.i18n.Toolkit; import com.fr.event.EventDispatcher; import com.fr.file.ConnectionConfig; -import com.fr.general.ComparatorUtils; +import com.fr.file.ConnectionOperator; import com.fr.general.NameObject; +import com.fr.license.database.DBTypes; +import com.fr.license.database.DataBaseTypePointManager; +import com.fr.license.exception.DataBaseNotSupportedException; import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils; import com.fr.stable.Nameable; import com.fr.stable.StringUtils; import com.fr.stable.core.PropertyChangeAdapter; - -import com.fr.third.org.apache.commons.collections4.MapUtils; +import com.fr.transaction.Configurations; +import com.fr.transaction.WorkerFacade; import com.fr.workspace.WorkContext; -import com.fr.file.ConnectionOperator; +import com.fr.workspace.server.database.DataBaseTypeOperator; +import org.jetbrains.annotations.NotNull; + +import javax.swing.SwingWorker; import java.awt.Window; -import javax.swing.*; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; /** * Connection List Pane. @@ -41,39 +55,57 @@ import java.util.Set; public class ConnectionListPane extends JListControlPane implements ConnectionShowPane { public static final String TITLE_NAME = Toolkit.i18nText("Fine-Design_Basic_Server_Define_Data_Connection"); private boolean isNamePermitted = true; - private HashMap renameMap = new HashMap(); + private final HashMap renameMap = new HashMap<>(); + private final Map populatedConnectionsSnapshot = new LinkedHashMap<>(); + private static List supportedDatabaseTypes = new ArrayList<>(); public ConnectionListPane() { renameMap.clear(); this.addEditingListener(new PropertyChangeAdapter() { public void propertyChange() { isNamePermitted = true; - String[] allListNames = nameableList.getAllNames(); - allListNames[nameableList.getSelectedIndex()] = StringUtils.EMPTY; - String tempName = getEditingName(); - if (StringUtils.isEmpty(tempName)) { - nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(ConnectionListPane.this), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Connection_Empty_Name")); - setIllegalIndex(editingIndex); + if (!checkName()) { isNamePermitted = false; return; } - if (!ComparatorUtils.equals(tempName, selectedName) - && isNameRepeated(new List[]{Arrays.asList(allListNames)}, tempName)) { - isNamePermitted = false; - nameableList.stopEditing(); - String message = Toolkit.i18nText("Fine-Design_Basic_Connection_Duplicate_Name", tempName); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(ConnectionListPane.this), message); - setIllegalIndex(editingIndex); - } - if (isNamePermitted && !ComparatorUtils.equals(tempName, selectedName)) { - rename(selectedName, tempName); - } - + rename(selectedName, getEditingName()); } }); + + getSupportedTypes(); + } + + /** + * 获取本地、远程环境lic中未受限制的数据库类型信息 + */ + private static void getSupportedTypes() { + SwingWorker, Void> getSupportedTypesWorker = new SwingWorker, Void>() { + @Override + protected List doInBackground() { + return WorkContext.getCurrent().get(DataBaseTypeOperator.class).getSupportedDatabaseTypes(); + } + + @Override + protected void done() { + try { + supportedDatabaseTypes = get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }; + getSupportedTypesWorker.execute(); + } + + @Override + public String getEmptyNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Connection_Empty_Name"); } + @Override + public String getDuplicatedNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Connection_Duplicate_Name", getEditingName()); + } protected void rename(String oldName, String newName) { //如果a改成了b,b又被改成了c,就认为是a改成了c @@ -115,21 +147,31 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh /** * 创建菜单项 + *

+ * 方法中获取limitDatabaseType使用了远程rpc调用,可能会比较耗时 * * @return 菜单项 */ public NameableCreator[] createNameableCreators() { - NameableCreator[] creators = new NameableCreator[]{new NameObjectCreator( + NameObjectCreator jdbc = new NameObjectCreator( "JDBC", "/com/fr/design/images/data/source/jdbcTableData.png", JDBCDatabaseConnection.class, DatabaseConnectionPane.JDBC.class - ), new NameObjectCreator( + ); + NameObjectCreator jndi = new NameObjectCreator( "JNDI", "/com/fr/design/images/data/source/jdbcTableData.png", JNDIDatabaseConnection.class, DatabaseConnectionPane.JNDI.class - )}; + ); + NameableCreator[] creators; + if (WorkContext.getCurrent().get(DataBaseTypeOperator.class).limitDatabaseType()) { + // 不支持JNDI,屏蔽接口 + creators = new NameableCreator[]{jdbc}; + } else { + creators = new NameableCreator[]{jdbc, jndi}; + } Set pluginCreators = ExtraDesignClassManager.getInstance().getArray(ConnectionProvider.XML_TAG); for (ConnectionProvider provider : pluginCreators) { NameObjectCreator creator = new NameObjectCreator( @@ -156,39 +198,177 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh */ public void populate(ConnectionConfig connectionConfig) { List nameObjectList = new ArrayList(); + populatedConnectionsSnapshot.clear(); for (Map.Entry entry : connectionConfig.getConnections().entrySet()) { nameObjectList.add(new NameObject(entry.getKey(), entry.getValue())); + try { + populatedConnectionsSnapshot.put(entry.getKey(), (Connection) entry.getValue().clone()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } } this.populate(nameObjectList.toArray(new NameObject[nameObjectList.size()])); - } /** * Update. */ - public void update(ConnectionConfig connectionConfig) { + public void update(ConnectionConfig connectionConfig) throws Exception { // Nameable[]居然不能强转成NameObject[],一定要这么写... Nameable[] res = this.update(); - List connectionBeans = new ArrayList<>(); - Map map = MapUtils.invertMap(getRenameMap()); - for (int i = 0; i < res.length; i++) { - NameObject nameObject = (NameObject) res[i]; - String oldName = map.get(nameObject.getName()); - if (oldName == null) { - oldName = StringUtils.EMPTY; + Map updatedMap = new LinkedHashMap<>(); + Arrays.stream(res).map(n -> (NameObject) n).forEach(no -> updatedMap.put(no.getName(), (Connection) no.getObject())); + + List removedConnNames = new ArrayList<>(); + List addedOrUpdatedConnections = new ArrayList<>(); + + MapCompareUtils.contrastMapEntries(populatedConnectionsSnapshot, updatedMap, (entryEventKind, s, connection) -> { + switch (entryEventKind) { + case REMOVED: + removedConnNames.add(s); + break; + case ADDED: + case UPDATED: + addedOrUpdatedConnections.add(new ConnectionBean(s, StringUtils.EMPTY, connection)); + if (connection instanceof JDBCDatabaseConnection) { + DatabaseConnectionMetricHandler.handleSaveConnection((JDBCDatabaseConnection) connection, null); + } + default: + break; + } + }, new MapCompareUtils.UpdateRule() { + @Override + public boolean needUpdate(Connection origin, Connection connection) { + return needUpdate0(origin, connection); + } + + /** + * 是否需要更新处理 + * 1. Connection本身equals为false,代表字段修改 + * 2. 非内置的Connection,即插件提供的Connection + * todo 原本一个equals方法就可以搞定,但是插件里面没有实现equals,结果导致不能正确判断,只能主代码里做兼容,很恶心,先记个todo,以后看有没有办法改掉 + * @param origin + * @param connection + * @return + */ + private boolean needUpdate0(Connection origin, Connection connection) { + return !connection.equals(origin) || !isEmbedConnection(connection); + } + + /** + * 是否是主工程里内置的Connection + * @return + */ + private boolean isEmbedConnection(Connection connection) { + return connection instanceof JDBCDatabaseConnection || connection instanceof JNDIDatabaseConnection; + } + }); + + this.validateDatabaseType(addedOrUpdatedConnections); + this.validateConnections(addedOrUpdatedConnections); + this.alterConnections(removedConnNames, addedOrUpdatedConnections); + } + + /** + * 校验是否支持所有新增和修改数据连接的数据库类型 + */ + public void validateDatabaseType(@NotNull List addedOrUpdatedConnections) { + Set notSupportedConnections = new HashSet<>(); + if (!addedOrUpdatedConnections.isEmpty()) { + for (ConnectionBean bean : addedOrUpdatedConnections) { + Connection connection = bean.getConnection(); + // 仅校验jdbc连接,其他插件数据连接不进行校验 + if (connection instanceof JDBCDatabaseConnection) { + DBTypes dataBaseTypePoint = DataBaseTypePointManager.getInstance().getDataBaseTypePoint(connection.getDriver(), connection.feature()); + if (connectionIsNotSupported(connection, dataBaseTypePoint)) { + notSupportedConnections.addAll(dataBaseTypePoint.getDataBaseType()); + } + } + } + } + + if (!notSupportedConnections.isEmpty()) { + throw new DataBaseNotSupportedException(notSupportedConnections, supportedDatabaseTypes); + } + } + + /** + * 校验当前数据连接是否被限制 + */ + private static boolean connectionIsNotSupported(Connection connection, DBTypes dataBaseTypePoint) { + return !validateFRDemo(connection.getDriver(), connection.feature()) && + (dataBaseTypePoint != null && !supportedDatabaseTypes.containsAll(dataBaseTypePoint.getDataBaseType())); + } + + /** + * 校验当前是否为FRDemo,不对其进行限制 + */ + private static boolean validateFRDemo(String driver, String url) { + if (DBTypes.Sqlite.getDriver().equals(driver) && url.contains(DBTypes.Sqlite.getUrlKey())) { + // 产品:对sqlite类型只允许示例连接FRDemo + String databaseName = url.substring(url.lastIndexOf("/") + 1); + return StringUtils.equals("FRDemo.db", databaseName); + } + + return false; + } + + + private void validateConnections(List addedOrUpdatedConnections) throws Exception { + + for (ConnectionBean connectionBean : addedOrUpdatedConnections) { + Connection connection = connectionBean.getConnection(); + try { + DataOperator.getInstance().validateConnectionSettings(connection); + } catch (DriverClassNotFoundException e) { + FineLoggerFactory.getLogger().info(e.getMessage()); + } catch (Exception e) { + throw new SQLException(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Invalid_Config", connectionBean.getName()) + ", " + e.getMessage(), e.getCause()); } - connectionBeans.add(new ConnectionBean(nameObject.getName(), oldName, (Connection) nameObject.getObject())); } + + } + + private void alterConnections(List removedConnNames, List addedOrUpdatedConnections) { + try { - WorkContext.getCurrent().get(ConnectionOperator.class).saveConnection(connectionBeans); + WorkContext.getCurrent().get(ConnectionOperator.class, exceptionInfo -> saveByOldWay(removedConnNames, addedOrUpdatedConnections)) + .saveConnection(removedConnNames, addedOrUpdatedConnections); + + // hades:远程环境时,由于时直接RPC调用远程修改,因此设计器本地配置需要失效 if (!WorkContext.getCurrent().isLocal()) { - EventDispatcher.fire(RemoteConfigEvent.EDIT, ConnectionConfig.class.getSimpleName()); + EventDispatcher.fire(RemoteConfigEvent.EDIT, ConnectionConfig.getInstance().getNameSpace()); } } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } } + private boolean saveByOldWay(List removedConnNames, List addedOrUpdatedConnections) { + final int remaining = ConnectionConfig.getInstance().getRemainingCon(removedConnNames.size(), addedOrUpdatedConnections.size()); + try { + return Configurations.modify(new WorkerFacade(ConnectionConfig.class) { + @Override + public void run() { + removedConnNames.forEach(n -> ConnectionConfig.getInstance().removeConnection(n)); + int innerRemaining = remaining; + for (ConnectionBean cb : addedOrUpdatedConnections) { + if (innerRemaining > 0) { + ConnectionConfig.getInstance().addConnectionWithoutCheck(cb.getName(), cb.getConnection()); + innerRemaining--; + } else { + break; + } + } + } + }); + } 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() { @@ -197,14 +377,23 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh ConnectionConfig cloned = connectionConfig.mirror(); populate(cloned); } - - @Override - protected void renameConnection(String oldName, String newName) { - connectionConfig.renameConnection(oldName, newName); - } }; final BasicDialog connectionListDialog = connectionManagerPane.showLargeWindow(parent, null); connectionListDialog.addDialogActionListener(new ConnectionListDialogActionAdapter(connectionManagerPane, connectionListDialog, connectionConfig)); connectionListDialog.setVisible(true); } + + @Override + public void onCopyItem() { + super.onCopyItem(); + ListModelElement selectedValue = getSelectedValue(); + // identity 需要重置 + if (selectedValue != null && selectedValue.wrapper != null) { + Object temp = ((NameObject) selectedValue.wrapper).getObject(); + if (temp instanceof JDBCDatabaseConnection) { + JDBCDatabaseConnection object = (JDBCDatabaseConnection) temp; + object.setIdentity(UUID.randomUUID().toString()); + } + } + } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java index 6c768145f3..eadf456e09 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java @@ -4,9 +4,8 @@ import com.fr.design.gui.frpane.LoadingBasicPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.file.ConnectionConfig; - -import javax.swing.*; -import java.awt.*; +import javax.swing.JPanel; +import java.awt.BorderLayout; import java.util.HashMap; public class ConnectionManagerPane extends LoadingBasicPane implements ConnectionShowPane { @@ -39,7 +38,7 @@ public class ConnectionManagerPane extends LoadingBasicPane implements Connectio this.connectionListPane.populate(datasourceManager); } - public void update(ConnectionConfig datasourceManager) { + public void update(ConnectionConfig datasourceManager) throws Exception { this.connectionListPane.update(datasourceManager); } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java index b5ae09be8e..2b74ddcf9e 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java @@ -7,7 +7,7 @@ import com.fr.file.ConnectionConfig; * 数据链接显示面板 */ public interface ConnectionShowPane { - void update(ConnectionConfig connectionConfig); + void update(ConnectionConfig connectionConfig) throws Exception; void populate(ConnectionConfig connectionConfig); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java index a979a20cd6..613eed9a48 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java @@ -1,26 +1,32 @@ package com.fr.design.data.datapane.connect; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.data.core.db.TableProcedure; import com.fr.data.impl.AbstractDatabaseConnection; import com.fr.data.impl.Connection; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.UIConstants; +import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ilist.TableViewList; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.general.GeneralContext; import com.fr.stable.ArrayUtils; +import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.ToolTipManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -45,7 +51,39 @@ public class ConnectionTableProcedurePane extends BasicPane { private java.util.List listeners = new java.util.ArrayList(); public ConnectionTableProcedurePane() { + init(null); + } + + /** + * 传入父容器 + * @param parent + */ + public ConnectionTableProcedurePane(SwitchableTableDataPane parent) { + init(parent); + } + + private void init(SwitchableTableDataPane parent) { this.setLayout(new BorderLayout(4, 4)); + // 初始化数据连接下拉框 + initConnectionComboBox(parent); + // 初始化中间的面板 + JPanel centerPane = initCenterPane(); + this.add(connectionComboBox, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); + addKeyMonitor(); + } + + private JPanel initCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 搜索面板 + centerPane.add(createSearchPane(), BorderLayout.NORTH); + // 数据库表视图面板 + centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER); + return centerPane; + } + + private void initConnectionComboBox(SwitchableTableDataPane parent) { connectionComboBox = new ConnectionComboBoxPanel(com.fr.data.impl.Connection.class) { @Override @@ -60,10 +98,34 @@ public class ConnectionTableProcedurePane extends BasicPane { search(true); } } + + @Override + protected void afterRefreshItems() { + // 刷新完成后,如果未选中(在nameList初始化完成之前可能会出现),则尝试再次设置 + if (isSelectedItemEmpty()) { + setRecentConnection(); + } + // 获取数据连接之后,让父容器切换面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + } + + @Override + protected void refreshItemsError() { + // 获取数据连接出现错误时,也让父容器从Loading面板切换至内容面板 + if (parent != null) { + parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); + } + } }; + connectionComboBox.addComboBoxActionListener(filter); + } + + private JPanel createTableViewBorderPane() { tableViewList = new TableViewList(); ToolTipManager.sharedInstance().registerComponent(tableViewList); - connectionComboBox.addComboBoxActionListener(filter); + tableViewList.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() >= 2) { @@ -80,23 +142,50 @@ public class ConnectionTableProcedurePane extends BasicPane { } } }); - JPanel filterPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); + tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER); JPanel checkBoxgroupPane = createCheckBoxgroupPane(); if (checkBoxgroupPane != null) { - filterPane.add(createCheckBoxgroupPane(), BorderLayout.NORTH); + tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH); } + return tableViewBorderPane; + } + + /** + * 创建搜索Panel,用于搜索表或视图 + * @return + */ + private JPanel createSearchPane() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); JPanel searchPane = new JPanel(new BorderLayout(10, 0)); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.setBackground(Color.WHITE); searchField = new UITextField(); - searchPane.add(searchField, BorderLayout.CENTER); + searchField.setBorderPainted(false); + searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search")); searchField.getDocument().addDocumentListener(searchListener); - filterPane.add(searchPane, BorderLayout.CENTER); - UIScrollPane tableViewListPane = new UIScrollPane(tableViewList); - tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - this.add(connectionComboBox, BorderLayout.NORTH); - this.add(tableViewListPane, BorderLayout.CENTER); - this.add(filterPane, BorderLayout.SOUTH); - this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height)); - addKeyMonitor(); + searchField.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + super.mouseEntered(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED)); + } + + @Override + public void mouseExited(MouseEvent e) { + super.mouseExited(e); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + } + }); + // 搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + searchPane.add(searchField, BorderLayout.CENTER); + searchPane.add(searchLabel, BorderLayout.EAST); + panel.add(searchPane, BorderLayout.CENTER); + return panel; } protected void filter(Connection connection, String conName, List nameList) { @@ -224,4 +313,4 @@ public class ConnectionTableProcedurePane extends BasicPane { */ public void actionPerformed(TableProcedure target); } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java index f65b6dc128..86e7633be0 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java @@ -20,6 +20,7 @@ import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingConstants; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Window; @@ -45,13 +46,8 @@ public class DBCPAttrPane extends BasicPane { private static final int EMPTY_FETCHSIZE = -2; // carl:DBCP的一些属性 private IntegerEditor DBCP_INITIAL_SIZE = new IntegerEditor(); - private IntegerEditor DBCP_MAX_ACTIVE = new IntegerEditor(); - private IntegerEditor DBCP_MAX_IDLE = new IntegerEditor(); private IntegerEditor DBCP_MIN_IDLE = new IntegerEditor(); - private IntegerEditor DBCP_MAX_WAIT = new IntegerEditor(); - private UITextField DBCP_VALIDATION_QUERY = new UITextField(); - private UIComboBox DBCP_TESTONBORROW = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Basic_No"), Toolkit.i18nText("Fine-Design_Basic_Yes")}); private UIComboBox DBCP_TESTONRETURN = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Basic_No"), Toolkit.i18nText("Fine-Design_Basic_Yes")}); private UIComboBox DBCP_TESTWHILEIDLE = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Basic_No"), Toolkit.i18nText("Fine-Design_Basic_Yes")}); @@ -75,25 +71,19 @@ public class DBCPAttrPane extends BasicPane { defaultPane = this; // JPanel northFlowPane - northFlowPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Basic_ConnectionPool_Attr")); - northFlowPane.setPreferredSize(new Dimension(630, 320)); + northFlowPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Basic_ConnectionPool_Attr")); + northFlowPane.setPreferredSize(new Dimension(630, 330)); defaultPane.add(northFlowPane, BorderLayout.NORTH); - DBCP_VALIDATION_QUERY.setColumns(15); // ContextPane double f = TableLayout.FILL; // double p = TableLayout.PREFERRED; - double[] rowSize = {f, f, f, f, f, f, f, f, f, f, f, f}; + double[] rowSize = {f, f, f, f, f, f, f}; double[] columnSize = {f, f}; Component[][] comps = { {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Initial_Size") + ":", SwingConstants.RIGHT), DBCP_INITIAL_SIZE}, - {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Max_Active") + ":", SwingConstants.RIGHT), DBCP_MAX_ACTIVE}, - {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Max_Idle") + ":", SwingConstants.RIGHT), DBCP_MAX_IDLE}, {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Min_Idle") + ":", SwingConstants.RIGHT), DBCP_MIN_IDLE}, - {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Connection_Pool_Max_Wait_Time") + ":", SwingConstants.RIGHT), DBCP_MAX_WAIT}, - {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Validation_Query") + ":", SwingConstants.RIGHT), DBCP_VALIDATION_QUERY}, - {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Test_On_Borrow") + ":", SwingConstants.RIGHT), DBCP_TESTONBORROW}, {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Test_On_Return") + ":", SwingConstants.RIGHT), DBCP_TESTONRETURN}, {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Dbcp_Test_While_Idle") + ":", SwingConstants.RIGHT), DBCP_TESTWHILEIDLE}, {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Connection_Pool_Evictionruns_millis") + ":", SwingConstants.RIGHT), @@ -102,8 +92,13 @@ public class DBCPAttrPane extends BasicPane { {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Connection_Pool_Mix_Evictable_Idle_Time_Millis") + ":", SwingConstants.RIGHT), DBCP_MINEVICTABLEIDLETIMEMILLIS}}; - JPanel contextPane = TableLayoutHelper.createGapTableLayoutPane(comps, rowSize, columnSize, 10, 4); + JPanel contextPane = TableLayoutHelper.createGapTableLayoutPane(comps, rowSize, columnSize, 10, 10); northFlowPane.add(contextPane); + JPanel boxFlowInnerContainer = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 5, 5); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Dbcp_Warning")); + uiLabel.setForeground(Color.RED); + boxFlowInnerContainer.add(uiLabel); + northFlowPane.add(boxFlowInnerContainer); } public void populate(JDBCDatabaseConnection jdbcDatabase) { @@ -113,12 +108,7 @@ public class DBCPAttrPane extends BasicPane { jdbcDatabase.setDbcpAttr(dbcpAttr); } this.DBCP_INITIAL_SIZE.setValue(dbcpAttr.getInitialSize()); - this.DBCP_MAX_ACTIVE.setValue(dbcpAttr.getMaxActive()); - this.DBCP_MAX_IDLE.setValue(dbcpAttr.getMaxIdle()); - this.DBCP_MAX_WAIT.setValue(dbcpAttr.getMaxWait()); this.DBCP_MIN_IDLE.setValue(dbcpAttr.getMinIdle()); - this.DBCP_VALIDATION_QUERY.setText(dbcpAttr.getValidationQuery()); - this.DBCP_TESTONBORROW.setSelectedIndex(dbcpAttr.isTestOnBorrow() ? 1 : 0); this.DBCP_TESTONRETURN.setSelectedIndex(dbcpAttr.isTestOnReturn() ? 1 : 0); this.DBCP_TESTWHILEIDLE.setSelectedIndex(dbcpAttr.isTestWhileIdle() ? 1 : 0); this.DBCP_MINEVICTABLEIDLETIMEMILLIS.setValue(dbcpAttr.getMinEvictableIdleTimeMillis() / TIME_MULTIPLE); @@ -141,12 +131,7 @@ public class DBCPAttrPane extends BasicPane { jdbcDatabase.setDbcpAttr(dbcpAttr); } dbcpAttr.setInitialSize(this.DBCP_INITIAL_SIZE.getValue().intValue()); - dbcpAttr.setMaxActive(this.DBCP_MAX_ACTIVE.getValue().intValue()); - dbcpAttr.setMaxIdle(this.DBCP_MAX_IDLE.getValue().intValue()); - dbcpAttr.setMaxWait(this.DBCP_MAX_WAIT.getValue().intValue()); dbcpAttr.setMinIdle(this.DBCP_MIN_IDLE.getValue().intValue()); - dbcpAttr.setValidationQuery(this.DBCP_VALIDATION_QUERY.getText()); - dbcpAttr.setTestOnBorrow(this.DBCP_TESTONBORROW.getSelectedIndex() == 0 ? false : true); dbcpAttr.setTestOnReturn(this.DBCP_TESTONRETURN.getSelectedIndex() == 0 ? false : true); dbcpAttr.setTestWhileIdle(this.DBCP_TESTWHILEIDLE.getSelectedIndex() == 0 ? false : true); dbcpAttr.setMinEvictableIdleTimeMillis(((Number) this.DBCP_MINEVICTABLEIDLETIMEMILLIS.getValue()).intValue() * TIME_MULTIPLE); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java index e55aaa2dd4..0a00f37041 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java @@ -3,10 +3,12 @@ */ package com.fr.design.data.datapane.connect; +import com.fr.data.driver.util.JarFileParseUtil; import com.fr.data.impl.Connection; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.impl.JNDIDatabaseConnection; import com.fr.data.operator.DataOperatorProvider; +import com.fr.data.security.ssl.impl.NormalSsl; import com.fr.data.solution.ExceptionSolutionSelector; import com.fr.data.solution.entity.DriverPage; import com.fr.data.solution.processor.ClassNotFoundExceptionSolutionProcessor; @@ -14,11 +16,11 @@ import com.fr.data.solution.processor.SolutionProcessor; import com.fr.design.beans.BasicBeanPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.scrollruler.ModLineBorder; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; import com.fr.rpc.ExceptionHandler; @@ -31,9 +33,12 @@ import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JDialog; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; @@ -53,6 +58,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.io.File; import java.net.URI; import java.util.concurrent.ExecutionException; @@ -60,6 +66,8 @@ import java.util.concurrent.ExecutionException; * Database Connection pane. */ public abstract class DatabaseConnectionPane extends BasicBeanPane { + private static int MAX_MAIN_PANEL_HEIGHT = 410; + private static int MAX_MAIN_PANEL_WIDTH = 675; private UILabel message; private UIButton okButton; @@ -89,120 +97,7 @@ public abstract class DatabaseConnectionPane connectionThread = new SwingWorker() { - @Override - protected Void doInBackground() throws Exception { - Connection database = DatabaseConnectionPane.this.updateBean(); - // 返回连接结果 - DriverPage.updateCache(); - final Exception[] exception = new Exception[1]; - WorkContext.getCurrent().get(DataOperatorProvider.class, new ExceptionHandler() { - @Override - public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { - // 正常调用发生的异常也会被捕获,因此需要对异常类型进行判断,如果是NoSuchMethodException 就要去调用 testConnection - // 如果不是 NoSuchMethodException 保存下异常上下文 - // 两种情况下异常都需要抛出 - if (exceptionInfo.getException() instanceof NoSuchMethodException) { - if (!WorkContext.getCurrent().get(DataOperatorProvider.class).testConnection(database)) { - exception[0] = new Exception(Toolkit.i18nText("Fine-Design_Description_Of_Test_Connection")); - } - } else { - exception[0] = exceptionInfo.getException(); - } - return null; - } - }).testConnectionWithException(database); - if (exception[0] != null) { - throw exception[0]; - } - return null; - } - - @Override - protected void done() { - try { - get(); - dialog.setSize(new Dimension(380, 125)); - okButton.setEnabled(true); - uiLabel.setIcon(UIManager.getIcon("OptionPane.informationIcon")); - message.setText(Toolkit.i18nText("Fine-Design_Basic_Datasource_Connection_Successfully")); - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } catch (ExecutionException e) { - dialog.setSize(new Dimension(380, 142)); - midPane.setVisible(true); - hiddenPanel.setVisible(false); - okButton.setEnabled(true); - uiLabel.setIcon(UIManager.getIcon("OptionPane.errorIcon")); - message.setText(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")); - Connection database = DatabaseConnectionPane.this.updateBean(); - SolutionProcessor select = ExceptionSolutionSelector.get().select(e, database); - if (select instanceof ClassNotFoundExceptionSolutionProcessor) { - JPanel gridJpanel = new JPanel(); - gridJpanel.setLayout(new GridLayout(5, 1, 0, 5)); - UILabel driverTips = new UILabel(); - driverTips.setText(Toolkit.i18nText("Fine_Designer_Not_Found_Driver")); - gridJpanel.add(driverTips); - UILabel deatail = new UILabel(); - String content = Toolkit.i18nText("Fine_Designer_Not_Found") + " " + select.getResultException().getDetailMessage() + " " + Toolkit.i18nText("Fine_Designer_Driver"); - deatail.setText(content); - deatail.setToolTipText(content); - gridJpanel.add(deatail); - String solution = select.getResultException().getSolution(); - UILabel redirect = new UILabel(); - if (solution != null) { - redirect.setText(Toolkit.i18nText("Fine_Designer_Download_Driver")); - redirect.setForeground(Color.BLUE); - redirect.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - try { - Desktop.getDesktop().browse(new URI(solution)); - } catch (Exception clickException) { - FineLoggerFactory.getLogger().warn("can not open browser with {}", solution); - } - } - - @Override - public void mouseEntered(MouseEvent e) { - redirect.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - - @Override - public void mouseExited(MouseEvent e) { - redirect.setCursor(Cursor.getDefaultCursor()); - } - }); - } else { - redirect.setText(Toolkit.i18nText("Fine_Designer_Not_Found_Driver_No_Solution")); - } - gridJpanel.add(redirect); - hiddenPanel.add(gridJpanel); - gridJpanel.setBackground(Color.WHITE); - } else { - JPanel borderPanel = new JPanel(); - borderPanel.setLayout(new BorderLayout()); - JTextArea jta = new JTextArea(); - JScrollPane jsp = new JScrollPane(jta); - jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - jta.append(select.getResultException().getDetailMessage() + "\n"); - jta.append(select.getResultException().getSolution()); - jta.setCaretPosition(0); - jta.setEditable(false); - jta.getCaret().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - jta.getCaret().setVisible(true); - } - }); - borderPanel.add(jsp, BorderLayout.CENTER); - hiddenPanel.add(borderPanel); - } - okButton.setEnabled(true); - } - } - }; + final SwingWorker connectionThread = new TestConnectionWorker(); midPane.setVisible(false); hiddenPanel.setVisible(false); initDialogPane(); @@ -305,6 +200,19 @@ public abstract class DatabaseConnectionPane MAX_MAIN_PANEL_HEIGHT || mainPanel.getPreferredSize().width > MAX_MAIN_PANEL_WIDTH) { + UIScrollPane jp = new + UIScrollPane(mainPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jp.setPreferredSize(new Dimension(MAX_MAIN_PANEL_WIDTH, MAX_MAIN_PANEL_HEIGHT)); + northPane.add(jp, BorderLayout.CENTER); + } else { + mainPanel.setPreferredSize(new Dimension(MAX_MAIN_PANEL_WIDTH, MAX_MAIN_PANEL_HEIGHT)); + northPane.add(mainPanel, BorderLayout.CENTER); + } // ChartSet String[] defaultEncode = new String[]{Toolkit.i18nText("Fine-Design_Encode_Auto")}; charSetComboBox = new UIComboBox(ArrayUtils.addAll(defaultEncode, EncodeConstants.ENCODING_ARRAY)); @@ -406,6 +327,13 @@ public abstract class DatabaseConnectionPane { private static JDBCDefPane jdbcDefPane = new JDBCDefPane(); private static DBCPAttrPane dbcpAttrPane = new DBCPAttrPane(); + private static AdvancePane advancePane = new AdvancePane(); + private static SslPane sslPane = new SslPane(); + private static SshPane sshPane = new SshPane(); + + static { + jdbcDefPane.addLinkPane(sslPane); + } @Override protected JPanel mainPanel() { @@ -425,15 +353,40 @@ public abstract class DatabaseConnectionPane { + @Override + protected Void doInBackground() throws Exception { + Connection database = DatabaseConnectionPane.this.updateBean(); + // 返回连接结果 + DriverPage.updateCache(); + final Exception[] exception = new Exception[1]; + WorkContext.getCurrent().get(DataOperatorProvider.class, new ExceptionHandler() { + @Override + public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { + // 正常调用发生的异常也会被捕获,因此需要对异常类型进行判断,如果是NoSuchMethodException 就要去调用 testConnection + // 如果不是 NoSuchMethodException 保存下异常上下文 + // 两种情况下异常都需要抛出 + if (exceptionInfo.getException() instanceof NoSuchMethodException) { + if (!WorkContext.getCurrent().get(DataOperatorProvider.class).testConnection(database)) { + exception[0] = new Exception(Toolkit.i18nText("Fine-Design_Description_Of_Test_Connection")); + } + } else { + exception[0] = exceptionInfo.getException(); + } + return null; + } + }).testConnectionWithException(database); + if (exception[0] != null) { + throw exception[0]; + } + return null; + } + + @Override + protected void done() { + try { + get(); + dialog.setSize(new Dimension(380, 125)); + okButton.setEnabled(true); + uiLabel.setIcon(UIManager.getIcon("OptionPane.informationIcon")); + message.setText(Toolkit.i18nText("Fine-Design_Basic_Datasource_Connection_Successfully")); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } catch (ExecutionException e) { + dealWithException(e); + } + } + + private void dealWithException(ExecutionException e) { + dialog.setSize(new Dimension(380, 142)); + midPane.setVisible(true); + hiddenPanel.setVisible(false); + okButton.setEnabled(true); + uiLabel.setIcon(UIManager.getIcon("OptionPane.errorIcon")); + message.setText(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")); + Connection database = DatabaseConnectionPane.this.updateBean(); + SolutionProcessor select = ExceptionSolutionSelector.get().select(e, database); + String detail = select.getResultException().getDetailMessage(); + String solution = select.getResultException().getSolution(); + if (select instanceof ClassNotFoundExceptionSolutionProcessor) { + showClassNotFoundUI(select.getResultException().getDetailMessage(), select.getResultException().getSolution()); + } else { + showExceptionMessageUI(detail, solution); + } + okButton.setEnabled(true); + } + + private void showClassNotFoundUI(String detailMessage, String solution) { + JPanel gridJpanel = new JPanel(); + gridJpanel.setLayout(new GridLayout(5, 1, 0, 5)); + UILabel driverTips = new UILabel(); + driverTips.setText(Toolkit.i18nText("Fine_Designer_Not_Found_Driver")); + gridJpanel.add(driverTips); + UILabel deatail = new UILabel(); + String content = Toolkit.i18nText("Fine_Designer_Not_Found") + " " + detailMessage+ " " + Toolkit.i18nText("Fine_Designer_Driver"); + deatail.setText(content); + deatail.setToolTipText(content); + gridJpanel.add(deatail); + UILabel redirect = new UILabel(); + if (solution != null) { + redirect.setText(Toolkit.i18nText("Fine_Designer_Download_Driver")); + redirect.setForeground(Color.BLUE); + redirect.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + try { + Desktop.getDesktop().browse(new URI(solution)); + } catch (Exception clickException) { + FineLoggerFactory.getLogger().warn("can not open browser with {}", solution); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + redirect.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + @Override + public void mouseExited(MouseEvent e) { + redirect.setCursor(Cursor.getDefaultCursor()); + } + }); + } else { + redirect.setText(Toolkit.i18nText("Fine_Designer_Not_Found_Driver_No_Solution")); + } + gridJpanel.add(redirect); + hiddenPanel.add(gridJpanel); + gridJpanel.setBackground(Color.WHITE); + } + + private void showExceptionMessageUI(String detail, String solution) { + JPanel borderPanel = new JPanel(); + borderPanel.setLayout(new BorderLayout()); + JTextArea jta = new JTextArea(); + JScrollPane jsp = new JScrollPane(jta); + jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + + Connection con = DatabaseConnectionPane.this.updateBean(); + if(con instanceof JDBCDatabaseConnection && WorkContext.getCurrent().isLocal()) { + String driverPath = JarFileParseUtil.getDriverClassPath((JDBCDatabaseConnection) con); + jta.append(Toolkit.i18nText("Fine_Designer_Current_Driver_Path") + ":" + driverPath + "\n"); + JPanel testDriverPanel = generateTestDriverPanel((JDBCDatabaseConnection) con, driverPath); + borderPanel.add(testDriverPanel, BorderLayout.NORTH); + } + jta.append(detail + "\n"); + jta.append(solution); + jta.setCaretPosition(0); + jta.setEditable(false); + jta.getCaret().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + jta.getCaret().setVisible(true); + } + }); + borderPanel.add(jsp, BorderLayout.CENTER); + hiddenPanel.add(borderPanel); + } + + private JPanel generateTestDriverPanel(JDBCDatabaseConnection con, String driverPath) { + JPanel xBorderPanel = new JPanel(); + xBorderPanel.setLayout(new BorderLayout()); + UILabel driverTestTip = new UILabel(); + JLabel testResult = new JLabel(); + driverTestTip.setForeground(Color.BLUE); + driverTestTip.setVisible(true); + testResult.setVisible(false); + testResult.setHorizontalAlignment(SwingConstants.CENTER); + driverTestTip.setText(Toolkit.i18nText("Fine_Designer_Driver_Path_Test")); + xBorderPanel.add(driverTestTip, BorderLayout.WEST); + xBorderPanel.add(testResult, BorderLayout.CENTER); + + driverTestTip.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + driverTestTip.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + @Override + public void mouseExited(MouseEvent e) { + driverTestTip.setCursor(Cursor.getDefaultCursor()); + } + @Override + public void mouseClicked(MouseEvent e) { + try { + String path; + if(driverPath.endsWith(JarFileParseUtil.JAR_MARKER)) { + path = new File(driverPath).getParent(); + } else { + path = driverPath; + } + if(JarFileParseUtil.hasDuplicateDriver(con.getDriver(), path)) { + testResult.setForeground(Color.RED); + testResult.setText(Toolkit.i18nText("Fine_Designer_Driver_Conflict")); + } else { + testResult.setForeground(Color.BLACK); + testResult.setText(Toolkit.i18nText("Fine_Designer_Driver_No_Conflict")); + } + testResult.setVisible(true); + } catch (Exception clickException) { + FineLoggerFactory.getLogger().warn(clickException, "can not test driver conflict"); + } + } + }); + return xBorderPanel; + } + + + } + } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java index d0738e57b8..a430a13bd1 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java @@ -127,10 +127,12 @@ public abstract class ItemEditableComboBoxPanel extends JPanel { itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1); itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1); } + afterRefreshItems(); } catch (Exception e) { if (!(e instanceof CancellationException)) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } + refreshItemsError(); } } @@ -160,6 +162,20 @@ public abstract class ItemEditableComboBoxPanel extends JPanel { */ protected abstract java.util.Iterator items(); + /** + * 刷新ComboBox.items之后 + */ + protected void afterRefreshItems() { + // 空实现,供子类重写 + } + + /** + * 刷新ComboBox.items时出现异常 + */ + protected void refreshItemsError() { + // 空实现,供子类重写 + } + /* * 弹出对话框编辑Items */ diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java index 0da46965b1..e8c7c17b8e 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java @@ -1,10 +1,15 @@ package com.fr.design.data.datapane.connect; import com.fr.base.GraphHelper; +import com.fr.data.driver.DriverLoader; +import com.fr.data.driver.config.DriverLoaderConfig; import com.fr.data.impl.JDBCDatabaseConnection; +import com.fr.data.solution.entity.DriverClasses; import com.fr.design.border.UITitledBorder; +import com.fr.design.constants.UIConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.icombobox.UIComboBoxUI; import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ipasswordfield.UIPasswordFieldWithFixedLength; @@ -21,13 +26,18 @@ import com.fr.general.ComparatorUtils; import com.fr.stable.ArrayUtils; import com.fr.stable.EncodeConstants; import com.fr.stable.StringUtils; +import com.fr.third.guava.collect.HashBiMap; +import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; +import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.plaf.ComboBoxUI; +import javax.swing.plaf.basic.ComboPopup; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -45,6 +55,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -59,6 +70,7 @@ public class JDBCDefPane extends JPanel { // 编码转换. private String originalCharSet = null; private static Map jdbcMap = new HashMap(); + private JPanel linkPanel; static { jdbcMap.put(OTHER_DB, new DriverURLName[]{new DriverURLName("sun.jdbc.odbc.JdbcOdbcDriver", "jdbc:odbc:"), @@ -101,8 +113,55 @@ public class JDBCDefPane extends JPanel { private JDBCDatabaseConnection jdbcDatabase; private boolean needRefresh = true; + private UIComboBox driverManageBox; + private ActionLabel driverManageLabel; + private UIComboBox driverLoaderBox; + ActionListener driverManageListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean selectSelfDefine = isSelfDefine(); + driverManageLabel.setVisible(selectSelfDefine); + driverLoaderBox.setVisible(selectSelfDefine); + driverComboBox.setVisible(!selectSelfDefine); + odbcTipsLink.setVisible(driverComboBox.isVisible() && ComparatorUtils.equals("sun.jdbc.odbc.JdbcOdbcDriver", driverComboBox.getSelectedItem())); + } + }; + ActionListener dbtypeActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + + urlTextField.setText(StringUtils.EMPTY); + driverComboBox.removeAllItems(); + driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default")); + if (driverLoaderBox.getItemCount() > 0) { + driverLoaderBox.setSelectedIndex(0); + } + if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) { + driverComboBox.setSelectedItem(StringUtils.EMPTY); + return; + } + + DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem()); + for (int i = 0, len = dus.length; i < len; i++) { + driverComboBox.addItem(dus[i].getDriver()); + if (i == 0) { + driverComboBox.setSelectedItem(dus[i].getDriver()); + urlTextField.setText(dus[i].getURL()); + } + } + // 更改数据库类型后 数据库名称置空和之前逻辑保持一致 + if (needRefresh) { + jdbcDatabase.setDatabase(StringUtils.EMPTY); + } + changePane(dbtypeComboBox.getSelectedItem()); + JDBCConnectionDef.getInstance().setConnection((String) dbtypeComboBox.getSelectedItem(), jdbcDatabase); + DatabaseConnectionPane.JDBC.getAdvancedAttrPane().populate(jdbcDatabase); + } + }; + private HashBiMap nameAndRepresent; public JDBCDefPane() { + initMap(); this.setBorder(UITitledBorder.createBorderWithTitle("JDBC" + ":")); this.setLayout(FRGUIPaneFactory.createLabelFlowLayout()); JPanel innerthis = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); @@ -115,7 +174,15 @@ public class JDBCDefPane extends JPanel { } dbtypeComboBox.addActionListener(dbtypeActionListener); dbtypeComboBox.setMaximumRowCount(10); - + driverLoaderBox = new SpecialUIComboBox(); + refreshDriverLoader(); + driverLoaderBox.setPreferredSize(new Dimension(200, driverLoaderBox.getPreferredSize().height)); + driverLoaderBox.setEditable(false); + driverManageBox = new UIComboBox(); + refreshDriverManage(true); + driverManageBox.setEditable(false); + driverManageBox.addActionListener(driverManageListener); + driverLoaderBox.setVisible(isSelfDefine()); driverComboBox = new UIComboBox(); driverComboBox.setEditable(true); driverComboBox.addActionListener(driverListener); @@ -130,7 +197,9 @@ public class JDBCDefPane extends JPanel { userNameTextField = new UITextField(15); userNameTextField.setName(USER_NAME); passwordTextField = new UIPasswordFieldWithFixedLength(15); - dbtypeButton = new UIButton("."); + dbtypeButton = new UIButton(); + dbtypeButton.setIcon(new ImageIcon(UIConstants.ACCESSIBLE_EDITOR_DOT)); + dbtypeButton.setPreferredSize(new Dimension(20, 20)); dbtypeButton.setToolTipText(Toolkit.i18nText("Fine-Design_Basic_Click_Get_Default_URL")); dbtypeButton.addActionListener(dbtypeButtonActionListener); @@ -163,9 +232,33 @@ public class JDBCDefPane extends JPanel { BrowseUtils.browser(url); } }); + driverManageLabel = new ActionLabel(Toolkit.i18nText("Fine-Design_Driver_Manage_Add_Driver")) { + @Override + public void paintComponent(Graphics _gfx) { + super.paintComponent(_gfx); + _gfx.setColor(Color.blue); + _gfx.drawLine(0, this.getHeight() - 1, GraphHelper.getWidth(this.getText()), this.getHeight() - 1); + } + }; + driverManageLabel.setPreferredSize(new Dimension(GraphHelper.getWidth(Toolkit.i18nText("Fine-Design_Driver_Manage_Add_Driver")), driverManageLabel.getPreferredSize().height)); + driverManageLabel.setVisible(isSelfDefine()); + driverManageLabel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + String url = CloudCenter.getInstance().acquireUrlByKind("driver.add.help"); + BrowseUtils.browser(url); + } + }); + + odbcTipsPane.add(driverManageLabel); + odbcTipsPane.add(odbcTipsLink); JPanel driverComboBoxAndTips = new JPanel(new BorderLayout()); - driverComboBoxAndTips.add(driverComboBox, BorderLayout.WEST); + JPanel normalFlowInnerContainer_s_pane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 5, 0); + normalFlowInnerContainer_s_pane.add(driverManageBox); + normalFlowInnerContainer_s_pane.add(driverComboBox); + normalFlowInnerContainer_s_pane.add(driverLoaderBox); + driverComboBoxAndTips.add(normalFlowInnerContainer_s_pane, BorderLayout.WEST); driverComboBoxAndTips.add(odbcTipsPane, BorderLayout.CENTER); JPanel hostPane = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); @@ -225,7 +318,71 @@ public class JDBCDefPane extends JPanel { innerthis.add(centerPanel); } + private void refreshDriverLoader() { + Set representSet = nameAndRepresent.values(); + driverLoaderBox.clearBoxItems(); + for (String represent : representSet) { + driverLoaderBox.addItem(represent); + } + } + + private String getRepresent(String driverClass, String driverName) { + return driverClass + "(" + driverName + ")"; + } + + private boolean isSelfDefine() { + return ComparatorUtils.equals(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define"), driverManageBox.getSelectedItem()); + } + + private void refreshDriverManage(boolean addSelfDefine) { + driverManageBox.clearBoxItems(); + driverManageBox.addItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default")); + if (addSelfDefine) { + driverManageBox.addItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define")); + } + } + + private void initMap() { + Map driverLoaders = DriverLoaderConfig.getInstance().getDriverLoaders(); + nameAndRepresent = getDriverLoaderAndRepresent(driverLoaders); + } + + private HashBiMap getDriverLoaderAndRepresent(Map driverLoaders) { + HashBiMap driverHashBiMap = HashBiMap.create(); + if (WorkContext.getCurrent().isWarDeploy()) { + return driverHashBiMap; + } + // name 是唯一的,name+driver自然也是唯一的 + for (DriverLoader driverLoader : driverLoaders.values()) { + driverHashBiMap.put(driverLoader.getName(), getRepresent(driverLoader.getDriverClass(), driverLoader.getName())); + } + return driverHashBiMap; + } + + + protected JDBCDatabaseConnection getJDBCDatabase() { + return this.jdbcDatabase; + } + + private void changePane(Object dbType) { + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double[] columnSize = {p, f, 22}; + if (ComparatorUtils.equals(dbType, OTHER_DB) || ComparatorUtils.equals(dbType, "Access") || ComparatorUtils.equals(dbType, "SQLite")) { + if (this.centerPanel.getComponentCount() != partComponents.length * 2) { + centerPanel.removeAll(); + TableLayoutHelper.addComponent2ResultPane(partComponents, new double[]{p, p, p, p, p}, columnSize, centerPanel); + } + } else if (this.centerPanel.getComponentCount() != allComponents.length * 2) { + centerPanel.removeAll(); + TableLayoutHelper.addComponent2ResultPane(allComponents, new double[]{p, p, p, p, p, p, p, p}, columnSize, centerPanel); + } + } + public void populate(JDBCDatabaseConnection jdbcDatabase) { + // 单例对象,重新打开的时候并不会新建,但是由于driverloaderbox里面需要是动态内容,因此需要进行刷新动作 + initMap(); + refreshDriverLoader(); needRefresh = false; if (jdbcDatabase == null) { jdbcDatabase = new JDBCDatabaseConnection(); @@ -255,7 +412,24 @@ public class JDBCDefPane extends JPanel { this.dbtypeComboBox.setSelectedItem(OTHER_DB); } } - this.driverComboBox.setSelectedItem(jdbcDatabase.getDriver()); + // jdbcDatabase.getDriverSource() 只会是空或者是有值,但是为了保险起见,还是应该做个处理 + String driverSource = jdbcDatabase.getDriverSource(); + if (driverSource == null) { + driverSource = StringUtils.EMPTY; + } + if (driverSource.isEmpty()) { + refreshDriverManage(!nameAndRepresent.isEmpty()); + this.driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default")); + this.driverComboBox.setSelectedItem(jdbcDatabase.getDriver()); + } else { + refreshDriverManage(true); + this.driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define")); + String represent = getRepresent(jdbcDatabase.getDriver(), jdbcDatabase.getDriverSource()); + if (!nameAndRepresent.containsValue(represent)) { + this.driverLoaderBox.addItem(represent); + } + this.driverLoaderBox.setSelectedItem(represent); + } this.urlTextField.setText(jdbcDatabase.getURL()); this.userNameTextField.setText(jdbcDatabase.getUser()); this.passwordTextField.setText(jdbcDatabase.getPassword()); @@ -268,31 +442,10 @@ public class JDBCDefPane extends JPanel { needRefresh = false; } - protected JDBCDatabaseConnection getJDBCDatabase() { - return this.jdbcDatabase; - } - - private void changePane(Object dbType) { - double p = TableLayout.PREFERRED; - double f = TableLayout.FILL; - double[] columnSize = {p, f, 22}; - if (ComparatorUtils.equals(dbType, OTHER_DB) || ComparatorUtils.equals(dbType, "Access") || ComparatorUtils.equals(dbType, "SQLite")) { - if (this.centerPanel.getComponentCount() != partComponents.length * 2) { - centerPanel.removeAll(); - TableLayoutHelper.addComponent2ResultPane(partComponents, new double[]{p, p, p, p, p}, columnSize, centerPanel); - } - } else if (this.centerPanel.getComponentCount() != allComponents.length * 2) { - centerPanel.removeAll(); - TableLayoutHelper.addComponent2ResultPane(allComponents, new double[]{p, p, p, p, p, p, p, p}, columnSize, centerPanel); - } - } - public JDBCDatabaseConnection update() { if (jdbcDatabase == null) { jdbcDatabase = new JDBCDatabaseConnection(); } - Object driveItem = this.driverComboBox.getSelectedItem(); - jdbcDatabase.setDriver(driveItem == null ? null : driveItem.toString().trim()); jdbcDatabase.setURL(this.urlTextField.getText().trim()); jdbcDatabase.setUser(this.userNameTextField.getText().trim()); jdbcDatabase.setPassword(new String(this.passwordTextField.getPassword()).trim()); @@ -304,43 +457,42 @@ public class JDBCDefPane extends JPanel { jdbcDatabase.setNewCharsetName(EncodeConstants.ENCODING_GBK); jdbcDatabase.setOriginalCharsetName(((String) this.charSetComboBox.getSelectedItem())); } - return jdbcDatabase; - } - - ActionListener dbtypeActionListener = new ActionListener() { - public void actionPerformed(ActionEvent evt) { - - urlTextField.setText(StringUtils.EMPTY); - driverComboBox.removeAllItems(); - if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) { - driverComboBox.setSelectedItem(StringUtils.EMPTY); - return; - } - - DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem()); - for (int i = 0, len = dus.length; i < len; i++) { - driverComboBox.addItem(dus[i].getDriver()); - if (i == 0) { - driverComboBox.setSelectedItem(dus[i].getDriver()); - urlTextField.setText(dus[i].getURL()); + String driverLoader = (String) this.driverLoaderBox.getSelectedItem(); + if (driverLoader == null) { + driverLoader = StringUtils.EMPTY; + } + if (isSelfDefine()) { + String[] split = driverLoader.split("\\("); + if (split.length > 1) { + String name = split[1]; + if (name.length() > 0) { + jdbcDatabase.setDriverSource(name.substring(0, name.length() - 1)); + } else { + jdbcDatabase.setDriverSource(StringUtils.EMPTY); } + } else { + jdbcDatabase.setDriverSource(StringUtils.EMPTY); } - // 更改数据库类型后 数据库名称置空和之前逻辑保持一致 - if (needRefresh) { - jdbcDatabase.setDatabase(StringUtils.EMPTY); - } - changePane(dbtypeComboBox.getSelectedItem()); - JDBCConnectionDef.getInstance().setConnection((String) dbtypeComboBox.getSelectedItem(), jdbcDatabase); - DatabaseConnectionPane.JDBC.getAdvancedAttrPane().populate(jdbcDatabase); + jdbcDatabase.setDriver(split[0]); + } else { + Object driveItem = this.driverComboBox.getSelectedItem(); + jdbcDatabase.setDriver(driveItem == null ? null : driveItem.toString().trim()); + jdbcDatabase.setDriverSource(StringUtils.EMPTY); } - }; + return jdbcDatabase; + } ActionListener driverListener = new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { + linkPanel.setVisible(DriverClasses.MYSQL.toString().equalsIgnoreCase((String) dbtypeComboBox.getSelectedItem()) + && driverComboBox.getSelectedItem() != null + && ComparatorUtils.equals(DriverClasses.MYSQL.getDriverClass(), driverComboBox.getSelectedItem().toString().trim())); + odbcTipsLink.setVisible(driverComboBox.getSelectedItem() != null + && ComparatorUtils.equals("sun.jdbc.odbc.JdbcOdbcDriver", driverComboBox.getSelectedItem().toString().trim())); // 选择的如果是ODBC就显示提示 if (driverComboBox.getSelectedItem() == null || ComparatorUtils.equals(driverComboBox.getSelectedItem(), StringUtils.EMPTY)) { return; } - odbcTipsLink.setVisible(ComparatorUtils.equals("sun.jdbc.odbc.JdbcOdbcDriver", driverComboBox.getSelectedItem())); // 选择的如果是ODBC就显示提示 Iterator> jdbc = jdbcMap.entrySet().iterator(); while (jdbc.hasNext()) { Entry entry = jdbc.next(); @@ -353,7 +505,6 @@ public class JDBCDefPane extends JPanel { } } } - }; ActionListener dbtypeButtonActionListener = new ActionListener() { @@ -579,4 +730,25 @@ public class JDBCDefPane extends JPanel { private String driver; private String url; } + + private static class SpecialUIComboBox extends UIComboBox { + + @Override + public ComboBoxUI getUIComboBoxUI() { + return new SpecialUIComboBoxUI(); + } + } + + private static class SpecialUIComboBoxUI extends UIComboBoxUI { + + @Override + public ComboPopup createPopup() { + return createHorizontalNeverUIComboPopUp(); + } + + } + + public void addLinkPane(JPanel panel) { + linkPanel = panel; + } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java new file mode 100644 index 0000000000..48f710dfbf --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java @@ -0,0 +1,301 @@ +package com.fr.design.data.datapane.connect; + +import com.fr.data.impl.JDBCDatabaseConnection; +import com.fr.data.security.ssh.BaseSsh; +import com.fr.data.security.ssh.Ssh; +import com.fr.data.security.ssh.SshException; +import com.fr.data.security.ssh.SshType; +import com.fr.data.security.ssh.impl.KeyVerifySsh; +import com.fr.data.security.ssh.impl.NormalSsh; +import com.fr.data.security.ssl.SslUtils; +import com.fr.design.border.UITitledBorder; +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.BasicPane; +import com.fr.design.editor.editor.NotNegativeIntegerEditor; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ipasswordfield.UIPasswordFieldWithFixedLength; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.file.FILE; +import com.fr.file.FILEChooserPane; +import com.fr.file.filter.ChooseFileFilter; +import com.fr.stable.StringUtils; +import com.fr.third.guava.collect.HashBiMap; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.fr.design.i18n.Toolkit.i18nText; + +/** + * @author xiqiu + * @date 2021/12/23 + * @description + */ +public class SshPane extends BasicPane { + private static HashBiMap typeMap; + + static { + typeMap = HashBiMap.create(); + typeMap.put(Toolkit.i18nText("Fine-Design_Basic_Password"), SshType.NORMAL); + typeMap.put(Toolkit.i18nText("Fine-Design_Basic_Ssh_Public_Key"), SshType.KEY); + } + + private UICheckBox usingSsh = new UICheckBox(i18nText("Fine-Design_Basic_Ssh_Using")); + private NotNegativeIntegerEditor port = new NotNegativeIntegerEditor(20); + private UITextField ip = new UITextField(20); + private UIComboBox type = new UIComboBox(); + private UITextField user = new UITextField(20); + private JPasswordField password = new UIPasswordFieldWithFixedLength(20); + private JPasswordField secret = new UIPasswordFieldWithFixedLength(20); + private KeyFileUITextField keyPath = new KeyFileUITextField(18); + private JPanel contextPane; + private Component[][] passwordComps; + private Component[][] keyComps; + private double p = TableLayout.PREFERRED; + private double f = TableLayout.FILL; + private JPanel jPanel; + private UIButton fileChooserButton = new UIButton(); + private double[] columnSize = new double[]{195, p}; + + public SshPane() { + fileChooserButton.setIcon(new ImageIcon(UIConstants.ACCESSIBLE_EDITOR_DOT)); + this.setBorder(UITitledBorder.createBorderWithTitle(Toolkit.i18nText("Fine-Design_Basic_Ssh_Settings"))); + this.setLayout(FRGUIPaneFactory.createLabelFlowLayout()); + typeMap.keySet().forEach(key -> type.addItem(key)); + type.setSelectedItem(typeMap.inverse().get(SshType.KEY)); + jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + fileChooserButton.setPreferredSize(new Dimension(20, 20)); + type.setEditable(false); + type.setSelectedItem(Toolkit.i18nText("Fine-Design_Basic_Ssh_Private_Key")); + JPanel filePanel = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{{keyPath, fileChooserButton}}, new double[]{p}, new double[]{f, 20}, 0); + Component[] compIp = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Host") + ":", SwingConstants.RIGHT), ip}; + Component[] compPort = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Port") + ":", SwingConstants.RIGHT), port}; + Component[] compUserName = {new UILabel(Toolkit.i18nText("Fine-Design_Report_UserName") + ":", SwingConstants.RIGHT), user}; + Component[] compMethod = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssh_Verify_Method") + ":", SwingConstants.RIGHT), type}; + Component[] compPassword = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Password") + ":", SwingConstants.RIGHT), password}; + Component[] compKey = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssh_Private_Key") + ":", SwingConstants.RIGHT), filePanel}; + Component[] comSecret = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssh_Secret") + ":", SwingConstants.RIGHT), secret}; + + passwordComps = new Component[][]{ + compIp, + compPort, + compUserName, + compMethod, + compPassword + }; + keyComps = new Component[][]{ + compIp, + compPort, + compUserName, + compMethod, + compKey, + comSecret + }; + usingSsh.setSelected(true); + contextPane = TableLayoutHelper.createGapTableLayoutPane(keyComps, new double[]{p, p, p, p, p, p}, columnSize, 11, 11); + jPanel.add(usingSsh, BorderLayout.NORTH); + jPanel.add(contextPane, BorderLayout.CENTER); + this.add(jPanel); + + usingSsh.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePane(); + } + }); + + type.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePaneForType(); + } + }); + fileChooserButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(SslUtils.PREFIX, new ChooseFileFilter(true), SslUtils.CERTIFICATES); + int type = fileChooser.showOpenDialog(SshPane.this, StringUtils.EMPTY); + if (type == FILEChooserPane.OK_OPTION) { + final FILE file = fileChooser.getSelectedFILE(); + if (file == null) { + keyPath.setText(StringUtils.EMPTY); + } else { + keyPath.setText(file.getPath()); + } + } + fileChooser.removeAllFilter(); + fileChooser.removeTopPath(); + } + }); + } + + + private void changePane() { + contextPane.setVisible(usingSsh.isSelected()); + } + + private void changePaneForType() { + contextPane.removeAll(); + switch (typeMap.get(type.getSelectedItem())) { + case NORMAL: + TableLayoutHelper.addComponent2ResultPane(passwordComps, new double[]{p, p, p, p, p}, columnSize, contextPane); + break; + case KEY: + TableLayoutHelper.addComponent2ResultPane(keyComps, new double[]{p, p, p, p, p, p}, columnSize, contextPane); + break; + default: + throw new SshException("un support ssh type"); + } + jPanel.revalidate(); + jPanel.repaint(); + } + + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_Ssh_Settings"); + } + + + public void populate(JDBCDatabaseConnection jdbcDatabase) { + if (jdbcDatabase.getSsh() == null) { + jdbcDatabase.setSsh(new NormalSsh()); + } + Ssh ssh = jdbcDatabase.getSsh(); + switch (ssh.getSshType()) { + case KEY: + type.setSelectedItem(typeMap.inverse().get(ssh.getSshType())); + KeyVerifySsh keyVerifySsh = (KeyVerifySsh) ssh; + keyPath.setText(keyVerifySsh.getPrivateKeyPath()); + secret.setText(keyVerifySsh.getSecret()); + password.setText(StringUtils.EMPTY); + setCommonConfig(keyVerifySsh); + break; + case NORMAL: + type.setSelectedItem(typeMap.inverse().get(ssh.getSshType())); + NormalSsh normalSsh = (NormalSsh) ssh; + password.setText(normalSsh.getSecret()); + keyPath.setText(StringUtils.EMPTY); + secret.setText(StringUtils.EMPTY); + setCommonConfig(normalSsh); + break; + default: + throw new SshException("un support ssh type"); + } + usingSsh.setSelected(ssh.isUsingSsh()); + changePane(); + } + + private void setCommonConfig(BaseSsh baseSsh) { + ip.setText(baseSsh.getIp()); + port.setValue(baseSsh.getPort()); + user.setText(baseSsh.getUser()); + } + + public void update(JDBCDatabaseConnection jdbcDatabase) { + Ssh ssh; + switch (typeMap.get(type.getSelectedItem())) { + case NORMAL: + NormalSsh normalSsh = new NormalSsh(); + normalSsh.setSecret(new String(password.getPassword()).trim()); + getCommonConfig(normalSsh); + ssh = normalSsh; + break; + case KEY: + KeyVerifySsh keyVerifySsh = new KeyVerifySsh(); + keyVerifySsh.setPrivateKeyPath(keyPath.getText().trim()); + keyVerifySsh.setSecret(new String(secret.getPassword()).trim()); + getCommonConfig(keyVerifySsh); + ssh = keyVerifySsh; + break; + default: + throw new SshException("un support ssh type"); + } + jdbcDatabase.setSsh(ssh); + } + + private void getCommonConfig(BaseSsh baseSsh) { + baseSsh.setUsingSsh(usingSsh.isSelected()); + baseSsh.setIp(ip.getText().trim()); + baseSsh.setPort(port.getValue()); + baseSsh.setUser(user.getText().trim()); + } + + public static class KeyFileUITextField extends UITextField { + private static final Pattern ERROR_START = Pattern.compile("^([/\\\\.]+).*"); + private static final Pattern MUTI_DOT = Pattern.compile("\\.+"); + private static final String UPPER = ".."; + + public KeyFileUITextField(int columns) { + this(); + this.setColumns(columns); + } + + + public KeyFileUITextField() { + super(); + this.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + String text = KeyFileUITextField.this.getTextOrigin(); + if (!StringUtils.isEmpty(text)) { + if (text.contains(UPPER)) { + text = MUTI_DOT.matcher(text).replaceAll("."); + KeyFileUITextField.this.setTextOrigin(text); + } + Matcher matcher = ERROR_START.matcher(text); + if (matcher.matches()) { + text = text.substring(matcher.group(1).length()); + KeyFileUITextField.this.setTextOrigin(text); + } + } + } + }); + } + + public String getTextOrigin() { + return super.getText(); + } + + public void setTextOrigin(String text) { + super.setText(text); + } + + @Override + public String getText() { + // 获取的时候,不为空,给他加上前缀就好了,否则还是空 + if (!StringUtils.isEmpty(super.getText())) { + return SslUtils.PREFIX + super.getText(); + } + return StringUtils.EMPTY; + } + + @Override + public void setText(String text) { + // 设置的时候,不为空,说明文件指定了(文件需要是resource下),替换掉前缀 + if (!StringUtils.isEmpty(text) && text.startsWith(SslUtils.PREFIX)) { + super.setText(text.replaceFirst(SslUtils.PREFIX, "")); + } else { + super.setText(text); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java new file mode 100644 index 0000000000..8789a39a18 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java @@ -0,0 +1,165 @@ +package com.fr.design.data.datapane.connect; + +import com.fr.data.impl.JDBCDatabaseConnection; +import com.fr.data.security.ssl.Ssl; +import com.fr.data.security.ssl.SslException; +import com.fr.data.security.ssl.SslType; +import com.fr.data.security.ssl.SslUtils; +import com.fr.data.security.ssl.impl.NormalSsl; +import com.fr.design.border.UITitledBorder; +import com.fr.design.constants.UIConstants; +import com.fr.design.data.datapane.connect.SshPane.KeyFileUITextField; +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.file.FILE; +import com.fr.file.FILEChooserPane; +import com.fr.file.filter.ChooseFileFilter; +import com.fr.stable.StringUtils; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import static com.fr.design.i18n.Toolkit.i18nText; + +/** + * @author xiqiu + * @date 2022/1/4 + * @description + */ +public class SslPane extends BasicPane { + UICheckBox usingSsl = new UICheckBox(i18nText("Fine-Design_Basic_Ssl_Using")); + private KeyFileUITextField keyPathCa = new KeyFileUITextField(18); + private UIButton fileChooserButtonCa = new UIButton(); + private KeyFileUITextField keyPathClientCert = new KeyFileUITextField(18); + private UIButton fileChooserButtonClientCert = new UIButton(); + private KeyFileUITextField keyPathClientKey = new KeyFileUITextField(18); + private UIButton fileChooserButtonClientKey = new UIButton(); + private UICheckBox verifyCa = new UICheckBox(i18nText("Fine-Design_Basic_Ssl_Verify_Ca")); +// private UITextField cipher = new UITextField(20); + private JPanel jPanel; + private Component[][] usingComps; + private double p = TableLayout.PREFERRED; + private double f = TableLayout.FILL; + private JPanel contextPane; + private double[] columnSize = new double[]{195, p}; + + public SslPane() { + fileChooserButtonCa.setIcon(new ImageIcon(UIConstants.ACCESSIBLE_EDITOR_DOT)); + fileChooserButtonClientCert.setIcon(new ImageIcon(UIConstants.ACCESSIBLE_EDITOR_DOT)); + fileChooserButtonClientKey.setIcon(new ImageIcon(UIConstants.ACCESSIBLE_EDITOR_DOT)); + this.setBorder(UITitledBorder.createBorderWithTitle(Toolkit.i18nText("Fine-Design_Basic_Ssl_Settings"))); + this.setLayout(FRGUIPaneFactory.createLabelFlowLayout()); + jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + Dimension dimension = new Dimension(20, 20); + fileChooserButtonCa.setPreferredSize(dimension); + fileChooserButtonClientCert.setPreferredSize(dimension); + fileChooserButtonClientKey.setPreferredSize(dimension); + JPanel filePanelCa = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{{keyPathCa, fileChooserButtonCa}}, new double[]{p}, new double[]{f, 20}, 0); + Component[] compCa = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssl_Ca") + ":", SwingConstants.RIGHT), filePanelCa}; + Component[] compVerifyCa = {null, verifyCa}; + JPanel filePanelClientKey = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{{keyPathClientKey, fileChooserButtonClientKey}}, new double[]{p}, new double[]{f, 20}, 0); + Component[] compClientKey = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssl_Client_Key") + ":", SwingConstants.RIGHT), filePanelClientKey}; + JPanel filePanelClientCert = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{{keyPathClientCert, fileChooserButtonClientCert}}, new double[]{p}, new double[]{f, 20}, 0); + Component[] compClientCert = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssl_Client_Cert") + ":", SwingConstants.RIGHT), filePanelClientCert}; +// Component[] comCipher = {new UILabel(Toolkit.i18nText("Fine-Design_Basic_Ssl_Cipher") + ":", SwingConstants.RIGHT), cipher}; + usingComps = new Component[][]{ + compCa, + compVerifyCa, + compClientKey, + compClientCert +// comCipher + }; + usingSsl.setSelected(true); + contextPane = TableLayoutHelper.createGapTableLayoutPane(usingComps, new double[]{p, p, p, p}, columnSize, 11, 11); + jPanel.add(usingSsl, BorderLayout.NORTH); + jPanel.add(contextPane, BorderLayout.CENTER); + this.add(jPanel); + usingSsl.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePane(); + } + }); + fileChooserButtonCa.addActionListener(new TextFieldActionListener(keyPathCa)); + fileChooserButtonClientCert.addActionListener(new TextFieldActionListener(keyPathClientCert)); + fileChooserButtonClientKey.addActionListener(new TextFieldActionListener(keyPathClientKey)); + } + + private void changePane() { + contextPane.setVisible(usingSsl.isSelected()); + } + + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_Ssl_Settings"); + } + + public void populate(JDBCDatabaseConnection jdbcDatabase) { + Ssl ssl = jdbcDatabase.getSsl(); + if (ssl == null) { + ssl = new NormalSsl(); + jdbcDatabase.setSsl(ssl); + } + if (ssl.getSslType() == SslType.NORMAL) { + NormalSsl normalSsl = (NormalSsl) ssl; + keyPathCa.setText(normalSsl.getCaCertificate()); + keyPathClientCert.setText(normalSsl.getClientCertificate()); + keyPathClientKey.setText(normalSsl.getClientPrivateKey()); + verifyCa.setSelected(normalSsl.isVerifyCa()); +// cipher.setText(normalSsl.getCipher()); + } else { + throw new SslException("un support ssl type"); + } + usingSsl.setSelected(ssl.isUsingSsl()); + changePane(); + } + + public void update(JDBCDatabaseConnection jdbcDatabase) { + NormalSsl normalSsl = new NormalSsl(); +// normalSsl.setCipher(cipher.getText().trim()); + normalSsl.setVerifyCa(verifyCa.isSelected()); + normalSsl.setCaCertificate(keyPathCa.getText().trim()); + normalSsl.setClientCertificate(keyPathClientCert.getText().trim()); + normalSsl.setClientPrivateKey(keyPathClientKey.getText().trim()); + normalSsl.setUsingSsl(usingSsl.isSelected()); + jdbcDatabase.setSsl(normalSsl); + } + + private class TextFieldActionListener implements ActionListener { + private UITextField textField; + + public TextFieldActionListener(UITextField textField) { + this.textField = textField; + } + + @Override + public void actionPerformed(ActionEvent e) { + FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(SslUtils.PREFIX, new ChooseFileFilter(true), SslUtils.CERTIFICATES); + int type = fileChooser.showOpenDialog(SslPane.this, StringUtils.EMPTY); + if (type == FILEChooserPane.OK_OPTION) { + final FILE file = fileChooser.getSelectedFILE(); + if (file == null) { + textField.setText(StringUtils.EMPTY); + } else { + textField.setText(file.getPath()); + } + } + fileChooser.removeAllFilter(); + fileChooser.removeTopPath(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java new file mode 100644 index 0000000000..3094df145b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java @@ -0,0 +1,74 @@ +package com.fr.design.data.datapane.management.clip; + +import com.fr.base.TableData; +import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils; +import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; +import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; +import com.fr.general.NameObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用于数据集的复制粘贴 + * + * @author Yvan + */ +public class TableDataTreeClipboard { + + /** + * 数据集名称 - 数据集Wrapper + */ + private Map clip = new HashMap<>(); + + private static class Holder { + private static final TableDataTreeClipboard INSTANCE = new TableDataTreeClipboard(); + } + + private TableDataTreeClipboard() { + } + + public static TableDataTreeClipboard getInstance() { + return Holder.INSTANCE; + } + + /** + * 添加选中的数据集数据到剪切板,覆盖原本剪切板内数据 + * + * @param copyMap + * @return + */ + public void addToClip(Map copyMap) { + this.clip = copyMap; + } + + public Map transferNameObjectArray2Map(NameObject[] selectedNameObjects) { + Map resultMap = new HashMap<>(); + if (selectedNameObjects == null) { + return resultMap; + } + for (NameObject selectedNameObject : selectedNameObjects) { + TableData cloned = TableDataFollowingPasteUtils.cloneTableData(((AbstractTableDataWrapper) selectedNameObject.getObject()).getTableData()); + if (cloned != null) { + resultMap.put(selectedNameObject.getName(), new TemplateTableDataWrapper(cloned)); + } + } + return resultMap; + } + + /** + * 取出剪切板内的所有数据集数据,剪切板不清空 + * + * @return + */ + public Map takeFromClip() { + return clip; + } + + /** + * 清空剪切板 + */ + public void reset() { + clip.clear(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java new file mode 100644 index 0000000000..6d88a227d7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java @@ -0,0 +1,242 @@ +package com.fr.design.data.datapane.management.search; + +import com.fr.data.TableDataSource; +import com.fr.design.DesignModelAdapter; +import com.fr.design.data.datapane.TableDataTree; +import com.fr.design.data.datapane.TableDataTreePane; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode; +import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.view.TreeSearchRendererHelper; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import javax.swing.SwingUtilities; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 数据集树搜索管理器 + * + * @author Yvan + */ +public class TableDataTreeSearchManager { + + /** + * 数据集树搜索器 + */ + private TableDataTreeSearcher treeSearcher; + + /** + * 搜索任务的状态 + */ + private TreeSearchStatus treeSearchStatus; + + /** + * 缓存上次搜索文本,避免重复搜索 + */ + private String lastSearchText; + + /** + * 存储与复原 原本数据集树的UI + */ + private TreeSearchRendererHelper rendererHelper; + + /** + * 取数计数器 + */ + private AtomicInteger count; + + /** + * 搜索状态变化监听 + */ + private List listeners = new ArrayList<>(); + + private TableDataTreeSearchManager() { + init(); + } + + private void init() { + this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE; + } + + private static class Holder { + private static final TableDataTreeSearchManager INSTANCE = new TableDataTreeSearchManager(); + } + + public static TableDataTreeSearchManager getInstance() { + return Holder.INSTANCE; + } + + public TreeSearchStatus getTreeSearchStatus() { + return treeSearchStatus; + } + + public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) { + this.treeSearchStatus = treeSearchStatus; + // 每次设置搜索状态,都触发下监听,让页面跟随变化 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + for (TreeSearchStatusChangeListener listener : listeners) { + listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus)); + } + } + }); + } + + public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) { + listeners.add(listener); + } + + /** + * 工具栏处切换到搜索面板 + * + * @param searchMode + * @param tableDataSource + */ + public void switchToSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + rendererHelper = new TreeSearchRendererHelper(); + rendererHelper.save(getCurrentTableDataTree().getTableDataTreeCellRenderer()); + treeSearcher = new TableDataTreeSearcher(); + FineLoggerFactory.getLogger().debug("switch to table data search for mode: {}", searchMode.name()); + treeSearcher.beforeSearch(searchMode, tableDataSource); + } + + /** + * 获取当前的tableDataTree + * + * @return + */ + private TableDataTree getCurrentTableDataTree() { + DesignModelAdapter currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); + TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter); + return tableDataTreePane.getDataTree(); + } + + public boolean isMatchSetsEmpty() { + return treeSearcher.isMatchSetsEmpty(); + } + + /** + * 开始搜索 + * + * @param searchText + */ + public void startSearch(String searchText) { + if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) { + return; + } + setTreeSearchStatus(TreeSearchStatus.SEARCHING); + rendererHelper.replaceTreeRenderer(getCurrentTableDataTree(), searchText); + count = new AtomicInteger(treeSearcher.getAllWrappersSize()); + FineLoggerFactory.getLogger().debug("start table data search for search text: {}", searchText); + treeSearcher.startSearch(searchText); + } + + /** + * 计数-1 + */ + public void decreaseCount() { + if (count == null) { + return; + } + int cunrrentCount = count.decrementAndGet(); + // 减到0后判断状态 + if (cunrrentCount == 0 && getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { + completeSearch(); + } + } + + private boolean isRepeatSearch(String searchText) { + boolean repeat = StringUtils.equals(lastSearchText, searchText); + lastSearchText = searchText; + return repeat; + } + + /** + * 刷新树,更新搜索的结果 + */ + public void updateTableDataTree() { + getCurrentTableDataTree().refresh4TreeSearch(); + } + + /** + * 中断搜索 + */ + public void stopSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED); + count = null; + FineLoggerFactory.getLogger().debug("stop table data search for search text: {}", lastSearchText); + treeSearcher.stopSearch(); + } + + /** + * 搜索完成 + */ + public void completeSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED); + count = null; + FineLoggerFactory.getLogger().debug("complete table data search for search text: {}", lastSearchText); + treeSearcher.completeSearch(); + } + + /** + * 切换回工具栏,恢复数据集树UI + */ + public void restoreToolBarAndTreePane() { + setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE); + FineLoggerFactory.getLogger().info("out of table data search"); + if (treeSearcher != null) { + treeSearcher.afterSearch(); + } + lastSearchText = null; + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTableDataTree()); + } + } + + /** + * 恢复数据集树UI + */ + public void restoreTreePane() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + lastSearchText = null; + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTableDataTree()); + } + } + + /** + * 节点是否应该添加到搜索结果树的根节点中 + * 只针对数据集节点 + * + * @param treeNodeName 数据集节点名称 + * @return + */ + public boolean nodeNameMatches(String treeNodeName) { + return treeSearcher.nodeMatches(treeNodeName); + } + + /** + * 节点是否应该展开 + * + * @param treeNodeName 节点名称 + * @return + */ + public boolean nodeCanExpand(String treeNodeName) { + return treeSearcher.nodeCanExpand(treeNodeName); + } + + public boolean isInSearchMode() { + return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE; + } + + public void outOfSearchMode() { + restoreToolBarAndTreePane(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java new file mode 100644 index 0000000000..d98b37c501 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java @@ -0,0 +1,54 @@ +package com.fr.design.data.datapane.management.search.control.common; + +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; +import com.fr.design.search.TreeSearchStatus; + +import javax.swing.SwingUtilities; + +/** + * @author Yvan + */ +public class TableDataSearchCallBack implements TreeSearchCallback { + + protected TableDataTreeSearcher treeSearcher; + + public TableDataSearchCallBack(TableDataTreeSearcher treeSearcher) { + this.treeSearcher = treeSearcher; + } + + @Override + public void done(TreeSearchResult treeSearchResult) { + if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + if (treeSearchResult.isSuccess()) { + // 添加结果 + addToTreeSearcher(treeSearchResult); + } + // 处理UI + updateTableDataTree(); + } + + protected void updateTableDataTree() { + SwingUtilities.invokeLater(() -> { + if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + TableDataTreeSearchManager.getInstance().updateTableDataTree(); + // 搜索计数 + TableDataTreeSearchManager.getInstance().decreaseCount(); + }); + } + + protected void addToTreeSearcher(TreeSearchResult treeSearchResult) { + // 添加到已计算结果集 + treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated()); + // 添加到匹配结果集 + treeSearcher.addToMatchSets(treeSearchResult.getAddToMatch()); + // 添加到展开结果集 + treeSearcher.addToCanExpandSets(treeSearchResult.getAddToExpand()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java new file mode 100644 index 0000000000..695ae11d06 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java @@ -0,0 +1,105 @@ +package com.fr.design.data.datapane.management.search.control.common; + +import com.fr.design.search.control.TreeSearchResult; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Yvan + */ +public class TableDataSearchResult implements TreeSearchResult { + + private boolean success; + + private List addToMatch; + + private List addToExpand; + + private List addToCalculated; + + protected TableDataSearchResult(Builder builder) { + this.success = builder.success; + this.addToMatch = builder.addToMatch; + this.addToExpand = builder.addToExpand; + this.addToCalculated = builder.addToCalculated; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public void setAddToMatch(List addToMatch) { + this.addToMatch = addToMatch; + } + + public void setAddToExpand(List addToExpand) { + this.addToExpand = addToExpand; + } + + public void setAddToCalculated(List addToCalculated) { + this.addToCalculated = addToCalculated; + } + + @Override + public boolean isSuccess() { + return this.success; + } + + @Override + public List getAddToMatch() { + return this.addToMatch; + } + + @Override + public List getAddToExpand() { + return this.addToExpand; + } + + @Override + public List getAddToCalculated() { + return this.addToCalculated; + } + + public static class Builder { + + private boolean success; + + private List addToMatch; + + private List addToExpand; + + private List addToCalculated; + + public Builder() { + this.success = false; + this.addToMatch = new ArrayList<>(); + this.addToExpand = new ArrayList<>(); + this.addToCalculated = new ArrayList<>(); + } + + public Builder buildSuccess(boolean success) { + this.success = success; + return this; + } + + public Builder buildAddToMatch(List addToMatch) { + this.addToMatch = addToMatch; + return this; + } + + public Builder buildAddToExpand(List addToExpand) { + this.addToExpand = addToExpand; + return this; + } + + public Builder buildAddToCalculated(List addToCalculated) { + this.addToCalculated = addToCalculated; + return this; + } + + public TableDataSearchResult build() { + return new TableDataSearchResult(this); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java new file mode 100644 index 0000000000..5dd7dca5fe --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java @@ -0,0 +1,148 @@ +package com.fr.design.data.datapane.management.search.control.common; + +import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.search.control.TreeSearchTask; +import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Yvan + */ +public class TableDataSearchTask implements TreeSearchTask { + + /** + * 用户搜索的文本 + */ + private String searchText; + + private TableDataWrapper tableDataWrapper; + + private TreeSearchCallback callback; + + public TableDataSearchTask(String searchText, TableDataWrapper tableDataWrapper, TreeSearchCallback callback) { + this.searchText = searchText; + this.tableDataWrapper = tableDataWrapper; + this.callback = callback; + } + + @Override + public void run() { + TreeSearchResult result; + try { + if (isTableDataStoreProcedure(tableDataWrapper)) { + result = dealWithStoreProcedureTableDataWrapper((MultiResultTableDataWrapper) tableDataWrapper); + } else { + result = dealWithCommonTableDataWrapper(tableDataWrapper); + } + FineLoggerFactory.getLogger().debug("calculate {}'s columns succeeded", tableDataWrapper.getTableDataName()); + } catch (Throwable e) { + FineLoggerFactory.getLogger().error(e, "calculate {}'s columns failed", tableDataWrapper.getTableDataName()); + result = dealWithErrorTableDataWrapper(tableDataWrapper); + } + callback.done(result); + } + + /** + * 处理错误情况 + * + * @param tableDataWrapper + */ + private TreeSearchResult dealWithErrorTableDataWrapper(TableDataWrapper tableDataWrapper) { + return new TableDataSearchResult.Builder().buildSuccess(false).build(); + } + + /** + * 处理普通数据集的搜索与匹配 + * + * @param tableDataWrapper + */ + private TreeSearchResult dealWithCommonTableDataWrapper(TableDataWrapper tableDataWrapper) { + String tableDataName = tableDataWrapper.getTableDataName(); + boolean isTableDataNameMatch = isMatchSearch(tableDataName, searchText); + List columnNameList = tableDataWrapper.calculateColumnNameList(); + // 没取到列名的话,代表取数那边出错了,就不添加数据集了 + if (columnNameList.size() == 0) { + return new TableDataSearchResult.Builder().buildSuccess(false).build(); + } + boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText)); + return new TableDataSearchResult.Builder() + .buildSuccess(true) + .buildAddToMatch(isTableDataNameMatch || isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>()) + .buildAddToExpand(isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>()) + .buildAddToCalculated(Arrays.asList(tableDataName)) + .build(); + } + + /** + * 处理存储过程的搜索与匹配 + * + * @param procedureDataWrapper + */ + private TreeSearchResult dealWithStoreProcedureTableDataWrapper(MultiResultTableDataWrapper procedureDataWrapper) { + // 存储过程数据集名称,例如 Proc1_Table1 + String tableDataName = procedureDataWrapper.getTableDataName(); + // 存储过程名称,例如 Proc1 + String storeProcedureName = procedureDataWrapper.getTableDataName(); + // 存储过程子表名称,例如 Table1 + String tableName = tableDataName.replaceFirst(storeProcedureName, StringUtils.EMPTY).replaceFirst("_", StringUtils.EMPTY); + boolean isStoreProcedureNameMatch = isMatchSearch(storeProcedureName, searchText); + boolean isTableNameMatch = isMatchSearch(tableName, searchText); + // 再处理子表的columns + List columnNameList = tableDataWrapper.calculateColumnNameList(); + boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText)); + Set addToMatch = new HashSet<>(); + Set addToExpand = new HashSet<>(); + Set addToCalculated = new HashSet<>(); + if (isStoreProcedureNameMatch) { + addToMatch.add(storeProcedureName); + } + if (isTableNameMatch) { + addToMatch.add(storeProcedureName); + addToExpand.add(storeProcedureName); + } + if (isColumnMatch) { + addToMatch.add(storeProcedureName); + addToExpand.add(storeProcedureName); + // 这里有重名风险,所以要添加 “Proc1_Table1”,在结果树展示的时候再去处理 + addToExpand.add(tableDataName); + } + addToCalculated.add(tableDataName); + return new TableDataSearchResult.Builder() + .buildSuccess(true) + .buildAddToMatch(new ArrayList<>(addToMatch)) + .buildAddToExpand(new ArrayList<>(addToExpand)) + .buildAddToCalculated(new ArrayList<>(addToCalculated)) + .build(); + + } + + /** + * 判断TableDataWrapper内的TableData是否为存储过程 + * + * @param tableDataWrapper + * @return + */ + private boolean isTableDataStoreProcedure(TableDataWrapper tableDataWrapper) { + return tableDataWrapper instanceof MultiResultTableDataWrapper; + } + + /** + * 判断是否匹配搜索文本,不区分大小写 + * + * @param str + * @return + */ + private boolean isMatchSearch(String str, String searchText) { + return str.toUpperCase().contains(searchText.toUpperCase()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java new file mode 100644 index 0000000000..9c5dd8341c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java @@ -0,0 +1,23 @@ +package com.fr.design.data.datapane.management.search.control.pre; + +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack; +import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher; + +/** + * 预取数任务回调 + * + * @author Yvan + */ +public class TableDataPreSearchCallBack extends TableDataSearchCallBack { + + + public TableDataPreSearchCallBack(TableDataTreeSearcher treeSearcher) { + super(treeSearcher); + } + + @Override + public void done(TreeSearchResult treeSearchResult) { + // do nothing + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java new file mode 100644 index 0000000000..b13657452e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java @@ -0,0 +1,40 @@ +package com.fr.design.data.datapane.management.search.control.pre; + +import com.fr.design.search.control.TreeSearchResult; + +import java.util.ArrayList; +import java.util.List; + +/** + * 预取数任务结果,不需要回调,因此空实现即可 + * + * @author Yvan + */ +public class TableDataPreSearchResult implements TreeSearchResult { + + private boolean success; + + public TableDataPreSearchResult(boolean success) { + this.success = success; + } + + @Override + public boolean isSuccess() { + return this.success; + } + + @Override + public List getAddToMatch() { + return new ArrayList<>(); + } + + @Override + public List getAddToExpand() { + return new ArrayList<>(); + } + + @Override + public List getAddToCalculated() { + return new ArrayList<>(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java new file mode 100644 index 0000000000..2eb572fcbb --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java @@ -0,0 +1,43 @@ +package com.fr.design.data.datapane.management.search.control.pre; + +import com.fr.design.search.control.TreeSearchTask; +import com.fr.design.data.datapane.management.search.control.common.TableDataSearchResult; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.log.FineLoggerFactory; + +/** + * 预取数任务 + * + * @author Yvan + */ +public class TableDataPreSearchTask implements TreeSearchTask { + + private TreeSearchCallback callback; + + private TableDataWrapper tableDataWrapper; + + public TableDataPreSearchTask(TreeSearchCallback callback, TableDataWrapper tableDataWrapper) { + this.callback = callback; + this.tableDataWrapper = tableDataWrapper; + } + + @Override + public void run() { + TreeSearchResult result; + try { + tableDataWrapper.calculateColumnNameList(); + result = new TableDataSearchResult.Builder() + .buildSuccess(true) + .build(); + FineLoggerFactory.getLogger().debug("pre calculate {}'s columns succeeded", tableDataWrapper.getTableDataName()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "pre calculate {}'s columns failed", tableDataWrapper.getTableDataName()); + result = new TableDataSearchResult.Builder() + .buildSuccess(false) + .build(); + } + callback.done(result); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java new file mode 100644 index 0000000000..dad2d4d4c6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java @@ -0,0 +1,215 @@ +package com.fr.design.data.datapane.management.search.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.data.datapane.TableDataTree; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/** + * @author Yvan + */ +public class TableDataSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener { + + private RemindPane remindPane; + private TreePane treePane; + + public TableDataSearchRemindPane(TableDataTree tableDataTree) { + this.setLayout(new BorderLayout()); + remindPane = new RemindPane(); + treePane = new TreePane(tableDataTree); + // 初始状态 + this.add(remindPane, BorderLayout.NORTH); + this.add(treePane, BorderLayout.CENTER); + TableDataTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + } + + /** + * 根据搜索状态变化,来调整自身面板的显示 + * + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + TreeSearchStatus status = event.getTreeSearchStatus(); + if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) { + remindPane.onNotBegin(); + treePane.onNotBegin(); + } else if (status == TreeSearchStatus.SEARCHING) { + remindPane.onInSearching(); + treePane.onInSearching(); + } else if (status == TreeSearchStatus.SEARCH_STOPPED) { + remindPane.onStoppedSearching(); + treePane.onStoppedSearching(); + } else { + boolean matchSetsEmpty = TableDataTreeSearchManager.getInstance().isMatchSetsEmpty(); + // 代表是否搜索出结果 + remindPane.onDoneSearching(matchSetsEmpty); + treePane.onDoneSearching(matchSetsEmpty); + } + this.revalidate(); + } + + private interface TreeSearchStatusChange { + + void onNotBegin(); + + void onInSearching(); + + void onStoppedSearching(); + + void onDoneSearching(boolean matchSetsEmpty); + } + + private class TreePane extends JPanel implements TreeSearchStatusChange { + + private UIScrollPane scrollPane; + + private JPanel notFoundPane; + + private CardLayout cardLayout; + + private static final String SCROLL_PANE = "scrollPane"; + + private static final String NOT_FOUND_PANE = "notFoundPane"; + + public TreePane(TableDataTree tableDataTree) { + init(tableDataTree); + } + + private void init(TableDataTree tableDataTree) { + + scrollPane = new UIScrollPane(tableDataTree); + scrollPane.setBorder(null); + + notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); + UILabel emptyPicLabel = new UILabel(); + emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png")); + emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER); + emptyPicLabel.setPreferredSize(new Dimension(240, 100)); + UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER); + textLabel.setForeground(Color.gray); + textLabel.setHorizontalAlignment(SwingConstants.CENTER); + textLabel.setPreferredSize(new Dimension(240, 20)); + notFoundPane.add(emptyPicLabel); + notFoundPane.add(textLabel); + notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0)); + + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + this.add(scrollPane, SCROLL_PANE); + this.add(notFoundPane, NOT_FOUND_PANE); + cardLayout.show(this, SCROLL_PANE); + } + + @Override + public void onNotBegin() { + switchPane(SCROLL_PANE); + } + + @Override + public void onInSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onStoppedSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + if (matchSetsEmpty) { + switchPane(NOT_FOUND_PANE); + } + } + + private void switchPane(String paneName) { + cardLayout.show(this, paneName); + } + } + + private static class RemindPane extends JPanel implements TreeSearchStatusChange { + + private static final String IN_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching"); + private static final String STOP_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search"); + private static final String SEARCHING_STOPPED = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped"); + private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed"); + + private UILabel textLabel; + + private UILabel stopLabel; + + private MouseListener stopSearch; + + public RemindPane() { + init(); + } + + private void init() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); + // 初始情况下为Not_Begin + textLabel = new UILabel(); + textLabel.setForeground(Color.gray); + stopLabel = new UILabel(); + stopLabel.setForeground(UIConstants.NORMAL_BLUE); + stopSearch = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TableDataTreeSearchManager.getInstance().stopSearch(); + } + }; + stopLabel.addMouseListener(stopSearch); + this.add(textLabel); + this.add(stopLabel); + onNotBegin(); + } + + @Override + public void onNotBegin() { + this.setVisible(false); + } + + @Override + public void onInSearching() { + this.textLabel.setVisible(false); + this.stopLabel.setText(STOP_SEARCHING); + this.stopLabel.setVisible(true); + this.setVisible(true); + } + + @Override + public void onStoppedSearching() { + this.textLabel.setText(SEARCHING_STOPPED); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + this.textLabel.setText(DONE_SEARCHING); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java new file mode 100644 index 0000000000..f5266c9b6d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java @@ -0,0 +1,207 @@ +package com.fr.design.data.datapane.management.search.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.DesignModelAdapter; +import com.fr.design.constants.UIConstants; +import com.fr.design.data.datapane.TableDataTreePane; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author Yvan + */ +public class TreeSearchToolbarPane extends JPanel implements TreeSearchStatusChangeListener { + + public static final String TOOLBAR_PANE = "toolbarPane"; + + public static final String SEARCH_PANE = "searchPane"; + + /** + * 工具栏 + */ + private UIToolbar toolbar; + + /** + * 工具栏面板 + */ + private JPanel toolbarPane; + + /** + * 搜索面板 + */ + private JPanel searchPane; + + /** + * 搜索输入框 + */ + private UITextField searchTextField; + + /** + * 内容面板 + */ + private JPanel contentPane; + + /** + * 卡片布局管理器 + */ + private CardLayout cardLayout; + + private final KeyAdapter enterPressed = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + TableDataTreeSearchManager.getInstance().startSearch(searchTextField.getText()); + } + } + }; + + public TreeSearchToolbarPane(UIToolbar toolbar) { + this.toolbar = toolbar; + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + initToolbarPane(); + initSearchPane(); + initContentPane(); + add(contentPane, BorderLayout.CENTER); + setPreferredSize(new Dimension(240, 30)); + TableDataTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + } + + private void initContentPane() { + cardLayout = new CardLayout(); + contentPane = new JPanel(cardLayout); + contentPane.add(searchPane, SEARCH_PANE); + contentPane.add(toolbarPane, TOOLBAR_PANE); + cardLayout.show(contentPane, TOOLBAR_PANE); + } + + private void initSearchPane() { + searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.setBackground(Color.WHITE); + // 左侧搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0)); + searchLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + }); + // 中间输入框 + searchTextField = new UITextField(){ + @Override + public Insets getInsets() { + return new Insets(2, 4, 0, 4); + } + }; + searchTextField.setBorderPainted(false); + searchTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Tree_Search_Press_Enter_For_Search")); + searchTextField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); + searchPane.repaint(); + } + + @Override + public void focusLost(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.repaint(); + } + }); + this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + } + + @Override + public void removeUpdate(DocumentEvent e) { + dealWithTextChange(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + this.searchTextField.addKeyListener(enterPressed); + // 右侧返回图标 + UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/clear")); + returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); + returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11)); + returnLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); + } + }); + + searchPane.add(searchLabel, BorderLayout.WEST); + searchPane.add(searchTextField, BorderLayout.CENTER); + searchPane.add(returnLabel, BorderLayout.EAST); + } + + private void dealWithTextChange() { + if (StringUtils.isEmpty(searchTextField.getText()) && TableDataTreeSearchManager.getInstance().isInSearchMode()) { + // 如果是搜索模式下,看作是用户删除输入框文字,仅复原TableDataTreePane + TableDataTreeSearchManager.getInstance().restoreTreePane(); + TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView(); + } + } + + private void initToolbarPane() { + toolbarPane = new JPanel(); + toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout()); + toolbarPane.add(toolbar, BorderLayout.CENTER); + } + + /** + * 交换当前面板层级 + */ + public void switchPane(String name) { + cardLayout.show(contentPane, name); + } + + public void setPlaceHolder(String placeHolder) { + this.searchTextField.setPlaceholder(placeHolder); + } + + /** + * 根据搜索状态变化,来调整自身面板的显示 + * + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + TreeSearchStatus treeSearchStatus = event.getTreeSearchStatus(); + if (treeSearchStatus == TreeSearchStatus.NOT_IN_SEARCH_MODE) { + this.searchTextField.setText(StringUtils.EMPTY); + switchPane(TOOLBAR_PANE); + } else { + switchPane(SEARCH_PANE); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java new file mode 100644 index 0000000000..d68455db56 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java @@ -0,0 +1,38 @@ +package com.fr.design.data.datapane.management.search.searcher; + +/** + * 搜索模式 + * + * @author Yvan + */ +public enum TableDataSearchMode { + + /** + * 搜索模板数据集 + */ + TEMPLATE_TABLE_DATA(0), + + /** + * 搜索服务器数据集 + */ + SERVER_TABLE_DATA(1); + + private final int mode; + + TableDataSearchMode(int mode) { + this.mode = mode; + } + + public int getMode() { + return mode; + } + + public static TableDataSearchMode match(int mode) { + for (TableDataSearchMode searchMode : TableDataSearchMode.values()) { + if (searchMode.getMode() == mode) { + return searchMode; + } + } + return TEMPLATE_TABLE_DATA; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java new file mode 100644 index 0000000000..0b65d54810 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java @@ -0,0 +1,150 @@ +package com.fr.design.data.datapane.management.search.searcher; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.data.TableDataSource; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; +import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack; +import com.fr.design.data.datapane.management.search.control.common.TableDataSearchTask; +import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchCallBack; +import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchTask; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.TreeSearcher; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @author Yvan + */ +public class TableDataTreeSearcher implements TreeSearcher { + + private ExecutorService executorService; + + private Map allWrappers = new ConcurrentHashMap<>(); + + private final Set calculatedSets = new HashSet<>(); + + private final Set notCalculatedSets = new HashSet<>(); + + private final Set matchSets = new HashSet<>(); + + private final Set canExpandSets = new HashSet<>(); + + public TableDataTreeSearcher() { + } + + public boolean isMatchSetsEmpty() { + return matchSets.isEmpty(); + } + + public int getAllWrappersSize() { + return allWrappers.size(); + } + + public synchronized void addToCalculatedSets(List tableDataNames) { + for (String tableDataName : tableDataNames) { + TableDataWrapper tableDataWrapper = allWrappers.get(tableDataName); + if (tableDataWrapper == null) { + return; + } + calculatedSets.add(tableDataName); + } + } + + public synchronized void addToMatchSets(List matchNodeNames) { + matchSets.addAll(matchNodeNames); + } + + public synchronized void addToCanExpandSets(List canExpandNodeNames) { + canExpandSets.addAll(canExpandNodeNames); + } + + + /** + * 正式搜索前,预加载一下数据集列名 + * + * @param searchMode + * @param tableDataSource + */ + public void beforeSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) { + executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TableDataTreeSearcher.class)); + collectTableDataWrappers(searchMode, tableDataSource); + preCalculateColumns(); + } + + /** + * 预先对数据集进行取列名的操作,提升用户搜索体验 + */ + private void preCalculateColumns() { + for (String notCalculatedSet : notCalculatedSets) { + TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet); + if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN) { + executorService.execute(new TableDataPreSearchTask(new TableDataPreSearchCallBack(this), tableDataWrapper)); + } + } + } + + /** + * 收集下此次搜索需要进行取数的TableDataWrapper + * + * @param searchSubject + * @param tableDataSource + */ + private void collectTableDataWrappers(TableDataSearchMode searchSubject, TableDataSource tableDataSource) { + Map dataSet = searchSubject == TableDataSearchMode.TEMPLATE_TABLE_DATA ? + DesignTableDataManager.getTemplateDataSet(tableDataSource) : + DesignTableDataManager.getGlobalDataSet(); + // 转化一下存储过程 + Map setIncludingProcedure = DesignTableDataManager.getAllDataSetIncludingProcedure(dataSet); + notCalculatedSets.addAll(setIncludingProcedure.keySet()); + allWrappers.putAll(setIncludingProcedure); + } + + @Override + public void startSearch(String searchText) { + reset(); + for (String notCalculatedSet : notCalculatedSets) { + TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet); + if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { + executorService.execute(new TableDataSearchTask(searchText, tableDataWrapper, new TableDataSearchCallBack(this))); + } + } + } + + @Override + public void stopSearch() { + + } + + @Override + public void completeSearch() { + + } + + private void reset() { + matchSets.clear(); + canExpandSets.clear(); + calculatedSets.clear(); + notCalculatedSets.addAll(allWrappers.keySet()); + } + + public void afterSearch() { + allWrappers.clear(); + executorService.shutdownNow(); + } + + public boolean nodeMatches(String dsName) { + return matchSets.contains(dsName); + } + + public boolean nodeCanExpand(String dsName) { + return canExpandSets.contains(dsName); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java index eb8d188a1f..a452a4d371 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java @@ -106,6 +106,7 @@ public class CopyableJTable extends SortableJTable { self.updateEndPoint(-1, column); self.refreshTable(); } + self.requestFocusInWindow(); } private int getColumn(MouseEvent e) { @@ -249,26 +250,9 @@ public class CopyableJTable extends SortableJTable { FineLoggerFactory.getLogger().info("copy cell value"); java.util.List> table = new ArrayList<>(); if ((startRow != endRow || startCol != endCol) && Math.min(startCol, endCol) > -1) { - for (int i = Math.min(startRow, endRow); i <= Math.max(startRow, endRow); i++) { - table.add(new ArrayList<>()); - for (int j = Math.min(startCol, endCol); j <= Math.max(startCol, endCol); j++) { - Object text = this.getTableValue(i, j); - table.get(table.size() - 1).add(text); - } - } + copyAreaData(table); } else if (pointList.size() > 0) { - Collections.sort(pointList, Comparator.comparing(Point::getX).thenComparing(Point::getY)); - int startRow = pointList.get(0).x; - int currentRow = startRow; - table.add(new ArrayList<>()); - for (Point point : pointList) { - while (currentRow < point.x) { - table.add(new ArrayList<>()); - currentRow++; - } - Object text = this.getTableValue(point.x, point.y); - table.get(table.size() - 1).add(text); - } + copyPointsData(table); } Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -276,6 +260,35 @@ public class CopyableJTable extends SortableJTable { clip.setContents(tText, null); } + private void copyAreaData(java.util.List> table) { + for (int i = Math.min(startRow, endRow); i <= Math.max(startRow, endRow); i++) { + table.add(new ArrayList<>()); + for (int j = Math.min(startCol, endCol); j <= Math.max(startCol, endCol); j++) { + Object text = this.getTableValue(i, j); + if (text != null) { + table.get(table.size() - 1).add(text); + } + } + } + } + + private void copyPointsData(java.util.List> table) { + Collections.sort(pointList, Comparator.comparing(Point::getX).thenComparing(Point::getY)); + int startRow = pointList.get(0).x; + int currentRow = startRow; + table.add(new ArrayList<>()); + for (Point point : pointList) { + while (currentRow < point.x) { + table.add(new ArrayList<>()); + currentRow++; + } + Object text = this.getTableValue(point.x, point.y); + if (text != null) { + table.get(table.size() - 1).add(text); + } + } + } + private Object getTableValue(int row, int col) { Object value = null; if (col > -1) { diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java index 46706cf591..9074a18d66 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java @@ -3,7 +3,7 @@ package com.fr.design.data.datapane.preview; import com.fr.cache.list.IntList; import com.fr.data.AbstractDataModel; import com.fr.data.impl.EmbeddedTableData.EmbeddedTDDataModel; -import com.fr.data.impl.storeproc.ProcedureDataModel; +import com.fr.data.impl.NameDataModel; import com.fr.design.utils.DesignUtils; import com.fr.general.data.DataModel; import com.fr.general.data.TableDataException; @@ -20,20 +20,29 @@ public class PreviewTableModel extends AbstractTableModel { private static final int LEN_LIMIT = 1000; private static final String THREE_DOT = "..."; + private static final int DEFAULT_MAX_ROW_COUNT = 10000; private DataModel dataModel; private String erroMessage = null; public IntList dateIndexs = new IntList(4); + /** + * 为了兼容子类的空参构造,一般不主动使用 + */ + public PreviewTableModel() { + this(new ErrorResultSet(), DEFAULT_MAX_ROW_COUNT); + } + public PreviewTableModel(int maxRowCount) { // peter:默认必须显示错误的数据源. this(new ErrorResultSet(), maxRowCount); } public PreviewTableModel(DataModel sourceResultSet, int maxRowCount) { - if (sourceResultSet instanceof ProcedureDataModel) { - ProcedureDataModel rs = (ProcedureDataModel) sourceResultSet; + // 如果是这种NameDataModel,根据maxRowCount截断一下 + if (sourceResultSet instanceof NameDataModel) { + NameDataModel rs = (NameDataModel) sourceResultSet; try { this.dataModel = createRowDataModel(rs, maxRowCount); } catch (TableDataException e) { @@ -45,7 +54,7 @@ public class PreviewTableModel extends AbstractTableModel { } } - public static DataModel createRowDataModel(final ProcedureDataModel rs, int maxRowCount) throws TableDataException { + public static DataModel createRowDataModel(final NameDataModel rs, int maxRowCount) throws TableDataException { int rowCount = rs.getRowCount(); if (maxRowCount == 0) { maxRowCount = rowCount; @@ -107,6 +116,19 @@ public class PreviewTableModel extends AbstractTableModel { } } + /** + * 根据列名获取列序号,当返回-1时代表异常,异常会被忽略,不打印日志或给出前台提示 + * @param columnName + * @return + */ + public int getColumnIndexWithExceptionIngore(String columnName) { + try { + return dataModel.getColumnIndex(columnName); + } catch (TableDataException ingore) { + return -1; + } + } + public int getRowCount() { try { return this.dataModel.getRowCount(); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java index 409ae7f7fa..ffac1388c6 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java @@ -3,17 +3,23 @@ */ package com.fr.design.data.datapane.preview; -import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; import com.fr.data.TableDataSource; +import com.fr.data.desensitize.base.DesensitizationTableData; import com.fr.data.impl.DBTableData; import com.fr.data.impl.EmbeddedTableData; -import com.fr.data.impl.storeproc.ProcedureDataModel; +import com.fr.data.impl.NameDataModel; import com.fr.data.operator.DataOperator; import com.fr.design.DesignerEnvManager; import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager; +import com.fr.design.data.datapane.preview.desensitization.model.DesensitizedPreviewTableModel; +import com.fr.design.data.datapane.preview.desensitization.view.PreviewTableDesensitizationPane; +import com.fr.design.data.datapane.preview.desensitization.view.setting.TableDataDesensitizationSettingPane; import com.fr.design.dialog.BasicDialog; 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.frpane.UITabbedPane; @@ -25,9 +31,12 @@ import com.fr.design.gui.itextfield.UINumberField; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; import com.fr.design.ui.util.UIUtil; +import com.fr.esd.query.StrategicTableData; import com.fr.function.TIME; import com.fr.general.FRFont; +import com.fr.general.data.DataModel; import com.fr.log.FineLoggerFactory; import javax.swing.BorderFactory; @@ -38,6 +47,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.table.DefaultTableCellRenderer; @@ -48,27 +58,28 @@ import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CancellationException; /** * august: PreviewTablePane一共提供5个共有的静态方法,用来预览。 */ public class PreviewTablePane extends BasicPane { + private TableData tableData; - private ProcedureDataModel storeProcedureDataModel; - private static UINumberField maxPreviewNumberField; + private DataModel dataModel; + private UINumberField maxPreviewNumberField; private UINumberField currentRowsField; private JTable preveiwTable; private static AutoProgressBar progressBar; private AutoProgressBar connectionBar; - private java.util.List listeners = new ArrayList(); + private List listeners = new ArrayList(); private BasicDialog dialog; private SwingWorker worker; @@ -76,6 +87,54 @@ public class PreviewTablePane extends BasicPane { private static PreviewTablePane THIS; private EmbeddedTableData previewTableData; + private PreviewTableDesensitizationPane desensitizationPane; + + /** + * 用于refreshLabel的鼠标监听 + */ + private final MouseAdapter refreshLabelMouseAdapter = new MouseAdapter() { + boolean mouseEntered = false; + boolean buttonPressed = false; + + @Override + public void mouseEntered(MouseEvent e) { // 当鼠标进入时候调用. + mouseEntered = true; + if (!buttonPressed) { + refreshLabel.setBackground(java.awt.Color.WHITE); + refreshLabel.setOpaque(true); + refreshLabel.setBorder(BorderFactory.createLineBorder(java.awt.Color.GRAY)); + } + } + + @Override + public void mouseExited(MouseEvent e) { + mouseEntered = false; + refreshLabel.setOpaque(false); + refreshLabel.setBorder(BorderFactory.createEmptyBorder()); + } + + @Override + public void mousePressed(MouseEvent e) { + buttonPressed = true; + refreshLabel.setBackground(java.awt.Color.lightGray); + } + + @Override + public void mouseReleased(MouseEvent e) { + buttonPressed = false; + if (mouseEntered) { + refreshLabel.setBackground(java.awt.Color.WHITE); + try { + populate(tableData); + if (dataModel != null) { + setRowsLimitTableModel(); + } + } catch (Exception ignore) { + } + } + } + }; + public static final PreviewTablePane getInstance() { if (THIS == null) { THIS = new PreviewTablePane(); @@ -85,91 +144,181 @@ public class PreviewTablePane extends BasicPane { private PreviewTablePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); + // northPane + this.add(initNorthPane(), BorderLayout.NORTH); + // centerPane + this.add(initCenterPane(), BorderLayout.CENTER); + // dialog + initDialog(); + // progressBar + initProgressBar(); + } - // elalke:预览行数 - JPanel previewNumberPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - this.add(previewNumberPanel, BorderLayout.NORTH); + /** + * 初始化northPane + * + * @return + */ + private JComponent initNorthPane() { + JPanel northPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 预览行数面板 + northPane.add(initPreviewNumberPane(), BorderLayout.CENTER); + // 脱敏预览设置面板 + northPane.add(initDesensitizationPane(), BorderLayout.EAST); + return northPane; + } + /** + * 初始化预览行数面板 + * + * @return + */ + private JComponent initPreviewNumberPane() { + JPanel previewNumberPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + // 当前行数 JPanel currentPreviewPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - previewNumberPanel.add(currentPreviewPanel); currentPreviewPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Current_Preview_Rows") + ":")); - currentRowsField = new UINumberField(); currentPreviewPanel.add(currentRowsField); currentRowsField.setEditable(false); currentRowsField.setColumns(4); currentRowsField.setInteger(true); - + // 最大行数 JPanel maxPanel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - previewNumberPanel.add(maxPanel); maxPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Datasource_Maximum_Number_of_Preview_Rows") + ":")); - maxPreviewNumberField = new UINumberField(); maxPanel.add(maxPreviewNumberField); maxPreviewNumberField.setColumns(4); maxPreviewNumberField.setInteger(true); - - DesignerEnvManager designerEnvManager = DesignerEnvManager.getEnvManager(); - maxPreviewNumberField.setValue(designerEnvManager.getMaxNumberOrPreviewRow()); - - maxPreviewNumberField.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - DesignerEnvManager designerEnvManager = DesignerEnvManager.getEnvManager(); - designerEnvManager.setMaxNumberOrPreviewRow((int) ((UINumberField) evt.getSource()).getValue()); - } + maxPreviewNumberField.setValue(DesignerEnvManager.getEnvManager().getMaxNumberOrPreviewRow()); + maxPreviewNumberField.addActionListener(event -> { + DesignerEnvManager designerEnvManager = DesignerEnvManager.getEnvManager(); + designerEnvManager.setMaxNumberOrPreviewRow((int) ((UINumberField) event.getSource()).getValue()); }); + // 刷新按钮 + initRefreshLabel(); - Icon refreshImage = BaseUtils.readIcon("/com/fr/design/images/control/refresh.png"); - refreshLabel = new UILabel(refreshImage); + previewNumberPanel.add(currentPreviewPanel); + previewNumberPanel.add(maxPanel); previewNumberPanel.add(refreshLabel); - refreshLabel.addMouseListener(new MouseAdapter() { - boolean mouseEntered = false; - boolean buttonPressed = false; - - public void mouseEntered(MouseEvent e) { // 当鼠标进入时候调用. - mouseEntered = true; - if (!buttonPressed) { - refreshLabel.setBackground(java.awt.Color.WHITE); - refreshLabel.setOpaque(true); - refreshLabel.setBorder(BorderFactory.createLineBorder(java.awt.Color.GRAY)); + return previewNumberPanel; + } + + private void initRefreshLabel() { + Icon refreshImage = IconUtils.readIcon("/com/fr/design/images/control/refresh"); + refreshLabel = new UILabel(refreshImage); + refreshLabel.addMouseListener(refreshLabelMouseAdapter); + } + + /** + * 初始化脱敏设置面板 + * + * @return + */ + private JComponent initDesensitizationPane() { + desensitizationPane = new PreviewTableDesensitizationPane(this); + return desensitizationPane; + } + + /** + * 点击脱敏配置后的操作 + */ + public void clickDesensitizationLabel() { + // 埋点记录 + recordDesensitization(); + // 判断数据集类型 + if (isGlobalTableData()) { + // 服务器数据集不允许在设计器端修改脱敏配置 + FineJOptionPane.showMessageDialog( + this, + Toolkit.i18nText("Fine-Design_Report_Cannot_Modify_Desensitization_Config_Of_ServerTableData"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + FineJOptionPane.WARNING_MESSAGE); + return; + } + TableDataDesensitizationSettingPane settingPane = new TableDataDesensitizationSettingPane((DesensitizationTableData) tableData); + settingPane.populateBean((DesensitizationTableData) tableData); + BasicDialog dialog = settingPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(PreviewTablePane.this), new DialogActionAdapter() { + @Override + public void doOk() { + // 保存脱敏规则配置 + settingPane.updateBean(); + // 改变模板保存状态 + JTemplate editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (Objects.nonNull(editingTemplate)) { + editingTemplate.fireTargetModified(true); } } - public void mouseExited(MouseEvent e) { - mouseEntered = false; - refreshLabel.setOpaque(false); - refreshLabel.setBorder(BorderFactory.createEmptyBorder()); - } + @Override + public void doCancel() { - public void mousePressed(MouseEvent e) { - buttonPressed = true; - refreshLabel.setBackground(java.awt.Color.lightGray); } + }, BasicDialog.DEFAULT); + dialog.setVisible(true); + // 关闭预览页面 + PreviewTablePane.this.dialog.setVisible(false); + } - public void mouseReleased(MouseEvent e) { - buttonPressed = false; - if (mouseEntered) { - refreshLabel.setBackground(java.awt.Color.WHITE); - try { - populate(tableData); - if (storeProcedureDataModel != null) { - populateStoreDataSQL(); - } - } catch (Exception e1) { - } - } - } - }); + /** + * 触发数据脱敏埋点记录 + * + * @return 数据脱敏字段数量 + */ + private int recordDesensitization() { + return getCurrentTableDataDesensitizationCount(); + } + /** + * 当前tableData是否为服务器数据集或服务器存储过程 + * + * @return + */ + public boolean isGlobalTableData() { + return this.tableData instanceof StrategicTableData && + DesignTableDataManager.isGlobalTableData(((StrategicTableData) this.tableData).getDsName()); + } + + /** + * 根据TableData设置脱敏设置的个数 + */ + private void setDesensitizationCountByTableData() { + desensitizationPane.setDesensitizationCount(isDesensitizeOpened(), getCurrentTableDataDesensitizationCount()); + desensitizationPane.dealWithTableDataType(isGlobalTableData()); + } + + /** + * 获取当前数据集中设置脱敏规则的个数 + * + * @return + */ + private int getCurrentTableDataDesensitizationCount() { + return this.tableData instanceof DesensitizationTableData ? + ((DesensitizationTableData) this.tableData).getDesensitizationConfig().getDesensitizationItems().size() : + 0; + } + + /** + * 初始化centerPane + * + * @return + */ + private JComponent initCenterPane() { preveiwTable = new CopyableJTable(new TableSorter()); preveiwTable.setRowSelectionAllowed(false); preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + return new JScrollPane(preveiwTable); + } - this.add(new JScrollPane(preveiwTable), BorderLayout.CENTER); + private void initDialog() { if (this.dialog == null) { this.dialog = this.showWindow(new JFrame()); } + } + + private void initProgressBar() { progressBar = new AutoProgressBar(this, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) { + @Override public void doMonitorCanceled() { if (getWorker() != null) { getWorker().cancel(true); @@ -180,7 +329,7 @@ public class PreviewTablePane extends BasicPane { } public AutoProgressBar getProgressBar() { - return this.progressBar; + return PreviewTablePane.progressBar; } @Override @@ -220,13 +369,19 @@ public class PreviewTablePane extends BasicPane { return this.worker; } - // elake:为预览表的columnIndex列着c色. + /** + * 为预览表的columnIndex列着色. + * + * @param columnIndex 列索引值 + * @param c 颜色 + */ private void setPreviewTableColumnColor(final int columnIndex, final Color c) { addLoadedListener(new LoadedEventListener() { @Override public void fireLoaded() { TableColumn column = preveiwTable.getColumnModel().getColumn(columnIndex); DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() { + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); comp.setBackground(c); @@ -247,7 +402,7 @@ public class PreviewTablePane extends BasicPane { getInstance().preveiwTable = new SortableJTable(new TableSorter()); getInstance().preveiwTable.setRowSelectionAllowed(false); getInstance().preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - getInstance().progressBar.close(); + PreviewTablePane.progressBar.close(); getInstance().repaint(); } @@ -329,6 +484,7 @@ public class PreviewTablePane extends BasicPane { private void previewTableDataSQL() throws Exception { connectionBar = new AutoProgressBar(this, Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) { + @Override public void doMonitorCanceled() { getWorker().cancel(true); getDialog().setVisible(false); @@ -343,42 +499,49 @@ public class PreviewTablePane extends BasicPane { private void setPreviewTableColumnValue(final Graphics g) { for (int i = 0; i < preveiwTable.getColumnModel().getColumnCount(); i++) { TableColumn column = preveiwTable.getColumnModel().getColumn(i); - DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() { - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - Font f = table.getFont(); - - //默认在系统不支持 无法显示时 如自造的字 ,字体设置为空. - Font defaultShowFont = FRFont.getInstance("", f.getStyle(), f.getSize()); - if (value instanceof String) { - String str = (String) value; - for (int j = 0; j < str.length(); j++) { - char c = str.charAt(j); - if (!f.canDisplay(c)) { - table.setFont(defaultShowFont); - } + DefaultTableCellRenderer cellRenderer = getDefaultTableCellRenderer(); + column.setCellRenderer(cellRenderer); + } + } + + /** + * 默认表格格子渲染器 + * + * @return + */ + private DefaultTableCellRenderer getDefaultTableCellRenderer() { + return new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Font f = table.getFont(); + + //默认在系统不支持 无法显示时 如自造的字 ,字体设置为空. + Font defaultShowFont = FRFont.getInstance("", f.getStyle(), f.getSize()); + if (value instanceof String) { + String str = (String) value; + for (int j = 0; j < str.length(); j++) { + char c = str.charAt(j); + if (!f.canDisplay(c)) { + table.setFont(defaultShowFont); } } - return comp; } - }; - column.setCellRenderer(cellRenderer); - } + return comp; + } + }; } private void setWorker() { - worker = new SwingWorker() { - protected PreviewTableModel doInBackground() throws Exception { + worker = new SwingWorker() { + + @Override + protected TableModel doInBackground() throws Exception { connectionBar.start(); try { - if (tableData instanceof DBTableData) { - boolean status = DataOperator.getInstance().testConnection(((DBTableData) tableData).getDatabase()); - if (!status) { - throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed")); - } - } + testDBTableDataConnection(tableData); } finally { // 将close操作放到EDT线程中 UIUtil.invokeLaterIfNeeded(() -> connectionBar.close()); @@ -388,22 +551,20 @@ public class PreviewTablePane extends BasicPane { // parameterInputDialog // update之后的parameters,转成一个parameterMap,用于预览TableData PreviewTableModel previewModel = new PreviewTableModel(previewTableData.createDataModel(null), (int) maxPreviewNumberField.getValue()); - for (int i = 0; i < previewTableData.getColumnCount(); i++) { - Class cls = previewTableData.getColumnClass(i); - if (cls == Date.class || cls == TIME.class || cls == Timestamp.class) { - previewModel.dateIndexs.add(i); - } + if (TableDataPreviewDesensitizeManager.getInstance().needDesensitize(tableData)) { + // 数据集预览脱敏 + previewModel = TableDataPreviewDesensitizeManager.getInstance().desensitizeTableModel(tableData, previewModel); } + dealWithPreviewTableModelColumnClass(previewModel, previewTableData); return previewModel; } + @Override public void done() { try { - PreviewTableModel model = get(); - setModel(model); - setCurrentRows(model.getRowCount()); + TableModel model = get(); + setPreviewTableModel(model); setPreviewTableColumnValue(getParent().getGraphics()); - fireLoadedListener(); } catch (Exception e) { if (!(e instanceof CancellationException)) { FineLoggerFactory.getLogger().error(e.getMessage(), e); @@ -418,12 +579,43 @@ public class PreviewTablePane extends BasicPane { }; } + /** + * 检查DBTableData连接 + * + * @param tableData + * @throws Exception + */ + private void testDBTableDataConnection(TableData tableData) throws Exception { + if (tableData instanceof DBTableData) { + boolean status = DataOperator.getInstance().testConnection(((DBTableData) tableData).getDatabase()); + if (!status) { + throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed")); + } + } + } + + /** + * 处理预览Model的列类型 + * + * @param previewModel + * @param previewTableData + */ + private void dealWithPreviewTableModelColumnClass(PreviewTableModel previewModel, EmbeddedTableData previewTableData) { + for (int i = 0; i < previewTableData.getColumnCount(); i++) { + Class cls = previewTableData.getColumnClass(i); + if (cls == Date.class || cls == TIME.class || cls == Timestamp.class) { + previewModel.dateIndexs.add(i); + } + } + } + /** * 直接预览存储过程的一个返回数据集,没有实际值和显示值 * * @param storeProcedureDataModel storeProcedureDataModel */ - public static void previewStoreData(ProcedureDataModel storeProcedureDataModel) { + @Deprecated + public static void previewStoreData(NameDataModel storeProcedureDataModel) { previewStoreData(storeProcedureDataModel, -1, -1); } @@ -434,13 +626,30 @@ public class PreviewTablePane extends BasicPane { * @param keyIndex 实际值 * @param valueIndex 显示值 */ - public static void previewStoreData(final ProcedureDataModel storeProcedureDataModel, final int keyIndex, final int valueIndex) { + @Deprecated + public static void previewStoreData(final NameDataModel storeProcedureDataModel, final int keyIndex, final int valueIndex) { + previewDataModel(storeProcedureDataModel, keyIndex, valueIndex); + } + + public static void previewDataModel(DataModel dataModel) { + previewDataModel(dataModel, -1, -1); + } + + + /** + * 直接预览数据集的结果集 + * + * @param dataModel 结果集 + * @param keyIndex + * @param valueIndex + */ + public static void previewDataModel(final DataModel dataModel, final int keyIndex, final int valueIndex) { final PreviewTablePane previewTablePane = new PreviewTablePane(); - previewTablePane.storeProcedureDataModel = storeProcedureDataModel; + previewTablePane.dataModel = dataModel; previewTablePane.setBorder(BorderFactory.createTitledBorder(Toolkit.i18nText("Fine-Design_Basic_Data"))); try { - previewTablePane.populateStoreDataSQL(); + previewTablePane.setRowsLimitTableModel(); previewTablePane.resetPreviewTableColumnColor(); if (keyIndex > -1) { @@ -457,27 +666,28 @@ public class PreviewTablePane extends BasicPane { previewTablePane.showWindow(new JFrame()).setVisible(true); } - /** - * 直接预览存储过程的所有返回数据集,没有实际值和显示值 - * - * @param storeProcedureDataModels storeProcedureDataModels - */ - public static void previewStoreDataWithAllDs(ProcedureDataModel[] storeProcedureDataModels) { - UITabbedPane tabPreviewpane = new UITabbedPane(); - int tableSize = storeProcedureDataModels.length; - for (int i = 0; i < tableSize; i++) { + + public static void previewMultiDataModels(NameDataModel[] nameDataModels) { + // tab窗口 + UITabbedPane tabbedPane = new UITabbedPane(); + + for (NameDataModel nameDataModel : nameDataModels) { + // 单个结果集的展示面板 PreviewTablePane previewTablePane = new PreviewTablePane(); - previewTablePane.storeProcedureDataModel = storeProcedureDataModels[i]; + previewTablePane.dataModel = nameDataModel; + // 数据 previewTablePane.setBorder(BorderFactory.createTitledBorder(Toolkit.i18nText("Fine-Design_Basic_Data"))); try { - previewTablePane.populateStoreDataSQL(); + // 带行数限制的数据集结果预览对象 + previewTablePane.setRowsLimitTableModel(); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } - tabPreviewpane.addTab(storeProcedureDataModels[i].getName(), previewTablePane); + tabbedPane.addTab(nameDataModel.getName(), previewTablePane); } - BasicPane prieviewPane = new BasicPane() { + // 包含整个tab的容器窗口 + BasicPane previewPane = new BasicPane() { @Override protected String title4PopupWindow() { @@ -485,21 +695,84 @@ public class PreviewTablePane extends BasicPane { } }; - prieviewPane.setLayout(FRGUIPaneFactory.createBorderLayout()); - prieviewPane.add(tabPreviewpane, BorderLayout.CENTER); - prieviewPane.showWindow(new JFrame()).setVisible(true); + previewPane.setLayout(FRGUIPaneFactory.createBorderLayout()); + previewPane.add(tabbedPane, BorderLayout.CENTER); + previewPane.showWindow(new JFrame()).setVisible(true); + } + + /** + * 直接预览存储过程的所有返回数据集,没有实际值和显示值 + * + * @param storeProcedureDataModels storeProcedureDataModels + */ + @Deprecated + public static void previewStoreDataWithAllDs(NameDataModel[] storeProcedureDataModels) { + previewMultiDataModels(storeProcedureDataModels); } - private void populateStoreDataSQL() throws Exception { + private void setRowsLimitTableModel() throws Exception { PreviewTableModel previewModel; try { - previewModel = new PreviewTableModel(storeProcedureDataModel, (int) maxPreviewNumberField.getValue()); + previewModel = new PreviewTableModel(dataModel, (int) maxPreviewNumberField.getValue()); } catch (Exception e) { previewModel = new PreviewTableModel((int) maxPreviewNumberField.getValue()); } - setModel(previewModel); - setCurrentRows(previewModel.getRowCount()); + setPreviewTableModel(previewModel); + + } + + /** + * 切换TableModel的展示状态 + */ + public void togglePreviewTableModelDesensitizeStatus() { + if (!isDesensitizeOpened()) { + // 未启用数据脱敏时,不需要切换 + return; + } + TableSorter tableSorter = (TableSorter) preveiwTable.getModel(); + TableModel originTableModel = tableSorter.getTableModel(); + if (originTableModel instanceof DesensitizedPreviewTableModel) { + ((DesensitizedPreviewTableModel) originTableModel).toggleNeedDesensite(); + } + } + + /** + * 刷新一下预览页面,用于切换脱敏和非脱敏时的显示 + */ + public void refreshTable() { + TableModel originTableModel = getCurrentTableModel(); + setPreviewTableModel(originTableModel); + } + + /** + * 获取当前的TableModel,已经除掉了TableSorter的包装 + * + * @return + */ + private TableModel getCurrentTableModel() { + TableSorter tableSorter = (TableSorter) preveiwTable.getModel(); + return tableSorter.getTableModel(); + } + + /** + * 设置预览TableModel + * + * @param previewTableModel + */ + private void setPreviewTableModel(TableModel previewTableModel) { + setDesensitizationCountByTableData(); + setModel(previewTableModel); + setCurrentRows(previewTableModel.getRowCount()); fireLoadedListener(); + } + /** + * 数据脱敏是否启用 + * + * @return + */ + private boolean isDesensitizeOpened() { + return tableData instanceof DesensitizationTableData && + ((DesensitizationTableData) tableData).getDesensitizationConfig().isDesensitizeOpened(); } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/TableDataPreviewDesensitizeManager.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/TableDataPreviewDesensitizeManager.java new file mode 100644 index 0000000000..abd5a4d166 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/TableDataPreviewDesensitizeManager.java @@ -0,0 +1,136 @@ +package com.fr.design.data.datapane.preview.desensitization; + + +import com.fr.base.TableData; +import com.fr.data.TableDataSource; +import com.fr.data.desensitize.TableDataDesensitizeManager; +import com.fr.data.desensitize.base.DesensitizationTableData; +import com.fr.data.desensitize.base.TableDataDesensitizationItem; +import com.fr.data.desensitize.manage.DesensitizationManager; +import com.fr.data.desensitize.util.DesentizationUtils; +import com.fr.decision.webservice.bean.user.DepartmentPostBean; +import com.fr.decision.webservice.bean.user.RoleBean; +import com.fr.decision.webservice.utils.DecisionServiceConstants; +import com.fr.decision.webservice.v10.user.CustomRoleService; +import com.fr.decision.webservice.v10.user.PositionService; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.preview.PreviewTableModel; +import com.fr.design.data.datapane.preview.desensitization.model.DesensitizedPreviewTableModel; +import com.fr.esd.query.StrategicTableData; +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + * 管理所有数据集预览过程中的脱敏计算 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/14 + */ +public class TableDataPreviewDesensitizeManager implements DesensitizationManager { + + private static final String CONNECTOR = "_"; + + private TableDataPreviewDesensitizeManager() { + } + + private static class Holder { + private static final TableDataPreviewDesensitizeManager INSTANCE = new TableDataPreviewDesensitizeManager(); + } + + /** + * 获取TableDataPreviewDesensitizeManager单例 + * + * @return + */ + public static TableDataPreviewDesensitizeManager getInstance() { + return TableDataPreviewDesensitizeManager.Holder.INSTANCE; + } + + /** + * 判断数据集预览时是否需要脱敏,这里不需要判断roleIds,因为默认有权限编辑的人一定有权限看脱敏前后字段值 + * 只需要保证此数据集存在脱敏配置就行 + * + * @param tableData + * @return + */ + public boolean needDesensitize(TableData tableData) { + return tableData instanceof DesensitizationTableData && + DesentizationUtils.isCollectionNotEmpty(((DesensitizationTableData) tableData).getDesensitizationConfig().getDesensitizationItems()); + } + + /** + * 数据集预览脱敏,使用DesensitizedPreviewTableModel对当前的预览TableModel做包装 + * + * @param model + * @return + */ + public PreviewTableModel desensitizeTableModel(TableData tableData, PreviewTableModel model) { + + Map desensitizationItemMap = new LinkedHashMap<>(); + // 获取此数据集的所有脱敏信息 + Collection desensitizationItems = ((DesensitizationTableData) tableData).getDesensitizationConfig().getDesensitizationItems(); + if (DesentizationUtils.isCollectionNotEmpty(desensitizationItems)) { + // 更新规则 + desensitizationItems = TableDataDesensitizeManager.getInstance().dealWithlatestRules(desensitizationItems); + // 对脱敏配置项集合做过滤和排序处理 + List items = desensitizationItems.stream() + .filter(item -> isAvaliableItem4Preview(item, model)) + .sorted(Comparator.comparingInt(item -> matchColumnIndex(item, model))) + .collect(Collectors.toList()); + // 然后转换成Map + for (int i = 0; i < items.size(); i++) { + desensitizationItemMap.put(i, items.get(i)); + } + } + // 包装TableModel + return new DesensitizedPreviewTableModel(model, desensitizationItemMap); + } + + /** + * 判断是否为有效的用于预览脱敏效果的DesensitizationItem + * + * @param item 脱敏配置项 + * @param model 数据集预览数据 + * @return + */ + private boolean isAvaliableItem4Preview(TableDataDesensitizationItem item, PreviewTableModel model) { + return item.getRule().isEnable() && + matchColumnIndex(item, model) >= 0; + } + + /** + * 通过TableData获取其列名,理论上一定存在缓存值 + * + * @param tableData + * @return + */ + public List getColumnNamesByTableData(TableData tableData) { + TableDataSource editingTableDataSource = DesignTableDataManager.getEditingTableDataSource(); + if (editingTableDataSource != null && tableData instanceof StrategicTableData) { + return Arrays.asList(DesignTableDataManager.getSelectedColumnNames(editingTableDataSource, ((StrategicTableData) tableData).getDsName())); + } + return Collections.EMPTY_LIST; + } + + /** + * 根据列名,从PreviewTableModel中匹配列序号,如果返回-1代表未匹配到 + * @param desensitizationItem + * @param previewModel + * @return + */ + public int matchColumnIndex(TableDataDesensitizationItem desensitizationItem, PreviewTableModel previewModel) { + return previewModel.getColumnIndexWithExceptionIngore(desensitizationItem.getColumnName()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/model/DesensitizedPreviewTableModel.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/model/DesensitizedPreviewTableModel.java new file mode 100644 index 0000000000..d8908fd14d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/model/DesensitizedPreviewTableModel.java @@ -0,0 +1,114 @@ +package com.fr.design.data.datapane.preview.desensitization.model; + + +import com.fr.data.desensitize.base.TableDataDesensitizationItem; +import com.fr.data.desensitize.calculate.DesensitizationCalculator; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.design.data.datapane.preview.PreviewTableModel; +import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager; + +import java.util.Map; +import java.util.Objects; + +/** + * 数据集预览TableModel的脱敏实现 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/14 + */ +public class DesensitizedPreviewTableModel extends PreviewTableModel { + + /** + * 原始数据Model + */ + private PreviewTableModel previewTableModel; + + /** + * 脱敏后新组装的TableModel中,列序号 - 脱敏信息 对应的Map + */ + private Map desensitizationItemMap; + + private boolean needDesensitize = false; + + public DesensitizedPreviewTableModel(PreviewTableModel previewTableModel, Map desensitizationItemMap) { + this.previewTableModel = previewTableModel; + this.desensitizationItemMap = desensitizationItemMap; + } + + @Override + public String getColumnName(int column) { + return needDesensitize ? + desensitizationItemMap.get(column).getColumnName() : + previewTableModel.getColumnName(column); + } + + @Override + public int getRowCount() { + return previewTableModel.getRowCount(); + } + + @Override + public int getColumnCount() { + return needDesensitize ? + getDesensitizeColumnsCount() : + previewTableModel.getColumnCount(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return needDesensitize && Objects.nonNull(desensitizationItemMap.get(columnIndex)) ? + getDesensitizedValue(rowIndex, columnIndex) : + previewTableModel.getValueAt(rowIndex, columnIndex); + } + + /** + * 返回脱敏后的数据值 + * + * @param rowIndex + * @param columnIndex + * @return + */ + private Object getDesensitizedValue(int rowIndex, int columnIndex) { + // 先通过columnIndex找到对应原TableModel的列序号 + int originColumnIndex = TableDataPreviewDesensitizeManager.getInstance().matchColumnIndex(desensitizationItemMap.get(columnIndex), previewTableModel); + // 获取原值 + Object value = previewTableModel.getValueAt(rowIndex, originColumnIndex); + // 判空 + if (Objects.isNull(value)) { + return value; + } + // 脱敏 + String strValue = String.valueOf(value); + value = desensitizeValue(strValue, columnIndex); + return value; + } + + /** + * 计算脱敏后的value,此时columnIndex对应的脱敏信息一定不为空 + * + * @param strValue + * @param columnIndex + * @return + */ + private String desensitizeValue(String strValue, int columnIndex) { + DesensitizationRule rule = desensitizationItemMap.get(columnIndex).getRule(); + return DesensitizationCalculator.getInstance().desensitize(strValue, rule); + } + + /** + * 获取当前有效的脱敏字段个数 + * + * @return + */ + public int getDesensitizeColumnsCount() { + return desensitizationItemMap.size(); + } + + /** + * 切换脱敏状态 + */ + public void toggleNeedDesensite() { + this.needDesensitize = !needDesensitize; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/PreviewTableDesensitizationPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/PreviewTableDesensitizationPane.java new file mode 100644 index 0000000000..01c92e333f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/PreviewTableDesensitizationPane.java @@ -0,0 +1,133 @@ +package com.fr.design.data.datapane.preview.desensitization.view; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.gui.ibutton.UIToggleButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.i18n.Toolkit; +import com.fr.design.menu.SeparatorDef; +import com.fr.design.menu.ToolBarDef; + +import javax.swing.Icon; +import javax.swing.JPanel; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * 数据集预览-脱敏配置面板,主要展示当前脱敏开启状态、当前脱敏设定数量等 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/11/14 + */ +public class PreviewTableDesensitizationPane extends JPanel { + + private static final String DATA_DESENSITIZATION_CONFIG = Toolkit.i18nText("Fine-Design_Report_Desensitization_Config"); + private static final String LEFT_BRACKET = "("; + private static final String RIGHT_BRACKET = ")"; + private static final String COUNT = Toolkit.i18nText("Fine-Design_Report_Desensitization_Count"); + + /** + * 预览面板 + */ + private PreviewTablePane previewTablePane; + + /** + * "数据脱敏设置"-标签 + */ + private UILabel desensitizationLabel; + + /** + * 脱敏效果预览按钮 + */ + private UIToggleButton previewToggle; + + + public PreviewTableDesensitizationPane(PreviewTablePane previewTablePane) { + this.previewTablePane = previewTablePane; + initComponents(); + } + + /** + * 初始化面板 + */ + private void initComponents() { + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + this.add(initDesensitizationLabel()); + this.add(initToolBar()); + this.add(initPreviewButton()); + } + + /** + * 初始化Label + * + * @return + */ + private Component initDesensitizationLabel() { + // 初始化Label + desensitizationLabel = new UILabel(DATA_DESENSITIZATION_CONFIG); + desensitizationLabel.setForeground(UIConstants.NORMAL_BLUE); + desensitizationLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + previewTablePane.clickDesensitizationLabel(); + } + }); + return desensitizationLabel; + } + + /** + * 初始化分隔符 + * + * @return + */ + private UIToolbar initToolBar() { + ToolBarDef toolbarDef = new ToolBarDef(); + toolbarDef.addShortCut(SeparatorDef.DEFAULT); + UIToolbar toolBar = ToolBarDef.createJToolBar(); + toolBar.setBorderPainted(false); + toolbarDef.updateToolBar(toolBar); + return toolBar; + } + + /** + * 初始化脱敏效果预览按钮 + * + * @return + */ + private UIToggleButton initPreviewButton() { + previewToggle = new UIToggleButton(new Icon[]{IconUtils.readIcon("/com/fr/design/images/m_file/preview"), IconUtils.readIcon("/com/fr/design/images/m_file/preview")}, true); + previewToggle.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Preview")); + previewToggle.setSelected(false); + previewToggle.addActionListener(e -> { + // 切换TableModel的脱敏状态 + previewTablePane.togglePreviewTableModelDesensitizeStatus(); + // 刷新预览页面,展示 + previewTablePane.refreshTable(); + }); + return previewToggle; + } + + /** + * 设置Label的值,主要是需要动态修改配置的脱敏规则的数量 + * + * @param desensitizeOpen + * @param count + */ + public void setDesensitizationCount(boolean desensitizeOpen, int count) { + desensitizationLabel.setText(desensitizeOpen ? + DATA_DESENSITIZATION_CONFIG + LEFT_BRACKET + count + RIGHT_BRACKET + COUNT : + DATA_DESENSITIZATION_CONFIG); + } + + /** + * 服务器数据集时,Label需要置灰 + */ + public void dealWithTableDataType(boolean globalTableData) { + desensitizationLabel.setForeground(globalTableData ? UIConstants.DISABLED_ICON_COLOR : UIConstants.NORMAL_BLUE); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/ChooseMark.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/ChooseMark.java new file mode 100644 index 0000000000..099e9a960a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/ChooseMark.java @@ -0,0 +1,42 @@ +package com.fr.design.data.datapane.preview.desensitization.view.common; + +import com.fr.design.gui.ibutton.UIRadioButton; + +import javax.swing.AbstractCellEditor; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import java.awt.Component; + +/** + * 标记选中的CellEditor + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/12/20 + */ +public class ChooseMark extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { + + private final UIRadioButton selectedButton; + + public ChooseMark() { + this.selectedButton = new UIRadioButton(); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + selectedButton.setSelected(isSelected); + return selectedButton; + } + + @Override + public Object getCellEditorValue() { + return selectedButton.isSelected(); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + selectedButton.setSelected(isSelected); + return selectedButton; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/DesensitizationOpenPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/DesensitizationOpenPane.java new file mode 100644 index 0000000000..949069aaa8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/common/DesensitizationOpenPane.java @@ -0,0 +1,94 @@ +package com.fr.design.data.datapane.preview.desensitization.view.common; + +import com.fr.base.svg.IconUtils; +import com.fr.design.border.UITitledBorder; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.log.FineLoggerFactory; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Desktop; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.net.URL; + +/** + * 启用数据脱敏的面板 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/10/12 + */ +public class DesensitizationOpenPane extends JPanel { + + /** + * 数据脱敏启用框 + */ + private UICheckBox desensitizeOpenCheckBox; + + /** + * 跳转帮助文档Label + */ + private UILabel hyperlinkLabel; + + /** + * 启用提示Label + */ + private UILabel tipsLabel; + + + public DesensitizationOpenPane() { + VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP); + layout.setAlignLeft(true); + this.setLayout(layout); + this.setBorder(UITitledBorder.createBorderWithTitle(Toolkit.i18nText("Fine-Design_Report_Desensitization_Config"))); + + JPanel panel = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); + // 启用数据脱敏的勾选框 + desensitizeOpenCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_Desensitization_Opened")); + // 跳转帮助文档Label + hyperlinkLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/tip/tips")); + hyperlinkLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Open_Tips")); + hyperlinkLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent event) { + try { + URL url = new URL(Toolkit.i18nText("Fine-Design_Report_Desensitization_Help_Document_Url")); + Desktop.getDesktop().browse(url.toURI()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "open browse of table data desensitization help document failed for {}", e.getMessage()); + } + } + }); + panel.add(desensitizeOpenCheckBox); + panel.add(hyperlinkLabel); + + // 提示Label + tipsLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Opened_Tooltips")); + tipsLabel.setForeground(UIConstants.CHECK_BOX_TIP_FONT_COLOR); + + this.add(panel); + this.add(tipsLabel); + } + + /** + * 数据脱敏启用状态 + * @return + */ + public boolean isDesensitizationOpened() { + return desensitizeOpenCheckBox.isSelected(); + } + + /** + * 设置数据脱敏启用状态 + * @param opened + */ + public void setDesensitizationOpened(boolean opened) { + desensitizeOpenCheckBox.setSelected(opened); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java new file mode 100644 index 0000000000..d37ed152d2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java @@ -0,0 +1,375 @@ +package com.fr.design.data.datapane.preview.desensitization.view.rule; + +import com.fr.base.svg.IconUtils; +import com.fr.data.desensitize.rule.DesensitizationRuleManager; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.data.desensitize.rule.base.DesensitizationRuleStatus; +import com.fr.design.data.datapane.preview.desensitization.view.common.ChooseMark; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itableeditorpane.UITableEditAction; +import com.fr.design.gui.itableeditorpane.UITableEditorPane; +import com.fr.design.gui.itableeditorpane.UITableModelAdapter; +import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.Toolkit; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; + +import javax.swing.AbstractCellEditor; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 脱敏规则选择页面 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/26 + */ +public class DesensitizationRuleChoosePane extends JPanel { + + private CardLayout cardLayout; + + private UITableEditorPane serverRuleEditPane; + + private UITableEditorPane customRuleEditPane; + + private DesensitizationRuleSource currentRuleSource; + + private Map> latestRules; + + public DesensitizationRuleChoosePane(Map> latestRules) { + this.latestRules = latestRules; + this.cardLayout = new CardLayout(); + this.setLayout(cardLayout); + serverRuleEditPane = new UITableEditorPane<>(new DesensitizationRuleChooseTableModel(this, true)); + customRuleEditPane = new UITableEditorPane<>(new DesensitizationRuleChooseTableModel(this, false)); + serverRuleEditPane.setHeaderResizing(false); + customRuleEditPane.setHeaderResizing(false); + populateDesensitizationRules(); + this.add(serverRuleEditPane, DesensitizationRuleSource.SERVER.name()); + this.add(customRuleEditPane, DesensitizationRuleSource.CUSTOM.name()); + // 默认显示平台规则 + switchPaneByRuleSource(DesensitizationRuleSource.SERVER); + } + + /** + * 通过脱敏规则来源,切换显示不同的脱敏规则Table面板 + * + * @param ruleSource + */ + public void switchPaneByRuleSource(DesensitizationRuleSource ruleSource) { + this.currentRuleSource = ruleSource; + this.cardLayout.show(this, ruleSource.name()); + } + + /** + * 展示当前规则 + */ + private void populateDesensitizationRules() { + serverRuleEditPane.populate(latestRules.get(DesensitizationRuleSource.SERVER).values().toArray(new DesensitizationRule[0])); + customRuleEditPane.populate(latestRules.get(DesensitizationRuleSource.CUSTOM).values().toArray(new DesensitizationRule[0])); + } + + /** + * 获取当前选中的规则 + * + * @return + */ + public DesensitizationRule getSelectedDesensitizationRule() { + switch (currentRuleSource) { + case SERVER: + return serverRuleEditPane.getTableModel().getSelectedValue(); + case CUSTOM: + return customRuleEditPane.getTableModel().getSelectedValue(); + default: + return null; + } + } + + /** + * 规则选择Table的TableModel + */ + private class DesensitizationRuleChooseTableModel extends UITableModelAdapter { + + private Component parent; + + private boolean debugActionOnly; + + protected DesensitizationRuleChooseTableModel(Component parent, boolean debugActionOnly) { + super(new String[]{ + StringUtils.EMPTY, + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Description"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status"), + }); + this.parent = parent; + this.debugActionOnly = debugActionOnly; + this.setColumnClass(new Class[]{ + ChooseMark.class, + UILabel.class, + UILabel.class, + DesensitizationRuleStatusPane.class + }); + this.setDefaultEditor(ChooseMark.class, new ChooseMark()); + this.setDefaultRenderer(ChooseMark.class, new ChooseMark()); + this.setDefaultEditor(DesensitizationRuleStatusPane.class, new DesensitizationRuleStatusPane()); + this.setDefaultRenderer(DesensitizationRuleStatusPane.class, new DesensitizationRuleStatusPane()); + this.createTable().getColumnModel().getColumn(0).setMaxWidth(20); + this.createTable().getColumnModel().getColumn(3).setMaxWidth(60); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DesensitizationRule rule = getList().get(rowIndex); + switch (columnIndex) { + case 0: + // 选中状态 + return rule.equals(getSelectedValue()); + case 1: + // 脱敏规则名称 + return rule.getRuleName(); + case 2: + // 脱敏规则描述 + return DesensitizationRule.getDescription(rule); + case 3: + // 脱敏规则状态 + DesensitizationRuleStatus ruleStatus = DesensitizationRuleManager.getInstance().getRuleStatus(rule, latestRules); + // 非正常状态需要标记为异常 + return ruleStatus == DesensitizationRuleStatus.NORMAL ? StringUtils.EMPTY : Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status_Abnormal"); + default: + return StringUtils.EMPTY; + } + } + + @Override + public boolean isCellEditable(int row, int col) { + return true; + } + + @Override + public UITableEditAction[] createAction() { + return debugActionOnly ? + new UITableEditAction[]{new DebugRuleAction(parent)} : + new UITableEditAction[]{new AddRuleAction(), new EditRuleAction(), new DeleteRuleAction(parent), new DebugRuleAction(parent)}; + } + + private Set getCurrentExistRuleNames(String excludeName) { + List rules = getList(); + return CollectionUtils.isEmpty(rules) ? + new LinkedHashSet<>() : + rules.stream() + .map(DesensitizationRule::getRuleName) + .filter(name -> !StringUtils.equals(name, excludeName)) + .collect(Collectors.toSet()); + } + + /** + * 根据语言环境获取规则编辑页面的宽高 + * + * @return + */ + private Dimension getRuleEditPaneDimensionByLocale() { + return DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane"); + } + + /** + * 规则状态展示页面 + */ + private class DesensitizationRuleStatusPane extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { + + private UILabel ruleStatusLabel; + + DesensitizationRuleStatusPane() { + // 规则状态 + this.ruleStatusLabel = new UILabel(); + this.ruleStatusLabel.setForeground(Color.RED); + } + + /** + * 根据脱敏规则信息,刷新规则状态,主要用于与规则选择器的联动 + * + * @param rule + */ + public void refreshRuleStatus(DesensitizationRule rule) { + DesensitizationRuleStatus ruleStatus = DesensitizationRuleManager.getInstance().getRuleStatus(rule, latestRules); + if (ruleStatus == DesensitizationRuleStatus.NORMAL) { + // 正常规则时,重置提示Label + this.ruleStatusLabel.setText(StringUtils.EMPTY); + this.ruleStatusLabel.setToolTipText(null); + } else { + this.ruleStatusLabel.setText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status_Abnormal")); + this.ruleStatusLabel.setToolTipText(ruleStatus.getDescription()); + } + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + refreshRuleStatus(getList().get(row)); + return ruleStatusLabel; + } + + @Override + public Object getCellEditorValue() { + return ruleStatusLabel; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + refreshRuleStatus(getList().get(row)); + return ruleStatusLabel; + } + } + + /** + * 添加规则 + */ + private class AddRuleAction extends AddTableRowAction { + + public AddRuleAction() { + this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Add")); + this.setSmallIcon("/com/fr/design/standard/add/add_black", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 新增一条规则 + DesensitizationRuleEditPane editPane = new DesensitizationRuleEditPane(getCurrentExistRuleNames(StringUtils.EMPTY)); + BasicDialog basicDialog = editPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() { + @Override + public void doOk() { + DesensitizationRule rule = editPane.updateBean(); + // 添加到Rule Manager中 + if (DesensitizationRule.valid(rule)) { + DesensitizationRuleManager.getInstance().addRule(rule); + } + // 添加到Table中 + addRow(rule); + fireTableDataChanged(); + } + + @Override + public void doCancel() { + super.doCancel(); + } + }, getRuleEditPaneDimensionByLocale()); + basicDialog.setVisible(true); + } + } + + private class EditRuleAction extends UITableEditAction { + + public EditRuleAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Edit")); + this.setSmallIcon(IconUtils.readIcon("/com/fr/design/standard/edit/edit")); + } + + @Override + public void checkEnabled() { + setEnabled(table.getSelectedRow() != -1); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 获取当前选中规则的副本 + DesensitizationRule selectedValue = null; + try { + selectedValue = (DesensitizationRule) getSelectedValue().clone(); + } catch (CloneNotSupportedException ex) { + throw new RuntimeException(ex); + } + DesensitizationRuleEditPane editPane = new DesensitizationRuleEditPane(getCurrentExistRuleNames(selectedValue.getRuleName())); + editPane.populateBean(selectedValue); + final DesensitizationRule finalRule = selectedValue; + BasicDialog basicDialog = editPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() { + @Override + public void doOk() { + DesensitizationRule rule = editPane.updateBean(); + // 修改同步到RuleManager中 + if (DesensitizationRule.valid(rule)) { + DesensitizationRuleManager.getInstance().updateRule(finalRule, rule); + } + setSelectedValue(rule); + fireTableDataChanged(); + } + + @Override + public void doCancel() { + super.doCancel(); + } + }, getRuleEditPaneDimensionByLocale()); + basicDialog.setVisible(true); + } + } + + private class DeleteRuleAction extends DeleteAction { + + public DeleteRuleAction(Component parent) { + super(parent); + this.setName(Toolkit.i18nText("Fine-Design_Basic_Base_Remove")); + this.setSmallIcon("/com/fr/design/images/control/remove"); + } + + @Override + public void checkEnabled() { + setEnabled(table.getSelectedRow() != -1); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 获取当前选中规则 + DesensitizationRule selectedRule = getSelectedValue(); + // 删除同步到RuleManager中 + if (DesensitizationRule.valid(selectedRule)) { + DesensitizationRuleManager.getInstance().removeRule(selectedRule); + } + super.actionPerformed(e); + } + } + + private class DebugRuleAction extends UITableEditAction { + + private Component parent; + + public DebugRuleAction(Component parent) { + this.parent = parent; + this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug")); + this.setSmallIcon("/com/fr/design/standard/debug/debug"); + } + + @Override + public void checkEnabled() { + setEnabled(table.getSelectedRow() != -1 && getList().get(table.getSelectedRow()).isEnable()); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 获取当前选中规则 + DesensitizationRule selectedRule = getSelectedValue(); + if (selectedRule == null) { + return; + } + DesensitizationRuleDebugPane ruleDebugPane = new DesensitizationRuleDebugPane(selectedRule); + BasicDialog ruleDebugDialog = ruleDebugPane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), null, BasicDialog.DEFAULT); + ruleDebugDialog.setVisible(true); + } + } + } + + +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleDebugPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleDebugPane.java new file mode 100644 index 0000000000..eba6d10899 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleDebugPane.java @@ -0,0 +1,128 @@ +package com.fr.design.data.datapane.preview.desensitization.view.rule; + +import com.fr.data.desensitize.calculate.DesensitizationCalculator; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.design.dialog.BasicPane; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +/** + * 脱敏规则调试页 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/8 + */ +public class DesensitizationRuleDebugPane extends BasicPane { + + /** + * 脱敏规则 + */ + private DesensitizationRule rule; + + public DesensitizationRuleDebugPane(DesensitizationRule rule) { + this.rule = rule; + initComponent(); + } + + private void initComponent() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.add(initNorthPane(), BorderLayout.NORTH); + this.add(initCenterPane(), BorderLayout.CENTER); + } + + private JPanel initNorthPane() { + JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Description")); + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0)); + UILabel desensitizationRule = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Algorithm")); + UILabel characterReplace = new UILabel(rule.getRuleType().getRuleTypeName()); + UILabel description = new UILabel(DesensitizationRule.getDescription(rule)); + JComponent[][] components = new JComponent[][]{ + {desensitizationRule, characterReplace}, + {new UILabel(), description} + }; + panel.add( + TableLayoutHelper.createCommonTableLayoutPane( + components, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED}, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED}, + 20), + BorderLayout.CENTER); + northPane.add(panel); + return northPane; + } + + private JPanel initCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug")); + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0)); + + UILabel beforeDesensitize = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Before")); + UITextField beforeDesensitizeText = new UITextField(20); + beforeDesensitizeText.setPlaceholder(Toolkit.i18nText("Fine-Design_Report_Desensitization_Enter_Content")); + UILabel afterDesensitize = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_After")); + UITextField afterDesensitizeText = new UITextField(20); + afterDesensitizeText.setEditable(false); + UIButton desensitizeButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Debug")); + beforeDesensitizeText.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + afterDesensitizeText.setText(StringUtils.EMPTY); + } + + @Override + public void focusLost(FocusEvent e) { + + } + }); + desensitizeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String text = beforeDesensitizeText.getText(); + if (StringUtils.isEmpty(text)) { + FineJOptionPane.showMessageDialog(DesensitizationRuleDebugPane.this, + Toolkit.i18nText("Fine-Design_Report_Desensitization_Please_Enter_Valid_Content")); + } + String desensitizedText = DesensitizationCalculator.getInstance().desensitize(text, rule); + afterDesensitizeText.setText(desensitizedText); + } + }); + + JComponent[][] components = new JComponent[][]{ + {beforeDesensitize, beforeDesensitizeText, desensitizeButton}, + {afterDesensitize, afterDesensitizeText, new UILabel()} + }; + panel.add( + TableLayoutHelper.createCommonTableLayoutPane( + components, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED}, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}, + 20), + BorderLayout.CENTER); + + centerPane.add(panel); + return centerPane; + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Debug"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java new file mode 100644 index 0000000000..5a0515a59e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java @@ -0,0 +1,309 @@ +package com.fr.design.data.datapane.preview.desensitization.view.rule; + +import com.fr.data.desensitize.rule.base.DesensitizationCondition; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.data.desensitize.rule.base.DesensitizationRuleType; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.constants.UIConstants; +import com.fr.design.event.UIObserverListener; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UINumberField; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Insets; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.Arrays; +import java.util.Set; + +/** + * 脱敏规则编辑页 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/8 + */ +public class DesensitizationRuleEditPane extends BasicBeanPane { + /** + * 已经存在的规则名称,用于检测重名 + */ + private Set existRuleNames; + + private UITextField ruleNameTextField; + private UIComboBox ruleTypeComboBox; + private UINumberField retainFrontTextField; + private UINumberField retainBackTextField; + private UITextField firstSymbolTextField; + private UITextField secondSymbolTextField; + private CardLayout cardLayout; + private JPanel ruleConditionPane; + + + private DesensitizationRule rule = DesensitizationRule.createDefaultEmptyRule(); + + private final FocusListener retainFrontListener = new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + } + + @Override + public void focusLost(FocusEvent e) { + rule.getCondition().setRetainFront((int) retainFrontTextField.getValue()); + } + }; + + private final FocusListener retainBackListener = new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + } + + @Override + public void focusLost(FocusEvent e) { + rule.getCondition().setRetainBack((int) retainBackTextField.getValue()); + } + }; + + private final FocusListener firstSymbolListener = new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + } + + @Override + public void focusLost(FocusEvent e) { + rule.getCondition().setSymbol(firstSymbolTextField.getText()); + } + }; + + private final FocusListener secondSymbolListener = new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + } + + @Override + public void focusLost(FocusEvent e) { + rule.getCondition().setRetainFront(0); + rule.getCondition().setRetainBack(0); + rule.getCondition().setSymbol(secondSymbolTextField.getText()); + } + }; + + public DesensitizationRuleEditPane(Set existRuleNames) { + this.existRuleNames = existRuleNames; + initComponent(); + } + + /** + * 初始化面板 + */ + private void initComponent() { + this.setLayout(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + panel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 0)); + UILabel ruleNameLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name")); + // 规则名称输入框 + initRuleNameTextField(); + UILabel ruleTypeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Algorithm")); + // 脱敏算法Type设置 + JPanel ruleTypePane = initRuleTypePane(); + // 脱敏算法Condition设置 + JPanel ruleConditionPane = initRuleConditionPane(); + JComponent[][] components = { + {ruleNameLabel, ruleNameTextField}, + {ruleTypeLabel, ruleTypePane}, + {new UILabel(), ruleConditionPane} + }; + panel.add( + TableLayoutHelper.createGapTableLayoutPane( + components, + new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.FILL}, + new double[]{TableLayout.FILL, TableLayout.PREFERRED}, + 20, + 20), + BorderLayout.CENTER); + this.add(panel); + } + + /** + * 初始化规则类型面板 + * + * @return + */ + private JPanel initRuleTypePane() { + JPanel ruleTypePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // 脱敏算法类型下拉框 + initRuleTypeComboBox(); + ruleTypePane.add(ruleTypeComboBox, BorderLayout.CENTER); + return ruleTypePane; + } + + /** + * 初始化规则条件面板 + * + * @return + */ + private JPanel initRuleConditionPane() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + cardLayout = new CardLayout(); + ruleConditionPane = new JPanel(cardLayout); + // 字符替换 + JPanel characterReplacePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); + UILabel retainFrontLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_One") + StringUtils.BLANK); + retainFrontTextField = new UINumberField(5); + retainFrontTextField.addFocusListener(retainFrontListener); + + UILabel retainBackLabel = new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_Two") + StringUtils.BLANK); + retainBackTextField = new UINumberField(5); + retainBackTextField.addFocusListener(retainBackListener); + + UILabel replaceLabel = new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_Three") + StringUtils.BLANK); + firstSymbolTextField = new UITextField(10); + firstSymbolTextField.addFocusListener(firstSymbolListener); + + characterReplacePane.add(retainFrontLabel); + characterReplacePane.add(retainFrontTextField); + characterReplacePane.add(retainBackLabel); + characterReplacePane.add(retainBackTextField); + characterReplacePane.add(replaceLabel); + characterReplacePane.add(firstSymbolTextField); + // 整体替换 + JPanel characterAllReplacePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); + UILabel allReplaceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_All_Character_Replace_By") + StringUtils.BLANK); + secondSymbolTextField = new UITextField(10); + secondSymbolTextField.addFocusListener(secondSymbolListener); + + characterAllReplacePane.add(allReplaceLabel); + characterAllReplacePane.add(secondSymbolTextField); + + ruleConditionPane.add(characterReplacePane, DesensitizationRuleType.CHARACTER_REPLACE.getRuleTypeName()); + ruleConditionPane.add(characterAllReplacePane, DesensitizationRuleType.ALL_CHARACTERS_REPLACE.getRuleTypeName()); + // 初始化状态为字符替换 + switchRuleConditionPane(DesensitizationRuleType.CHARACTER_REPLACE); + + panel.add(ruleConditionPane, BorderLayout.CENTER); + return panel; + } + + /** + * 切换规则类型面板 + * + * @param ruleType + */ + private void switchRuleConditionPane(DesensitizationRuleType ruleType) { + this.cardLayout.show(ruleConditionPane, ruleType.getRuleTypeName()); + } + + /** + * 初始化规则类型下拉框 + */ + private void initRuleTypeComboBox() { + ruleTypeComboBox = new UIComboBox(Arrays.stream(DesensitizationRuleType.values()).map(DesensitizationRuleType::getRuleTypeName).toArray()); + ruleTypeComboBox.setSelectedIndex(0); + ruleTypeComboBox.registerChangeListener(new UIObserverListener() { + @Override + public void doChange() { + DesensitizationRuleType ruleType = DesensitizationRuleType.matchByTypeName((String) ruleTypeComboBox.getSelectedItem()); + rule.setRuleType(ruleType); + // 修改底下的conditionPane + switchRuleConditionPane(ruleType); + } + }); + } + + /** + * 初始化规则名称输入框 + */ + private void initRuleNameTextField() { + ruleNameTextField = new UITextField(20) { + @Override + public Insets getInsets() { + return new Insets(2, 4, 0, 4); + } + }; + ruleNameTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Report_Desensitization_Please_Enter_Rule_Name")); + ruleNameTextField.setBorderPainted(true); + ruleNameTextField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + ruleNameTextField.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); + ruleNameTextField.repaint(); + } + + @Override + public void focusLost(FocusEvent e) { + ruleNameTextField.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + rule.setRuleName(ruleNameTextField.getText()); + ruleNameTextField.repaint(); + } + }); + } + + + @Override + public void populateBean(DesensitizationRule ob) { + this.rule = ob; + this.ruleNameTextField.setText(rule.getRuleName()); + String typeName = rule.getRuleType().getRuleTypeName(); + this.ruleTypeComboBox.setSelectedItem(typeName); + switch (DesensitizationRuleType.matchByTypeName(typeName)) { + case CHARACTER_REPLACE: + this.retainFrontTextField.setValue(rule.getCondition().getRetainFront()); + this.retainBackTextField.setValue(rule.getCondition().getRetainBack()); + this.firstSymbolTextField.setText(rule.getCondition().getSymbol()); + break; + case ALL_CHARACTERS_REPLACE: + this.secondSymbolTextField.setText(rule.getCondition().getSymbol()); + break; + default: + } + + } + + @Override + public DesensitizationRule updateBean() { + rule.setRuleName(this.ruleNameTextField.getText()); + rule.setRuleSource(DesensitizationRuleSource.CUSTOM); + DesensitizationRuleType ruleType = DesensitizationRuleType.matchByTypeName(String.valueOf(this.ruleTypeComboBox.getSelectedItem())); + rule.setRuleType(ruleType); + rule.getCondition().setRetainFront((int) this.retainFrontTextField.getValue()); + rule.getCondition().setRetainBack((int) this.retainBackTextField.getValue()); + rule.getCondition().setSymbol(ruleType == DesensitizationRuleType.CHARACTER_REPLACE ? + this.firstSymbolTextField.getText() : + this.secondSymbolTextField.getText()); + rule.setEnable(true); + return rule; + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Report_Desensitization_Custom_Config_Rules"); + } + + @Override + public void checkValid() throws Exception { + // 保存rule前检查下 + String checkMessage = StringUtils.EMPTY; + if (StringUtils.isEmpty(rule.getRuleName())) { + checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name_Cannot_Be_Empty"); + } else if (existRuleNames.contains(rule.getRuleName())) { + checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Name_Cannot_Repeat"); + } else if (DesensitizationCondition.invalid(rule.getCondition())) { + checkMessage = Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Wrong_Condition"); + } + if (StringUtils.isNotEmpty(checkMessage)) { + throw new Exception(checkMessage); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRulePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRulePane.java new file mode 100644 index 0000000000..ba8b00d735 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRulePane.java @@ -0,0 +1,89 @@ +package com.fr.design.data.datapane.preview.desensitization.view.rule; + +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.border.UITitledBorder; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.util.Map; + +/** + * 脱敏规则展示页 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/8 + */ +public class DesensitizationRulePane extends BasicBeanPane { + + /** + * 规则来源选择面板 + */ + private DesensitizationRuleSourceChoosePane ruleSourceChoosePane; + + /** + * 规则选择面板 + */ + private DesensitizationRuleChoosePane ruleChoosePane; + + /** + * 最新的所有规则 + */ + private Map> latestRules; + + /** + * 内容面板 + */ + private JPanel contentPane; + + public DesensitizationRulePane(Map> latestRules) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.latestRules = latestRules; + initPane(); + } + + private void initPane() { + // 内容面板 + contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + contentPane.setBorder(UITitledBorder.createBorderWithTitle(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Choose"))); + this.add(contentPane, BorderLayout.CENTER); + // 规则来源选择Pane + ruleSourceChoosePane = new DesensitizationRuleSourceChoosePane(this); + // 规则选择Pane + ruleChoosePane = new DesensitizationRuleChoosePane(latestRules); + contentPane.add(ruleSourceChoosePane, BorderLayout.NORTH); + contentPane.add(ruleChoosePane, BorderLayout.CENTER); + } + + /** + * 处理规则来源选择面板中改动来源的事件 + * + * @param newRuleSource + */ + public void dealWithRuleSourceChanged(DesensitizationRuleSource newRuleSource) { + ruleChoosePane.switchPaneByRuleSource(newRuleSource); + } + + + @Override + public void populateBean(DesensitizationRule ob) { + // 这边展示当前所有规则时,不依靠外界传值,初始化的时候,从规则管理中心去获取 + } + + @Override + public DesensitizationRule updateBean() { + DesensitizationRule desensitizationRule = ruleChoosePane.getSelectedDesensitizationRule(); + return DesensitizationRule.valid(desensitizationRule) ? + desensitizationRule : + DesensitizationRule.createDefaultEmptyRule(); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleSourceChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleSourceChoosePane.java new file mode 100644 index 0000000000..05ace32bdd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleSourceChoosePane.java @@ -0,0 +1,49 @@ +package com.fr.design.data.datapane.preview.desensitization.view.rule; + +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.design.gui.ibutton.UIRadioButton; +import com.fr.design.i18n.Toolkit; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JPanel; +import java.awt.FlowLayout; + +/** + * 脱敏规则来源选择页面 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/26 + */ +public class DesensitizationRuleSourceChoosePane extends JPanel { + + /** + * 来源平台的按钮 + */ + private UIRadioButton serverSource; + + /** + * 来源本地的按钮 + */ + private UIRadioButton customSource; + + public DesensitizationRuleSourceChoosePane(DesensitizationRulePane desensitizationRulePane) { + this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + + serverSource = new UIRadioButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Server_Config_Rules")); + customSource = new UIRadioButton(Toolkit.i18nText("Fine-Design_Report_Desensitization_Custom_Config_Rules")); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(serverSource); + buttonGroup.add(customSource); + serverSource.setSelected(true); + + serverSource.registerChangeListener(() -> desensitizationRulePane.dealWithRuleSourceChanged(DesensitizationRuleSource.SERVER)); + customSource.registerChangeListener(() -> desensitizationRulePane.dealWithRuleSourceChanged(DesensitizationRuleSource.CUSTOM)); + + this.add(serverSource); + this.add(customSource); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationSettingPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationSettingPane.java new file mode 100644 index 0000000000..a37d9d0220 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationSettingPane.java @@ -0,0 +1,98 @@ +package com.fr.design.data.datapane.preview.desensitization.view.setting; + +import com.fr.data.desensitize.base.DesensitizationTableData; +import com.fr.data.desensitize.base.TableDataDesensitizationItem; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.data.datapane.preview.desensitization.view.common.DesensitizationOpenPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.JComponent; +import java.awt.BorderLayout; +import java.util.List; + +/** + * 数据集脱敏字段设置页面 + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/8 + */ +public class TableDataDesensitizationSettingPane extends BasicBeanPane { + + /** + * 设置针对的数据集 + */ + private DesensitizationTableData tableData; + + private DesensitizationOpenPane desensitizationOpenPane; + + private TableDataDesensitizationTablePane tableDataDesensitizationTablePane; + + + public TableDataDesensitizationSettingPane(DesensitizationTableData tableData) { + this.tableData = tableData; + initComponents(); + } + + private void initComponents() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.add(initNorthPane(), BorderLayout.NORTH); + this.add(initCenterPane(), BorderLayout.CENTER); + } + + /** + * 初始化启用数据脱敏面板 + * + * @return + */ + private JComponent initNorthPane() { + this.desensitizationOpenPane = new DesensitizationOpenPane(); + return desensitizationOpenPane; + } + + /** + * 初始化数据脱敏规则表面板 + * + * @return + */ + private JComponent initCenterPane() { + this.tableDataDesensitizationTablePane = new TableDataDesensitizationTablePane(tableData, this); + return tableDataDesensitizationTablePane; + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Report_Desensitization_Config"); + } + + @Override + public void populateBean(DesensitizationTableData tableData) { + this.tableData = tableData; + this.desensitizationOpenPane.setDesensitizationOpened(tableData.getDesensitizationConfig().isDesensitizeOpened()); + tableDataDesensitizationTablePane.populateDesensitizationSetting(tableData); + } + + @Override + public DesensitizationTableData updateBean() { + saveDesensitizeOpened(); + saveDesensitizationBeans(tableDataDesensitizationTablePane.updateDesensitizationSetting()); + return tableData; + } + + /** + * 保存脱敏启用状态 + */ + public void saveDesensitizeOpened() { + tableData.getDesensitizationConfig().setDesensitizeOpened(this.desensitizationOpenPane.isDesensitizationOpened()); + } + + /** + * 保存脱敏规则配置信息 + * + * @param desensitizationItems + */ + public void saveDesensitizationBeans(List desensitizationItems) { + tableData.getDesensitizationConfig().setDesensitizationItems(desensitizationItems); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTableModel.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTableModel.java new file mode 100644 index 0000000000..52b7e5b19b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTableModel.java @@ -0,0 +1,619 @@ +package com.fr.design.data.datapane.preview.desensitization.view.setting; + +import com.fr.data.desensitize.base.DesensitizationTableData; +import com.fr.data.desensitize.base.TableDataDesensitizationItem; +import com.fr.data.desensitize.rule.DesensitizationRuleManager; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.data.desensitize.rule.base.DesensitizationRuleStatus; +import com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRulePane; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.icombocheckbox.UIComboCheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itableeditorpane.UITableEditAction; +import com.fr.design.gui.itableeditorpane.UITableModelAdapter; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.stable.StringUtils; +import org.jetbrains.annotations.Nullable; + +import javax.swing.AbstractCellEditor; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * 处理TableDataDesensitizationTablePane中TableEditPane的Model + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/23 + */ +public class TableDataDesensitizationTableModel extends UITableModelAdapter { + + private static final String APOSTROPHE = "..."; + + private static final String COMMA = ","; + + /** + * 当前数据集的所有列名 + */ + private List columnNames = new ArrayList<>(); + + /** + * key为用户组唯一标识(id拼接),value为用户组名称 + */ + private Map roleMap = new LinkedHashMap<>(); + + /** + * 当前最新的所有规则 + */ + private Map> latestRules = new LinkedHashMap<>(); + + private Component parent; + + public TableDataDesensitizationTableModel(DesensitizationTableData tableData, Component parent, List columnNames, Map roleMap, Map> latestRules) { + // table相关 + super(new String[]{ + Toolkit.i18nText("Fine-Design_Report_Desensitization_Column"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Description"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Effected_Roles"), + Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status"), + }); + this.parent = parent; + this.columnNames = columnNames; + this.roleMap = roleMap; + this.latestRules = latestRules; + + initTable(); + } + + /** + * 初始化Table + */ + private void initTable() { + this.setColumnClass(new Class[]{ + // 列名选择 + ColumnNamesComboBox.class, + // 规则选择 + DesensitizationRuleChooser.class, + // 规则详情展示 + DesensitizationRuleDescriptionPane.class, + // 生效用户组选择 + EffectedRolesChooser.class, + // 规则状态 + DesensitizationRuleStatusPane.class + }); + ColumnNamesComboBox columnNamesComboBox = new ColumnNamesComboBox(); + this.setDefaultEditor(ColumnNamesComboBox.class, columnNamesComboBox); + this.setDefaultEditor(DesensitizationRuleChooser.class, new DesensitizationRuleChooser()); + this.setDefaultEditor(DesensitizationRuleDescriptionPane.class, new DesensitizationRuleDescriptionPane()); + EffectedRolesChooser effectedRolesChooser = new EffectedRolesChooser(); + this.setDefaultEditor(EffectedRolesChooser.class, effectedRolesChooser); + this.setDefaultEditor(DesensitizationRuleStatusPane.class, new DesensitizationRuleStatusPane()); + this.setDefaultRenderer(DesensitizationRuleStatusPane.class, new DesensitizationRuleStatusPane()); + + this.createTable().getColumnModel().getColumn(TableSequences.DesensitizationRuleStatus.getNum()).setMaxWidth(60); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + TableDataDesensitizationItem desensitizationItem = this.getList().get(rowIndex); + TableSequences match = TableSequences.match(columnIndex); + switch (match) { + case ColumnName: + // 选中的数据集字段名称 + return desensitizationItem.getColumnName(); + case DesensitizationRule: + // 脱敏规则名称 + return desensitizationItem.getRule().getRuleName(); + case DesensitizationRuleDescription: + // 脱敏规则详情 + return DesensitizationRule.getDescription(desensitizationItem.getRule()); + case EffectedRoles: + // 生效用户组 + return matchRoleNamesByIds(desensitizationItem.getRoleIds()); + case DesensitizationRuleStatus: + // 规则状态 + return needMarkRule(desensitizationItem.getRule()) ? StringUtils.EMPTY : Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status_Abnormal"); + default: + return StringUtils.EMPTY; + } + } + + /** + * 通过id匹配此用户组对应的部门职位名称(或者说自定义角色名称),并拼接成字符串返回 + * + * @param roleIds + * @return + */ + private String matchRoleNamesByIds(Collection roleIds) { + StringBuilder builder = new StringBuilder(); + for (String roleId : roleIds) { + if (roleMap != null && roleMap.containsKey(roleId)) { + builder.append(roleMap.get(roleId)); + builder.append(COMMA); + } + } + return builder.length() <= 1 ? StringUtils.EMPTY : builder.substring(0, builder.length() - 1); + } + + @Override + public boolean isCellEditable(int row, int col) { + TableSequences match = TableSequences.match(col); + return match != TableSequences.DesensitizationRuleStatus; + } + + @Override + public UITableEditAction[] createAction() { + return new UITableEditAction[]{ + new AddDesensitizationAction(), + new RemoveDesensitizationAction(parent), + new RefreshTableAction(), + }; + } + + /** + * 获取当前选中的item,可能为null + * + * @return + */ + @Nullable + private TableDataDesensitizationItem getCurrentSelectBean() { + return table.getSelectedRow() == -1 ? + null : + getList().get(table.getSelectedRow()); + } + + /** + * 列名选择下拉框 + */ + private class ColumnNamesComboBox extends AbstractCellEditor implements TableCellEditor { + + private UIComboBox columnNameComboBox; + + ColumnNamesComboBox() { + columnNameComboBox = new UIComboBox(columnNames.toArray(new String[0])); + this.addCellEditorListener(new CellEditorListener() { + @Override + public void editingStopped(ChangeEvent e) { + + TableDataDesensitizationItem desensitizationItem = getCurrentSelectBean(); + if (Objects.nonNull(desensitizationItem)) { + desensitizationItem.setColumnName(columnNames.get(columnNameComboBox.getSelectedIndex())); + fireTableDataChanged(); + } + } + + @Override + public void editingCanceled(ChangeEvent e) { + + } + }); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + columnNameComboBox.setSelectedItem(getList().get(row).getColumnName()); + return columnNameComboBox; + } + + @Override + public Object getCellEditorValue() { + Object selectedItem = columnNameComboBox.getSelectedItem(); + return Objects.isNull(selectedItem) ? StringUtils.EMPTY : selectedItem.toString(); + } + } + + private class DesensitizationRuleChooser extends AbstractCellEditor implements TableCellEditor { + /** + * 规则选择页面 + */ + private JPanel choosePane; + /** + * 规则名称 + */ + private UITextField ruleNameTextField; + /** + * 规则选择按钮 + */ + private UIButton chooseButton; + + private ActionListener chooseRuleListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // 重新获取一下本地规则缓存 + refreshCustomRuleCache(); + DesensitizationRulePane rulePane = new DesensitizationRulePane(latestRules); + TableDataDesensitizationItem desensitizationItem = getCurrentSelectBean(); + int selectedRow = table.getSelectedRow(); + BasicDialog ruleDialog = rulePane.showWindowWithCustomSize(SwingUtilities.getWindowAncestor(parent), new DialogActionAdapter() { + @Override + public void doOk() { + DesensitizationRule rule = rulePane.updateBean(); + if (Objects.nonNull(desensitizationItem) && DesensitizationRule.valid(rule)) { + desensitizationItem.setRule(rule); + desensitizationItem.setRuleName(rule.getRuleName()); + // 刷新规则名称、描述、状态 + ruleNameTextField.setText(rule.getRuleName()); + fireTableDataChanged(); + table.getSelectionModel().setSelectionInterval(selectedRow, selectedRow); + } + } + }, BasicDialog.DEFAULT); + ruleDialog.setVisible(true); + } + }; + + DesensitizationRuleChooser() { + // 规则名称展示 + ruleNameTextField = new UITextField(); + ruleNameTextField.setEnabled(false); + // 规则选择按钮 + chooseButton = new UIButton(APOSTROPHE); + chooseButton.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Click_To_Choose_Rule")); + chooseButton.addActionListener(chooseRuleListener); + // 规则选择页面 + Component[][] templateChooserComponent = {{ruleNameTextField, chooseButton}}; + double[] rowSize = {TableLayout.PREFERRED}; + double[] columnSize = {TableLayout.FILL, 22}; + choosePane = TableLayoutHelper.createCommonTableLayoutPane(templateChooserComponent, rowSize, columnSize, 0); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + ruleNameTextField.setText(getList().get(row).getRule().getRuleName()); + return choosePane; + } + + @Override + public Object getCellEditorValue() { + return ruleNameTextField.getText(); + } + } + + private class DesensitizationRuleDescriptionPane extends AbstractCellEditor implements TableCellEditor { + + private UILabel descriptionLabel; + + DesensitizationRuleDescriptionPane() { + // 规则描述 + this.descriptionLabel = new UILabel(); + } + + /** + * 根据脱敏规则信息,刷新下规则描述文字,主要用于与规则选择器的联动 + * + * @param desensitizationRule + */ + public void refreshDescription(DesensitizationRule desensitizationRule) { + this.descriptionLabel.setText(DesensitizationRule.getDescription(desensitizationRule)); + this.descriptionLabel.setToolTipText(this.descriptionLabel.getText()); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + refreshDescription(getList().get(row).getRule()); + return descriptionLabel; + } + + @Override + public Object getCellEditorValue() { + return this.descriptionLabel.getText(); + } + } + + /** + * 生效用户组复选框 + */ + private class EffectedRolesChooser extends AbstractCellEditor implements TableCellEditor { + + private UIComboCheckBox rolesCheckBox; + + EffectedRolesChooser() { + this.rolesCheckBox = new UIComboCheckBox(roleMap.values().toArray(), true) { + @Override + protected void setLayoutAndAddComponents() { + // 使用BorderLayout,否则默认使用的FlowLayout会让整个下拉选框使用最小Size,然后TableCell这边会出现空白 + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.add(getEditor(), BorderLayout.CENTER); + this.add(getArrowButton(), BorderLayout.EAST); + } + + @Override + protected void setEditorToolTipText(JComponent editor, String text) { + // 选项过多时,已选中的值会做省略显示处理,此处添加一个Tooltips,显示完整值 + if (text != null) { + editor.setToolTipText(text); + } + } + }; + this.addCellEditorListener(new CellEditorListener() { + @Override + public void editingStopped(ChangeEvent e) { + TableDataDesensitizationItem desensitizationItem = getCurrentSelectBean(); + if (Objects.nonNull(desensitizationItem)) { + desensitizationItem.setRoleIds(generateRolesIdsBySelectedValues()); + fireTableDataChanged(); + } + } + + @Override + public void editingCanceled(ChangeEvent e) { + + } + }); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + rolesCheckBox.setSelectedValues(generateRolesCheckBoxSelectedValues(getList().get(row))); + return rolesCheckBox; + } + + /** + * 根据当前的规则配置信息,生成选中的rolesMap用来展示 + * + * @param desensitizationItem + * @return + */ + private Map generateRolesCheckBoxSelectedValues(TableDataDesensitizationItem desensitizationItem) { + Map result = new HashMap<>(roleMap.size()); + for (Map.Entry roleEntry : roleMap.entrySet()) { + String roleId = roleEntry.getKey(); + String roleName = roleEntry.getValue(); + if (desensitizationItem.getRoleIds().contains(roleId)) { + result.put(roleName, true); + } else { + result.put(roleName, false); + } + } + return result; + } + + /** + * 根据当前的RoleName选择项,生成其对应的RoleId的set存入规则配置信息 + * + * @return + */ + private Set generateRolesIdsBySelectedValues() { + Set result = new LinkedHashSet<>(); + Object[] selectedValues = rolesCheckBox.getSelectedValues(); + for (Object selectedValue : selectedValues) { + String selectedRoleName = (String) selectedValue; + if (roleMap.containsValue(selectedRoleName)) { + Optional> matchedEntry = roleMap.entrySet().stream().filter(entry -> StringUtils.equals(entry.getValue(), selectedRoleName)).findFirst(); + matchedEntry.ifPresent(stringStringEntry -> result.add(stringStringEntry.getKey())); + } + } + return result; + } + + @Override + public Object getCellEditorValue() { + return rolesCheckBox.getSelectedValues(); + } + } + + /** + * 规则状态展示页面 + */ + private class DesensitizationRuleStatusPane extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { + + private UILabel ruleStatusLabel; + + DesensitizationRuleStatusPane() { + // 规则状态 + this.ruleStatusLabel = new UILabel(); + this.ruleStatusLabel.setForeground(Color.RED); + } + + /** + * 根据脱敏规则信息,刷新规则状态,主要用于与规则选择器的联动 + * + * @param currentItem + */ + public void refreshRuleStatus(TableDataDesensitizationItem currentItem) { + DesensitizationRule rule = currentItem.getRule(); + if (needMarkRule(rule)) { + // 非正常规则,根据规则状态展示不同提示文字 + DesensitizationRuleStatus ruleStatus = DesensitizationRuleManager.getInstance().getRuleStatus(rule, latestRules); + this.ruleStatusLabel.setText(Toolkit.i18nText("Fine-Design_Report_Desensitization_Rule_Status_Abnormal")); + this.ruleStatusLabel.setToolTipText(ruleStatus.getDescription()); + } else { + // 正常规则,重置提示Label + this.ruleStatusLabel.setText(StringUtils.EMPTY); + this.ruleStatusLabel.setToolTipText(null); + } + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + refreshRuleStatus(getList().get(row)); + return ruleStatusLabel; + } + + @Override + public Object getCellEditorValue() { + return ruleStatusLabel; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + refreshRuleStatus(getList().get(row)); + return ruleStatusLabel; + } + } + + private class AddDesensitizationAction extends AddTableRowAction { + + public AddDesensitizationAction() { + this.setName(Toolkit.i18nText("Fine-Design_Report_Desensitization_Add")); + this.setSmallIcon("/com/fr/design/standard/add/add_black", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + super.actionPerformed(e); + // 添加一条空白数据 + addRow(TableDataDesensitizationItem.createDefault()); + fireTableDataChanged(); + table.getSelectionModel().setSelectionInterval(table.getRowCount() - 1, table.getRowCount() - 1); + } + } + + private class RemoveDesensitizationAction extends DeleteAction { + + public RemoveDesensitizationAction(Component component) { + super(component); + this.setName(Toolkit.i18nText("Fine-Design_Basic_Base_Remove")); + this.setSmallIcon("/com/fr/design/standard/remove/remove_red", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + super.actionPerformed(e); + } + } + + private class RefreshTableAction extends UITableEditAction { + + public RefreshTableAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Refresh")); + this.setSmallIcon("/com/fr/design/standard/refresh/refresh", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 刷新TableData的规则,主要是为了自动替换掉平台中被修改的规则 + List items = getList(); + Iterator iterator = items.iterator(); + while (iterator.hasNext()) { + TableDataDesensitizationItem item = iterator.next(); + DesensitizationRuleStatus ruleStatus = DesensitizationRuleManager.getInstance().getRuleStatus(item.getRule(), latestRules); + if (ruleStatus == DesensitizationRuleStatus.REMOVED) { + // 规则被移除,则删除整条脱敏Item + iterator.remove(); + } else { + // 规则被修改、禁用等,更新一下规则 + item.setRule(DesensitizationRuleManager.getInstance().getLastedDesentizationRule(item.getRule(), latestRules)); + } + } + fireTableDataChanged(); + } + + @Override + public void checkEnabled() {} + } + + /** + * 规则表-列字段编号 + */ + private enum TableSequences { + + /** + * 数据集列名选择 + */ + ColumnName(0), + + /** + * 规则选择 + */ + DesensitizationRule(1), + + /** + * 规则描述 + */ + DesensitizationRuleDescription(2), + + /** + * 规则生效用户组 + */ + EffectedRoles(3), + + /** + * 规则状态 + */ + DesensitizationRuleStatus(4), + + /** + * 未知,用于无法匹配时的返回 + */ + Unknown(100); + + + private int num; + + TableSequences(int num) { + this.num = num; + } + + public int getNum() { + return num; + } + + /** + * 根据列序号匹配列字段 + * + * @param num + * @return + */ + public static TableSequences match(int num) { + for (TableSequences value : TableSequences.values()) { + if (value.getNum() == num) { + return value; + } + } + return Unknown; + } + } + + /** + * 是否需要对异常规则做标记,需要满足 + * 1. 规则非默认空规则 + * 2. 规则本身异常 + * + * @return + */ + private boolean needMarkRule(DesensitizationRule rule) { + return !rule.equals(DesensitizationRule.createDefaultEmptyRule()) && + DesensitizationRuleManager.getInstance().getRuleStatus(rule, latestRules) != DesensitizationRuleStatus.NORMAL; + } + + /** + * 刷新当前页面的本地规则缓存,查询最新本地规则的逻辑也是使用了缓存,因此无需考虑耗时 + */ + private void refreshCustomRuleCache() { + Map customRules = DesensitizationRuleManager.getInstance().getRulesBySource(DesensitizationRuleSource.CUSTOM); + latestRules.put(DesensitizationRuleSource.CUSTOM, customRules); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTablePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTablePane.java new file mode 100644 index 0000000000..6473a02d07 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/setting/TableDataDesensitizationTablePane.java @@ -0,0 +1,153 @@ +package com.fr.design.data.datapane.preview.desensitization.view.setting; + +import com.fr.base.operator.org.OrganizationOperator; +import com.fr.data.desensitize.base.DesensitizationTableData; +import com.fr.data.desensitize.base.TableDataDesensitizationItem; +import com.fr.data.desensitize.rule.DesensitizationRuleManager; +import com.fr.data.desensitize.rule.base.DesensitizationRule; +import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; +import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager; +import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; +import com.fr.design.gui.itableeditorpane.UITableEditorPane; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.log.FineLoggerFactory; +import com.fr.workspace.WorkContext; + +import javax.swing.JPanel; +import javax.swing.SwingWorker; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 脱敏字段设置页面中的Table + * + * @author Yvan + * @version 11.0 + * Created by Yvan on 2022/9/14 + */ +public class TableDataDesensitizationTablePane extends JPanel { + + /** + * 脱敏数据集 + */ + private DesensitizationTableData tableData; + + /** + * 父页面 + */ + private Component parent; + + /** + * 脱敏信息Table + */ + private UITableEditorPane editorPane; + + private static final String LOADING_PANE = "loading"; + private static final String CONTENT_PANE = "content"; + + private CardLayout card; + + private JPanel loadingPane; + + private JPanel contentPane; + + public TableDataDesensitizationTablePane(DesensitizationTableData tableData, Component parent) { + this.tableData = tableData; + this.parent = parent; + initComponent(); + } + + private void initComponent() { + + card = new CardLayout(); + this.setLayout(card); + // 初始化Loading面板 + loadingPane = new TipsPane(true); + this.add(LOADING_PANE, loadingPane); + switchTo(LOADING_PANE); + + // 在SwingWorker中初始化Content面板并切换 + initContent(); + } + + /** + * 初始化内容面板 + * 考虑到远程设计下的性能,需要限制查询数据库的次数,所以这里查一次,之后子面板内复用 + */ + private void initContent() { + final List columnNames = new ArrayList<>(); + final Map roleMap = new LinkedHashMap<>(); + final Map> latestRules = new LinkedHashMap<>(); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + // 获取当前数据集的所有列名 + columnNames.addAll(TableDataPreviewDesensitizeManager.getInstance().getColumnNamesByTableData(tableData)); + // 获取当前所有用户组 + roleMap.putAll(WorkContext.getCurrent().get(OrganizationOperator.class).getAllRoles4Desensitization()); + // 获取当前最新的所有规则 + latestRules.putAll(DesensitizationRuleManager.getInstance().getAllRules()); + return null; + } + + @Override + protected void done() { + contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + editorPane = new UITableEditorPane<>(new TableDataDesensitizationTableModel(tableData, parent, columnNames, roleMap, latestRules)); + editorPane.setHeaderResizing(false); + editorPane.populate(tableData.getDesensitizationConfig().getDesensitizationItems().toArray(new TableDataDesensitizationItem[0])); + contentPane.add(editorPane, BorderLayout.CENTER); + add(CONTENT_PANE, contentPane); + switchTo(CONTENT_PANE); + } + }.execute(); + } + + /** + * 切换面板 + * + * @param panelName + */ + public void switchTo(String panelName) { + try { + if (panelName != null) { + card.show(this, panelName); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + /** + * 展示此TableData中已配置的脱敏规则信息 + * + * @param tableData + */ + public void populateDesensitizationSetting(DesensitizationTableData tableData) { + this.tableData = tableData; + if (editorPane != null) { + // editorPane的初始化在SwingWorker中完成,这里做个判空 + editorPane.populate(tableData.getDesensitizationConfig().getDesensitizationItems().toArray(new TableDataDesensitizationItem[0])); + } + } + + /** + * 获取当前对TableData的配置脱敏规则信息 + */ + public List updateDesensitizationSetting() { + + return editorPane == null ? + new ArrayList<>() : + editorPane.update() + .stream() + .filter(item -> TableDataDesensitizationItem.valid(item)) + .collect(Collectors.toList()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java b/designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java new file mode 100644 index 0000000000..b82423fe71 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java @@ -0,0 +1,411 @@ +package com.fr.design.data.tabledata.paste; + +import com.fr.base.TableData; +import com.fr.base.chart.BaseChartCollection; +import com.fr.data.TableDataSource; +import com.fr.data.impl.storeproc.StoreProcedure; +import com.fr.design.DesignModelAdapter; +import com.fr.design.data.BasicTableDataTreePane; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.TableDataTreePane; +import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.ProcedureDataPane; +import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; +import com.fr.form.FormElementCaseProvider; +import com.fr.form.data.DataBinding; +import com.fr.form.data.DataTableConfig; +import com.fr.form.main.Form; +import com.fr.form.main.WidgetGather; +import com.fr.form.ui.DataControl; +import com.fr.form.ui.DictionaryContainer; +import com.fr.form.ui.ElementCaseEditor; +import com.fr.form.ui.Widget; +import com.fr.form.ui.concept.data.ValueInitializer; +import com.fr.log.FineLoggerFactory; +import com.fr.report.cell.FloatElement; +import com.fr.report.cell.tabledata.ElementUsedTableDataProvider; +import com.fr.report.worksheet.FormElementCase; +import com.fr.stable.StringUtils; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 数据集跟随复制粘贴的工具类 + * + * @author Yvan + */ +public class TableDataFollowingPasteUtils { + + private static final String UNDERLINE = "_"; + + /** + * 粘贴所有Map中的tabledata到当前模板 + * + * @param tableDataWrapperMap + */ + public static void paste(Map tableDataWrapperMap) { + if (tableDataWrapperMap == null) { + return; + } + // 获取当前的TableDataTreePane + DesignModelAdapter currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); + BasicTableDataTreePane tableDataTreePane = TableDataTreePane.getInstanceWithoutRefreshEverytime(currentModelAdapter); + // 粘贴(添加)数据集 + for (Map.Entry dataWrapperEntry : tableDataWrapperMap.entrySet()) { + String dsName = dataWrapperEntry.getKey(); + // 处理名称重复情况 + if (isDsNameRepeated(dsName)) { + continue; + } + AbstractTableDataWrapper tableDataWrapper = new TemplateTableDataWrapper(dataWrapperEntry.getValue(), dsName); + AbstractTableDataPane tableDataPane = generateTableDataPaneWhenPaste(tableDataWrapper); + if (tableDataPane != null) { + tableDataTreePane.addDataPane(tableDataPane, dsName); + } + } + } + + private static boolean isDsNameRepeated(String dsName) { + DesignModelAdapter currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter(); + String[] allDSNames = DesignTableDataManager.getAllDSNames(currentModelAdapter.getBook()); + return Arrays.stream(allDSNames).anyMatch(name -> StringUtils.equals(name, dsName)); + } + + /** + * 处理 ElementUsedTableDataProvider,从中获取数据集名称 - 数据集Wrapper 的Map + * + * @param providers + * @return + */ + public static Map transferProvider2TableDataMap(ElementUsedTableDataProvider... providers) { + if (providers == null) { + return new HashMap<>(); + } + // 获取当前的所有模板数据集 + Map templateTableData = getCurrentTemplateTableDataWrapperIncludingProcedure(); + Map tempMap = new HashMap<>(); + try { + for (ElementUsedTableDataProvider tableDataProvider : providers) { + Set usedTableDataNames = tableDataProvider.getElementUsedTableDataNames(); + for (String usedTableDataName : usedTableDataNames) { + if (templateTableData.containsKey(usedTableDataName)) { + tempMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData()); + } + } + } + return dealWithTableDataMap(tempMap); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("transfer widget tabledata failed", e); + } + return new HashMap<>(); + } + + /** + * 处理结果集 + * @param tableDataMap + * @return + */ + private static Map dealWithTableDataMap(Map tableDataMap) { + // 处理存储过程名称问题,名称问题需要优先处理,否则就找不到匹配的TableData了 + tableDataMap = dealWithStoreProcedure(tableDataMap); + // 对TableData做clone处理 + tableDataMap = dealWithTableData4Clone(tableDataMap); + return tableDataMap; + } + + /** + * 处理结果集,将结果集中的存储过程子表替换为原本的存储过程,否则跟随粘贴过去的存储过程名称有问题 + * + * @param tableDataMap + */ + private static Map dealWithStoreProcedure(Map tableDataMap) { + Map resultMap = new HashMap<>(); + if (tableDataMap == null) { + return resultMap; + } + for (Map.Entry result : tableDataMap.entrySet()) { + String tableDataName = result.getKey(); + TableData tableData = result.getValue(); + // 判断名称中存在"_"的 + if (tableDataName.contains(UNDERLINE)) { + String matchedName = matchTableDataName(tableDataName, tableData); + resultMap.put(matchedName, tableData); + } else { + resultMap.put(tableDataName, tableData); + } + } + return resultMap; + } + + /** + * 存储过程子表名称匹配其存储过程数据集名称,其余模板数据集名称不变 + * + * @param tableDataName 待匹配的数据集名称 + * @param tableData + * @return + */ + private static String matchTableDataName(String tableDataName, TableData tableData) { + if (tableDataName == null) { + return null; + } + // 获取不包括存储过程子表的所有TableDataMap + Map dataWrapperMap = getCurrentTemplateTableDataWrapper(); + // 名称匹配时,直接返回 + if (dataWrapperMap.containsKey(tableDataName)) { + return tableDataName; + } + // 名称不匹配时,判断TableData是否一致 + for (Map.Entry dataWrapperEntry : dataWrapperMap.entrySet()) { + String tdName = dataWrapperEntry.getKey(); + TableData td = dataWrapperEntry.getValue().getTableData(); + // 有些数据集的equals方法有问题,这里直接判断对象地址 + if (td == tableData) { + return tdName; + } + } + return tableDataName; + } + + + /** + * 提取控件内使用的数据集,转化成Map返回 + * + * @param widgets + * @return + */ + public static Map transferWidgetArray2TableDataMap(Widget... widgets) { + if (widgets == null) { + return new HashMap<>(); + } + // 获取当前的所有模板数据集 + Map templateTableData = getCurrentTemplateTableDataWrapperIncludingProcedure(); + Map tempMap = new HashMap<>(); + try { + for (Widget widget : widgets) { + // widget这个接口太大了,布局和子控件互相嵌套,所以只能分情况一个个收集 + collectTableDataInDictionary(templateTableData, tempMap, widget); + collectTableDataInWidgetValue(templateTableData, tempMap, widget); + collectTableDataInChartCollection(templateTableData, tempMap, widget); + collectTableDataInElementCaseEditor(templateTableData, tempMap, widget); + } + return dealWithTableDataMap(tempMap); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("transfer widget tabledata failed", e); + } + return new HashMap<>(); + } + + /** + * 对Map中所有的TableData做clone处理 + * @param tempMap + */ + private static Map dealWithTableData4Clone(Map tempMap) { + Map resultMap = new HashMap<>(); + for (Map.Entry entry : tempMap.entrySet()) { + String name = entry.getKey(); + TableData tableData = entry.getValue(); + TableData clonedTableData = cloneTableData(tableData); + if (clonedTableData != null) { + resultMap.put(name, clonedTableData); + } + } + return resultMap; + } + + /** + * 收集控件-报表块中使用的数据集 + * + * @param templateTableData + * @param tempMap + * @param widget + */ + private static void collectTableDataInElementCaseEditor(Map templateTableData, Map tempMap, Widget widget) { + Form.traversalWidget(widget, new WidgetGather() { + @Override + public void dealWith(Widget widget) { + ElementCaseEditor elementCaseEditor = (ElementCaseEditor) widget; + FormElementCaseProvider elementCase = elementCaseEditor.getElementCase(); + if (elementCase != null) { + // 普通单元格 + Iterator cellIterator = elementCase.cellIterator(); + while (cellIterator.hasNext()) { + ElementUsedTableDataProvider cellElement = (ElementUsedTableDataProvider) cellIterator.next(); + collectElement(cellElement); + } + // 悬浮元素 + Iterator floatIterator = ((FormElementCase) elementCase).floatIterator(); + while (floatIterator.hasNext()) { + ElementUsedTableDataProvider floatElement = floatIterator.next(); + collectElement(floatElement); + } + } + } + + private void collectElement(ElementUsedTableDataProvider provider) { + Set usedTableDataNames = provider.getElementUsedTableDataNames(); + for (String usedTableDataName : usedTableDataNames) { + if (templateTableData.containsKey(usedTableDataName)) { + tempMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData()); + } + } + } + + @Override + public boolean dealWithAllCards() { + return true; + } + }, ElementCaseEditor.class); + } + + /** + * 收集控件-图表中的TableData + * + * @param templateTableData + * @param tempMap + * @param widget + */ + private static void collectTableDataInChartCollection(Map templateTableData, Map tempMap, Widget widget) { + List chartCollections = widget.getChartCollections(); + for (BaseChartCollection chartCollection : chartCollections) { + Set dataSetNames = chartCollection.getDataSetNames(); + for (String dataSetName : dataSetNames) { + if (templateTableData.containsKey(dataSetName)) { + tempMap.put(dataSetName, templateTableData.get(dataSetName).getTableData()); + } + } + } + } + + /** + * 收集控件值中的TableData + * + * @param templateTableData + * @param tempMap + * @param widget + */ + private static void collectTableDataInWidgetValue(Map templateTableData, Map tempMap, Widget widget) { + Form.traversalWidget(widget, new WidgetGather() { + @Override + public void dealWith(Widget widget) { + if (((DataControl) widget).getWidgetValue() != null) { + ValueInitializer widgetValue = ((DataControl) widget).getWidgetValue(); + Object value = widgetValue.getValue(); + if (value instanceof DataBinding) { + String dataSourceName = ((DataBinding) value).getDataSourceName(); + if (templateTableData.containsKey(dataSourceName)) { + tempMap.put(dataSourceName, templateTableData.get(dataSourceName).getTableData()); + } + } + if (value instanceof DataTableConfig) { + String tableDataName = ((DataTableConfig) value).getTableDataName(); + if (templateTableData.containsKey(tableDataName)) { + tempMap.put(tableDataName, templateTableData.get(tableDataName).getTableData()); + } + } + } + } + + @Override + public boolean dealWithAllCards() { + return true; + } + }, DataControl.class); + + } + + /** + * 收集控件-数据字典中的TableData + * + * @param templateTableData + * @param tempMap + * @param widget + */ + private static void collectTableDataInDictionary(Map templateTableData, Map tempMap, Widget widget) { + Form.traversalWidget(widget, new WidgetGather() { + @Override + public void dealWith(Widget widget) { + Set usedTableDataSets = ((DictionaryContainer) widget).getUsedTableDataSets(); + for (String usedTableDataSet : usedTableDataSets) { + if (templateTableData.containsKey(usedTableDataSet)) { + tempMap.put(usedTableDataSet, templateTableData.get(usedTableDataSet).getTableData()); + } + } + } + + @Override + public boolean dealWithAllCards() { + return true; + } + }, DictionaryContainer.class); + } + + /** + * 获取当前所有的模板数据集,包括存储过程 + * + * @return + */ + private static Map getCurrentTemplateTableDataWrapperIncludingProcedure() { + Map templateTableDataWrapper = getCurrentTemplateTableDataWrapper(); + // 处理存储过程 + Map dataWrapperMap = DesignTableDataManager.getAllDataSetIncludingProcedure(templateTableDataWrapper); + return dataWrapperMap; + } + + /** + * 获取当前所有的模板数据集,不包括存储过程 + * + * @return + */ + private static Map getCurrentTemplateTableDataWrapper() { + TableDataSource tableDataSource = DesignTableDataManager.getEditingTableDataSource(); + List> editingDataSet = DesignTableDataManager.getEditingDataSet(tableDataSource); + Map templeteDataSet = editingDataSet.get(0); + return templeteDataSet; + } + + /** + * 生成粘贴(新建)时使用的AbstractTableDataPane + * 主要是为了处理StoreProcedure,它在远程情况下,无法及时获取参数。这边因为是复制粘贴,所以直接用原TableData的参数即可 + * @param tableDataWrapper wrapper + * @return AbstractTableDataPane,当TableData clone失败时,方法返回null + */ + @Nullable + public static AbstractTableDataPane generateTableDataPaneWhenPaste(AbstractTableDataWrapper tableDataWrapper) { + // 粘贴时再做一次TableData的clone + TableData clonedTableData = cloneTableData(tableDataWrapper.getTableData()); + if (clonedTableData == null) { + return null; + } + AbstractTableDataWrapper clonedWrapper = new TemplateTableDataWrapper(clonedTableData); + AbstractTableDataPane tableDataPane = clonedWrapper.creatTableDataPane(); + TableData tableData = clonedWrapper.getTableData(); + if (tableData instanceof StoreProcedure) { + StoreProcedure storeProcedure = (StoreProcedure) tableData; + ((ProcedureDataPane) tableDataPane).populateParameters(storeProcedure.getParameters()); + } + return tableDataPane; + } + + /** + * clone数据源,如果失败,打印日志,并返回null,谨慎使用 + * @param tableData + * @return + */ + @Nullable + public static TableData cloneTableData(TableData tableData) { + try { + return (TableData) tableData.clone(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, "clone table data {} failed", tableData.getName()); + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java index 173da2fbf7..d0ffd7f22c 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java @@ -20,6 +20,8 @@ import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane; import com.fr.design.data.datapane.sqlpane.SQLEditPane; import com.fr.design.data.tabledata.strategy.StrategyConfigHandler; import com.fr.design.data.tabledata.tabledatapane.db.StrategyConfigFrom; +import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; @@ -36,6 +38,7 @@ import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; import com.fr.design.gui.syntax.ui.rtextarea.RTextScrollPane; import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; @@ -66,9 +69,11 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JToolBar; +import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import java.awt.BorderLayout; +import java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; @@ -85,7 +90,7 @@ import java.util.List; * @version 10.0 * Created by rinoux on 2020/7/22 */ -public class DBTableDataPane extends AbstractTableDataPane { +public class DBTableDataPane extends AbstractTableDataPane implements SwitchableTableDataPane { private static final int BOTTOM = 6; private static final String PREVIEW_BUTTON = Toolkit.i18nText("Fine-Design_Basic_Preview"); @@ -108,14 +113,42 @@ public class DBTableDataPane extends AbstractTableDataPane { private StrategyConfigHandler configHandler; + private CardLayout card; + /** 数据库查询面板真正的内容面板 */ + private JPanel contentPane; + /** 加载中面板 */ + private JPanel loadingPane; public DBTableDataPane() { + initCards(); + initContentPane(); + } + + /** + * 初始化内容面板 + */ + protected void initContentPane() { init(); initMainSplitPane(); } + /** + * 初始化cardLayout以及LoadingPane等,并且布局切到LoadingPane + */ + protected void initCards() { + card = new CardLayout(); + setLayout(card); + + loadingPane = new TipsPane(true); + contentPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + + add(LOADING_PANE_NAME, loadingPane); + add(CONTENT_PANE_NAME, contentPane); + switchTo(LOADING_PANE_NAME); + } + private void init() { - setLayout(new BorderLayout(4, 4)); + contentPane.setLayout(new BorderLayout(4, 4)); this.sqlTextPane = new SQLEditPane(); this.sqlTextPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL); @@ -129,7 +162,7 @@ public class DBTableDataPane extends AbstractTableDataPane { editorPane = new UITableEditorPane<>(model); - this.connectionTableProcedurePane = new ConnectionTableProcedurePane() { + this.connectionTableProcedurePane = new ConnectionTableProcedurePane(this) { @Override protected void filter(Connection connection, String conName, List nameList) { connection.addConnection(nameList, conName, new Class[]{ @@ -230,7 +263,21 @@ public class DBTableDataPane extends AbstractTableDataPane { JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.connectionTableProcedurePane, sqlSplitPane); mainSplitPane.setBorder(BorderFactory.createLineBorder(GUICoreUtils.getTitleLineBorderColor())); mainSplitPane.setOneTouchExpandable(true); - add(mainSplitPane, BorderLayout.CENTER); + contentPane.add(mainSplitPane, BorderLayout.CENTER); + } + + @Override + public void switchTo(String panelName) { + try { + if (panelName != null) { + card.show(this, panelName); + } + } catch (IllegalArgumentException ingore) { + // 有些直接继承此面板或者替换掉此面板的插件,在未适配此功能时会出现报错,因为不是CardLayout,无法切换,这里处理下 + FineLoggerFactory.getLogger().info("cannot switch pane by {}", this.getClass().getName()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } } private boolean isPreviewOrRefreshButton(FocusEvent e) { @@ -303,7 +350,7 @@ public class DBTableDataPane extends AbstractTableDataPane { //显示对应的配置 strategyConfigPane.populateBean(populateStrategyConfig); - BasicDialog dlg = strategyConfigPane.showMediumWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + BasicDialog dlg = strategyConfigPane.showMediumWindow(SwingUtilities.getWindowAncestor(DBTableDataPane.this), new DialogActionAdapter() { @Override public void doOk() { super.doOk(); @@ -314,7 +361,7 @@ public class DBTableDataPane extends AbstractTableDataPane { } } }); - dlg.setAlwaysOnTop(true); + //dlg.setAlwaysOnTop(true); dlg.setVisible(true); } }); @@ -715,8 +762,8 @@ public class DBTableDataPane extends AbstractTableDataPane { if (useGlobal(getTableData(), strategyConfig)) { //使用全局配置 strategyConfig = StrategyConfigHelper.createStrategyConfig(true); - } else if (getTableData().isShare()) { - //使用共享数据集兼容配置 + } else if (strategyConfig == null && getTableData().isShare()) { + //没有配置时,使用共享数据集兼容配置 strategyConfig = StrategyConfigHelper.createStrategyConfig(true, false, true); } } diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/EmbeddedTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/EmbeddedTableDataPane.java index 8b47b222d6..731816243e 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/EmbeddedTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/EmbeddedTableDataPane.java @@ -65,6 +65,9 @@ public class EmbeddedTableDataPane extends AbstractTableDataPane imp } + /** + * 手动更新参数,用于上面populateBean方法中SwingWorker查询来不及的情况 + * @param procedureParameters + */ + public void populateParameters(StoreProcedureParameter[] procedureParameters) { + this.editorPane.populate(procedureParameters); + } + /** * 增加存储过程监听器 * @@ -282,8 +290,8 @@ public class ProcedureDataPane extends AbstractTableDataPane imp protected Void doInBackground() throws Exception { DesignTableDataManager.setThreadLocal(DesignTableDataManager.NO_PARAMETER); sp.setCalculating(true); - ProcedureDataModel[] dataModels = DesignTableDataManager.createLazyDataModel(sp, false); - sp.refreshDataModelListAndResultNames(dataModels); + ProcedureDataModel[] dataModels = (ProcedureDataModel[]) DesignTableDataManager.createLazyDataModel(sp, false); + sp.refreshResults(dataModels); return null; } @@ -374,8 +382,8 @@ public class ProcedureDataPane extends AbstractTableDataPane imp @Override public void actionPerformed(ActionEvent evt) { StoreProcedure sp = updateBeanWithOutExecute(); - StoreProcedureDataWrapper storeProcedureDataWrapper = new StoreProcedureDataWrapper(this.procedureDataPane, sp, StringUtils.EMPTY, queryText.getText()); - storeProcedureDataWrapper.previewData(StoreProcedureDataWrapper.PREVIEW_ALL); + MultiResultTableDataWrapper wrapper = new MultiResultTableDataWrapper(this.procedureDataPane, sp, StringUtils.EMPTY, queryText.getText()); + wrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL); } } diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java new file mode 100644 index 0000000000..221ee1cbba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java @@ -0,0 +1,23 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + + + +/** + * 可切换的DBTableData对应的数据集面板,需要使用CardLayout布局 + * 主要是给插件适配用的 + * @author Yvan + */ +public interface SwitchableTableDataPane { + + /** Loading面板 */ + String LOADING_PANE_NAME = "Loading"; + /** 内容面板 */ + String CONTENT_PANE_NAME = "Content"; + + /** + * 根据面板名称切换面板 + * @param paneName 面板名称 + */ + void switchTo(String paneName); + +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java new file mode 100644 index 0000000000..c3f12c3e7f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java @@ -0,0 +1,54 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + +import com.fr.design.dialog.BasicPane; +import com.fr.design.i18n.Toolkit; + +import javax.swing.JPanel; +import java.awt.CardLayout; + +/** + * @author Yvan + */ +public class TableDataLoadingPane extends BasicPane { + + /** Loading面板 */ + public static final String LOADING_PANE_NAME = "Loading"; + /** 无权限提示面板 */ + public static final String NO_AUTH_PANE_NAME = "NoAuthority"; + /** 错误提示面板 */ + public static final String ERROR_NAME = "Error"; + + private CardLayout card; + + /** 加载中面板 */ + private JPanel loadingPane; + /** 错误提示面板 */ + private JPanel errorPane; + /** 数据连接无权限面板 */ + private JPanel noAuthorityPane; + + public TableDataLoadingPane() { + initPanes(); + } + + private void initPanes() { + card = new CardLayout(); + this.setLayout(card); + loadingPane = new TipsPane(true); + errorPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Error")); + noAuthorityPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_No_Auth")); + add(LOADING_PANE_NAME, loadingPane); + add(NO_AUTH_PANE_NAME, noAuthorityPane); + add(ERROR_NAME, errorPane); + switchTo(LOADING_PANE_NAME); + } + + public void switchTo(String panelName) { + card.show(this, panelName); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java new file mode 100644 index 0000000000..40fcb6ef28 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java @@ -0,0 +1,45 @@ +package com.fr.design.data.tabledata.tabledatapane.loading; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; + +/** + * 提示面板,支持自定义提示,支持进度条配置可选 + * @author Yvan + */ +public class TipsPane extends JPanel { + + /** + * 默认提示 + */ + private static final String LOADING = Toolkit.i18nText("Fine-Design_Basic_Loading_And_Waiting"); + + public TipsPane () { + this(LOADING, false); + } + + public TipsPane (String tip) { + this(tip, false); + } + + public TipsPane (boolean needProgressBar) { + this(LOADING, needProgressBar); + } + + public TipsPane (String tips, boolean needProgressBar) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + UILabel tipsLabel = new UILabel(tips, SwingConstants.CENTER); + this.add(tipsLabel, BorderLayout.CENTER); + if (needProgressBar) { + JProgressBar progressBar = new JProgressBar(); + progressBar.setIndeterminate(true); + this.add(progressBar, BorderLayout.SOUTH); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataNameWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataNameWrapper.java new file mode 100644 index 0000000000..97bf701a62 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataNameWrapper.java @@ -0,0 +1,143 @@ +package com.fr.design.data.tabledata.wrapper; + +import com.fr.base.TableData; +import com.fr.data.MultiResultTableData; +import com.fr.data.impl.NameDataModel; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.log.FineLoggerFactory; +import com.fr.workspace.WorkContext; + +import javax.swing.Icon; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +/** + * 多结果数据集-结果包装 + * + * @author rinoux + * @version 11.0 + * Created by rinoux on 2022/8/12 + */ +public final class MultiResultTableDataNameWrapper implements TableDataWrapper { + private NameDataModel dataModel; + private final String name; + private final MultiResultTableData tableData; + private List childrenList; + + /** + * @param name 数据集名字 + * @param tableData 数据集 + */ + public MultiResultTableDataNameWrapper(String name, MultiResultTableData tableData) { + this.name = name; + this.tableData = tableData; + } + + /** + * 生成子节点 + * + * @return 子节点 + */ + public ExpandMutableTreeNode[] load() { + // 生成多数据集结果子节点 + List namelist = calculateColumnNameList(); + ExpandMutableTreeNode[] res = new ExpandMutableTreeNode[namelist.size()]; + for (int i = 0; i < res.length; i++) { + res[i] = new ExpandMutableTreeNode(namelist.get(i)); + } + + return res; + } + + @Override + public String getTableDataName() { + return name; + } + + @Override + public TableData getTableData() { + return tableData; + } + + @Override + public Icon getIcon() { + return MultiResultTableDataWrapperHelper.getIcon(this.tableData.getClass()); + } + + private void createResult(boolean needLoadingBar) { + try { + // todo 啥意思? + dataModel = DesignTableDataManager.createLazyDataModel(tableData, needLoadingBar)[0]; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + /** + * 数据集执行结果返回的所有字段 + *

+ * TODO:要不要加上Exception呢?个人感觉很有必要 + * + * @return 字段 + */ + public List calculateColumnNameList() { + if (childrenList != null) { + return childrenList; + } + childrenList = new ArrayList<>(); + if (!WorkContext.getCurrent().isLocal()) { + try { + createResult(false); + childrenList = Arrays.asList(dataModel.getColumnNames()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + } else { + if (dataModel == null) { + createResult(false); + } + if (dataModel != null) { + childrenList = Arrays.asList(dataModel.getColumnNames()); + } + } + return childrenList; + } + + /** + * 预览数据集 + */ + public void previewData() { + if (dataModel == null) { + createResult(true); + } + PreviewTablePane.previewDataModel(dataModel); + + } + + /** + * 预览数据集,带有显示值和实际值的标记结果 + * + * @param keyIndex 显示值Index + * @param valueIndex 实际值index + */ + public void previewData(int keyIndex, int valueIndex) { + if (dataModel == null) { + createResult(true); + } + PreviewTablePane.previewDataModel(dataModel, keyIndex, valueIndex); + } + + /** + * 是否异常 + * + * @return 异常返回true + */ + public boolean isUnusual() { + return false; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java new file mode 100644 index 0000000000..c72baf4356 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java @@ -0,0 +1,327 @@ +package com.fr.design.data.tabledata.wrapper; + +import com.fr.base.TableData; +import com.fr.data.MultiResultTableData; +import com.fr.data.impl.NameDataModel; +import com.fr.data.impl.storeproc.StoreProcedure; +import com.fr.data.operator.DataOperator; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.datapane.preview.PreviewTablePane; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.iprogressbar.AutoProgressBar; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; + +import javax.swing.Icon; +import javax.swing.JFrame; +import javax.swing.SwingWorker; +import java.awt.Component; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CancellationException; + +/** + * 多结果数据集包装 + * + * @author rinoux + * @version 11.0 + * Created by rinoux on 2022/8/12 + */ +public final class MultiResultTableDataWrapper implements TableDataWrapper { + public static final int PREVIEW_ALL = 0; + public static final int PREVIEW_ONE = 1; + public static AutoProgressBar loadingBar; + + private NameDataModel dataModel; + private final String dataModelName; + private final String tableDataName; + private final MultiResultTableData tableData; + private List columnNameList; + private AutoProgressBar connectionBar; + private NameDataModel[] dataModels; + private SwingWorker worker; + private int previewModel; + + /** + * @param tableData 数据集 + * @param tableDataName 数据集名称 + * @param dataModelName 数据集的一个结果的名称(全限定名称) + */ + public MultiResultTableDataWrapper(MultiResultTableData tableData, String tableDataName, String dataModelName) { + this(null, tableData, tableDataName, dataModelName, true); + } + + /** + * @param tableData 数据集 + * @param tableDataName 数据集名称 + * @param dataModelName 数据集的一个结果的名称(全限定名称) + * @param needLoad 是否需要加载 + */ + public MultiResultTableDataWrapper(MultiResultTableData tableData, String tableDataName, String dataModelName, boolean needLoad) { + this(null, tableData, tableDataName, dataModelName, needLoad); + } + + /** + * @param component 父容器 + * @param tableData 数据集 + * @param tableDataName 数据集名称 + * @param dataModelName 数据集的一个结果的名称(全限定名称) + */ + public MultiResultTableDataWrapper(Component component, MultiResultTableData tableData, String tableDataName, String dataModelName) { + this(component, tableData, tableDataName, dataModelName, true); + } + + /** + * @param component loadingBar的父弹框(如果不设置父弹框的话,可能出现loadingBar隐藏在一个弹框后的情况) + * @param tableData 多结果数据集 + * @param tableDataName 多结果数据集的名字(某些情况下可以为空) + * @param dataModelName 多结果数据集一个返回数据集的名字 + * @param needLoad 是否要加载 + **/ + public MultiResultTableDataWrapper(Component component, MultiResultTableData tableData, String tableDataName, String dataModelName, boolean needLoad) { + this.dataModelName = dataModelName; + this.tableData = tableData; + this.tableDataName = tableDataName; + if (component == null) { + component = new JFrame(); + } + if (needLoad) { + setWorker(component); + } + loadingBar = new AutoProgressBar(component, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) { + @Override + public void doMonitorCanceled() { + getWorker().cancel(true); + } + }; + } + + /** + * 数据集执行结果返回的所有字段 + * + * @return 数据集执行结果返回的所有字段 + * @date 2014-12-3-下午7:43:17 + */ + @Override + public List calculateColumnNameList() { + if (columnNameList != null) { + return columnNameList; + } + + try { + createResults(false); + } catch (Exception e) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Engine_No_TableData")); + return new ArrayList(); + } + columnNameList = Arrays.asList(dataModel.getColumnNames()); + return columnNameList; + } + + /** + * 生成子节点 + * + * @return 节点数组 + * @date 2014-12-3-下午7:06:47 + */ + @Override + public ExpandMutableTreeNode[] load() { + List namelist; + if (tableData.isCalculating()) { + namelist = Arrays.asList(new String[0]); + } else { + namelist = calculateColumnNameList(); + } + ExpandMutableTreeNode[] res = new ExpandMutableTreeNode[namelist.size()]; + for (int i = 0; i < res.length; i++) { + res[i] = new ExpandMutableTreeNode(namelist.get(i)); + } + + return res; + } + + private void createResults(boolean needLoadingBar) throws Exception { + + this.dataModel = null; + dataModels = DesignTableDataManager.createLazyDataModel(tableData, needLoadingBar); + if (dataModels != null && dataModels.length != 0) { + for (NameDataModel dataModel : dataModels) { + if (ComparatorUtils.equals(this.dataModelName, tableDataName + MultiResultTableData.GROUP_MARKER + dataModel.getName())) { + this.dataModel = dataModel; + break; + } + } + } + } + + @Override + public Icon getIcon() { + return MultiResultTableDataWrapperHelper.getIcon(this.tableData.getClass()); + } + + /** + * 预览数据 + * + * @param previewModel 预览模式, 全部还是一个 + * @date 2014-12-3-下午7:05:50 + */ + public void previewData(final int previewModel) { + this.previewModel = previewModel; + connectionBar = new AutoProgressBar(new JFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) { + @Override + public void doMonitorCanceled() { + connectionBar.close(); + worker.cancel(true); + } + }; + worker.execute(); + } + + private void setWorker(final Component parent) { + worker = new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + loadingBar.close(); + PreviewTablePane.resetPreviewTable(); + + // 存储过程需要先测试一下连接 + if (tableData instanceof StoreProcedure) { + try { + connectionBar.start(); + boolean success = DataOperator.getInstance().testConnection(((StoreProcedure) getTableData()).getDatabaseConnection()); + if (!success) { + throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed")); + } + } finally { + connectionBar.close(); + } + } + + tableData.resetDataModelList(); + + // 获取结果 + createResults(true); + return null; + } + + @Override + public void done() { + try { + get(); + loadingBar.close(); + switch (previewModel) { + case MultiResultTableDataWrapper.PREVIEW_ALL: + PreviewTablePane.previewMultiDataModels(dataModels); + break; + case MultiResultTableDataWrapper.PREVIEW_ONE: + previewData(); + break; + default: + break; + } + } catch (Exception e) { + loadingBar.close(); + if (!(e instanceof CancellationException)) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineJOptionPane.showMessageDialog(parent, e.getMessage()); + } + } + } + }; + } + + private SwingWorker getWorker() { + return this.worker; + } + + // august:这个只是预览返回的一个数据集 + + /** + * 预览返回的一个数据集 + * + * @date 2014-12-3-下午7:42:53 + */ + @Override + public void previewData() { + previewData(-1, -1); + } + + // august:这个只是预览返回的一个数据集 + + /** + * 预览返回的一个数据集,带有显示值和实际值的标记结果 + * + * @param keyIndex 实际值 + * @param valueIndex 显示值 + * @date 2014-12-3-下午7:42:27 + */ + @Override + public void previewData(final int keyIndex, final int valueIndex) { + PreviewTablePane.previewDataModel(dataModel, keyIndex, valueIndex); + } + + + /** + * 预览返回的所有数据集,只有在编辑多结果数据集时才用到 + */ + public void previewAllTable() { + if (dataModel == null) { + try { + createResults(true); + } catch (Exception e) { + return; + } + } + PreviewTablePane.previewMultiDataModels(dataModels); + } + + @Override + public String getTableDataName() { + // todo 这里返回数据集结果名称,带_的 + return dataModelName; + } + + public String getDataModelName() { + return dataModelName; + } + + @Override + public TableData getTableData() { + return tableData; + } + + + /** + * 获取当前节点所属可编辑的数据集名称 + * + * @return + */ + public String getMultiResultTableDataName() { + return tableDataName; + } + + /** + * 是否异常 + * + * @return 是否异常 + */ + @Override + public boolean isUnusual() { + return false; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof MultiResultTableDataWrapper + && ComparatorUtils.equals(this.getDataModelName(), ((MultiResultTableDataWrapper) obj).getDataModelName()) + && ComparatorUtils.equals(this.getTableData(), ((MultiResultTableDataWrapper) obj).getTableData()) + && ComparatorUtils.equals(this.getMultiResultTableDataName(), ((MultiResultTableDataWrapper) obj).getMultiResultTableDataName()) + && ComparatorUtils.equals(this.getTableDataName(), ((MultiResultTableDataWrapper) obj).getTableDataName()); + + } + +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapperHelper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapperHelper.java new file mode 100644 index 0000000000..45211c095f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapperHelper.java @@ -0,0 +1,54 @@ +package com.fr.design.data.tabledata.wrapper; + +import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; +import com.fr.design.data.datapane.TableDataCreatorProducer; +import com.fr.design.data.datapane.TableDataNameObjectCreator; +import com.fr.design.fun.ServerTableDataDefineProvider; +import com.fr.design.fun.TableDataDefineProvider; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.observer.PluginEventType; +import com.fr.stable.Filter; +import org.jetbrains.annotations.NotNull; + +import javax.swing.Icon; +import java.util.HashMap; +import java.util.Map; + +/** + * @author rinoux + * @version 11.0 + * Created by rinoux on 2022/9/7 + */ +class MultiResultTableDataWrapperHelper { + private static final Map, Icon> TABLE_DATA_ICON_PATHS = new HashMap<>(); + private static final String DEFAULT_MULTI_RESULT_TD_ICON = "/com/fr/design/standard/multi"; + + + static { + Listener listener = new Listener() { + @Override + public void on(Event event, PluginContext param) { + TABLE_DATA_ICON_PATHS.clear(); + } + }; + Filter filter = pluginContext -> pluginContext.contain(TableDataDefineProvider.XML_TAG) || pluginContext.contain(ServerTableDataDefineProvider.XML_TAG); + EventDispatcher.listen(PluginEventType.AfterRun, listener, filter); + EventDispatcher.listen(PluginEventType.BeforeStop, listener, filter); + } + + + public static @NotNull Icon getIcon(@NotNull Class tableDataClass) { + return TABLE_DATA_ICON_PATHS.computeIfAbsent(tableDataClass, cls -> { + for (TableDataNameObjectCreator creator : TableDataCreatorProducer.getInstance().createReportTableDataCreator()) { + if (creator.createObject().getClass().isAssignableFrom(tableDataClass)) { + return IconUtils.readIcon(creator.getIconPath()); + } + } + return IconUtils.readIcon(DEFAULT_MULTI_RESULT_TD_ICON); + }); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/ServerTableDataWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/ServerTableDataWrapper.java index c309e1fde4..cf66d9700e 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/ServerTableDataWrapper.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/ServerTableDataWrapper.java @@ -2,6 +2,8 @@ package com.fr.design.data.tabledata.wrapper; import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; +import com.fr.base.svg.SVGLoader; import com.fr.data.impl.ClassTableData; import com.fr.data.impl.DBTableData; import com.fr.data.impl.EmbeddedTableData; @@ -24,20 +26,22 @@ public final class ServerTableDataWrapper extends AbstractTableDataWrapper { @Override public Icon getIcon() { if (tabledata instanceof DBTableData) { - if (StringUtils.isBlank(((DBTableData) tabledata).getQuery())) - return new WarningIcon(BaseUtils.readImage("/com/fr/design/images/data/dock/serverdatabase.png")); - else - return BaseUtils.readIcon("/com/fr/design/images/data/dock/serverdatabase.png"); + if (StringUtils.isBlank(((DBTableData) tabledata).getQuery())) { + return new WarningIcon(SVGLoader.load("/com/fr/design/standard/server_database_normal.svg")); + } + else { + return IconUtils.readIcon("/com/fr/design/standard/server_database"); + } } else if (tabledata instanceof ClassTableData) { - return BaseUtils.readIcon("/com/fr/design/images/data/dock/serverclasstabledata.png"); + return IconUtils.readIcon("/com/fr/design/standard/class_table_data"); } else if (tabledata instanceof EmbeddedTableData) { - return BaseUtils.readIcon("/com/fr/design/images/data/dock/serverdatatable.png"); + return IconUtils.readIcon("/com/fr/design/standard/data_table"); }else if(tabledata instanceof RecursionTableData){ - return BaseUtils.readIcon("/com/fr/design/images/data/tree.png"); + return IconUtils.readIcon("/com/fr/design/standard/tree"); } else if (tabledata instanceof StoreProcedure) { - return BaseUtils.readIcon("/com/fr/design/images/data/store_procedure.png"); + return IconUtils.readIcon("/com/fr/design/standard/store_procedure"); } - return BaseUtils.readIcon("/com/fr/design/images/data/dock/serverdatabase.png"); + return IconUtils.readIcon("/com/fr/design/standard/server_database"); } /** diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java index 08274fd71d..6c9af4827f 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java @@ -1,7 +1,7 @@ package com.fr.design.data.tabledata.wrapper; -import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; import com.fr.data.impl.storeproc.ProcedureDataModel; import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.data.operator.DataOperator; @@ -36,7 +36,9 @@ import java.util.concurrent.CancellationException; * * @author zhou * @since 2012-4-12上午10:29:15 + * @deprecated 请勿使用,见{@link MultiResultTableDataWrapper} */ +@Deprecated public final class StoreProcedureDataWrapper implements TableDataWrapper { public static final int PREVIEW_ALL = 0; public static final int PREVIEW_ONE = 1; @@ -63,26 +65,27 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName) { this(component, storeProcedure, storeprocedureName, dsName, true); } - + /** - * @param: component loadingBar的父弹框(如果不设置父弹框的话,可能出现loadingBar隐藏在一个弹框后的情况) - * @param: storeProcedure 存储过程 - * @param: storeprocedureName 存储过程的名字(某些情况下可以为空) - * @param: dsName 存储过程一个返回数据集的名字 - * @param: needLoad 是否要加载 + * @param component loadingBar的父弹框(如果不设置父弹框的话,可能出现loadingBar隐藏在一个弹框后的情况) + * @param storeProcedure 存储过程 + * @param storeprocedureName 存储过程的名字(某些情况下可以为空) + * @param dsName 存储过程一个返回数据集的名字 + * @param needLoad 是否要加载 **/ public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName, boolean needLoad) { this.dsName = dsName; this.storeProcedure = storeProcedure; - this.storeProcedure.setCalculating(false); + /*this.storeProcedure.setCalculating(false);*/ this.storeprocedureName = storeprocedureName; - if (needLoad) { - setWorker(); - } if (component == null) { component = new JFrame(); } + if (needLoad) { + setWorker(component); + } loadingBar = new AutoProgressBar(component, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) { + @Override public void doMonitorCanceled() { getWorker().cancel(true); } @@ -93,16 +96,17 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * 数据集执行结果返回的所有字段 * * @return 数据集执行结果返回的所有字段 - * - * - * @date 2014-12-3-下午7:43:17 - * - */ + * @date 2014-12-3-下午7:43:17 + */ + @Override public List calculateColumnNameList() { if (columnNameList != null) { return columnNameList; } - if (!createStore(false)) { + + try { + createStore(false); + } catch (Exception e) { FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Engine_No_TableData")); return new ArrayList(); } @@ -114,11 +118,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * 生成子节点 * * @return 节点数组 - * - * - * @date 2014-12-3-下午7:06:47 - * - */ + * @date 2014-12-3-下午7:06:47 + */ + @Override public ExpandMutableTreeNode[] load() { List namelist; if (storeProcedure.isCalculating()) { @@ -134,42 +136,33 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return res; } - private boolean createStore(boolean needLoadingBar) { - try { - dataModels = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar); - if (dataModels == null || dataModels.length == 0) { - return false; - } - for (int i = 0; i < dataModels.length; i++) { - if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModels[i].getName())) { - procedureDataModel = dataModels[i]; + private void createStore(boolean needLoadingBar) throws Exception { + dataModels = (ProcedureDataModel[]) DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar); + if (dataModels != null && dataModels.length != 0) { + for (ProcedureDataModel dataModel : dataModels) { + if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModel.getName())) { + procedureDataModel = dataModel; break; } } - return true; - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); } - return false; } @Override public Icon getIcon() { - return BaseUtils.readIcon("/com/fr/design/images/data/store_procedure.png"); + return IconUtils.readIcon("/com/fr/design/standard/store_procedure"); } /** - * 预览数据 - * - * @param previewModel 预览模式, 全部还是一个 - * - * - * @date 2014-12-3-下午7:05:50 - * - */ + * 预览数据 + * + * @param previewModel 预览模式, 全部还是一个 + * @date 2014-12-3-下午7:05:50 + */ public void previewData(final int previewModel) { this.previewModel = previewModel; connectionBar = new AutoProgressBar(new JFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) { + @Override public void doMonitorCanceled() { connectionBar.close(); worker.cancel(true); @@ -178,8 +171,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { worker.execute(); } - private void setWorker() { + private void setWorker(final Component parent) { worker = new SwingWorker() { + @Override protected Void doInBackground() throws Exception { loadingBar.close(); PreviewTablePane.resetPreviewTable(); @@ -195,6 +189,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return null; } + @Override public void done() { try { get(); @@ -206,13 +201,15 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { case StoreProcedureDataWrapper.PREVIEW_ONE: previewData(); break; + default: + break; } } catch (Exception e) { + loadingBar.close(); if (!(e instanceof CancellationException)) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage()); + FineJOptionPane.showMessageDialog(parent, e.getMessage()); } - loadingBar.close(); } } }; @@ -227,10 +224,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { /** * 预览返回的一个数据集 * - * - * @date 2014-12-3-下午7:42:53 - * - */ + * @date 2014-12-3-下午7:42:53 + */ + @Override public void previewData() { previewData(-1, -1); } @@ -240,13 +236,11 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { /** * 预览返回的一个数据集,带有显示值和实际值的标记结果 * - * @param keyIndex 实际值 - * @param valueIndex 显示值 - * - * - * @date 2014-12-3-下午7:42:27 - * - */ + * @param keyIndex 实际值 + * @param valueIndex 显示值 + * @date 2014-12-3-下午7:42:27 + */ + @Override public void previewData(final int keyIndex, final int valueIndex) { PreviewTablePane.previewStoreData(procedureDataModel, keyIndex, valueIndex); } @@ -257,7 +251,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { */ public void previewAllTable() { if (procedureDataModel == null) { - if (!createStore(true)) { + try { + createStore(true); + } catch (Exception e) { return; } } @@ -269,6 +265,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { return dsName; } + @Override public TableData getTableData() { return storeProcedure; } @@ -282,10 +279,12 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper { * * @return 是否异常 */ + @Override public boolean isUnusual() { return false; } + @Override public boolean equals(Object obj) { return obj instanceof StoreProcedureDataWrapper && ComparatorUtils.equals(this.dsName, ((StoreProcedureDataWrapper) obj).getTableDataName()) diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java index a0d0182acd..c2c815e8a8 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java @@ -1,7 +1,7 @@ package com.fr.design.data.tabledata.wrapper; -import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; import com.fr.data.impl.storeproc.ProcedureDataModel; import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.design.data.DesignTableDataManager; @@ -27,7 +27,9 @@ import java.util.List; * * @author zhou * @since 2012-4-12上午10:29:15 + * @deprecated 请勿使用,见{@link MultiResultTableDataNameWrapper} */ +@Deprecated public final class StoreProcedureNameWrapper implements TableDataWrapper { private ProcedureDataModel procedureDataModel; private String name; @@ -69,12 +71,12 @@ public final class StoreProcedureNameWrapper implements TableDataWrapper { @Override public Icon getIcon() { - return BaseUtils.readIcon("/com/fr/design/images/data/store_procedure.png"); + return IconUtils.readIcon("/com/fr/design/standard/store_procedure"); } private void createStore(boolean needLoadingBar) { try { - procedureDataModel = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar)[0]; + procedureDataModel = (ProcedureDataModel) DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar)[0]; } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TableDataFactory.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TableDataFactory.java index 6bc9e21ed6..8345bde944 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TableDataFactory.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TableDataFactory.java @@ -55,15 +55,15 @@ public abstract class TableDataFactory { * 同一类型的只能加一次,就加最上层的类,因为要排序。如果将所有的 FileTableData都加进来,那么FileTableData的排序就不正确了 */ static { - defaultMap.put(DBTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/database.png", DBTableData.class, DBTableDataPane.class)); - defaultMap.put(ClassTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/source/classTableData.png", ClassTableData.class, ClassTableDataPane.class)); - defaultMap.put(EmbeddedTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/dataTable.png", EmbeddedTableData.class, EmbeddedTableDataPane.class)); - defaultMap.put(DecoratedTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/multi.png", DecoratedTableData.class, DecoratedTableDataPane.class)); - defaultMap.put(StoreProcedure.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/store_procedure.png", StoreProcedure.class, ProcedureDataPane.class)); - defaultMap.put(MultiTDTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/multi.png", MultiTDTableData.class, MultiTDTableDataPane.class)); - defaultMap.put(FileTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/file.png", FileTableData.class, FileTableDataPane.class)); - defaultMap.put(RecursionTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/tree.png", RecursionTableData.class, TreeTableDataPane.class)); - defaultMap.put(MultiFieldTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/images/data/database.png", MultiFieldTableData.class, null)); + defaultMap.put(DBTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/database_normal.svg", DBTableData.class, DBTableDataPane.class)); + defaultMap.put(ClassTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/class_table_data_normal.svg", ClassTableData.class, ClassTableDataPane.class)); + defaultMap.put(EmbeddedTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/data_table_normal.svg", EmbeddedTableData.class, EmbeddedTableDataPane.class)); + defaultMap.put(DecoratedTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/multi_normal.svg", DecoratedTableData.class, DecoratedTableDataPane.class)); + defaultMap.put(StoreProcedure.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/store_procedure_normal.svg", StoreProcedure.class, ProcedureDataPane.class)); + defaultMap.put(MultiTDTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/multi_normal.svg", MultiTDTableData.class, MultiTDTableDataPane.class)); + defaultMap.put(FileTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/file_normal.svg", FileTableData.class, FileTableDataPane.class)); + defaultMap.put(RecursionTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/tree_normal.svg", RecursionTableData.class, TreeTableDataPane.class)); + defaultMap.put(MultiFieldTableData.class.getName(), new TableDataNameObjectCreator(null, "/com/fr/design/standard/database_normal.svg", MultiFieldTableData.class, null)); map.putAll(defaultMap); } @@ -151,7 +151,7 @@ public abstract class TableDataFactory { if (tableDataNameObjectCreator != null && tableDataNameObjectCreator.getIconPath() != null) { return tableDataNameObjectCreator.getIconPath(); } - return "/com/fr/design/images/data/database.png"; + return "/com/fr/design/standard/database_normal.svg"; } /** diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TemplateTableDataWrapper.java b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TemplateTableDataWrapper.java index 49e6f625ae..93bb7bf3bf 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TemplateTableDataWrapper.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/TemplateTableDataWrapper.java @@ -2,8 +2,9 @@ package com.fr.design.data.tabledata.wrapper; import javax.swing.Icon; -import com.fr.base.BaseUtils; import com.fr.base.TableData; +import com.fr.base.svg.IconUtils; +import com.fr.base.svg.SVGLoader; import com.fr.data.impl.DBTableData; import com.fr.design.icon.WarningIcon; import com.fr.stable.StringUtils; @@ -20,9 +21,9 @@ public final class TemplateTableDataWrapper extends AbstractTableDataWrapper { @Override public Icon getIcon() { if (tabledata instanceof DBTableData && StringUtils.isBlank(((DBTableData) tabledata).getQuery())) { - return new WarningIcon(BaseUtils.readImage("/com/fr/design/images/data/database.png")); + return new WarningIcon(SVGLoader.load("/com/fr/design/standard/database_normal.svg")); } - return BaseUtils.readIcon(TableDataFactory.getIconPath(tabledata)); + return IconUtils.readIcon(TableDataFactory.getIconPath(tabledata)); } @Override diff --git a/designer-base/src/main/java/com/fr/design/deeplink/DeepLink.java b/designer-base/src/main/java/com/fr/design/deeplink/DeepLink.java new file mode 100644 index 0000000000..5b40c88450 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/deeplink/DeepLink.java @@ -0,0 +1,15 @@ +package com.fr.design.deeplink; + +import java.util.Map; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/6 + */ +public abstract class DeepLink { + + public abstract boolean accept(String url, String host, String path, Map params); + + public abstract void run(String url, String host, String path, Map params); +} diff --git a/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java new file mode 100644 index 0000000000..c9b80ebf72 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java @@ -0,0 +1,249 @@ +package com.fr.design.deeplink; + +import com.fr.design.constants.DesignerLaunchStatus; +import com.fr.design.startup.FineStartupNotificationFactory; +import com.fr.design.startup.FineStartupNotificationProvider; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.event.Null; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.stable.os.OperatingSystem; +import com.fr.start.common.DesignerStartupContext; +import com.fr.third.org.apache.http.NameValuePair; +import com.fr.web.URLUtils; + +import javax.swing.SwingUtilities; +import java.awt.Color; +import java.awt.Frame; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/6 + */ +public class DeepLinkCore { + + protected DeepLinkCore(){} + private static final DeepLinkCore instance = new DeepLinkCore(); + public static DeepLinkCore getInstance(){ + return instance; + } + + private String pendingURL; + + private final List deepLinkPrepareList = new ArrayList<>(); + + private final List deepLinkList = new ArrayList<>(); + + private boolean isDesignerStartupCompleted = false; + + public void register(DeepLink deepLink) { + if (deepLink != null) { + deepLinkList.add(deepLink); + if (deepLink instanceof DeepLinkPrepare) { + deepLinkPrepareList.add((DeepLinkPrepare) deepLink); + } + } + } + + public void start(String[] args) { + if (OperatingSystem.isWindows()) { + if (args.length > 0) { + receiveDeeplink(args[0]); + } + } + + if (OperatingSystem.isWindows() && args.length > 0) { + receiveDeeplink(args[0]); + } + + FineStartupNotificationFactory.getNotification() + .registerStartupListener(new FineStartupNotificationProvider.Listener() { + @Override + public void startupPerformed(String parameters) { + receiveDeeplink(parameters); + } + }); + + EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { + @Override + public void on(Event event, Null param) { + EventDispatcher.stopListen(this); + isDesignerStartupCompleted = true; + if (canConsumePendingURL()) { + consumePendingURL(); + } + } + }); + } + + public void receiveDeeplink(String url) { + if (canAcceptNewURL()) { + acceptNewURL(url); + if (canConsumePendingURL()) { + consumePendingURL(); + } + } + } + + public void receiveDeeplink2(String url) { + if (canAcceptNewURL()) { + acceptNewURL(url); + if (canConsumePendingURL()) { + consumePendingURL(); + } else { + Frame frame = new Frame("can not ConsumePendingURL"); + frame.setSize(400, 400); + frame.setBackground(Color.BLACK); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent windowEvent){ + frame.dispose(); + } + }); + frame.setVisible(true); + } + } else { + Frame frame = new Frame("can not AcceptNewURL"); + frame.setSize(400, 400); + frame.setBackground(Color.BLACK); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent windowEvent){ + frame.dispose(); + } + }); + frame.setVisible(true); + } + } + + private boolean canAcceptNewURL() { + return StringUtils.isEmpty(this.pendingURL); + } + + private void acceptNewURL(String url) { + this.pendingURL = url; + + UrlBean urlBean = UrlBean.create(this.pendingURL); + for (DeepLinkPrepare deepLinkPrepare : deepLinkPrepareList) { + deepLinkPrepare.prepare(urlBean.getUrl(), urlBean.getHost(), urlBean.getPath(), urlBean.getParams()); + } + } + + private boolean canConsumePendingURL() { + return StringUtils.isNotEmpty(this.pendingURL) && isAvailableConsumingTime(); + } + + /** + * 是否是可用的消耗时机 + * 满足任一即可 + * 1-设计器已经启动 + * 2-出在设计器启动页页面 + * + * @return 是/否 + */ + private boolean isAvailableConsumingTime() { + return isDesignerStartupCompleted || DesignerStartupContext.getInstance().isOnWaiting(); + } + + private void consumePendingURL() { + + UrlBean urlBean = UrlBean.create(this.pendingURL); + + FineLoggerFactory.getLogger().info("consume deep link: " + this.pendingURL); + performDeepLinks(urlBean.getUrl(), urlBean.getHost(), urlBean.getPath(), urlBean.getParams()); + + markPendingURLConsumed(); + } + + private void performDeepLinks(String url, String host, String path, Map params) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + for (DeepLink deepLink: deepLinkList) { + if (deepLink.accept(url, host, path, params)) { + deepLink.run(url, host, path, params); + } + } + } + }); + } + + private void markPendingURLConsumed() { + this.pendingURL = null; + } + + private static class UrlBean { + + private String url; + + private String host; + + private String path; + + private Map params; + + public UrlBean(String url, String host, String path, Map params) { + this.url = url; + this.host = host; + this.path = path; + this.params = params; + } + + public String getUrl() { + return url; + } + + public String getHost() { + return host; + } + + public String getPath() { + return path; + } + + public Map getParams() { + return params; + } + + public static UrlBean create(String pendingUrl) { + + String host = null; + String path = null; + Map params = new HashMap<>(); + + URL url = null; + try { + url = new URL(null, pendingUrl, new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + return null; + } + }); + } catch (MalformedURLException ignored) { + } + + if (url != null) { + host = url.getHost(); + path = url.getPath(); + + List pairs = URLUtils.parse(url.getQuery()); + for (NameValuePair pair : pairs) { + params.put(pair.getName(), pair.getValue()); + } + } + return new UrlBean(pendingUrl, host, path, params); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkPrepare.java b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkPrepare.java new file mode 100644 index 0000000000..e74d99d8b7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkPrepare.java @@ -0,0 +1,17 @@ +package com.fr.design.deeplink; + +import java.util.Map; + +/** + * created by Harrison on 2022/08/23 + **/ +public interface DeepLinkPrepare { + + /** + * 准备 + * + * @param url 链接 + * @return 成功/失败 + */ + boolean prepare(String url, String host, String path, Map params); +} diff --git a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java index d3c592a4ed..75626441bf 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java +++ b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java @@ -8,9 +8,14 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.stable.core.PropertyChangeAdapter; -import javax.swing.*; +import javax.swing.JPanel; import javax.swing.event.DocumentEvent; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Window; @Open public abstract class BasicPane extends JPanel { @@ -262,6 +267,10 @@ public abstract class BasicPane extends JPanel { public void checkValid() throws Exception { } + public boolean confirmContinueBeforeDoOK() { + return true; + } + public static class NamePane extends BasicPane { private UITextField nameTextField; private UILabel Name; @@ -390,6 +399,10 @@ public abstract class BasicPane extends JPanel { BasicPane.this.checkValid(); } + public boolean confirmContinueBeforeDoOK() { + return BasicPane.this.confirmContinueBeforeDoOK(); + } + } private class UnsizedDialog extends UIDialog { diff --git a/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java b/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java index c644550795..4e0b4e520d 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java +++ b/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java @@ -8,6 +8,7 @@ import javax.swing.JDialog; import javax.swing.JOptionPane; import java.awt.Component; import java.awt.HeadlessException; +import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; @@ -184,6 +185,29 @@ public class FineJOptionPane extends JOptionPane { messageType, icon, options, initialValue); } + /** + * 带确认+取消按钮的弹出框,并绑定确认事件 + * + * @param parentComponent 父容器 + * @param message 具体的提示消息 + * @param title 标题 + * @param icon 图标 + * @param initialValue 初始选项 + * @throws HeadlessException + */ + public static int showConfirmDialogWithOkListener(Component parentComponent, Object message, + String title, Icon icon, Object initialValue, ActionListener listener) + throws HeadlessException { + int val = showOptionDialog(parentComponent, message, title, JOptionPane.DEFAULT_OPTION, + FineJOptionPane.WARNING_MESSAGE, icon, OPTION_OK_CANCEL, initialValue); + if (val == JOptionPane.OK_OPTION && listener!=null) { + listener.actionPerformed(null); + } + return val; + } + + + /** * 指定消息内容的输入弹出框 * @param message 消息内容 diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java index b9854c6bcd..24ff7e10c7 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java +++ b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java @@ -92,7 +92,7 @@ public class UIDetailErrorLinkDialog extends UIDialog { contentPane.add(link, BorderLayout.SOUTH); // 确定 + 取消 - JPanel actionPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, GAP_10, GAP_10)); + JPanel actionPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, GAP_10, GAP_5)); actionPane.add(createButton(Toolkit.i18nText("Fine-Design_Report_OK"))); actionPane.add(createButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"))); this.getContentPane().add(topPane, BorderLayout.NORTH); diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java index c158123574..63aea87c3c 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java +++ b/designer-base/src/main/java/com/fr/design/dialog/UIDialog.java @@ -18,6 +18,7 @@ import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.Frame; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -33,6 +34,7 @@ public abstract class UIDialog extends JDialog { private BasicPane pane; private java.util.List listeners = new ArrayList(); private boolean isDoOKSucceed; + private boolean needExceptionCheck = true; public UIDialog(Frame parent) { @@ -43,6 +45,10 @@ public abstract class UIDialog extends JDialog { super(parent); } + public UIDialog(Window parent) { + super(parent); + } + public UIDialog(Frame parent, BasicPane pane) { this(parent, pane, true); @@ -151,6 +157,10 @@ public abstract class UIDialog extends JDialog { }); } + public void setNeedExceptionCheck(boolean needExceptionCheck) { + this.needExceptionCheck = needExceptionCheck; + } + /** * 添加监听器 @@ -172,14 +182,21 @@ public abstract class UIDialog extends JDialog { * 确定操作 */ public void doOK() { + //由于checkValid不可以加入自定义的弹窗以及操作,添加一个接口 + if (!confirmContinueBeforeDoOK()) { + return; + } + try { checkValid(); } catch (Exception exp) { - FineJOptionPane.showMessageDialog( - this, - exp.getMessage(), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.WARNING_MESSAGE); + if (needExceptionCheck) { + FineJOptionPane.showMessageDialog( + this, + exp.getMessage(), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + JOptionPane.WARNING_MESSAGE); + } return; } @@ -253,6 +270,10 @@ public abstract class UIDialog extends JDialog { */ public abstract void checkValid() throws Exception; + public boolean confirmContinueBeforeDoOK() { + return true; + } + public void setButtonEnabled(boolean b) { this.okButton.setEnabled(b); } diff --git a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java index f73ec77df5..3e41750585 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java +++ b/designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java @@ -1,16 +1,18 @@ package com.fr.design.dialog.link; -import com.fr.design.gui.ilable.UILabel; +import com.fr.design.utils.LinkStrUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import javax.swing.JEditorPane; import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; import java.awt.Color; import java.awt.Desktop; import java.awt.Font; import java.net.URI; +import java.net.URL; + +import static com.fr.design.utils.LinkStrUtils.LABEL; /** * 用来构建JOptionPane带超链的消息提示 @@ -21,9 +23,33 @@ import java.net.URI; */ public class MessageWithLink extends JEditorPane { - private static final UILabel LABEL = new UILabel(); + private static final String HTML_BODY = " 的话,将会自动点击匹配 url + * + * @param htmlText html内容 + */ + public MessageWithLink(String htmlText) { + + super("text/html", htmlText); + initListener(); + setEditable(false); + setBorder(null); + } + + public MessageWithLink(String htmlText, Runnable action) { + + super("text/html", htmlText); + initListener(action); + setEditable(false); + setBorder(null); + } + public MessageWithLink(String message, String linkName, String link) { this(message, linkName, link, LABEL.getBackground(), LABEL.getFont()); } @@ -37,43 +63,85 @@ public class MessageWithLink extends JEditorPane { } public MessageWithLink(String frontMessage, String linkName, String link, String backMessage) { - this(frontMessage, linkName, link, backMessage, LABEL.getBackground(), LABEL.getFont()); + this(frontMessage, linkName, link, backMessage, LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground()); } public MessageWithLink(String message, String linkName, String link, Color color, Font font) { - this(message, linkName, link, StringUtils.EMPTY, color, font); + this(message, linkName, link, StringUtils.EMPTY, color, font, LABEL.getForeground()); } public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color color, Font font) { - super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); + this(frontMessage, linkName, link, backMessage, color, font, LABEL.getForeground()); + } + + public MessageWithLink(String htmlText, Font font) { + this(setHtmlFont(htmlText, font)); + } + + + + /** + * 将指定的字体赋给html文本 + * 任何失败,返回原html文本 + * */ + private static String setHtmlFont(String htmlText, Font font) { + + try { + int bodyIndex = htmlText.indexOf(HTML_BODY); + StringBuilder sb = new StringBuilder(); + String left = htmlText.substring(0, bodyIndex + HTML_BODY.length()); + String right = htmlText.substring(bodyIndex + HTML_BODY.length()); + sb.append(left); + sb.append(String.format(HTML_STYLE_FORMAT, LinkStrUtils.generateStyle(Color.WHITE, font, Color.BLACK))); + sb.append(right); + return sb.toString(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + + return htmlText; + } + + public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) { + + super("text/html", "" + frontMessage + "" + linkName + "" + backMessage + ""); initListener(link); setEditable(false); setBorder(null); } - - protected void initListener(String link) { - addHyperlinkListener(new HyperlinkListener() { - @Override - public void hyperlinkUpdate(HyperlinkEvent e) { - if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { - try { - Desktop.getDesktop().browse(URI.create(link)); - } catch (Exception exception) { - FineLoggerFactory.getLogger().error(exception.getMessage(), exception); - } + + protected void initListener() { + + addHyperlinkListener(hyperlinkEvent -> { + try { + if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { + URL url = hyperlinkEvent.getURL(); + Desktop.getDesktop().browse(url.toURI()); } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + }); + } + + protected void initListener(Runnable runnable) { + + addHyperlinkListener(e -> { + if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { + runnable.run(); } }); } - private static StringBuilder generateStyle(Color color, Font font) { - // 构建相同风格样式 - StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); - style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); - style.append("font-size:").append(font.getSize()).append("pt;"); - style.append("background-color: rgb(").append(color.getRed()).append(",").append(color.getGreen()).append(",").append(color.getBlue()).append(");"); - - return style; + protected void initListener(String link) { + + initListener(() -> { + try { + Desktop.getDesktop().browse(URI.create(link)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + }); } } diff --git a/designer-base/src/main/java/com/fr/design/editor/editor/NotNegativeIntegerEditor.java b/designer-base/src/main/java/com/fr/design/editor/editor/NotNegativeIntegerEditor.java new file mode 100644 index 0000000000..98c59c1736 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/editor/editor/NotNegativeIntegerEditor.java @@ -0,0 +1,33 @@ +package com.fr.design.editor.editor; + +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +/** + * @author xiqiu + * @date 2022/1/10 + * @description 一个简单的非负整数框 + */ +public class NotNegativeIntegerEditor extends IntegerEditor { + private static final String NEG = "-"; + + public NotNegativeIntegerEditor(int columns) { + this(); + this.setColumns(columns); + } + + public NotNegativeIntegerEditor() { + super(); + this.numberField.addKeyListener(new KeyAdapter() { + + @Override + public void keyReleased(KeyEvent evt) { + char keyChar = evt.getKeyChar(); + if (NEG.equals(keyChar + "")) { + numberField.setText(numberField.getTextValue().replace(NEG, "")); + } + } + }); + } +} + diff --git a/designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java b/designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java index a7d6eb6c17..d3fb4268da 100644 --- a/designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java +++ b/designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java @@ -1,8 +1,7 @@ package com.fr.design.env; import com.fr.general.ComparatorUtils; -import com.fr.general.GeneralUtils; -import com.fr.locale.InterProviderFactory; +import com.fr.stable.CommonUtils; import com.fr.stable.CoreConstants; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; @@ -10,8 +9,8 @@ import com.fr.stable.project.ProjectConstants; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLableReader; import com.fr.workspace.connect.WorkspaceConnectionInfo; - import com.fr.workspace.engine.exception.MainVersionNotMatchException; + import java.io.File; import java.util.Properties; @@ -100,11 +99,17 @@ public class LocalDesignerWorkspaceInfo implements DesignerWorkspaceInfo { @Override public boolean checkValid(){ + File file = new File(this.path); //判断不是文件夹/路径不在WEB-INF下/代码启动三种情况 if(!file.isDirectory() || !ComparatorUtils.equals(file.getName(), "WEB-INF") || this.path.startsWith(".")) { return false; } + + // 如果当前是 debug 模式,就不检测是否 mainVersion 不一致 + if (CommonUtils.isDebug()) { + return true; + } File engineLib = new File(StableUtils.pathJoin(this.path, ProjectConstants.LIB_NAME, REPORT_ENGINE_JAR)); // 非安装版本允许自由切换 diff --git a/designer-base/src/main/java/com/fr/design/event/ComponentChangeListener.java b/designer-base/src/main/java/com/fr/design/event/ComponentChangeListener.java new file mode 100644 index 0000000000..d16d49b6a4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/event/ComponentChangeListener.java @@ -0,0 +1,7 @@ +package com.fr.design.event; + +import java.awt.*; + +public interface ComponentChangeListener { + void initListener(Container changedComponent); +} diff --git a/designer-base/src/main/java/com/fr/design/event/ComponentChangeObserver.java b/designer-base/src/main/java/com/fr/design/event/ComponentChangeObserver.java new file mode 100644 index 0000000000..9ef75d514a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/event/ComponentChangeObserver.java @@ -0,0 +1,6 @@ +package com.fr.design.event; + + +public interface ComponentChangeObserver { + void registerChangeListener(ComponentChangeListener uiChangeableListener); +} diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginInstalledPane.java b/designer-base/src/main/java/com/fr/design/extra/PluginInstalledPane.java index 2fa1ea1102..1923a22876 100644 --- a/designer-base/src/main/java/com/fr/design/extra/PluginInstalledPane.java +++ b/designer-base/src/main/java/com/fr/design/extra/PluginInstalledPane.java @@ -60,11 +60,14 @@ public class PluginInstalledPane extends PluginAbstractViewPane { public void actionPerformed(ActionEvent e) { PluginView plugin = controlPane.getSelectedPlugin(); if (plugin != null) { - boolean isActive = plugin.isActive(); - PluginMarker pluginMarker = PluginMarker.create(plugin.getID(), plugin.getVersion()); - final String modifyMessage = isActive ? com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Has_Been_Actived") : com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Has_Been_Disabled"); - if (isActive) { - PluginManager.getController().forbid(pluginMarker, new PluginTaskCallback() { + PluginContext pluginContext = getPluginContextByView(plugin); + if (pluginContext == null) { + return; + } + boolean running = pluginContext.isRunning(); + final String modifyMessage = running ? com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Has_Been_Actived") : com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Has_Been_Disabled"); + if (running) { + PluginManager.getController().forbidPersistently(pluginContext.getMarker(), new PluginTaskCallback() { @Override public void done(PluginTaskResult result) { if (result.isSuccess()) { @@ -75,7 +78,7 @@ public class PluginInstalledPane extends PluginAbstractViewPane { } }); } else { - PluginManager.getController().enable(pluginMarker, new PluginTaskCallback() { + PluginManager.getController().enablePersistently(pluginContext.getMarker(), new PluginTaskCallback() { @Override public void done(PluginTaskResult result) { if (result.isSuccess()) { @@ -145,13 +148,25 @@ public class PluginInstalledPane extends PluginAbstractViewPane { } private void changeTextForButton(PluginView plugin) { - if (plugin.isActive()) { + PluginContext pluginContext = getPluginContextByView(plugin); + if (pluginContext == null) { + return; + } + if (pluginContext.isRunning()) { disableButton.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Disable")); } else { disableButton.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Active")); } } + private PluginContext getPluginContextByView(PluginView pluginView) { + if (pluginView != null) { + PluginMarker pluginMarker = PluginMarker.create(pluginView.getID(), pluginView.getVersion()); + return PluginManager.getContext(pluginMarker); + } + return null; + } + @Override protected String title4PopupWindow() { return "Installed"; diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java b/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java index d7260f84ee..379daab28e 100644 --- a/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java +++ b/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java @@ -25,6 +25,8 @@ import com.fr.plugin.manage.control.PluginTask; import com.fr.plugin.manage.control.PluginTaskCallback; import com.fr.plugin.manage.control.PluginTaskResult; import com.fr.plugin.view.PluginView; +import com.fr.plugin.xml.PluginElementName; +import com.fr.plugin.xml.PluginXmlElement; import com.fr.stable.StringUtils; import javax.swing.JOptionPane; @@ -91,15 +93,37 @@ public class PluginOperateUtils { public static void setPluginActive(String pluginInfo, JSCallback jsCallback) { - PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); - PluginContext plugin = PluginManager.getContext(pluginMarker); - boolean active = plugin.isActive(); - PluginTaskCallback modifyStatusCallback = new ModifyStatusCallback(active, jsCallback); - if (active) { - PluginManager.getController().forbid(pluginMarker, modifyStatusCallback); - } else { - PluginManager.getController().enable(pluginMarker, modifyStatusCallback); - } + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); + PluginContext plugin = PluginManager.getContext(pluginMarker); + boolean isRunning = plugin.isRunning(); + PluginTaskCallback modifyStatusCallback = new ModifyStatusCallback(isRunning, jsCallback); + if (isRunning) { + PluginXmlElement forbidReminder = plugin.getXml().getElement(PluginElementName.ForbidReminder); + if (forbidReminder != null && forbidReminder.getContent() != null) { + // 禁用前提示 + int rv = FineJOptionPane.showConfirmDialog( + null, + forbidReminder.getContent(), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE + ); + if (rv == JOptionPane.OK_OPTION) { + PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); + } + } else { + // 正常禁用 + PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); + } + } else { + PluginManager.getController().enablePersistently(pluginMarker, modifyStatusCallback); + } + } + }); } public static void uninstallPlugin(final String pluginInfo, final boolean isForce, final JSCallback jsCallback) { diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java b/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java index ed7253bad2..f12f8f8446 100644 --- a/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java +++ b/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java @@ -10,8 +10,8 @@ import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; import com.fr.plugin.PluginVerifyException; import com.fr.plugin.basic.version.Version; -import com.fr.plugin.basic.version.VersionIntervalType; import com.fr.plugin.basic.version.VersionIntervalFactory; +import com.fr.plugin.basic.version.VersionIntervalType; import com.fr.plugin.context.PluginContext; import com.fr.plugin.context.PluginMarker; import com.fr.plugin.error.PluginBaseErrorCode; @@ -23,7 +23,7 @@ import com.fr.stable.ProductConstants; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; -import javax.swing.*; +import javax.swing.JOptionPane; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -47,9 +47,10 @@ public class PluginUtils { public static PluginMarker createPluginMarker(String pluginInfo) { - //todo 判空 - String[] plugin = pluginInfo.split("_"); - return PluginMarker.create(plugin[0], plugin[1]); + int splitIndex = pluginInfo.lastIndexOf("_"); + String pluginID = pluginInfo.substring(0, splitIndex); + String version = pluginInfo.substring(splitIndex + 1); + return PluginMarker.create(pluginID, version); } public static JSONObject getLatestPluginInfo(String pluginID) throws Exception { @@ -80,10 +81,12 @@ public class PluginUtils { public static String transPluginsToString(List plugins) throws Exception { JSONArray jsonArray = new JSONArray(); for (PluginContext plugin : plugins) { - JSONObject jo = new JSONObject(); - jo.put("id", plugin.getID()); - jo.put("version", plugin.getVersion()); - jsonArray.put(jo); + if (VersionIntervalType.isSupported(plugin.supportCurrentFRVersion())) { + JSONObject jo = new JSONObject(); + jo.put("id", plugin.getID()); + jo.put("version", plugin.getVersion()); + jsonArray.put(jo); + } } return jsonArray.toString(); } @@ -267,7 +270,8 @@ public class PluginUtils { jo.put("vendor", pluginContext.getVendor()); jo.put("price", pluginContext.getPrice()); jo.put("requiredJarTime", pluginContext.getRequiredJarTime()); - jo.put("active", pluginContext.isActive()); + // 前端需求的active实际上是插件的运行状态,通过isRunning()获取 + jo.put("active", pluginContext.isRunning()); jo.put("hidden", pluginContext.isHidden()); jo.put("free", pluginContext.isFree()); jo.put("licDamaged", pluginContext.isLicDamaged()); diff --git a/designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java b/designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java index f35fbdf116..3fe8184619 100644 --- a/designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java +++ b/designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java @@ -1,6 +1,5 @@ package com.fr.design.extra; -import com.fr.base.FRContext; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.UIDialog; @@ -15,12 +14,12 @@ import com.fr.general.IOUtils; import com.fr.general.http.HttpToolbox; import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; +import com.fr.plugin.PluginStoreConfig; import com.fr.plugin.PluginStoreConstants; import com.fr.stable.CommonUtils; import com.fr.stable.EnvChangedListener; import com.fr.stable.ProductConstants; import com.fr.stable.StableUtils; -import com.fr.stable.StringUtils; import javax.swing.JOptionPane; import javax.swing.SwingWorker; @@ -44,15 +43,14 @@ public class WebViewDlgHelper { private static final String LATEST = "latest"; private static final String SHOP_SCRIPTS = "shop_scripts"; private static final int VERSION_8 = 8; - private static String installHome = FRContext.getCommonOperator().getWebRootPath(); + private static String installHome = PluginStoreConstants.getLocalInstallHome(); private static final String MAIN_JS_PATH = "/scripts/plugin.html"; - private static final String ENV_VERSION = "ENV_VERSION"; static { GeneralContext.addEnvChangedListener(new EnvChangedListener() { @Override public void envChanged() { - installHome = FRContext.getCommonOperator().getWebRootPath(); + installHome = PluginStoreConstants.getLocalInstallHome(); } }); } @@ -74,8 +72,11 @@ public class WebViewDlgHelper { } return; } - String jar_version = PluginStoreConstants.getProps(ENV_VERSION, StringUtils.EMPTY); - if (ComparatorUtils.equals(jar_version, ProductConstants.VERSION)) { + // 检测更新前先刷新一下版本号 + PluginStoreConstants.refreshProps(); + + String jarVersion = PluginStoreConfig.getInstance().getEnvVersion(); + if (ComparatorUtils.equals(jarVersion, ProductConstants.VERSION)) { updateShopScripts(SHOP_SCRIPTS); showPluginDlg(); } else { @@ -133,7 +134,7 @@ public class WebViewDlgHelper { * * @param filePath 待删除文件路径 */ - private static void deleteExtraFile(String filePath){ + private static void deleteExtraFile(String filePath) { CommonIOUtils.deleteFile(new File(filePath)); } @@ -259,7 +260,7 @@ public class WebViewDlgHelper { try { if (get()) { File scriptZip = new File(StableUtils.pathJoin(PluginConstants.DOWNLOAD_PATH, PluginConstants.TEMP_FILE)); - if(scriptZip.exists()){ + if (scriptZip.exists()) { IOUtils.unzip(scriptZip, installHome); CommonUtils.deleteFile(scriptZip); } @@ -283,7 +284,7 @@ public class WebViewDlgHelper { protected Void doInBackground() throws Exception { String url = CloudCenter.getInstance().acquireUrlByKind("shop.plugin.update"); if (url != null) { - String text = HttpToolbox.get(url + "?" + PluginUtils.FR_VERSION + "=" + ProductConstants.VERSION + "&version=" + PluginStoreConstants.getProps("VERSION")); + String text = HttpToolbox.get(url + "?" + PluginUtils.FR_VERSION + "=" + ProductConstants.VERSION + "&version=" + PluginStoreConfig.getInstance().getVersion()); JSONObject resultJSONObject = new JSONObject(text); String isLatest = resultJSONObject.optString("result"); if (!ComparatorUtils.equals(isLatest, LATEST)) { diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java b/designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java index 739b84666d..4656d8d393 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java @@ -1,15 +1,24 @@ package com.fr.design.extra.exe; +import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginsReaderFromStore; import com.fr.design.extra.Process; +import com.fr.design.i18n.Toolkit; +import com.fr.design.utils.DesignUtils; +import com.fr.general.SiteBlockedException; import com.fr.json.JSONArray; import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; import com.fr.plugin.view.PluginView; import com.fr.stable.StringUtils; +import javax.swing.JOptionPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.List; +import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL; + /** * Created by vito on 16/4/19. */ @@ -41,6 +50,19 @@ public class ReadUpdateOnlineExecutor implements Executor { jsonArray.put(jsonObject); } result = jsonArray.toString(); + } catch (SiteBlockedException e1) { + FineJOptionPane.showConfirmDialogWithOkListener(null, + e1.getMessage(), + Toolkit.i18nText("Fine-Design_Basic_Alert"), null, null, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignUtils.visitEnvServerByParameters( + "#management/system/normal", + null, + null); + } + }); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java index 92fdd4878a..ea591f3bf4 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java @@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback; import com.fr.design.bridge.exec.JSCallback; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginOperateUtils; +import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper; import com.fr.design.i18n.Toolkit; import com.fr.log.FineLoggerFactory; @@ -73,7 +74,7 @@ public class InstallFromDiskCallback extends AbstractPluginTaskCallback { }else { jsCallback.execute("failed"); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Install_Failed")); - FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); + PluginCallBackHelper.showErrorMessage(result, pluginInfo); } } } diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java index 0b1eb33fb9..09c360b4f1 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java @@ -4,6 +4,7 @@ import com.fr.design.bridge.exec.JSCallback; import com.fr.design.bridge.exec.JSExecutor; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginOperateUtils; +import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper; import com.fr.design.i18n.Toolkit; import com.fr.log.FineLoggerFactory; @@ -63,7 +64,7 @@ public class InstallOnlineCallback extends AbstractDealPreTaskCallback { } else { jsCallback.execute("failed"); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Install_Failed")); - FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); + PluginCallBackHelper.showErrorMessage(result, pluginInfo); } } diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java index 21c7871f52..31bf482ebe 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java @@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback; import com.fr.design.bridge.exec.JSCallback; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginOperateUtils; +import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper; import com.fr.design.i18n.Toolkit; import com.fr.log.FineLoggerFactory; @@ -72,7 +73,7 @@ public class UpdateFromDiskCallback extends AbstractPluginTaskCallback { }else { jsCallback.execute("failed"); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Failed")); - FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); + PluginCallBackHelper.showErrorMessage(result, pluginInfo); } } } diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java index 8dbad6a541..3469ed1a59 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java @@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback; import com.fr.design.bridge.exec.JSCallback; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginOperateUtils; +import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper; import com.fr.design.i18n.Toolkit; import com.fr.log.FineLoggerFactory; @@ -38,7 +39,7 @@ public class UpdateOnlineCallback extends AbstractDealPreTaskCallback { } else { jsCallback.execute("failed"); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Failed")); - FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); + PluginCallBackHelper.showErrorMessage(result, pluginInfo); } } } diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java new file mode 100644 index 0000000000..fc5f957f63 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java @@ -0,0 +1,70 @@ +package com.fr.design.extra.exe.callback.handle; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.i18n.Toolkit; +import com.fr.plugin.error.PluginErrorCode; +import com.fr.plugin.manage.control.PluginTaskResult; + +/** + * 帮助处理插件操作(安装、更新等)的弹窗 + * @author Yvan + */ +public class PluginCallBackHelper { + + private static final String NEW_LINE_TAG = "
"; + private static final String REFERENCE = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_Reference"); + private static final String HELP_DOCUMENT_NAME = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_NAME"); + private static final String CONNECTOR = "-"; + private static final String HELP_DOCUMENT_LINK = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK"); + + + /** + * 展示插件操作失败后的提示弹窗 + * @param result + * @param pluginInfo + */ + public static void showErrorMessage(PluginTaskResult result, String pluginInfo) { + // 单独处理下插件完整性校验失败的提示 + if (PluginCallBackHelper.needHandleInvalidatePackage(result)) { + MessageWithLink messageWithLink = PluginCallBackHelper.generate4InvalidatePackage(pluginInfo); + PluginTaskResultErrorDialog resultDialog = new PluginTaskResultErrorDialog(null, messageWithLink); + resultDialog.showResult(); + } else { + FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE); + } + } + + /** + * 判断是否需要处理 插件安装包校验失败 导致的安装失败任务 + * @param result + * @return + */ + private static boolean needHandleInvalidatePackage(PluginTaskResult result) { + return !result.isSuccess() && result.getCode() == PluginErrorCode.InstallPackageValidateFailed; + } + + /** + * 根据插件原始报错信息,构建MessageWithLink + * @param originInfo + * @return + */ + private static MessageWithLink generate4InvalidatePackage(String originInfo) { + + return new MessageWithLink(getSupplementaryMessage(originInfo), HELP_DOCUMENT_NAME, HELP_DOCUMENT_LINK); + } + + /** + * 根据插件原始报错信息,获取增加了补充说明后的信息 + * @param originInfo + * @return + */ + private static String getSupplementaryMessage(String originInfo) { + return new StringBuilder() + .append(originInfo) + .append(NEW_LINE_TAG) + .append(REFERENCE) + .append(CONNECTOR) + .toString(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java new file mode 100644 index 0000000000..5cc0dce953 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java @@ -0,0 +1,86 @@ +package com.fr.design.extra.exe.callback.handle; + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.utils.gui.GUICoreUtils; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * 当前仅处理Error提示,之后有需要再扩展 + * @author Yvan + */ +public class PluginTaskResultErrorDialog extends JDialog { + + private static final Dimension LABEL = new Dimension(60, 90); + + private JPanel contentPane; + + private UILabel errorLabel; + + private UIButton confirmButton; + + private MessageWithLink messageWithLink; + + public PluginTaskResultErrorDialog(Frame parent, MessageWithLink messageWithLink) { + super(parent, true); + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning")); + this.messageWithLink = messageWithLink; + + initContentPane(); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setResizable(false); + this.add(contentPane, BorderLayout.CENTER); + this.setSize(new Dimension( 380, 160)); + GUICoreUtils.centerWindow(this); + } + + /** + * 初始化内容面板 + */ + private void initContentPane() { + this.contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + // error图标 + errorLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/error_tips")); + errorLabel.setPreferredSize(LABEL); + errorLabel.setBorder(BorderFactory.createEmptyBorder(10, 20, 40, 20)); + // 提示内容 + JPanel messagePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + messagePane.add(errorLabel, BorderLayout.WEST); + messagePane.add(messageWithLink, BorderLayout.CENTER); + messagePane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); + this.contentPane.add(messagePane, BorderLayout.CENTER); + // 确定按钮 + confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Button_OK")); + confirmButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hideResult(); + } + }); + JPanel confirmPane = new JPanel(new VerticalFlowLayout()); + confirmPane.add(confirmButton); + confirmPane.setBorder(BorderFactory.createEmptyBorder(0, 160, 10, 0)); + this.contentPane.add(confirmPane, BorderLayout.SOUTH); + } + + public void showResult() { + this.setVisible(true); + } + + public void hideResult() { + this.setVisible(false); + } +} diff --git a/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java b/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java new file mode 100644 index 0000000000..1bcfe3c622 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java @@ -0,0 +1,494 @@ +package com.fr.design.file; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.actions.file.DelFileAction; +import com.fr.design.actions.file.LocateAction; +import com.fr.design.actions.file.RenameAction; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.fun.impl.AbstractTemplateTreeDefineProcessor; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.imenu.UIPopupMenu; +import com.fr.design.gui.itree.filetree.TemplateDirTree; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard; +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirTreeSearchPane; +import com.fr.design.mainframe.toast.DesignerToastMsgUtil; +import com.fr.design.mainframe.toast.ToastMsgDialog; +import com.fr.design.utils.TemplateUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; + +/** + * 默认的模板右键处理方式:包含重命名、复制、黏贴、删除、移动等功能 + */ +public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefineProcessor { + + private UIPopupMenu popupMenu; + private RenameAction renameAction; + private CopyAction copyAction; + private PasteAction pasteAction; + private DelFileAction delFileAction; + private MoveAction moveAction; + private LocateAction locateAction; + + public static DefaultTemplateTreeDefineProcessor getInstance() { + return DefaultTemplateTreeDefineProcessor.HOLDER.singleton; + } + + private static class HOLDER { + private static DefaultTemplateTreeDefineProcessor singleton = new DefaultTemplateTreeDefineProcessor(); + } + + private DefaultTemplateTreeDefineProcessor() { + initPane(); + } + + private void initPane() { + renameAction = new RenameAction(); + copyAction = new CopyAction(); + pasteAction = new PasteAction(); + delFileAction = new DelFileAction(); + moveAction = new MoveAction(); + locateAction = new OpenInTemplateTreeAction(); + //右键菜单 + popupMenu = new UIPopupMenu(); + popupMenu.add(renameAction.createMenuItem()); + popupMenu.addSeparator(); + popupMenu.add(copyAction.createMenuItem()); + popupMenu.add(pasteAction.createMenuItem()); + popupMenu.add(delFileAction.createMenuItem()); + popupMenu.addSeparator(); + popupMenu.add(moveAction.createMenuItem()); + popupMenu.add(locateAction.createMenuItem()); + } + + @Override + public void rightClickAction(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + GUICoreUtils.showPopupMenu(popupMenu, e.getComponent(), e.getX(), e.getY()); + checkButtonEnabled(); + } + } + + private void checkButtonEnabled() { + renameAction.setEnabled(false); + copyAction.setEnabled(false); + pasteAction.setEnabled(false); + delFileAction.setEnabled(false); + moveAction.setEnabled(false); + locateAction.setEnabled(false); + int length = getFileTree().getSelectionCount(); + if (length == 0) { + //没有选中文件时,只能黏贴 + if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) { + pasteAction.setEnabled(true); + } + return; + } + if (length == 1) { + //选中一个时可以,可以重命名、黏贴 + renameAction.setEnabled(true); + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + //搜索模式开启定位当前模板 + locateAction.setEnabled(true); + } + if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) { + pasteAction.setEnabled(true); + } + } + moveAction.setEnabled(true); + delFileAction.setEnabled(true); + copyAction.setEnabled(true); + } + + private TemplateFileTree getFileTree() { + return TemplateTreePane.getInstance().getTemplateFileTree(); + } + + private TemplateDirTree getDirTree() { + return TemplateDirTreePane.getInstance().getTemplateDirTree(); + } + + /** + * 复制功能 + */ + private class CopyAction extends UpdateAction { + + public CopyAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Copy")); + this.setMnemonic('C'); + this.setSmallIcon("/com/fr/design/images/m_edit/copy"); + } + + @Override + public void actionPerformed(ActionEvent e) { + FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); + if (!selectedOperation.access()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + //先记录所有的要复制的模板 + List treeNodeList = TemplateTreeClipboard.getInstance().transferNameObjectArray2Map(getFileTree().getSelectedTreeNodes()); + TemplateTreeClipboard.getInstance().addToClip(treeNodeList); + } + } + + private class OpenInTemplateTreeAction extends LocateAction { + + public OpenInTemplateTreeAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate_Node")); + } + + @Override + public void actionPerformed(ActionEvent e) { + FileNode fileNode = getFileTree().getSelectedFileNode(); + if (fileNode == null) { + return; + } + gotoEditingTemplateLeaf(fileNode.getEnvPath()); + } + } + + /** + * 黏贴功能 + */ + private class PasteAction extends UpdateAction { + + public PasteAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Action_Paste_Name")); + this.setMnemonic('P'); + this.setSmallIcon("/com/fr/design/images/m_edit/paste"); + } + + @Override + public void actionPerformed(ActionEvent e) { + List treeNodeList = TemplateTreeClipboard.getInstance().takeFromClip(); + if (!canPaste(treeNodeList)) { + return; + } + String targetDir = getTargetDir(); + + // 筛选可以黏贴的文件 + ArrayList pasteNodes = new ArrayList<>(); + ArrayList lockedNodes = new ArrayList<>(); + for (ExpandMutableTreeNode treeNode : treeNodeList) { + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, pasteNodes, lockedNodes); + } + if (pasteNodes.isEmpty() || !lockedNodes.isEmpty()) { + //提示:复制的文件都不能黏贴 + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Unlock_File"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + doPaste(targetDir, treeNodeList); + } + + /** + * 检测是否能够黏贴 + * @param treeNodeList + * @return + */ + private boolean canPaste(List treeNodeList) { + if (CollectionUtils.isEmpty(treeNodeList)) { + return false; + } + //确定目标目录并检查权限 + FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); + boolean rootAuthority = true; + if (selectedOperation.getFileNode() == null && selectedOperation instanceof TemplateTreePane) { + //没有选中文件节点时,默认粘贴到根目录下,所以直接检测根目录是否有权限 + ExpandMutableTreeNode root = (ExpandMutableTreeNode) ((TemplateTreePane) selectedOperation).getTemplateFileTree().getModel().getRoot(); + rootAuthority = root.hasFullAuthority(); + } + if (!rootAuthority && !selectedOperation.access()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return false; + } + //检测之前复制的文件是否被打开 + if (TemplateUtils.checkTemplateIsEditing(treeNodeList.toArray(new ExpandMutableTreeNode[0]))) { + return FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + YES_NO_OPTION) == JOptionPane.YES_OPTION; + } + return true; + } + + + private void doPaste(String targetDir, List pasteNodes) { + String targetFile = targetDir; + try { + if (StringUtils.isEmpty(targetDir) || !confirmTargetDir(targetDir, pasteNodes)) { + return; + } + for (ExpandMutableTreeNode node : pasteNodes) { + if (node.getUserObject() instanceof FileNode) { + FileNode fileNode = (FileNode) node.getUserObject(); + String newTargetFile = FileOperationHelper.getInstance().copyFile(fileNode, targetDir); + if (StringUtils.isNotEmpty(newTargetFile)) { + targetFile = newTargetFile; + } + FineLoggerFactory.getLogger().debug("Template: {} paste to {} success.", fileNode.getEnvPath(), targetDir); + } + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e,"Template paste failed.", e.getMessage()); + FineJOptionPane.showConfirmDialog(null, + Toolkit.i18nText("Fine-Design_Basic_Paste_Failure"), + Toolkit.i18nText("Fine-Design_Basic_Error"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.ERROR_MESSAGE); + } + + DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refreshParent(); + LocateAction.gotoEditingTemplateLeaf(targetFile); + } + + /** + * 确认粘贴的目标目录是否是复制文件的子目录,并确认是否继续执行粘贴任务 + * + * @param targetDir 目标文件夹 + * @param pasteNodes 待粘贴的文件 + * @return 是否继续 + */ + private boolean confirmTargetDir(String targetDir, List pasteNodes) { + List filterNodes = pasteNodes.stream().filter( + treeNode -> targetDir.startsWith(((FileNode) (treeNode.getUserObject())).getEnvPath())).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(filterNodes)) { + if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Target_Dir"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + YES_NO_OPTION) != JOptionPane.YES_OPTION) { + return false; + } + //移除待粘贴文件中目标目录的父目录 + pasteNodes.removeAll(filterNodes); + } + return true; + } + } + + + /** + * 移动功能 + */ + private class MoveAction extends UpdateAction { + + public MoveAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Move")); + this.setSmallIcon("/com/fr/design/images/m_edit/move"); + } + + @Override + public void actionPerformed(ActionEvent e) { + FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); + if (!selectedOperation.access()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + // 筛选可以移动的文件 + ArrayList moveNodes = new ArrayList<>(); + ArrayList lockedNodes = new ArrayList<>(); + for (ExpandMutableTreeNode treeNode : getFileTree().getSelectedTreeNodes()) { + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, moveNodes, lockedNodes); + } + + if (!lockedNodes.isEmpty()) { + // 提醒被锁定模板无法移动 + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Unable_Move_Locked_File"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return; + } + + new TemplateMoveDialog(); + } + } + + private class TemplateMoveDialog extends JDialog { + + private static final String DIR = "dir"; + private TemplateDirTreeSearchPane searchPane; + private TemplateDirTreePane dirTreePane; + private UIButton confirmButton; + private String targetFile; + + public TemplateMoveDialog() { + super(DesignerContext.getDesignerFrame(), true); + this.setLayout(new BorderLayout()); + + searchPane = new TemplateDirTreeSearchPane(); + add(searchPane, BorderLayout.NORTH); + + CardLayout card; + JPanel cardPane = new JPanel(card = new CardLayout()); + cardPane.add(TemplateDirTreePane.getInstance(), DIR); + dirTreePane = TemplateDirTreePane.getInstance(); + card.show(cardPane, DIR); + add(cardPane, BorderLayout.CENTER); + cardPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 10)); + dirTreePane.refresh(); + + // 确认按钮,默认就可用 + confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm")); + confirmButton.setPreferredSize(new Dimension(60, 25)); + confirmButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + confirmClose(); + } + }); + confirmButton.setEnabled(true); + + // 取消按钮 + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.setPreferredSize(new Dimension(60, 25)); + + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + + JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); + bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10)); + bottomPanel.add(confirmButton); + bottomPanel.add(cancelButton); + this.add(bottomPanel, BorderLayout.SOUTH); + + this.setSize(new Dimension(600, 400)); + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Move")); + this.setResizable(false); + this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + GUICoreUtils.centerWindow(this); + this.setVisible(true); + } + + private void confirmClose() { + //获取目录树中所选中的文件,并判断是否有权限 + if (!checkBeforeMove()) { + return; + } + boolean moveSuccess = doMove(); + dispose(); + if (moveSuccess) { + ToastMsgDialog dialog = DesignerToastMsgUtil.createPromptDialog(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success")); + dialog.setVisible(true); + + DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh(); + LocateAction.gotoEditingTemplateLeaf(targetFile); + } + } + + private boolean checkBeforeMove() { + if (getDirTree().getSelectionCount() != 0 && !TemplateDirTreePane.getInstance().selectedAccess()) { + FineJOptionPane.showMessageDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return false; + } + if (TemplateUtils.checkSelectedTemplateIsEditing()) { + return FineJOptionPane.showConfirmDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + YES_NO_OPTION) == JOptionPane.YES_OPTION; + } + return true; + } + + private boolean doMove() { + FileNode fileNode = getDirTree().getSelectedFileNode(); + ExpandMutableTreeNode rootTreeNode = (ExpandMutableTreeNode) getDirTree().getModel().getRoot(); + fileNode = fileNode == null ? (FileNode) rootTreeNode.getUserObject() : fileNode; + boolean moveSuccess = true; + try { + //待移动的文件可以有多个 + ExpandMutableTreeNode[] sourceSelected = getFileTree().getSelectedTreeNodes(); + for (ExpandMutableTreeNode treeNode : sourceSelected) { + FileNode sourceFileNode = (FileNode) treeNode.getUserObject(); + targetFile = FileOperationHelper.getInstance().moveFile(sourceFileNode, fileNode.getEnvPath()); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineJOptionPane.showMessageDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Fail"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + moveSuccess = false; + } + return moveSuccess; + } + + @Override + public void dispose() { + TemplateDirTreeSearchManager.getInstance().outOfSearchMode(); + super.dispose(); + } + } + + /** + * 黏贴时确定黏贴的目录 + * + * @return + */ + private String getTargetDir() { + int count = getFileTree().getSelectionCount(); + String targetDir; + if (count == 0) { + targetDir = ProjectConstants.REPORTLETS_NAME; + } else { + FileNode fileNode = getFileTree().getSelectedFileNode(); + targetDir = fileNode.getParent(); + if (fileNode.isDirectory()) { + targetDir = StableUtils.pathJoin(targetDir, fileNode.getName()); + } + } + return targetDir; + } +} diff --git a/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java new file mode 100644 index 0000000000..a3abaf4606 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java @@ -0,0 +1,211 @@ +package com.fr.design.file; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import com.fr.workspace.resource.ResourceIOException; + +import java.util.ArrayList; + +import static javax.swing.JOptionPane.WARNING_MESSAGE; + +/** + * 文件操作的辅助类 + */ +public class FileOperationHelper { + + private static final FileOperationHelper INSTANCE = new FileOperationHelper(); + + public static FileOperationHelper getInstance() { + return INSTANCE; + } + + public String moveFile(FileNode sourceFileNode, String targetDir) { + String targetPath = copyFileAndVcs(sourceFileNode, targetDir); + FileNodeFILE nodeFILE = new FileNodeFILE(sourceFileNode); + if (nodeFILE.exists()) { + if (TemplateResourceManager.getResource().delete(nodeFILE)) { + HistoryTemplateListCache.getInstance().deleteFile(nodeFILE); + FineLoggerFactory.getLogger().info("template {} move to {} success.", sourceFileNode.getEnvPath(), targetDir); + } else { + //删除源文件失败,将复制过去的文件删掉 + TemplateResourceManager.getResource().delete(new FileNodeFILE(new FileNode(targetPath, sourceFileNode.isDirectory()))); + FineLoggerFactory.getLogger().error("template {} move to {} failed.", sourceFileNode.getEnvPath(), targetDir); + throw new ResourceIOException(String.format("template %s move to %s failed", sourceFileNode.getEnvPath(), targetDir)); + } + } + return targetPath; + } + + /** + * 拷贝文件的同时拷贝对应的版本控制文件 + * @param sourceFile 源文件或目录 + * @param targetDir 目标目录 + * @return 复制后的目标文件的路径 + */ + public String copyFileAndVcs(FileNode sourceFile, String targetDir) { + return copyFile(sourceFile, targetDir, true); + } + + /** + * 只拷贝文件, 不拷贝对应的版本控制文件 + * @param sourceFile 源文件或目录 + * @param targetDir 目标目录 + * @return 复制后的目标文件的路径 + */ + public String copyFile(FileNode sourceFile, String targetDir) { + return copyFile(sourceFile, targetDir, false); + } + + /** + * 检测节点是否被锁住了 + * @param node 待检测节点 + * @param dNodes 没有锁住的节点集合 + * @param lNodes 锁住的节点集合 + * @return 是否存在被锁住的文件 + */ + public boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList dNodes, ArrayList lNodes) { + // 自己没锁 + boolean selfEmptyLock = false; + boolean dir = false; + Object userObj = node.getUserObject(); + if (userObj instanceof FileNode) { + FileNode fileNode = (FileNode) userObj; + String lock = fileNode.getLock(); + selfEmptyLock = lock == null || fileNode.getUserID().equals(lock); + dir = fileNode.isDirectory(); + } + + if (!dir) { + if (selfEmptyLock) { + dNodes.add(node); + } else { + lNodes.add(node); + } + return selfEmptyLock; + } + + return checkChildNode(node, dNodes, lNodes, selfEmptyLock); + } + + private boolean checkChildNode(ExpandMutableTreeNode node, ArrayList dNodes, ArrayList lNodes, boolean selfEmptyLock) { + ExpandMutableTreeNode[] children = TemplateTreePane.getInstance().getTemplateFileTree().loadChildTreeNodes(node); + + boolean childrenEmptyLock = true; + + for (ExpandMutableTreeNode child : children) { + childrenEmptyLock = checkFreeOrLock(child, dNodes, lNodes) && childrenEmptyLock; + } + + boolean emptyLock = childrenEmptyLock && selfEmptyLock; + if (emptyLock) { + dNodes.add(node); + } else { + lNodes.add(node); + } + return emptyLock; + } + + private String copyFile(FileNode sourceFile, String targetDir, boolean withCopyVcs) { + String sourcePath = sourceFile.getEnvPath(); + if (!TemplateResourceManager.getResource().exist(sourcePath)) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Source_File_Not_Exist", sourcePath), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return StringUtils.EMPTY; + } + String name = getNoRepeatedName4Paste(targetDir, sourceFile); + String targetFile = StableUtils.pathJoin(targetDir, name); + if (sourceFile.isDirectory()) { + copyDir(sourcePath, targetFile, withCopyVcs); + } else { + copyFile(sourcePath, targetFile, withCopyVcs); + } + return targetFile; + } + + private void copyDir(String sourceDir, String targetDir, boolean withCopyVcs) { + FileNode[] fileNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(sourceDir); + if (ArrayUtils.isEmpty(fileNodes)) { + //空目录:相当于新建一个目录 + if (!DesignerFrameFileDealerPane.getInstance().getSelectedOperation().mkdir(targetDir)) { + throw new ResourceIOException(String.format("copy dir failed: from %s to %s.", sourceDir, targetDir)); + } + return; + } + for (FileNode fileNode : fileNodes) { + if (fileNode.isDirectory()) { + copyDir(StableUtils.pathJoin(fileNode.getParent(), fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()), withCopyVcs); + } else { + copyFile(StableUtils.pathJoin(sourceDir, fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()), withCopyVcs); + } + } + } + + private void copyFile(String sourcePath, String targetPath, boolean withCopyVcs) { + //检查源文件是不是还存在 + if (!WorkContext.getWorkResource().exist(sourcePath)) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Source_File_Not_Exist", sourcePath), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + } else { + if (!TemplateResourceManager.getResource().copy(sourcePath, targetPath)) { + throw new ResourceIOException(String.format("copy file failed, from %s to %s", sourcePath, targetPath)); + } else if (withCopyVcs){ + sourcePath = sourcePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); + targetPath = targetPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); + VcsHelper.getInstance().moveVcs(sourcePath, targetPath); + } + } + } + + /** + * 重名处理 + * + * @param targetDir + * @param sourceFile + * @return + */ + private String getNoRepeatedName4Paste(String targetDir, FileNode sourceFile) { + String oldName = sourceFile.getName(); + while (isNameRepeaded(targetDir, oldName)) { + if (sourceFile.isDirectory()) { + //目录重名 + oldName = oldName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data"); + } else { + int index = oldName.lastIndexOf("."); + if (index > 0) { + String oName = oldName.substring(0, index); + oName = oName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data"); + oldName = oName.concat(oldName.substring(index)); + } + } + } + return oldName; + } + + private boolean isNameRepeaded(String targetDir, String name) { + FileNode[] fileNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(targetDir); + for (int i = 0; i < fileNodes.length; i++) { + if (ComparatorUtils.equals(name, fileNodes[i].getName())) { + return true; + } + } + return false; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/file/FileOperations.java b/designer-base/src/main/java/com/fr/design/file/FileOperations.java index 6509142a44..8c428af5e9 100644 --- a/designer-base/src/main/java/com/fr/design/file/FileOperations.java +++ b/designer-base/src/main/java/com/fr/design/file/FileOperations.java @@ -29,6 +29,11 @@ public interface FileOperations { */ void refresh(); + /** + * 刷新父目录 + */ + void refreshParent(); + /** * 删除文件 */ @@ -82,7 +87,8 @@ public interface FileOperations { * * @param newName 原名 * @param suffix 后缀名 + * @param baseOnSelf 检验目录时,是基于自身目录的子节点还是基于父目录的子节点进行校验 * @return 是否存在 */ - boolean duplicated(String newName, String suffix); + boolean duplicated(String newName, String suffix, boolean baseOnSelf); } \ No newline at end of file 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 52fb1bcfa2..86820aa227 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 @@ -1,40 +1,33 @@ package com.fr.design.file; import com.fr.base.chart.chartdata.CallbackEvent; -import com.fr.base.io.BaseBook; import com.fr.design.DesignerEnvManager; import com.fr.design.base.mode.DesignModeContext; import com.fr.design.base.mode.DesignerMode; import com.fr.design.data.DesignTableDataManager; -import com.fr.design.file.filter.ClassFilter; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.JNullTemplate; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JVirtualTemplate; -import com.fr.design.module.DesignModuleFactory; 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; import com.fr.plugin.context.PluginContext; -import com.fr.plugin.manage.PluginManager; import com.fr.stable.CoreConstants; import com.fr.stable.StringUtils; import com.fr.third.org.apache.commons.io.FilenameUtils; +import org.jetbrains.annotations.Nullable; -import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.Set; -import javax.swing.SwingWorker; /** * 历史模板缓存 @@ -47,7 +40,8 @@ public class HistoryTemplateListCache implements CallbackEvent { private static final int DEAD_LINE = DesignerEnvManager.getEnvManager().getCachingTemplateLimit(); private List> historyList; private JTemplate editingTemplate; - private SwingWorker stashWorker; + + private JTemplate openingOrEditingTemplate; public static HistoryTemplateListCache getInstance() { return Holder.INSTANCE; @@ -81,7 +75,7 @@ public class HistoryTemplateListCache implements CallbackEvent { historyList.remove(contains(selected)); selected.getEditingFILE().closeTemplate(); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Closed_Warn_Text", selected.getEditingFILE().getName())); - MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList); + MultiTemplateTabPane.getInstance().refreshOpenedTemplate(historyList); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } @@ -107,7 +101,20 @@ public class HistoryTemplateListCache implements CallbackEvent { } } + public void setCurrentOpeningTemplate(JTemplate jt) { + this.openingOrEditingTemplate = jt; + } + + public JTemplate getCurrentOpeningOrEditingTemplate() { + return openingOrEditingTemplate; + } + /** + * 需要使用 {@link JTemplate#isValid(JTemplate)} 来判断空 + * + * @return 当前正在编辑的模板 + */ + @Nullable public JTemplate getCurrentEditingTemplate() { return this.editingTemplate; } @@ -118,15 +125,19 @@ public class HistoryTemplateListCache implements CallbackEvent { */ public void setCurrentEditingTemplate(JTemplate jt) { this.editingTemplate = jt; + this.openingOrEditingTemplate = jt; + + if (!JTemplate.isValid(jt)) { + return; + } //如果当前历史面板中没有 - if (contains(jt) == -1) { addHistory(); } - MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList); + MultiTemplateTabPane.getInstance().refreshOpenedTemplate(historyList); //设置tab栏为当前选中的那一栏 if (editingTemplate != null) { - MutilTempalteTabPane.getInstance().setSelectedIndex(contains(jt)); + MultiTemplateTabPane.getInstance().setSelectedIndex(contains(jt)); } } @@ -254,12 +265,16 @@ public class HistoryTemplateListCache implements CallbackEvent { for (int i = 0; i < vCount; i++) { JTemplate overTemplate = historyList.get(i); - if (overTemplate.getEditingFILE().exists() && overTemplate.isALLSaved() && overTemplate != editingTemplate) { + boolean replaceWithJVirtualTemplate = overTemplate.getEditingFILE().exists() + && overTemplate.isALLSaved() + && overTemplate != editingTemplate + && overTemplate.checkEnable(); + if (replaceWithJVirtualTemplate) { closeVirtualSelectedReport(overTemplate); historyList.set(i, new JVirtualTemplate(overTemplate.getEditingFILE())); } } - MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList); + MultiTemplateTabPane.getInstance().refreshOpenedTemplate(historyList); } @@ -282,7 +297,7 @@ public class HistoryTemplateListCache implements CallbackEvent { int index = iterator.nextIndex(); if (size == index + 1 && index > 0) { //如果删除的是后一个Tab,则定位到前一个 - MutilTempalteTabPane.getInstance().setSelectedIndex(index - 1); + MultiTemplateTabPane.getInstance().setSelectedIndex(index - 1); } } } @@ -292,13 +307,13 @@ public class HistoryTemplateListCache implements CallbackEvent { DesignerContext.getDesignerFrame().addAndActivateJTemplate(); } - JTemplate selectedFile = MutilTempalteTabPane.getInstance().getSelectedFile(); + JTemplate selectedFile = MultiTemplateTabPane.getInstance().getSelectedFile(); if (!isCurrentEditingFile(selectedFile.getPath())) { //如果此时面板上的实时刷新的selectedIndex得到的和历史的不一样 DesignerContext.getDesignerFrame().activateJTemplate(selectedFile); } - MutilTempalteTabPane.getInstance().repaint(); + MultiTemplateTabPane.getInstance().repaint(); } @@ -308,7 +323,7 @@ public class HistoryTemplateListCache implements CallbackEvent { JTemplate template; template = this.getCurrentEditingTemplate(); - if (template != null) { + if (template != null && !(template instanceof JNullTemplate)) { String editingPath = FilenameUtils.standard(template.getEditingFILE().getPath()); if (isDir ? editingPath.contains(from + CoreConstants.SEPARATOR) : editingPath.equals(from)) { FILE renameFile = template.getEditingFILE(); @@ -341,14 +356,7 @@ public class HistoryTemplateListCache implements CallbackEvent { * @see HistoryTemplateListCache#load() */ public void stash() { - stashWorker = new SwingWorker() { - @Override - protected Boolean doInBackground() throws Exception { - _stash(); - return true; - } - }; - stashWorker.execute(); + _stash(); } private void _stash() { @@ -361,31 +369,14 @@ public class HistoryTemplateListCache implements CallbackEvent { int size = historyList.size(); for (int i = 0; i < size; i++) { JTemplate template = historyList.get(i); - FILE file = template.getEditingFILE(); - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - BaseBook target = template.getTarget(); - if (target != null) { - target.export(outputStream); - stashFILEMap.put(i, new StashedFILE(file, outputStream.toByteArray())); - } - // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + FILE file = template.templateToStashFile4Envchange(); + if (file != null) { + stashFILEMap.put(i, file); } } FineLoggerFactory.getLogger().info("Env Change Template Stashed."); } - private boolean checkStash() { - try { - return stashWorker.get(); - } catch (Exception e) { - FineLoggerFactory.getLogger().debug(e.getMessage(), e); - return false; - } - } - /** * 切换环境前将正在编辑的模板暂存起来后,在新环境重新读取一遍 *

@@ -394,9 +385,6 @@ public class HistoryTemplateListCache implements CallbackEvent { * @see HistoryTemplateListCache#stash() */ public void load() { - if (!checkStash()) { - return; - } FineLoggerFactory.getLogger().info("Env Change Template Loading..."); if (stashFILEMap != null && stashFILEMap.size() != 0) { int size = historyList.size(); @@ -410,7 +398,8 @@ public class HistoryTemplateListCache implements CallbackEvent { } FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName()); JTemplate template = historyList.get(i); - template.refreshResource(stashedFile); + // 切换环境后,刷新资源并且将暂存的FILE替换到template中 + template.refreshResourceAndEditingFILE(stashedFile); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } @@ -456,21 +445,10 @@ public class HistoryTemplateListCache implements CallbackEvent { for (int i = 0; i < size; i++) { JTemplate template = historyList.get(i); FILE file = template.getEditingFILE(); - boolean needReload = context == null || needReloadTemplate(context, template); - if (needReload) { - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - BaseBook target = template.getTarget(); - if (target != null) { - FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName()); - target.export(outputStream); - FILE stashedFile = new StashedFILE(file, outputStream.toByteArray()); - template.refreshResource(stashedFile); - } - // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } + FILE stashFile = template.templateToStashFile(); + if (stashFile != null) { + FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName()); + template.refreshResource(stashFile); } } FineLoggerFactory.getLogger().info("Plugin env change reload all template ended"); @@ -492,33 +470,11 @@ public class HistoryTemplateListCache implements CallbackEvent { _reloadAllEditingTemplate(null); } - private boolean needReloadTemplate(PluginContext context, JTemplate template) { - BaseBook baseBook = template.getTarget(); - if (baseBook != null) { - String name = template.getEditingFILE().getName(); - String pluginId = context.getID(); - long start = System.currentTimeMillis(); - Set set = ClassHelper.getClassLoadersByFilter(baseBook, ClassFilter.getInstance()); - FineLoggerFactory.getLogger().info("{} find plugin classloader spend: {} ms", name, (System.currentTimeMillis() - start)); - if (set != null) { - for (ClassLoader classLoader : set) { - if (ComparatorUtils.equals(pluginId, PluginManager.detectLeakingPlugin(classLoader))) { - return true; - } - } - } else { - // set为null说明 检测classloader 这里返回true直接刷新 兜底行为 - return true; - } - } - return false; - } - public void replaceCurrentEditingTemplate(JTemplate jt) { int index = contains(this.editingTemplate); this.editingTemplate = jt; historyList.set(index, jt); - MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList); - MutilTempalteTabPane.getInstance().setSelectedIndex(contains(jt)); + MultiTemplateTabPane.getInstance().refreshOpenedTemplate(historyList); + MultiTemplateTabPane.getInstance().setSelectedIndex(contains(jt)); } } diff --git a/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java new file mode 100644 index 0000000000..8e302fd977 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java @@ -0,0 +1,1255 @@ +package com.fr.design.file; + + +import com.fr.base.BaseUtils; +import com.fr.base.GraphHelper; +import com.fr.base.svg.IconUtils; +import com.fr.base.vcs.DesignerMode; +import com.fr.design.actions.UpdateAction; +import com.fr.design.actions.file.LocateAction; +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.imenu.UIMenuItem; +import com.fr.design.gui.imenu.UIPopupMenu; +import com.fr.design.gui.imenu.UIScrollPopUpMenu; +import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.TemplateSavingChecker; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.TemplateUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.design.utils.gui.GUIPaintUtils; +import com.fr.design.worker.WorkerManager; +import com.fr.design.worker.save.CallbackSaveWorker; +import com.fr.file.FILE; +import com.fr.file.FileNodeFILE; +import com.fr.general.ComparatorUtils; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.Constants; +import com.fr.third.javax.annotation.Nonnull; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.lock.TplOperator; + +import javax.swing.BorderFactory; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.MenuElement; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicMenuItemUI; +import java.awt.AWTEvent; +import java.awt.AlphaComposite; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.AWTEventListener; +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.awt.event.MouseMotionListener; +import java.awt.geom.Arc2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.RoundRectangle2D; +import java.util.List; + +import static com.fr.design.dialog.FineJOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.OK_CANCEL_OPTION; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.WARNING_MESSAGE; + +/** + * 改个名字,一个拼写 n 个错误 + * + * @author daisy + * @version 11.0 + *

+ * created by daisy on 2013/08/05 + **/ +public class MultiTemplateTabPane extends JComponent { + + private static Icon LIST_DOWN = IconUtils.readIcon("/com/fr/design/standard/list/list"); + private static Icon MOUSE_OVER_LIST_DOWN = IconUtils.readIcon("/com/fr/design/standard/list/list_pressed.svg"); + private static Icon MOUSE_PRESS_LIST_DOWN = IconUtils.readIcon("/com/fr/design/standard/list/list_pressed.svg"); + private static Icon CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close"); + private static Icon MOUSE_OVER_CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close_mouseover.svg"); + private static Icon MOUSE_PRESS_CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close_press.svg"); + private static final Icon WHITE_SAVING_CLOSE_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/file/white_saving_close.gif")); + private static final Icon GREY_SAVING_CLOSE_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/file/grey_saving_close.gif")); + private static final String ELLIPSIS = "..."; + private static final int GAP = 5; + private static final int SMALLGAP = 3; + private static final int LIST_BUTTON_WIDTH = 34; + private static final int HEIGHT = 26; + private static final int LIST_DOWN_HEIGHT = 25; + private static final double CORNOR_RADIUS = 0.0; + //选了30度和60度的特殊角度的x,y作为经过的两个点的坐标 + private static final double SPECIAL_LOCATION_1 = 2.5; + private static final double SPECIAL_LOCATION_2 = 4.330127; + private static final int ICON_WIDTH = 22; + + + //每个标签页的最大的长度和最小长度。这些长度均为均分 + + private static final int MAXWIDTH = 240; + private static final int MINWIDTH = 100; + + + private static MultiTemplateTabPane THIS; + //用于存放工作簿 + private java.util.List> openedTemplate; + //选中的Tab项 + private int selectedIndex = 0; + // + private int mouseOveredIndex = -1; + + //tab栏可以放下的每个tab的实际宽度 + private int realWidth = MAXWIDTH; + + + //当前标签页栏存放的所有标签页的index + private int minPaintIndex = 0; + private int maxPaintIndex = 0; + + //每个关闭图标的起始位置 + private int[] startX; + + private boolean[] isNeedToolTips; + + //记录关闭按钮的状态 + private int closeIconIndex = -1; + private boolean isCloseCurrent = false; + private Icon clodeMode = CLOSE; + private Icon listDownMode = LIST_DOWN; + private boolean isShowList = false; + + //自动新建的模板B若没有进行任何编辑,切换到其他 + // + // 模板时,模板B会自动关闭 + private JTemplate temTemplate = null; + + + public static MultiTemplateTabPane getInstance() { + if (THIS == null) { + THIS = new MultiTemplateTabPane(); + } + return THIS; + } + + + /** + * 多工作簿面板 + */ + public MultiTemplateTabPane() { + this.setLayout(new BorderLayout(0, 0)); + this.addMouseListener(new MultiTemplateTabMouseListener()); + this.addMouseMotionListener(new MultiTemplateTabMouseMotionListener()); + this.setBorder(null); + this.setForeground(new Color(58, 56, 58)); + this.setFont(DesignUtils.getDefaultGUIFont().applySize(12)); + openedTemplate = HistoryTemplateListCache.getInstance().getHistoryList(); + selectedIndex = openedTemplate.size() - 1; + AWTEventListener awt = new AWTEventListener() { + @Override + public void eventDispatched(AWTEvent event) { + if (event instanceof MouseEvent) { + MouseEvent mv = (MouseEvent) event; + if (mv.getClickCount() > 0 && !ComparatorUtils.equals(mv.getSource(), MultiTemplateTabPane.this)) { + isShowList = false; + } + } + } + + }; + java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(awt, AWTEvent.MOUSE_EVENT_MASK); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + int tplIndex = getTemplateIndex(e.getX()); + if (tplIndex > -1) { + UIPopupMenu menu = new UIPopupMenu(); + menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0)); + + for (CloseOption option : CloseOption.values()) { + menu.add(new UIMenuItem(new RightMenuCloseAction(option, tplIndex))); + } + menu.add(new CloseMenuItemJSeparator()); + menu.add(new UIMenuItem(new OpenInTemplateTreeAction(tplIndex))); + + int height = 0; + for (MenuElement subElement : menu.getSubElements()) { + if (subElement instanceof CloseMenuItemJSeparator) { + height += 10; + } else { + height += 25; + } + } + //根据当前i18n语言环境,动态调整popupMenu的宽度 + menu.setPreferredSize(new Dimension((int) DesignSizeI18nManager.getInstance(). + i18nDimension("com.fr.design.file.MultiTemplateTabPane.popUpMenu").getWidth(), height)); + GUICoreUtils.showPopupMenu(menu, MultiTemplateTabPane.getInstance(), e.getX(), MultiTemplateTabPane.getInstance().getY() - 1 + MultiTemplateTabPane.getInstance().getHeight()); + } + } + } + }); + } + + enum CloseOption { + Left(Toolkit.i18nText("Fine-Design_Close_templates_To_The_Left")) { + @Override + boolean shouldClose(int tplIndex, int i) { + return i < tplIndex; + } + }, + Right(Toolkit.i18nText("Fine-Design_Close_templates_To_The_Right")) { + @Override + boolean shouldClose(int tplIndex, int i) { + return i > tplIndex; + } + }, + All(Toolkit.i18nText("Fine-Design_Close_All_templates")), + Others(Toolkit.i18nText("Fine-Design_Close_Other_templates")) { + @Override + boolean shouldClose(int tplIndex, int i) { + return i != tplIndex; + } + }; + + + String optionName; + + CloseOption(String optionName) { + this.optionName = optionName; + } + + boolean shouldClose(int tplIndex, int i) { + return true; + } + } + + private static class CloseMenuItemJSeparator extends JSeparator { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.height = 1; + return d; + } + + @Override + public Color getForeground() { + return UIConstants.PRESSED_DARK_GRAY; + } + } + + + private class OpenInTemplateTreeAction extends LocateAction { + + int tplIndex; + + public OpenInTemplateTreeAction(int tplIndex) { + this.tplIndex = tplIndex; + this.setName(Toolkit.i18nText("Fine-Design_Open_In_Template_Tree")); + } + + @Override + public void actionPerformed(ActionEvent e) { + //处于搜索模式时,先退出搜索模式,再定位 + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + TemplateTreeSearchManager.getInstance().outOfSearchMode(); + TemplateTreePane.getInstance().refreshDockingView(); + } + JTemplate template = openedTemplate.get(this.tplIndex); + locateTemplate(template); + } + + private void locateTemplate(JTemplate template) { + FILE currentTemplate = template.getEditingFILE(); + //模板不属于当前环境,跟预览一样先提示保存,再定位模板 + //如果是拖拽进来的模板单单用exist不能判断,这边参考预览的判断逻辑(browserTemplate),补充一下 + if (!currentTemplate.exists() || !(currentTemplate instanceof FileNodeFILE)) { + int selVal = showConfirmDialog( + DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Web_Preview_Message"), + Toolkit.i18nText("Fine-Design_Basic_Preview_Tool_Tips"), + OK_CANCEL_OPTION, + WARNING_MESSAGE + ); + if (OK_OPTION == selVal) { + CallbackSaveWorker worker = template.saveAs(); + worker.start(template.getRuntimeId()); + worker.addSuccessCallback(new Runnable() { + @Override + public void run() { + gotoEditingTemplateLeaf(template.getPath()); + } + }); + } + } else { + gotoEditingTemplateLeaf(template.getPath()); + } + } + } + + private class RightMenuCloseAction extends UpdateAction { + + CloseOption option; + int tplIndex = -1; + + public RightMenuCloseAction(CloseOption option, int tplIndex) { + this.option = option; + this.setName(option.optionName); + this.tplIndex = tplIndex; + } + + + @Override + public void actionPerformed(ActionEvent e) { + SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false); + if (saveSomeTempaltePane.showSavePane()) { + + JTemplate[] templates = new JTemplate[openedTemplate.size()]; + for (int i = 0; i < openedTemplate.size(); i++) { + templates[i] = openedTemplate.get(i); + } + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + closeTemplate(templates, currentTemplate); + + if (option == CloseOption.All) { + DesignerContext.getDesignerFrame().addAndActivateJTemplate(); + } else { + DesignerContext.getDesignerFrame().activateJTemplate(currentTemplate); + } + + MultiTemplateTabPane.getInstance().repaint(); + } + } + + private void closeTemplate(JTemplate[] templates, JTemplate currentTemplate) { + for (int i = 0; i < templates.length; i++) { + if (option.shouldClose(tplIndex, i)) { + JTemplate jTemplate = templates[i]; + if (jTemplate == currentTemplate) { + currentTemplate = option == CloseOption.All ? null : templates[tplIndex]; + } + //判断关闭的模板是不是格式刷的被参照的模板 + openedTemplate.remove(jTemplate); + if (jTemplate != currentTemplate) { + MultiTemplateTabPane.getInstance().closeFormat(jTemplate); + HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate); + closeAndFreeLock(jTemplate); + } + } + } + } + + private void closeAndFreeLock(@Nonnull JTemplate template) { + FILE file = template.getEditingFILE(); + // 只有是环境内的文件,才执行释放锁 + if (file != null && file.isEnvFile()) { + // release lock + WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(file.getPath()); + } + } + } + + public JTemplate getSelectedFile() { + if (openedTemplate.size() == selectedIndex) { + selectedIndex = Math.max(--selectedIndex, 0); + } + return openedTemplate.get(selectedIndex); + } + + + /** + * 关闭掉当前已打开文件列表中指定的文件 + * + * @param file 指定的文件 + */ + public void closeFileTemplate(FILE file) { + for (JTemplate temp : openedTemplate) { + if (ComparatorUtils.equals(file, temp.getEditingFILE())) { + closeSpecifiedTemplate(temp); + break; + } + } + + } + + @Override + public Dimension getPreferredSize() { + Dimension dimension = super.getPreferredSize(); + dimension.height = HEIGHT; + return dimension; + } + + private UIMenuItem initCloseOther() { + UIMenuItem closeOther = new UIMenuItem(Toolkit.i18nText("Fine-Design_Basic_FS_Close_Other_Templates")); + // Yvan: 英文下文本显示不全,后续发现如果将模板名设置的比较短,其它语言也会出现显示不全的问题,所以设置一下文本水平居中 + closeOther.setHorizontalAlignment(SwingConstants.CENTER); + setListDownItemPreferredSize(closeOther); + closeOther.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (openedTemplate.size() == 1) { + return; + } + if (!TemplateSavingChecker.check()) { + return; + } + SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false); + //点击关闭其他模板,并且点击确定保存 + if (saveSomeTempaltePane.showSavePane()) { + JTemplate[] panes = new JTemplate[openedTemplate.size()]; + for (int i = 0; i < openedTemplate.size(); i++) { + panes[i] = openedTemplate.get(i); + } + for (int i = 0; i < panes.length; i++) { + if (i != selectedIndex) { + JTemplate jTemplate = panes[i]; + //判断关闭的模板是不是格式刷的被参照的模板 + openedTemplate.remove(jTemplate); + closeFormat(jTemplate); + HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate); + closeAndFreeLock(jTemplate); + } + } + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + HistoryTemplateListCache.getInstance().removeAllHistory(); + DesignerContext.getDesignerFrame().activateJTemplate(currentTemplate); + THIS.repaint(); + } + //如果取消保存了,则不关闭其他模板 + } + }); + if (openedTemplate.size() == 1) { + closeOther.setEnabled(false); + } + return closeOther; + } + + + private UIMenuItem[] createListDownTemplate() { + UIMenuItem[] templates = new UIMenuItem[openedTemplate.size()]; + for (int i = 0; i < openedTemplate.size(); i++) { + final int index = i; + final JTemplate tem = openedTemplate.get(i); + templates[i] = new UIMenuItem(tempalteShowName(tem), tem.getIcon()); + templates[i].setUI(new UIListDownItemUI()); + setListDownItemPreferredSize(templates[i]); + if (i == selectedIndex) { + //画选中的高亮 + templates[i].setBackground(UIConstants.SHADOW_CENTER); + } + templates[i].addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + selectedIndex = index; + tem.activeNewJTemplate(); + } + }); + } + return templates; + } + + private void setListDownItemPreferredSize(UIMenuItem item) { + Dimension dimension = item.getPreferredSize(); + dimension.height = LIST_DOWN_HEIGHT; + item.setPreferredSize(dimension); + } + + + private String tempalteShowName(JTemplate template) { + String name = TemplateUtils.createLockeTemplatedName(template, template.getTemplateName()); + if (!template.isSaved() && !name.endsWith(" *")) { + name += " *"; + } + return name; + } + + /** + * 刷新打开模板 + * + * @param history 模板 + */ + public void refreshOpenedTemplate(List> history) { + openedTemplate = history; + } + + public void setTemTemplate(JTemplate auotCreate) { + temTemplate = auotCreate; + } + + + private void showListDown() { + + UIScrollPopUpMenu menu = new UIScrollPopUpMenu(); + menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0)); + menu.add(initCloseOther()); + JSeparator separator = new JSeparator() { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.height = 1; + return d; + } + }; + menu.add(new JPanel() { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.height = 1; + return d; + } + }); + separator.setForeground(UIConstants.LINE_COLOR); + menu.add(separator); + menu.add(new JPanel() { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.height = 1; + return d; + } + }); + UIMenuItem[] items = createListDownTemplate(); + for (int i = 0; i < items.length; i++) { + menu.add(items[i]); + } + GUICoreUtils.showPopupMenu(menu, MultiTemplateTabPane.getInstance(), MultiTemplateTabPane.getInstance().getWidth() - menu.getPreferredSize().width, getY() - 1 + getHeight()); + } + + + public void setSelectedIndex(int index) { + selectedIndex = index; + } + + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + double maxWidth = getWidth() - LIST_BUTTON_WIDTH * 1.0D; //最大宽度 + Graphics2D g2d = (Graphics2D) g; + paintBackgroundAndLine(g2d, maxWidth); + } + + + @Override + public void paint(Graphics g) { + //不可见时,按钮.4f透明 + AlphaComposite composite = DesignerMode.isVcsMode() + ? AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f) + : (AlphaComposite) ((Graphics2D) g).getComposite(); + ((Graphics2D) g).setComposite(composite); + super.paint(g); + } + + private void paintBackgroundAndLine(Graphics2D g2d, double maxWidth) { + paintDefaultBackground(g2d); + //最多能画的个数 + int maxTemplateNum = (int) (maxWidth) / MINWIDTH; + //计算开始画的最小模板index和最大模板index + calMinAndMaxIndex(maxTemplateNum); + calculateRealAverageWidth(maxWidth, maxTemplateNum); + int maxStringlength = calculateStringMaxLength(); + if (selectedIndex >= openedTemplate.size()) { + selectedIndex = openedTemplate.size() - 1; + } + if (selectedIndex < 0) { + selectedIndex = 0; + } + double templateStartX = 0; + startX = new int[maxPaintIndex - minPaintIndex + 1]; + isNeedToolTips = new boolean[maxPaintIndex - minPaintIndex + 1]; + + //从可以开始展示在tab面板上的tab开始画 + for (int i = minPaintIndex; i <= maxPaintIndex; i++) { + JTemplate template = openedTemplate.get(i); + Icon icon = template.getIcon(); + String name = tempalteShowName(template); + //如果tab名字的长度大于最大能显示的英文字符长度,则进行省略号处理 + if (getStringWidth(name) > maxStringlength) { + name = getEllipsisName(name, maxStringlength); + isNeedToolTips[i - minPaintIndex] = true; + } else { + isNeedToolTips[i - minPaintIndex] = false; + } + + Icon selectedIcon; + if (i == closeIconIndex) { + selectedIcon = clodeMode; + } else { + selectedIcon = CLOSE; + } + if (i == selectedIndex) { + if (template.isSaving()) { + selectedIcon = WHITE_SAVING_CLOSE_ICON; + } + startX[i - minPaintIndex] = paintSelectedTab(g2d, icon, templateStartX, name, selectedIcon); + } else { + if (template.isSaving()) { + selectedIcon = GREY_SAVING_CLOSE_ICON; + } + boolean isLeft = i < selectedIndex; + startX[i - minPaintIndex] = paintUnSelectedTab(g2d, icon, templateStartX, name, selectedIcon, isLeft, mouseOveredIndex, i); + } + templateStartX += realWidth; + } + + if (!DesignerMode.isVcsMode()) { + paintListDown(g2d, maxWidth); + } + paintUnderLine(templateStartX, maxWidth, g2d); + } + + + private void paintUnderLine(double templateStartX, double maxWidth, Graphics2D g2d) { + //画下面的那条线 + if (templateStartX < maxWidth) { + GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, 2); + generalPath.moveTo((float) templateStartX, (float) (getHeight() - 1.0D)); + generalPath.lineTo((float) maxWidth, (float) (getHeight() - 1.0D)); + g2d.fill(generalPath); + //TODO hzzz delete +// g2d.setPaint(UIConstants.LINE_COLOR); +// g2d.draw(new Line2D.Double((float) templateStartX, getHeight() - 1, (float) maxWidth + LIST_BUTTON_WIDTH, getHeight() - 1)); + } + } + + private void paintDefaultBackground(Graphics2D g2d) { + //画默认背景 + g2d.setPaint(new GradientPaint(1, 1, UIConstants.TEMPLATE_TAB_PANE_BACKGROUND, 1, (float) (getHeight() - 1.0D), UIConstants.TEMPLATE_TAB_PANE_BACKGROUND)); + g2d.fillRect(0, 0, getWidth(), getHeight()); + } + + + private void paintListDown(Graphics2D g2d, double maxWidth) { + int x = (int) maxWidth + (LIST_BUTTON_WIDTH - listDownMode.getIconWidth()) / 2; + int y = (getHeight() - listDownMode.getIconHeight()) / 2; + listDownMode.paintIcon(this, g2d, x, y); + } + + /** + * 判断tab文字的长度大于能装下的最大文字长度,要用省略号 + * + * @param name + * @param maxStringlength + * @return + */ + private String getEllipsisName(String name, int maxStringlength) { + + //若是名字长度大于能显示的长度,那能显示的文字的最大长度还要减去省略号的最大长度 +// int maxellipsislength = maxStringlength - ELLIPSIS.length(); + int ellipsisWidth = getStringWidth(ELLIPSIS); + int leftkeyPoint = 0; + int rightKeyPoint = name.length() - 1; + int leftStrWidth = 0; + int rightStrWidth = 0; + while (leftStrWidth + rightStrWidth + ellipsisWidth < maxStringlength) { + if (leftStrWidth <= rightStrWidth) { + leftkeyPoint++; + } else { + rightKeyPoint--; + } + leftStrWidth = getStringWidth(name.substring(0, leftkeyPoint)); + rightStrWidth = getStringWidth(name.substring(rightKeyPoint)); + + if (leftStrWidth + rightStrWidth + ellipsisWidth > maxStringlength) { + if (leftStrWidth <= rightStrWidth) { + rightKeyPoint++; + } + break; + } + } + + return name.substring(0, leftkeyPoint) + ELLIPSIS + name.substring(rightKeyPoint); + } + + private void calMinAndMaxIndex(int maxTemplateNum) { + //如果个数大于最多能容纳的个数,则多余的进行处理 + if (openedTemplate.size() > maxTemplateNum) { + //所点击列表中的标签页处在标签页栏最后一个标签页之后,则标签页栏左移至所点击标签页出现 + if (selectedIndex >= maxPaintIndex) { + minPaintIndex = selectedIndex - maxTemplateNum + 1; + maxPaintIndex = selectedIndex; + if (minPaintIndex <= 0) { + minPaintIndex = 0; + maxPaintIndex = maxTemplateNum - 1; + } + } else if (selectedIndex <= minPaintIndex) { + //所点击列表中的标签页处在标签页栏第一个标签页之前,则标签页栏右移至所点击标签页出现 + minPaintIndex = selectedIndex; + maxPaintIndex = minPaintIndex + maxTemplateNum - 1; + if (maxPaintIndex > openedTemplate.size() - 1) { + maxPaintIndex = openedTemplate.size() - 1; + } + } else { + if (selectedIndex >= openedTemplate.size() - 1) { + selectedIndex = openedTemplate.size() - 1; + maxPaintIndex = selectedIndex; + minPaintIndex = selectedIndex - maxTemplateNum + 1; + } else { + maxPaintIndex = minPaintIndex + maxTemplateNum - 1; + if (maxPaintIndex > openedTemplate.size() - 1) { + maxPaintIndex = openedTemplate.size() - 1; + } + } + } + } else { + minPaintIndex = 0; + maxPaintIndex = openedTemplate.size() - 1; + } + } + + + //个数小于最多能容纳的个数的情况下,看看宽度每个要画多少 + private void calculateRealAverageWidth(double maxwidth, int templateNum) { + + int num = openedTemplate.size() > templateNum ? templateNum : openedTemplate.size(); + realWidth = (int) (maxwidth / (num)); + if (realWidth > MAXWIDTH) { + realWidth = MAXWIDTH; + } else if (realWidth < MINWIDTH) { + //平均下来每个的宽度小于最小宽度 + realWidth = MINWIDTH; + } + } + + /** + * 计算过长度之后的每个tab的能接受的文字的英文字符数 + * + * @return + */ + private int calculateStringMaxLength() { + return realWidth - 3 * GAP - ICON_WIDTH - SMALLGAP - CLOSE.getIconWidth(); + + } + + private int getStringWidth(String str) { + return GraphHelper.getFontMetrics(this.getFont()).stringWidth(str); + } + + + /** + * 画选中的tab + * + * @param g2d + * @param sheeticon + * @param templateStartX + * @param sheetName + * @param closeIcon + * @return + */ + private int paintSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon) { + double[] x = {templateStartX, templateStartX, templateStartX + realWidth, templateStartX + realWidth, templateStartX}; + double[] y = {1, getHeight() + 1, getHeight() + 1, 1, 1}; + RoundRectangle2D.Double rect1 = new RoundRectangle2D.Double(templateStartX, 1, this.getWidth(), this.getHeight(), 7, 7); + g2d.setPaint(new GradientPaint(1, 1, UIConstants.SELECT_TAB, 1, (float) (getHeight() - 1.0D), UIConstants.SELECT_TAB)); + //选了30度和60度的特殊角度的x,y作为经过的两个点的坐标 + double specialLocation1 = 2.5; + double specialLocation2 = 4.330127; + GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, x.length); + generalPath.moveTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); + generalPath.curveTo(((float) x[0] + CORNOR_RADIUS - specialLocation1), (y[0] + CORNOR_RADIUS - specialLocation2), ((float) x[0] + CORNOR_RADIUS - specialLocation2), (y[0] + CORNOR_RADIUS - specialLocation1), x[0], y[0] + CORNOR_RADIUS); + + for (int index = 1; index <= 2; index++) { + generalPath.lineTo((float) x[index], (float) y[index]); + } + + generalPath.lineTo((float) x[3], (float) y[3] + CORNOR_RADIUS); + generalPath.curveTo(((float) x[3] - CORNOR_RADIUS + specialLocation1), ((float) y[3] + CORNOR_RADIUS - specialLocation2), ((float) x[3] - CORNOR_RADIUS + specialLocation2), ((float) y[3] + CORNOR_RADIUS - specialLocation1), (float) x[3] - CORNOR_RADIUS, (float) y[3]); + generalPath.lineTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); + + generalPath.closePath(); + g2d.fill(generalPath); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setPaint(new Color(200, 201, 205)); + g2d.draw(new Arc2D.Double(x[0], y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); + g2d.draw(new Line2D.Double(x[0], y[0] + CORNOR_RADIUS, x[1], y[1])); + g2d.draw(new Line2D.Double(x[1], y[1], x[2], y[2])); + g2d.draw(new Line2D.Double(x[2], y[2], x[3], y[3] + CORNOR_RADIUS)); + g2d.draw(new Arc2D.Double(x[3] - CORNOR_RADIUS * 2, y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + int sheetIconY = (getHeight() - sheeticon.getIconHeight()) / 2; + sheeticon.paintIcon(this, g2d, (int) templateStartX + GAP, sheetIconY); + // 画字符 + g2d.setPaint(getForeground()); + g2d.drawString(sheetName, (int) templateStartX + sheeticon.getIconWidth() + 2 * GAP, getHeight() - GAP * 2); + int closePosition = (int) templateStartX + realWidth - CLOSE.getIconWidth() - SMALLGAP; + int closeY = (getHeight() - closeIcon.getIconHeight()) / 2; + if (!DesignerMode.isVcsMode()) { + closeIcon.paintIcon(this, g2d, closePosition, closeY); + } + return closePosition; + + } + + /** + * 画没有选中的tab + * + * @param g2d + * @param sheeticon + * @param templateStartX + * @param sheetName + * @param closeIcon + * @param isLeft + * @return + */ + private int paintUnSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon, boolean isLeft, int mouseOveredIndex, int selfIndex) { + double[] x = {templateStartX, templateStartX, templateStartX + realWidth, templateStartX + realWidth, templateStartX}; + double[] y = {-1, getHeight() - 1, getHeight() - 1, -1, -1}; + if (selfIndex == mouseOveredIndex) { + g2d.setPaint(new GradientPaint(1, 1, UIConstants.HOVER_BLUE, 1, (float) (getHeight() - 1.0D), UIConstants.HOVER_BLUE)); + } else { + g2d.setPaint(new GradientPaint(1, 1, UIConstants.SHADOW_GREY, 1, (float) (getHeight() - 1.0D), UIConstants.SHADOW_GREY)); + } + + + GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, x.length); + + unSelectedClosedPath(generalPath, isLeft, x, y); + g2d.fill(generalPath); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setPaint(UIConstants.TEMPLATE_TAB_PANE_BACKGROUND); + //TODO hzzz delete +// if (isLeft) { +// g2d.draw(new Arc2D.Double(x[0], y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); +// } else { +// g2d.draw(new Arc2D.Double(x[0] - CORNOR_RADIUS * 2, y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); +// } + +// g2d.draw(new Line2D.Double(x[0], y[0] + CORNOR_RADIUS, x[1], y[1] + 1)); +// g2d.draw(new Line2D.Double(x[1], y[1], x[2], y[2])); + g2d.draw(new Line2D.Double(x[2], y[2], x[3], y[3] + CORNOR_RADIUS)); +// if (isLeft) { +// g2d.draw(new Arc2D.Double(x[3], y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); +// } else { +// g2d.draw(new Arc2D.Double(x[3] - CORNOR_RADIUS * 2, y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); +// } + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + int sheetIconY = (getHeight() - sheeticon.getIconHeight()) / 2; + sheeticon.paintIcon(this, g2d, (int) templateStartX + GAP, sheetIconY); + // 画字符 + g2d.setPaint(getForeground()); + g2d.drawString(sheetName, (int) templateStartX + sheeticon.getIconWidth() + 2 * GAP, getHeight() - GAP * 2); + int closeY = (getHeight() - closeIcon.getIconHeight()) / 2; + int closePosition = (int) templateStartX + realWidth - CLOSE.getIconWidth() - SMALLGAP; + if (!DesignerMode.isVcsMode()) { + closeIcon.paintIcon(this, g2d, closePosition, closeY); + } + return closePosition; + } + + + private void unSelectedClosedPath(GeneralPath generalPath, boolean isLeft, double[] x, double[] y) { + + if (isLeft) { + generalPath.moveTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); + generalPath.curveTo(((float) x[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), x[0], y[0] + CORNOR_RADIUS); + } else { + generalPath.moveTo((float) x[0] - CORNOR_RADIUS, (float) y[0]); + generalPath.curveTo(((float) x[0] - CORNOR_RADIUS + SPECIAL_LOCATION_1), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[0] - CORNOR_RADIUS + SPECIAL_LOCATION_2), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), x[0], y[0] + CORNOR_RADIUS); + } + + for (int index = 1; index <= 2; index++) { + generalPath.lineTo((float) x[index], (float) y[index]); + } + + generalPath.lineTo((float) x[3], (float) y[3] + CORNOR_RADIUS); + + if (isLeft) { + generalPath.curveTo(((float) x[3] + CORNOR_RADIUS - SPECIAL_LOCATION_1), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) y[3] - CORNOR_RADIUS + SPECIAL_LOCATION_1), (float) x[3] + CORNOR_RADIUS, (float) y[3]); + generalPath.lineTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); + } else { + generalPath.curveTo(((float) x[3] - CORNOR_RADIUS + SPECIAL_LOCATION_1), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[3] - CORNOR_RADIUS + SPECIAL_LOCATION_2), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_1), (float) x[3] - CORNOR_RADIUS, (float) y[3]); + generalPath.lineTo((float) x[0] - CORNOR_RADIUS, (float) y[0]); + } + + generalPath.closePath(); + } + + + public void setIsCloseCurrent(boolean isCloseCurrent) { + this.isCloseCurrent = isCloseCurrent; + + } + + /** + * 关闭模板 + * + * @param specifiedTemplate 模板 + */ + public void closeSpecifiedTemplate(JTemplate specifiedTemplate) { + if (specifiedTemplate == null) { + return; + } + + if (!specifiedTemplate.isALLSaved() && !DesignerMode.isVcsMode()) { + specifiedTemplate.stopEditing(); + int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + specifiedTemplate.getEditingFILE() + "\" ?", + Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (returnVal == JOptionPane.YES_OPTION) { + CallbackSaveWorker worker = specifiedTemplate.save(); + worker.addSuccessCallback(new Runnable() { + @Override + public void run() { + FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); + closeTpl(specifiedTemplate); + } + }); + worker.start(specifiedTemplate.getRuntimeId()); + } else if (returnVal == JOptionPane.NO_OPTION) { + closeTpl(specifiedTemplate); + } + } else { + closeTpl(specifiedTemplate); + } + + } + + private void closeTpl(@Nonnull JTemplate specifiedTemplate) { + HistoryTemplateListCache.getInstance().closeSelectedReport(specifiedTemplate); + closeAndFreeLock(specifiedTemplate); + activePrevTemplateAfterClose(); + } + + private void closeAndFreeLock(@Nonnull JTemplate template) { + FILE file = template.getEditingFILE(); + // 只有是环境内的文件,才执行释放锁 + if (file != null && file.isEnvFile()) { + // release lock + TemplateResourceManager.getResource().closeTemplate(file.getPath()); + } + } + + /** + * 后台关闭当前编辑模板 + */ + public void closeCurrentTpl() { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + this.setIsCloseCurrent(true); + this.closeFormat(jTemplate); + this.closeSpecifiedTemplate(jTemplate); + } + + /** + * 关闭模板 + * + * @param closedTemplate 模板 + */ + public void closeFormat(JTemplate closedTemplate) { + //表单不需要处理 + if (!closedTemplate.isJWorkBook()) { + return; + } + + if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_NULL) { + return; + } + + //是被参照的模板被关闭,则重置格式刷 + closedTemplate.doConditionCancelFormat(); + } + + /** + * 关闭掉一个模板之后激活新的待显示模板 + */ + public void activePrevTemplateAfterClose() { + if (openedTemplate.isEmpty()) { + //新建并激活模板 + DesignerContext.getDesignerFrame().addAndActivateJTemplate(); + selectedIndex = 0; + //此时刚自动新建的模板在HistoryTemplateListCache的editingTemplate + temTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + + } else { + // 如果关闭的模板是当前选中的模板,则重新激活当前 selectIndex 的模板; + // selectIndex 没有变化,但是对应的模板已经变成了前一张模板 + if (closeIconIndex == selectedIndex || isCloseCurrent) { + // 如果当前关闭的模板在最右侧,那么预览上一个,防止数组越界 + if (selectedIndex >= maxPaintIndex) { + // selectIndex 不会 <0 因为如果关闭的是打开的最后一个模板,那么关闭之后 openedTemplate.isEmpty() = true + selectedIndex--; + } + isCloseCurrent = false; + } + // 如果关闭的模板不是当前选中的模板,那么重新获取一下当前模板的 index,激活该 index + else { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + selectedIndex = HistoryTemplateListCache.getInstance().contains(template); + } + if (selectedIndex < openedTemplate.size()) { + //如果是已后台关闭的模板,则重新打开文件 + openedTemplate.get(selectedIndex).activeOldJTemplate(); + } + + } + } + + + private boolean isOverCloseIcon(int evtX) { + boolean isOverCloseIcon = false; + for (int i = 0; i < startX.length; i++) { + if (evtX >= startX[i] && evtX <= startX[i] + CLOSE.getIconWidth()) { + isOverCloseIcon = true; + break; + } + } + return isOverCloseIcon; + } + + + private boolean isOverListDown(int evtX) { + int maxWidth = getWidth() - LIST_BUTTON_WIDTH; + return evtX >= (maxWidth + SMALLGAP) && evtX <= (getWidth() - SMALLGAP); + } + + + private int getTemplateIndex(int evtX) { + int textX = 0; + for (int i = minPaintIndex; i <= maxPaintIndex; i++) { + int textWidth = realWidth; + if (evtX >= textX && evtX < textX + textWidth) { + return i; + } + textX += textWidth; + } + return -1; + } + + + /** + * 处理自动新建的模板 在切换时的处理 + */ + public void doWithtemTemplate() { + //temtemplate保存的一定是手动新建的没有编辑或是编辑了没有保存的模板 + //没有保存,说明有编辑;已经保存在磁盘里的文件,说明有过处理,并且已经保存,此时切换都不将其自动关闭 + if (temTemplate == null || temTemplate == HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()) { + return; + } + + if (!temTemplate.isSaved() || !temTemplate.getEditingFILE().isMemFile()) { + temTemplate = null; + } + + //自动新建的模板B若没有进行任何编辑(新建模板没有进行任何编辑时saved都是true):还没有存盘 + if (temTemplate != null && temTemplate.getEditingFILE().isMemFile() && temTemplate.isSaved()) { + HistoryTemplateListCache.getInstance().closeSelectedReport(temTemplate); + temTemplate = null; + setSelectedIndex(HistoryTemplateListCache.getInstance().contains(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate())); + } + } + + private class UIListDownItemUI extends BasicMenuItemUI { + @Override + protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { + if (menuItem.getIcon() == null) { + super.paintBackground(g, menuItem, bgColor); + return; + } + ButtonModel model = menuItem.getModel(); + Color oldColor = g.getColor(); + int menuWidth = menuItem.getWidth(); + int menuHeight = menuItem.getHeight(); + g.setColor(UIConstants.NORMAL_BACKGROUND); + g.fillRect(0, 0, menuWidth, menuHeight); + boolean itemIsSelected = menuItem instanceof JMenu && model.isSelected(); + if (menuItem.isOpaque()) { + if (model.isArmed() || itemIsSelected) { + GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, UIConstants.FLESH_BLUE, UIConstants.ARC); + } else { + GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, menuItem.getBackground(), UIConstants.ARC); + } + g.setColor(oldColor); + } else if (model.isArmed() || itemIsSelected) { + GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, UIConstants.FLESH_BLUE, UIConstants.ARC); + g.setColor(oldColor); + } + } + } + + private class MultiTemplateTabMouseListener implements MouseListener { + + + /** + * 鼠标进入 + * + * @param e 鼠标事件 + */ + @Override + public void mouseEntered(MouseEvent e) { + // do nothing + } + + /** + * 鼠标离开 + * + * @param e 鼠标事件 + */ + @Override + public void mouseExited(MouseEvent e) { + listDownMode = LIST_DOWN; + closeIconIndex = -1; + mouseOveredIndex = -1; + MultiTemplateTabPane.this.repaint(); + } + + /** + * 鼠标释放 + * + * @param e 鼠标事件 + */ + @Override + public void mouseReleased(MouseEvent e) { + // do nothing + } + + /** + * 点击 + * + * @param e 鼠标事件 + */ + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + + /** + * 按下 + * + * @param e 鼠标事件 + */ + @Override + public void mousePressed(MouseEvent e) { + //如果在版本管理情况下,不允许切换tab + if (DesignerMode.isVcsMode()) { + return; + } + + int evtX = e.getX(); + + //是否点击关闭按钮 如果点击了关闭按钮,则将点击的模板关闭,不需要切换,如果没有点击关闭按钮,则切换到点击的模板处 + boolean isOverCloseIcon = isOverCloseIcon(evtX); + if (isOverListDown(evtX)) { + listDownMode = isOverListDown(evtX) ? MOUSE_PRESS_LIST_DOWN : LIST_DOWN; + if (!isShowList) { + showListDown(); + } + isShowList = !isShowList; + + } else if (isOverCloseIcon) { + //关闭按钮的图标变化 + closeIconIndex = getTemplateIndex(evtX); + clodeMode = MOUSE_PRESS_CLOSE; + //关闭close图标所在的模板{ + JTemplate template = openedTemplate.get(closeIconIndex); + if (template.isOpening()) { + WorkerManager.getInstance().cancelWorker(template.getPath()); + } else if (template.isSaving()) { + boolean completed = WorkerManager.getInstance().isCompleted(template.getTarget().getTemplateID()); + if (!completed) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Close_Template_Tip", template.getEditingFILE().getName())); + return; + } + } + //参考CloseCurrentTemplateAction,在closeFormat与closeSpecifiedTemplate之前要先设定isCloseCurrent,这样关闭之后才会自动切换tab + if (checkCurrentClose(template)) { + setIsCloseCurrent(true); + } + closeFormat(template); + closeSpecifiedTemplate(template); + DesignerContext.getDesignerFrame().getContentFrame().repaint(); + isShowList = false; + } else { + //没有点击关闭和ListDown按钮,则切换到点击的模板处 + closeIconIndex = -1; + clodeMode = CLOSE; + int tempSelectedIndex = selectedIndex; + if (selectedIndex != getTemplateIndex(evtX) && getTemplateIndex(evtX) != -1) { + openedTemplate.get(selectedIndex).stopEditing(); + selectedIndex = getTemplateIndex(evtX); + //如果在权限编辑情况下,不允许切换到表单类型的工作簿 + if (DesignerMode.isAuthorityEditing() && !openedTemplate.get(selectedIndex).isJWorkBook()) { + DesignerContext.getDesignerFrame().addAndActivateJTemplate(openedTemplate.get(tempSelectedIndex)); + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Form_Authority_Edited_Cannot_Be_Supported") + + "!", Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.WARNING_MESSAGE); + MultiTemplateTabPane.this.repaint(); + return; + } + JTemplate evtXTemplate = openedTemplate.get(getTemplateIndex(evtX)); + evtXTemplate.activeNewJTemplate(); + } + isShowList = false; + } + MultiTemplateTabPane.this.repaint(); + + + } + + + } + + private boolean checkCurrentClose(JTemplate template) { + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + return JTemplate.isValid(currentTemplate) && ComparatorUtils.equals(template.getPath(), currentTemplate.getPath()); + } + + private class MultiTemplateTabMouseMotionListener implements MouseMotionListener { + /** + * 鼠标拖拽 + * + * @param e 鼠标事件 + */ + @Override + public void mouseDragged(MouseEvent e) { + // do nothing + } + + /** + * 鼠标移动 + * + * @param e 鼠标事件 + */ + @Override + public void mouseMoved(MouseEvent e) { + int evtX = e.getX(); + mouseOveredIndex = getTemplateIndex(evtX); + + //看是否需要显示toolTip + if (mouseOveredIndex != -1 && isNeedToolTips[mouseOveredIndex - minPaintIndex]) { + setToolTipText(openedTemplate.get(mouseOveredIndex).getEditingFILE().getName()); + } else { + setToolTipText(null); + } + + listDownMode = isOverListDown(evtX) ? MOUSE_OVER_LIST_DOWN : LIST_DOWN; + + boolean isOverCloseIcon = isOverCloseIcon(evtX); + clodeMode = isOverCloseIcon ? MOUSE_OVER_CLOSE : CLOSE; + closeIconIndex = isOverCloseIcon ? mouseOveredIndex : -1; + MultiTemplateTabPane.this.repaint(); + } + } + + +} diff --git a/designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java b/designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java index b7a564713b..36e0b58754 100644 --- a/designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java +++ b/designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java @@ -1,1037 +1,24 @@ package com.fr.design.file; - -import com.fr.base.BaseUtils; -import com.fr.base.GraphHelper; -import com.fr.base.vcs.DesignerMode; -import com.fr.design.base.mode.DesignModeContext; -import com.fr.design.constants.UIConstants; -import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.gui.imenu.UIMenuItem; -import com.fr.design.gui.imenu.UIScrollPopUpMenu; -import com.fr.design.i18n.Toolkit; -import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.JTemplate; -import com.fr.design.mainframe.TemplateSavingChecker; -import com.fr.design.utils.DesignUtils; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.design.utils.gui.GUIPaintUtils; -import com.fr.design.worker.WorkerManager; -import com.fr.design.worker.save.CallbackSaveWorker; -import com.fr.file.FILE; -import com.fr.general.ComparatorUtils; -import com.fr.general.IOUtils; -import com.fr.log.FineLoggerFactory; -import com.fr.stable.Constants; -import com.fr.third.javax.annotation.Nonnull; - -import javax.swing.BorderFactory; -import javax.swing.ButtonModel; -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSeparator; -import javax.swing.SwingConstants; -import javax.swing.plaf.basic.BasicMenuItemUI; -import java.awt.AWTEvent; -import java.awt.AlphaComposite; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GradientPaint; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.AWTEventListener; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.geom.Arc2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.Line2D; -import java.awt.geom.Path2D; -import java.awt.geom.RoundRectangle2D; -import java.util.List; - /** - * Author : daisy - * Date: 13-8-5 - * Time: 下午6:12 + * @author shine + * @version 10.0 + * Created by shine on 2022/11/25 + * fvs plugin jartime升级到2022-12-2之后就可以删了 */ -public class MutilTempalteTabPane extends JComponent { - - private static Icon LIST_DOWN = BaseUtils.readIcon("/com/fr/design/images/buttonicon/list_normal.png"); - private static Icon MOUSE_OVER_LIST_DOWN = BaseUtils.readIcon("/com/fr/design/images/buttonicon/list_pressed.png"); - private static Icon MOUSE_PRESS_LIST_DOWN = BaseUtils.readIcon("/com/fr/design/images/buttonicon/list_pressed.png"); - private static Icon CLOSE = BaseUtils.readIcon("/com/fr/design/images/buttonicon/close_icon.png"); - private static Icon MOUSE_OVER_CLOSE = BaseUtils.readIcon("/com/fr/design/images/buttonicon/mouseoverclose icon.png"); - private static Icon MOUSE_PRESS_CLOSE = BaseUtils.readIcon("/com/fr/design/images/buttonicon/pressclose icon.png"); - private static final Icon WHITE_SAVING_CLOSE_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/file/white_saving_close.gif")); - private static final Icon GREY_SAVING_CLOSE_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/file/grey_saving_close.gif")); - private static final String ELLIPSIS = "..."; - private static final int GAP = 5; - private static final int SMALLGAP = 3; - private static final int LIST_BUTTON_WIDTH = 34; - private static final int HEIGHT = 26; - private static final int LIST_DOWN_HEIGHT = 25; - private static final double CORNOR_RADIUS = 0.0; - //选了30度和60度的特殊角度的x,y作为经过的两个点的坐标 - private static final double SPECIAL_LOCATION_1 = 2.5; - private static final double SPECIAL_LOCATION_2 = 4.330127; - private static final int ICON_WIDTH = 22; - - - //每个标签页的最大的长度和最小长度。这些长度均为均分 - - private static final int MAXWIDTH = 240; - private static final int MINWIDTH = 100; - - - private static MutilTempalteTabPane THIS; - //用于存放工作簿 - private java.util.List> openedTemplate; - //选中的Tab项 - private int selectedIndex = 0; - // - private int mouseOveredIndex = -1; - - //tab栏可以放下的每个tab的实际宽度 - private int realWidth = MAXWIDTH; - - - //当前标签页栏存放的所有标签页的index - private int minPaintIndex = 0; - private int maxPaintIndex = 0; - - //每个关闭图标的起始位置 - private int[] startX; - - private boolean[] isNeedToolTips; - - //记录关闭按钮的状态 - private int closeIconIndex = -1; - private boolean isCloseCurrent = false; - private Icon clodeMode = CLOSE; - private Icon listDownMode = LIST_DOWN; - private boolean isShowList = false; - - //自动新建的模板B若没有进行任何编辑,切换到其他 - // - // 模板时,模板B会自动关闭 - private JTemplate temTemplate = null; - +@Deprecated +public class MutilTempalteTabPane { public static MutilTempalteTabPane getInstance() { - if (THIS == null) { - THIS = new MutilTempalteTabPane(); - } - return THIS; - } - - - /** - * 多工作簿面板 - */ - public MutilTempalteTabPane() { - this.setLayout(new BorderLayout(0, 0)); - this.addMouseListener(new MultiTemplateTabMouseListener()); - this.addMouseMotionListener(new MultiTemplateTabMouseMotionListener()); - this.setBorder(null); - this.setForeground(new Color(58, 56, 58)); - this.setFont(DesignUtils.getDefaultGUIFont().applySize(12)); - openedTemplate = HistoryTemplateListCache.getInstance().getHistoryList(); - selectedIndex = openedTemplate.size() - 1; - AWTEventListener awt = new AWTEventListener() { - @Override - public void eventDispatched(AWTEvent event) { - if (event instanceof MouseEvent) { - MouseEvent mv = (MouseEvent) event; - if (mv.getClickCount() > 0 && !ComparatorUtils.equals(mv.getSource(), MutilTempalteTabPane.this)) { - isShowList = false; - } - } - } - - }; - java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(awt, AWTEvent.MOUSE_EVENT_MASK); - } - - public JTemplate getSelectedFile() { - if (openedTemplate.size() == selectedIndex) { - selectedIndex = Math.max(--selectedIndex, 0); - } - return openedTemplate.get(selectedIndex); - } - - - /** - * 关闭掉当前已打开文件列表中指定的文件 - * - * @param file 指定的文件 - */ - public void closeFileTemplate(FILE file) { - for (JTemplate temp : openedTemplate) { - if (ComparatorUtils.equals(file, temp.getEditingFILE())) { - closeSpecifiedTemplate(temp); - break; - } - } - - } - - @Override - public Dimension getPreferredSize() { - Dimension dimension = super.getPreferredSize(); - dimension.height = HEIGHT; - return dimension; - } - - private UIMenuItem initCloseOther() { - UIMenuItem closeOther = new UIMenuItem(Toolkit.i18nText("Fine-Design_Basic_FS_Close_Other_Templates")); - // Yvan: 英文下文本显示不全,后续发现如果将模板名设置的比较短,其它语言也会出现显示不全的问题,所以设置一下文本水平居中 - closeOther.setHorizontalAlignment(SwingConstants.CENTER); - setListDownItemPreferredSize(closeOther); - closeOther.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (openedTemplate.size() == 1) { - return; - } - if (!TemplateSavingChecker.check()) { - return; - } - SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false); - //点击关闭其他模板,并且点击确定保存 - if (saveSomeTempaltePane.showSavePane()) { - JTemplate[] panes = new JTemplate[openedTemplate.size()]; - for (int i = 0; i < openedTemplate.size(); i++) { - panes[i] = openedTemplate.get(i); - } - for (int i = 0; i < panes.length; i++) { - if (i != selectedIndex) { - JTemplate jTemplate = panes[i]; - //判断关闭的模板是不是格式刷的被参照的模板 - openedTemplate.remove(jTemplate); - closeFormat(jTemplate); - HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate); - closeAndFreeLock(jTemplate); - } - } - JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - HistoryTemplateListCache.getInstance().removeAllHistory(); - DesignerContext.getDesignerFrame().activateJTemplate(currentTemplate); - THIS.repaint(); - } - //如果取消保存了,则不关闭其他模板 - } - }); - if (openedTemplate.size() == 1) { - closeOther.setEnabled(false); - } - return closeOther; - } - - - private UIMenuItem[] createListDownTemplate() { - UIMenuItem[] templates = new UIMenuItem[openedTemplate.size()]; - for (int i = 0; i < openedTemplate.size(); i++) { - final int index = i; - final JTemplate tem = openedTemplate.get(i); - templates[i] = new UIMenuItem(tempalteShowName(tem), tem.getIcon()); - templates[i].setUI(new UIListDownItemUI()); - setListDownItemPreferredSize(templates[i]); - if (i == selectedIndex) { - //画选中的高亮 - templates[i].setBackground(UIConstants.SHADOW_CENTER); - } - templates[i].addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - selectedIndex = index; - tem.activeNewJTemplate(); - } - }); - } - return templates; - } - - private void setListDownItemPreferredSize(UIMenuItem item) { - Dimension dimension = item.getPreferredSize(); - dimension.height = LIST_DOWN_HEIGHT; - item.setPreferredSize(dimension); - } - - - private String tempalteShowName(JTemplate template) { - String name = template.getTemplateName(); - if (!template.isSaved() && !name.endsWith(" *")) { - name += " *"; - } - return name; - } - - /** - * 刷新打开模板 - * - * @param history 模板 - */ - public void refreshOpenedTemplate(List> history) { - openedTemplate = history; + return new MutilTempalteTabPane(); } - public void setTemTemplate(JTemplate auotCreate) { - temTemplate = auotCreate; - } - - - private void showListDown() { - - UIScrollPopUpMenu menu = new UIScrollPopUpMenu(); - menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0)); - menu.add(initCloseOther()); - JSeparator separator = new JSeparator() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }; - menu.add(new JPanel() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }); - separator.setForeground(UIConstants.LINE_COLOR); - menu.add(separator); - menu.add(new JPanel() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }); - UIMenuItem[] items = createListDownTemplate(); - for (int i = 0; i < items.length; i++) { - menu.add(items[i]); - } - GUICoreUtils.showPopupMenu(menu, MutilTempalteTabPane.getInstance(), MutilTempalteTabPane.getInstance().getWidth() - menu.getPreferredSize().width, getY() - 1 + getHeight()); - } - - - public void setSelectedIndex(int index) { - selectedIndex = index; - } - - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - double maxWidth = getWidth() - LIST_BUTTON_WIDTH * 1.0D; //最大宽度 - Graphics2D g2d = (Graphics2D) g; - paintBackgroundAndLine(g2d, maxWidth); - } - - - @Override - public void paint(Graphics g) { - //不可见时,按钮.4f透明 - AlphaComposite composite = DesignerMode.isVcsMode() - ? AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f) - : (AlphaComposite) ((Graphics2D) g).getComposite(); - ((Graphics2D) g).setComposite(composite); - super.paint(g); - } - - private void paintBackgroundAndLine(Graphics2D g2d, double maxWidth) { - paintDefaultBackground(g2d); - //最多能画的个数 - int maxTemplateNum = (int) (maxWidth) / MINWIDTH; - //计算开始画的最小模板index和最大模板index - calMinAndMaxIndex(maxTemplateNum); - calculateRealAverageWidth(maxWidth, maxTemplateNum); - int maxStringlength = calculateStringMaxLength(); - if (selectedIndex >= openedTemplate.size()) { - selectedIndex = openedTemplate.size() - 1; - } - if (selectedIndex < 0) { - selectedIndex = 0; - } - double templateStartX = 0; - startX = new int[maxPaintIndex - minPaintIndex + 1]; - isNeedToolTips = new boolean[maxPaintIndex - minPaintIndex + 1]; - - //从可以开始展示在tab面板上的tab开始画 - for (int i = minPaintIndex; i <= maxPaintIndex; i++) { - JTemplate template = openedTemplate.get(i); - Icon icon = template.getIcon(); - String name = tempalteShowName(template); - //如果tab名字的长度大于最大能显示的英文字符长度,则进行省略号处理 - if (getStringWidth(name) > maxStringlength) { - name = getEllipsisName(name, maxStringlength); - isNeedToolTips[i - minPaintIndex] = true; - } else { - isNeedToolTips[i - minPaintIndex] = false; - } - - Icon selectedIcon; - if (i == closeIconIndex) { - selectedIcon = clodeMode; - } else { - selectedIcon = CLOSE; - } - if (i == selectedIndex) { - if (template.isSaving()) { - selectedIcon = WHITE_SAVING_CLOSE_ICON; - } - startX[i - minPaintIndex] = paintSelectedTab(g2d, icon, templateStartX, name, selectedIcon); - } else { - if (template.isSaving()) { - selectedIcon = GREY_SAVING_CLOSE_ICON; - } - boolean isLeft = i < selectedIndex; - startX[i - minPaintIndex] = paintUnSelectedTab(g2d, icon, templateStartX, name, selectedIcon, isLeft, mouseOveredIndex, i); - } - templateStartX += realWidth; - } - - if (!DesignerMode.isVcsMode()) { - paintListDown(g2d, maxWidth); - } - paintUnderLine(templateStartX, maxWidth, g2d); - } - - - private void paintUnderLine(double templateStartX, double maxWidth, Graphics2D g2d) { - //画下面的那条线 - if (templateStartX < maxWidth) { - GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, 2); - generalPath.moveTo((float) templateStartX, (float) (getHeight() - 1.0D)); - generalPath.lineTo((float) maxWidth, (float) (getHeight() - 1.0D)); - g2d.fill(generalPath); - //TODO hzzz delete -// g2d.setPaint(UIConstants.LINE_COLOR); -// g2d.draw(new Line2D.Double((float) templateStartX, getHeight() - 1, (float) maxWidth + LIST_BUTTON_WIDTH, getHeight() - 1)); - } - } - - private void paintDefaultBackground(Graphics2D g2d) { - //画默认背景 - g2d.setPaint(new GradientPaint(1, 1, UIConstants.TEMPLATE_TAB_PANE_BACKGROUND, 1, (float) (getHeight() - 1.0D), UIConstants.TEMPLATE_TAB_PANE_BACKGROUND)); - g2d.fillRect(0, 0, getWidth(), getHeight()); - } - - - private void paintListDown(Graphics2D g2d, double maxWidth) { - int x = (int) maxWidth + (LIST_BUTTON_WIDTH - listDownMode.getIconWidth()) / 2; - int y = (getHeight() - listDownMode.getIconHeight()) / 2; - listDownMode.paintIcon(this, g2d, x, y); - } - - /** - * 判断tab文字的长度大于能装下的最大文字长度,要用省略号 - * - * @param name - * @param maxStringlength - * @return - */ - private String getEllipsisName(String name, int maxStringlength) { - - //若是名字长度大于能显示的长度,那能显示的文字的最大长度还要减去省略号的最大长度 -// int maxellipsislength = maxStringlength - ELLIPSIS.length(); - int ellipsisWidth = getStringWidth(ELLIPSIS); - int leftkeyPoint = 0; - int rightKeyPoint = name.length() - 1; - int leftStrWidth = 0; - int rightStrWidth = 0; - while (leftStrWidth + rightStrWidth + ellipsisWidth < maxStringlength) { - if (leftStrWidth <= rightStrWidth) { - leftkeyPoint++; - } else { - rightKeyPoint--; - } - leftStrWidth = getStringWidth(name.substring(0, leftkeyPoint)); - rightStrWidth = getStringWidth(name.substring(rightKeyPoint)); - - if (leftStrWidth + rightStrWidth + ellipsisWidth > maxStringlength) { - if (leftStrWidth <= rightStrWidth) { - rightKeyPoint++; - } - break; - } - } - - return name.substring(0, leftkeyPoint) + ELLIPSIS + name.substring(rightKeyPoint); - } - - private void calMinAndMaxIndex(int maxTemplateNum) { - //如果个数大于最多能容纳的个数,则多余的进行处理 - if (openedTemplate.size() > maxTemplateNum) { - //所点击列表中的标签页处在标签页栏最后一个标签页之后,则标签页栏左移至所点击标签页出现 - if (selectedIndex >= maxPaintIndex) { - minPaintIndex = selectedIndex - maxTemplateNum + 1; - maxPaintIndex = selectedIndex; - if (minPaintIndex <= 0) { - minPaintIndex = 0; - maxPaintIndex = maxTemplateNum - 1; - } - } else if (selectedIndex <= minPaintIndex) { - //所点击列表中的标签页处在标签页栏第一个标签页之前,则标签页栏右移至所点击标签页出现 - minPaintIndex = selectedIndex; - maxPaintIndex = minPaintIndex + maxTemplateNum - 1; - if (maxPaintIndex > openedTemplate.size() - 1) { - maxPaintIndex = openedTemplate.size() - 1; - } - } else { - if (selectedIndex >= openedTemplate.size() - 1) { - selectedIndex = openedTemplate.size() - 1; - maxPaintIndex = selectedIndex; - minPaintIndex = selectedIndex - maxTemplateNum + 1; - } else { - maxPaintIndex = minPaintIndex + maxTemplateNum - 1; - if (maxPaintIndex > openedTemplate.size() - 1) { - maxPaintIndex = openedTemplate.size() - 1; - } - } - } - } else { - minPaintIndex = 0; - maxPaintIndex = openedTemplate.size() - 1; - } - } - - - //个数小于最多能容纳的个数的情况下,看看宽度每个要画多少 - private void calculateRealAverageWidth(double maxwidth, int templateNum) { - - int num = openedTemplate.size() > templateNum ? templateNum : openedTemplate.size(); - realWidth = (int) (maxwidth / (num)); - if (realWidth > MAXWIDTH) { - realWidth = MAXWIDTH; - } else if (realWidth < MINWIDTH) { - //平均下来每个的宽度小于最小宽度 - realWidth = MINWIDTH; - } - } - - /** - * 计算过长度之后的每个tab的能接受的文字的英文字符数 - * - * @return - */ - private int calculateStringMaxLength() { - return realWidth - 3 * GAP - ICON_WIDTH - SMALLGAP - CLOSE.getIconWidth(); - - } + public void setIsCloseCurrent(boolean b) { + MultiTemplateTabPane.getInstance().setIsCloseCurrent(b); - private int getStringWidth(String str) { - return GraphHelper.getFontMetrics(this.getFont()).stringWidth(str); } - - /** - * 画选中的tab - * - * @param g2d - * @param sheeticon - * @param templateStartX - * @param sheetName - * @param closeIcon - * @return - */ - private int paintSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon) { - double[] x = {templateStartX, templateStartX, templateStartX + realWidth, templateStartX + realWidth, templateStartX}; - double[] y = {1, getHeight() + 1, getHeight() + 1, 1, 1}; - RoundRectangle2D.Double rect1 = new RoundRectangle2D.Double(templateStartX, 1, this.getWidth(), this.getHeight(), 7, 7); - g2d.setPaint(new GradientPaint(1, 1, UIConstants.SELECT_TAB, 1, (float) (getHeight() - 1.0D), UIConstants.SELECT_TAB)); - //选了30度和60度的特殊角度的x,y作为经过的两个点的坐标 - double specialLocation1 = 2.5; - double specialLocation2 = 4.330127; - GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, x.length); - generalPath.moveTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); - generalPath.curveTo(((float) x[0] + CORNOR_RADIUS - specialLocation1), (y[0] + CORNOR_RADIUS - specialLocation2), ((float) x[0] + CORNOR_RADIUS - specialLocation2), (y[0] + CORNOR_RADIUS - specialLocation1), x[0], y[0] + CORNOR_RADIUS); - - for (int index = 1; index <= 2; index++) { - generalPath.lineTo((float) x[index], (float) y[index]); - } - - generalPath.lineTo((float) x[3], (float) y[3] + CORNOR_RADIUS); - generalPath.curveTo(((float) x[3] - CORNOR_RADIUS + specialLocation1), ((float) y[3] + CORNOR_RADIUS - specialLocation2), ((float) x[3] - CORNOR_RADIUS + specialLocation2), ((float) y[3] + CORNOR_RADIUS - specialLocation1), (float) x[3] - CORNOR_RADIUS, (float) y[3]); - generalPath.lineTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); - - generalPath.closePath(); - g2d.fill(generalPath); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setPaint(new Color(200, 201, 205)); - g2d.draw(new Arc2D.Double(x[0], y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); - g2d.draw(new Line2D.Double(x[0], y[0] + CORNOR_RADIUS, x[1], y[1])); - g2d.draw(new Line2D.Double(x[1], y[1], x[2], y[2])); - g2d.draw(new Line2D.Double(x[2], y[2], x[3], y[3] + CORNOR_RADIUS)); - g2d.draw(new Arc2D.Double(x[3] - CORNOR_RADIUS * 2, y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - int sheetIconY = (getHeight() - sheeticon.getIconHeight()) / 2; - sheeticon.paintIcon(this, g2d, (int) templateStartX + GAP, sheetIconY); - // 画字符 - g2d.setPaint(getForeground()); - g2d.drawString(sheetName, (int) templateStartX + sheeticon.getIconWidth() + 2 * GAP, getHeight() - GAP * 2); - int closePosition = (int) templateStartX + realWidth - CLOSE.getIconWidth() - SMALLGAP; - int closeY = (getHeight() - closeIcon.getIconHeight()) / 2; - if (!DesignerMode.isVcsMode()) { - closeIcon.paintIcon(this, g2d, closePosition, closeY); - } - return closePosition; - - } - - /** - * 画没有选中的tab - * - * @param g2d - * @param sheeticon - * @param templateStartX - * @param sheetName - * @param closeIcon - * @param isLeft - * @return - */ - private int paintUnSelectedTab(Graphics2D g2d, Icon sheeticon, double templateStartX, String sheetName, Icon closeIcon, boolean isLeft, int mouseOveredIndex, int selfIndex) { - double[] x = {templateStartX, templateStartX, templateStartX + realWidth, templateStartX + realWidth, templateStartX}; - double[] y = {-1, getHeight() - 1, getHeight() - 1, -1, -1}; - if (selfIndex == mouseOveredIndex) { - g2d.setPaint(new GradientPaint(1, 1, UIConstants.HOVER_BLUE, 1, (float) (getHeight() - 1.0D), UIConstants.HOVER_BLUE)); - } else { - g2d.setPaint(new GradientPaint(1, 1, UIConstants.SHADOW_GREY, 1, (float) (getHeight() - 1.0D), UIConstants.SHADOW_GREY)); - } - - - GeneralPath generalPath = new GeneralPath(Path2D.WIND_EVEN_ODD, x.length); - - unSelectedClosedPath(generalPath, isLeft, x, y); - g2d.fill(generalPath); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setPaint(UIConstants.TEMPLATE_TAB_PANE_BACKGROUND); - //TODO hzzz delete -// if (isLeft) { -// g2d.draw(new Arc2D.Double(x[0], y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); -// } else { -// g2d.draw(new Arc2D.Double(x[0] - CORNOR_RADIUS * 2, y[0], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); -// } - -// g2d.draw(new Line2D.Double(x[0], y[0] + CORNOR_RADIUS, x[1], y[1] + 1)); -// g2d.draw(new Line2D.Double(x[1], y[1], x[2], y[2])); - g2d.draw(new Line2D.Double(x[2], y[2], x[3], y[3] + CORNOR_RADIUS)); -// if (isLeft) { -// g2d.draw(new Arc2D.Double(x[3], y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, 90, 0)); -// } else { -// g2d.draw(new Arc2D.Double(x[3] - CORNOR_RADIUS * 2, y[3], CORNOR_RADIUS * 2, CORNOR_RADIUS * 2, 90, -90, 0)); -// } - - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - int sheetIconY = (getHeight() - sheeticon.getIconHeight()) / 2; - sheeticon.paintIcon(this, g2d, (int) templateStartX + GAP, sheetIconY); - // 画字符 - g2d.setPaint(getForeground()); - g2d.drawString(sheetName, (int) templateStartX + sheeticon.getIconWidth() + 2 * GAP, getHeight() - GAP * 2); - int closeY = (getHeight() - closeIcon.getIconHeight()) / 2; - int closePosition = (int) templateStartX + realWidth - CLOSE.getIconWidth() - SMALLGAP; - if (!DesignerMode.isVcsMode()) { - closeIcon.paintIcon(this, g2d, closePosition, closeY); - } - return closePosition; - } - - - private void unSelectedClosedPath(GeneralPath generalPath, boolean isLeft, double[] x, double[] y) { - - if (isLeft) { - generalPath.moveTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); - generalPath.curveTo(((float) x[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), x[0], y[0] + CORNOR_RADIUS); - } else { - generalPath.moveTo((float) x[0] - CORNOR_RADIUS, (float) y[0]); - generalPath.curveTo(((float) x[0] - CORNOR_RADIUS + SPECIAL_LOCATION_1), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[0] - CORNOR_RADIUS + SPECIAL_LOCATION_2), (y[0] + CORNOR_RADIUS - SPECIAL_LOCATION_1), x[0], y[0] + CORNOR_RADIUS); - } - - for (int index = 1; index <= 2; index++) { - generalPath.lineTo((float) x[index], (float) y[index]); - } - - generalPath.lineTo((float) x[3], (float) y[3] + CORNOR_RADIUS); - - if (isLeft) { - generalPath.curveTo(((float) x[3] + CORNOR_RADIUS - SPECIAL_LOCATION_1), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) y[3] - CORNOR_RADIUS + SPECIAL_LOCATION_1), (float) x[3] + CORNOR_RADIUS, (float) y[3]); - generalPath.lineTo((float) x[0] + CORNOR_RADIUS, (float) y[0]); - } else { - generalPath.curveTo(((float) x[3] - CORNOR_RADIUS + SPECIAL_LOCATION_1), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_2), ((float) x[3] - CORNOR_RADIUS + SPECIAL_LOCATION_2), ((float) y[3] + CORNOR_RADIUS - SPECIAL_LOCATION_1), (float) x[3] - CORNOR_RADIUS, (float) y[3]); - generalPath.lineTo((float) x[0] - CORNOR_RADIUS, (float) y[0]); - } - - generalPath.closePath(); - } - - - public void setIsCloseCurrent(boolean isCloseCurrent) { - this.isCloseCurrent = isCloseCurrent; - - } - - /** - * 关闭模板 - * - * @param specifiedTemplate 模板 - */ - public void closeSpecifiedTemplate(JTemplate specifiedTemplate) { - if (specifiedTemplate == null) { - return; - } - - if (!specifiedTemplate.isALLSaved() && !DesignerMode.isVcsMode()) { - specifiedTemplate.stopEditing(); - int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + specifiedTemplate.getEditingFILE() + "\" ?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (returnVal == JOptionPane.YES_OPTION) { - CallbackSaveWorker worker = specifiedTemplate.save(); - worker.addSuccessCallback(new Runnable() { - @Override - public void run() { - FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); - closeTpl(specifiedTemplate); - } - }); - worker.start(specifiedTemplate.getRuntimeId()); - } else if (returnVal == JOptionPane.NO_OPTION) { - closeTpl(specifiedTemplate); - } - } else { - closeTpl(specifiedTemplate); - } - - } - - private void closeTpl(@Nonnull JTemplate specifiedTemplate) { - HistoryTemplateListCache.getInstance().closeSelectedReport(specifiedTemplate); - closeAndFreeLock(specifiedTemplate); - activePrevTemplateAfterClose(); - } - - private void closeAndFreeLock(@Nonnull JTemplate template) { - FILE file = template.getEditingFILE(); - // 只有是环境内的文件,才执行释放锁 - if (file != null && file.isEnvFile()) { - // release lock - TemplateResourceManager.getResource().closeTemplate(file.getPath()); - } - } - - /** - * 后台关闭当前编辑模板 - */ - public void closeCurrentTpl(){ - JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - this.setIsCloseCurrent(true); - this.closeFormat(jTemplate); - this.closeSpecifiedTemplate(jTemplate); - } - - /** - * 关闭模板 - * - * @param closedTemplate 模板 - */ - public void closeFormat(JTemplate closedTemplate) { - //表单不需要处理 - if (!closedTemplate.isJWorkBook()) { - return; - } - - if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_NULL) { - return; - } - - //是被参照的模板被关闭,则重置格式刷 - closedTemplate.doConditionCancelFormat(); - } - - /** - * 关闭掉一个模板之后激活新的待显示模板 - */ public void activePrevTemplateAfterClose() { - if (openedTemplate.isEmpty()) { - //新建并激活模板 - DesignerContext.getDesignerFrame().addAndActivateJTemplate(); - selectedIndex = 0; - //此时刚自动新建的模板在HistoryTemplateListCache的editingTemplate - temTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - - } else { - // 如果关闭的模板是当前选中的模板,则重新激活当前 selectIndex 的模板; - // selectIndex 没有变化,但是对应的模板已经变成了前一张模板 - if (closeIconIndex == selectedIndex || isCloseCurrent) { - // 如果当前关闭的模板在最右侧,那么预览上一个,防止数组越界 - if (selectedIndex >= maxPaintIndex) { - // selectIndex 不会 <0 因为如果关闭的是打开的最后一个模板,那么关闭之后 openedTemplate.isEmpty() = true - selectedIndex--; - } - isCloseCurrent = false; - } - // 如果关闭的模板不是当前选中的模板,那么重新获取一下当前模板的 index,激活该 index - else { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - selectedIndex = HistoryTemplateListCache.getInstance().contains(template); - } - if (selectedIndex < openedTemplate.size()) { - //如果是已后台关闭的模板,则重新打开文件 - openedTemplate.get(selectedIndex).activeOldJTemplate(); - } - - } - } - - - private boolean isOverCloseIcon(int evtX) { - boolean isOverCloseIcon = false; - for (int i = 0; i < startX.length; i++) { - if (evtX >= startX[i] && evtX <= startX[i] + CLOSE.getIconWidth()) { - isOverCloseIcon = true; - break; - } - } - return isOverCloseIcon; - } - - - private boolean isOverListDown(int evtX) { - int maxWidth = getWidth() - LIST_BUTTON_WIDTH; - return evtX >= (maxWidth + SMALLGAP) && evtX <= (getWidth() - SMALLGAP); - } - - - private int getTemplateIndex(int evtX) { - int textX = 0; - for (int i = minPaintIndex; i <= maxPaintIndex; i++) { - int textWidth = realWidth; - if (evtX >= textX && evtX < textX + textWidth) { - return i; - } - textX += textWidth; - } - return -1; - } - - - /** - * 处理自动新建的模板 在切换时的处理 - */ - public void doWithtemTemplate() { - //temtemplate保存的一定是手动新建的没有编辑或是编辑了没有保存的模板 - //没有保存,说明有编辑;已经保存在磁盘里的文件,说明有过处理,并且已经保存,此时切换都不将其自动关闭 - if (temTemplate == null || temTemplate == HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()) { - return; - } - - if (!temTemplate.isSaved() || !temTemplate.getEditingFILE().isMemFile()) { - temTemplate = null; - } - - //自动新建的模板B若没有进行任何编辑(新建模板没有进行任何编辑时saved都是true):还没有存盘 - if (temTemplate != null && temTemplate.getEditingFILE().isMemFile() && temTemplate.isSaved()) { - HistoryTemplateListCache.getInstance().closeSelectedReport(temTemplate); - temTemplate = null; - setSelectedIndex(HistoryTemplateListCache.getInstance().contains(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate())); - } - } - - private class UIListDownItemUI extends BasicMenuItemUI { - @Override - protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { - if (menuItem.getIcon() == null) { - super.paintBackground(g, menuItem, bgColor); - return; - } - ButtonModel model = menuItem.getModel(); - Color oldColor = g.getColor(); - int menuWidth = menuItem.getWidth(); - int menuHeight = menuItem.getHeight(); - g.setColor(UIConstants.NORMAL_BACKGROUND); - g.fillRect(0, 0, menuWidth, menuHeight); - boolean itemIsSelected = menuItem instanceof JMenu && model.isSelected(); - if (menuItem.isOpaque()) { - if (model.isArmed() || itemIsSelected) { - GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, UIConstants.FLESH_BLUE, UIConstants.ARC); - } else { - GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, menuItem.getBackground(), UIConstants.ARC); - } - g.setColor(oldColor); - } else if (model.isArmed() || itemIsSelected) { - GUIPaintUtils.fillPaint((Graphics2D) g, GAP, 0, menuWidth - GAP, menuHeight, true, Constants.NULL, UIConstants.FLESH_BLUE, UIConstants.ARC); - g.setColor(oldColor); - } - } - } - - private class MultiTemplateTabMouseListener implements MouseListener { - - - /** - * 鼠标进入 - * - * @param e 鼠标事件 - */ - @Override - public void mouseEntered(MouseEvent e) { - // do nothing - } - - /** - * 鼠标离开 - * - * @param e 鼠标事件 - */ - @Override - public void mouseExited(MouseEvent e) { - listDownMode = LIST_DOWN; - closeIconIndex = -1; - mouseOveredIndex = -1; - MutilTempalteTabPane.this.repaint(); - } - - /** - * 鼠标释放 - * - * @param e 鼠标事件 - */ - @Override - public void mouseReleased(MouseEvent e) { - // do nothing - } - - /** - * 点击 - * - * @param e 鼠标事件 - */ - @Override - public void mouseClicked(MouseEvent e) { - // do nothing - } - - /** - * 按下 - * - * @param e 鼠标事件 - */ - @Override - public void mousePressed(MouseEvent e) { - //如果在版本管理情况下,不允许切换tab - if (DesignerMode.isVcsMode()) { - return; - } - - int evtX = e.getX(); - - //是否点击关闭按钮 如果点击了关闭按钮,则将点击的模板关闭,不需要切换,如果没有点击关闭按钮,则切换到点击的模板处 - boolean isOverCloseIcon = isOverCloseIcon(evtX); - if (isOverListDown(evtX)) { - listDownMode = isOverListDown(evtX) ? MOUSE_PRESS_LIST_DOWN : LIST_DOWN; - if (!isShowList) { - showListDown(); - } - isShowList = !isShowList; - - } else if (isOverCloseIcon) { - //关闭按钮的图标变化 - closeIconIndex = getTemplateIndex(evtX); - clodeMode = MOUSE_PRESS_CLOSE; - //关闭close图标所在的模板{ - JTemplate template = openedTemplate.get(closeIconIndex); - if (template.isOpening()) { - WorkerManager.getInstance().cancelWorker(template.getPath()); - } else if (template.isSaving()) { - boolean completed = WorkerManager.getInstance().isCompleted(template.getTarget().getTemplateID()); - if (!completed) { - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Close_Template_Tip", template.getEditingFILE().getName())); - return; - } - } - closeFormat(template); - closeSpecifiedTemplate(template); - DesignerContext.getDesignerFrame().getContentFrame().repaint(); - isShowList = false; - } else { - //没有点击关闭和ListDown按钮,则切换到点击的模板处 - closeIconIndex = -1; - clodeMode = CLOSE; - int tempSelectedIndex = selectedIndex; - if (selectedIndex != getTemplateIndex(evtX) && getTemplateIndex(evtX) != -1) { - openedTemplate.get(selectedIndex).stopEditing(); - selectedIndex = getTemplateIndex(evtX); - //如果在权限编辑情况下,不允许切换到表单类型的工作簿 - if (DesignerMode.isAuthorityEditing() && !openedTemplate.get(selectedIndex).isJWorkBook()) { - DesignerContext.getDesignerFrame().addAndActivateJTemplate(openedTemplate.get(tempSelectedIndex)); - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Form_Authority_Edited_Cannot_Be_Supported") - + "!", Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.WARNING_MESSAGE); - MutilTempalteTabPane.this.repaint(); - return; - } - JTemplate evtXTemplate = openedTemplate.get(getTemplateIndex(evtX)); - evtXTemplate.activeNewJTemplate(); - } - isShowList = false; - } - MutilTempalteTabPane.this.repaint(); - - - } - - - } - - private class MultiTemplateTabMouseMotionListener implements MouseMotionListener { - /** - * 鼠标拖拽 - * - * @param e 鼠标事件 - */ - @Override - public void mouseDragged(MouseEvent e) { - // do nothing - } - - /** - * 鼠标移动 - * - * @param e 鼠标事件 - */ - @Override - public void mouseMoved(MouseEvent e) { - int evtX = e.getX(); - mouseOveredIndex = getTemplateIndex(evtX); - - //看是否需要显示toolTip - if (mouseOveredIndex != -1 && isNeedToolTips[mouseOveredIndex - minPaintIndex]) { - setToolTipText(openedTemplate.get(mouseOveredIndex).getEditingFILE().getName()); - } else { - setToolTipText(null); - } - - listDownMode = isOverListDown(evtX) ? MOUSE_OVER_LIST_DOWN : LIST_DOWN; - - boolean isOverCloseIcon = isOverCloseIcon(evtX); - clodeMode = isOverCloseIcon ? MOUSE_OVER_CLOSE : CLOSE; - closeIconIndex = isOverCloseIcon ? mouseOveredIndex : -1; - MutilTempalteTabPane.this.repaint(); - } + MultiTemplateTabPane.getInstance().activePrevTemplateAfterClose(); } - - } diff --git a/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java b/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java index 7fef2e379b..72945b31c9 100644 --- a/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java +++ b/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java @@ -17,7 +17,6 @@ import com.fr.design.mainframe.JTemplate; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; -import com.fr.stable.ProductConstants; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -43,17 +42,27 @@ public class SaveSomeTemplatePane extends BasicPane { private boolean isJudgeCurrentEditingTemplate = true; public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent) { + this(isNeedTojudgeCurrent, DesignerContext.getDesignerFrame()); + } + + /** + * 支持自定义设置 dialog的父窗口 + * @param isNeedTojudgeCurrent + * @param parent + */ + public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent, Window parent) { this.setLayout(FRGUIPaneFactory.createBorderLayout()); if (this.dialog == null) { - this.dialog = this.showSmallWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + this.dialog = this.showSmallWindow(parent, new DialogActionAdapter() { @Override public void doOk() { + isAllSaved = true; for (int i = 0; i < templateCheckBoxes.length; i++) { if (templateCheckBoxes[i].isSelected()) { - saveSelectedTemplate(unSavedTemplate.get(i)); + // 当存在模板保存失败时,视为整体的isAllSaved失败 + isAllSaved = saveSelectedTemplate(unSavedTemplate.get(i)) && isAllSaved; } } - isAllSaved = true; } public void doCancel() { @@ -180,31 +189,15 @@ public class SaveSomeTemplatePane extends BasicPane { } - private void saveSelectedTemplate(JTemplate specifiedTemplate) { + private boolean saveSelectedTemplate(JTemplate specifiedTemplate) { if (!specifiedTemplate.isSaved()) { specifiedTemplate.stopEditing(); - specifiedTemplate.saveTemplate(); + return specifiedTemplate.saveTemplate(); } FineLoggerFactory.getLogger().info( com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); + return true; } - - public int saveLastOneTemplate() { - JTemplate specifiedTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); - if (!specifiedTemplate.isALLSaved()) { - specifiedTemplate.stopEditing(); - int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + specifiedTemplate.getEditingFILE() + "\" ?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (returnVal == JOptionPane.YES_OPTION) { - specifiedTemplate.saveTemplate(); - FineLoggerFactory.getLogger().info(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); - } - return returnVal; - } - return JOptionPane.YES_OPTION; - } - - protected String title4PopupWindow() { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Save"); } diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java b/designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java new file mode 100644 index 0000000000..08531b895c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java @@ -0,0 +1,82 @@ +package com.fr.design.file; + +import com.fr.base.FRContext; +import com.fr.design.gui.itree.filetree.TemplateDirTree; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirSearchRemindPane; +import com.fr.file.filetree.IOFileNodeFilter; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.tree.TreePath; +import java.awt.BorderLayout; +import java.awt.Color; + +/** + * 目录树面板 + */ +public class TemplateDirTreePane extends JPanel { + + public static TemplateDirTreePane getInstance() { + return TemplateDirTreePane.HOLDER.singleton; + } + + private static class HOLDER { + private static TemplateDirTreePane singleton = new TemplateDirTreePane(); + } + + private TemplateDirTree templateDirTree; + private TemplateDirSearchRemindPane remindPane; + + public TemplateDirTreePane() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setBorder(BorderFactory.createLineBorder(Color.gray)); + templateDirTree = new TemplateDirTree(); + remindPane = new TemplateDirSearchRemindPane(getTemplateDirTree()); + + this.add(remindPane, BorderLayout.CENTER); + } + + public TemplateDirTree getTemplateDirTree() { + return this.templateDirTree; + } + + /** + * 判断所选的目录是否有权限 + * + * @return + */ + public boolean selectedAccess() { + TreePath[] selectedTreePaths = templateDirTree.getSelectionPaths(); + + if (ArrayUtils.isEmpty(selectedTreePaths)) { + return false; + } + // 选中的是文件夹 + TreePath treePath = selectedTreePaths[0]; + ExpandMutableTreeNode currentTreeNode = (ExpandMutableTreeNode) treePath.getLastPathComponent(); + return currentTreeNode != null && currentTreeNode.hasFullAuthority(); + } + + public void refresh() { + // 刷新远程文件夹权限 + NodeAuthProcessor.getInstance().refresh(); + templateDirTree.refresh(); + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); + FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); + } + + /** + * 刷新 + */ + public void refreshDockingView() { + templateDirTree.setFileNodeFilter(new IOFileNodeFilter(FRContext.getFileNodes().getSupportedTypes())); + templateDirTree.refreshEnv(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateResource.java b/designer-base/src/main/java/com/fr/design/file/TemplateResource.java index f394822d6b..0bc8b5c96f 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateResource.java +++ b/designer-base/src/main/java/com/fr/design/file/TemplateResource.java @@ -67,5 +67,11 @@ public interface TemplateResource { */ boolean mkdir(String path); - + /** + * 复制模板 + * @param from 源模板路径 + * @param to 目标模板路径 + * @return + */ + boolean copy(String from, String to); } diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java index 363eb1ab07..d985595f5f 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java +++ b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java @@ -7,12 +7,17 @@ import com.fr.base.FRContext; import com.fr.design.ExtraDesignClassManager; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.fun.TemplateTreeDefineProcessor; -import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.itree.filetree.TemplateFileTree; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.lock.LockInfoUtils; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.lock.LockInfoDialog; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateSearchRemindPane; import com.fr.file.FILE; import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; @@ -21,12 +26,15 @@ import com.fr.form.fit.web.editpreview.FileLockStateObservable; import com.fr.general.ComparatorUtils; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; +import com.fr.workspace.base.UserInfo; import com.fr.stable.ArrayUtils; import com.fr.stable.CoreConstants; import com.fr.stable.StableUtils; import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; +import com.fr.report.lock.LockInfoOperator; +import java.util.UUID; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; @@ -50,6 +58,11 @@ import java.util.Enumeration; import java.util.Objects; import java.util.Observable; import java.util.Observer; +import java.util.Set; +import java.util.stream.Collectors; + +import org.jetbrains.annotations.Nullable; + import static javax.swing.JOptionPane.WARNING_MESSAGE; import static javax.swing.JOptionPane.YES_NO_OPTION; @@ -65,19 +78,19 @@ public class TemplateTreePane extends JPanel implements FileOperations { } private TemplateFileTree reportletsTree; + private TemplateSearchRemindPane remindPane; private FileToolbarStateChangeListener toolBarStateChangeListener; private TemplateTreePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.setPreferredSize(new Dimension(250, super.getPreferredSize().height)); - JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - this.add(contentPane, BorderLayout.CENTER); reportletsTree = new TemplateFileTree(); + + remindPane = new TemplateSearchRemindPane(getTemplateFileTree()); + this.add(remindPane, BorderLayout.CENTER); + ToolTipManager.sharedInstance().registerComponent(reportletsTree); - UIScrollPane scrollPane = new UIScrollPane(reportletsTree); - scrollPane.setBorder(null); - contentPane.add(scrollPane, BorderLayout.CENTER); FileLockStateObservable.getInstance().addObserver(new Observer() { @Override @@ -104,6 +117,8 @@ public class TemplateTreePane extends JPanel implements FileOperations { TemplateTreeDefineProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TemplateTreeDefineProcessor.XML_TAG); if (processor != null) { processor.rightClickAction(e); + } else { + DefaultTemplateTreeDefineProcessor.getInstance().rightClickAction(e); } } } @@ -113,6 +128,7 @@ public class TemplateTreePane extends JPanel implements FileOperations { if (toolBarStateChangeListener != null) { toolBarStateChangeListener.stateChange(); } + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(reportletsTree.getSelectedFileNode()); } }; // lx: add mouse listener @@ -216,15 +232,44 @@ public class TemplateTreePane extends JPanel implements FileOperations { if (node == null) { return; } + String reportPath = reportletsTree.getSelectedTemplatePath(); + final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, reportPath); String lock = node.getLock(); - if (lock != null && !lock.equals(node.getUserID())) { + boolean showLockInfo = LockInfoUtils.isCompatibleOperator() + || LockInfoUtils.unableGetLockInfo() + || WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(selectedFilePath) + ? (lock != null && !lock.equals(node.getUserID())) + : WorkContext.getCurrent().get(LockInfoOperator.class).isTplLocked(selectedFilePath); + if (showLockInfo) { + UserInfo userInfo = WorkContext.getCurrent().get(LockInfoOperator.class).getUserInfo(selectedFilePath); + node.setLock(UUID.randomUUID().toString()); + // 对于开发者预览占位锁定 定位到tab中 + checkDevelopForBiddenTemplate(selectedFilePath); + LockInfoDialog.show(userInfo); return; + } else { + node.setLock(null); } - String reportPath = reportletsTree.getSelectedTemplatePath(); - final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, reportPath); DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); } + private void checkDevelopForBiddenTemplate(String selectedFilePath) { + JTemplate template = getOpenedTemplate(selectedFilePath); + if (template != null && template.isForbidden()) { + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); + } + } + + @Nullable + private JTemplate getOpenedTemplate(String path) { + for (JTemplate template : HistoryTemplateListCache.getInstance().getHistoryList()) { + if (ComparatorUtils.equals(template.getEditingFILE().getPath(), path)) { + return template; + } + } + return null; + } + /** * 打开文件夹 */ @@ -248,9 +293,28 @@ public class TemplateTreePane extends JPanel implements FileOperations { // 刷新远程文件夹权限 NodeAuthProcessor.getInstance().refresh(); reportletsTree.refresh(); + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); } + /** + * 刷新父目录 + */ + @Override + public void refreshParent() { + // 刷新远程文件夹权限 + NodeAuthProcessor.getInstance().refresh(); + if (reportletsTree.getSelectionCount() == 0) { + //没选中文件刷新根目录 + reportletsTree.refresh(); + return; + } + reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath())); + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); + FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully")); + } + + /** * 删除文件 * 文件夹和文件均可删除 @@ -267,7 +331,7 @@ public class TemplateTreePane extends JPanel implements FileOperations { ArrayList deletableNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodes) { - checkFreeOrLock(treeNode, deletableNodes, lockedNodes); + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, deletableNodes, lockedNodes); } if (lockedNodes.isEmpty()) { @@ -322,16 +386,23 @@ public class TemplateTreePane extends JPanel implements FileOperations { } } } - refreshAfterDelete(); + Set deletedFileNode = deletableNodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet()); + refreshAfterDelete(deletedFileNode); } - private void refreshAfterDelete() { - TreePath[] paths = reportletsTree.getSelectionPaths(); - if (paths == null) { - reportletsTree.refresh(); - } else { - for (TreePath path : Objects.requireNonNull(reportletsTree.getSelectionPaths())) { - reportletsTree.refreshParent(path); + private void refreshAfterDelete(Set deletedPaths) { + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + TemplateTreeSearchManager.getInstance().deleteMatchedNode(deletedPaths); + TemplateTreeSearchManager.getInstance().updateTemplateTree(); + TemplateTreeSearchManager.getInstance().setRefreshing(false); + } else { + TreePath[] paths = reportletsTree.getSelectionPaths(); + if (paths == null) { + reportletsTree.refresh(); + } else { + for (TreePath path : Objects.requireNonNull(reportletsTree.getSelectionPaths())) { + reportletsTree.refreshParent(path); + } } } } @@ -355,41 +426,6 @@ public class TemplateTreePane extends JPanel implements FileOperations { return success; } - private boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList dNodes, ArrayList lNodes) { - // 自己没锁 - boolean selfEmptyLock = false; - Object userObj = node.getUserObject(); - if (userObj instanceof FileNode) { - String lock = ((FileNode) userObj).getLock(); - selfEmptyLock = lock == null || ((FileNode) userObj).getUserID().equals(lock); - } - - if (node.isLeaf()) { - if (selfEmptyLock) { - dNodes.add(node); - } else { - lNodes.add(node); - } - return selfEmptyLock; - } - - ExpandMutableTreeNode[] children = reportletsTree.loadChildTreeNodes(node); - - boolean childrenEmptyLock = true; - - for (ExpandMutableTreeNode child : children) { - childrenEmptyLock = checkFreeOrLock(child, dNodes, lNodes) && childrenEmptyLock; - } - - boolean emptyLock = childrenEmptyLock && selfEmptyLock; - if (emptyLock) { - dNodes.add(node); - } else { - lNodes.add(node); - } - return emptyLock; - } - @Override public void lockFile() { @@ -433,7 +469,7 @@ public class TemplateTreePane extends JPanel implements FileOperations { ArrayList unlockedNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodes) { - checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); } if (!lockedNodes.isEmpty()) { @@ -468,32 +504,42 @@ public class TemplateTreePane extends JPanel implements FileOperations { * * @param newName 原名 * @param suffix 后缀名 + * @param baseOnSelf 检验目录时,是基于自身目录的子节点还是基于父目录的子节点进行校验 * @return 是否有重名的 */ @Override - public boolean duplicated(String newName, String suffix) { + public boolean duplicated(String newName, String suffix, boolean baseOnSelf) { // 选中的节点 TreePath treePath = reportletsTree.getSelectionPath(); if (treePath == null) { return false; } - DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent(); - TreeNode parentTreeNode = currentTreeNode.getParent(); - - Enumeration children = parentTreeNode.children(); + boolean result = false; + Enumeration children = getChild(treePath, baseOnSelf); while (children.hasMoreElements()) { DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement(); Object object = childNode.getUserObject(); if (object instanceof FileNode) { if (ComparatorUtils.equals(((FileNode) object).getName(), newName + suffix)) { - return true; + result = true; } - } else { - return false; } } - return false; + return result; + } + + private Enumeration getChild(TreePath treePath, boolean baseOnSelf) { + DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent(); + Enumeration children; + //现在可以在目录下创建目录,重命名时是基于所选节点的父目录的子目录进行校验,目录下新建子目录时,基于所选目录的子目录进行校验 + if (reportletsTree.getSelectedFileNode().isDirectory() && baseOnSelf) { + children = currentTreeNode.children(); + } else { + TreeNode parentTreeNode = currentTreeNode.getParent(); + children = parentTreeNode.children(); + } + return children; } } diff --git a/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java b/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java index cb76792a13..58406c935c 100644 --- a/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java +++ b/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java @@ -2,12 +2,7 @@ package com.fr.design.file.impl; import com.fr.design.file.TemplateResource; -import com.fr.file.FILE; import com.fr.workspace.WorkContext; -import com.fr.workspace.server.lock.TplOperator; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.OutputStream; /** * @author hades @@ -16,4 +11,10 @@ import java.io.OutputStream; */ public abstract class AbstractTemplateResource implements TemplateResource { + @Override + public boolean copy(String from, String to) { + byte[] data = WorkContext.getWorkResource().readFully(from); + WorkContext.getWorkResource().write(to, data); + return WorkContext.getWorkResource().length(to) > 0; + } } diff --git a/designer-base/src/main/java/com/fr/design/formula/FRFormulaLexer.java b/designer-base/src/main/java/com/fr/design/formula/FRFormulaLexer.java new file mode 100644 index 0000000000..23c15d98ac --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/FRFormulaLexer.java @@ -0,0 +1,1689 @@ +package com.fr.design.formula; + +import com.fr.parser.FRParserTokenTypes; +import com.fr.third.antlr.ByteBuffer; +import com.fr.third.antlr.CharBuffer; +import com.fr.third.antlr.CharStreamException; +import com.fr.third.antlr.CharStreamIOException; +import com.fr.third.antlr.InputBuffer; +import com.fr.third.antlr.LexerSharedInputState; +import com.fr.third.antlr.NoViableAltForCharException; +import com.fr.third.antlr.RecognitionException; +import com.fr.third.antlr.Token; +import com.fr.third.antlr.TokenStream; +import com.fr.third.antlr.TokenStreamException; +import com.fr.third.antlr.TokenStreamIOException; +import com.fr.third.antlr.TokenStreamRecognitionException; +import com.fr.third.antlr.collections.impl.BitSet; + +import java.io.InputStream; +import java.io.Reader; +import java.util.Hashtable; + +/** + * @author Hoky + * @date 2021/11/22 + */ + +public class FRFormulaLexer extends com.fr.third.antlr.CharScanner implements FRParserTokenTypes, TokenStream { + public FRFormulaLexer(InputStream in) { + this(new ByteBuffer(in)); + } + + public FRFormulaLexer(Reader in) { + this(new CharBuffer(in)); + } + + public FRFormulaLexer(InputBuffer ib) { + this(new LexerSharedInputState(ib)); + } + + public FRFormulaLexer(LexerSharedInputState state) { + super(state); + caseSensitiveLiterals = true; + setCaseSensitive(true); + literals = new Hashtable(); + } + + public Token nextToken() throws TokenStreamException { + Token theRetToken = null; + tryAgain: + for (; ; ) { + Token _token = null; + int _ttype = Token.INVALID_TYPE; + resetText(); + try { // for char stream error handling + try { // for lexical error handling + switch (LA(1)) { + case '?': { + mQUESTION(true); + theRetToken = _returnToken; + break; + } + case '(': { + mLPAREN(true); + theRetToken = _returnToken; + break; + } + case ')': { + mRPAREN(true); + theRetToken = _returnToken; + break; + } + case '[': { + mLBRACK(true); + theRetToken = _returnToken; + break; + } + case ']': { + mRBRACK(true); + theRetToken = _returnToken; + break; + } + case '{': { + mLCURLY(true); + theRetToken = _returnToken; + break; + } + case '}': { + mRCURLY(true); + theRetToken = _returnToken; + break; + } + case ',': { + mCOMMA(true); + theRetToken = _returnToken; + break; + } + case '/': { + mDIV(true); + theRetToken = _returnToken; + break; + } + case '+': { + mPLUS(true); + theRetToken = _returnToken; + break; + } + case '-': { + mMINUS(true); + theRetToken = _returnToken; + break; + } + case '*': { + mSTAR(true); + theRetToken = _returnToken; + break; + } + case '%': { + mMOD(true); + theRetToken = _returnToken; + break; + } + case '^': { + mPOWER(true); + theRetToken = _returnToken; + break; + } + case ';': { + mSEMI(true); + theRetToken = _returnToken; + break; + } + case '#': { + mSHARP(true); + theRetToken = _returnToken; + break; + } + case '@': { + mAT(true); + theRetToken = _returnToken; + break; + } + case '~': { + mWAVE(true); + theRetToken = _returnToken; + break; + } + case '`': { + mALLL2(true); + theRetToken = _returnToken; + break; + } + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + mINT_NUM(true); + theRetToken = _returnToken; + break; + } + case '"': { + mSTRING_LITERAL_DSQ(true); + theRetToken = _returnToken; + break; + } + case '\'': { + mSTRING_LITERAL_SSQ(true); + theRetToken = _returnToken; + break; + } + case '\t': + case '\n': + case '\u000c': + case '\r': + case ' ': { + mWS(true); + theRetToken = _returnToken; + break; + } + default: + if ((LA(1) == ':') && (LA(2) == ':')) { + mDCOLON(true); + theRetToken = _returnToken; + } else if ((LA(1) == '=') && (LA(2) == '=')) { + mEQUAL(true); + theRetToken = _returnToken; + } else if ((LA(1) == '!') && (LA(2) == '=')) { + mNOT_EQUAL(true); + theRetToken = _returnToken; + } else if ((LA(1) == '<') && (LA(2) == '>')) { + mNOT_EQUAL2(true); + theRetToken = _returnToken; + } else if ((LA(1) == '>') && (LA(2) == '=')) { + mGE(true); + theRetToken = _returnToken; + } else if ((LA(1) == '<') && (LA(2) == '=')) { + mLE(true); + theRetToken = _returnToken; + } else if ((LA(1) == '|') && (LA(2) == '|')) { + mLOR(true); + theRetToken = _returnToken; + } else if ((LA(1) == '&') && (LA(2) == '&')) { + mLAND(true); + theRetToken = _returnToken; + } else if ((LA(1) == '!') && (LA(2) == '0')) { + mALLL(true); + theRetToken = _returnToken; + } else if ((LA(1) == '&') && (_tokenSet_0.member(LA(2)))) { + mCR_ADRESS(true); + theRetToken = _returnToken; + } else if ((LA(1) == ':') && (true)) { + mCOLON(true); + theRetToken = _returnToken; + } else if ((LA(1) == '=') && (true)) { + mEQUAL2(true); + theRetToken = _returnToken; + } else if ((LA(1) == '!') && (true)) { + mLNOT(true); + theRetToken = _returnToken; + } else if ((LA(1) == '>') && (true)) { + mGT(true); + theRetToken = _returnToken; + } else if ((LA(1) == '<') && (true)) { + mLT(true); + theRetToken = _returnToken; + } else if ((LA(1) == '|') && (true)) { + mBOR(true); + theRetToken = _returnToken; + } else if ((LA(1) == '&') && (true)) { + mBAND(true); + theRetToken = _returnToken; + } else if ((_tokenSet_1.member(LA(1)))) { + mIDENT(true); + theRetToken = _returnToken; + } else { + if (LA(1) == EOF_CHAR) { + uponEOF(); + _returnToken = makeToken(Token.EOF_TYPE); + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + } + if (_returnToken == null) continue tryAgain; // found SKIP token + _ttype = _returnToken.getType(); + _ttype = testLiteralsTable(_ttype); + _returnToken.setType(_ttype); + return _returnToken; + } catch (RecognitionException e) { + throw new TokenStreamRecognitionException(e); + } + } catch (CharStreamException cse) { + if (cse instanceof CharStreamIOException) { + throw new TokenStreamIOException(((CharStreamIOException) cse).io); + } else { + throw new TokenStreamException(cse.getMessage()); + } + } + } + } + + public final void mQUESTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = QUESTION; + int _saveIndex; + + match('?'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LPAREN; + int _saveIndex; + + match('('); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mRPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = RPAREN; + int _saveIndex; + + match(')'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLBRACK(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LBRACK; + int _saveIndex; + + match('['); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mRBRACK(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = RBRACK; + int _saveIndex; + + match(']'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLCURLY(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LCURLY; + int _saveIndex; + + match('{'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mRCURLY(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = RCURLY; + int _saveIndex; + + match('}'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mCOLON(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = COLON; + int _saveIndex; + + match(':'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mDCOLON(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = DCOLON; + int _saveIndex; + + match("::"); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mCOMMA(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = COMMA; + int _saveIndex; + + match(','); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mEQUAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = EQUAL; + int _saveIndex; + + match("=="); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mEQUAL2(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = EQUAL2; + int _saveIndex; + + match('='); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLNOT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LNOT; + int _saveIndex; + + match('!'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mNOT_EQUAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = NOT_EQUAL; + int _saveIndex; + + match("!="); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mNOT_EQUAL2(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = NOT_EQUAL2; + int _saveIndex; + + match("<>"); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mDIV(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = DIV; + int _saveIndex; + + match('/'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mPLUS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = PLUS; + int _saveIndex; + + match('+'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mMINUS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = MINUS; + int _saveIndex; + + match('-'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mSTAR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = STAR; + int _saveIndex; + + match('*'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mMOD(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = MOD; + int _saveIndex; + + match('%'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mPOWER(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = POWER; + int _saveIndex; + + match('^'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mGE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = GE; + int _saveIndex; + + match(">="); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mGT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = GT; + int _saveIndex; + + match('>'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LE; + int _saveIndex; + + match("<="); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LT; + int _saveIndex; + + match('<'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mBOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = BOR; + int _saveIndex; + + match('|'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mBAND(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = BAND; + int _saveIndex; + + match('&'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LOR; + int _saveIndex; + + match("||"); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mLAND(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LAND; + int _saveIndex; + + match("&&"); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mSEMI(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = SEMI; + int _saveIndex; + + match(';'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mSHARP(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = SHARP; + int _saveIndex; + + match('#'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mAT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = AT; + int _saveIndex; + + match('@'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mWAVE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = WAVE; + int _saveIndex; + + match('~'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mALLL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = ALLL; + int _saveIndex; + + match('!'); + match('0'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mALLL2(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = ALLL2; + int _saveIndex; + + match('`'); + match('0'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mIDENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = IDENT; + int _saveIndex; + + mChar(false); + { + _loop109: + do { + if ((_tokenSet_1.member(LA(1)))) { + mChar(false); + } else if (((LA(1) >= '0' && LA(1) <= '9'))) { + { + mDIGIT(false); + } + } else { + break _loop109; + } + + } while (true); + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + /** + * 'a'..'z', '_', 'A'..'Z' and others without number + */ + protected final void mChar(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = Char; + int _saveIndex; + + switch (LA(1)) { + case '$': { + match('\u0024'); + break; + } + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': { + matchRange('\u0041', '\u005a'); + break; + } + case '_': { + match('\u005f'); + break; + } + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': { + matchRange('\u0061', '\u007a'); + break; + } + case '\u00c0': + case '\u00c1': + case '\u00c2': + case '\u00c3': + case '\u00c4': + case '\u00c5': + case '\u00c6': + case '\u00c7': + case '\u00c8': + case '\u00c9': + case '\u00ca': + case '\u00cb': + case '\u00cc': + case '\u00cd': + case '\u00ce': + case '\u00cf': + case '\u00d0': + case '\u00d1': + case '\u00d2': + case '\u00d3': + case '\u00d4': + case '\u00d5': + case '\u00d6': { + matchRange('\u00c0', '\u00d6'); + break; + } + case '\u00d8': + case '\u00d9': + case '\u00da': + case '\u00db': + case '\u00dc': + case '\u00dd': + case '\u00de': + case '\u00df': + case '\u00e0': + case '\u00e1': + case '\u00e2': + case '\u00e3': + case '\u00e4': + case '\u00e5': + case '\u00e6': + case '\u00e7': + case '\u00e8': + case '\u00e9': + case '\u00ea': + case '\u00eb': + case '\u00ec': + case '\u00ed': + case '\u00ee': + case '\u00ef': + case '\u00f0': + case '\u00f1': + case '\u00f2': + case '\u00f3': + case '\u00f4': + case '\u00f5': + case '\u00f6': { + matchRange('\u00d8', '\u00f6'); + break; + } + case '\u00f8': + case '\u00f9': + case '\u00fa': + case '\u00fb': + case '\u00fc': + case '\u00fd': + case '\u00fe': + case '\u00ff': { + matchRange('\u00f8', '\u00ff'); + break; + } + default: + if (((LA(1) >= '\u0100' && LA(1) <= '\u1fff'))) { + matchRange('\u0100', '\u1fff'); + } else if (((LA(1) >= '\u3040' && LA(1) <= '\u318f'))) { + matchRange('\u3040', '\u318f'); + } else if (((LA(1) >= '\u3300' && LA(1) <= '\u337f'))) { + matchRange('\u3300', '\u337f'); + } else if (((LA(1) >= '\u3400' && LA(1) <= '\u3d2d'))) { + matchRange('\u3400', '\u3d2d'); + } else if (((LA(1) >= '\u4e00' && LA(1) <= '\u9fff'))) { + matchRange('\u4e00', '\u9fff'); + } else if (((LA(1) >= '\uf900' && LA(1) <= '\ufaff'))) { + matchRange('\uf900', '\ufaff'); + } else if (((LA(1) >= '\uac00' && LA(1) <= '\ud7af'))) { + matchRange('\uac00', '\ud7af'); + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + protected final void mDIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = DIGIT; + int _saveIndex; + + matchRange('0', '9'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mCR_ADRESS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = CR_ADRESS; + int _saveIndex; + + mBAND(false); + { + int _cnt112 = 0; + _loop112: + do { + if ((_tokenSet_0.member(LA(1)))) { + mLETTER(false); + } else { + if (_cnt112 >= 1) { + break _loop112; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt112++; + } while (true); + } + { + int _cnt114 = 0; + _loop114: + do { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + mDIGIT(false); + } else { + if (_cnt114 >= 1) { + break _loop114; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt114++; + } while (true); + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + protected final void mLETTER(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = LETTER; + int _saveIndex; + + switch (LA(1)) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': { + matchRange('A', 'Z'); + break; + } + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': { + matchRange('a', 'z'); + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mINT_NUM(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = INT_NUM; + int _saveIndex; + + switch (LA(1)) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + { + int _cnt117 = 0; + _loop117: + do { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + mDIGIT(false); + } else { + if (_cnt117 >= 1) { + break _loop117; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt117++; + } while (true); + } + { + if ((LA(1) == '.')) { + match('.'); + { + _loop120: + do { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + mDIGIT(false); + } else { + break _loop120; + } + + } while (true); + } + _ttype = FLOT_NUM; + } else { + } + + } + { + if ((LA(1) == 'E' || LA(1) == 'e')) { + mExponent(false); + _ttype = FLOT_NUM; + } else { + } + + } + + //System.out.println("number like 1.2e+12"); + + break; + } + case '.': { + match('.'); + _ttype = DOT; + { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + { + int _cnt124 = 0; + _loop124: + do { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + mDIGIT(false); + } else { + if (_cnt124 >= 1) { + break _loop124; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt124++; + } while (true); + } + { + if ((LA(1) == 'E' || LA(1) == 'e')) { + mExponent(false); + } else { + } + + } + _ttype = FLOT_NUM; + } else { + } + + } + + //System.out.println("number like .3e-2"); + + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + protected final void mExponent(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = Exponent; + int _saveIndex; + + { + switch (LA(1)) { + case 'e': { + match('e'); + break; + } + case 'E': { + match('E'); + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + } + { + switch (LA(1)) { + case '+': { + match('+'); + break; + } + case '-': { + match('-'); + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + } + { + int _cnt144 = 0; + _loop144: + do { + if (((LA(1) >= '0' && LA(1) <= '9'))) { + mDIGIT(false); + } else { + if (_cnt144 >= 1) { + break _loop144; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt144++; + } while (true); + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mSTRING_LITERAL_DSQ(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = STRING_LITERAL_DSQ; + int _saveIndex; + + match('"'); + { + _loop128: + do { + if ((LA(1) == '\\')) { + mESC(false); + } else if ((_tokenSet_2.member(LA(1)))) { + matchNot('"'); + } else { + break _loop128; + } + + } while (true); + } + match('"'); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + protected final void mESC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = ESC; + int _saveIndex; + + match('\\'); + { + switch (LA(1)) { + case 'n': { + match('n'); + break; + } + case 'r': { + match('r'); + break; + } + case 't': { + match('t'); + break; + } + case 'b': { + match('b'); + break; + } + case 'f': { + match('f'); + break; + } + case '"': { + match('"'); + break; + } + case '\'': { + match('\''); + break; + } + case '\\': { + match('\\'); + break; + } + case 'u': { + { + int _cnt136 = 0; + _loop136: + do { + if ((LA(1) == 'u')) { + match('u'); + } else { + if (_cnt136 >= 1) { + break _loop136; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + + _cnt136++; + } while (true); + } + mXDIGIT(false); + mXDIGIT(false); + mXDIGIT(false); + mXDIGIT(false); + break; + } + case '0': + case '1': + case '2': + case '3': { + matchRange('0', '3'); + { + if (((LA(1) >= '0' && LA(1) <= '7')) && ((LA(2) >= '\u0003' && LA(2) <= '\ufffe'))) { + matchRange('0', '7'); + { + if (((LA(1) >= '0' && LA(1) <= '7')) && ((LA(2) >= '\u0003' && LA(2) <= '\ufffe'))) { + matchRange('0', '7'); + } else if (((LA(1) >= '\u0003' && LA(1) <= '\ufffe')) && (true)) { + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + + } + } else if (((LA(1) >= '\u0003' && LA(1) <= '\ufffe')) && (true)) { + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + + } + break; + } + case '4': + case '5': + case '6': + case '7': { + matchRange('4', '7'); + { + if (((LA(1) >= '0' && LA(1) <= '7')) && ((LA(2) >= '\u0003' && LA(2) <= '\ufffe'))) { + matchRange('0', '7'); + } else if (((LA(1) >= '\u0003' && LA(1) <= '\ufffe')) && (true)) { + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + + } + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mSTRING_LITERAL_SSQ(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = STRING_LITERAL_SSQ; + int _saveIndex; + + match('\''); + { + _loop131: + do { + if ((LA(1) == '\\')) { + mESC(false); + } else if ((_tokenSet_3.member(LA(1)))) { + matchNot('\''); + } else { + break _loop131; + } + + } while (true); + } + match('\''); + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + protected final void mXDIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = XDIGIT; + int _saveIndex; + + switch (LA(1)) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + matchRange('0', '9'); + break; + } + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': { + matchRange('a', 'f'); + break; + } + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': { + matchRange('A', 'F'); + break; + } + default: { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + public final void mWS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException { + int _ttype; + Token _token = null; + int _begin = text.length(); + _ttype = WS; + int _saveIndex; + + { + int _cnt151 = 0; + _loop151: + do { + switch (LA(1)) { + case ' ': { + match(' '); + break; + } + case '\t': { + match('\t'); + break; + } + case '\u000c': { + match('\f'); + break; + } + case '\n': + case '\r': { + { + if ((LA(1) == '\r') && (LA(2) == '\n')) { + match("\r\n"); + } else if ((LA(1) == '\r') && (true)) { + match('\r'); + } else if ((LA(1) == '\n')) { + match('\n'); + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + + } + //new line 不生效情况居多,此line对于公式语法的检测没有什么作用,还不如直接用column定位,表示第xx个字符 + //newline(); + break; + } + default: { + if (_cnt151 >= 1) { + break _loop151; + } else { + throw new NoViableAltForCharException((char) LA(1), getFilename(), getLine(), getColumn()); + } + } + } + _cnt151++; + } while (true); + } + _ttype = Token.SKIP; + if (_createToken && _token == null && _ttype != Token.SKIP) { + _token = makeToken(_ttype); + _token.setText(new String(text.getBuffer(), _begin, text.length() - _begin)); + } + _returnToken = _token; + } + + + private static final long[] mk_tokenSet_0() { + long[] data = new long[1025]; + data[1] = 576460743847706622L; + return data; + } + + public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0()); + + private static final long[] mk_tokenSet_1() { + long[] data = new long[3988]; + data[0] = 68719476736L; + data[1] = 576460745995190270L; + data[3] = -36028797027352577L; + for (int i = 4; i <= 127; i++) { + data[i] = -1L; + } + for (int i = 193; i <= 197; i++) { + data[i] = -1L; + } + data[198] = 65535L; + for (int i = 204; i <= 205; i++) { + data[i] = -1L; + } + for (int i = 208; i <= 243; i++) { + data[i] = -1L; + } + data[244] = 70368744177663L; + for (int i = 312; i <= 639; i++) { + data[i] = -1L; + } + for (int i = 688; i <= 861; i++) { + data[i] = -1L; + } + data[862] = 281474976710655L; + for (int i = 996; i <= 1003; i++) { + data[i] = -1L; + } + return data; + } + + public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1()); + + private static final long[] mk_tokenSet_2() { + long[] data = new long[2048]; + data[0] = -17179869192L; + data[1] = -268435457L; + for (int i = 2; i <= 1022; i++) { + data[i] = -1L; + } + data[1023] = 9223372036854775807L; + return data; + } + + public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2()); + + private static final long[] mk_tokenSet_3() { + long[] data = new long[2048]; + data[0] = -549755813896L; + data[1] = -268435457L; + for (int i = 2; i <= 1022; i++) { + data[i] = -1L; + } + data[1023] = 9223372036854775807L; + return data; + } + + public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3()); + +} + diff --git a/designer-base/src/main/java/com/fr/design/formula/FormulaChecker.java b/designer-base/src/main/java/com/fr/design/formula/FormulaChecker.java index 093f26edf8..302be0b08d 100644 --- a/designer-base/src/main/java/com/fr/design/formula/FormulaChecker.java +++ b/designer-base/src/main/java/com/fr/design/formula/FormulaChecker.java @@ -1,88 +1,48 @@ package com.fr.design.formula; +import com.fr.design.formula.exception.FormulaExceptionTipsProcessor; import com.fr.design.i18n.Toolkit; -import com.fr.log.FineLoggerFactory; -import com.fr.parser.FRLexer; import com.fr.parser.FRParser; import com.fr.script.checker.FunctionCheckerDispatcher; -import com.fr.script.checker.exception.ConditionCheckWrongException; -import com.fr.script.checker.exception.FunctionCheckWrongException; -import com.fr.script.rules.FunctionParameterType; -import com.fr.script.rules.FunctionRule; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; import com.fr.stable.StringUtils; import com.fr.stable.script.Expression; import com.fr.stable.script.Node; +import com.fr.third.antlr.TokenStreamRecognitionException; import java.io.StringReader; -import java.util.List; /** * @author Hoky * @date 2021/9/28 */ public class FormulaChecker { - private static final String VALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula"); - private static final String INVALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"); - public static final String COLON = ":"; + public static final String VALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula"); + public static final String INVALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"); + private static FormulaExceptionTipsProcessor processor = FormulaExceptionTipsProcessor.getProcessor(); - public static String check(String formulaText) { + public static FormulaCheckResult check(String formulaText) { + if (StringUtils.isEmpty(formulaText) || formulaText.equals(Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Tips"))) { + return new FormulaCheckResult(true, VALID_FORMULA, FormulaCoordinates.INVALID, true); + } + //过滤一些空格等符号 StringReader in = new StringReader(formulaText); - - FRLexer lexer = new FRLexer(in); + //此lexer为公式校验定制 + FRFormulaLexer lexer = new FRFormulaLexer(in); FRParser parser = new FRParser(lexer); try { Expression expression = parser.parse(); Node node = expression.getConditionalExpression(); - return FunctionCheckerDispatcher.getInstance() - .getFunctionChecker(node) - .checkFunction(node) ? VALID_FORMULA : INVALID_FORMULA; - } catch (ConditionCheckWrongException cce) { - String functionName = cce.getFunctionName(); - return functionName + Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Condition_Tips") + COLON; - } catch (FunctionCheckWrongException ce) { - List rules = ce.getRules(); - String functionName = ce.getFunctionName(); - StringBuilder errorMsg = new StringBuilder(functionName + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Error_Tips") + COLON); - for (int i = 0; i < rules.size(); i++) { - errorMsg.append("("); - if (rules.get(i).getParameterList().isEmpty()) { - errorMsg.append(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_No_Param")); - } - for (FunctionParameterType functionParameterType : rules.get(i).getParameterList()) { - errorMsg.append(getTypeString(functionParameterType)).append(","); - } - if (",".equals(errorMsg.charAt(errorMsg.length() - 1) + "")) { - errorMsg.deleteCharAt(errorMsg.length() - 1); - } - errorMsg.append(")"); - if (i != rules.size() - 1) { - errorMsg.append(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Or")); - } - } - return errorMsg.toString(); + boolean valid = FunctionCheckerDispatcher.getInstance().getFunctionChecker(node).checkFunction(formulaText, node); + return new FormulaCheckResult(valid, valid ? Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula") : + Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"), FormulaCoordinates.INVALID, true); } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - return INVALID_FORMULA; - // alex:继续往下面走,expression为null时告知不合法公式 - } - } - - private static String getTypeString(FunctionParameterType type) { - switch (type) { - case NUMBER: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Number"); - case STRING: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_String"); - case ANY: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Any"); - case DATE: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Date"); - case BOOLEAN: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Boolean"); - case ARRAY: - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Array"); + if (e instanceof TokenStreamRecognitionException) { + return processor.getExceptionTips(((TokenStreamRecognitionException) e).recog); + } + return processor.getExceptionTips(e); } - return StringUtils.EMPTY; } } diff --git a/designer-base/src/main/java/com/fr/design/formula/FormulaCheckerException.java b/designer-base/src/main/java/com/fr/design/formula/FormulaCheckerException.java new file mode 100644 index 0000000000..42fc585cbb --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/FormulaCheckerException.java @@ -0,0 +1,11 @@ +package com.fr.design.formula; + +public class FormulaCheckerException extends Exception { + public FormulaCheckerException() { + + } + + public FormulaCheckerException(String message) { + super(message); + } +} 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 447421a415..f53930602c 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 @@ -14,9 +14,17 @@ 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.dialog.DialogActionListener; 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; +import com.fr.design.gui.autocomplete.FormulaCompletion; +import com.fr.design.gui.autocomplete.FormulaPaneAutoCompletion; import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ilist.QuickList; @@ -30,6 +38,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; +import com.fr.design.parameter.ParameterInputNoneListenerPane; import com.fr.design.parameter.ParameterInputPane; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; @@ -40,21 +49,23 @@ import com.fr.parser.BlockIntervalLiteral; import com.fr.parser.ColumnRowRangeInPage; import com.fr.parser.NumberLiteral; import com.fr.parser.SheetIntervalLiteral; +import com.fr.record.analyzer.EnableMetrics; import com.fr.report.core.namespace.SimpleCellValueNameSpace; import com.fr.script.Calculator; import com.fr.script.ScriptConstants; +import com.fr.script.checker.result.FormulaCheckResult; import com.fr.stable.EncodeConstants; import com.fr.stable.EssentialUtils; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; -import com.fr.stable.UtilEvalError; -import com.fr.stable.script.CRAddress; +import com.fr.parser.CRAddress; import com.fr.stable.script.ColumnRowRange; import com.fr.stable.script.Expression; import com.fr.stable.script.Node; import com.fr.stable.script.Tiny; import com.fr.stable.script.TinyHunter; +import java.awt.Window; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; @@ -65,6 +76,7 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; @@ -80,8 +92,11 @@ import java.awt.BorderLayout; import java.awt.Color; 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.FocusEvent; +import java.awt.event.FocusListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -111,19 +126,25 @@ import java.util.Set; * @editor zhou * @since 2012-3-29下午1:50:53 */ +@EnableMetrics public class FormulaPane extends BasicPane implements KeyListener, UIFormula { - - public static final String VALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula"); - public static final String INVALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"); public static final int DEFUAL_FOMULA_LENGTH = 103; public static final String ELLIPSIS = "..."; + public static final char KEY_CODE_A = 'A'; + public static final char KEY_CODE_Z = 'z'; + public static final String NEWLINE = "\n"; + public static final String FORMULA_ICON = "/com/fr/design/images/m_file/formula.png"; + public static final String PARAM_ICON = "/com/fr/design/images/m_file/param.png"; private VariableTreeAndDescriptionArea variableTreeAndDescriptionArea; private RSyntaxTextArea formulaTextArea; private UITextField keyWordTextField = new UITextField(18); private int currentPosition = 0; private int beginPosition = 0; private int insertPosition = 0; + protected static UICheckBox autoCompletionCheck; + protected static UICheckBox checkBeforeColse; private JList tipsList; + private JPopupMenu popupMenu; protected DefaultListModel listModel = new DefaultListModel(); private int ifHasBeenWriten = 0; private DefaultListModel functionTypeListModel = new DefaultListModel(); @@ -131,6 +152,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private DefaultListModel functionNameModel; private JList functionNameList; private UITableEditorPane editor4CalPane; + private FormulaPaneAutoCompletion autoCompletion; + private DefaultCompletionProvider completionProvider; + private static final Map PARAM_PREFIX_MAP = new HashMap<>(); + + public static final int DESCRIPTION_TEXT_AREA_ROW = 16, DESCRIPTION_TEXT_AREA_COLUMN = 27; public FormulaPane() { initComponents(); @@ -139,6 +165,20 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initFormulaTextAreaKeyListener() { formulaTextArea.addKeyListener(this); formulaTextArea.addKeyListener(new KeyAdapter() { + //用来判断一下是不是组合键 + + @Override + public void keyTyped(KeyEvent e) { + if (inKeyCodeRange(e) && autoCompletionCheck.isSelected()) { + autoCompletion.doCompletion(); + } + } + + private boolean inKeyCodeRange(KeyEvent e) { + return (e.getKeyChar() >= KEY_CODE_A && e.getKeyChar() <= KEY_CODE_Z); + } + + @Override public void keyReleased(KeyEvent e) { formulaTextArea.setForeground(Color.black); String text = formulaTextArea.getText(); @@ -174,7 +214,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { beginPosition = getBeginPosition(); insertPosition = beginPosition; firstStepToFindTips(beginPosition); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } } } }); @@ -204,7 +246,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { if (e.getKeyCode() == KeyEvent.VK_ENTER) { String toFind = keyWordTextField.getText(); search(toFind, false); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } e.consume(); } } @@ -213,28 +257,35 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initTipsPane() { // tipsPane - JPanel tipsPane = new JPanel(new BorderLayout(4, 4)); - this.add(tipsPane, BorderLayout.EAST); + JPanel containerSPane = new JPanel(new BorderLayout(4, 1)); + JPanel labelPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0), true); + JPanel searchPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0), true); + containerSPane.setPreferredSize(new Dimension(892, 23)); + this.add(containerSPane, BorderLayout.NORTH); - JPanel searchPane = new JPanel(new BorderLayout(4, 4)); - searchPane.add(keyWordTextField, BorderLayout.CENTER); UIButton searchButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Search")); + UILabel formulaLabel = new UILabel( + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Input_Formula_In_The_Text_Area_Below") + ":"); + formulaLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + + labelPane.add(formulaLabel, BorderLayout.WEST); + keyWordTextField.setPreferredSize(new Dimension(240, 23)); + searchPane.add(keyWordTextField, BorderLayout.EAST); searchPane.add(searchButton, BorderLayout.EAST); - tipsPane.add(searchPane, BorderLayout.NORTH); + + containerSPane.add(labelPane, BorderLayout.WEST); + containerSPane.add(searchPane, BorderLayout.EAST); + initKeyWordTextFieldKeyListener(); tipsList = new JList(listModel); tipsList.addMouseListener(new DoubleClick()); - UIScrollPane tipsScrollPane = new UIScrollPane(tipsList); - tipsScrollPane.setPreferredSize(new Dimension(170, 75)); - tipsScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - tipsPane.add(tipsScrollPane, BorderLayout.CENTER); - searchButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String toFind = keyWordTextField.getText(); - search(toFind, false); - formulaTextArea.requestFocusInWindow(); - fixFunctionNameList(); + searchButton.addActionListener(e -> { + String toFind = keyWordTextField.getText(); + search(toFind, false); + popTips(); + formulaTextArea.requestFocusInWindow(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); } }); } @@ -245,6 +296,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { initTextPane(); initTipsPane(); initVariableTreeAndDescriptionArea(); + refocusInWindow(); + } + + public void refocusInWindow() { + SwingUtilities.invokeLater(() -> formulaTextArea.requestFocusInWindow()); } private void initVariableTreeAndDescriptionArea() { @@ -254,18 +310,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initTextPane() { // text - JPanel textPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); this.add(textPane, BorderLayout.CENTER); - JPanel checkBoxandbuttonPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - UILabel formulaLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Input_Formula_In_The_Text_Area_Below") + ":" - + " "); - formulaLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + JPanel checkBoxandbuttonPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); initFormulaTextArea(); UIScrollPane formulaTextAreaScrollPane = new UIScrollPane(formulaTextArea); formulaTextAreaScrollPane.setBorder(null); - textPane.add(formulaLabel, BorderLayout.NORTH); textPane.add(formulaTextAreaScrollPane, BorderLayout.CENTER); textPane.add(checkBoxandbuttonPane, BorderLayout.SOUTH); @@ -275,19 +326,108 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { checkValidButton.addActionListener(checkValidActionListener); calButton.addActionListener(calculateActionListener); + //靠左流式布局 JPanel checkBoxPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - checkBoxPane.setPreferredSize(new Dimension(450, 30)); checkBoxandbuttonPane.add(checkBoxPane, BorderLayout.WEST); - checkBoxandbuttonPane.add(checkValidButton, BorderLayout.EAST); - checkBoxandbuttonPane.add(calButton, BorderLayout.EAST); + //靠右流式布局 + JPanel buttonPane = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); + buttonPane.add(checkValidButton, BorderLayout.EAST); + buttonPane.add(calButton, BorderLayout.EAST); + checkBoxandbuttonPane.add(buttonPane, BorderLayout.EAST); + if (autoCompletionCheck == null) { + autoCompletionCheck = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_AutoCompletion")); + autoCompletionCheck.setSelected(true); + } + if (checkBeforeColse == null) { + checkBeforeColse = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Before_Closed")); + checkBeforeColse.setSelected(true); + } + checkBoxPane.add(autoCompletionCheck, BorderLayout.WEST); + checkBoxPane.add(checkBeforeColse, BorderLayout.WEST); extendCheckBoxPane(checkBoxPane); ParameterTableModel model = new ParameterTableModel(0); editor4CalPane = new UITableEditorPane<>(model); + formulaTextArea.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + // 获得焦点时 安装 + if (autoCompletion == null && autoCompletionCheck.isSelected()) { + installAutoCompletion(); + } + } + + @Override + public void focusLost(FocusEvent e) { + // 失去焦点时 卸载 + uninstallAutoCompletion(); + } + }); + } + + private CompletionProvider createCompletionProvider() { + if (completionProvider == null) { + completionProvider = new DefaultCompletionProvider(); + NameAndDescription[] nameAndDescriptions = FunctionConstants.ALL.getDescriptions(); + for (NameAndDescription nameAndDescription : nameAndDescriptions) { + completionProvider.addCompletion(new FormulaCompletion(completionProvider, nameAndDescription.getName(), BaseUtils.readIcon(FORMULA_ICON))); + } + + VariableResolver variableResolver = VariableResolver.DEFAULT; + List allParameters = new ArrayList<>(); + allParameters.addAll(Arrays.asList(variableResolver.resolveCurReportVariables())); + allParameters.addAll(Arrays.asList(variableResolver.resolveColumnNames())); + allParameters.addAll(Arrays.asList(variableResolver.resolveGlobalParameterVariables())); + allParameters.addAll(Arrays.asList(variableResolver.resolveReportParameterVariables())); + allParameters.addAll(Arrays.asList(variableResolver.resolveTableDataParameterVariables())); + + //先把参数前缀拿出来 + for (String parameter : allParameters) { + String paramWithoutPre; + if (parameter.startsWith("$$")) { + paramWithoutPre = parameter.substring(2); + PARAM_PREFIX_MAP.put(paramWithoutPre, "$$"); + } else if (parameter.startsWith("$")) { + paramWithoutPre = parameter.substring(1); + PARAM_PREFIX_MAP.put(paramWithoutPre, "$"); + } else { + paramWithoutPre = parameter; + PARAM_PREFIX_MAP.put(paramWithoutPre, StringUtils.EMPTY); + } + completionProvider.addCompletion(new FormulaCompletion(completionProvider, paramWithoutPre, BaseUtils.readIcon(PARAM_ICON))); + } + + return completionProvider; + } + return completionProvider; + } + + public static boolean containsParam(String param) { + return PARAM_PREFIX_MAP.containsKey(param); + } + + public static String getParamPrefix(String param) { + return PARAM_PREFIX_MAP.getOrDefault(param, StringUtils.EMPTY); + } + + private void uninstallAutoCompletion() { + if (autoCompletion != null) { + autoCompletion.uninstall(); + autoCompletion = null; + } + } + + private void installAutoCompletion() { + CompletionProvider provider = createCompletionProvider(); + autoCompletion = new FormulaPaneAutoCompletion(provider); + autoCompletion.setListCellRenderer(new CompletionCellRenderer()); + autoCompletion.install(formulaTextArea); + autoCompletion.installExtraRefreshComponent(variableTreeAndDescriptionArea); } protected void extendCheckBoxPane(JPanel checkBoxPane) { + // do nothing } @@ -334,6 +474,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { if (ComparatorUtils.equals((String) listModel.getElementAt(index), doublePressContent)) { doubleClickActuator(doublePressContent); } + if (popupMenu != null) { + popupMenu.setVisible(false); + } } } } @@ -341,7 +484,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void singleClickActuator(String currentLineContent) { refreshDescriptionTextArea(currentLineContent); formulaTextArea.requestFocusInWindow(); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } } private void doubleClickActuator(String currentLineContent) { @@ -405,43 +550,47 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { beginPosition = getBeginPosition(); insertPosition = beginPosition; firstStepToFindTips(beginPosition); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } ifHasBeenWriten = 1; } } } - private void fixFunctionNameList() { - if (tipsList.getSelectedValue() != null) { - int signOfContinue = 1; - int indexOfFunction = 0; - for (int i = 0; i < functionTypeListModel.size(); i++) { - int signOfType = 0; - FunctionGroup functionType = (FunctionGroup) functionTypeListModel.getElementAt(i); - NameAndDescription[] nads = functionType.getDescriptions(); - if (signOfContinue == 1) { - functionNameModel.removeAllElements(); - String functionName = ((String) tipsList.getSelectedValue()); - for (int k = 0; k < nads.length; k++) { - functionNameModel.addElement(nads[k]); - if (functionName.equals(nads[k].getName()))//若相等,找出显示的函数的index,setSelectedIndex() - { - signOfType = 1; - signOfContinue = 0; - indexOfFunction = k; - } + 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); + NameAndDescription[] nads = functionType.getDescriptions(); + if (signOfContinue == 1) { + functionNameModel.removeAllElements(); + for (int k = 0; k < nads.length; k++) { + functionNameModel.addElement(nads[k]); + if (functionName.equals(nads[k].getName()))//若相等,找出显示的函数的index,setSelectedIndex() + { + signOfType = 1; + signOfContinue = 0; + indexOfFunction = k; + found = true; } + } - if (signOfType == 1) { - functionTypeList.setSelectedIndex(i); - signOfType = 0; - } + if (signOfType == 1) { + functionTypeList.setSelectedIndex(i); + signOfType = 0; } } + } + if (found) { functionNameList.setSelectedIndex(indexOfFunction); functionNameList.ensureIndexIsVisible(indexOfFunction); + } else { + functionTypeList.setSelectedIndex(0); } - } private int getBeginPosition() { @@ -492,9 +641,17 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { // do nothing } + private void popTips() { + popupMenu = new JPopupMenu(); + JScrollPane tipsScrollPane = new JScrollPane(tipsList); + popupMenu.add(tipsScrollPane); + tipsScrollPane.setPreferredSize(new Dimension(240, 146)); + tipsScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + popupMenu.show(keyWordTextField, 0, 23); + } + protected void search(String keyWord, boolean findDescription) { listModel.removeAllElements(); - keyWord = removeAllSpace(keyWord); if (keyWord.length() != 0) { NameAndDescription[] descriptions = FunctionConstants.ALL.getDescriptions(); @@ -584,6 +741,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Formula_Definition"); } + public BasicDialog showLargeWindow(Window window, DialogActionListener l) { + BasicDialog basicDialog = super.showWindowWithCustomSize(window, l, new Dimension(900, 600)); + basicDialog.setMinimumSize(new Dimension(900, 600)); + basicDialog.setResizable(true); + return basicDialog; + } + /** * Populate */ @@ -610,7 +774,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { beginPosition = getBeginPosition(); insertPosition = beginPosition; firstStepToFindTips(beginPosition); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } ifHasBeenWriten = 1; } else { this.formulaTextArea.setText(content); @@ -618,7 +784,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { beginPosition = getBeginPosition(); insertPosition = beginPosition; firstStepToFindTips(beginPosition); - fixFunctionNameList(); + if (tipsList.getSelectedValue() != null) { + fixFunctionNameList(tipsList.getSelectedValue().toString()); + } ifHasBeenWriten = 1; } } @@ -650,68 +818,113 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { public void actionPerformed(ActionEvent evt) { // Execute Formula default cell element. String formulaText = formulaTextArea.getText().trim(); - String formulaValidMessage = FormulaChecker.check(formulaText); - FineJOptionPane.showMessageDialog( - FormulaPane.this, - formulaValidMessage + ".", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.WARNING_MESSAGE); + FormulaCheckResult checkResult = FormulaChecker.check(formulaText); + confirmCheckResult(checkResult, checkResult.getTips()); } }; + private void calculateFormula() { + String formulaText = formulaTextArea.getText().trim(); + String unSupportFormula = containsUnsupportedSimulationFormulas(formulaText); + if (unSupportFormula != null) { + showMessageDialog(Toolkit.i18nText("Fine-Design_Basic_Formula_Unsupported_Formulas") + ":" + unSupportFormula, false, true); + return; + } + + boolean calException = false; + String messageTips; + FormulaCheckResult checkResult = FormulaChecker.check(formulaText); + if (checkResult.grammarValid()) { + messageTips = checkResult.getTips() + NEWLINE; + Map paramsMap = setParamsIfExist(formulaText); + Calculator calculator = Calculator.createCalculator(); + ParameterMapNameSpace parameterMapNameSpace = ParameterMapNameSpace.create(paramsMap); + calculator.pushNameSpace(parameterMapNameSpace); + + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + IOFile file = (IOFile) currentEditingTemplate.getTarget(); + calculator.setAttribute(TableDataSource.KEY, file); + calculator.pushNameSpace(TableDataNameSpace.getInstance()); + calculator.pushNameSpace(SimpleCellValueNameSpace.getInstance()); + } + + BaseFormula baseFormula = BaseFormula.createFormulaBuilder().build(formulaText); + Object calResult; + try { + calResult = calculator.evalValue(baseFormula); + String objectToString = EssentialUtils.objectToString(calResult); + String result = objectToString.length() > DEFUAL_FOMULA_LENGTH ? + objectToString.substring(0, DEFUAL_FOMULA_LENGTH - ELLIPSIS.length()) + ELLIPSIS : objectToString; + messageTips = messageTips + Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Result") + ":" + result; + } catch (Exception ce) { + //模拟计算如果出现错误,则抛出错误 + calResult = ce.getMessage(); + calException = true; + FineLoggerFactory.getLogger().error(ce.getMessage(), ce); + messageTips = messageTips + Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Error") + ":" + calResult; + } + FineLoggerFactory.getLogger().info("value:{}", calResult); + } else { + messageTips = checkResult.getTips(); + } + if (checkResult.isValid()) { + showMessageDialog(messageTips, checkResult.isValid(), calException); + } else { + confirmCheckResult(checkResult, messageTips); + } + } + + private final ActionListener calculateActionListener = new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - String formulaText = formulaTextArea.getText().trim(); - String formulaValidMessage = FormulaChecker.check(formulaText); - ; - String unSupportFormula = containsUnsupportedSimulationFormulas(formulaText); - if (unSupportFormula != null) { - FineJOptionPane.showMessageDialog( - FormulaPane.this, - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Unsupported_Formulas") + ":" + unSupportFormula, - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.INFORMATION_MESSAGE); - return; - } - String messageTips; - if (formulaValidMessage.equals(INVALID_FORMULA)) { - messageTips = INVALID_FORMULA; - } else { - messageTips = formulaValidMessage.equals(VALID_FORMULA) ? "" : formulaValidMessage + "\n"; - Map paramsMap = setParamsIfExist(formulaText); - Calculator calculator = Calculator.createCalculator(); - ParameterMapNameSpace parameterMapNameSpace = ParameterMapNameSpace.create(paramsMap); - calculator.pushNameSpace(parameterMapNameSpace); - - JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (currentEditingTemplate != null) { - IOFile file = (IOFile) currentEditingTemplate.getTarget(); - calculator.setAttribute(TableDataSource.KEY, file); - calculator.pushNameSpace(TableDataNameSpace.getInstance()); - calculator.pushNameSpace(SimpleCellValueNameSpace.getInstance()); - } + calculateFormula(); + } + }; - BaseFormula baseFormula = BaseFormula.createFormulaBuilder().build(formulaText); - try { - Object value = calculator.evalValue(baseFormula); - String objectToString = EssentialUtils.objectToString(value); - String result = objectToString.length() > DEFUAL_FOMULA_LENGTH ? - objectToString.substring(0, DEFUAL_FOMULA_LENGTH - ELLIPSIS.length()) + ELLIPSIS : objectToString; - messageTips = messageTips + - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Result") + ":" + result; - FineLoggerFactory.getLogger().info("value:{}", value); - } catch (UtilEvalError utilEvalError) { - FineLoggerFactory.getLogger().error("", utilEvalError); - } + private boolean confirmCheckResult(FormulaCheckResult checkResult, String messageTips) { + if (checkResult.isValid()) { + showMessageDialog(checkResult.getTips(), checkResult.isValid(), false); + } else { + int columns = checkResult.getFormulaCoordinates().getColumns() + 1; + String position = StringUtils.EMPTY; + if (columns > 0) { + position = Toolkit.i18nText("Fine-Design_Basic_Formula_The") + columns + + Toolkit.i18nText("Fine-Design_Basic_Formula_Error_Position") + " "; } - FineJOptionPane.showMessageDialog( + int confirmDialog = FineJOptionPane.showConfirmDialog( FormulaPane.this, - messageTips, + position + messageTips, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + new String[]{Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Result"), Toolkit.i18nText("Fine-Design_Basic_Formula_Continue")}, + Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Result")); + if (confirmDialog == 0) { + formulaTextArea.setCaretPosition(Math.max(columns, 0)); + formulaTextArea.requestFocus(); + return false; + } } - }; + return true; + } + + private void showMessageDialog(String message, boolean formulaValid, boolean calException) { + if (formulaValid && !calException) { + FineJOptionPane.showMessageDialog( + FormulaPane.this, + message); + } else { + FineJOptionPane.showMessageDialog( + FormulaPane.this, + message, + Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + JOptionPane.WARNING_MESSAGE); + } + } private String containsUnsupportedSimulationFormulas(String formulaText) { try { @@ -730,6 +943,18 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { return null; } + @Override + public boolean confirmContinueBeforeDoOK() { + if (checkBeforeColse.isSelected()) { + String formula = formulaTextArea.getText().trim(); + FormulaCheckResult checkResult = FormulaChecker.check(formula); + if (!checkResult.isValid()) { + return confirmCheckResult(checkResult, checkResult.getTips()); + } + } + return true; + } + private Map setParamsIfExist(String formulaText) { Map parameterMap = new HashMap<>(); try { @@ -742,7 +967,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { if (parameters.length < 1 && editor4CalPane.update().size() < 1) { return parameterMap; } - ParameterInputPane pPane = new ParameterInputPane(parameters); + ParameterInputPane pPane = new ParameterInputNoneListenerPane(parameters); pPane.showSmallWindow(new JFrame(), new DialogActionAdapter() { @Override public void doOk() { @@ -832,7 +1057,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; @@ -889,6 +1114,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initGroupTypeModel() { functionTypeListModel.addElement(FunctionConstants.COMMON); + functionTypeListModel.addElement(FunctionConstants.NEW); for (int i = 0; i < FunctionConstants.EMBFUNCTIONS.length; i++) { functionTypeListModel.addElement(FunctionConstants.EMBFUNCTIONS[i]); } @@ -970,11 +1196,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initDescriptionTextArea() { // Description - descriptionTextArea = new UITextArea(16, 27); - - UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea); - desScrollPane.setBorder(null); - this.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.EAST); + descriptionTextArea = new UITextArea(DESCRIPTION_TEXT_AREA_ROW,DESCRIPTION_TEXT_AREA_COLUMN); descriptionTextArea.setBackground(Color.white); descriptionTextArea.setLineWrap(true); descriptionTextArea.setWrapStyleWord(true); @@ -1042,12 +1264,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initVariablesTree() { + JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); // vairable. variablesTree = new JTree(); UIScrollPane variablesTreePane = new UIScrollPane(variablesTree); variablesTreePane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); - this.add(this.createNamePane( - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.CENTER); + panel.add(this.createNamePane( + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.WEST); variablesTree.setRootVisible(false); variablesTree.setShowsRootHandles(true); variablesTree.addMouseListener(applyTextMouseListener); @@ -1055,7 +1278,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { initDescriptionTextArea(); + UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea); + desScrollPane.setBorder(null); + panel.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.CENTER); initVariablesTreeSelectionListener(); + this.add(panel,BorderLayout.CENTER); } private void initComponents() { @@ -1072,6 +1299,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { functionTypeList.setSelectedIndex(0); } + @Override + public void refresh(String replacementText) { + refreshText(replacementText); + } + /* * 查看函数的详细信息 */ @@ -1098,7 +1330,6 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { }; basicPane.setLayout(FRGUIPaneFactory.createBorderLayout()); UITextArea desArea = new UITextArea(); -// desArea。setEnabled(false); desArea.setText(this.getTextAreaText()); basicPane.add(new UIScrollPane(desArea), BorderLayout.CENTER); BasicDialog dialog = basicPane.showWindow(DesignerContext.getDesignerFrame()); @@ -1171,6 +1402,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { } }; + public void refreshText(String line) { + fixFunctionNameList(line); + refreshDescriptionTextArea(line); + } + public void populate(VariableResolver variableResolver) { // varibale tree. DefaultTreeModel variableModel = (DefaultTreeModel) variablesTree.getModel(); @@ -1306,12 +1542,12 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { buffer.append(name.toUpperCase()); buffer.append("\""); buffer.append("|"); - buffer.append("\n"); + buffer.append(NEWLINE); buffer.append("\""); buffer.append(name.toLowerCase()); buffer.append("\""); buffer.append("|"); - buffer.append("\n"); + buffer.append(NEWLINE); } FineLoggerFactory.getLogger().debug(buffer.toString()); } diff --git a/designer-base/src/main/java/com/fr/design/formula/FormulaPaneWhenReserveFormula.java b/designer-base/src/main/java/com/fr/design/formula/FormulaPaneWhenReserveFormula.java index e08f7e3b40..ab49b605d4 100644 --- a/designer-base/src/main/java/com/fr/design/formula/FormulaPaneWhenReserveFormula.java +++ b/designer-base/src/main/java/com/fr/design/formula/FormulaPaneWhenReserveFormula.java @@ -3,11 +3,10 @@ package com.fr.design.formula; import com.fr.base.BaseFormula; import com.fr.design.gui.icheckbox.UICheckBox; - -import javax.swing.*; +import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; +import java.awt.BorderLayout; /** * @author richie @@ -41,8 +40,8 @@ public class FormulaPaneWhenReserveFormula extends FormulaPane { reserveCheckBox4Write = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Write_Save_Formula")); reserveCheckBox4Write.setSelected(false); - checkBoxPane.add(reserveCheckBox4Result, BorderLayout.CENTER); - checkBoxPane.add(reserveCheckBox4Write, BorderLayout.SOUTH); + checkBoxPane.add(reserveCheckBox4Result, BorderLayout.WEST); + checkBoxPane.add(reserveCheckBox4Write, BorderLayout.WEST); } @Override diff --git a/designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java b/designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java index 28bb985552..6a1b32aaa3 100644 --- a/designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java +++ b/designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java @@ -5,10 +5,19 @@ import com.fr.function.AVERAGE; import com.fr.function.CHAR; import com.fr.function.COUNT; import com.fr.function.DATE; +import com.fr.function.ENBYSTRNUM; +import com.fr.function.ENDOFMONTH; +import com.fr.function.GCD; +import com.fr.function.GETCHARNUM; +import com.fr.function.ISWORKDAY; +import com.fr.function.LCM; import com.fr.function.MAX; +import com.fr.function.MIDCHAR; import com.fr.function.MIN; +import com.fr.function.NUMTOZH; import com.fr.function.RANGE; import com.fr.function.SUM; +import com.fr.function.TEXTGETNUM; import com.fr.function.TIME; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralUtils; @@ -36,6 +45,7 @@ import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -46,6 +56,8 @@ public final class FunctionConstants { public static NameAndFunctionList COMMON = getCommonFunctionList(); public static NameAndTypeAndFunctionList[] EMBFUNCTIONS = getEmbededFunctionListArray(); public static FunctionGroup ALL = getAllFunctionGroup(); + public static List abandonFormulas = Arrays.asList("CIRCULAR", "CROSSLAYERTOTAL", "HIERARCHY", "LAYERTOTAL"); + public static NameAndFunctionList NEW = getNewFunctionList(); static { loadEmbededFunctions(); @@ -54,7 +66,8 @@ public final class FunctionConstants { /** * Don't let anyone instantiate this class. */ - private FunctionConstants() {} + private FunctionConstants() { + } private static void loadEmbededFunctions() { String pkgName = "com.fr.function"; @@ -88,7 +101,10 @@ public final class FunctionConstants { Class cls = Class.forName(pkgName + "." + fileName.substring(0, fileName.length() - 6)); if (StableUtils.classInstanceOf(cls, iface)) { Function inst; - inst = (Function)cls.newInstance(); + inst = (Function) cls.newInstance(); + if (abandonFormulas.contains(inst.getClass().getSimpleName())) { + continue; + } for (NameAndTypeAndFunctionList EMBFUNCTION : EMBFUNCTIONS) { if (EMBFUNCTION.test(inst)) { break; @@ -270,6 +286,13 @@ public final class FunctionConstants { }); } + private static NameAndFunctionList getNewFunctionList() { + return new NameAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_New"), new Function[]{ + new ENDOFMONTH(), new NUMTOZH(), new MIDCHAR(), new ISWORKDAY(),new ENBYSTRNUM(), new TEXTGETNUM(), + new GETCHARNUM(), new GCD(), new LCM() + }); + } + private static NameAndTypeAndFunctionList[] getEmbededFunctionListArray() { return new NameAndTypeAndFunctionList[] { new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Math_&_Trig"), Function.MATH), @@ -300,11 +323,12 @@ public final class FunctionConstants { Collections.addAll(all, CUSTOM.getDescriptions()); //hugh:自定义函数分组 Set containers = ExtraClassManager.getInstance().getArray(FunctionDefContainer.MARK_STRING); - if(!containers.isEmpty()){ - for(Mutable container : containers){ - Collections.addAll(all,createFunctionGroup(((FunctionDefContainer)container)).getDescriptions()); + if (!containers.isEmpty()) { + for (Mutable container : containers) { + Collections.addAll(all, createFunctionGroup(((FunctionDefContainer) container)).getDescriptions()); } } + all = all.stream().filter(n -> !abandonFormulas.contains(n.getName())).collect(Collectors.toList()); Collections.sort(all, new Comparator() { @Override diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/FormulaExceptionTipsProcessor.java b/designer-base/src/main/java/com/fr/design/formula/exception/FormulaExceptionTipsProcessor.java new file mode 100644 index 0000000000..53fa9aaf89 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/FormulaExceptionTipsProcessor.java @@ -0,0 +1,48 @@ +package com.fr.design.formula.exception; + +import com.fr.design.formula.FormulaChecker; +import com.fr.design.formula.exception.function.FormulaCheckWrongFunction; +import com.fr.design.formula.exception.function.MismatchedCharFunction; +import com.fr.design.formula.exception.function.MismatchedTokenFunction; +import com.fr.design.formula.exception.function.NoViableAltForCharFunction; +import com.fr.design.formula.exception.function.NoViableAltFunction; +import com.fr.script.checker.exception.FunctionCheckWrongException; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.third.antlr.MismatchedCharException; +import com.fr.third.antlr.MismatchedTokenException; +import com.fr.third.antlr.NoViableAltException; +import com.fr.third.antlr.NoViableAltForCharException; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/26 + */ +public class FormulaExceptionTipsProcessor { + private static final Map> EXCEPTION_TIPS = new ConcurrentHashMap<>(); + + private static final FormulaExceptionTipsProcessor PROCESSOR = new FormulaExceptionTipsProcessor(); + + static { + EXCEPTION_TIPS.put(FunctionCheckWrongException.class, FormulaCheckWrongFunction.getFunction()); + EXCEPTION_TIPS.put(MismatchedCharException.class, MismatchedCharFunction.getFunction()); + EXCEPTION_TIPS.put(MismatchedTokenException.class, MismatchedTokenFunction.getFunction()); + EXCEPTION_TIPS.put(NoViableAltException.class, NoViableAltFunction.getFunction()); + EXCEPTION_TIPS.put(NoViableAltForCharException.class, NoViableAltForCharFunction.getFunction()); + + } + + public FormulaCheckResult getExceptionTips(Exception e) { + return EXCEPTION_TIPS.getOrDefault(e.getClass(), + e1 -> new FormulaCheckResult(false, FormulaChecker.INVALID_FORMULA, FormulaCoordinates.INVALID, false)) + .apply(e); + } + + public static FormulaExceptionTipsProcessor getProcessor() { + return PROCESSOR; + } +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckConstants.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckConstants.java new file mode 100644 index 0000000000..20ad72156b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckConstants.java @@ -0,0 +1,14 @@ +package com.fr.design.formula.exception.function; + +/** + * @author Hoky + * @date 2021/10/28 + */ +public class FormulaCheckConstants { + public static final String COLON = ":"; + public static final String LEFT = "("; + public static final String COMMON = ","; + public static final String RIGHT = ")"; + public static final String BLANK = " "; + public static final String SINGLE_QUOTES = "'"; +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckWrongFunction.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckWrongFunction.java new file mode 100644 index 0000000000..417e9b37a6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/FormulaCheckWrongFunction.java @@ -0,0 +1,80 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.i18n.Toolkit; +import com.fr.script.checker.exception.FunctionCheckWrongException; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.script.rules.FunctionParameterType; +import com.fr.script.rules.FunctionRule; +import com.fr.stable.StringUtils; + +import java.util.List; +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/26 + */ +public class FormulaCheckWrongFunction implements Function { + private final static FormulaCheckWrongFunction FUNCTION = new FormulaCheckWrongFunction(); + + @Override + public FormulaCheckResult apply(Exception e) { + if (e instanceof FunctionCheckWrongException) { + FunctionCheckWrongException ce = (FunctionCheckWrongException) e; + List rules = ce.getRules(); + String functionName = ce.getFunctionName(); + StringBuilder errorMsg = new StringBuilder(functionName + Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Error_Tips") + FormulaCheckConstants.COLON); + for (int i = 0; i < rules.size(); i++) { + errorMsg.append(FormulaCheckConstants.LEFT); + if (rules.get(i).getParameterList().isEmpty()) { + errorMsg.append(Toolkit.i18nText("Fine-Design_Basic_Formula_No_Param")); + } + for (FunctionParameterType functionParameterType : rules.get(i).getParameterList()) { + errorMsg.append(getTypeString(functionParameterType)).append(FormulaCheckConstants.COMMON); + } + if (FormulaCheckConstants.COMMON.equals(errorMsg.charAt(errorMsg.length() - 1) + StringUtils.EMPTY)) { + errorMsg.deleteCharAt(errorMsg.length() - 1); + } + errorMsg.append(FormulaCheckConstants.RIGHT); + if (i != rules.size() - 1) { + errorMsg.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Or")); + } + } + return new FormulaCheckResult(false, errorMsg.toString(), new FormulaCoordinates(1, indexPosition(ce.getFormulaText(), ce.getNode().toString())), true); + } + return new FormulaCheckResult(false, StringUtils.EMPTY, new FormulaCoordinates(-1, -1), true); + } + + private static String getTypeString(FunctionParameterType type) { + switch (type) { + case NUMBER: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Number"); + case STRING: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_String"); + case ANY: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Any"); + case DATE: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Date"); + case BOOLEAN: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Boolean"); + case ARRAY: + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Array"); + } + return StringUtils.EMPTY; + } + + public static Function getFunction() { + return FUNCTION; + } + + private int indexPosition(String formulaText, String invalidFormula) { + //处理一下自己FunctionCall自己拼的逗号逻辑 + if (invalidFormula.contains(",")) { + invalidFormula = invalidFormula.substring(0, invalidFormula.indexOf(",")); + } + int index = formulaText.indexOf(invalidFormula); + return index; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedCharFunction.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedCharFunction.java new file mode 100644 index 0000000000..69ea0c81a9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedCharFunction.java @@ -0,0 +1,95 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.formula.FormulaChecker; +import com.fr.design.i18n.Toolkit; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.third.antlr.MismatchedCharException; + +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/28 + */ +public class MismatchedCharFunction implements Function { + private final static MismatchedCharFunction FUNCTION = new MismatchedCharFunction(); + + @Override + public FormulaCheckResult apply(Exception e) { + if (e instanceof MismatchedCharException) { + MismatchedCharException charException = (MismatchedCharException) e; + FormulaCoordinates formulaCoordinates = new FormulaCoordinates(charException.line, charException.column - 1); + return new FormulaCheckResult(false, getMessage(charException), formulaCoordinates, false); + } + return new FormulaCheckResult(false, FormulaChecker.INVALID_FORMULA, FormulaCoordinates.INVALID, false); + } + + public static Function getFunction() { + return FUNCTION; + } + + private String getMessage(MismatchedCharException charException) { + StringBuffer sb = new StringBuffer(); + switch (charException.mismatchType) { + case 1: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": "); + appendCharName(sb, charException.expecting); + break; + case 2: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting_Anything") + ": ") + .append(FormulaCheckConstants.BLANK) + .append(FormulaCheckConstants.SINGLE_QUOTES); + appendCharName(sb, charException.expecting); + sb.append("';").append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_GotItAnyway")); + break; + case 3: + case 4: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ").append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Token")); + if (charException.mismatchType == 4) { + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Not")); + } + + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_In_Range")).append(": "); + appendCharName(sb, charException.expecting); + sb.append(".."); + appendCharName(sb, charException.upper); + break; + case 5: + case 6: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ") + .append(charException.mismatchType == 6 ? Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Not") : FormulaCheckConstants.BLANK) + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ONE_OF")).append(" ("); + int[] elems = charException.set.toArray(); + + for (int i = 0; i < elems.length; ++i) { + appendCharName(sb, elems[i]); + } + break; + default: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Mismatched_Char")); + } + + return sb.toString(); + } + + private void appendCharName(StringBuffer sb, int c) { + switch (c) { + case 9: + sb.append("'\\t'"); + break; + case 10: + sb.append("'\\n'"); + break; + case 13: + sb.append("'\\r'"); + break; + case 65535: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Mismatched_EOF")); + break; + default: + sb.append((char) c); + } + + } +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedTokenFunction.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedTokenFunction.java new file mode 100644 index 0000000000..fb4eea22b7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/MismatchedTokenFunction.java @@ -0,0 +1,112 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.formula.FormulaChecker; +import com.fr.design.i18n.Toolkit; +import com.fr.log.FineLoggerFactory; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.stable.StringUtils; +import com.fr.third.antlr.MismatchedTokenException; + +import java.lang.reflect.Field; +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/28 + */ +public class MismatchedTokenFunction implements Function { + private final static MismatchedTokenFunction FUNCTION = new MismatchedTokenFunction(); + public static final String NULL_STRING = "null"; + + @Override + public FormulaCheckResult apply(Exception e) { + if (e instanceof MismatchedTokenException) { + MismatchedTokenException charException = (MismatchedTokenException) e; + FormulaCoordinates formulaCoordinates = new FormulaCoordinates(charException.line, charException.column - 1); + return new FormulaCheckResult(false, getMessage(charException), formulaCoordinates, false); + } + return new FormulaCheckResult(false, FormulaChecker.INVALID_FORMULA, FormulaCoordinates.INVALID, false); + } + + public static Function getFunction() { + return FUNCTION; + } + + public String getMessage(MismatchedTokenException exception) { + StringBuilder sb = new StringBuilder(); + Object fieldValue = getFieldValue(exception, "tokenText"); + String tokenText = fieldValue == null ? NULL_STRING : fieldValue.toString(); + switch (exception.mismatchType) { + case 1: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ") + .append(tokenName(exception.expecting, exception)); + break; + case 2: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting_Anything") + ": ") + .append(tokenName(exception.expecting, exception)) + .append("; ") + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_GotItAnyway")); + break; + case 3: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ") + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Token")) + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_In_Range")) + .append(": ") + .append(tokenName(exception.expecting, exception)) + .append("..") + .append(tokenName(exception.upper, exception)); + break; + case 4: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ") + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Token")) + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Not")) + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_In_Range")) + .append(": ") + .append(tokenName(exception.expecting, exception)) + .append("..") + .append(tokenName(exception.upper, exception)); + break; + case 5: + case 6: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Expecting") + ": ") + .append(exception.mismatchType == 6 ? Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Not") : FormulaCheckConstants.BLANK) + .append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ONE_OF")).append("("); + int[] elms = exception.set.toArray(); + + for (int i = 0; i < elms.length; ++i) { + sb.append(' '); + sb.append(tokenName(elms[i], exception)); + } + + break; + default: + sb.append(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Mismatched_Token")); + } + + return sb.toString(); + } + + private String tokenName(int tokenType, MismatchedTokenException exception) { + if (tokenType == 0) { + return ""; + } else if (tokenType == 33 || tokenType == 26 || tokenType == 31) { + return Toolkit.i18nText("Fine-Design_Basic_Formula_Right_Closing_Symbol"); + } else { + String[] tokenNames = (String[]) getFieldValue(exception, "tokenNames"); + return tokenType >= 0 && tokenType < tokenNames.length ? TranslateTokenUtils.translateToken(tokenNames[tokenType]) : "<" + tokenType + ">"; + } + } + + + private Object getFieldValue(Object object, String fieldName) { + try { + Field field = object.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(object); + } catch (Exception e) { + FineLoggerFactory.getLogger().warn(e.getMessage(), e); + return StringUtils.EMPTY; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltForCharFunction.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltForCharFunction.java new file mode 100644 index 0000000000..1f0bdf8735 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltForCharFunction.java @@ -0,0 +1,44 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.formula.FormulaChecker; +import com.fr.design.i18n.Toolkit; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.third.antlr.NoViableAltForCharException; + +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/28 + */ +public class NoViableAltForCharFunction implements Function { + private final static NoViableAltForCharFunction FUNCTION = new NoViableAltForCharFunction(); + + @Override + public FormulaCheckResult apply(Exception e) { + if (e instanceof NoViableAltForCharException) { + NoViableAltForCharException charException = (NoViableAltForCharException) e; + FormulaCoordinates formulaCoordinates = new FormulaCoordinates(charException.line, charException.column - 1); + return new FormulaCheckResult(false, getMessage(charException), formulaCoordinates, false); + } + return new FormulaCheckResult(false, FormulaChecker.INVALID_FORMULA, FormulaCoordinates.INVALID, false); + } + + public static Function getFunction() { + return FUNCTION; + } + + public String getMessage(NoViableAltForCharException exception) { + String mesg = Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Unexpected_Char") + ": "; + if (exception.foundChar >= ' ' && exception.foundChar <= '~') { + mesg = mesg + '\''; + mesg = mesg + exception.foundChar; + mesg = mesg + '\''; + } else { + mesg = mesg + exception.foundChar; + } + + return mesg; + } +} diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltFunction.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltFunction.java new file mode 100644 index 0000000000..85cc0ecc64 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/NoViableAltFunction.java @@ -0,0 +1,41 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.formula.FormulaChecker; +import com.fr.design.i18n.Toolkit; +import com.fr.script.checker.result.FormulaCheckResult; +import com.fr.script.checker.result.FormulaCoordinates; +import com.fr.third.antlr.NoViableAltException; +import com.fr.third.antlr.TreeParser; + +import java.util.function.Function; + +/** + * @author Hoky + * @date 2021/10/28 + */ +public class NoViableAltFunction implements Function { + private final static NoViableAltFunction FUNCTION = new NoViableAltFunction(); + + @Override + public FormulaCheckResult apply(Exception e) { + if (e instanceof NoViableAltException) { + NoViableAltException altException = (NoViableAltException) e; + FormulaCoordinates formulaCoordinates = new FormulaCoordinates(altException.line, altException.column - 1); + return new FormulaCheckResult(false, getMessage(altException), formulaCoordinates, false); + } + return new FormulaCheckResult(false, FormulaChecker.INVALID_FORMULA, FormulaCoordinates.INVALID, false); + } + + public static Function getFunction() { + return FUNCTION; + } + + public String getMessage(NoViableAltException exception) { + if (exception.token != null) { + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Unexpected_Token") + ": " + exception.token.getText(); + } else { + return exception.node == TreeParser.ASTNULL ? Toolkit.i18nText("Fine-Design_Basic_Formula_Check_End_Of_Subtree") : + Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Unexpected_AST_Node") + ": " + exception.node.toString(); + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/formula/exception/function/TranslateTokenUtils.java b/designer-base/src/main/java/com/fr/design/formula/exception/function/TranslateTokenUtils.java new file mode 100644 index 0000000000..1df697d071 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/exception/function/TranslateTokenUtils.java @@ -0,0 +1,96 @@ +package com.fr.design.formula.exception.function; + +import com.fr.design.i18n.Toolkit; + +/** + * @author Hoky + * @date 2021/11/30 + */ +public class TranslateTokenUtils { + public static String translateToken(String token) { + switch (token) { + case ("RPAREN"): + return ")"; + case ("LPAREN"): + return "("; + case ("COMMA"): + return ","; + case ("COLON"): + return ":"; + case ("EOF"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Mismatched_EOF"); + case ("DOT"): + return "."; + case ("FLOT_NUM"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Float_Number"); + case ("LOR"): + return "||"; + case ("LAND"): + return "&&"; + case ("EQUAL"): + return "="; + case ("EQUAL2"): + return "="; + case ("NOT_EQUAL"): + return "!="; + case ("NOT_EQUAL2"): + return "!="; + case ("GE"): + return ">="; + case ("LE"): + return "<="; + case ("LT"): + return "<"; + case ("PLUS"): + return "+"; + case ("MINUS"): + return "-"; + case ("STAR"): + return "*"; + case ("DIV"): + return "/"; + case ("MOD"): + return "%"; + case ("POWER"): + return "^"; + case ("LNOT"): + return "!"; + case ("WAVE"): + return "~"; + case ("LBRACK"): + return "["; + case ("SEMI"): + return ";"; + case ("RBRACK"): + return "]"; + case ("LCURLY"): + return "{"; + case ("RCURLY"): + return "}"; + case ("DCOLON"): + return ";"; + case ("INT_NUM"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Integer"); + case ("CR_ADRESS"): + return "\n"; + case ("SHARP"): + return "#"; + case ("AT"): + return "@"; + case ("QUESTION"): + return "?"; + case ("BOR"): + return "||"; + case ("BAND"): + return "&&"; + case ("Char"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Character"); + case ("DIGIT"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Digital"); + case ("XDIGIT"): + return Toolkit.i18nText("Fine-Design_Basic_Formula_Hexadecimal_Digital"); + default: + return token; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java b/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java new file mode 100644 index 0000000000..1e553735dd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java @@ -0,0 +1,65 @@ +package com.fr.design.fun; + +import com.fr.base.Utils; +import com.fr.base.chart.BaseChartCollection; +import com.fr.chartx.attr.ChartProvider; +import com.fr.general.FRFont; +import com.fr.report.cell.CellElement; +import com.fr.stable.fun.mark.Selectable; + +import java.awt.Font; + +/** + * 主要用于fvs报表块内元素默认值的调整,以达到所见所得效果,后续fvs内置后删除 + */ +public interface DefaultValueAdjustProvider extends Selectable { + String MARK_STRING = "DefaultValueAdjustProvider"; + int CURRENT_LEVEL = 1; + + /** + * 调整单元格对象默认值 + * + * @param cellElement + */ + void adjustCellElement(CellElement cellElement); + + /** + * 调整富文本默认值 + * + * @param fontSize + * @return + */ + int adjustRichTextTransform(int fontSize, double transformedFontSize); + + /** + * 调整ChartCollection + * + * @param chartCollection + */ + void adjustChartCollectionStyle(BaseChartCollection chartCollection); + + /** + * 调整图表 + * + * @param chartProvider + */ + void adjustChart(ChartProvider chartProvider); + + + /** + * 转成当前分辨率下显示的font + * @param font + * @param resolution + * @return + */ + Font transformFontByResolution(FRFont font, int resolution); + + /** + * 修改设计可用字体默认列表 + * @return + */ + default String[] getAvailableFontFamilyNames4Report() { + return Utils.getAvailableFontFamilyNames4Report(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/fun/TemplateThemePaneProvider.java b/designer-base/src/main/java/com/fr/design/fun/TemplateThemePaneProvider.java new file mode 100644 index 0000000000..4c91a18a87 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/TemplateThemePaneProvider.java @@ -0,0 +1,35 @@ +package com.fr.design.fun; + +import com.fr.design.beans.BasicBeanPane; +import com.fr.stable.fun.mark.Mutable; + +/** + * 设计器模板主题管理-细节定制部分,支持添加tab + * + * @author Bruce.Deng + * @version 11.0 + * Created by Bruce.Deng on 2023/2/7 + */ +public interface TemplateThemePaneProvider extends Mutable { + + String XML_TAG = "TemplateThemePaneProvider"; + + int CURRENT_LEVEL = 1; + + /** + * 插入tab的位置 + * + * @param total 已插入的tab数 + * @return 插入位置 + */ + int getInsertPosition(int total); + + + /** + * 获取tab对象 + * + * @return tab对象 + */ + BasicBeanPane getTab(); + +} diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java new file mode 100644 index 0000000000..b2fc58ba8f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java @@ -0,0 +1,24 @@ +package com.fr.design.fun.impl; + + +import com.fr.design.fun.DefaultValueAdjustProvider; +import com.fr.stable.fun.assist.Selector; +import com.fr.stable.fun.impl.AbstractProvider; +import com.fr.stable.fun.mark.API; + +@API(level = DefaultValueAdjustProvider.CURRENT_LEVEL) +public abstract class AbstractDefaultValueAdjustProvider extends AbstractProvider implements DefaultValueAdjustProvider { + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + public String mark4Provider() { + return this.getClass().getName(); + } + + public Selector selector() { + return Selector.ALWAYS; + } +} diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractTemplateThemePaneProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractTemplateThemePaneProvider.java new file mode 100644 index 0000000000..7e8fe617dc --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractTemplateThemePaneProvider.java @@ -0,0 +1,26 @@ +package com.fr.design.fun.impl; + +import com.fr.design.fun.TemplateThemePaneProvider; +import com.fr.stable.fun.impl.AbstractProvider; +import com.fr.stable.fun.mark.API; + +/** + * @author Bruce.Deng + * @version 11.0 + * @see TemplateThemePaneProvider + * Created by Bruce.Deng on 2023/2/7 + */ +@API(level = TemplateThemePaneProvider.CURRENT_LEVEL) +public abstract class AbstractTemplateThemePaneProvider extends AbstractProvider implements TemplateThemePaneProvider { + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public String mark4Provider() { + return getClass().getName(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java index 488cbad37e..a8e45b24cf 100644 --- a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java +++ b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java @@ -160,10 +160,10 @@ public class UILookAndFeel extends MetalLookAndFeel { table.put("Tree.collapsedIcon", loadIcon("TreePlusIcon.png", this)); table.put("Tree.openIcon", loadIcon("TreeFolderOpenedIcon.png", this)); table.put("Tree.closedIcon", loadIcon("TreeFolderClosedIcon.png", this)); - table.put("Tree.leafIcon", loadIcon("TreeLeafIcon.png", this)); + table.put("Tree.leafIcon", loadIcon("TreeLeafIcon.svg", this)); table.put("FileView.directoryIcon", loadIcon("DirectoryIcon.png", this)); table.put("FileView.computerIcon", loadIcon("ComputerIcon.png", this)); - table.put("FileView.fileIcon", loadIcon("FileIcon.png", this)); + table.put("FileView.fileIcon", loadIcon("FileIcon.svg", this)); table.put("FileView.floppyDriveIcon", loadIcon("FloppyIcon.png", this)); table.put("FileView.hardDriveIcon", loadIcon("HarddiskIcon.png", this)); table.put("FileChooser.detailsViewIcon", loadIcon("FileDetailsIcon.png", this)); 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 new file mode 100644 index 0000000000..daed7cd4c5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaAutoCompletePopupWindow.java @@ -0,0 +1,31 @@ +/* + * 12/21/2008 + * + * AutoCompletePopupWindow.java - A window containing a list of auto-complete + * choices. + * + * This library is distributed under a modified BSD license. See the included + * RSyntaxTextArea.License.txt file for details. + */ +package com.fr.design.gui.autocomplete; + +import java.awt.Window; + +/** + * The actual popup window of choices. When visible, this window intercepts + * certain keystrokes in the parent text component and uses them to navigate + * the completion choices instead. If Enter or Escape is pressed, the window + * hides itself and notifies the {@link AutoCompletion} to insert the selected + * text. + * + * @author Robert Futrell + * @version 1.0 + */ +class FormulaAutoCompletePopupWindow extends AutoCompleteWithExtraRefreshPopupWindow { + + + public FormulaAutoCompletePopupWindow(Window parent, final FormulaPaneAutoCompletion ac) { + super(parent,ac); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaCompletion.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaCompletion.java new file mode 100644 index 0000000000..3b344dc358 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaCompletion.java @@ -0,0 +1,22 @@ +package com.fr.design.gui.autocomplete; + +import javax.swing.Icon; + +/** + * @author Hoky + * @date 2021/11/5 + */ +public class FormulaCompletion extends BasicCompletion { + private Icon icon; + + public FormulaCompletion(CompletionProvider provider, String replacementText, Icon icon) { + super(provider, replacementText); + this.icon = icon; + } + + @Override + public Icon getIcon() { + return icon; + } + +} 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 new file mode 100644 index 0000000000..cd37fd9bc4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/FormulaPaneAutoCompletion.java @@ -0,0 +1,90 @@ +package com.fr.design.gui.autocomplete; + +import com.fr.design.formula.FormulaPane; + +import javax.swing.KeyStroke; +import javax.swing.ListCellRenderer; +import javax.swing.text.Caret; +import javax.swing.text.JTextComponent; +import java.awt.Window; + +/** + * @author Hoky + * @date 2021/11/2 + * @description 重写一个支持刷新公式树组件的AutoCompletion + */ +public class FormulaPaneAutoCompletion extends AutoCompletionWithExtraRefresh { + /** + * Constructor. + * + * @param provider The completion provider. This cannot be + * null. + */ + public FormulaPaneAutoCompletion(CompletionProvider provider) { + super(provider); + } + + @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 (getCellRender() != null) { + popupWindow.setListCellRenderer(getCellRender()); + } + if (getPreferredChoicesWindowSize() != null) { + popupWindow.setSize(getPreferredChoicesWindowSize()); + } + if (getPreferredDescWindowSize() != null) { + popupWindow.setDescriptionWindowSize( + getPreferredDescWindowSize()); + } + return popupWindow; + } + + /** + * Inserts a completion. Any time a code completion event occurs, the + * actual text insertion happens through this method. + * + * @param c A completion to insert. This cannot be null. + * @param typedParamListStartChar Whether the parameterized completion + * start character was typed (typically '('). + */ + protected void insertCompletion(Completion c, + boolean typedParamListStartChar) { + + JTextComponent textComp = getTextComponent(); + String alreadyEntered = c.getAlreadyEntered(textComp); + hidePopupWindow(); + Caret caret = textComp.getCaret(); + + int dot = caret.getDot(); + int len = alreadyEntered.length(); + int start = dot - len; + String replacement = getReplacementText(c, textComp.getDocument(), + start, len); + + caret.setDot(start); + caret.moveDot(dot); + if (FormulaPane.containsParam(replacement)) { + textComp.replaceSelection(FormulaPane.getParamPrefix(replacement) + replacement); + int caretPosition = textComp.getCaretPosition(); + textComp.setCaretPosition(caretPosition); + } else { + textComp.replaceSelection(replacement + "()"); + int caretPosition = textComp.getCaretPosition(); + textComp.setCaretPosition(caretPosition - 1); + } + + + if (isParameterAssistanceEnabled() && + (c instanceof ParameterizedCompletion)) { + ParameterizedCompletion pc = (ParameterizedCompletion) c; + startParameterizedCompletionAssistance(pc, typedParamListStartChar); + } + + } +} 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/autocomplete/ParameterizedCompletionContext.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java index 78d5e74a48..238fa496b8 100644 --- a/designer-base/src/main/java/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java @@ -16,16 +16,34 @@ import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; import com.fr.design.gui.syntax.ui.rtextarea.ChangeableHighlightPainter; import com.fr.log.FineLoggerFactory; -import javax.swing.*; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +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.*; +import javax.swing.text.AbstractDocument; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; import javax.swing.text.Highlighter.Highlight; import javax.swing.text.Highlighter.HighlightPainter; -import java.awt.*; -import java.awt.event.*; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; @@ -41,7 +59,7 @@ import java.util.List; * @author Robert Futrell * @version 1.0 */ -class ParameterizedCompletionContext { +public class ParameterizedCompletionContext { /** * The parent window. diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/AbstractNameableCreator.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/AbstractNameableCreator.java index 45c940ed4d..9ad08a9e63 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/AbstractNameableCreator.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/AbstractNameableCreator.java @@ -1,6 +1,7 @@ package com.fr.design.gui.controlpane; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.design.beans.BasicBeanPane; import com.fr.general.ComparatorUtils; import com.fr.general.NameObject; @@ -25,14 +26,14 @@ public abstract class AbstractNameableCreator implements NameableCreator { public AbstractNameableCreator(String menuName, String iconPath, Class clazz) { this.menuName = menuName; - this.menuIcon = BaseUtils.readIcon(iconPath); + this.menuIcon = IconUtils.readIcon(iconPath); this.clazzOfObject = clazz; this.clazzOfInitCase = clazz; } public AbstractNameableCreator(String menuName, String iconPath, Class clazz, Class clazzOfEditor) { this.menuName = menuName; - this.menuIcon = BaseUtils.readIcon(iconPath); + this.menuIcon = IconUtils.readIcon(iconPath); this.clazzOfObject = clazz; this.clazzOfEditor = clazzOfEditor; this.clazzOfInitCase = clazz; @@ -40,7 +41,7 @@ public abstract class AbstractNameableCreator implements NameableCreator { public AbstractNameableCreator(String menuName, String iconPath, Class clazz, Class clazz4Init, Class clazzOfEditor) { this.menuName = menuName; - this.menuIcon = BaseUtils.readIcon(iconPath); + this.menuIcon = IconUtils.readIcon(iconPath); this.clazzOfObject = clazz; this.clazzOfEditor = clazzOfEditor; this.clazzOfInitCase = clazz; diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java index 0d01ddbdaa..37fef509db 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java @@ -9,10 +9,16 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.menu.ToolBarDef; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.stable.ArrayUtils; +import com.fr.stable.Filter; import com.fr.stable.Nameable; -import javax.swing.*; -import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.util.Arrays; +import java.util.stream.Stream; /** * Coder: zack @@ -27,6 +33,8 @@ abstract class JControlPane extends BasicPane implements UnrepeatedNameHelper, S ShortCut4JControlPane[] shorts; NameableCreator[] creators; + + protected Filter creatorsFilter; private ToolBarDef toolbarDef; UIToolbar toolBar; @@ -38,6 +46,7 @@ abstract class JControlPane extends BasicPane implements UnrepeatedNameHelper, S JControlPane() { this.initShortCutFactory(); + this.initCreatorsFilter(); this.initComponentPane(); } @@ -106,6 +115,10 @@ abstract class JControlPane extends BasicPane implements UnrepeatedNameHelper, S this.checkButtonEnabled(); } + protected void initCreatorsFilter() { + this.creatorsFilter = nameableCreator -> true; + } + protected void initCardPane() { this.controlUpdatePane = createControlUpdatePane(); @@ -183,7 +196,12 @@ abstract class JControlPane extends BasicPane implements UnrepeatedNameHelper, S } public NameableCreator[] creators() { - return creators == null ? new NameableCreator[0] : creators; + if (creators == null) { + return new NameableCreator[0]; + } else { + Stream nameableCreatorStream = Arrays.stream(creators).filter(creator -> creatorsFilter.accept(creator)); + return nameableCreatorStream.toArray(NameableCreator[]::new); + } } /** diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java index 82cba758b7..ee05422caa 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java @@ -1,10 +1,12 @@ package com.fr.design.gui.controlpane; import com.fr.design.beans.BasicBeanPane; +import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilist.JNameEdList; import com.fr.design.gui.ilist.ListModelElement; import com.fr.design.gui.ilist.ModNameActionListener; +import com.fr.design.i18n.Toolkit; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.form.event.Listener; import com.fr.general.ComparatorUtils; @@ -12,6 +14,7 @@ import com.fr.general.IOUtils; import com.fr.invoke.Reflect; import com.fr.stable.ArrayUtils; import com.fr.stable.Nameable; +import com.fr.stable.StringUtils; import com.fr.stable.core.PropertyChangeAdapter; import javax.swing.DefaultListCellRenderer; @@ -23,12 +26,16 @@ import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import java.util.Collection; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import static javax.swing.JOptionPane.WARNING_MESSAGE; public abstract class JListControlPane extends JControlPane implements ListControlPaneProvider { private static final String LIST_NAME = "JControl_List"; @@ -424,4 +431,47 @@ public abstract class JListControlPane extends JControlPane implements ListContr } + public boolean checkName() { + String tempName = getEditingName(); + if (ComparatorUtils.equals(tempName, selectedName)) { + return false; + } + + if (StringUtils.isEmpty(tempName)) { + nameableList.stopEditing(); + showWarningDialog(getEmptyNameTip()); + setIllegalIndex(editingIndex); + return false; + } + + String[] allListNames = nameableList.getAllNames(); + allListNames[editingIndex] = StringUtils.EMPTY; + if (isNameRepeated(new Collection[]{getExtraItemsToCheckNameRepeat(), Arrays.asList(allListNames)}, tempName)) { + nameableList.stopEditing(); + showWarningDialog(getDuplicatedNameTip()); + setIllegalIndex(editingIndex); + return false; + } + return true; + } + + public String getEmptyNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Not_Null_Des"); + } + + public String getDuplicatedNameTip() { + return StringUtils.EMPTY; + } + + public Collection getExtraItemsToCheckNameRepeat() { + return new ArrayList(); + } + + private void showWarningDialog(String tip) { + FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(JListControlPane.this), + tip, + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + } + } diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIControlPane.java index f7229136f5..12f904922d 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIControlPane.java @@ -31,7 +31,6 @@ import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; @@ -212,7 +211,7 @@ public abstract class UIControlPane extends JControlPane { } // 点击"编辑"按钮,弹出面板 - class PopupEditDialog extends JDialog { + protected class PopupEditDialog extends JDialog { private JComponent editPane; private PopupToolPane popupToolPane; private static final int WIDTH = 570; @@ -241,51 +240,12 @@ public abstract class UIControlPane extends JControlPane { } private void hideDialog() { - // 检查是否有子弹窗,如果有,则不隐藏 - for (Window window : getOwnedWindows()) { - if (window.isVisible()) { - return; - } - } - // 如果有可见模态对话框,则不隐藏 - for (Window window : DesignerContext.getDesignerFrame().getOwnedWindows()) { - if (window instanceof JDialog && window.isVisible() && ((JDialog) window).isModal()) { - return; - } - } - - try { - //没有指定owner的弹出框用的是SwingUtilities.getSharedOwnerFrame() - Frame sharedOwnerFrame = Reflect.on(SwingUtilities.class).call("getSharedOwnerFrame").get(); - for (Window window : sharedOwnerFrame.getOwnedWindows()) { - if (window instanceof JDialog && window.isVisible() && ((JDialog) window).isModal()) { - // 如果有可见模态对话框,则不隐藏 - return; - } - } - } catch (Exception ignore) { - //do nothing - } - - // 要隐藏 先检查有没有非法输入 - // 非法输入检查放在最后,因为可能出现面板弹出新弹框而失去焦点的情况,比如 输入公式时,弹出公式编辑对话框 - try { - checkValid(); - } catch (Exception exp) { - // 存在非法输入 拒绝隐藏 - this.setAlwaysOnTop(true); - FineJOptionPane.showMessageDialog(this, exp.getMessage()); - this.requestFocus(); - return; - } - if (JavaFxNativeFileChooser.isShowDialogState()) { - JavaFxNativeFileChooser.setShowDialogState(false); - return; + if (needToHidePopupEditDialog()) { + saveSettings(); + setVisible(false); + PopupDialogSaveAction saveAction = OSSupportCenter.getAction(PopupDialogSaveAction.class); + saveAction.unregister(); } - saveSettings(); - setVisible(false); - PopupDialogSaveAction saveAction = OSSupportCenter.getAction(PopupDialogSaveAction.class); - saveAction.unregister(); } private void initListener() { @@ -302,6 +262,54 @@ public abstract class UIControlPane extends JControlPane { } } + /** + * 是否需要隐藏popupEditDialog + */ + protected boolean needToHidePopupEditDialog() { + // 检查是否有子弹窗,如果有,则不隐藏 + for (Window window : popupEditDialog.getOwnedWindows()) { + if (window.isVisible()) { + return false; + } + } + // 如果有可见模态对话框,则不隐藏 + for (Window window : DesignerContext.getDesignerFrame().getOwnedWindows()) { + if (window instanceof JDialog && window.isVisible() && ((JDialog) window).isModal()) { + return false; + } + } + + try { + //没有指定owner的弹出框用的是SwingUtilities.getSharedOwnerFrame() + Frame sharedOwnerFrame = Reflect.on(SwingUtilities.class).call("getSharedOwnerFrame").get(); + for (Window window : sharedOwnerFrame.getOwnedWindows()) { + if (window instanceof JDialog && window.isVisible() && ((JDialog) window).isModal()) { + // 如果有可见模态对话框,则不隐藏 + return false; + } + } + } catch (Exception ignore) { + //do nothing + } + + // 要隐藏 先检查有没有非法输入 + // 非法输入检查放在最后,因为可能出现面板弹出新弹框而失去焦点的情况,比如 输入公式时,弹出公式编辑对话框 + try { + checkValid(); + } catch (Exception exp) { + // 存在非法输入 拒绝隐藏 + popupEditDialog.setAlwaysOnTop(true); + FineJOptionPane.showMessageDialog(this, exp.getMessage()); + popupEditDialog.requestFocus(); + return false; + } + if (JavaFxNativeFileChooser.isShowDialogState()) { + JavaFxNativeFileChooser.setShowDialogState(false); + return false; + } + return true; + } + // 移动弹出编辑面板的工具条 private class PopupToolPane extends JPanel { private JDialog parentDialog; // 如果不在对话框中,值为null diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java index 7ba536492a..034847a704 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java @@ -34,6 +34,9 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon private CommonShortCutHandlers commonHandlers; private ListControlPaneHelper helper; + // 目前被触发的事件 + private ListDataEvent currentEvent; + public UIListControlPane() { super(); @@ -96,7 +99,9 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon nameableList.getModel().addListDataListener(new ListDataListener() { @Override public void intervalAdded(ListDataEvent e) { + setCurrentEvent(e); saveSettings(); + setCurrentEvent(null); } @Override @@ -321,4 +326,11 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon } + public ListDataEvent getCurrentEvent() { + return currentEvent; + } + + public void setCurrentEvent(ListDataEvent currentEvent) { + this.currentEvent = currentEvent; + } } diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java index 7c40235304..ed07ecc2d5 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java @@ -125,7 +125,9 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li for (int i = 0, size = widget.getListenerSize(); i < size; i++) { Listener listener = widget.getListener(i); if (!listener.isDefault()) { - nameObjectList.add(i, new NameObject(switchLang(listener.getEventName()) + (i + 1), listener)); + String eventName = switchLang(listener.getEventName()) + (nameObjectList.size() + 1); + NameObject nameObject = new NameObject(eventName, listener); + nameObjectList.add(nameObject); } } populate(getHelper().processCatalog(nameObjectList)); diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/shortcutfactory/ShortCutFactory.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/shortcutfactory/ShortCutFactory.java index 7d16995435..da0b552682 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/shortcutfactory/ShortCutFactory.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/shortcutfactory/ShortCutFactory.java @@ -142,10 +142,6 @@ public class ShortCutFactory extends AbstractShortCutFactory { private void wrapActionListener(NameableCreator[] creators) { for (final NameableCreator creator : creators) { - Filter> filter = DesignModuleFactory.getHyperlinkGroupType().getFilter(); - if (!filter.accept(creator.getHyperlink())) { - continue; - } boolean isTrue = ComparatorUtils.equals(creator.menuName(), com.fr.design.i18n.Toolkit.i18nText("Datasource-Stored_Procedure")) || ComparatorUtils.equals(creator.menuName(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DS_Relation_TableData")) || ComparatorUtils.equals(creator.menuName(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DS_Multi_Dimensional_Database")); if (isTrue) { diff --git a/designer-base/src/main/java/com/fr/design/gui/core/WidgetOption.java b/designer-base/src/main/java/com/fr/design/gui/core/WidgetOption.java index 71289376a0..4c9db5a6a0 100644 --- a/designer-base/src/main/java/com/fr/design/gui/core/WidgetOption.java +++ b/designer-base/src/main/java/com/fr/design/gui/core/WidgetOption.java @@ -2,13 +2,33 @@ package com.fr.design.gui.core; import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; -import com.fr.form.ui.*; +import com.fr.form.ui.Button; +import com.fr.form.ui.CheckBox; +import com.fr.form.ui.CheckBoxGroup; +import com.fr.form.ui.ComboBox; +import com.fr.form.ui.ComboCheckBox; +import com.fr.form.ui.DateEditor; +import com.fr.form.ui.FreeButton; +import com.fr.form.ui.IframeEditor; +import com.fr.form.ui.Label; +import com.fr.form.ui.ListEditor; +import com.fr.form.ui.MultiFileEditor; +import com.fr.form.ui.NumberEditor; +import com.fr.form.ui.Password; +import com.fr.form.ui.PictureWidget; +import com.fr.form.ui.RadioGroup; +import com.fr.form.ui.TextArea; +import com.fr.form.ui.TextEditor; +import com.fr.form.ui.TreeComboBoxEditor; +import com.fr.form.ui.TreeEditor; +import com.fr.form.ui.UserDefinedWidgetConfig; +import com.fr.form.ui.Widget; +import com.fr.form.ui.WidgetConfig; +import com.fr.form.ui.WidgetInfoConfig; import com.fr.general.ComparatorUtils; - - -import javax.swing.*; import java.io.Serializable; import java.util.ArrayList; +import javax.swing.Icon; public abstract class WidgetOption implements Serializable { @@ -124,7 +144,7 @@ public abstract class WidgetOption implements Serializable { */ public static WidgetOption[] getFormWidgetIntance() { return new WidgetOption[]{TEXTEDITOR, LABEL, FREEBUTTON, COMBOBOX, COMBOCHECKBOX, DATEEDITOR, - NUMBEREDITOR, TREECOMBOBOX, RADIOGROUP, CHECKBOXGROUP, TEXTAREA, PASSWORD, CHECKBOX, TREE, MULTI_FILEEDITOR}; + NUMBEREDITOR, TREECOMBOBOX, RADIOGROUP, CHECKBOXGROUP, TEXTAREA, PASSWORD, CHECKBOX, TREE, MULTI_FILEEDITOR,PICTURE}; } public static final WidgetOption DATEEDITOR = WidgetOptionFactory.createByWidgetClass(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Type_Date"), @@ -196,4 +216,7 @@ public abstract class WidgetOption implements Serializable { public static final WidgetOption IFRAMEDITOR = WidgetOptionFactory.createByWidgetClass(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Form_Iframe"), BaseUtils.readIcon("/com/fr/web/images/form/resources/iframe_16.png"), IframeEditor.class); + public static final WidgetOption PICTURE = WidgetOptionFactory.createByWidgetClass(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Type_Image"), IconUtils.readIcon("/com/fr/web/images/form/resources/picture_widget_16.png"), + PictureWidget.class); + } diff --git a/designer-base/src/main/java/com/fr/design/gui/core/WidgetOptionFactory.java b/designer-base/src/main/java/com/fr/design/gui/core/WidgetOptionFactory.java index e9ba427880..8d290ac2a8 100644 --- a/designer-base/src/main/java/com/fr/design/gui/core/WidgetOptionFactory.java +++ b/designer-base/src/main/java/com/fr/design/gui/core/WidgetOptionFactory.java @@ -4,7 +4,7 @@ import com.fr.base.BaseUtils; import com.fr.base.svg.IconUtils; import com.fr.form.ui.Widget; -import javax.swing.*; +import javax.swing.Icon; public class WidgetOptionFactory { diff --git a/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java b/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java index fbbe38ce48..fb21021179 100644 --- a/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java +++ b/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java @@ -2,6 +2,8 @@ package com.fr.design.gui.date; import com.fr.base.BaseUtils; import com.fr.base.background.GradientBackground; +import com.fr.design.carton.MonthlyCartonFile; +import com.fr.design.carton.SwitchForSwingChecker; import com.fr.design.constants.UIConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; @@ -9,7 +11,10 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUIPaintUtils; +import com.fr.general.GeneralUtils; import com.fr.stable.Constants; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; @@ -40,16 +45,20 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.RoundRectangle2D; +import java.io.File; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; +import java.util.Set; public class UICalendarPanel extends JPanel { private static final Font FONT_UI = DesignUtils.getDefaultGUIFont().applySize(12); private static final Font FONT_BLACK = new Font(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Black_Font"), Font.PLAIN, 12); private static final int WEEKDAY_COUNT = 7; private static final int TOTAL_DAYS_COUNT = 42; - + //卡顿日志所在地址 + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); protected Color selectedBackground; protected Color selectedForeground; protected Color background; @@ -63,12 +72,27 @@ public class UICalendarPanel extends JPanel { private boolean isSupportDateChangeListener = false; private java.util.Date selectedDate = null; private boolean isTimePicker; + private final Color LABEL_FORGE_GROUND = new Color(0x6F6F6); + private MouseListener todayListener; + private UIDayLabel lbToday; + /** + * 一个int类型用于判断日历是否是专门用于处理卡顿的设计器反馈箱中的日历 + * 0表示是 + * -1表示不是 + */ + private boolean speciallyForCarton = false; /** * 年月格式 */ final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM"); + /** + * 年月格式2 + */ + final SimpleDateFormat dayFormat + = new SimpleDateFormat("yyyy-MM-dd"); + public UICalendarPanel() { this(new Date(), false); } @@ -77,6 +101,14 @@ public class UICalendarPanel extends JPanel { this(new Date(), isTimerPicker); } + /** + * 构造函数,用于给speciallyForCarton赋值 + */ + public UICalendarPanel(boolean isTimePicker, boolean speciallyForCarton) { + this(new Date(), isTimePicker); + this.speciallyForCarton = speciallyForCarton; + initTodayListener(); + } public UICalendarPanel(Date selectedDate, boolean isTimerPicker) { this.selectedDate = selectedDate; @@ -106,7 +138,12 @@ public class UICalendarPanel extends JPanel { updateHMS(); } } - + private void initTodayListener() { + if (speciallyForCarton && !SwitchForSwingChecker.isCartonExists()) { + lbToday.setEnabled(false); + lbToday.removeMouseListener(todayListener); + } + } // << < yyyy/MM/dd > >> private JPanel createNorthPane() { JPanel pNorth = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); @@ -187,13 +224,13 @@ public class UICalendarPanel extends JPanel { GradientPane pToday = new GradientPane(new GradientBackground(new Color(0x097BDA), new Color(0x40A3EE), GradientBackground.TOP2BOTTOM), false); pToday.setPreferredSize(new Dimension(216, 18)); pToday.setLayout(new BorderLayout()); - UIDayLabel lbToday = new UIDayLabel(new Date(), false); + lbToday = new UIDayLabel(new Date(), false); lbToday.setForeground(new Color(0x000000)); - lbToday.addMouseListener(createTodayListener(pToday, lbToday)); + todayListener = createTodayListener(pToday, lbToday); + lbToday.addMouseListener(todayListener); pToday.setBackground(new Color(0xF0F0F0)); pToday.add(lbToday, BorderLayout.CENTER); pCenter.add(pToday, BorderLayout.SOUTH); - return pCenter; } @@ -288,10 +325,67 @@ public class UICalendarPanel extends JPanel { }; } + /** + *根据当月获取下个月 + * 圈复杂度比较高就单独拿出来了 + */ + private int getNextMonth(int month) { + int num = (month + 1) % 12; + return num == 0 ? 12 : num; + } + private int getYearOfNextMonth(int month, int year) { + return year + (month + 1) / 13; + } + /** + * 将配置目录中已有的所有卡顿日志文件的名字如(2022-08-09)加入到set中 + */ + private void addFileIntoSet(Set set, MonthlyCartonFile monthlyCartonFile) { + File currentMonthFile = monthlyCartonFile.getCurrentMonthFile(); + File lastMonthFile = monthlyCartonFile.getLastMonthFile(); + File nextMonthFile = monthlyCartonFile.getNextMonthFile(); + File[] monthFiles = new File[3]; + monthFiles[0] = lastMonthFile; + monthFiles[1] = currentMonthFile; + monthFiles[2] = nextMonthFile; + for (File file : monthFiles) { + if (file.exists() && file.isDirectory()) { + File[] files = file.listFiles(); + for (File detailFile : files) { + set.add(detailFile.getName()); + } + } + } + } + /** + * 给label设置属性 + */ + private void setUIDayLabel(UIDayLabel label, boolean isCurrentMonth, + Calendar setupCalendar, Set logSet) { + /** + * 区分开两种panel + */ + if (speciallyForCarton) { + if (!logSet.contains(GeneralUtils.objectToString(dayFormat.format(setupCalendar.getTime())))) { + label.setEnabled(false); + } else { + label.addMouseListener(dayBttListener); + } + } else { + label.addMouseListener(dayBttListener); + label.setEnabled(isCurrentMonth); + } + if (!isCurrentMonth) { + label.setForeground(LABEL_FORGE_GROUND); + } + } /** * 更新日期 */ protected void updateDays() { + /** + * 用于处理卡顿日志日历的一些工具 + */ + Set logSet = new HashSet<>(); //更新月份 monthLabel.setText(monthFormat.format(calendar.getTime())); days.removeAll(); @@ -302,8 +396,29 @@ public class UICalendarPanel extends JPanel { setupCalendar.set(Calendar.DAY_OF_MONTH, 1); int first = setupCalendar.get(Calendar.DAY_OF_WEEK); setupCalendar.add(Calendar.DATE, -first); - boolean isCurrentMonth = false; + if (speciallyForCarton) { + Calendar clone = (Calendar)setupCalendar.clone(); + clone.add(Calendar.DATE, 1); + int year = clone.get(Calendar.YEAR); + //日历获取的月份是从0开始的 + int month = clone.get(Calendar.MONTH) + 1; + //往后推一个月的年月份 + int month2 = getNextMonth(month); + int year2 = getYearOfNextMonth(month, year); + //再往后推一个月的年月份 + int month3 = getNextMonth(month2); + int year3 = getYearOfNextMonth(month2, year2); + //文件地址如:"C:\Users\23131\.FineReport110\journal_log\2022\month-9\2022-09-01" + MonthlyCartonFile monthlyCartonFile = new MonthlyCartonFile(); + monthlyCartonFile.setCurrentMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year2), "month-" + month2))); + monthlyCartonFile.setLastMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month))); + monthlyCartonFile.setNextMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year3), "month-" + month3))); + addFileIntoSet(logSet, monthlyCartonFile); + } for (int i = 0; i < TOTAL_DAYS_COUNT; i++) { setupCalendar.add(Calendar.DATE, 1); GradientPane gp = new GradientPane(new GradientBackground(new Color(0xFEFEFE), new Color(0xF3F2F3), GradientBackground.TOP2BOTTOM), true); @@ -313,14 +428,10 @@ public class UICalendarPanel extends JPanel { UIDayLabel label = new UIDayLabel(setupCalendar.getTime()); label.setHorizontalAlignment(SwingConstants.RIGHT); label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 9)); - label.addMouseListener(dayBttListener); if ("1".equals(label.getText())) { isCurrentMonth = !isCurrentMonth; } - label.setEnabled(isCurrentMonth); - if (!isCurrentMonth) { - label.setForeground(new Color(0x6F6F6)); - } + setUIDayLabel(label, isCurrentMonth, setupCalendar, logSet); //当前选择的日期 if (setupCalendar.get(Calendar.DAY_OF_MONTH) == selectedCalendar.get(Calendar.DAY_OF_MONTH) && isCurrentMonth) { gp.setGradientBackground(new GradientBackground(new Color(0x097BD9), new Color(0x41A3EE), GradientBackground.TOP2BOTTOM)); @@ -534,6 +645,7 @@ public class UICalendarPanel extends JPanel { this.setLayout(new GridLayout(6, 7, 1, 1)); this.setBackground(new Color(0xFFFFFF)); this.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, new Color(0xDADADA))); + } public void paint(Graphics g) { @@ -754,7 +866,6 @@ public class UICalendarPanel extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(); - UICalendarPanel calendarPanel = new UICalendarPanel(); final UITextField field = new UITextField(); field.setPreferredSize(new Dimension(120, 25)); diff --git a/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java b/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java index be3ef20a3a..1da26c302c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java +++ b/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java @@ -7,6 +7,7 @@ import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import com.fr.design.carton.FeedbackToolboxDialog; import javax.swing.BorderFactory; import javax.swing.JComboBox; @@ -32,6 +33,11 @@ import java.util.Date; * UIDatePicker */ public class UIDatePicker extends UIComboBox implements Serializable { + + /** + * 用于记录本datePicker是否是由设计器卡顿优化箱上打开(后续要去调用方法) + */ + private FeedbackToolboxDialog feedbackToolboxDialog = null; /** * 日期格式类型 */ @@ -40,7 +46,7 @@ public class UIDatePicker extends UIComboBox implements Serializable { public static final int STYLE_CN_DATETIME = 2; public static final int STYLE_CN_DATETIME1 = 3; public static final int STYLE_EN_DATE = 4; - public boolean isWillHide = false; + private boolean willHide = false; /** * 日期格式类型 */ @@ -67,23 +73,43 @@ public class UIDatePicker extends UIComboBox implements Serializable { this(formatStyle, new Date()); } - public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException { + public UIDatePicker(int formatStyle, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException { + this(formatStyle, new Date(), feedbackToolboxDialog); + } + + /** + * + * @param formatStyle + * @param initialDatetime + * @param feedbackToolboxDialog 判断该日历是否由设计器反馈工具箱打开 + * @throws UnsupportedOperationException + */ + public UIDatePicker(int formatStyle, Date initialDatetime, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException { this.setStyle(formatStyle); //设置可编辑 this.setEditable(true); - this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - //设置编辑器属性(只能输入正确日期) JTextField textField = ((JTextField) getEditor().getEditorComponent()); - textField.setHorizontalAlignment(SwingConstants.CENTER); - dateDocument = new JDateDocument(textField, this.dateFormat); + if (feedbackToolboxDialog != null) { + dateDocument = new JDateDocument(textField, this.dateFormat, StringUtils.EMPTY); + this.feedbackToolboxDialog = feedbackToolboxDialog; + textField.setHorizontalAlignment(SwingConstants.LEFT); + //设置当前选择日期 + this.setSelectedItem(initialDatetime); + } else { + dateDocument = new JDateDocument(textField, this.dateFormat); + this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime); + textField.setHorizontalAlignment(SwingConstants.CENTER); + } textField.setDocument(dateDocument); //设置Model为单值Model this.setModel(model); - //设置当前选择日期 - this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime); - updateUI(); + updateUI(); + } + + public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException { + this(formatStyle, initialDatetime, null); } /** @@ -149,20 +175,20 @@ public class UIDatePicker extends UIComboBox implements Serializable { * @return Date */ public Date getSelectedDate() throws ParseException { - synchronized (this) { - return dateFormat.parse(getSelectedItem().toString()); - } + synchronized (this) { + return dateFormat.parse(getSelectedItem().toString()); + } } /** * 设置当前选择的日期 */ public synchronized void setSelectedDate(Date date) throws ParseException { - if (date == null) { - this.setSelectedItem(null); - } else { - this.setSelectedItem(dateFormat.format(date)); - } + if (date == null) { + this.setSelectedItem(null); + } else { + this.setSelectedItem(dateFormat.format(date)); + } } @Override @@ -182,34 +208,36 @@ public class UIDatePicker extends UIComboBox implements Serializable { */ class DatePopup extends BasicComboPopup implements ChangeListener { UICalendarPanel calendarPanel = null; - public DatePopup(JComboBox box) { super(box); - setLayout(FRGUIPaneFactory.createBorderLayout()); - calendarPanel = new UICalendarPanel(formatStyle > 1); + if (feedbackToolboxDialog != null) { + calendarPanel = new UICalendarPanel(formatStyle > 1, true); + } else { + calendarPanel = new UICalendarPanel(formatStyle > 1); + } calendarPanel.addDateChangeListener(this); add(calendarPanel, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder()); } @Override - public void hide() { - if (isWillHide) { - super.hide(); - } - } + public void hide() { + if (willHide) { + super.hide(); + } + } - @Override - public void show() { - if (isWillHide || UIDatePicker.this.isEnabled() == false) { - return; - } - if (calendarPanel != null) { - calendarPanel.resetHMSPaneSelectedNumberField(); - } - super.show(); - } + @Override + public void show() { + if (willHide || UIDatePicker.this.isEnabled() == false) { + return; + } + if (calendarPanel != null) { + calendarPanel.resetHMSPaneSelectedNumberField(); + } + super.show(); + } /** * 显示弹出面板 @@ -223,16 +251,16 @@ public class UIDatePicker extends UIComboBox implements Serializable { && ComparatorUtils.equals(newValue, Boolean.TRUE)) { //SHOW try { String strDate = comboBox.getSelectedItem().toString(); - synchronized (this) { - Date selectionDate = new Date(); - if (StringUtils.isNotBlank(strDate)) { + synchronized (this) { + Date selectionDate = new Date(); + if (StringUtils.isNotBlank(strDate)) { selectionDate = dateFormat.parse(strDate); } calendarPanel.setSelectedDate(selectionDate); - calendarPanel.updateHMS(); - } + calendarPanel.updateHMS(); + } } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineLoggerFactory.getLogger().error(e.getMessage(), e); } } else if (ComparatorUtils.equals(oldValue, Boolean.TRUE) && ComparatorUtils.equals(newValue, Boolean.FALSE)) { //HIDE @@ -241,16 +269,21 @@ public class UIDatePicker extends UIComboBox implements Serializable { super.firePropertyChange(propertyName, oldValue, newValue); } + @Override public void stateChanged(ChangeEvent e) { - if (calendarPanel.getSelectedDate() != null && dateFormat != null) { - String strDate = dateFormat.format(calendarPanel.getSelectedDate()); - if (comboBox.isEditable() && comboBox.getEditor() != null) { - comboBox.configureEditor(comboBox.getEditor(), strDate); - } - comboBox.setSelectedItem(strDate); - } - comboBox.repaint(); - setVisible(false); + if (calendarPanel.getSelectedDate() != null && dateFormat != null) { + String strDate = dateFormat.format(calendarPanel.getSelectedDate()); + if (comboBox.isEditable() && comboBox.getEditor() != null) { + comboBox.configureEditor(comboBox.getEditor(), strDate); + } + comboBox.setSelectedItem(strDate); + } + comboBox.repaint(); + setVisible(false); + //选择完日期,导出/上传按钮变可用 + if (feedbackToolboxDialog != null) { + feedbackToolboxDialog.setSwitches(true); + } } } @@ -258,53 +291,53 @@ public class UIDatePicker extends UIComboBox implements Serializable { protected ComboBoxUI getUIComboBoxUI() { return new UIComboBoxUI() { @Override - protected ComboPopup createPopup() { - return new DatePopup(comboBox); - } - @Override - public void mousePressed(MouseEvent e) { - if (UIDatePicker.this.isPopupVisible()) { - isWillHide = true; - UIDatePicker.this.hidePopup(); - } else { - isWillHide = false; - UIDatePicker.this.showPopup(); - } - } - }; + protected ComboPopup createPopup() { + return new DatePopup(comboBox); + } + @Override + public void mousePressed(MouseEvent e) { + if (UIDatePicker.this.isPopupVisible()) { + willHide = true; + UIDatePicker.this.hidePopup(); + } else { + willHide = false; + UIDatePicker.this.showPopup(); + } + } + }; } - + //设置dataFormat public void setDateFormat(SimpleDateFormat format){ this.dateFormat = format; } - + //获取dateFormat public SimpleDateFormat getDateFormat(){ return this.dateFormat; } - + public JDateDocument getDateDocument(){ return this.dateDocument; } - public static void main(String[] args) { - LayoutManager layoutManager = null; - JFrame jf = new JFrame("test"); - jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - JPanel content = (JPanel) jf.getContentPane(); - content.setLayout(layoutManager); - UIDatePicker bb = new UIDatePicker(); - if (args.length != 0) { - bb = new UIDatePicker(STYLE_CN_DATETIME); - } - bb.setEditable(true); - bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height); - content.add(bb); - GUICoreUtils.centerWindow(jf); - jf.setSize(400, 400); - jf.setVisible(true); - } + public static void main(String[] args) { + LayoutManager layoutManager = null; + JFrame jf = new JFrame("test"); + jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JPanel content = (JPanel) jf.getContentPane(); + content.setLayout(layoutManager); + UIDatePicker bb = new UIDatePicker(); + if (args.length != 0) { + bb = new UIDatePicker(STYLE_CN_DATETIME); + } + bb.setEditable(true); + bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height); + content.add(bb); + GUICoreUtils.centerWindow(jf); + jf.setSize(400, 400); + jf.setVisible(true); + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java index 381a9cd761..15d50d00cb 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java @@ -3,6 +3,8 @@ package com.fr.design.gui.frpane; import com.fr.design.dialog.BasicPane; import com.fr.design.event.GlobalNameListener; import com.fr.design.event.GlobalNameObserver; +import com.fr.design.event.ComponentChangeListener; +import com.fr.design.event.ComponentChangeObserver; import com.fr.design.event.UIObserver; import com.fr.design.event.UIObserverListener; import com.fr.stable.StringUtils; @@ -24,6 +26,16 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane { private AttributeChangeListener listener; private String globalName = ""; + private boolean autoFireAttributesChanged = true; + + public boolean isAutoFireAttributesChanged() { + return this.autoFireAttributesChanged; + } + + public void setAutoFireAttributesChanged(boolean autoFireAttributesChanged) { + this.autoFireAttributesChanged = autoFireAttributesChanged; + } + protected AbstractAttrNoScrollPane() { initAll(); } @@ -93,6 +105,15 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane { } }); } + if(tmpComp instanceof ComponentChangeObserver){ + ComponentChangeObserver uiChangeableObserver = ((ComponentChangeObserver)tmpComp); + uiChangeableObserver.registerChangeListener(new ComponentChangeListener() { + @Override + public void initListener(Container changedComponent) { + AbstractAttrNoScrollPane.this.initListener(changedComponent); + } + }); + } } } @@ -127,7 +148,9 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane { public void attributeChanged() { synchronized (this) { if (listener != null) { - listener.attributeChange(); + if (autoFireAttributesChanged) { + listener.attributeChange(); + } } } } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java b/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java new file mode 100644 index 0000000000..bfc1ff9d45 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/AttributeChangeUtils.java @@ -0,0 +1,47 @@ +package com.fr.design.gui.frpane; + +import java.awt.Component; +import java.awt.Container; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/17 + */ +public class AttributeChangeUtils { + private static AbstractAttrNoScrollPane findNearestAttrNoScrollPaneAncestor(Component c) { + for(Container p = c.getParent(); p != null; p = p.getParent()) { + if (p instanceof AbstractAttrNoScrollPane) { + return (AbstractAttrNoScrollPane) p; + } + } + return null; + } + + public static void changeComposedUI(Component composedComponent, boolean fireMiddleStateChanged, UIChangeAction action) { + AbstractAttrNoScrollPane attrPane = findNearestAttrNoScrollPaneAncestor(composedComponent); + boolean oldAutoFire = true; + + if (!fireMiddleStateChanged) { + // 禁止属性面板自动处理属性更新 + if (attrPane != null) { + oldAutoFire = attrPane.isAutoFireAttributesChanged(); + attrPane.setAutoFireAttributesChanged(false); + } + } + + // 更新UI + action.changeComposedUI(); + + if (!fireMiddleStateChanged) { + // 恢复属性面板自动处理属性更新 + if (attrPane != null) { + attrPane.setAutoFireAttributesChanged(oldAutoFire); + } + } + } + + public interface UIChangeAction { + void changeComposedUI(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/ClosableBubbleFloatPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/ClosableBubbleFloatPane.java new file mode 100644 index 0000000000..41a4471daa --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/ClosableBubbleFloatPane.java @@ -0,0 +1,46 @@ +package com.fr.design.gui.frpane; + +import com.fr.base.BaseUtils; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.gui.ilable.UILabel; + +import javax.swing.Icon; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public abstract class ClosableBubbleFloatPane extends UIBubbleFloatPane { + public ClosableBubbleFloatPane(int arrowPosition, Point arrowPoint, BasicBeanPane contentPane) { + super(arrowPosition, arrowPoint, contentPane); + } + + public ClosableBubbleFloatPane(int arrowPosition, Point arrowPoint, BasicBeanPane contentPane, int width, int height) { + super(arrowPosition, arrowPoint, contentPane, width, height); + } + + protected void initAWTEventListener() { + + } + + public boolean forceLockFocus() { + return true; + } + + protected JPanel initTopOptionMenu() { + JPanel menu = new JPanel(new BorderLayout()); + Icon icon = BaseUtils.readIcon("/com/fr/design/images/buttonicon/close_icon.png"); + UILabel label = new UILabel(icon); + label.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + showDialog.setVisible(false); + updateContentPane(); + } + }); + + menu.add(label, BorderLayout.EAST); + return menu; + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPaneActionProvider.java b/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPaneActionProvider.java index 525bb5b792..be0d8e8523 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPaneActionProvider.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPaneActionProvider.java @@ -8,6 +8,8 @@ import com.fr.design.designer.TargetComponent; */ public interface HyperlinkGroupPaneActionProvider { + String XML_TAG = "HyperlinkGroupPane"; + /** * 刷新面板展示 * diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeAutoBuildPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeAutoBuildPane.java index 83c52ac784..a47b0021f2 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeAutoBuildPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeAutoBuildPane.java @@ -242,12 +242,22 @@ public class JTreeAutoBuildPane extends BasicPane implements PreviewLabel.Previe rtd = treeTableDataComboBox.getSelcetedTableData(); name = treeTableDataComboBox.getSelectedItem().getTableDataName(); } + final String tableDataName = name; AbstractTableDataWrapper atdw = new TemplateTableDataWrapper(rtd, ""); - tdtp.dgEdit(atdw.creatTableDataPane(), name); - treeTableDataComboBox.refresh(); - treeTableDataComboBox.setSelectedTableDataByName(name); - textPane.populate(1); - valuePane.populate(1); + tdtp.showEditPane(atdw.creatTableDataPane(), name, new BasicTableDataTreePane.TableDataTreePaneListener() { + @Override + public void doOk() { + // 去除缓存列,后面刷新会重新选中 + DesignTableDataManager.removeSelectedColumnNames(tableDataName); + treeTableDataComboBox.refresh(); + treeTableDataComboBox.setSelectedTableDataByName(tableDataName); + } + + @Override + public void doCancel() { + + } + }); } } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java index 04e3626a4a..4c4785be01 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java @@ -42,14 +42,10 @@ public class JTreeControlPane extends ControlPane { private JTree tree; private DefaultTreeModel defaultTreeModel; - - boolean isEditor = false; - private UICheckBox isPerformanceFirst; - public JTreeControlPane(NameableCreator[] creators, BasicBeanPane updatePane, boolean isEditor) { + public JTreeControlPane(NameableCreator[] creators, BasicBeanPane updatePane) { this.initComponents(creators, updatePane); - this.isEditor = isEditor; } private void initComponents(NameableCreator[] creators, BasicBeanPane updatePane) { @@ -120,11 +116,7 @@ public class JTreeControlPane extends ControlPane { if (obj instanceof TreeNodeAttr[]) { treeNodeAttr = ((TreeNodeAttr[]) obj); isPerformanceFirst.setSelected(false); - } else if (obj instanceof TreeEditor) { - TreeEditor treeEditor = (TreeEditor) obj; - treeNodeAttr = treeEditor.getTreeNodeAttr(); - isPerformanceFirst.setSelected(treeEditor.isPerformanceFirst()); - } else if (obj instanceof TreeNodeWrapper) { + }else if (obj instanceof TreeNodeWrapper) { treeNodeAttr = ((TreeNodeWrapper) obj).getTreeNodeAttrs(); isPerformanceFirst.setSelected(((TreeNodeWrapper) obj).isPerformanceFirst()); } @@ -146,18 +138,8 @@ public class JTreeControlPane extends ControlPane { } public NameObject update() { - if (isEditor) { - TreeEditor treeEditor = new TreeEditor(); - - treeEditor.setTreeNodeAttr(updateTreeNodeAttr()); - - treeEditor.setPerformanceFirst(isPerformanceFirst.isSelected()); - - return new NameObject("tree", treeEditor); - } else { - TreeNodeWrapper treeNodeWrapper = new TreeNodeWrapper(isPerformanceFirst.isSelected(), updateTreeNodeAttr()); - return new NameObject("tree", treeNodeWrapper); - } + TreeNodeWrapper treeNodeWrapper = new TreeNodeWrapper(isPerformanceFirst.isSelected(), updateTreeNodeAttr()); + return new NameObject("tree", treeNodeWrapper); } public TreeNodeAttr[] updateTreeNodeAttr() { diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java index ba75cce9df..b187a8bfa0 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java @@ -26,12 +26,18 @@ import java.awt.event.ItemListener; import java.util.Arrays; public class TreeSettingPane extends BasicPane implements DataCreatorUI { + /** + * 普通分层构建方式 + */ private JTreeControlPane controlPane; + /** + * 自动构建方式 + */ private JTreeAutoBuildPane autoBuildPane; /** - * 新的分层构建方式 + * 急速分层构建方式 */ private LayerDataControlPane layerDataControlPane; @@ -43,37 +49,41 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI { private static final long serialVersionUID = 1762889323082827111L; private String[] buildWay = new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DataTable_Build"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Auto_Build"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Layer_Build")}; + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Auto_Build"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Layer_Build")}; - public TreeSettingPane(boolean isEditor) { - this.initComponents(isEditor); + public TreeSettingPane() { + this.initComponents(); } - private void initComponents(boolean isEditor) { + private void initComponents() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel buildWayPanel= FRGUIPaneFactory.createMediumHGapFlowInnerContainer_M_Pane(); + JPanel buildWayPanel = FRGUIPaneFactory.createMediumHGapFlowInnerContainer_M_Pane(); buildWayPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); UILabel buildWayLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Build_Way") + " :"); buildWayPanel.add(buildWayLabel); buildBox = new UIComboBox(buildWay); - buildBox.addItemListener(new ItemListener() { - - @Override - public void itemStateChanged(ItemEvent e) { - cardChanged(buildBox.getSelectedIndex()); - } + buildBox.addItemListener(e -> { + cardChanged(buildBox.getSelectedIndex()); }); buildWayPanel.add(buildBox); - controlPane = new JTreeControlPane(new NameableCreator[] { treeNode }, - new TreeDataCardPane(), isEditor); + controlPane = new JTreeControlPane(new NameableCreator[]{treeNode}, + new TreeDataCardPane()); autoBuildPane = new JTreeAutoBuildPane(); layerDataControlPane = new LayerDataControlPane(); this.add(buildWayPanel, BorderLayout.NORTH); cardChanged(0); } - private void cardChanged(int index) { + @Override + public void checkValid() throws Exception { + doBuildBoxSelect(buildBox.getSelectedIndex()); + } + + private void doBuildBoxSelect(Integer selectedIndex) { + } + + private void cardChanged(int index) { this.remove(controlPane); this.remove(autoBuildPane); @@ -108,87 +118,14 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI { } NameableCreator treeNode = new NameObjectCreator( - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Gradation"), - "/com/fr/design/images/data/source/jdbcTableData.png", - TreeNodeAttr.class); - - /** - * - * @param treeEditor - */ - public void populate(TreeEditor treeEditor) { - boolean isAutoBuild = treeEditor.isAutoBuild(); - TreeAttr treeAttr = treeEditor.getTreeAttr(); - if (treeAttr != null) { - NameObject no = new NameObject("name", treeEditor); - controlPane.populate(no); - } - if (isAutoBuild) { - buildBox.setSelectedIndex(1); - TableDataDictionary dictionary = treeEditor.getDictionary(); - autoBuildPane.populate(dictionary); - } else if (treeEditor.isLayerBuild()) { - buildBox.setSelectedIndex(0); - java.util.List layerConfigList = treeEditor.getLayerConfigs(); - LayerConfig[] layerConfigs = new LayerConfig[layerConfigList.size()]; - int i = 0; - for (LayerConfig layerConfig : layerConfigList) { - layerConfigs[i++] = layerConfig; - } - this.layerDataControlPane.populate(new NameObject("Tree Layer Data", layerConfigs)); - } else { - buildBox.setSelectedIndex(2); - } - } + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Gradation"), + "/com/fr/design/images/data/source/jdbcTableData.png", + TreeNodeAttr.class); - /** - * 视图树的update - * @return - */ - public TreeEditor updateTreeEditor() { -// NameObject no = this.controlPane.update(); -// if (no != null) { -// return ((TreeEditor) no.getObject()); -// } -// -// return null; - TreeEditor te = new TreeEditor(); - if (buildBox.getSelectedIndex() == 1) { - TableDataDictionary dictionary = this.autoBuildPane.update(); - te.setAutoBuild(true); - te.setLayerBuild(false); - te.setDictionary(dictionary); - te.setNodeOrDict(dictionary); - } else if (buildBox.getSelectedIndex() == 2) { - te.setAutoBuild(false); - te.setLayerBuild(false); - NameObject no = this.controlPane.update(); - if (no != null) { - TreeEditor editor = (TreeEditor) no.getObject(); - te.setAllowBlank(editor.isAllowBlank()); - te.setEnabled(editor.isEnabled()); - te.setDirectEdit(editor.isDirectEdit()); - te.setErrorMessage(editor.getErrorMessage()); - te.setWidgetName(editor.getWidgetName()); - te.setVisible(editor.isVisible()); - te.setWaterMark(editor.getWaterMark()); - te.setRemoveRepeat(editor.isRemoveRepeat()); - te.setTreeAttr(editor.getTreeAttr()); - te.setTreeNodeAttr(editor.getTreeNodeAttr()); - te.setNodeOrDict(editor.getTreeNodeAttr()); - te.setPerformanceFirst(editor.isPerformanceFirst()); - } - } else { - LayerConfig[] configs = (LayerConfig[]) layerDataControlPane.update().getObject(); - te.setAutoBuild(false); - te.setLayerBuild(true); - te.setLayerConfigs(Arrays.asList(configs)); - } - return te; - } /** * 树节点属性的update + * * @return */ public Object updateTreeNodeAttrs() { @@ -207,64 +144,19 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI { } /** - * 下拉树的update - * @return - */ - public TreeComboBoxEditor updateTreeComboBox() { - TreeComboBoxEditor tcb = new TreeComboBoxEditor(); - if (buildBox.getSelectedIndex() == 1) { - TableDataDictionary dictionary = this.autoBuildPane.update(); - tcb.setAutoBuild(true); - tcb.setLayerBuild(false); - tcb.setDictionary(dictionary); - tcb.setNodeOrDict(dictionary); - } else if (buildBox.getSelectedIndex() == 2) { - tcb.setAutoBuild(false); - tcb.setLayerBuild(false); - NameObject no = this.controlPane.update(); - if (no != null) { - if (no.getObject() instanceof TreeComboBoxEditor) { - return (TreeComboBoxEditor) no.getObject(); - } - - TreeEditor editor = (TreeEditor) no.getObject(); - tcb.setAllowBlank(editor.isAllowBlank()); - tcb.setEnabled(editor.isEnabled()); - tcb.setDirectEdit(editor.isDirectEdit()); - tcb.setErrorMessage(editor.getErrorMessage()); - tcb.setWidgetName(editor.getWidgetName()); - tcb.setVisible(editor.isVisible()); - tcb.setWaterMark(editor.getWaterMark()); - tcb.setRemoveRepeat(editor.isRemoveRepeat()); - tcb.setTreeAttr(editor.getTreeAttr()); - tcb.setTreeNodeAttr(editor.getTreeNodeAttr()); - tcb.setNodeOrDict(editor.getTreeNodeAttr()); - tcb.setPerformanceFirst(editor.isPerformanceFirst()); - } - }else { - LayerConfig[] configs = (LayerConfig[]) layerDataControlPane.update().getObject(); - tcb.setAutoBuild(false); - tcb.setLayerBuild(true); - tcb.setLayerConfigs(Arrays.asList(configs)); - } - return tcb; - } - - /** - * * @param nodeOrDict */ public void populate(Object nodeOrDict) { - if(nodeOrDict instanceof TreeNodeAttr[] || nodeOrDict instanceof TreeNodeWrapper) { + if (nodeOrDict instanceof TreeNodeAttr[] || nodeOrDict instanceof TreeNodeWrapper) { buildBox.setSelectedIndex(2); NameObject no = new NameObject("name", nodeOrDict); controlPane.populate(no); - } else if(nodeOrDict instanceof TableDataDictionary) { + } else if (nodeOrDict instanceof TableDataDictionary) { buildBox.setSelectedIndex(1); - autoBuildPane.populate((TableDataDictionary)nodeOrDict); - } else if (nodeOrDict instanceof NameObject) { + autoBuildPane.populate((TableDataDictionary) nodeOrDict); + } else if (nodeOrDict instanceof LayerConfig[]) { buildBox.setSelectedIndex(0); - layerDataControlPane.populate((NameObject) nodeOrDict); + layerDataControlPane.populate((LayerConfig[]) nodeOrDict); } } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java index 03927ca468..e501401217 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java @@ -48,7 +48,7 @@ public abstract class UIBubbleFloatPane extends BasicBeanPane { private int arrowPosition; private double time = 0.5; - private UIDialog showDialog; + protected UIDialog showDialog; /** * @param arrowPosition 箭头的位置,上下左右,暂时只处理了左边,后面用到了再说 TODO @@ -93,11 +93,22 @@ public abstract class UIBubbleFloatPane extends BasicBeanPane { populateBean(ob); if (showDialog == null) { showDialog = showUnsizedWindow(SwingUtilities.getWindowAncestor(fatherPane)); + if (forceLockFocus()) { + showDialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); + } } - Toolkit.getDefaultToolkit().addAWTEventListener(awt, AWTEvent.MOUSE_EVENT_MASK); + initAWTEventListener(); showDialog.setVisible(true); } + public boolean forceLockFocus() { + return false; + } + + protected void initAWTEventListener() { + Toolkit.getDefaultToolkit().addAWTEventListener(awt, AWTEvent.MOUSE_EVENT_MASK); + } + /** * 数据展现 */ @@ -213,9 +224,14 @@ public abstract class UIBubbleFloatPane extends BasicBeanPane { } this.setLayout(new BorderLayout()); + this.add(initTopOptionMenu(), BorderLayout.NORTH); this.add(contentPane, BorderLayout.CENTER); } + protected JPanel initTopOptionMenu() { + return new JPanel(); + } + private class CustomShapedDialog extends UIDialog { private static final int GAP_SMALL = 10; diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java index 6d74e48015..eedc12058d 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java @@ -179,7 +179,7 @@ public class LayerDataControlPane extends ControlPane { public void actionPerformed(ActionEvent e) { // TODO remove tree node int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val != JOptionPane.OK_OPTION) { return; } @@ -193,36 +193,32 @@ public class LayerDataControlPane extends ControlPane { } } - public void populate(NameObject nameObject) { + public void populate(LayerConfig[] layerConfigs) { // 重新添加tree节点的时候需要remove掉原来的所有子节点 ((DefaultMutableTreeNode) defaultTreeModel.getRoot()).removeAllChildren(); - if (BEAN_NAME.equals(nameObject.getName())) { - Object obj = nameObject.getObject(); - LayerConfig[] layerConfigs = null; - if (obj instanceof LayerConfig[]) { - layerConfigs = ((LayerConfig[]) obj); - } + if (layerConfigs == null) { + return; + } - int count = layerConfigs == null ? 0 : layerConfigs.length; - //将树的层次一层一层的加上去 - DefaultMutableTreeNode node4root = (DefaultMutableTreeNode) defaultTreeModel.getRoot(); - for (int i = 0; i < count; i++) { + int count = layerConfigs.length; + //将树的层次一层一层的加上去 + DefaultMutableTreeNode node4root = (DefaultMutableTreeNode) defaultTreeModel.getRoot(); + for (int i = 0; i < count; i++) { - DefaultMutableTreeNode node4add = new DefaultMutableTreeNode( + DefaultMutableTreeNode node4add = new DefaultMutableTreeNode( new NameObject(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Gradation") + (i + 1), layerConfigs[i].clone())); - node4root.add(node4add); - node4root = node4add; - } - - defaultTreeModel.reload(); - expandAll(tree, true); - tree.setSelectionRow(0); + node4root.add(node4add); + node4root = node4add; } + + defaultTreeModel.reload(); + expandAll(tree, true); + tree.setSelectionRow(0); } - public NameObject update() { + public LayerConfig[] update() { - return new NameObject(BEAN_NAME, updateLayerDatas()); + return updateLayerDatas(); } private LayerConfig[] updateLayerDatas() { diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButton.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButton.java index 335397d908..e5f2c03ff8 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButton.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButton.java @@ -61,6 +61,14 @@ public class UIButton extends JButton implements UIObserver, UITextComponent { init(); } + public UIButton(Icon icon, boolean decorate) { + this(icon); + if (!decorate) { + setContentAreaFilled(false); + setFocusPainted(false); + setBorderPainted(false); + } + } public UIButton(Icon icon) { super(icon); @@ -397,4 +405,8 @@ public class UIButton extends JButton implements UIObserver, UITextComponent { public boolean shouldResponseChangeListener() { return true; } + + + + } diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java index 624e2e8ee8..bd2e8b2afb 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIButtonGroup.java @@ -3,6 +3,8 @@ package com.fr.design.gui.ibutton; import com.fr.design.constants.UIConstants; import com.fr.design.event.GlobalNameListener; import com.fr.design.event.GlobalNameObserver; +import com.fr.design.event.UIObserver; +import com.fr.design.event.UIObserverListener; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.stable.ArrayUtils; import com.fr.stable.StringUtils; @@ -24,7 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class UIButtonGroup extends JPanel implements GlobalNameObserver { +public class UIButtonGroup extends JPanel implements GlobalNameObserver, UIObserver { private static final long serialVersionUID = 1L; private static final int TEXT_LENGTH = 3; private static final int BUTTON_SIZE = 2; @@ -37,6 +39,9 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { private boolean isToolBarComponent = false; private boolean isClick; + private UIObserverListener uiObserverListener; + private boolean autoFireStateChanged = true; + public UIButtonGroup(String[] textArray) { this(textArray, null); } @@ -72,7 +77,7 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { if (globalNameListener != null) { globalNameListener.setGlobalName(buttonGroupName); } - setSelectedWithFireChanged(index); + setSelectedIndex(index, autoFireStateChanged); } }; } @@ -108,7 +113,7 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { if (globalNameListener != null) { globalNameListener.setGlobalName(buttonGroupName); } - setSelectedWithFireChanged(index); + setSelectedIndex(index, autoFireStateChanged); } }; } @@ -175,7 +180,7 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { if (globalNameListener != null) { globalNameListener.setGlobalName(buttonGroupName); } - setSelectedWithFireChanged(index); + setSelectedIndex(index, autoFireStateChanged); } }; } @@ -253,6 +258,10 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { g2d.setClip(oldClip); } + public void setAutoFireStateChanged(boolean autoFireStateChanged) { + this.autoFireStateChanged = autoFireStateChanged; + } + /** * setSelectedItem * @@ -287,13 +296,14 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { return selectedIndex; } - protected void setSelectedWithFireChanged(int newSelectedIndex) { - selectedIndex = newSelectedIndex; - for (int i = 0; i < labelButtonList.size(); i++) { - if (i == selectedIndex) { - labelButtonList.get(i).setSelectedWithFireListener(true); - } else { - labelButtonList.get(i).setSelected(false); + public void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { + if (selectedIndex != newSelectedIndex) { + selectedIndex = newSelectedIndex; + for (int i = 0; i < labelButtonList.size(); i++) { + labelButtonList.get(i).setSelected(i == selectedIndex, false); + } + if (fireChanged) { + fireStateChanged(); } } } @@ -304,10 +314,7 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { * @param newSelectedIndex */ public void setSelectedIndex(int newSelectedIndex) { - selectedIndex = newSelectedIndex; - for (int i = 0; i < labelButtonList.size(); i++) { - labelButtonList.get(i).setSelected(i == selectedIndex); - } + setSelectedIndex(newSelectedIndex, false); } private void fireStateChanged() { @@ -322,6 +329,9 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { ((ChangeListener) listeners[i + 1]).stateChanged(e); } } + if (uiObserverListener != null) { + uiObserverListener.doChange(); + } } /** @@ -364,14 +374,24 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { return true; } + @Override + public void registerChangeListener(UIObserverListener listener) { + this.uiObserverListener = listener; + } + + @Override + public boolean shouldResponseChangeListener() { + return true; + } + /** * @param l */ public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); for (int i = 0; i < labelButtonList.size(); i++) { labelButtonList.get(i).addChangeListener(l); - listenerList.add(ChangeListener.class, l); } } @@ -379,7 +399,10 @@ public class UIButtonGroup extends JPanel implements GlobalNameObserver { * @param l */ public void removeChangeListener(ChangeListener l) { - this.listenerList.remove(ChangeListener.class, l); + listenerList.remove(ChangeListener.class, l); + for (int i = 0; i < labelButtonList.size(); i++) { + labelButtonList.get(i).removeChangeListener(l); + } } diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java index 69f5845f1d..12ca005249 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UITabGroup.java @@ -63,13 +63,8 @@ public class UITabGroup extends UIButtonGroup { } @Override - protected void setSelectedWithFireChanged(int newSelectedIndex) { - if (selectedIndex != newSelectedIndex) { - selectedIndex = newSelectedIndex; - for (int i = 0; i < labelButtonList.size(); i++) { - labelButtonList.get(i).setSelected(i == selectedIndex); - } - } + public void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { + super.setSelectedIndex(newSelectedIndex, false); tabChanged(newSelectedIndex); } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIToggleButton.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIToggleButton.java index dc380c0c94..18764e9119 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIToggleButton.java +++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIToggleButton.java @@ -142,10 +142,12 @@ public class UIToggleButton extends UIButton implements GlobalNameObserver{ } } - public void setSelectedWithFireListener(boolean isSelected) { + public void setSelected(boolean isSelected, boolean fireChanged) { if (this.isSelected != isSelected) { this.isSelected = isSelected; - fireSelectedChanged(); + if (fireChanged) { + fireSelectedChanged(); + } refresh(isSelected); } } @@ -175,7 +177,7 @@ public class UIToggleButton extends UIButton implements GlobalNameObserver{ @Override public void mouseClicked(MouseEvent e) { if (isEnabled() && !isEventBannded) { - setSelectedWithFireListener(!isSelected()); + setSelected(!isSelected(), true); } } }; diff --git a/designer-base/src/main/java/com/fr/design/gui/icheckbox/UICheckBox.java b/designer-base/src/main/java/com/fr/design/gui/icheckbox/UICheckBox.java index e294d80220..8162c7ba86 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icheckbox/UICheckBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/icheckbox/UICheckBox.java @@ -58,7 +58,7 @@ public class UICheckBox extends JCheckBox implements UIObserver, GlobalNameObser super(locText, b); setUI(new UICheckBoxUI()); initListener(); - this.markMnemonic=markMnemonic; + this.markMnemonic = markMnemonic; } public UICheckBox(String text, Icon icon) { @@ -100,6 +100,10 @@ public class UICheckBox extends JCheckBox implements UIObserver, GlobalNameObser } + public void removeChangeListener() { + uiObserverListener = null; + } + @Override public void setGlobalName(String name) { checkboxName = name; @@ -135,6 +139,15 @@ public class UICheckBox extends JCheckBox implements UIObserver, GlobalNameObser return true; } + /** + * 获取UICheckBox的UI层,可以用于设置UI + * + * @return UICheckBoxUI + */ + public UICheckBoxUI getUICheckBoxUI(){ + return new UICheckBoxUI(); + } + private class UICheckBoxUI extends MetalCheckBoxUI { @Override public synchronized void paint(Graphics g, JComponent c) { @@ -182,9 +195,9 @@ public class UICheckBox extends JCheckBox implements UIObserver, GlobalNameObser g2d.drawRoundRect(iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1, UIConstants.ARC, UIConstants.ARC); } - if (model.isSelected()) { - UIConstants.YES_ICON.paintIcon(c, g, iconRect.x + 2, iconRect.y + 2); - } + if (model.isSelected()) { + UIConstants.YES_ICON.paintIcon(c, g, iconRect.x + 2, iconRect.y + 2); + } g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); // Draw the Text diff --git a/designer-base/src/main/java/com/fr/design/gui/icombobox/ColorSchemeComboBox.java b/designer-base/src/main/java/com/fr/design/gui/icombobox/ColorSchemeComboBox.java index f8816a1844..9f9a3f13c0 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icombobox/ColorSchemeComboBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/icombobox/ColorSchemeComboBox.java @@ -8,17 +8,12 @@ import com.fr.cert.token.lang.Collections; import com.fr.chart.base.ChartConstants; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.general.GeneralUtils; import javax.swing.DefaultComboBoxModel; import javax.swing.JLabel; import javax.swing.JList; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -27,6 +22,12 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.LinearGradientPaint; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author Bjorn @@ -69,21 +70,22 @@ public class ColorSchemeComboBox extends UIComboBox { Iterator names = config.names(); if (preDefined) { - ColorInfo colorInfo = new ColorInfo(); - List list = new ArrayList<>(); - colorInfo.setColors(list); - TemplateTheme templateTheme = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTemplateTheme(); - ThemedChartSeriesColor themedChartSeriesColor = templateTheme.getChartStyle().getThemedChartSeriesColor(); - if (themedChartSeriesColor.isCombineColor()) { - colorInfo.setGradient(false); - list.addAll(templateTheme.getColorScheme().getColors()); - } else { - colorInfo.setGradient(true); - list.add(themedChartSeriesColor.getBeginColor()); - list.add(themedChartSeriesColor.getEndColor()); + if (ChartEditContext.supportTheme()) { + ColorInfo colorInfo = new ColorInfo(); + List list = new ArrayList<>(); + colorInfo.setColors(list); + TemplateTheme templateTheme = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTemplateTheme(); + ThemedChartSeriesColor themedChartSeriesColor = templateTheme.getChartStyle().getThemedChartSeriesColor(); + if (themedChartSeriesColor.isCombineColor()) { + colorInfo.setGradient(false); + list.addAll(templateTheme.getColorScheme().getColors()); + } else { + colorInfo.setGradient(true); + list.add(themedChartSeriesColor.getBeginColor()); + list.add(themedChartSeriesColor.getEndColor()); + } + colorSchemes.put(Toolkit.i18nText("Fine-Design_Chart_Follow_Theme"), colorInfo); } - colorSchemes.put(Toolkit.i18nText("Fine-Design_Chart_Follow_Theme"), colorInfo); - } else { //添加默认的方案和第一个方案 String defaultName = config.getCurrentStyle(); @@ -151,7 +153,7 @@ public class ColorSchemeComboBox extends UIComboBox { if (selectedIndex == itemCount - 2) { return SelectType.COMBINATION_COLOR; } - if (selectedIndex == 0) { + if (selectedIndex == 0 && ChartEditContext.supportTheme()) { return SelectType.DEFAULT; } return SelectType.NORMAL; diff --git a/designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java b/designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java index 8fe79d41ed..c122394476 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java @@ -248,7 +248,7 @@ public class FRTreeComboBox extends UIComboBox { private static TreePopup treePopup; - private static class FRTreeComboBoxUI extends BasicComboBoxUI implements MouseListener{ + protected static class FRTreeComboBoxUI extends BasicComboBoxUI implements MouseListener{ private boolean isRollover = false; public FRTreeComboBoxUI() { @@ -535,7 +535,7 @@ public class FRTreeComboBox extends UIComboBox { public class FrTreeSearchComboBoxEditor extends UIComboBoxEditor implements DocumentListener { private volatile boolean setting = false; private FRTreeComboBox comboBox; - private Object item; + protected Object item; public FrTreeSearchComboBoxEditor(FRTreeComboBox comboBox) { super(); diff --git a/designer-base/src/main/java/com/fr/design/gui/icombobox/SearchPreTaskTreeComboBox.java b/designer-base/src/main/java/com/fr/design/gui/icombobox/SearchPreTaskTreeComboBox.java deleted file mode 100644 index 2d936d8964..0000000000 --- a/designer-base/src/main/java/com/fr/design/gui/icombobox/SearchPreTaskTreeComboBox.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.fr.design.gui.icombobox; - -import com.fr.log.FineLoggerFactory; - -import javax.swing.JTree; -import javax.swing.SwingWorker; -import javax.swing.tree.TreeCellRenderer; -import java.util.concurrent.FutureTask; - -/** - * 模糊搜索前需执行完前置任务的TreeComboBox - * @author Lucian.Chen - * @version 10.0 - * Created by Lucian.Chen on 2021/4/14 - */ -public class SearchPreTaskTreeComboBox extends FRTreeComboBox { - - /** - * 模糊搜索前任务 - */ - private FutureTask preSearchTask; - - public SearchPreTaskTreeComboBox(JTree tree, TreeCellRenderer renderer, boolean editable) { - super(tree, renderer, editable); - } - - public FutureTask getPreSearchTask() { - return preSearchTask; - } - - public void setPreSearchTask(FutureTask preSearchTask) { - this.preSearchTask = preSearchTask; - } - - protected UIComboBoxEditor createEditor() { - return new SearchPreTaskComboBoxEditor(this); - } - - private class SearchPreTaskComboBoxEditor extends FrTreeSearchComboBoxEditor { - - public SearchPreTaskComboBoxEditor(FRTreeComboBox comboBox) { - super(comboBox); - } - - protected void changeHandler() { - if (isSetting()) { - return; - } - setPopupVisible(true); - new SwingWorker() { - @Override - protected Void doInBackground() { - FutureTask task = getPreSearchTask(); - try { - // 确保模糊搜索前任务执行完成后,再进行模糊搜索 - if (task != null) { - task.get(); - } - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - if (task != null) { - // 任务执行后置空,否则会被别的操作重复触发 - setPreSearchTask(null); - } - return null; - } - - @Override - protected void done() { - // 模糊搜索 - search(); - } - }.execute(); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/gui/icombobox/TableSearchTreeComboBox.java b/designer-base/src/main/java/com/fr/design/gui/icombobox/TableSearchTreeComboBox.java new file mode 100644 index 0000000000..916cd3cf6f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/icombobox/TableSearchTreeComboBox.java @@ -0,0 +1,236 @@ +package com.fr.design.gui.icombobox; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.data.core.DataCoreUtils; +import com.fr.data.core.db.TableProcedure; +import com.fr.data.impl.Connection; +import com.fr.design.DesignerEnvManager; +import com.fr.design.data.datapane.ChoosePane; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.mainframe.DesignerContext; +import com.fr.log.FineLoggerFactory; +import com.fr.module.ModuleContext; +import com.fr.stable.ArrayUtils; +import com.fr.stable.Filter; +import com.fr.stable.StringUtils; + +import javax.swing.JOptionPane; +import javax.swing.JTree; +import javax.swing.SwingWorker; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.util.Enumeration; +import java.util.concurrent.ExecutorService; + +/** + * 实现模糊搜索表名的FRTreeComboBox + * FRTreeComboBox:搜索后滚动到首个匹配节点 + * SearchFRTreeComboBox:显示所有匹配的节点 + * + * @author Lucian.Chen + * @version 10.0 + * Created by Lucian.Chen on 2021/4/14 + */ +public class TableSearchTreeComboBox extends FRTreeComboBox { + // 持有父容器,需要实时获取其他组件值 + private final ChoosePane parent; + /** + * 保证模糊搜索的原子性操作 + */ + private final ExecutorService singleExecutor = ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory("TableSearchTreeComboBox")); + + public TableSearchTreeComboBox(ChoosePane parent, JTree tree, TreeCellRenderer renderer) { + super(tree, renderer); + this.parent = parent; + initPopupListener(); + } + + protected UIComboBoxEditor createEditor() { + return new TableSearchComboBoxEditor(this); + } + + @Override + protected String pathToString(TreePath path) { + Object obj = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject(); + if (obj instanceof TableProcedure) { + return ((TableProcedure) obj).getName(); + } + return super.pathToString(path); + } + + @Override + public void setSelectedItemString(String _name) { + super.setSelectedItemString(_name); + // 会因为连续两次选中的值一致,导致未触发编辑框联动 + this.getEditor().setItem(_name); + } + + /** + * 执行模糊搜索 + */ + private void searchExecute() { + UIComboBoxEditor searchEditor = (UIComboBoxEditor) this.getEditor(); + String searchText = (String) searchEditor.getItem(); + singleExecutor.execute(new SwingWorker() { + @Override + protected Void doInBackground() { + processTableDataNames( + parent.getDSName(), + parent.getConnection(), + parent.getSchema(), + createFilter(searchText)); + return null; + } + + @Override + protected void done() { + expandTree(); + // 输入框获取焦点 + searchEditor.getEditorComponent().requestFocus(); + } + }); + } + + private TableNameFilter createFilter(String text) { + return StringUtils.isEmpty(text) ? EMPTY_FILTER : new TableNameFilter(text); + } + + /** + * 查询数据库表,并构建节点目录 + * + * @param databaseName 数据库名 + * @param connection 数据连接 + * @param schema 模式 + * @param filter 模糊搜索过滤器 + */ + private void processTableDataNames(String databaseName, Connection connection, String schema, TableNameFilter filter) { + if (tree == null) { + return; + } + DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot(); + rootTreeNode.removeAllChildren(); + + if (connection == null) { + return; + } + try { + schema = StringUtils.isEmpty(schema) ? null : schema; + TableProcedure[] sqlTableArray = DataCoreUtils.getTables(connection, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); + if (ArrayUtils.isNotEmpty(sqlTableArray)) { + ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table")); + rootTreeNode.add(tableTreeNode); + addArrayNode(tableTreeNode, sqlTableArray, filter); + } + TableProcedure[] sqlViewArray = DataCoreUtils.getTables(connection, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace()); + if (ArrayUtils.isNotEmpty(sqlViewArray)) { + ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View")); + rootTreeNode.add(viewTreeNode); + addArrayNode(viewTreeNode, sqlViewArray, filter); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE); + } + } + + private void addArrayNode(ExpandMutableTreeNode rootNode, TableProcedure[] sqlArray, TableNameFilter filter) { + if (sqlArray != null) { + for (TableProcedure procedure : sqlArray) { + if (filter.accept(procedure)) { + ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(procedure); + rootNode.add(viewChildTreeNode); + } + } + } + } + + /** + * 展开节点 + */ + private void expandTree() { + ((DefaultTreeModel) tree.getModel()).reload(); + // daniel 展开所有tree + TreeNode root = (TreeNode) tree.getModel().getRoot(); + TreePath parent = new TreePath(root); + TreeNode node = (TreeNode) parent.getLastPathComponent(); + for (Enumeration e = node.children(); e.hasMoreElements(); ) { + TreeNode n = (TreeNode) e.nextElement(); + TreePath path = parent.pathByAddingChild(n); + tree.expandPath(path); + } + } + + /** + * 表名模糊搜索实现 + */ + private static class TableNameFilter implements Filter { + private String searchFilter; + + public TableNameFilter() { + } + + public TableNameFilter(String searchFilter) { + this.searchFilter = searchFilter.toLowerCase().trim(); + } + + // 表名匹配 + @Override + public boolean accept(TableProcedure procedure) { + return procedure.getName().toLowerCase().contains(searchFilter); + } + } + + private static final TableNameFilter EMPTY_FILTER = new TableNameFilter() { + public boolean accept(TableProcedure procedure) { + return true; + } + }; + + private void initPopupListener() { + // 点击下拉时触发模糊搜索 + this.addPopupMenuListener(new PopupMenuListener() { + + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + searchExecute(); + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + + } + }); + } + + /** + * 重写输入框编辑器,实现输入框模糊搜索逻辑 + */ + private class TableSearchComboBoxEditor extends FrTreeSearchComboBoxEditor { + + public TableSearchComboBoxEditor(FRTreeComboBox comboBox) { + super(comboBox); + } + + @Override + protected void changeHandler() { + if (isSetting()) { + return; + } + setPopupVisible(true); + this.item = textField.getText(); + searchExecute(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java b/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java index 3eed2d799d..80e7e88bbf 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java +++ b/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java @@ -37,6 +37,10 @@ public class UICheckListPopup extends UIPopupMenu { private Color mouseEnteredColor = UIConstants.CHECKBOX_HOVER_SELECTED; private int maxDisplayNumber = 8; private boolean supportSelectAll = true; + /** + * 每项数据都有可能因为宽度设置问题,而被省略显示,这个常量代表,是否要给每项数据添加一个值等于其原值的Tooltips + */ + private boolean labelNeedToolTips = false; public static final String COMMIT_EVENT = "commit"; private static final String SELECT_ALL = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Choose_All"); @@ -47,9 +51,14 @@ public class UICheckListPopup extends UIPopupMenu { } public UICheckListPopup(Object[] value, boolean supportSelectAll) { + this(value, supportSelectAll, false); + } + + public UICheckListPopup(Object[] values, boolean supportSelectAll, boolean labelNeedToolTips) { super(); - values = value; + this.values = values; this.supportSelectAll = supportSelectAll; + this.labelNeedToolTips = labelNeedToolTips; initComponent(); } @@ -62,6 +71,11 @@ public class UICheckListPopup extends UIPopupMenu { addCheckboxValues(); } + public UICheckListPopup setLabelNeedToolTips(boolean labelNeedToolTips) { + this.labelNeedToolTips = labelNeedToolTips; + return this; + } + private void initComponent() { checkboxPane = new JPanel(); checkboxPane.setLayout(new GridLayout(checkBoxList.size(), 1, 0, 0)); @@ -111,6 +125,10 @@ public class UICheckListPopup extends UIPopupMenu { checkPane.setBackground(Color.WHITE); checkPane.add(temp); checkPane.add(label); + if (labelNeedToolTips) { + // 设置每项Label的tooltips为其省略前的内容 + label.setToolTipText(checkValue.toString()); + } addMouseListener(temp, label); checkBoxList.add(temp); diff --git a/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java b/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java index 4dcea229ce..ce0a9f869e 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java @@ -17,9 +17,6 @@ import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -32,6 +29,9 @@ import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * 设计器下拉复选框组件 @@ -52,7 +52,7 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam //选中的值之间显示的分隔符 private String valueSperator; private static final String DEFAULT_VALUE_SPERATOR = ","; - private static final String OMIT_TEXT = "..."; + protected static final String OMIT_TEXT = "..."; private UIObserverListener uiObserverListener; private GlobalNameListener globalNameListener = null; @@ -60,6 +60,7 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam private boolean showOmitText = true; private boolean supportSelectAll = true; + private String placeHolder = StringUtils.EMPTY; public UIComboCheckBox(Object[] value) { this(value, DEFAULT_VALUE_SPERATOR, true); @@ -112,14 +113,42 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam } private void initComponent() { - this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); this.popup = new UICheckListPopup(values, supportSelectAll); this.popup.addActionListener(new PopupAction()); this.editor = createEditor(); this.arrowButton = createArrowButton(); + setLayoutAndAddComponents(); + setText(); + } + + /** + * 设置布局管理器并且添加组件 + * 默认使用FlowLayout + */ + protected void setLayoutAndAddComponents() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); this.add(editor); this.add(arrowButton); - setText(); + } + + public UICheckListPopup getPopup() { + return popup; + } + + public UITextField getEditor() { + return editor; + } + + public String getPlaceHolder() { + return placeHolder; + } + + public void setPlaceHolder(String placeHolder) { + this.placeHolder = placeHolder; + } + + public UIButton getArrowButton() { + return arrowButton; } private UIButton createArrowButton() { @@ -171,6 +200,9 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { attributeChange(); + if (uiObserverListener != null) { + uiObserverListener.doChange(); + } } @Override @@ -270,6 +302,28 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam String text = builder.length() > 0 ? builder.substring(0, builder.length() - 1) : StringUtils.EMPTY; //计算加省略号后的文本 editor.setText(this.showOmitText ? omitEditorText(editor, text) : text); + // 添加placeHolder + setEditorPlaceHolder(editor); + // tooltips显示原值 + setEditorToolTipText(editor, text); + } + + /** + * 为为添加placeholder + * @param editor + */ + protected void setEditorPlaceHolder(UITextField editor) { + // 默认空实现 + } + + /** + * 为UITextField设置悬浮提示值 + * + * @param editor + * @param text + */ + protected void setEditorToolTipText(JComponent editor, String text) { + // 默认不做设置 } /** @@ -279,7 +333,7 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam * @param text * @return 省略后的文字 */ - private static String omitEditorText(UITextField textEditor, String text) { + protected String omitEditorText(UITextField textEditor, String text) { char[] omitChars = OMIT_TEXT.toCharArray(); //获取字体的大小 FontMetrics fontMetrics = textEditor.getFontMetrics(textEditor.getFont()); diff --git a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java index 125cd3aa16..f00fbee498 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java +++ b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java @@ -327,7 +327,7 @@ public class UIEastResizableContainer extends JPanel { button = UIConstants.DRAG_RIGHT_PRESS; } } - g.drawImage(button, 18, 7, 5, 10, null); + g.drawImage(button, 18, 7, this); } } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIModeControlContainer.java b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIModeControlContainer.java index 1837711cd1..627baf6b92 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIModeControlContainer.java +++ b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIModeControlContainer.java @@ -282,7 +282,7 @@ public class UIModeControlContainer extends JLayeredPane { setLayout(new FlowLayout(FlowLayout.CENTER, 10, -3)); setBackground(UIConstants.NORMAL_BACKGROUND); add(new UILabel("" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Parameter_Panel") + "")); - UIButton viewButton = new UIButton(UIConstants.VIEW_NORMAL_ICON, UIConstants.VIEW_PRESSED_ICON, UIConstants.VIEW_PRESSED_ICON) { + UIButton viewButton = new UIButton(UIConstants.VIEW_NORMAL_ICON, UIConstants.VIEW_NORMAL_ICON, UIConstants.VIEW_NORMAL_ICON) { @Override public Dimension getPreferredSize() { return new Dimension(32, 32); diff --git a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java index f3f45768f3..8e562cc3ce 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java +++ b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java @@ -3,6 +3,7 @@ package com.fr.design.gui.icontainer; import com.fr.base.vcs.DesignerMode; import com.fr.design.constants.UIConstants; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.SvgPaintUtils; import com.fr.stable.Constants; import com.fr.design.utils.gui.GUICoreUtils; @@ -406,13 +407,15 @@ public class UIResizableContainer extends JPanel { @Override public void paint(Graphics g) { + Image upButton = (upModel == UIConstants.MODEL_NORMAL ? UIConstants.DRAG_UP_NORMAL : UIConstants.DRAG_UP_PRESS); Image downButton = (downModel == UIConstants.MODEL_NORMAL ? UIConstants.DRAG_DOWN_NORMAL : UIConstants.DRAG_DOWN_PRESS); - g.drawImage(UIConstants.DRAG_BAR_LIGHT, 0, 0, getWidth(), getHeight(), null); - g.drawImage(UIConstants.DRAG_LINE, (getWidth() - toolPaneHeight) / 2, 3, toolPaneHeight, 5, null); - g.drawImage(upButton, ARROW_MARGIN, 3, toolPaneHeight, 5, null); - g.drawImage(downButton, getWidth() - toolPaneHeight - ARROW_MARGIN, 3, toolPaneHeight, 5, null); + SvgPaintUtils.beforePaint((Graphics2D) g); + g.drawImage(UIConstants.DRAG_LINE, (getWidth() - toolPaneHeight) / 2, 3, null); + g.drawImage(upButton, ARROW_MARGIN, 1, null); + g.drawImage(downButton, getWidth() - toolPaneHeight - ARROW_MARGIN, 1, null); + SvgPaintUtils.afterPaint((Graphics2D) g); } } @@ -509,7 +512,7 @@ public class UIResizableContainer extends JPanel { button = UIConstants.DRAG_LEFT_PRESS; } } - g.drawImage(button, 3, ARROW_MARGIN_VERTICAL, 5, toolPaneHeight, null); + g.drawImage(button, -1, ARROW_MARGIN_VERTICAL, this); } else { g.drawImage(UIConstants.DRAG_BAR_LIGHT, 0, 0, toolPaneHeight, getHeight(), null); if (containerWidth == toolPaneHeight) { @@ -525,7 +528,7 @@ public class UIResizableContainer extends JPanel { button = UIConstants.DRAG_RIGHT_PRESS; } } - g.drawImage(button, 2, ARROW_MARGIN_VERTICAL, 5, toolPaneHeight, null); + g.drawImage(button, 2, ARROW_MARGIN_VERTICAL, this); } if (isLeftRightDragEnabled) { g.drawImage(UIConstants.DRAG_DOT_VERTICAL, 2, getHeight() / 2, 5, toolPaneHeight, null); diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/ExtensionFilter.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/ExtensionFilter.java new file mode 100644 index 0000000000..9ec582f693 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/ExtensionFilter.java @@ -0,0 +1,25 @@ +package com.fr.design.gui.ifilechooser; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/29 + */ +public class ExtensionFilter { + + private final String des; + private final String[] extensions; + + public ExtensionFilter(String des, String... extensions) { + this.des = des; + this.extensions = extensions; + } + + public String getDes() { + return des; + } + + public String[] getExtensions() { + return extensions; + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserArgs.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserArgs.java new file mode 100644 index 0000000000..b011e5b350 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserArgs.java @@ -0,0 +1,109 @@ +package com.fr.design.gui.ifilechooser; + +/** + * 文件选择器可设置的参数集合 + * + * @author hades + * @version 10.0 + * Created by hades on 2021/12/21 + */ +public class FileChooserArgs { + + private final FileSelectionMode fileSelectionMode; + private final String filterDes; + private final String[] extensions; + private final String selectedPath; + private final ExtensionFilter[] filters; + private final String tipText; + private final boolean multiSelectionEnabled; + + public static Builder newBuilder() { + return new Builder(); + } + + private FileChooserArgs(Builder builder) { + this.fileSelectionMode = builder.fileSelectionMode; + this.filterDes = builder.filterDes; + this.extensions = builder.extensions; + this.selectedPath = builder.selectedPath; + this.filters = builder.filters; + this.tipText = builder.tipText; + this.multiSelectionEnabled = builder.multiSelectionEnabled; + } + + public FileSelectionMode getFileSelectionMode() { + return fileSelectionMode; + } + + public String getFilterDes() { + return filterDes; + } + + public String[] getExtensions() { + return extensions; + } + + public String getSelectedPath() { + return selectedPath; + } + + public ExtensionFilter[] getFilters() { + return filters; + } + + public String getTipText() { + return tipText; + } + + public boolean isMultiSelectionEnabled() { + return multiSelectionEnabled; + } + + public static class Builder { + + private FileSelectionMode fileSelectionMode; + private String filterDes; + private String[] extensions; + private String selectedPath; + private ExtensionFilter[] filters = new ExtensionFilter[0]; + private String tipText; + private boolean multiSelectionEnabled; + + public Builder setFileSelectionMode(FileSelectionMode fileSelectionMode) { + this.fileSelectionMode = fileSelectionMode; + return this; + } + + public Builder setFilter(String filterDes, String... extensions) { + this.filterDes = filterDes; + this.extensions = extensions; + return this; + } + + public Builder setSelectedPath(String selectedPath) { + this.selectedPath = selectedPath; + return this; + } + + public Builder setFilters(ExtensionFilter[] filters) { + this.filters = filters; + return this; + } + + public Builder setTipText(String tipText) { + this.tipText = tipText; + return this; + } + + public Builder setMultiSelectionEnabled(boolean multiSelectionEnabled) { + this.multiSelectionEnabled = multiSelectionEnabled; + return this; + } + + public FileChooserArgs build() { + return new FileChooserArgs(this); + } + } + + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserFactory.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserFactory.java new file mode 100644 index 0000000000..36a53c8dc9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserFactory.java @@ -0,0 +1,44 @@ +package com.fr.design.gui.ifilechooser; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.os.impl.SupportOSImpl; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/21 + */ +public class FileChooserFactory { + + public static FileChooserProvider createFileChooser(FileChooserArgs fileChooserArgs) { + if (SupportOSImpl.OLD_STYLE_CHOOSER.support()) { + return new SwingFileChooser.Builder(). + setFileSelectionMode(fileChooserArgs.getFileSelectionMode()). + setFileFilter(fileChooserArgs.getFilterDes(), fileChooserArgs.getExtensions()). + setSelectedFile(fileChooserArgs.getSelectedPath()). + setMultiSelectionEnabled(fileChooserArgs.isMultiSelectionEnabled()). + setTipText(fileChooserArgs.getTipText()). + setFileFilter(fileChooserArgs.getFilters()).build(); + } else { + return new JavaFxNativeFileChooser.Builder(). + fileSelectionMode(fileChooserArgs.getFileSelectionMode()). + filter(fileChooserArgs.getFilterDes(), fileChooserArgs.getExtensions()). + currentDirectory(fileChooserArgs.getSelectedPath()). + title(fileChooserArgs.getTipText()). + filters(fileChooserArgs.getFilters()).build(); + } + } + + public static FileChooserProvider createImageFileChooser() { + if (SupportOSImpl.OLD_STYLE_CHOOSER.support()) { + return new SwingImageFileChooser(); + } else { + return new JavaFxNativeFileChooser.Builder(). + fileSelectionMode(FileSelectionMode.FILE). + title(Toolkit.i18nText("Fine-Design_Basic_Open")). + filter(Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files"), "*.jpg", "*.gif", "*.png", "*.bmp"). + build(); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java index aa95fe27bd..a5d7e97303 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java @@ -9,4 +9,17 @@ public interface FileChooserProvider { File getSelectedFile(); int showDialog(Component parent); + + + default int showOpenDialog(Component parent, String approveButtonText) { + return -1; + } + + default void setMultiSelectionEnabled(boolean multiple) { + + } + + default void setCurrentDirectory(File file) { + + } } diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java index 452deb5c8d..fb6a7e88be 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java @@ -4,6 +4,8 @@ package com.fr.design.gui.ifilechooser; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StringUtils; import com.sun.javafx.application.PlatformImpl; import javafx.application.Platform; import javafx.scene.Scene; @@ -163,6 +165,8 @@ public class JavaFxNativeFileChooser implements FileChooserProvider { try { latch.await(); } catch (InterruptedException ignore) { + } finally { + setShowDialogState(false); } return selectedFiles.length > 0 ? JFileChooser.APPROVE_OPTION : JFileChooser.CANCEL_OPTION; } @@ -171,10 +175,20 @@ public class JavaFxNativeFileChooser implements FileChooserProvider { this.fileSelectionMode = fileSelectionMode; } + @Override public void setCurrentDirectory(File currentDirectory) { this.currentDirectory = currentDirectory; } + @Override + public void setMultiSelectionEnabled(boolean multiple) { + this.setSelectionMode(multiple ? FileSelectionMode.MULTIPLE_FILE : FileSelectionMode.FILE); + } + + @Override + public int showOpenDialog(Component parent, String approveButtonText) { + return this.showDialog(parent); + } public static class Builder { private FileSelectionMode fileSelectionMode = FileSelectionMode.FILE; @@ -183,17 +197,32 @@ public class JavaFxNativeFileChooser implements FileChooserProvider { private File currentDirectory; public Builder fileSelectionMode(FileSelectionMode fileSelectionMode) { - this.fileSelectionMode = fileSelectionMode; + if (fileSelectionMode != null) { + this.fileSelectionMode = fileSelectionMode; + } return this; } public Builder title(String title) { - this.title = title; + if (StringUtils.isNotEmpty(title)) { + this.title = title; + } return this; } public Builder filters(FileChooser.ExtensionFilter[] filters) { - this.filters = filters; + if (filters != null) { + this.filters = filters; + } + return this; + } + + public Builder filters(ExtensionFilter[] filters) { + if (filters != null) { + for (ExtensionFilter filter : filters) { + this.filters = ArrayUtils.add(this.filters, new FileChooser.ExtensionFilter(filter.getDes(), filter.getExtensions())); + } + } return this; } diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingFileChooser.java new file mode 100644 index 0000000000..47abaa8b67 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingFileChooser.java @@ -0,0 +1,134 @@ +package com.fr.design.gui.ifilechooser; + +import com.fr.common.annotations.Negative; +import com.fr.design.upm.UpmUtils; +import com.fr.stable.ArrayUtils; +import com.fr.stable.StringUtils; +import java.awt.Component; +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/21 + */ +@Negative(until = "2022-6-1") +class SwingFileChooser implements FileChooserProvider { + + private final JFileChooser fileChooser; + private final Builder builder; + + private SwingFileChooser(Builder builder) { + fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(builder.fileSelectionMode); + fileChooser.setFileFilter(builder.fileFilter); + fileChooser.setSelectedFile(builder.selectedFile); + fileChooser.setMultiSelectionEnabled(builder.multiSelectionEnabled); + this.builder = builder; + } + + @Override + public File[] getSelectedFiles() { + if (ArrayUtils.isNotEmpty(fileChooser.getSelectedFiles())) { + return fileChooser.getSelectedFiles(); + } else { + return new File[]{fileChooser.getSelectedFile()}; + } + } + + @Override + public File getSelectedFile() { + return fileChooser.getSelectedFile(); + } + + @Override + public int showDialog(Component parent) { + if (StringUtils.isEmpty(builder.tipText)) { + return fileChooser.showOpenDialog(parent); + } else { + return fileChooser.showDialog(parent, builder.tipText); + } + } + + @Override + public int showOpenDialog(Component parent, String approveButtonText) { + return fileChooser.showDialog(parent, approveButtonText); + } + + @Override + public void setCurrentDirectory(File file) { + fileChooser.setCurrentDirectory(file); + } + + @Override + public void setMultiSelectionEnabled(boolean multiple) { + fileChooser.setMultiSelectionEnabled(multiple); + } + + /** + * 和一般builder不同的是 setXXX还做参数转换逻辑 + */ + public static class Builder { + + private int fileSelectionMode = JFileChooser.FILES_ONLY; + private FileFilter fileFilter; + private File selectedFile; + private boolean multiSelectionEnabled; + private String tipText; + + public Builder setFileSelectionMode(FileSelectionMode fileSelectionMode) { + if (FileSelectionMode.DIR.equals(fileSelectionMode)) { + this.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY; + } else if (FileSelectionMode.FILE.equals(fileSelectionMode)) { + this.fileSelectionMode = JFileChooser.FILES_ONLY; + } else if (FileSelectionMode.MULTIPLE_FILE.equals(fileSelectionMode)) { + this.fileSelectionMode = JFileChooser.FILES_AND_DIRECTORIES; + } + return this; + } + + public Builder setFileFilter(String des, String... extension) { + if (StringUtils.isNotEmpty(des) && ArrayUtils.isNotEmpty(extension)) { + this.fileFilter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(extension)); + } + return this; + } + + public Builder setFileFilter(ExtensionFilter[] extensionFilters) { + StringBuilder desBuilder = new StringBuilder(); + String[] extensions = new String[0]; + for (ExtensionFilter extensionFilter : extensionFilters) { + desBuilder.append(extensionFilter.getDes()).append(" "); + extensions = ArrayUtils.addAll(extensions, UpmUtils.findMatchedExtension(extensionFilter.getExtensions())); + } + if (ArrayUtils.isNotEmpty(extensionFilters)) { + this.fileFilter = new FileNameExtensionFilter(desBuilder.toString().trim(), extensions); + } + return this; + } + + public Builder setSelectedFile(String selectedPath) { + if (StringUtils.isNotEmpty(selectedPath)) { + this.selectedFile = new File(selectedPath); + } + return this; + } + + public Builder setMultiSelectionEnabled(boolean multiSelectionEnabled) { + this.multiSelectionEnabled = multiSelectionEnabled; + return this; + } + + public Builder setTipText(String tipText) { + this.tipText = tipText; + return this; + } + + public SwingFileChooser build() { + return new SwingFileChooser(this); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingImageFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingImageFileChooser.java new file mode 100644 index 0000000000..3c0c6c1afc --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingImageFileChooser.java @@ -0,0 +1,276 @@ +package com.fr.design.gui.ifilechooser; + +import com.fr.base.BaseUtils; +import com.fr.common.annotations.Negative; +import com.fr.design.DesignerEnvManager; +import com.fr.design.style.ChooseFileView; +import com.fr.design.style.background.image.ExpandFileChooser; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.Enumeration; +import java.util.Hashtable; +import javax.swing.filechooser.FileFilter; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/30 + */ +@Negative(until = "2022-6-1") +class SwingImageFileChooser extends ExpandFileChooser implements FileChooserProvider { + + public SwingImageFileChooser() { + super(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Compress"),com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open")); + ExampleFileFilter bothFilter = new ExampleFileFilter( + new String[]{"jpg", "gif", "png", "bmp"}, + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files")); + bothFilter.setExtensionListInDescription(true); + this.addChoosableFileFilter(bothFilter); + this.setAcceptAllFileFilterUsed(false); + + // Create Custom FileView + ChooseFileView fileView = new ChooseFileView(); + fileView.putIcon("jpg", BaseUtils.readIcon("/com/fr/base/images/dialog/file/jpgFile.gif")); + fileView.putIcon("gif", BaseUtils.readIcon("/com/fr/base/images/dialog/file/gifFile.gif")); + fileView.putIcon("png", BaseUtils.readIcon("/com/fr/base/images/dialog/file/pngFile.png")); + fileView.putIcon("bmp", BaseUtils.readIcon("/com/fr/base/images/dialog/file/bmpFile.gif")); + + this.setFileView(fileView); + } + + @Override + public int showDialog(Component parent, String approveButtonText) { + return super.showDialog(parent, approveButtonText); + } + + @Override + public ActionListener checkAction() { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignerEnvManager.getEnvManager().setImageCompress(isCheckSelected()); + DesignerEnvManager.getEnvManager().saveXMLFile(); + } + }; + + } + + @Override + public int showDialog(Component parent) { + return showOpenDialog(parent); + } + + /** + * A convenience implementation of FileFilter that filters out + * all files except for those type extensions that it knows about. + *

D:\finereport\develop\code\test\TestCase\WEB-INF\reportlets\TestCase\01903.cpt + *

+ * Extensions are of the type ".foo", which is typically found on + * Windows and Unix boxes, but not on Macinthosh. Case is ignored. + *

+ * Example - create a new filter that filerts out all files + * but gif and jpg image files: + *

+ * JFileChooser chooser = new JFileChooser(); + * ExampleFileFilter filter = new ExampleFileFilter( + * new String{"gif", "jpg"}, "JPEG & GIF Images") + * chooser.addChoosableFileFilter(filter); + * chooser.showOpenDialog(this); + * + * @author Jeff Dinkins + * @version 1.12 12/03/01 + */ + class ExampleFileFilter extends FileFilter { + private Hashtable filters = null; + private String description = null; + private String fullDescription = null; + private boolean useExtensionsInDescription = true; + + /** + * Creates a file filter. If no filters are added, then all + * files are accepted. + * + * @see #addExtension + */ + public ExampleFileFilter() { + this.filters = new Hashtable(); + } + + /** + * Creates a file filter that accepts files with the given extension. + * Example: new ExampleFileFilter("jpg"); + * + * @see #addExtension + */ + public ExampleFileFilter(String extension) { + this(extension, null); + } + + /** + * Creates a file filter that accepts the given file type. + * Example: new ExampleFileFilter("jpg", "JPEG Image Images"); + *

+ * Note that the "." before the extension is not needed. If + * provided, it will be ignored. + * + * @see #addExtension + */ + public ExampleFileFilter(String extension, String description) { + this(); + if (extension != null) addExtension(extension); + if (description != null) setDescription(description); + } + + /** + * Creates a file filter from the given string array. + * Example: new ExampleFileFilter(String {"gif", "jpg"}); + *

+ * Note that the "." before the extension is not needed adn + * will be ignored. + * + * @see #addExtension + */ + public ExampleFileFilter(String[] filters) { + this(filters, null); + } + + /** + * Creates a file filter from the given string array and description. + * Example: new ExampleFileFilter(String {"gif", "jpg"}, "Gif and JPG Images"); + *

+ * Note that the "." before the extension is not needed and will be ignored. + * + * @see #addExtension + */ + public ExampleFileFilter(String[] filters, String description) { + this(); + for (int i = 0; i < filters.length; i++) { + // add filters one by one + addExtension(filters[i]); + } + if (description != null) setDescription(description); + } + + /** + * Return true if this file should be shown in the directory pane, + * false if it shouldn't. + *

+ * Files that begin with "." are ignored. + * + * @see #getExtension + */ + @Override + public boolean accept(File f) { + if (f != null) { + if (f.isDirectory()) { + return true; + } + String extension = getExtension(f); + if (extension != null && filters.get(getExtension(f)) != null) { + return true; + } + } + return false; + } + + /** + * Return the extension portion of the file's name . + * + * @see #getExtension + * @see FileFilter#accept + */ + public String getExtension(File f) { + if (f != null) { + String filename = f.getName(); + int i = filename.lastIndexOf('.'); + if (i > 0 && i < filename.length() - 1) { + return filename.substring(i + 1).toLowerCase(); + } + } + return null; + } + + /** + * Adds a filetype "dot" extension to filter against. + *

+ * For example: the following code will create a filter that filters + * out all files except those that end in ".jpg" and ".tif": + *

+ * ExampleFileFilter filter = new ExampleFileFilter(); + * filter.addExtension("jpg"); + * filter.addExtension("tif"); + *

+ * Note that the "." before the extension is not needed and will be ignored. + */ + public void addExtension(String extension) { + if (filters == null) { + filters = new Hashtable(5); + } + filters.put(extension.toLowerCase(), this); + fullDescription = null; + } + + + /** + * Returns the human readable description of this filter. For + * example: "JPEG and GIF Image Files (*.jpg, *.gif)" + * + * @see FileFilter#getDescription + */ + @Override + public String getDescription() { + if (fullDescription == null) { + if (description == null || isExtensionListInDescription()) { + fullDescription = description == null ? "(" : description + " ("; + // build the description from the extension list + Enumeration extensions = filters.keys(); + if (extensions != null) { + fullDescription += "." + extensions.nextElement(); + while (extensions.hasMoreElements()) { + fullDescription += ", ." + extensions.nextElement(); + } + } + fullDescription += ")"; + } else { + fullDescription = description; + } + } + return fullDescription; + } + + /** + * Sets the human readable description of this filter. For + * example: filter.setDescription("Gif and JPG Images"); + */ + public void setDescription(String description) { + this.description = description; + fullDescription = null; + } + + /** + * Determines whether the extension list (.jpg, .gif, etc) should + * show up in the human readable description. + *

+ * Only relevent if a description was provided in the constructor + * or using setDescription(); + */ + public void setExtensionListInDescription(boolean b) { + useExtensionsInDescription = b; + fullDescription = null; + } + + /** + * Returns whether the extension list (.jpg, .gif, etc) should + * show up in the human readable description. + *

+ * Only relevent if a description was provided in the constructor + * or using setDescription(); + */ + public boolean isExtensionListInDescription() { + return useExtensionsInDescription; + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java b/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java index ebccd24f45..c98455a58f 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java +++ b/designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java @@ -13,11 +13,23 @@ import java.awt.event.MouseEvent; */ public class ActionLabel extends UILabel { private ActionListener actionListener; + private Color color; + // 文字是否有下划线 + private boolean drawUnderLine = true; public ActionLabel(String text) { - super(text); + this(text, Color.blue); + } - this.setForeground(Color.blue); + public ActionLabel(String text, boolean drawUnderLine) { + this(text, Color.blue); + this.drawUnderLine = drawUnderLine; + } + + public ActionLabel(String text, Color color) { + super(text); + this.color = color; + this.setForeground(color); this.addMouseListener(mouseInputAdapter); this.addMouseMotionListener(mouseInputAdapter); } @@ -33,8 +45,10 @@ public class ActionLabel extends UILabel { public void paintComponent(Graphics _gfx) { super.paintComponent(_gfx); - _gfx.setColor(Color.blue); - _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); + _gfx.setColor(this.color); + if (drawUnderLine) { + _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); + } } private MouseInputAdapter mouseInputAdapter = new MouseInputAdapter() { @@ -90,4 +104,12 @@ public class ActionLabel extends UILabel { } } }; -} \ No newline at end of file + + public boolean isDrawUnderLine() { + return drawUnderLine; + } + + public void setDrawUnderLine(boolean drawUnderLine) { + this.drawUnderLine = drawUnderLine; + } +} 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/ilist/CheckBoxListWithPartialSelect.java b/designer-base/src/main/java/com/fr/design/gui/ilist/CheckBoxListWithPartialSelect.java new file mode 100644 index 0000000000..fe1c6bda89 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/ilist/CheckBoxListWithPartialSelect.java @@ -0,0 +1,177 @@ +package com.fr.design.gui.ilist; + +import com.fr.design.event.StateChangeListener; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.itree.checkboxtree.TristateCheckBox; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.AbstractListModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.List; + +/** + * 支持全选、全不选、半选的CheckBoxList面板 + * @author Yvan + */ +public class CheckBoxListWithPartialSelect extends JPanel { + + private UICheckBox[] dataCheckBoxes; + + private TristateCheckBox chooseAllCheckBox; + + private UIList dataList; + + public CheckBoxListWithPartialSelect (Object[] data) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + init(data); + this.add(chooseAllCheckBox, BorderLayout.NORTH); + this.add(dataList, BorderLayout.CENTER); + } + + private void init(Object[] data) { + // 复选框组 + dataCheckBoxes = new UICheckBox[data.length]; + for (int i = 0; i < dataCheckBoxes.length; i++) { + dataCheckBoxes[i] = new UICheckBox(transferDataValue2Show(data[i])); + dataCheckBoxes[i].setSelected(true); + } + + // UIList + dataList = new UIList(dataCheckBoxes); + dataList.setModel(getListModel()); + dataList.setCellRenderer(getListCellRenderer()); + + // 全选框 + chooseAllCheckBox = new TristateCheckBox(Toolkit.i18nText("Fine-Design_Basic_Remove_All_Selected")) { + @Override + protected State getNextState(State current) { + if (current == TristateCheckBox.SELECTED || current == TristateCheckBox.DO_NOT_CARE) { + return TristateCheckBox.NOT_SELECTED; + } + return TristateCheckBox.SELECTED; + } + }; + chooseAllCheckBox.setState(TristateCheckBox.SELECTED); + chooseAllCheckBox.setFocusable(false); + chooseAllCheckBox.addStateChangeListener(getChooseAllCheckBoxStateChangeListener()); + dataList.addMouseListener(getDataListMouseListener()); + } + + public List getSelectedObjects() { + List seleted = new ArrayList<>(); + for (UICheckBox dataCheckBox : dataCheckBoxes) { + if (dataCheckBox.isSelected()) { + seleted.add(dataCheckBox.getText()); + } + } + return seleted; + } + + protected MouseListener getDataListMouseListener() { + return new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + super.mousePressed(e); + int index = dataList.getSelectedIndex(); + if (index < 0) { + return; + } + UICheckBox checkBox = (UICheckBox) dataList.getModel().getElementAt(index); + checkBox.setSelected(!checkBox.isSelected()); + //根据CheckBoxes中的选择情况来更新全选框的状态 + int selectedCount = calculateSelectedNum(); + if (selectedCount == 0) { + chooseAllCheckBox.setState(TristateCheckBox.NOT_SELECTED); + } else if (selectedCount == dataCheckBoxes.length) { + chooseAllCheckBox.setState(TristateCheckBox.SELECTED); + } else { + chooseAllCheckBox.setState(TristateCheckBox.DO_NOT_CARE); + } + dataList.repaint(); + } + }; + } + + /** + * 获取全选框状态改变监听 + * @return + */ + protected StateChangeListener getChooseAllCheckBoxStateChangeListener() { + return () -> { + if (chooseAllCheckBox.getState() == TristateCheckBox.DO_NOT_CARE) { + return; + } + boolean isSelected = chooseAllCheckBox.isSelected(); + for (int i = 0; i < dataList.getModel().getSize(); i++) { + UICheckBox checkBox = (UICheckBox) dataList.getModel().getElementAt(i); + checkBox.setSelected(isSelected); + } + dataList.repaint(); + }; + } + + /** + * 计算CheckBox的选中情况,用来更新全选框的状态 + * @return + */ + protected int calculateSelectedNum() { + int count = 0; + for (UICheckBox dataCheckBox : dataCheckBoxes) { + if (dataCheckBox.isSelected()) { + count++; + } + } + return count; + } + + /** + * 将传入的Object转化为字符串展示,默认调用toString方法 + * @param object + * @return + */ + protected String transferDataValue2Show(Object object) { + return object.toString(); + } + + protected AbstractListModel getListModel() { + return new SelectedListDataModel(); + } + + protected ListCellRenderer getListCellRenderer() { + return new SelectedListCellRender(); + } + + private class SelectedListCellRender extends DefaultListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, final boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + dataCheckBoxes[index] = (UICheckBox) value; + dataCheckBoxes[index].setBackground(list.getBackground()); + return dataCheckBoxes[index]; + } + + } + + private class SelectedListDataModel extends AbstractListModel { + @Override + public int getSize() { + return dataCheckBoxes.length; + } + + @Override + public Object getElementAt(int index) { + return (index > getSize() - 1 || index < 0) ? null : dataCheckBoxes[index]; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/imenu/UIPopupMenu.java b/designer-base/src/main/java/com/fr/design/gui/imenu/UIPopupMenu.java index cdad63bff2..3aeaa186be 100644 --- a/designer-base/src/main/java/com/fr/design/gui/imenu/UIPopupMenu.java +++ b/designer-base/src/main/java/com/fr/design/gui/imenu/UIPopupMenu.java @@ -8,8 +8,10 @@ import javax.swing.*; import com.fr.design.constants.UIConstants; public class UIPopupMenu extends JPopupMenu{ - private static final float REC = 8f; + private static final float DEFAULT_REC = 8f; private boolean onlyText = false; + private float rec = DEFAULT_REC; + public static UIPopupMenu EMPTY = new UIPopupMenu(); public UIPopupMenu() { super(); @@ -19,8 +21,7 @@ public class UIPopupMenu extends JPopupMenu{ @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; - Shape shape = null; - shape = new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), REC, REC); + Shape shape = new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), rec, rec); g2d.setClip(shape); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); super.paintComponent(g2d); @@ -29,10 +30,9 @@ public class UIPopupMenu extends JPopupMenu{ @Override protected void paintBorder(Graphics g) { Graphics2D g2d = (Graphics2D) g; - int rec = (int) REC; g2d.setColor(UIConstants.UIPOPUPMENU_LINE_COLOR); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, rec, rec); + g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, (int) rec, (int) rec); } @Override @@ -46,4 +46,8 @@ public class UIPopupMenu extends JPopupMenu{ public void setOnlyText(boolean onlyText) { this.onlyText = onlyText; } + + public void setRadius(float radius) { + this.rec = radius; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java b/designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java index d1847545ce..44e697d043 100644 --- a/designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java +++ b/designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java @@ -5,7 +5,6 @@ import com.fr.design.dialog.UIDialog; import com.fr.design.gui.ilable.UILabel; import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.utils.DesignUtils; -import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; import com.fr.stable.os.support.OSBasedAction; import com.fr.stable.os.support.OSSupportCenter; @@ -21,51 +20,68 @@ import java.awt.Frame; /** * 加载进度弹窗 + * 使用注意点: + * 必须到使用时再初始化,不要作为属性存在 + * 因为涉及到 大小/位置 相对于 parent 的相对判断 + * 见 {@link com.fr.design.gui.iprogressbar.ProgressDialogTest} */ public class ProgressDialog extends UIDialog { - private JProgressBar progressBar; + protected static final FRFont font = DesignUtils + .getDefaultGUIFont() + .applySize(14) + .applyForeground(new ColorUIResource(333334)); + + protected JProgressBar progressBar; private JDialog centerDialog; - private JLabel text; + protected JLabel text; + protected JPanel progressPanel; public ProgressDialog(Frame parent) { super(parent); setUndecorated(true); setSize(parent.getSize()); - setLocationRelativeTo(null); + setLocation(parent.getLocation()); OSSupportCenter.buildAction(new OSBasedAction() { @Override public void execute(Object... objects) { setOpacity(0.5f); } }, SupportOSImpl.OPACITY); - initComponent(); + initComponent(parent); } - private void initComponent() { + private void initComponent(Frame parent) { + initProgressBar(); + initProgressPanel(); + initCenterDialog(parent); + } + protected void initCenterDialog(Frame parent) { centerDialog = new JDialog(this); centerDialog.setSize(new Dimension(482, 124)); centerDialog.setUndecorated(true); - GUICoreUtils.centerWindow(centerDialog); - JPanel panel = new JPanel(); - panel.setBorder(new UIProgressBorder(3, UIConstants.DEFAULT_BG_RULER, 14, 46, 47, 37, 47)); - panel.setLayout(new BorderLayout(4, 15)); + centerDialog.setLocationRelativeTo(parent); + centerDialog.getContentPane().add(progressPanel); + } + + protected void initProgressBar() { progressBar = new JProgressBar(); progressBar.setUI(new ModernUIProgressBarUI()); progressBar.setBorderPainted(false); progressBar.setOpaque(false); progressBar.setBorder(null); progressBar.setMaximum(1000); - panel.add(progressBar, BorderLayout.CENTER); + } + + protected void initProgressPanel() { + progressPanel = new JPanel(); + progressPanel.setBorder(new UIProgressBorder(3, UIConstants.DEFAULT_BG_RULER, 14, 46, 47, 37, 47)); + progressPanel.setLayout(new BorderLayout(4, 15)); + progressPanel.add(progressBar, BorderLayout.CENTER); text = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Loading_Project"), JLabel.CENTER); - FRFont font = DesignUtils - .getDefaultGUIFont() - .applySize(14) - .applyForeground(new ColorUIResource(333334)); text.setFont(font); - panel.add(text, BorderLayout.SOUTH); - panel.setVisible(true); - centerDialog.getContentPane().add(panel); + progressPanel.add(text, BorderLayout.SOUTH); + progressPanel.setVisible(true); } @Override diff --git a/designer-base/src/main/java/com/fr/design/gui/ispinner/UISpinner.java b/designer-base/src/main/java/com/fr/design/gui/ispinner/UISpinner.java index 4a722fc50d..a19db05060 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ispinner/UISpinner.java +++ b/designer-base/src/main/java/com/fr/design/gui/ispinner/UISpinner.java @@ -312,6 +312,25 @@ public class UISpinner extends JPanel implements UIObserver, GlobalNameObserver componentInitListeners(); } + /** + * 设置最大值 + * @param maxValue 最大值 + */ + public void setMaxValue(double maxValue) { + this.maxValue = maxValue; + textField.setMaxValue(maxValue); + } + + /** + * 设置最小值 + * + * @param minValue 最小值 + */ + public void setMinValue(double minValue) { + this.minValue = minValue; + textField.setMinValue(minValue); + } + private void componentInitListeners() { preButton.addActionListener(new ActionListener() { @Override diff --git a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableEditorPane.java b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableEditorPane.java index d6973f6bb4..aca38b28d2 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableEditorPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableEditorPane.java @@ -8,10 +8,12 @@ import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; - -import javax.swing.*; +import javax.swing.JPanel; +import javax.swing.JTable; import javax.swing.event.TableModelListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.Insets; import java.util.List; /** @@ -31,25 +33,25 @@ public class UITableEditorPane extends BasicPane { private String leftLabelName; private JPanel buttonPane; - public UITableEditorPane(UITableModelAdapter model) { - this.tableModel = model; - this.initComponent(model.createAction()); - } + public UITableEditorPane(UITableModelAdapter model) { + this.tableModel = model; + this.initComponent(model.createAction()); + } - public UITableEditorPane(UITableModelAdapter model, String s) { - leftLabelName = s; - this.tableModel = model; - this.initComponent(model.createAction()); - } + public UITableEditorPane(UITableModelAdapter model, String s) { + leftLabelName = s; + this.tableModel = model; + this.initComponent(model.createAction()); + } - private void initComponent(UITableEditAction[] action) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel pane = new JPanel(new BorderLayout(4, 4)); - this.add(pane, BorderLayout.CENTER); + protected void initComponent(UITableEditAction[] action) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + JPanel pane = new JPanel(new BorderLayout(4, 4)); + this.add(pane, BorderLayout.CENTER); - UILabel l = new UILabel(leftLabelName); - editTable = tableModel.createTable(); - editTable.getTableHeader().setBackground(UIConstants.DEFAULT_BG_RULER); + UILabel l = new UILabel(leftLabelName); + editTable = tableModel.createTable(); + editTable.getTableHeader().setBackground(UIConstants.DEFAULT_BG_RULER); UIScrollPane scrollPane = new UIScrollPane(editTable); scrollPane.setBorder(new UIRoundedBorder(UIConstants.TITLED_BORDER_COLOR, 1, UIConstants.ARC)); @@ -62,11 +64,11 @@ public class UITableEditorPane extends BasicPane { } - public UITableModelAdapter getTableModel(){ + public UITableModelAdapter getTableModel() { return tableModel; } - private void initbuttonPane(UITableEditAction[] action) { + protected void initbuttonPane(UITableEditAction[] action) { buttonPane = new JPanel(); if (action != null) { @@ -146,6 +148,14 @@ public class UITableEditorPane extends BasicPane { return buttonPane; } + public JTable getEditTable() { + return editTable; + } + + public void setEditTable(JTable editTable) { + this.editTable = editTable; + } + /** * 停止编辑 */ @@ -153,4 +163,12 @@ public class UITableEditorPane extends BasicPane { tableModel.stopCellEditing(); } + + /** + * 设置表头是否可以改变大小 + */ + public void setHeaderResizing(boolean resizingAllowed) { + editTable.getTableHeader().setResizingAllowed(resizingAllowed); + } + } diff --git a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java index 4506bb9a6c..87e21c75be 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java +++ b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java @@ -219,57 +219,69 @@ public abstract class UITableModelAdapter extends AbstractTableModel implemen protected class DeleteAction extends UITableEditAction { private Component component = null; + // 删除时界面显示的提示语,可自定义 + private String deleteTipText; public DeleteAction() { - this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete")); - this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png")); - } - + this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete")); + this.setDeleteTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?"); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png")); + } + public DeleteAction(Component component){ - this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete")); - this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png")); + this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete")); + this.setDeleteTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?"); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png")); this.component = component; } @Override public void actionPerformed(ActionEvent e) { - int[] selectedRow = table.getSelectedRows(); - if (ismultiSelected()) { - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Multiple_Select_Warn_Text")); - return; - } - if (table.getCellEditor() != null) { - try { - table.getCellEditor().stopCellEditing(); - } catch (Exception ee) { + int[] selectedRow = table.getSelectedRows(); + if (ismultiSelected()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Multiple_Select_Warn_Text")); + return; + } + if (table.getCellEditor() != null) { + try { + table.getCellEditor().stopCellEditing(); + } catch (Exception ee) { FineLoggerFactory.getLogger().error(ee.getMessage(), ee); - } - } - if (getRowCount() < 1) { - return; - } - - if(component == null){ - component = DesignerContext.getDesignerFrame(); - } - int val = FineJOptionPane.showConfirmDialog(component, - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (val != JOptionPane.OK_OPTION) { - return; - } - for (int i = 0; i < selectedRow.length; i++) { - if (selectedRow[i] - i < 0) { - continue; - } - removeRow(selectedRow[i] - i); - } - fireTableDataChanged(); - int selection = selectedRow[0] > table.getRowCount() ? table.getRowCount() - 1 - : (selectedRow[0] > 1 ? selectedRow[0] - 1 : 0); - table.getSelectionModel().setSelectionInterval(selection, selection); - } + } + } + if (getRowCount() < 1) { + return; + } + + if (component == null) { + component = DesignerContext.getDesignerFrame(); + } + int val = FineJOptionPane.showConfirmDialog(component, getDeleteTipText() + , com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (val != JOptionPane.OK_OPTION) { + return; + } + for (int i = 0; i < selectedRow.length; i++) { + if (selectedRow[i] - i < 0) { + continue; + } + removeRow(selectedRow[i] - i); + } + fireTableDataChanged(); + int selection = selectedRow[0] > table.getRowCount() ? table.getRowCount() - 1 + : (selectedRow[0] > 1 ? selectedRow[0] - 1 : 0); + table.getSelectionModel().setSelectionInterval(selection, selection); + } + + public String getDeleteTipText() { + return deleteTipText; + } + + public void setDeleteTipText(String deleteTipText) { + this.deleteTipText = deleteTipText; + } - private boolean ismultiSelected(){ + private boolean ismultiSelected() { int[] selectedRow = table.getSelectedRows(); return (selectedRow.length == 1 && (selectedRow[0] > table.getRowCount() - 1 || selectedRow[0] < 0)) || selectedRow.length == 0; } diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIAutoCompletionField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIAutoCompletionField.java index 967aeddbb9..f976f3471c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIAutoCompletionField.java +++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIAutoCompletionField.java @@ -256,10 +256,9 @@ public class UIAutoCompletionField extends UITextField implements DocumentListen * */ public void setText(String t) { - if (this.isOpen == true) { - if (!UIAutoCompletionField.this.isShowing()) { - return; - } + boolean unavailable = !this.isEnabled() && !this.isEditable(); + if (unavailable) { + return; } try { Document doc = getDocument(); diff --git a/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java b/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java index 8db73f8e66..ab6fb70b41 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java +++ b/designer-base/src/main/java/com/fr/design/gui/itooltip/UIToolTip.java @@ -67,6 +67,9 @@ public class UIToolTip extends JToolTip{ this.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { Container container = getComponent(); + if (container == null) { + return; + } while (!ComparatorUtils.equals(container.getClass(), UIScrollPane.class)) { if (container.getParent() == null) { break; diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/UITreeUI.java b/designer-base/src/main/java/com/fr/design/gui/itree/UITreeUI.java index fde3bf6461..a4d66c4384 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/UITreeUI.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/UITreeUI.java @@ -1,6 +1,7 @@ package com.fr.design.gui.itree; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.design.utils.ThemeUtils; import javax.swing.*; @@ -27,8 +28,8 @@ public class UITreeUI extends MetalTreeUI { protected void installDefaults() { super.installDefaults(); - setExpandedIcon(BaseUtils.readIcon("/com/fr/design/images/buttonicon/minus.png")); - setCollapsedIcon(BaseUtils.readIcon("/com/fr/design/images/buttonicon/plus.png")); + setExpandedIcon(IconUtils.readIcon("/com/fr/design/standard/fileicon/minus.svg")); + setCollapsedIcon(IconUtils.readIcon("/com/fr/design/standard/fileicon/plus.svg")); if (tree.getCellRenderer() instanceof DefaultTreeCellRenderer) { DefaultTreeCellRenderer r = (DefaultTreeCellRenderer) tree.getCellRenderer(); r.setBackgroundNonSelectionColor(ThemeUtils.TEXT_BG_COLOR); diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java index a748fa3201..d61b58cf1c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java @@ -52,40 +52,6 @@ public class EnvFileTree extends RefreshableJTree { /*一些自己的 init 放在这里,防止直接错误重写了父类的 init 方法导致子类不能使用 CheckBoxTree 的一些特性。*/ this.putClientProperty("JTree.lineStyle", "Angled"); - // CellRenderer - // 这里新建一个Label作为render是因为JTree在动态刷新的时候,节点上render画布的的宽度不会变,会使得一部分比较长的数据显示为 - DefaultTreeCellRenderer fileTreeCellRenderer = new DefaultTreeCellRenderer() { - - @Override - 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); - ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) value; - Object userObj = treeNode.getUserObject(); - if (userObj instanceof FileNode) { - FileNode node = (FileNode) userObj; - String lock = node.getLock(); - String name = node.getName(); - if (treeNode.hasFullAuthority()) { - if (lock != null && !lock.equals(node.getUserID())) { - name = name + Toolkit.i18nText("Fine-Design_Basic_Template_Status_Locked", "(", ")"); - } - this.setIcon(FileTreeIcon.getIcon(node)); - } else { - this.setIcon(FileTreeIcon.getFolderHalfImageIcon()); - } - this.setText(name); - } else if (userObj == PENDING) { - this.setIcon(null); - this.setText(PENDING.toString()); - } - this.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0)); - this.setBackgroundNonSelectionColor(UIConstants.TREE_BACKGROUND); - this.setTextSelectionColor(Color.WHITE); - this.setBackgroundSelectionColor(UIConstants.FLESH_BLUE); - return this; - } - }; this.setCellRenderer(fileTreeCellRenderer); this.setRootVisible(false); @@ -93,6 +59,45 @@ public class EnvFileTree extends RefreshableJTree { this.setEditable(false); } + // CellRenderer + // 这里新建一个Label作为render是因为JTree在动态刷新的时候,节点上render画布的的宽度不会变,会使得一部分比较长的数据显示为 + DefaultTreeCellRenderer fileTreeCellRenderer = new DefaultTreeCellRenderer() { + + @Override + 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); + ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) value; + Object userObj = treeNode.getUserObject(); + if (userObj instanceof FileNode) { + FileNode node = (FileNode) userObj; + String lock = node.getLock(); + String name = node.getName(); + if (treeNode.hasFullAuthority()) { + if (lock != null && !lock.equals(node.getUserID())) { + name = name + Toolkit.i18nText("Fine-Design_Basic_Template_Status_Locked", "(", ")"); + } + this.setIcon(FileTreeIcon.getIcon(node)); + } else { + this.setIcon(FileTreeIcon.getFolderHalfImageIcon()); + } + this.setText(name); + } else if (userObj == PENDING) { + this.setIcon(null); + this.setText(PENDING.toString()); + } + this.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0)); + this.setBackgroundNonSelectionColor(UIConstants.TREE_BACKGROUND); + this.setTextSelectionColor(Color.WHITE); + this.setBackgroundSelectionColor(UIConstants.FLESH_BLUE); + return this; + } + }; + + public DefaultTreeCellRenderer getFileTreeCellRenderer() { + return fileTreeCellRenderer; + } + private void setTreeRootPath(String path) { if (path == null) { path = ""; diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileTreeIcon.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileTreeIcon.java index e0515fe815..194dfa82de 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileTreeIcon.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileTreeIcon.java @@ -1,7 +1,9 @@ package com.fr.design.gui.itree.filetree; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.design.ExtraDesignClassManager; +import com.fr.design.icon.LocalFileIcon; import com.fr.design.icon.LockIcon; import com.fr.design.fun.ReportSupportedFileUIProvider; import com.fr.file.filetree.FileNode; @@ -19,11 +21,13 @@ public class FileTreeIcon { private FileTreeIcon() { } + public static final String FILE_LOCKED_ICON_PATH = "/com/fr/design/images/gui/file_lock.png"; + public static final Icon BLANK_IMAGE_ICON = BaseUtils.readIcon("/com/fr/design/images/gui/blank.gif"); - public static final Icon FOLDER_IMAGE_ICON = BaseUtils.readIcon("/com/fr/design/images/gui/folder.png"); + public static final Icon FOLDER_IMAGE_ICON = IconUtils.readIcon("/com/fr/design/standard/fileicon/folder.svg"); public static final Icon FOLDER_HALF_IMAGE_ICON = - BaseUtils.readIcon("/com/fr/design/images/gui/filetree_folder_half_authority_normal.png"); + IconUtils.readIcon("/com/fr/design/standard/fileicon/folder_half_authority.svg"); public static final Icon FILE_IMAGE_ICON = UIManager.getIcon("FileView.fileIcon"); @@ -42,14 +46,14 @@ public class FileTreeIcon { public static final Icon CHT_FILE_IMAGE_ICON = BaseUtils.readIcon("/com/fr/design/images/gui/cht.png"); public static final Icon MODERN_CPT_FILE_IMAGE_ICON = - BaseUtils.readIcon("/com/fr/design/images/gui/modern_style_cpt_file_icon_16x16.png"); + IconUtils.readIcon("/com/fr/design/standard/fileicon/cpt_icon.svg"); public static final Icon MODERN_FRM_FILE_IMAGE_ICON = - BaseUtils.readIcon("/com/fr/design/images/gui/modern_style_frm_file_icon_16x16.png"); + IconUtils.readIcon("/com/fr/design/standard/fileicon/frm_icon.svg"); public static final Icon MODERN_CHT_FILE_IMAGE_ICON = - BaseUtils.readIcon("/com/fr/design/images/gui/modern_style_cht_file_icon_16x16.png"); + IconUtils.readIcon("/com/fr/design/standard/fileicon/cht_icon.svg"); - public static final Icon CPTX_ICON = BaseUtils.readIcon("/com/fr/nx/app/designer/cptx_file_icon.png"); - public static final Icon CPTX_LOCKED_ICON = BaseUtils.readIcon("/com/fr/nx/app/designer/cptx_file_icon_locked.png"); + public static final Icon CPTX_ICON = IconUtils.readIcon("/com/fr/design/standard/fileicon/cptx_icon.svg"); + public static final Icon CPTX_LOCKED_ICON = IconUtils.readIcon("/com/fr/design/standard/fileicon/cptx_icon_locked.svg"); public static final LockIcon FOLDER_LOCK_ICON = new LockIcon(BaseUtils.readImage("/com/fr/design/images/gui/fold.png")); @@ -153,7 +157,7 @@ public class FileTreeIcon { if (node.isDirectory()) { return FileTreeIcon.FOLDER_IMAGE_ICON; } - return getLocalFileIcon(path); + return getLocalFileIcon(path, isShowLock); } } if (node.isDirectory()) { @@ -163,12 +167,12 @@ public class FileTreeIcon { } } - private static Icon getLocalFileIcon(String path) { - Icon icon = getExtraIcon(path, false); + private static Icon getLocalFileIcon(String path, boolean isShowLock) { + Icon icon = getExtraIcon(path, isShowLock); if (icon != null) { return icon; } - return FileSystemView.getFileSystemView().getSystemIcon(new File(path)); + return new LocalFileIcon(FileSystemView.getFileSystemView().getSystemIcon(new File(path)), isShowLock); } private static Icon getRemoteFileIcon(FileNode node, boolean isShowLock) { diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java new file mode 100644 index 0000000000..c4c5b7bf55 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java @@ -0,0 +1,53 @@ +package com.fr.design.gui.itree.filetree; + +import com.fr.base.FRContext; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.file.filetree.FileNode; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +/* + * 目录树 + */ +public class TemplateDirTree extends TemplateFileTree { + + public TemplateDirTree() { + super(); + } + + + /** + * 查找所有目录子节点 + * + * @param path + * @return + */ + public FileNode[] listFile(String path) { + return Arrays.stream(FRContext.getFileNodes().list(path)).filter(FileNode::isDirectory).toArray(FileNode[]::new); + } + + + /** + * 搜索时刷新目录树 + * @param root + */ + public void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) { + if (interceptRefresh(root)) { + return; + } + currentTreeMode.clear(); + allTreeNode = TemplateDirTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect( + Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0])); + root.removeAllChildren(); + + FileNode[] treeNodes = TemplateDirTreeSearchManager.getInstance().matchesNode(); + for (FileNode fileNode : treeNodes) { + ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0]; + addToTreeModel(root, treeNode); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java index b1f641b3b6..b87a70b5b6 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java @@ -6,10 +6,12 @@ import com.fr.design.ExtraDesignClassManager; import com.fr.design.file.NodeAuthProcessor; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.mainframe.App; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; import com.fr.file.filetree.FileNode; import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils; import com.fr.stable.StableUtils; +import com.fr.stable.collections.CollectionUtils; import com.fr.stable.project.ProjectConstants; import javax.swing.text.Position; @@ -17,15 +19,25 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; /* * 显示Env下的reportlets目录下面的所有cpt文件 */ public class TemplateFileTree extends EnvFileTree { + protected Map allTreeNode = new ConcurrentHashMap<>(); + protected Map calculateNode = new ConcurrentHashMap<>(); + protected Map> currentTreeMode = new ConcurrentHashMap<>(); + private static final int MAX_NODE_EXPAND_NUM = 50; + private static final int MAX_MATCHED_NODE_NUM = 500; + public TemplateFileTree() { super(ProjectConstants.REPORTLETS_NAME, null, null); } @@ -132,8 +144,8 @@ public class TemplateFileTree extends EnvFileTree { Set supportTypes = createFileExtensionFilter(); return FRContext.getFileNodes().list( path, - supportTypes.toArray(new FileExtension[supportTypes.size()]) - ); + supportTypes.toArray(new FileExtension[supportTypes.size()]), false, true + ); } private Set createFileExtensionFilter() { @@ -213,7 +225,7 @@ public class TemplateFileTree extends EnvFileTree { /* * 把FileNode[]转成ExpandMutableTreeNode[] */ - private ExpandMutableTreeNode[] fileNodeArray2TreeNodeArray(FileNode[] fileNodes) { + protected ExpandMutableTreeNode[] fileNodeArray2TreeNodeArray(FileNode[] fileNodes) { return NodeAuthProcessor.getInstance().parser2TreeNodeArray(fileNodes); } @@ -251,4 +263,123 @@ public class TemplateFileTree extends EnvFileTree { return new FileNode[0]; } + + /** + * 搜索时更新搜索结果 + */ + @Override + public void refresh4TreeSearch() { + ExpandMutableTreeNode root = (ExpandMutableTreeNode) this.getModel().getRoot(); + NodeAuthProcessor.getInstance().fixTreeNodeAuth(root); + refreshTreeNode4TreeSearch(root); + sortTreeNode(root); + ((DefaultTreeModel) this.getModel()).reload(root); + if (currentTreeMode.keySet().size() < MAX_NODE_EXPAND_NUM || TemplateTreeSearchManager.getInstance().matchesNode().length < MAX_MATCHED_NODE_NUM) { + //要展开的节点比较多的话,全部展开会有性能问题 + root.expandCurrentTreeNode(this); + } + } + + /** + * 重新对整个目录树排序 + * + * @param root 根节点 + */ + private void sortTreeNode(ExpandMutableTreeNode root) { + List childFileNode = new ArrayList<>(); + for (int i = 0; i < root.getChildCount(); i++) { + ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) root.getChildAt(i); + childFileNode.add(treeNode); + } + childFileNode = childFileNode.stream().sorted(Comparator.comparing(treeNode -> ((FileNode) (treeNode.getUserObject())), + new FileNodeComparator(FileNodeConstants.getSupportFileTypes()))).collect(Collectors.toList()); + root.removeAllChildren(); + root.addChildTreeNodes(childFileNode.toArray(new ExpandMutableTreeNode[0])); + for (ExpandMutableTreeNode treeNode : childFileNode) { + if (!treeNode.isLeaf()) { + sortTreeNode(treeNode); + } + } + } + + protected void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) { + if (interceptRefresh(root)) { + return; + } + if (!TemplateTreeSearchManager.getInstance().isRefreshing() || TemplateTreeSearchManager.getInstance().allFileNodes().size() != allTreeNode.size()) { + currentTreeMode.clear(); + calculateNode.clear(); + allTreeNode = TemplateTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect( + Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0])); + TemplateTreeSearchManager.getInstance().setRefreshing(true); + root.removeAllChildren(); + } + + FileNode[] treeNodes = TemplateTreeSearchManager.getInstance().matchesNode(); + //排序一下,保证父子节点的情况下,子节点排在前面,先添加到树结构中 + List treeNodeList = Arrays.stream(treeNodes).sorted((t1, t2) -> t2.getEnvPath().compareToIgnoreCase(t1.getEnvPath())).collect(Collectors.toList()); + for (FileNode fileNode : treeNodeList) { + if (!calculateNode.containsKey(fileNode.getEnvPath())) { + ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0]; + addToTreeModel(root, treeNode); + calculateNode.put(fileNode.getEnvPath(), treeNode); + } + } + } + + /** + * 将搜索匹配到的模板添加到搜索结果树里面 + * + * @param root + * @param treeNode + */ + protected void addToTreeModel(ExpandMutableTreeNode root, ExpandMutableTreeNode treeNode) { + + FileNode fileNode = (FileNode) treeNode.getUserObject(); + String parentPath = fileNode.getParent(); + removePending(treeNode); + + while (!ProjectConstants.REPORTLETS_NAME.equals(parentPath)) { + ExpandMutableTreeNode parentNode = allTreeNode.get(parentPath); + if (parentNode == null) { + FineLoggerFactory.getLogger().info("{} parent path {} is not found in allTreeNode.", fileNode.getEnvPath(), parentPath); + break; + } + parentNode.setExpanded(true); + removePending(parentNode); + if (notContained(parentPath, treeNode)) { + parentNode.add(treeNode); + } + parentPath = ((FileNode) (parentNode.getUserObject())).getParent(); + treeNode = parentNode; + } + + //最外层节点 + if (notContained(ProjectConstants.REPORTLETS_NAME, treeNode)) { + root.add(treeNode); + } + } + + private boolean notContained(String parentPath, ExpandMutableTreeNode treeNode) { + List childList = currentTreeMode.getOrDefault(parentPath, new ArrayList<>()); + String name = ((FileNode) (treeNode.getUserObject())).getName(); + boolean result = false; + if (CollectionUtils.isEmpty(childList)) { + childList.add(name); + result = true; + } else { + if (!childList.contains(name)) { + childList.add(name); + result = true; + } + } + currentTreeMode.put(parentPath, childList); + return result; + } + + private void removePending(ExpandMutableTreeNode treeNode) { + if (treeNode.getChildCount() >= 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) { + treeNode.remove(0); + } + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java index 48a4d933bb..af31420a2c 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java @@ -92,4 +92,12 @@ public class ExpandMutableTreeNode extends DefaultMutableTreeNode { this.add(newChildNodes[i]); } } + + @Override + public Object clone() { + ExpandMutableTreeNode cloned = (ExpandMutableTreeNode) super.clone(); + cloned.setExpanded(this.isExpanded); + cloned.setFullAuthority(this.hasFullAuthority); + return cloned; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java index a22f2a302a..338038c36b 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java @@ -150,10 +150,22 @@ public abstract class RefreshableJTree extends CheckBoxTree { refresh((ExpandMutableTreeNode) path.getParentPath().getLastPathComponent(), StringUtils.EMPTY); } + //刷新指定目录 + public void refreshDir(TreePath path) { + refresh((ExpandMutableTreeNode) path.getLastPathComponent(), StringUtils.EMPTY); + } + public void refreshChildByName(String childName) { refresh((ExpandMutableTreeNode) this.getModel().getRoot(), childName); } + /** + * 刷新树,用于搜索结果的展示 + */ + public void refresh4TreeSearch() { + + } + /* * 刷新expandRoot节点下所有已打开的节点的UserObject,并打开isExpanded为true的TreeNode */ diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java new file mode 100644 index 0000000000..c31cfe5295 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeAttrChangeListener.java @@ -0,0 +1,7 @@ +package com.fr.design.gui.itree.refreshabletree; + +import com.fr.data.impl.TreeAttr; + +public interface TreeAttrChangeListener { + void doChange(TreeAttr treeAttr); +} diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java index bb754716f6..691749fac6 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java @@ -8,75 +8,115 @@ import com.fr.design.layout.FRGUIPaneFactory; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JPanel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; public class TreeRootPane extends BasicPane { - - // 是否支持多选(checkBoxTree) - //private JCheckBox multipleSelection; - private UICheckBox checkTypeCheckBox; - - // richer:加载的方式,支持异步加载和完全加载 - private UICheckBox loadTypeCheckBox; - - private UICheckBox layerTypeCheckBox; - - private UICheckBox returnFullPathCheckBox ; - - public TreeRootPane() { - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); - checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - checkTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Mutiple_Selection_Or_Not")); - checkTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - checkTypePane.add(checkTypeCheckBox); - this.add(checkTypePane); - - JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); - checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - loadTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async")); - loadTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - loadTypePane.add(loadTypeCheckBox); - this.add(loadTypePane); - - JPanel leafSelectPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); - checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - leafSelectPane.add(layerTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Select_Leaf_Only"))); - layerTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - this.add(leafSelectPane); + + private final List listeners = new ArrayList<>(); + + // 是否支持多选(checkBoxTree) + //private JCheckBox multipleSelection; + private final UICheckBox checkTypeCheckBox; + + // richer:加载的方式,支持异步加载和完全加载 + private final UICheckBox loadTypeCheckBox; + + private final UICheckBox layerTypeCheckBox; + + private final UICheckBox returnFullPathCheckBox; + + public TreeRootPane() { + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); + checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + checkTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Mutiple_Selection_Or_Not")); + checkTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + checkTypePane.add(checkTypeCheckBox); + this.add(checkTypePane); + + JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); + checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + loadTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async")); + loadTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + loadTypePane.add(loadTypeCheckBox); + this.add(loadTypePane); + + JPanel leafSelectPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); + checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + leafSelectPane.add(layerTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Select_Leaf_Only"))); + layerTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + this.add(leafSelectPane); JPanel returnFullPathPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); - checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - returnFullPathPane.add(returnFullPathCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Return_Full_Path"))); - returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - - this.add(returnFullPathPane); - - } - - @Override - protected String title4PopupWindow() { - return "tree"; - } - - public void populate(TreeAttr treeAttr) { - checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection()); - loadTypeCheckBox.setSelected(treeAttr.isAjax()); - layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly()); + checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + returnFullPathPane.add(returnFullPathCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Return_Full_Path"))); + returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + addCheckBoxListener(); + + this.add(returnFullPathPane); + + } + + private void addCheckBoxListener() { + loadTypeCheckBox.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + UICheckBox checkBox = (UICheckBox) e.getSource(); + doLoadTypeChange(checkBox.isSelected()); + } + }); + + checkTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + loadTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + layerTypeCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + returnFullPathCheckBox.addActionListener(event->fireTreeAttrChangeListener()); + } + + private void doLoadTypeChange(Boolean selected) { + //给埋点插件提供一个方法,埋埋点用 + } + + @Override + protected String title4PopupWindow() { + return "tree"; + } + + public void populate(TreeAttr treeAttr) { + checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection()); + loadTypeCheckBox.setSelected(treeAttr.isAjax()); + layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly()); returnFullPathCheckBox.setSelected(treeAttr.isReturnFullPath()); - } - - public TreeAttr update() { - TreeAttr treeAttr = new TreeAttr(); - treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected()); - treeAttr.setAjax(loadTypeCheckBox.isSelected()); - treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected()); + fireTreeAttrChangeListener(); + } + + public TreeAttr update() { + TreeAttr treeAttr = new TreeAttr(); + treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected()); + treeAttr.setAjax(loadTypeCheckBox.isSelected()); + treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected()); treeAttr.setReturnFullPath(returnFullPathCheckBox.isSelected()); - return treeAttr; - } + return treeAttr; + } + + public void addTreeAttrChangeListener(TreeAttrChangeListener listener) { + listeners.add(listener); + } + + public void fireTreeAttrChangeListener() { + TreeAttr treeAttr = new TreeAttr(); + treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected()); + treeAttr.setAjax(loadTypeCheckBox.isSelected()); + treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected()); + treeAttr.setReturnFullPath(returnFullPathCheckBox.isSelected()); + listeners.forEach(listener -> listener.doChange(treeAttr)); + } } diff --git a/designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java b/designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java index bdf96f32e3..3e0f6c2130 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java @@ -34,6 +34,11 @@ public class BackgroundPane extends AbstractBasicStylePane { //获取当前面板 protected BackgroundQuickPane currentPane = null; + /** + * 记录上次选中的面板 + */ + protected BackgroundQuickPane lastSelectedPane = null; + public BackgroundPane() { this.initComponents(); @@ -62,6 +67,9 @@ public class BackgroundPane extends AbstractBasicStylePane { @Override public void itemStateChanged(ItemEvent e) { cardlayout.show(centerPane, (String) typeComboBox.getSelectedItem()); + if (e.getStateChange() == ItemEvent.DESELECTED) { + lastSelectedPane = currentPane; + } currentPane = paneList[typeComboBox.getSelectedIndex()]; fireStateChanged(); } @@ -144,6 +152,8 @@ public class BackgroundPane extends AbstractBasicStylePane { pane.populateBean(background); typeComboBox.setSelectedIndex(i); currentPane = paneList[i]; + // 填充 初始化 + lastSelectedPane = currentPane; return; } } 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 2e04b6ce58..d2a302ea01 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; @@ -16,15 +15,23 @@ import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.backgroundpane.NullBackgroundQuickPane; import com.fr.design.style.color.NewColorSelectBox; - +import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils; +import com.fr.general.IOUtils; import com.fr.stable.Constants; import com.fr.stable.CoreConstants; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridLayout; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -38,7 +45,6 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse private static final String[] BORDERARRAY = {"currentLineCombo", "currentLineColorPane", "outerToggleButton", "topToggleButton", "leftToggleButton", "bottomToggleButton", "rightToggleButton", "innerToggleButton", "horizontalToggleButton", "verticalToggleButton"}; private static final Set BORDER_SET = new HashSet<>(Arrays.asList(BORDERARRAY)); - private boolean insideMode = false; private UIToggleButton topToggleButton; private UIToggleButton horizontalToggleButton; @@ -50,11 +56,8 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse private UIToggleButton innerToggleButton; private UIToggleButton outerToggleButton; - private LineComboBox currentLineCombo; - private NewColorSelectBox currentLineColorPane; - private JPanel panel; - private JPanel borderPanel; - private JPanel backgroundPanel; + protected LineComboBox currentLineCombo; + protected NewColorSelectBox currentLineColorPane; private BackgroundPane backgroundPane; private GlobalNameListener globalNameListener = null; @@ -81,18 +84,18 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse new Component[]{null, null}, new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Color") + " ", SwingConstants.LEFT), currentLineColorPane}, new Component[]{null, null}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Out_Border") + " ", SwingConstants.LEFT), outerToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("com/fr/design/images/m_format/out.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/out_white.png")}, false)}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Out_Border") + " ", SwingConstants.LEFT), outerToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("com/fr/design/images/m_format/out.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/out_white.png")}, false)}, new Component[]{null, externalPane}, new Component[]{null, null}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_In_Border") + " ", SwingConstants.LEFT), innerToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("com/fr/design/images/m_format/in.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/in_white.png")}, false)}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_In_Border") + " ", SwingConstants.LEFT), innerToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("com/fr/design/images/m_format/in.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/in_white.png")}, false)}, new Component[]{null, insidePane}, new Component[]{null, null} }; double[] rowSize = {p, p, p, p, p, p, p, p, p, p, p}; double[] columnSize = {p, f}; int[][] rowCount = {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}; - panel = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, LayoutConstants.VGAP_SMALL, LayoutConstants.VGAP_MEDIUM); - borderPanel = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Border"), 280, 24, panel); + JPanel panel = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, LayoutConstants.VGAP_SMALL, LayoutConstants.VGAP_MEDIUM); + JPanel borderPanel = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Border"), 280, 24, panel); this.add(borderPanel, BorderLayout.NORTH); UILabel backgroundFillLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Background_Fill")); @@ -102,7 +105,7 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse JPanel backgroundContainPane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{backgroundFillLabel, backgroundPane}}, TableLayoutHelper.FILL_LASTCOLUMN, LayoutConstants.VGAP_SMALL, LayoutConstants.VGAP_MEDIUM); - backgroundPanel = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background"), 280, 24, backgroundContainPane); + JPanel backgroundPanel = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background"), 280, 24, backgroundContainPane); this.add(backgroundPanel, BorderLayout.CENTER); initAllNames(); outerToggleButton.addChangeListener(outerToggleButtonChangeListener); @@ -130,12 +133,12 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse }; private void initButtonsWithIcon() { - topToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/top.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/top_white.png")}, false); - leftToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/left.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/left_white.png")}, false); - bottomToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/bottom.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bottom_white.png")}, false); - rightToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/right.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/right_white.png")}, false); - horizontalToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/horizontal.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/horizontal_white.png")}, false); - verticalToggleButton = new UIToggleButton(new Icon[]{BaseUtils.readIcon("/com/fr/base/images/dialog/border/vertical.png"), BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/vertical_white.png")}, false); + topToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/top.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/top_white.png")}, false); + leftToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/left.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/left_white.png")}, false); + bottomToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/bottom.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bottom_white.png")}, false); + rightToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/right.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/right_white.png")}, false); + horizontalToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/horizontal.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/horizontal_white.png")}, false); + verticalToggleButton = new UIToggleButton(new Icon[]{IOUtils.readIcon("/com/fr/base/images/dialog/border/vertical.png"), IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/vertical_white.png")}, false); this.currentLineCombo = new LineComboBox(CoreConstants.UNDERLINE_STYLE_ARRAY); this.currentLineColorPane = new NewColorSelectBox(100); } @@ -174,15 +177,15 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse cellBorderStyle.setRightStyle(style.getBorderRight()); cellBorderStyle.setRightColor(style.getBorderRightColor()); this.backgroundPane.populateBean(style.getBackground()); - this.populateBean(cellBorderStyle, false, style.getBorderTop(), style.getBorderTopColor()); + this.populateBean(cellBorderStyle, false); } - public void populateBean(CellBorderStyle cellBorderStyle, boolean insideMode, int currentStyle, Color currentColor) { - this.insideMode = insideMode; + public void populateBean(CellBorderStyle cellBorderStyle, boolean insideMode) { + populateBean(cellBorderStyle, insideMode, true); + } - this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getTopStyle() == Constants.LINE_NONE ? Constants.LINE_THIN : cellBorderStyle.getTopStyle()); - this.currentLineColorPane.setSelectObject(cellBorderStyle.getTopColor()); + public void populateBean(CellBorderStyle cellBorderStyle, boolean insideMode, boolean onlyInspectTop) { this.topToggleButton.setSelected(cellBorderStyle.getTopStyle() != Constants.LINE_NONE); this.bottomToggleButton.setSelected(cellBorderStyle.getBottomStyle() != Constants.LINE_NONE); @@ -195,25 +198,64 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse this.innerToggleButton.setSelected(cellBorderStyle.getInnerBorder() != Constants.LINE_NONE); this.outerToggleButton.setSelected(cellBorderStyle.getOuterBorderStyle() != Constants.LINE_NONE); - this.innerToggleButton.setEnabled(this.insideMode); - this.horizontalToggleButton.setEnabled(this.insideMode); - this.verticalToggleButton.setEnabled(this.insideMode); + this.innerToggleButton.setEnabled(insideMode); + this.horizontalToggleButton.setEnabled(insideMode); + this.verticalToggleButton.setEnabled(insideMode); + + populateLineStyleAndColor(cellBorderStyle, onlyInspectTop); + } + + public void populateLineStyleAndColor(CellBorderStyle cellBorderStyle, boolean onlyInspectTop) { + resetLineStyleAndColorSetting(); + + if (cellBorderStyle.getTopStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getTopStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getTopColor()); + } else if (!onlyInspectTop) { + if (cellBorderStyle.getBottomStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getBottomStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getBottomColor()); + } else if (cellBorderStyle.getLeftStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getLeftStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getLeftColor()); + } else if (cellBorderStyle.getRightStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getRightStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getRightColor()); + } else if (cellBorderStyle.getVerticalStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getVerticalStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getVerticalColor()); + } else if (cellBorderStyle.getHorizontalStyle() != Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(cellBorderStyle.getHorizontalStyle()); + this.currentLineColorPane.setSelectObject(cellBorderStyle.getHorizontalColor()); + } + } + + if (this.currentLineCombo.getSelectedLineStyle() == Constants.LINE_NONE) { + this.currentLineCombo.setSelectedLineStyle(Constants.LINE_THIN); + } + } + + private void resetLineStyleAndColorSetting() { + this.currentLineCombo.setSelectedLineStyle(Constants.LINE_NONE); + this.currentLineColorPane.setSelectObject(null); } @Override public Style update(Style style) { if (style == null) { - style = Style.DEFAULT_STYLE; + style = AdjustWorkBookDefaultStyleUtils.adjustCellElement(Style.DEFAULT_STYLE); } - if (backgroundPane.currentPane.isBackgroundChange()) { + boolean isSetNullBackground = backgroundPane.currentPane instanceof NullBackgroundQuickPane + && !(backgroundPane.lastSelectedPane instanceof NullBackgroundQuickPane); + if (backgroundPane.currentPane.isBackgroundChange() || isSetNullBackground) { style = style.deriveBackground(backgroundPane.update()); } if (BORDER_SET.contains(globalNameListener.getGlobalName())) { CellBorderStyle cellBorderStyle = this.update(); style = style.deriveBorder(cellBorderStyle.getTopStyle(), cellBorderStyle.getTopColor(), cellBorderStyle.getBottomStyle(), cellBorderStyle.getBottomColor(), - cellBorderStyle.getLeftStyle(), cellBorderStyle.getLeftColor(), cellBorderStyle.getRightStyle(), cellBorderStyle.getRightColor()); + cellBorderStyle.getLeftStyle(), cellBorderStyle.getLeftColor(), cellBorderStyle.getRightStyle(), cellBorderStyle.getRightColor()); } return style; @@ -223,46 +265,35 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse int lineStyle = currentLineCombo.getSelectedLineStyle(); Color lineColor = currentLineColorPane.getSelectObject(); CellBorderStyle cellBorderStyle = new CellBorderStyle(); - if (topToggleButton.isSelected()) { - cellBorderStyle.setTopColor(lineColor); + if (lineColor != null) { + if (topToggleButton.isSelected()) { + cellBorderStyle.setTopColor(lineColor); + } + if (bottomToggleButton.isSelected()) { + cellBorderStyle.setBottomColor(lineColor); + } + if (leftToggleButton.isSelected()) { + cellBorderStyle.setLeftColor(lineColor); + } + if (rightToggleButton.isSelected()) { + cellBorderStyle.setRightColor(lineColor); + } + if (verticalToggleButton.isSelected()) { + cellBorderStyle.setVerticalColor(lineColor); + } + if (horizontalToggleButton.isSelected()) { + cellBorderStyle.setHorizontalColor(lineColor); + } } cellBorderStyle.setTopStyle(topToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - - if (bottomToggleButton.isSelected()) { - cellBorderStyle.setBottomColor(lineColor); - } cellBorderStyle.setBottomStyle(bottomToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - - if (leftToggleButton.isSelected()) { - cellBorderStyle.setLeftColor(lineColor); - } cellBorderStyle.setLeftStyle(leftToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - - if (rightToggleButton.isSelected()) { - cellBorderStyle.setRightColor(lineColor); - } cellBorderStyle.setRightStyle(rightToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - - if (verticalToggleButton.isSelected()) { - cellBorderStyle.setVerticalColor(lineColor); - } cellBorderStyle.setVerticalStyle(verticalToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - - if (horizontalToggleButton.isSelected()) { - cellBorderStyle.setHorizontalColor(lineColor); - } cellBorderStyle.setHorizontalStyle(horizontalToggleButton.isSelected() ? lineStyle : Constants.LINE_NONE); - if (leftToggleButton.isSelected() && bottomToggleButton.isSelected() && rightToggleButton.isSelected() && topToggleButton.isSelected()) { - outerToggleButton.setSelected(true); - } else { - outerToggleButton.setSelected(false); - } - if (verticalToggleButton.isSelected() && horizontalToggleButton.isSelected()) { - innerToggleButton.setSelected(true); - } else { - innerToggleButton.setSelected(false); - } + outerToggleButton.setSelected(leftToggleButton.isSelected() && bottomToggleButton.isSelected() && rightToggleButton.isSelected() && topToggleButton.isSelected()); + innerToggleButton.setSelected(verticalToggleButton.isSelected() && horizontalToggleButton.isSelected()); return cellBorderStyle; } diff --git a/designer-base/src/main/java/com/fr/design/gui/style/ComponentTitleStylePane.java b/designer-base/src/main/java/com/fr/design/gui/style/ComponentTitleStylePane.java index 33af029ad6..1f2fb91b82 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/ComponentTitleStylePane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/ComponentTitleStylePane.java @@ -12,6 +12,7 @@ import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.utils.DesignUtils; import com.fr.design.widget.FRWidgetFactory; import com.fr.form.ui.LayoutBorderStyle; import com.fr.form.ui.WidgetTitle; @@ -90,7 +91,7 @@ public class ComponentTitleStylePane extends AbstractBorderPackerPane { textContentPane = new TinyFormulaPane(); - fontFamilyComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontFamilyComboBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); FRFont frFont = DEFAULT_TITLE_PACKER.getFrFont(); if (frFont != null) { String fontFamily = frFont.getFamily(); diff --git a/designer-base/src/main/java/com/fr/design/gui/style/FRFontPane.java b/designer-base/src/main/java/com/fr/design/gui/style/FRFontPane.java index f806ded065..8af5c08d40 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/FRFontPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/FRFontPane.java @@ -18,6 +18,7 @@ import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; import com.fr.general.DefaultValues; @@ -246,7 +247,7 @@ public class FRFontPane extends AbstractBasicStylePane implements GlobalNameObse protected void initComponents() { fontSizeStyleComboBox = new UIComboBox(fontSizeStyles); - fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontNameComboBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); fontNameComboBox.setPreferredSize(new Dimension(144, 20)); fontSizeComboBox = new UIComboBox(getFontSizes()); fontSizeComboBox.setEditable(true); diff --git a/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java b/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java index f9f556b3d3..bf06aa2fd7 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/FollowingThemePane.java @@ -5,6 +5,7 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.event.UIObserver; import com.fr.design.event.UIObserverListener; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.frpane.AttributeChangeUtils; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; @@ -47,16 +48,20 @@ public class FollowingThemePane extends BasicPane implements UIObserver { this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); followingThemeButtonGroup = new UIButtonGroup<>(FOLLOWING_THEME_STRING_ARRAYS); + followingThemeButtonGroup.setAutoFireStateChanged(false); followingThemeButtonGroup.setSelectedIndex(1); followingThemeButtonGroup.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - for (FollowingThemeActionChangeListener changeListener : changeListeners) { - changeListener.onFollowingTheme(isFollowingTheme()); - } - invalidate(); - - // 与主题相关的属性面板更新完毕后,再通知外层更新数据 + AttributeChangeUtils.changeComposedUI(FollowingThemePane.this, false, new AttributeChangeUtils.UIChangeAction() { + @Override + public void changeComposedUI() { + for (FollowingThemeActionChangeListener changeListener : changeListeners) { + changeListener.onFollowingTheme(isFollowingTheme()); + } + invalidate(); + } + }); if (uiObserverListener != null) { uiObserverListener.doChange(); } diff --git a/designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java b/designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java index ba68ab36f5..2485b4de4e 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java @@ -24,12 +24,22 @@ import com.fr.general.ComparatorUtils; import com.fr.stable.StringUtils; -import java.math.BigDecimal; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; import java.math.RoundingMode; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.TitledBorder; -import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.text.Format; @@ -54,6 +64,7 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse private static final Integer[] TYPES = new Integer[]{ FormatContents.NULL, FormatContents.NUMBER, FormatContents.CURRENCY, FormatContents.PERCENT, + FormatContents.THOUSANDTHS, FormatContents.SCIENTIFIC, FormatContents.DATE, FormatContents.TIME, FormatContents.TEXT}; @@ -244,6 +255,9 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse } else if (pattern.indexOf("%") > 0) { setPatternComboBoxAndList(FormatContents.PERCENT, pattern); this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); + } else if (pattern.indexOf("‰") > 0) { + setPatternComboBoxAndList(FormatContents.THOUSANDTHS, pattern); + this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); } else if (pattern.indexOf("E") > 0) { setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern); } else { diff --git a/designer-base/src/main/java/com/fr/design/gui/style/ReportBackgroundSpecialPane.java b/designer-base/src/main/java/com/fr/design/gui/style/ReportBackgroundSpecialPane.java index aeb2938a27..257e090c20 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/ReportBackgroundSpecialPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/ReportBackgroundSpecialPane.java @@ -29,7 +29,7 @@ public class ReportBackgroundSpecialPane extends BackgroundPane { protected BackgroundQuickPane[] supportKindsOfBackgroundUI() { NullBackgroundQuickPane nullBackgroundPane = new NullBackgroundQuickPane(); - ColorBackgroundQuickPane colorBackgroundPane = new ColorBackgroundQuickPane(); + ColorBackgroundQuickPane colorBackgroundPane = new ColorBackgroundQuickPane(true); colorBackgroundPane.registerChangeListener(new UIObserverListener() { @Override public void doChange() { diff --git a/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java b/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java index ae0a947992..0b8e8287ab 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java @@ -7,7 +7,6 @@ import com.fr.base.TextFormat; import com.fr.data.core.FormatField; import com.fr.data.core.FormatField.FormatContents; import com.fr.design.border.UIRoundedBorder; -import com.fr.design.constants.LayoutConstants; import com.fr.design.constants.UIConstants; import com.fr.design.event.GlobalNameListener; import com.fr.design.event.GlobalNameObserver; @@ -18,21 +17,18 @@ import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.icombobox.UIComboBoxRenderer; 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.general.ComparatorUtils; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; +import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; -import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import java.awt.BorderLayout; -import java.awt.CardLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -62,74 +58,51 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName private static final Integer[] TYPES = new Integer[]{ FormatContents.NULL, FormatContents.NUMBER, FormatContents.CURRENCY, FormatContents.PERCENT, - FormatContents.SCIENTIFIC, FormatContents.DATE, - FormatContents.TIME, FormatContents.TEXT}; + FormatContents.THOUSANDTHS, FormatContents.SCIENTIFIC, + FormatContents.DATE, FormatContents.TIME, + FormatContents.TEXT}; private static final Integer[] DATE_TYPES = new Integer[]{FormatContents.NULL, FormatContents.DATE, FormatContents.TIME}; - private Format format; - - private UIComboBox typeComboBox; - private TextFontComboBox textField; - private UILabel sampleLabel; - private JPanel contentPane; - private JPanel txtCenterPane; - private JPanel centerPane; - private JPanel optionPane; - private UICheckBox roundingBox; - private JPanel formatFontPane; + protected UIComboBox typeComboBox; + protected TextFontComboBox textField; + protected UICheckBox roundingBox; + protected UILabel previewLabel; + private boolean isRightFormat; private boolean isDate = false; private GlobalNameListener globalNameListener = null; - /** - * Constructor. - */ public TextFormatPane() { - this.initComponents(TYPES); - } - protected UIComboBox getTypeComboBox() { - return typeComboBox; + initFormatTypesComboBox(); + initTextFontComboBox4GeneralFormats(); + initRoundingCheckBox4PercentFormat(); + initPreviewLabel4GeneralFormat(); + + initLayout(); + + setTextFieldVisible(false); + setRoundingBoxVisible(false); + setPreviewLabelVisible(false); } - protected void initComponents(Integer[] types) { - this.setLayout(new BorderLayout(0, 4)); - initSampleLabel(); - contentPane = new JPanel(new BorderLayout(0, 4)) { - @Override - public Dimension getPreferredSize() { - return new Dimension(super.getPreferredSize().width, 65); - } - }; - typeComboBox = new UIComboBox(types); - UIComboBoxRenderer render = createComBoxRender(); - typeComboBox.setRenderer(render); + private void initFormatTypesComboBox() { + typeComboBox = new UIComboBox(TextFormatPane.TYPES); + typeComboBox.setRenderer(createComBoxRender()); typeComboBox.addItemListener(itemListener); typeComboBox.setGlobalName("typeComboBox"); - contentPane.add(sampleLabel, BorderLayout.NORTH); + typeComboBox.setPreferredSize(new Dimension(155,20)); + } - txtCenterPane = new JPanel(new BorderLayout()); - textField = new TextFontComboBox(); + private void initTextFontComboBox4GeneralFormats() { + textField = new TextFontComboBox<>(); textField.addItemListener(textFieldItemListener); textField.setEditable(true); textField.setGlobalName("textField"); - txtCenterPane.add(textField, BorderLayout.NORTH); - - contentPane.add(txtCenterPane, BorderLayout.CENTER); - - centerPane = new JPanel(new CardLayout()); - centerPane.add(new JPanel(), "hide"); - centerPane.setPreferredSize(new Dimension(0, 0)); - centerPane.add(contentPane, "show"); - - typeComboBox.setPreferredSize(new Dimension(155,20)); - JPanel typePane = new JPanel(new BorderLayout()); - typePane.add(typeComboBox, BorderLayout.CENTER); - typePane.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); + } - JPanel option = new JPanel(new BorderLayout()); - option.add(new UILabel(Toolkit.i18nText("Fine-Design_Report_Base_Option"), SwingConstants.LEFT), BorderLayout.WEST); + private void initRoundingCheckBox4PercentFormat() { roundingBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_Base_Option_Half_Up")); roundingBox.setBorder(BorderFactory.createEmptyBorder(0, 30, 0, 0)); roundingBox.addItemListener(new ItemListener() { @@ -138,53 +111,13 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName } }); roundingBox.setGlobalName("roundingBox"); - option.add(roundingBox, BorderLayout.CENTER); - optionPane = new JPanel(new CardLayout()); - optionPane.add(new JPanel(), "hide"); - optionPane.setPreferredSize(new Dimension(0, 0)); - optionPane.add(option, "show"); - - Component[][] components = getComponent(centerPane, typePane); - this.add(createContentPane(components), BorderLayout.CENTER); - } - - protected JPanel createContentPane (Component[][] components) { - double f = TableLayout.FILL; - double p = TableLayout.PREFERRED; - double[] rowSize = {p, p, p, p, p}; - double[] columnSize = {p, f}; - int[][] rowCount = {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}; - return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, LayoutConstants.VGAP_LARGE, LayoutConstants.VGAP_MEDIUM); - } - - - protected Component[][] getComponent (JPanel centerPane, JPanel typePane) { - return new Component[][]{ - new Component[]{null, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Report_Base_Format"), SwingConstants.LEFT), typePane}, - new Component[]{centerPane, null}, - new Component[]{optionPane, null}, - }; - } - - protected UIComboBoxRenderer createComBoxRender() { - return new UIComboBoxRenderer() { - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (value instanceof Integer) { - label.setText(" " + FormatField.getInstance().getName((Integer) value)); - } - return label; - } - }; } - private void initSampleLabel() { + private void initPreviewLabel4GeneralFormat() { Border interBorder = new UIRoundedBorder(UIConstants.LINE_COLOR, 1, 4); String title = Toolkit.i18nText("Fine-Design_Report_Base_StyleFormat_Sample"); Border border = BorderFactory.createTitledBorder(interBorder, title, TitledBorder.LEFT, 0, null, UIConstants.LINE_COLOR); - sampleLabel = new UILabel(FormatField.getInstance().getFormatValue()) { + previewLabel = new UILabel(FormatField.getInstance().getFormatValue()) { @Override public void paint(Graphics g) { @@ -196,12 +129,65 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName g.setColor(UIConstants.LINE_COLOR); FontMetrics cellFM = g.getFontMetrics(); int textWidth = cellFM.stringWidth(getText()); - GraphHelper.drawString(g, getText(), (width - textWidth) / 2, 26); + GraphHelper.drawString(g, getText(), (width - textWidth) / 2F, 26); g.setColor(original); } }; - sampleLabel.setHorizontalAlignment(UILabel.CENTER); - sampleLabel.setBorder(border); + previewLabel.setHorizontalAlignment(UILabel.CENTER); + previewLabel.setBorder(border); + } + + protected void initLayout() { + JPanel labeledFormatTypeComboBoxPane = new JPanel(new BorderLayout(20, 0)); + labeledFormatTypeComboBoxPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Report_Base_Format")), BorderLayout.WEST); + labeledFormatTypeComboBoxPane.add(typeComboBox, BorderLayout.CENTER); + + JPanel labeledRoundingCheckboxPane = new JPanel(new BorderLayout(0, 0)); + labeledRoundingCheckboxPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Report_Base_Option")), BorderLayout.WEST); + labeledRoundingCheckboxPane.add(roundingBox, BorderLayout.CENTER); + + addComponents(4, new JComponent[] { labeledFormatTypeComboBoxPane, textField, labeledRoundingCheckboxPane, previewLabel}); + } + + protected void setTextFieldVisible(boolean visible) { + textField.setVisible(visible); + } + + protected void setRoundingBoxVisible(boolean visible) { + roundingBox.getParent().setVisible(visible); + } + + protected void setPreviewLabelVisible(boolean visible) { + previewLabel.setVisible(visible); + } + + protected void addComponents(int gap, JComponent[] components) { + JPanel container = this; + container.setLayout(new BorderLayout(0, gap)); + for (JComponent component: components) { + if (component != null) { + container.add(component, BorderLayout.NORTH); + JPanel nextContainer = new JPanel(new BorderLayout(0, gap)); + container.add(nextContainer, BorderLayout.CENTER); + container = nextContainer; + } + } + if (container.getComponentCount() == 0) { + container.getParent().remove(container); + } + } + + protected UIComboBoxRenderer createComBoxRender() { + return new UIComboBoxRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof Integer) { + label.setText(" " + FormatField.getInstance().getName((Integer) value)); + } + return label; + } + }; } @@ -229,8 +215,6 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName * Populate */ public void populateBean(Format format) { - this.format = format; - if (format == null) { this.typeComboBox.setSelectedIndex(FormatContents.NULL); } else { @@ -244,6 +228,9 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); } else if (pattern.indexOf("E") > 0) { setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern); + } else if (pattern.indexOf("‰") > 0) { + setPatternComboBoxAndList(FormatContents.THOUSANDTHS, pattern); + this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); } else { setPatternComboBoxAndList(FormatContents.NUMBER, pattern); } @@ -323,17 +310,17 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName * Refresh preview label. */ private void refreshPreviewLabel() { - this.sampleLabel.setText(FormatField.getInstance().getFormatValue()); - this.sampleLabel.setForeground(UIManager.getColor("Label.foreground")); + this.previewLabel.setText(FormatField.getInstance().getFormatValue()); + this.previewLabel.setForeground(UIManager.getColor("Label.foreground")); try { isRightFormat = true; if (StringUtils.isEmpty(String.valueOf(textField.getSelectedItem()))) { return; } - this.sampleLabel.setText(FormatField.getInstance().getFormatValue(getFormatContents(), String.valueOf(textField.getSelectedItem()))); + this.previewLabel.setText(FormatField.getInstance().getFormatValue(getFormatContents(), String.valueOf(textField.getSelectedItem()))); } catch (Exception e) { - this.sampleLabel.setForeground(Color.red); - this.sampleLabel.setText(e.getMessage()); + this.previewLabel.setForeground(Color.red); + this.previewLabel.setText(e.getMessage()); isRightFormat = false; } } @@ -352,28 +339,16 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { int contents = getFormatContents(); - String[] items = FormatField.getInstance().getFormatArray(contents, false); - CardLayout cardLayout = (CardLayout) centerPane.getLayout(); - if (isTextOrNull()) { - centerPane.setPreferredSize(new Dimension(0, 0)); - cardLayout.show(centerPane, "hide"); - } else { + if (!isTextOrNull()) { textField.removeAllItems(); + String[] items = FormatField.getInstance().getFormatArray(contents, false); textField.setItemArray(items); textField.setSelectedIndex(0); - centerPane.setPreferredSize(new Dimension(270, 65)); - cardLayout.show(centerPane, "show"); - } - CardLayout optionLayout = ((CardLayout) optionPane.getLayout()); - if (getFormatContents() == FormatContents.PERCENT) { - optionPane.setPreferredSize(new Dimension(100, 20)); - optionLayout.show(optionPane, "show"); - } else { - optionPane.setPreferredSize(new Dimension(0, 0)); - optionLayout.show(optionPane, "hide"); - roundingBox.setSelected(false); } + setTextFieldVisible(!isTextOrNull()); + setPreviewLabelVisible(!isTextOrNull()); + setRoundingBoxVisible(getFormatContents() == FormatContents.PERCENT || getFormatContents() == FormatContents.THOUSANDTHS); } } @@ -401,10 +376,20 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName * update */ public Style update(Style style) { - if (ComparatorUtils.equals(globalNameListener.getGlobalName(), "textField") - || ComparatorUtils.equals(globalNameListener.getGlobalName(), "typeComboBox") - || ComparatorUtils.equals(globalNameListener.getGlobalName(), "roundingBox")) { - return style.deriveFormat(this.update()); + return updateByGlobalNamedSetting(style); + } + + private Style updateByGlobalNamedSetting(Style style) { + if (globalNameListener != null) { + String[] alterSettingNames = new String[] {"typeComboBox", "textField", "roundingBox"}; + String globalSettingName = globalNameListener.getGlobalName(); + if (StringUtils.isNotEmpty(globalSettingName)) { + for (String alterSettingName : alterSettingNames) { + if (ComparatorUtils.equals(alterSettingName, globalSettingName)) { + return style.deriveFormat(this.update()); + } + } + } } return style; } diff --git a/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPaneContainer.java b/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPaneContainer.java new file mode 100644 index 0000000000..bf58ab6558 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/gui/style/TextFormatPaneContainer.java @@ -0,0 +1,81 @@ +package com.fr.design.gui.style; + +import com.fr.base.Style; +import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; +import com.fr.design.gui.frpane.AttributeChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; + +/** + * 封装格式panel,管理 AttributeChangeListener + * + * @author Leo.Qin + * @version 11.0 + * Created by Leo.Qin on 2022/10/31 + */ +public class TextFormatPaneContainer extends AbstractAttrNoScrollPane { + private TextFormatPane formatPane; + private AttributeChangeListener oldListner; + + @Override + protected JPanel createContentPane() { + formatPane = new TextFormatPane(); + return formatPane; + } + + protected void initContentPane() { + leftContentPane = createContentPane(); + if (leftContentPane != null) { + leftContentPane.setBorder(BorderFactory.createEmptyBorder()); + this.add(leftContentPane, BorderLayout.CENTER); + } + } + + @Override + public Dimension getPreferredSize() { + if (formatPane == null) { + return super.getPreferredSize(); + } + return formatPane.getPreferredSize(); + } + + /** + * 根据单元格样式填充面板设置 + * + * @param style 单元格样式 + */ + public void populateBean(Style style) { + formatPane.populateBean(style); + } + + /** + * 根据面板设置获取修改后的单元格样式 + * + * @param style 单元格当前样式 + * @return 更新后的单元格样式 + */ + public Style update(Style style) { + return formatPane.update(style); + } + + @Override + public void removeAttributeChangeListener() { + super.removeAttributeChangeListener(); + } + + @Override + public void addAttributeChangeListener(AttributeChangeListener listener) { + oldListner = listener; + super.addAttributeChangeListener(listener); + } + + /** + * 恢复使用AttributeChangeListener + */ + public void restoreAttributeChangeListener() { + super.addAttributeChangeListener(oldListner); + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java b/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java index bb3ccf38bc..cc49820de5 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java @@ -26,6 +26,7 @@ import com.fr.design.style.color.NewColorSelectBox; import com.fr.env.utils.DesignerInteractionHistory; import com.fr.general.Background; import com.fr.general.IOUtils; +import com.fr.i18n.UrlI18nManager; import com.fr.general.act.BorderPacker; import com.fr.stable.Constants; import com.fr.stable.GraphDrawHelper; @@ -117,7 +118,7 @@ public class TranslucentBorderSpecialPane extends AbstractBorderPackerPane imple public void actionPerformed(ActionEvent e) { Desktop desktop = Desktop.getDesktop(); try { - desktop.browse(new URI(TWEAK_NINE_POINT_HELP_URL)); + desktop.browse(new URI(UrlI18nManager.getInstance().getI18nUrl("nine.point.help"))); } catch (IOException | URISyntaxException ioException) { ioException.printStackTrace(); } @@ -190,7 +191,7 @@ public class TranslucentBorderSpecialPane extends AbstractBorderPackerPane imple String lastUsedBorderImageDirPath = history.getLastSelectedBorderImageDir(); File lastUsedBorderImageDir = StringUtils.isNotEmpty(lastUsedBorderImageDirPath) ? new File(lastUsedBorderImageDirPath) : null; - File inbuiltBorderImagesDir = new File(StableUtils.pathJoin(ProjectLibrary.getInstance().getLibHome(), ProjectConstants.ASSETS_NAME, "border_images")); + File inbuiltBorderImagesDir = new File(StableUtils.pathJoin(ProjectLibrary.getInstance().getLibHome(), ProjectConstants.LOCAL, ProjectConstants.BORDER_IMAGES)); if (lastUsedBorderImageDir!= null && lastUsedBorderImageDir.exists()) { imageFileChooser.setCurrentDirectory(lastUsedBorderImageDir); diff --git a/designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java b/designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java index 98b5265c39..6ffe49f4eb 100644 --- a/designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java +++ b/designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java @@ -1,24 +1,24 @@ -/* The following code was generated by JFlex 1.4.1 on 9/18/19 6:12 PM */ +/* The following code was generated by JFlex 1.4.1 on 22-4-11 下午2:19 */ package com.fr.design.gui.syntax.ui.rsyntaxtextarea.modes; + import com.fr.design.gui.syntax.ui.rsyntaxtextarea.AbstractJFlexCTokenMaker; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.Token; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.TokenImpl; - -import javax.swing.text.Segment; import java.io.IOException; +import javax.swing.text.Segment; + /** - * This class is a scanner generated by + * This class is a scanner generated by * JFlex 1.4.1 - * on 9/18/19 6:12 PM from the specification file - * /Users/3dot141/Downloads/FolxDownload/App/jflex-1.4.1/bin/FormulaTokenMaker.flex + * on 22-4-11 下午2:19 from the specification file + * C:/Users/pengda/Desktop/bug/FormulaTokenMaker.flex */ -@SuppressWarnings("squid:S1192") public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { /** This character denotes the end of file */ @@ -32,57 +32,58 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { public static final int YYINITIAL = 0; public static final int MLC = 1; - /** + /** * Translates characters to character classes */ - private static final String ZZ_CMAP_PACKED = - "\11\0\1\50\1\43\1\0\1\50\1\56\22\0\1\50\1\36\1\44"+ - "\1\57\1\60\1\65\1\132\1\33\1\31\1\31\1\51\1\7\1\64"+ - "\1\37\1\54\1\32\1\47\1\41\1\100\1\120\1\5\1\127\1\121"+ - "\1\5\1\126\1\3\1\70\1\63\1\34\1\30\1\35\1\27\1\61"+ - "\1\72\1\73\1\75\1\4\1\6\1\55\1\110\1\77\1\105\1\125"+ - "\1\116\1\53\1\112\1\104\1\76\1\111\1\113\1\101\1\74\1\106"+ - "\1\52\1\107\1\115\1\122\1\102\1\123\1\62\1\40\1\62\1\131"+ - "\1\2\1\0\1\24\1\46\1\21\1\10\1\11\1\12\1\25\1\66"+ - "\1\13\1\1\1\117\1\15\1\26\1\14\1\20\1\23\1\114\1\17"+ - "\1\16\1\67\1\22\1\45\1\71\1\42\1\103\1\124\1\130\1\133"+ - "\1\130\1\64\uff81\0"; - - /** + private static final String ZZ_CMAP_PACKED = + "\11\0\1\50\1\43\1\0\1\50\1\56\22\0\1\50\1\36\1\44"+ + "\1\57\1\60\1\65\1\132\1\33\1\31\1\31\1\51\1\7\1\64"+ + "\1\37\1\54\1\32\1\47\1\41\1\100\1\120\1\5\1\127\1\121"+ + "\1\5\1\126\1\3\1\70\1\63\1\34\1\30\1\35\1\27\1\61"+ + "\1\72\1\73\1\75\1\4\1\6\1\55\1\110\1\77\1\105\1\125"+ + "\1\116\1\53\1\112\1\104\1\76\1\111\1\113\1\101\1\74\1\106"+ + "\1\52\1\107\1\115\1\122\1\102\1\123\1\62\1\40\1\62\1\131"+ + "\1\2\1\0\1\24\1\46\1\21\1\10\1\11\1\12\1\25\1\66"+ + "\1\13\1\1\1\117\1\15\1\26\1\14\1\20\1\23\1\114\1\17"+ + "\1\16\1\67\1\22\1\45\1\71\1\42\1\103\1\124\1\130\1\133"+ + "\1\130\1\64\uff81\0"; + + /** * Translates characters to character classes */ private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); - /** + /** * Translates DFA states to action switch labels. */ private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\3\0\1\1\2\2\1\3\2\2\1\4\17\2\2\4"+ - "\1\5\1\4\1\6\4\4\1\2\1\7\1\10\2\2"+ - "\1\3\1\11\2\2\1\4\1\2\2\1\30\2\2\4"+ - "\2\12\1\13\5\12\1\14\2\12\1\2\2\15\2\3"+ - "\1\16\16\2\1\17\61\2\1\0\1\20\1\21\2\22"+ - "\1\23\1\6\2\10\1\24\2\2\1\15\13\2\6\1"+ - "\1\0\77\2\2\0\1\25\6\0\1\2\1\3\1\0"+ - "\1\3\1\15\1\16\2\2\1\17\11\2\1\17\16\2"+ - "\1\17\3\2\1\17\2\2\1\17\14\2\1\17\10\2"+ - "\1\17\17\2\1\17\1\2\1\17\1\6\1\26\1\6"+ - "\3\22\1\6\2\10\1\27\2\2\1\30\10\2\4\1"+ - "\1\31\4\1\6\0\26\2\1\17\2\2\1\17\10\2"+ - "\1\17\17\2\1\17\25\2\1\17\1\2\1\17\6\2"+ - "\10\0\1\2\1\16\1\0\4\2\1\17\6\2\1\17"+ - "\34\2\1\17\15\2\1\17\4\2\1\6\1\10\2\2"+ - "\2\30\5\2\7\1\4\0\1\31\4\0\12\2\1\17"+ - "\4\2\1\17\32\2\1\17\1\2\2\17\23\2\1\17"+ - "\2\2\2\0\1\32\2\0\1\33\27\2\1\17\7\2"+ - "\1\17\14\2\1\30\3\2\1\31\3\1\7\0\30\2"+ - "\1\17\2\2\1\17\12\2\4\0\36\2\2\1\1\31"+ - "\3\0\54\2\2\0\116\2"; + "\3\0\1\1\2\2\1\3\2\2\1\4\17\2\2\4"+ + "\1\5\1\4\1\6\4\4\1\2\1\7\1\10\2\2"+ + "\1\3\1\11\2\2\1\4\1\2\2\1\30\2\2\4"+ + "\2\12\1\13\5\12\1\14\2\12\1\2\2\15\2\3"+ + "\1\16\16\2\1\17\62\2\1\0\1\20\1\21\2\22"+ + "\1\23\1\6\2\10\1\24\2\2\1\15\14\2\6\1"+ + "\1\0\101\2\2\0\1\25\6\0\1\2\1\3\1\0"+ + "\1\3\1\15\1\16\2\2\1\17\12\2\1\17\20\2"+ + "\1\17\3\2\1\17\2\2\1\17\14\2\1\17\10\2"+ + "\1\17\20\2\2\17\1\2\1\17\1\6\1\26\1\6"+ + "\3\22\1\6\2\10\1\27\2\2\1\30\10\2\4\1"+ + "\1\31\4\1\6\0\27\2\1\17\2\2\1\17\10\2"+ + "\1\17\17\2\1\17\26\2\1\17\1\2\2\17\6\2"+ + "\10\0\1\2\1\16\1\0\4\2\1\17\10\2\1\17"+ + "\40\2\1\17\17\2\1\17\6\2\1\6\1\10\2\2"+ + "\2\30\5\2\7\1\4\0\1\31\4\0\13\2\1\17"+ + "\5\2\1\17\34\2\1\17\1\2\2\17\27\2\1\17"+ + "\2\2\2\0\1\32\2\0\1\33\33\2\1\17\1\2"+ + "\1\17\10\2\1\17\7\2\1\17\6\2\1\30\3\2"+ + "\1\31\3\1\7\0\20\2\1\17\12\2\1\17\2\2"+ + "\1\17\1\2\1\17\14\2\4\0\44\2\2\1\1\31"+ + "\3\0\62\2\2\0\114\2"; private static int [] zzUnpackAction() { - int [] result = new int[887]; + int [] result = new int[943]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -101,126 +102,133 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { } - /** + /** * Translates a state to a row index in the transition table */ private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\134\0\270\0\u0114\0\u0170\0\u01cc\0\u0228\0\u0284"+ - "\0\u02e0\0\u033c\0\u0398\0\u03f4\0\u0450\0\u04ac\0\u0508\0\u0564"+ - "\0\u05c0\0\u061c\0\u0678\0\u06d4\0\u0730\0\u078c\0\u07e8\0\u0844"+ - "\0\u08a0\0\u08fc\0\u0958\0\u09b4\0\u0a10\0\u0a6c\0\u0ac8\0\u0b24"+ - "\0\u09b4\0\u0b80\0\u0114\0\u09b4\0\u0bdc\0\u0c38\0\u0c94\0\u0cf0"+ - "\0\u0d4c\0\u0da8\0\u0e04\0\u0e60\0\u0ebc\0\u09b4\0\u0f18\0\u09b4"+ - "\0\u0f74\0\u0fd0\0\u102c\0\u1088\0\u10e4\0\u1140\0\u119c\0\u11f8"+ - "\0\u1254\0\u12b0\0\u130c\0\u1368\0\u13c4\0\u1420\0\u147c\0\u14d8"+ - "\0\u1534\0\u1590\0\u15ec\0\u1648\0\u16a4\0\u1700\0\u175c\0\u17b8"+ - "\0\u1814\0\u1870\0\u18cc\0\u09b4\0\u1928\0\u1984\0\u19e0\0\u1a3c"+ - "\0\u1a98\0\u09b4\0\u1af4\0\u1b50\0\u1bac\0\u1c08\0\u1c64\0\u1cc0"+ - "\0\u1d1c\0\u1d78\0\u1dd4\0\u1e30\0\u1e8c\0\u1ee8\0\u1f44\0\u1fa0"+ - "\0\u1ffc\0\u2058\0\u20b4\0\u2110\0\u216c\0\u21c8\0\u2224\0\u2280"+ - "\0\u01cc\0\u22dc\0\u2338\0\u2394\0\u23f0\0\u244c\0\u24a8\0\u2504"+ - "\0\u2560\0\u25bc\0\u2618\0\u2674\0\u26d0\0\u272c\0\u2788\0\u27e4"+ - "\0\u2840\0\u289c\0\u28f8\0\u2954\0\u29b0\0\u2a0c\0\u2a68\0\u2ac4"+ - "\0\u2b20\0\u2b7c\0\u2bd8\0\u2c34\0\u2c90\0\u2cec\0\u2d48\0\u2da4"+ - "\0\u2e00\0\u2e5c\0\u2eb8\0\u2f14\0\u2f70\0\u2fcc\0\u3028\0\u3084"+ - "\0\u30e0\0\u313c\0\u3198\0\u31f4\0\u3250\0\u32ac\0\u3308\0\u3364"+ - "\0\u33c0\0\u341c\0\u3478\0\u09b4\0\u09b4\0\u34d4\0\u3530\0\u09b4"+ - "\0\u358c\0\u35e8\0\u3644\0\u09b4\0\u36a0\0\u36fc\0\u3758\0\u37b4"+ - "\0\u3810\0\u386c\0\u38c8\0\u3924\0\u3980\0\u39dc\0\u3a38\0\u3a94"+ - "\0\u3af0\0\u3b4c\0\u3ba8\0\u3c04\0\u3c60\0\u3cbc\0\u3d18\0\u3d74"+ - "\0\u3dd0\0\u3e2c\0\u3e88\0\u3ee4\0\u3f40\0\u3f9c\0\u3ff8\0\u4054"+ - "\0\u40b0\0\u410c\0\u4168\0\u41c4\0\u4220\0\u427c\0\u42d8\0\u4334"+ - "\0\u4390\0\u43ec\0\u4448\0\u44a4\0\u4500\0\u455c\0\u45b8\0\u4614"+ - "\0\u4670\0\u46cc\0\u4728\0\u4784\0\u47e0\0\u483c\0\u4898\0\u48f4"+ - "\0\u4950\0\u49ac\0\u4a08\0\u4a64\0\u4ac0\0\u4b1c\0\u4b78\0\u4bd4"+ - "\0\u4c30\0\u4c8c\0\u4ce8\0\u4d44\0\u4da0\0\u4dfc\0\u4e58\0\u4eb4"+ - "\0\u4f10\0\u4f6c\0\u4fc8\0\u5024\0\u5080\0\u50dc\0\u5138\0\u5194"+ - "\0\u51f0\0\u524c\0\u52a8\0\u5304\0\u5360\0\u53bc\0\u5418\0\u5474"+ - "\0\u54d0\0\u552c\0\u09b4\0\u5588\0\u55e4\0\u5640\0\u569c\0\u56f8"+ - "\0\u5754\0\u57b0\0\u580c\0\u5868\0\u1c08\0\u58c4\0\u1c08\0\u5920"+ - "\0\u597c\0\u59d8\0\u5a34\0\u5a90\0\u5aec\0\u5b48\0\u5ba4\0\u5c00"+ - "\0\u5c5c\0\u5cb8\0\u5d14\0\u5d70\0\u5dcc\0\u5e28\0\u5e84\0\u5ee0"+ - "\0\u5f3c\0\u5f98\0\u5ff4\0\u6050\0\u60ac\0\u6108\0\u6164\0\u61c0"+ - "\0\u621c\0\u6278\0\u62d4\0\u6330\0\u638c\0\u63e8\0\u6444\0\u64a0"+ - "\0\u64fc\0\u6558\0\u65b4\0\u6610\0\u666c\0\u66c8\0\u6724\0\u6780"+ - "\0\u67dc\0\u6838\0\u6894\0\u68f0\0\u694c\0\u69a8\0\u6a04\0\u6a60"+ - "\0\u6abc\0\u6b18\0\u6b74\0\u6bd0\0\u6c2c\0\u6c88\0\u6ce4\0\u6d40"+ - "\0\u6d9c\0\u6df8\0\u6e54\0\u6eb0\0\u6f0c\0\u6f68\0\u6fc4\0\u7020"+ - "\0\u707c\0\u70d8\0\u7134\0\u7190\0\u71ec\0\u7248\0\u72a4\0\u7300"+ - "\0\u735c\0\u73b8\0\u7414\0\u09b4\0\u7470\0\u74cc\0\u7528\0\u7584"+ - "\0\u75e0\0\u763c\0\u7698\0\u09b4\0\u76f4\0\u7750\0\u77ac\0\u7808"+ - "\0\u7864\0\u78c0\0\u791c\0\u7978\0\u79d4\0\u7a30\0\u7a8c\0\u7ae8"+ - "\0\u7b44\0\u7ba0\0\u7bfc\0\u7c58\0\u7cb4\0\u7d10\0\u7d6c\0\u7dc8"+ - "\0\u7e24\0\u7e80\0\u7edc\0\u7f38\0\u7f94\0\u7ff0\0\u804c\0\u80a8"+ - "\0\u8104\0\u8160\0\u81bc\0\u8218\0\u8274\0\u82d0\0\u832c\0\u8388"+ - "\0\u83e4\0\u8440\0\u849c\0\u84f8\0\u8554\0\u85b0\0\u860c\0\u8668"+ - "\0\u86c4\0\u8720\0\u877c\0\u87d8\0\u8834\0\u8890\0\u88ec\0\u8948"+ - "\0\u89a4\0\u8a00\0\u8a5c\0\u8ab8\0\u8b14\0\u8b70\0\u8bcc\0\u8c28"+ - "\0\u8c84\0\u8ce0\0\u8d3c\0\u8d98\0\u8df4\0\u8e50\0\u8eac\0\u8f08"+ - "\0\u8f64\0\u8fc0\0\u901c\0\u9078\0\u90d4\0\u9130\0\u918c\0\u91e8"+ - "\0\u9244\0\u92a0\0\u92fc\0\u9358\0\u93b4\0\u9410\0\u946c\0\u94c8"+ - "\0\u9524\0\u9580\0\u95dc\0\u9638\0\u9694\0\u96f0\0\u974c\0\u97a8"+ - "\0\u9804\0\u9860\0\u98bc\0\u9918\0\u9974\0\u99d0\0\u9a2c\0\u9a88"+ - "\0\u9ae4\0\u9b40\0\u9b9c\0\u9bf8\0\u9c54\0\u9cb0\0\u9d0c\0\u9d68"+ - "\0\u9dc4\0\u9e20\0\u9e7c\0\u9ed8\0\u9f34\0\u9f90\0\u9fec\0\u73b8"+ - "\0\ua048\0\ua0a4\0\ua100\0\ua15c\0\ua1b8\0\ua214\0\ua270\0\ua2cc"+ - "\0\ua328\0\ua384\0\ua3e0\0\ua43c\0\ua498\0\ua4f4\0\ua550\0\ua5ac"+ - "\0\ua608\0\ua664\0\ua6c0\0\ua71c\0\ua778\0\ua7d4\0\ua830\0\ua88c"+ - "\0\ua8e8\0\ua944\0\ua9a0\0\ua9fc\0\uaa58\0\uaab4\0\uab10\0\uab6c"+ - "\0\uabc8\0\uac24\0\uac80\0\uacdc\0\uad38\0\uad94\0\uadf0\0\uae4c"+ - "\0\uaea8\0\uaf04\0\uaf60\0\uafbc\0\ub018\0\ub074\0\ub0d0\0\ub12c"+ - "\0\ub188\0\ub1e4\0\ub240\0\ub29c\0\ub2f8\0\ub354\0\ub3b0\0\ub40c"+ - "\0\ub468\0\ub4c4\0\ub520\0\ub57c\0\ub5d8\0\ub634\0\ub690\0\ub6ec"+ - "\0\ub748\0\ub7a4\0\ub800\0\ub85c\0\ub8b8\0\ub914\0\ub970\0\ub9cc"+ - "\0\uba28\0\uba84\0\ubae0\0\ubb3c\0\ubb98\0\ubbf4\0\ubc50\0\ubcac"+ - "\0\ubd08\0\ubd64\0\ubdc0\0\ube1c\0\ube78\0\ubed4\0\ubf30\0\ubf8c"+ - "\0\ubfe8\0\uc044\0\uc0a0\0\uc0fc\0\uc158\0\uc1b4\0\uc210\0\uc26c"+ - "\0\uc2c8\0\uc324\0\uc380\0\uc3dc\0\uc438\0\u9a2c\0\uc494\0\uc4f0"+ - "\0\uc54c\0\uc5a8\0\uc604\0\uc660\0\uc6bc\0\uc718\0\uc774\0\uc7d0"+ - "\0\uc82c\0\uc888\0\uc8e4\0\uc940\0\uc99c\0\uc9f8\0\uca54\0\ucab0"+ - "\0\ucb0c\0\ucb68\0\ucbc4\0\ucc20\0\ucc7c\0\uccd8\0\ucd34\0\ucd90"+ - "\0\ucdec\0\uce48\0\ucea4\0\ucf00\0\ucf5c\0\ucfb8\0\ud014\0\ud070"+ - "\0\ud0cc\0\ud128\0\ud184\0\ud1e0\0\ud23c\0\ud298\0\ud2f4\0\ud350"+ - "\0\ud3ac\0\ud408\0\ud464\0\ud4c0\0\ud51c\0\ud578\0\ud5d4\0\ud630"+ - "\0\ud68c\0\ud6e8\0\ud744\0\ud7a0\0\ud7fc\0\ud858\0\ud8b4\0\ud910"+ - "\0\ud96c\0\ud9c8\0\uda24\0\uda80\0\udadc\0\udb38\0\udb94\0\udbf0"+ - "\0\udc4c\0\udca8\0\udd04\0\udd60\0\uddbc\0\ude18\0\ude74\0\uded0"+ - "\0\udf2c\0\udf88\0\udfe4\0\ue040\0\ue09c\0\ue0f8\0\ue154\0\ue1b0"+ - "\0\ue20c\0\ue268\0\ue2c4\0\ue320\0\ue37c\0\u6444\0\ue3d8\0\ue434"+ - "\0\ue490\0\ue4ec\0\ue548\0\ue5a4\0\ue600\0\ue65c\0\ue6b8\0\ue714"+ - "\0\ue770\0\ue7cc\0\ue828\0\ue884\0\ue8e0\0\ue93c\0\u1c08\0\ue998"+ - "\0\ue9f4\0\uea50\0\u0114\0\ueaac\0\ueb08\0\ueb64\0\uebc0\0\uec1c"+ - "\0\uec78\0\uecd4\0\ued30\0\ued8c\0\uede8\0\uee44\0\ueea0\0\ueefc"+ - "\0\uef58\0\uefb4\0\uf010\0\uf06c\0\uf0c8\0\uf124\0\uf180\0\uf1dc"+ - "\0\uf238\0\u8948\0\uf294\0\uf2f0\0\uf34c\0\uf3a8\0\uf404\0\uf460"+ - "\0\uf4bc\0\uf518\0\uf574\0\uf5d0\0\uf62c\0\uf688\0\uf6e4\0\uf740"+ - "\0\uf79c\0\uf7f8\0\uf854\0\uf8b0\0\uf90c\0\uf968\0\uf9c4\0\ufa20"+ - "\0\ufa7c\0\ufad8\0\ufb34\0\ufb90\0\ud8b4\0\ufbec\0\ud9c8\0\ufc48"+ - "\0\ufca4\0\ufd00\0\ufd5c\0\ufdb8\0\ufe14\0\ufe70\0\ufecc\0\uff28"+ - "\0\uff84\0\uffe0\1\74\1\230\1\364\1\u0150\1\u01ac\1\u0208"+ - "\1\u0264\1\u02c0\1\u031c\1\u0378\1\u03d4\1\u0430\1\u048c\1\u04e8"+ - "\1\u0544\1\u05a0\1\u05fc\1\u0658\1\u06b4\1\u0710\1\u076c\0\u09b4"+ - "\1\u07c8\1\u0824\1\u0880\1\u08dc\1\u0938\1\u0994\1\u09f0\1\u0a4c"+ - "\1\u0aa8\1\u0b04\1\u0b60\1\u0bbc\1\u0c18\1\u0c74\1\u0cd0\1\u0d2c"+ - "\1\u0d88\1\u0de4\1\u0e40\1\u0e9c\1\u0ef8\1\u0f54\1\u0fb0\1\u100c"+ - "\1\u1068\1\u10c4\1\u1120\1\u117c\1\u11d8\1\u1234\1\u1290\1\u12ec"+ - "\1\u1348\1\u13a4\1\u1400\1\u145c\1\u14b8\1\u1514\1\u1570\1\u15cc"+ - "\0\u7300\1\u1628\1\u1684\1\u16e0\1\u173c\1\u1798\1\u17f4\1\u1850"+ - "\1\u18ac\1\u1908\1\u1964\1\u19c0\1\u1a1c\0\u9ae4\1\u1a78\1\u1ad4"+ - "\1\u1b30\1\u1b8c\1\u1be8\1\u1c44\1\u1ca0\1\u1cfc\1\u1d58\1\u1db4"+ - "\1\u1e10\1\u1e6c\1\u1ec8\1\u1f24\1\u1f80\1\u1fdc\1\u2038\1\u2094"+ - "\1\u20f0\1\u214c\1\u21a8\1\u2204\1\u2260\1\u22bc\1\u2318\1\u2374"+ - "\1\u23d0\1\u242c\1\u2488\1\u24e4\1\u2540\1\u259c\1\u25f8\1\u2654"+ - "\1\u26b0\1\u270c\1\u2768\1\u27c4\1\u2820\1\u287c\1\u28d8\1\u2934"+ - "\1\u2990\1\u29ec\1\u2a48\1\u2aa4\1\u2b00\1\u2b5c\1\u2bb8\1\u2c14"+ - "\1\u2c70\1\u2ccc\1\u2d28\1\u2d84\1\u2de0\1\u2e3c\1\u2e98\1\u2ef4"+ - "\1\u2f50\1\u2fac\1\u3008\1\u3064\1\u30c0\1\u311c\1\u3178\1\u31d4"+ - "\1\u3230\1\u328c\1\u32e8\1\u3344\1\u33a0\1\u33fc\1\u3458"; + "\0\0\0\134\0\270\0\u0114\0\u0170\0\u01cc\0\u0228\0\u0284"+ + "\0\u02e0\0\u033c\0\u0398\0\u03f4\0\u0450\0\u04ac\0\u0508\0\u0564"+ + "\0\u05c0\0\u061c\0\u0678\0\u06d4\0\u0730\0\u078c\0\u07e8\0\u0844"+ + "\0\u08a0\0\u08fc\0\u0958\0\u09b4\0\u0a10\0\u0a6c\0\u0ac8\0\u0b24"+ + "\0\u09b4\0\u0b80\0\u0114\0\u09b4\0\u0bdc\0\u0c38\0\u0c94\0\u0cf0"+ + "\0\u0d4c\0\u0da8\0\u0e04\0\u0e60\0\u0ebc\0\u09b4\0\u0f18\0\u09b4"+ + "\0\u0f74\0\u0fd0\0\u102c\0\u1088\0\u10e4\0\u1140\0\u119c\0\u11f8"+ + "\0\u1254\0\u12b0\0\u130c\0\u1368\0\u13c4\0\u1420\0\u147c\0\u14d8"+ + "\0\u1534\0\u1590\0\u15ec\0\u1648\0\u16a4\0\u1700\0\u175c\0\u17b8"+ + "\0\u1814\0\u1870\0\u18cc\0\u09b4\0\u1928\0\u1984\0\u19e0\0\u1a3c"+ + "\0\u1a98\0\u09b4\0\u1af4\0\u1b50\0\u1bac\0\u1c08\0\u1c64\0\u1cc0"+ + "\0\u1d1c\0\u1d78\0\u1dd4\0\u1e30\0\u1e8c\0\u1ee8\0\u1f44\0\u1fa0"+ + "\0\u1ffc\0\u2058\0\u20b4\0\u2110\0\u216c\0\u21c8\0\u2224\0\u2280"+ + "\0\u01cc\0\u22dc\0\u2338\0\u2394\0\u23f0\0\u244c\0\u24a8\0\u2504"+ + "\0\u2560\0\u25bc\0\u2618\0\u2674\0\u26d0\0\u272c\0\u2788\0\u27e4"+ + "\0\u2840\0\u289c\0\u28f8\0\u2954\0\u29b0\0\u2a0c\0\u2a68\0\u2ac4"+ + "\0\u2b20\0\u2b7c\0\u2bd8\0\u2c34\0\u2c90\0\u2cec\0\u2d48\0\u2da4"+ + "\0\u2e00\0\u2e5c\0\u2eb8\0\u2f14\0\u2f70\0\u2fcc\0\u3028\0\u3084"+ + "\0\u30e0\0\u313c\0\u3198\0\u31f4\0\u3250\0\u32ac\0\u3308\0\u3364"+ + "\0\u33c0\0\u341c\0\u3478\0\u34d4\0\u09b4\0\u09b4\0\u3530\0\u358c"+ + "\0\u09b4\0\u35e8\0\u3644\0\u36a0\0\u09b4\0\u36fc\0\u3758\0\u37b4"+ + "\0\u3810\0\u386c\0\u38c8\0\u3924\0\u3980\0\u39dc\0\u3a38\0\u3a94"+ + "\0\u3af0\0\u3b4c\0\u3ba8\0\u3c04\0\u3c60\0\u3cbc\0\u3d18\0\u3d74"+ + "\0\u3dd0\0\u3e2c\0\u3e88\0\u3ee4\0\u3f40\0\u3f9c\0\u3ff8\0\u4054"+ + "\0\u40b0\0\u410c\0\u4168\0\u41c4\0\u4220\0\u427c\0\u42d8\0\u4334"+ + "\0\u4390\0\u43ec\0\u4448\0\u44a4\0\u4500\0\u455c\0\u45b8\0\u4614"+ + "\0\u4670\0\u46cc\0\u4728\0\u4784\0\u47e0\0\u483c\0\u4898\0\u48f4"+ + "\0\u4950\0\u49ac\0\u4a08\0\u4a64\0\u4ac0\0\u4b1c\0\u4b78\0\u4bd4"+ + "\0\u4c30\0\u4c8c\0\u4ce8\0\u4d44\0\u4da0\0\u4dfc\0\u4e58\0\u4eb4"+ + "\0\u4f10\0\u4f6c\0\u4fc8\0\u5024\0\u5080\0\u50dc\0\u5138\0\u5194"+ + "\0\u51f0\0\u524c\0\u52a8\0\u5304\0\u5360\0\u53bc\0\u5418\0\u5474"+ + "\0\u54d0\0\u552c\0\u5588\0\u55e4\0\u5640\0\u569c\0\u09b4\0\u56f8"+ + "\0\u5754\0\u57b0\0\u580c\0\u5868\0\u58c4\0\u5920\0\u597c\0\u59d8"+ + "\0\u1c08\0\u5a34\0\u1c08\0\u5a90\0\u5aec\0\u5b48\0\u5ba4\0\u5c00"+ + "\0\u5c5c\0\u5cb8\0\u5d14\0\u5d70\0\u5dcc\0\u5e28\0\u5e84\0\u5ee0"+ + "\0\u5f3c\0\u5f98\0\u5ff4\0\u6050\0\u60ac\0\u6108\0\u6164\0\u61c0"+ + "\0\u621c\0\u6278\0\u62d4\0\u6330\0\u638c\0\u63e8\0\u6444\0\u64a0"+ + "\0\u64fc\0\u6558\0\u65b4\0\u6610\0\u666c\0\u66c8\0\u6724\0\u6780"+ + "\0\u67dc\0\u6838\0\u6894\0\u68f0\0\u694c\0\u69a8\0\u6a04\0\u6a60"+ + "\0\u6abc\0\u6b18\0\u6b74\0\u6bd0\0\u6c2c\0\u6c88\0\u6ce4\0\u6d40"+ + "\0\u6d9c\0\u6df8\0\u6e54\0\u6eb0\0\u6f0c\0\u6f68\0\u6fc4\0\u7020"+ + "\0\u707c\0\u70d8\0\u7134\0\u7190\0\u71ec\0\u7248\0\u72a4\0\u7300"+ + "\0\u735c\0\u73b8\0\u7414\0\u7470\0\u74cc\0\u7528\0\u7584\0\u75e0"+ + "\0\u763c\0\u7698\0\u76f4\0\u7750\0\u09b4\0\u77ac\0\u7808\0\u7864"+ + "\0\u78c0\0\u791c\0\u7978\0\u79d4\0\u09b4\0\u7a30\0\u7a8c\0\u7ae8"+ + "\0\u7b44\0\u7ba0\0\u7bfc\0\u7c58\0\u7cb4\0\u7d10\0\u7d6c\0\u7dc8"+ + "\0\u7e24\0\u7e80\0\u7edc\0\u7f38\0\u7f94\0\u7ff0\0\u804c\0\u80a8"+ + "\0\u8104\0\u8160\0\u81bc\0\u8218\0\u8274\0\u82d0\0\u832c\0\u8388"+ + "\0\u83e4\0\u8440\0\u849c\0\u84f8\0\u8554\0\u85b0\0\u860c\0\u8668"+ + "\0\u86c4\0\u8720\0\u877c\0\u87d8\0\u8834\0\u8890\0\u88ec\0\u8948"+ + "\0\u89a4\0\u8a00\0\u8a5c\0\u8ab8\0\u8b14\0\u8b70\0\u8bcc\0\u8c28"+ + "\0\u8c84\0\u8ce0\0\u8d3c\0\u8d98\0\u8df4\0\u8e50\0\u8eac\0\u8f08"+ + "\0\u8f64\0\u8fc0\0\u901c\0\u9078\0\u90d4\0\u9130\0\u918c\0\u91e8"+ + "\0\u9244\0\u92a0\0\u92fc\0\u9358\0\u93b4\0\u9410\0\u946c\0\u94c8"+ + "\0\u9524\0\u9580\0\u95dc\0\u9638\0\u9694\0\u96f0\0\u974c\0\u97a8"+ + "\0\u9804\0\u9860\0\u98bc\0\u9918\0\u9974\0\u99d0\0\u9a2c\0\u9a88"+ + "\0\u9ae4\0\u9b40\0\u9b9c\0\u9bf8\0\u9c54\0\u9cb0\0\u9d0c\0\u9d68"+ + "\0\u9dc4\0\u9e20\0\u9e7c\0\u9ed8\0\u9f34\0\u9f90\0\u9fec\0\ua048"+ + "\0\ua0a4\0\ua100\0\ua15c\0\ua1b8\0\ua214\0\ua270\0\ua2cc\0\ua328"+ + "\0\ua384\0\ua3e0\0\ua43c\0\u76f4\0\ua498\0\ua4f4\0\ua550\0\ua5ac"+ + "\0\ua608\0\ua664\0\ua6c0\0\ua71c\0\ua778\0\ua7d4\0\ua830\0\ua88c"+ + "\0\ua8e8\0\ua944\0\ua9a0\0\ua9fc\0\uaa58\0\uaab4\0\uab10\0\uab6c"+ + "\0\uabc8\0\uac24\0\uac80\0\uacdc\0\uad38\0\uad94\0\uadf0\0\uae4c"+ + "\0\uaea8\0\uaf04\0\uaf60\0\uafbc\0\ub018\0\ub074\0\ub0d0\0\ub12c"+ + "\0\ub188\0\ub1e4\0\ub240\0\ub29c\0\ub2f8\0\ub354\0\ub3b0\0\ub40c"+ + "\0\ub468\0\ub4c4\0\ub520\0\ub57c\0\ub5d8\0\ub634\0\ub690\0\ub6ec"+ + "\0\ub748\0\ub7a4\0\ub800\0\ub85c\0\ub8b8\0\ub914\0\ub970\0\ub9cc"+ + "\0\uba28\0\uba84\0\ubae0\0\ubb3c\0\ubb98\0\ubbf4\0\ubc50\0\ubcac"+ + "\0\ubd08\0\ubd64\0\ubdc0\0\ube1c\0\ube78\0\ubed4\0\ubf30\0\ubf8c"+ + "\0\ubfe8\0\uc044\0\uc0a0\0\uc0fc\0\uc158\0\uc1b4\0\uc210\0\uc26c"+ + "\0\uc2c8\0\uc324\0\uc380\0\uc3dc\0\uc438\0\uc494\0\uc4f0\0\uc54c"+ + "\0\uc5a8\0\uc604\0\uc660\0\uc6bc\0\uc718\0\uc774\0\uc7d0\0\uc82c"+ + "\0\uc888\0\uc8e4\0\uc940\0\uc99c\0\uc9f8\0\uca54\0\ucab0\0\ucb0c"+ + "\0\ucb68\0\ucbc4\0\ucc20\0\ucc7c\0\u9e20\0\uccd8\0\ucd34\0\ucd90"+ + "\0\ucdec\0\uce48\0\ucea4\0\ucf00\0\ucf5c\0\ucfb8\0\ud014\0\ud070"+ + "\0\ud0cc\0\ud128\0\ud184\0\ud1e0\0\ud23c\0\ud298\0\ud2f4\0\ud350"+ + "\0\ud3ac\0\ud408\0\ud464\0\ud4c0\0\ud51c\0\ud578\0\ud5d4\0\ud630"+ + "\0\ud68c\0\ud6e8\0\ud744\0\ud7a0\0\ud7fc\0\ud858\0\ud8b4\0\ud910"+ + "\0\ud96c\0\ud9c8\0\uda24\0\uda80\0\udadc\0\udb38\0\udb94\0\udbf0"+ + "\0\udc4c\0\udca8\0\udd04\0\udd60\0\uddbc\0\ude18\0\ude74\0\uded0"+ + "\0\udf2c\0\udf88\0\udfe4\0\ue040\0\ue09c\0\ue0f8\0\ue154\0\ue1b0"+ + "\0\ue20c\0\ue268\0\ue2c4\0\ue320\0\ue37c\0\ue3d8\0\ue434\0\ue490"+ + "\0\ue4ec\0\ue548\0\ue5a4\0\ue600\0\ue65c\0\ue6b8\0\ue714\0\ue770"+ + "\0\ue7cc\0\ue828\0\ue884\0\ue8e0\0\ue93c\0\ue998\0\ue9f4\0\uea50"+ + "\0\ueaac\0\ueb08\0\ueb64\0\uebc0\0\uec1c\0\uec78\0\uecd4\0\ued30"+ + "\0\ued8c\0\uede8\0\uee44\0\ueea0\0\ueefc\0\uef58\0\uefb4\0\uf010"+ + "\0\uf06c\0\uf0c8\0\u66c8\0\uf124\0\uf180\0\uf1dc\0\uf238\0\uf294"+ + "\0\uf2f0\0\uf34c\0\uf3a8\0\uf404\0\uf460\0\uf4bc\0\uf518\0\uf574"+ + "\0\uf5d0\0\uf62c\0\uf688\0\uf6e4\0\uf740\0\u1c08\0\uf79c\0\uf7f8"+ + "\0\uf854\0\u0114\0\uf8b0\0\uf90c\0\uf968\0\uf9c4\0\ufa20\0\ufa7c"+ + "\0\ufad8\0\ufb34\0\ufb90\0\ufbec\0\ufc48\0\ufca4\0\ufd00\0\ufd5c"+ + "\0\ufdb8\0\ufe14\0\ufe70\0\ufecc\0\uff28\0\uff84\0\uffe0\1\74"+ + "\1\230\1\364\0\u8ce0\1\u0150\1\u01ac\1\u0208\1\u0264\1\u02c0"+ + "\1\u031c\1\u0378\1\u03d4\1\u0430\1\u048c\1\u04e8\1\u0544\1\u05a0"+ + "\1\u05fc\1\u0658\1\u06b4\1\u0710\1\u076c\1\u07c8\1\u0824\1\u0880"+ + "\1\u08dc\1\u0938\1\u0994\1\u09f0\1\u0a4c\1\u0aa8\1\u0b04\1\u0b60"+ + "\1\u0bbc\1\u0c18\0\ue37c\1\u0c74\0\ue490\1\u0cd0\1\u0d2c\1\u0d88"+ + "\1\u0de4\1\u0e40\1\u0e9c\1\u0ef8\1\u0f54\1\u0fb0\1\u100c\1\u1068"+ + "\1\u10c4\1\u1120\1\u117c\1\u11d8\1\u1234\1\u1290\1\u12ec\1\u1348"+ + "\1\u13a4\1\u1400\1\u145c\1\u14b8\1\u1514\1\u1570\1\u15cc\1\u1628"+ + "\1\u1684\1\u16e0\1\u173c\1\u1798\1\u17f4\1\u1850\1\u18ac\1\u1908"+ + "\1\u1964\1\u19c0\1\u1a1c\0\u09b4\1\u1a78\1\u1ad4\1\u1b30\1\u1b8c"+ + "\1\u1be8\1\u1c44\1\u1ca0\1\u1cfc\1\u1d58\1\u1db4\1\u1e10\1\u1e6c"+ + "\1\u1ec8\1\u1f24\1\u1f80\1\u1fdc\1\u2038\1\u2094\1\u20f0\1\u214c"+ + "\1\u21a8\1\u2204\1\u2260\1\u22bc\1\u2318\1\u2374\1\u23d0\1\u242c"+ + "\1\u2488\1\u24e4\1\u2540\1\u259c\1\u25f8\1\u2654\1\u26b0\1\u270c"+ + "\1\u2768\1\u27c4\1\u2820\1\u287c\1\u28d8\1\u2934\1\u2990\1\u29ec"+ + "\1\u2a48\1\u2aa4\0\u763c\1\u2b00\1\u2b5c\1\u2bb8\1\u2c14\1\u2c70"+ + "\1\u2ccc\1\u2d28\1\u2d84\1\u2de0\1\u2e3c\1\u2e98\1\u2ef4\0\u9f34"+ + "\1\u2f50\1\u2fac\1\u3008\1\u3064\1\u30c0\1\u311c\1\u3178\1\u31d4"+ + "\1\u3230\1\u328c\1\u32e8\1\u3344\1\u33a0\1\u33fc\1\u3458\1\u34b4"+ + "\1\u3510\1\u356c\1\u35c8\1\u3624\1\u3680\1\u36dc\1\u3738\1\u3794"+ + "\1\u37f0\1\u384c\1\u38a8\1\u3904\1\u3960\1\u39bc\1\u3a18\1\u3a74"+ + "\1\u3ad0\1\u3b2c\1\u3b88\1\u3be4\1\u3c40\1\u3c9c\1\u3cf8\1\u3d54"+ + "\1\u3db0\1\u3e0c\1\u3e68\1\u3ec4\1\u3f20\1\u3f7c\1\u3fd8\1\u4034"+ + "\1\u4090\1\u40ec\1\u4148\1\u41a4\1\u4200\1\u425c\1\u42b8\1\u4314"+ + "\1\u4370\1\u43cc\1\u4428\1\u4484\1\u44e0\1\u453c\1\u4598\1\u45f4"+ + "\1\u4650\1\u46ac\1\u4708\1\u4764\1\u47c0\1\u481c\1\u4878"; private static int [] zzUnpackRowMap() { - int [] result = new int[887]; + int [] result = new int[943]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -237,2415 +245,2584 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { return j; } - /** + /** * The transition table of the DFA */ private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\4\1\5\1\6\1\7\1\10\1\7\1\11\1\12"+ - "\1\13\1\14\1\15\1\16\1\17\1\20\1\21\1\22"+ - "\1\23\1\24\1\25\1\26\1\27\1\30\1\31\1\32"+ - "\1\33\1\34\1\35\1\36\1\37\1\40\1\41\1\42"+ - "\1\43\1\7\1\6\1\44\1\45\1\46\1\47\1\50"+ - "\1\51\1\33\1\52\1\53\1\54\1\55\1\56\1\57"+ - "\2\4\1\34\1\60\1\41\1\33\1\61\1\62\1\41"+ - "\1\63\1\64\1\65\1\66\1\67\1\70\1\71\1\7"+ - "\1\72\1\73\1\74\1\75\1\76\1\77\1\100\1\101"+ - "\1\102\1\103\1\104\1\105\1\106\2\6\2\7\3\6"+ - "\1\107\2\7\1\34\1\41\1\110\1\111\12\112\1\113"+ - "\30\112\1\114\5\112\1\115\14\112\1\116\2\112\1\117"+ - "\42\112\12\120\1\121\30\120\1\122\22\120\1\123\2\120"+ - "\1\124\42\120\7\4\1\0\17\4\11\0\3\4\2\0"+ - "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ - "\2\4\1\0\37\4\4\0\1\4\6\6\1\0\10\6"+ - "\1\125\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\3\126\1\7\1\126\1\7\1\127\1\0"+ - "\1\126\1\127\3\126\1\130\4\126\1\131\4\126\11\0"+ - "\1\126\1\7\1\126\2\0\2\126\1\7\2\0\1\131"+ - "\1\130\1\132\1\126\1\0\3\126\4\0\2\126\1\0"+ - "\7\126\1\7\17\126\2\7\4\126\2\7\4\0\1\4"+ - "\5\6\1\133\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\134\35\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\135\2\6\1\136"+ - "\12\6\1\137\5\6\13\0\1\41\20\0\1\41\103\0"+ - "\1\4\6\6\1\0\1\6\1\140\12\6\1\141\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\4\6\1\142\12\6"+ - "\11\0\1\4\1\6\1\143\2\0\1\144\2\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ - "\1\145\1\6\1\146\2\6\1\147\3\6\1\150\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\2\6\1\151\1\6"+ - "\1\152\1\6\1\153\10\6\11\0\1\4\1\154\1\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\10\6\1\155\1\6\1\156\4\6\11\0"+ - "\1\4\2\6\2\0\1\157\2\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\160\2\6"+ - "\1\151\3\6\1\161\1\6\1\162\1\6\1\163\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\164\1\6"+ - "\1\165\1\6\1\166\2\6\1\167\1\6\1\170\1\171"+ - "\3\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\172\1\0\1\173\22\6\1\174\13\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\175\1\6\1\176\4\6\1\177"+ - "\3\6\1\200\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\201\6\6\1\151\7\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\202\1\6\1\203\1\204\1\205\1\6"+ - "\1\206\1\207\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\1\210\1\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\4\6\1\211\5\6\1\212\1\213\3\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\3\6\1\151\3\6\1\214"+ - "\1\215\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\216"+ - "\3\6\1\201\1\6\1\217\1\220\1\6\1\221\5\6"+ - "\11\0\1\4\2\6\2\0\1\222\1\223\1\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\1\6\1\224\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\6\1\225\5\6\1\226\7\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\227\1\6\1\230\4\6\1\231"+ - "\3\6\1\232\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\33\0\1\233\134\0\1\41"+ - "\267\0\1\41\1\0\1\234\16\0\1\235\62\0\27\236"+ - "\1\237\3\236\1\240\4\236\1\241\2\236\1\0\70\236"+ - "\34\0\1\33\134\0\1\33\126\0\1\41\6\0\1\41"+ - "\74\0\40\45\1\242\2\45\1\243\1\244\67\45\1\4"+ - "\6\6\1\0\14\6\1\245\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\3\6\1\246\13\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\3\126"+ - "\1\7\1\126\1\7\1\127\1\0\1\126\1\127\3\126"+ - "\1\130\4\126\1\131\4\126\11\0\1\126\1\7\1\247"+ - "\2\0\2\126\1\7\2\0\1\131\1\130\1\132\1\126"+ - "\1\0\3\126\4\0\2\126\1\0\7\126\1\7\17\126"+ - "\2\7\1\247\3\126\2\7\54\0\1\51\63\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\1\250\1\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\251\4\6\1\252"+ - "\16\6\4\0\1\4\5\6\1\253\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\1\254\1\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\1\6\1\255\3\6\1\256\5\6\1\151\23\6\7\0"+ - "\1\132\1\0\1\132\33\0\1\132\5\0\1\132\30\0"+ - "\1\132\17\0\2\132\4\0\2\132\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\257\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\6\1\260\3\6\1\261\6\6"+ - "\1\262\22\6\4\0\7\4\1\0\1\263\1\264\1\4"+ - "\1\265\1\4\1\266\4\4\1\267\1\270\3\4\11\0"+ - "\3\4\2\0\3\4\1\271\1\0\2\4\1\0\1\4"+ - "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\1\4"+ - "\6\6\1\0\3\6\1\272\4\6\1\273\6\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\3\6\1\274\3\6\1\275"+ - "\1\276\3\6\1\277\2\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\300\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\3\6"+ - "\1\301\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\2\6\1\302\1\303\1\304"+ - "\3\6\1\305\2\6\1\306\1\6\1\307\1\310\20\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\14\6\1\311\22\6"+ - "\4\0\1\4\5\6\1\312\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\1\313\1\314\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ - "\1\315\6\6\1\316\1\317\2\6\1\320\1\6\1\321"+ - "\1\6\1\322\12\6\4\0\1\4\5\6\1\323\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ - "\1\324\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\5\6\1\325\1\326\1\6\1\327\2\6"+ - "\1\330\1\331\22\6\4\0\1\4\3\6\1\306\2\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\151\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\5\6\1\332\6\6\1\333\22\6\4\0"+ - "\1\4\5\6\1\334\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\335\3\6"+ - "\1\336\6\6\1\337\22\6\4\0\1\4\5\6\1\340"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ - "\1\341\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\1\342\1\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\5\6\1\343\10\6\1\344\20\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\1\345\1\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\151\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\3\6\1\346\7\6\1\347"+ - "\23\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\350"+ - "\3\6\1\351\2\6\1\352\3\6\1\353\22\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\354\35\6\4\0"+ - "\1\4\5\6\1\355\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\10\6\1\356\26\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\5\6\1\357\2\6"+ - "\1\360\3\6\1\151\22\6\4\0\1\4\5\6\1\361"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\362\3\6\1\363\6\6\1\364"+ - "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\1\365\1\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\12\6\1\366\4\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\5\6\1\367\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\5\6\1\370\31\6\136\0"+ - "\1\41\134\0\1\41\12\112\1\0\30\112\1\0\5\112"+ - "\1\0\14\112\1\0\2\112\1\0\42\112\13\0\1\371"+ - "\53\0\1\372\76\0\1\373\170\0\1\374\135\0\1\375"+ - "\42\0\12\120\1\0\30\120\1\0\22\120\1\0\2\120"+ - "\1\0\42\120\13\0\1\376\53\0\1\377\133\0\1\u0100"+ - "\135\0\1\u0101\42\0\1\4\6\6\1\0\3\6\1\u0102"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\7\126\1\0\17\126\11\0\3\126"+ - "\2\0\3\126\2\0\2\126\1\0\1\126\1\0\3\126"+ - "\4\0\2\126\1\0\37\126\4\0\3\126\1\u0103\1\126"+ - "\1\u0103\1\126\1\u0104\17\126\10\0\1\u0104\1\126\1\u0103"+ - "\1\126\2\0\2\126\1\u0103\2\0\2\126\1\0\1\126"+ - "\1\0\3\126\4\0\2\126\1\0\7\126\1\u0103\17\126"+ - "\2\u0103\4\126\2\u0103\4\0\7\126\1\0\12\126\1\u0105"+ - "\4\126\11\0\3\126\2\0\3\126\2\0\1\u0105\1\126"+ - "\1\0\1\126\1\0\3\126\4\0\2\126\1\0\37\126"+ - "\4\0\7\126\1\0\5\126\1\u0105\11\126\11\0\3\126"+ - "\2\0\3\126\2\0\1\126\1\u0105\1\0\1\126\1\0"+ - "\3\126\4\0\2\126\1\0\37\126\4\0\3\126\1\132"+ - "\1\126\1\132\1\u0106\1\0\1\126\1\u0106\1\u0107\2\126"+ - "\1\u0107\11\126\11\0\1\126\1\132\1\126\2\0\2\126"+ - "\1\132\2\0\1\126\1\u0107\1\0\1\u0107\1\0\3\126"+ - "\4\0\2\126\1\0\7\126\1\132\17\126\2\132\4\126"+ - "\2\132\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\4\6\1\u0108"+ - "\12\6\1\u0109\17\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\11\6\1\u010a\3\6\1\u010b\21\6\4\0\1\4\3\6"+ - "\1\u010c\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\4\6\1\u010d\6\6\1\u010e"+ - "\5\6\1\u010f\15\6\4\0\1\4\5\6\1\u0110\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\1\6\1\344\35\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\1\6\1\260\16\6\1\151\16\6\4\0\1\4"+ - "\6\6\1\0\11\6\1\u0111\3\6\1\u0112\1\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u0113\1\0\12\6\1\u0114"+ - "\24\6\4\0\1\4\6\6\1\0\1\u0115\3\6\1\u0116"+ - "\4\6\1\u0117\4\6\1\u0118\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\13\6\1\151\1\150\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u0119\12\6\1\157\2\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\6\1\u011a\2\6\1\201"+ - "\1\u011b\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ - "\1\u011c\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\7\6"+ - "\1\u011d\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\11\6"+ - "\1\u011e\5\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u011f"+ - "\13\6\1\u0120\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\1\6\1\151\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\4\6\1\u0121\12\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\35\6\1\u0119\1\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\151\36\6\4\0\1\4\6\6\1\0"+ - "\16\6\1\u0122\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\5\6"+ - "\1\151\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\2\6"+ - "\1\u011e\1\6\1\151\12\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\1\6\1\151\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\15\6\1\u0123\1\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\u0124\36\6\4\0"+ - "\1\4\6\6\1\0\4\6\1\210\12\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\12\6\1\u0125\24\6\4\0"+ - "\1\4\6\6\1\0\11\6\1\u0126\5\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\23\6\1\151"+ - "\13\6\4\0\1\4\6\6\1\0\4\6\1\u0127\10\6"+ - "\1\u0119\1\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ - "\1\u0128\13\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\7\6"+ - "\1\u0129\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\16\6"+ - "\1\u012a\11\0\1\4\2\6\2\0\1\6\1\u012b\1\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\5\6\1\u012c\11\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\u012d\13\6\1\u012e\2\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\3\6\1\u012f\13\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\5\6\1\151\1\6\1\u011e\7\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\11\6\1\u0130\1\6\1\u0131\1\6"+ - "\1\u0132\1\u0133\11\0\1\4\2\6\2\0\1\u0134\2\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\15\6\1\u0135\1\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\12\6\1\u0136\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\u0137\36\6\4\0\1\4\6\6"+ - "\1\0\1\u0138\3\6\1\u0139\12\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\151\16\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\3\6\1\u013a\13\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\7\6\1\u013b\7\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\16\6\1\u0118\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\u013c\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\10\6\1\u013d\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\u013e\3\6\1\u013f\1\u0140\1\u0127\1\u0141\2\6\1\u0142"+ - "\3\6\1\u0143\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ - "\1\u0144\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ - "\1\u0145\13\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ - "\1\201\13\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\13\6"+ - "\1\u0124\3\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ - "\1\u0146\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\1\u0124\36\6\4\0\1\4\6\6\1\0\1\u0147\16\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\3\6\1\u0148\13\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\7\6\1\u0149\7\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\10\6\1\u014a\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u014b\15\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\6\6\1\151\10\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\14\6\1\u014c\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\1\6\1\u014d\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\6\1\u014e\15\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\u014f\16\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\1\151\3\6\1\u0150\12\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\151\3\6\1\u0151\11\6"+ - "\1\151\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\13\6\1\u0152"+ - "\3\6\11\0\1\4\1\6\1\151\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\34\0\10\41\74\0\33\u0153\1\u0154"+ - "\7\u0153\1\0\117\u0153\1\u0155\3\u0153\1\u0154\7\u0153\1\0"+ - "\75\u0153\1\u0156\4\u0153\1\236\1\u0153\1\236\2\u0153\1\236"+ - "\4\u0153\1\236\2\u0153\1\236\3\u0153\1\u0157\4\u0153\1\236"+ - "\1\u0158\1\u0159\1\0\3\236\1\u0158\17\u0153\1\236\10\u0153"+ - "\1\u0158\17\u0153\1\u0158\1\u0156\1\u0159\4\u0153\1\u0156\4\u0153"+ - "\5\243\1\45\4\243\1\45\1\243\1\45\2\243\1\45"+ - "\4\243\1\45\2\243\1\45\3\243\1\45\4\243\2\45"+ - "\1\u015a\1\0\4\45\17\243\1\45\10\243\1\45\17\243"+ - "\2\45\1\u015a\4\243\1\45\44\243\1\u015b\3\243\1\u015c"+ - "\67\243\1\4\6\6\1\0\5\6\1\u015d\11\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u015e\1\0\37\6\4\0"+ - "\3\126\4\u015f\1\0\3\u015f\6\126\1\u015f\2\126\1\u015f"+ - "\2\126\11\0\1\126\1\u015f\1\126\2\0\1\126\2\u015f"+ - "\2\0\2\126\1\0\1\u015f\1\0\3\126\4\0\2\126"+ - "\1\0\1\126\2\u015f\1\126\1\u015f\2\126\1\u015f\17\126"+ - "\2\u015f\4\126\2\u015f\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\14\6\1\306\22\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\14\6\1\u0160\22\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\20\6\1\u0161\16\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\u0162\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\13\6\1\151\1\6\1\151\21\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\13\6\1\326\23\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\11\6\1\u0163\25\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\17\6\1\u0123\4\6\1\u0161\12\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\5\6\1\u0164\31\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\4\6\1\u0162\32\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\10\6\1\u0165\26\6\4\0"+ - "\1\4\5\6\1\u0166\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\1\6\1\u0167\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\306"+ - "\23\6\4\0\7\4\1\0\1\4\1\u0168\15\4\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ - "\4\4\1\u0169\1\u016a\1\4\1\u016b\7\4\11\0\3\4"+ - "\2\0\3\4\2\0\2\4\1\0\1\4\1\0\3\4"+ - "\4\0\2\4\1\0\37\4\4\0\7\4\1\0\2\4"+ - "\1\u016c\1\4\1\u016d\12\4\11\0\3\4\2\0\3\4"+ - "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ - "\1\0\37\4\4\0\7\4\1\0\3\4\1\u016e\13\4"+ - "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ - "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ - "\1\0\4\4\1\u016f\12\4\11\0\3\4\2\0\3\4"+ - "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ - "\1\0\37\4\4\0\7\4\1\0\7\4\1\u0170\7\4"+ - "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ - "\1\0\3\4\4\0\2\4\1\0\37\4\14\0\1\u0171"+ - "\1\u0172\1\0\1\u0173\1\0\1\u0174\4\0\1\u0175\1\u0176"+ - "\24\0\1\271\63\0\1\4\6\6\1\0\1\6\1\u0177"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u0144"+ - "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\16\6\1\u013e"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u0178\1\6"+ - "\1\u0179\6\6\1\u017a\4\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\u017b\2\6\1\u017c\4\6\1\u017d\6\6\11\0"+ - "\1\4\2\6\2\0\1\6\1\u017e\1\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\u017f"+ - "\1\6\1\0\37\6\4\0\1\4\6\6\1\0\4\6"+ - "\1\u0127\12\6\11\0\1\4\2\6\2\0\1\6\1\u0180"+ - "\1\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u0181\1\6\1\u0182\13\6\11\0\1\4"+ - "\2\6\2\0\1\6\1\u0183\1\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\3\6\1\u0184\2\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\3\6\1\151"+ - "\33\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0185"+ - "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\5\6\1\u0186"+ - "\31\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\10\6\1\u0187"+ - "\26\6\4\0\1\4\3\6\1\151\2\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u0188"+ - "\35\6\4\0\1\4\5\6\1\u0189\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\15\6\1\u018a\21\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\4\6\1\u018b\15\6"+ - "\1\151\14\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\2\6"+ - "\1\u018c\16\6\1\u018d\15\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\14\6\1\u018e\22\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\10\6\1\u018f\26\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\13\6\1\u0190\3\6\1\u0110\17\6\4\0\1\4"+ - "\3\6\1\u0191\2\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\u0192\35\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\1\6\1\u0193\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\6\1\151\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\10\6\1\u0162\26\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0194\22\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0195\22\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\u0196\35\6"+ - "\4\0\1\4\3\6\1\u0197\2\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\1\u0198\1\u0199\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\3\6\1\u0190\4\6\1\u019a\2\6\1\u019b\5\6\1\u019c"+ - "\15\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u019d"+ - "\35\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\5\6\1\u019e"+ - "\31\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\21\6\1\u010f"+ - "\15\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\10\6\1\u019f"+ - "\26\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\1\u019d\1\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\5\6\1\u01a0\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\4\6\1\u01a1\11\6\1\u01a2"+ - "\1\u01a3\1\u01a4\1\u01a5\15\6\4\0\1\4\3\6\1\u01a6"+ - "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\u01a7\23\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\1\u01a8\1\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\24\6\1\u01a9\12\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\17\6\1\u01aa\17\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\u01ab\35\6\4\0"+ - "\1\4\6\6\1\0\14\6\1\u01ac\2\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\21\6\1\u01ad\15\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\24\6\1\151\12\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\6\1\151\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\35\6\1\u0110\1\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\u01ae\23\6\4\0\1\4"+ - "\3\6\1\u01af\2\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\u01b0\13\6"+ - "\1\151\21\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\2\6"+ - "\1\u01b1\10\6\1\u0190\23\6\4\0\1\4\3\6\1\u01b2"+ - "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\2\6\1\u01b3\2\6\1\u01b4\1\u01b5"+ - "\5\6\1\u01b6\22\6\4\0\1\4\5\6\1\u01b7\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\u01b8"+ - "\1\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u01b9\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\21\6\1\u0197\15\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\u01ba\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\15\6\1\u01bb\21\6\4\0\1\4\5\6\1\u01bc"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\24\6\1\u0161\12\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\5\6\1\u01bd\31\6\4\0\1\4\3\6\1\u01be\2\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\20\6\1\u01bf\10\6\1\151\5\6\4\0\1\4\3\6"+ - "\1\151\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\u01c0\5\6\1\151"+ - "\15\6\4\0\1\4\3\6\1\151\2\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\13\6\1\u01c1\23\6\4\0\1\4\5\6\1\u01c2\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u01c3"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\5\6\1\u01c4\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\2\6\1\u01c5\11\6\1\u01c6\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u01c7\22\6\21\0\1\u01c8\141\0"+ - "\1\u01c9\177\0\1\u01ca\135\0\1\u01cb\57\0\1\u01cc\141\0"+ - "\1\u01cd\177\0\1\u01ce\135\0\1\u01cf\42\0\1\4\6\6"+ - "\1\0\4\6\1\u01d0\12\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\3\126\1\u0103"+ - "\1\126\1\u0103\1\126\1\0\5\126\1\130\4\126\1\131"+ - "\4\126\11\0\1\126\1\u0103\1\126\2\0\2\126\1\u0103"+ - "\2\0\1\131\1\130\1\0\1\126\1\0\3\126\4\0"+ - "\2\126\1\0\7\126\1\u0103\17\126\2\u0103\4\126\2\u0103"+ - "\7\0\1\u0103\1\0\1\u0103\33\0\1\u0103\5\0\1\u0103"+ - "\30\0\1\u0103\17\0\2\u0103\4\0\2\u0103\4\0\3\126"+ - "\1\u01d1\1\126\1\u01d1\1\126\1\u01d2\17\126\10\0\1\u01d2"+ - "\1\126\1\u01d1\1\126\2\0\2\126\1\u01d1\2\0\2\126"+ - "\1\0\1\126\1\0\3\126\4\0\2\126\1\0\7\126"+ - "\1\u01d1\17\126\2\u01d1\4\126\2\u01d1\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\5\6\1\u01d3\6\6\1\u01d4\22\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\10\6\1\u01d5\26\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\3\6\1\u01d6\12\6\1\100"+ - "\20\6\4\0\1\4\5\6\1\u01d7\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\24\6\1\u01d8\12\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\5\6\1\u01d3\31\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\1\u01d9\1\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\5\6\1\u01da\31\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\151\23\6\4\0"+ - "\1\4\6\6\1\0\3\6\1\u01db\4\6\1\u01dc\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\7\6\1\u01dd\7\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u01de\15\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\6\6\1\u01df\10\6"+ - "\11\0\1\4\2\6\2\0\1\46\2\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\u01e0"+ - "\36\6\4\0\1\4\6\6\1\0\12\6\1\u01e1\4\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\10\6\1\u01dc\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\10\6\1\u01e2\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\4\6\1\151\12\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\5\6\1\u01e3\11\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u01e4\15\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\10\6\1\u0144\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\16\6\1\u01e5\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\151\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\1\6\1\u01e6\15\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\7\6\1\220\7\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\12\6\1\u01e7\4\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\1\6\1\u01e8\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\1\u01e9\1\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u0144\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u01ea\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\10\6\1\u01eb\6\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\1\151\1\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\11\6\1\u01ec\5\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u0152\1\0\37\6\4\0\1\4\6\6\1\0\6\6"+ - "\1\u01ed\4\6\1\u01ee\3\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\6\6\1\u01ef\10\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\3\6\1\u011e\13\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u01f0\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\7\6\1\u01f1\7\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\1\6\1\u01f2\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\10\6\1\u01f3\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\6\1\u01e5\3\6\1\u01f4\11\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u01f5\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\10\6\1\u01f6\6\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u01f7\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\1\u011e\1\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\4\6\1\u01f8\12\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\11\6\1\u01f9\5\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\3\6\1\u01fa\13\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\u01fb\14\6\1\u013e\1\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\26\6\1\151\10\6"+ - "\4\0\1\4\6\6\1\0\5\6\1\u01fc\11\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\11\6\1\u01fd\5\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\6\6\1\223\10\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\6\6\1\u01fe\10\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\6\1\151\15\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\11\6\1\u01ff\5\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\4\6\1\u0200\4\6\1\u01f9"+ - "\5\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\u0201"+ - "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u011e"+ - "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\1\6\1\u0202\1\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\151"+ - "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\23\6"+ - "\1\u0203\13\6\4\0\1\4\6\6\1\0\1\u0204\12\6"+ - "\1\u0205\2\6\1\u0206\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\7\6\1\u01d0\27\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u0127\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\u0207\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\6\6\1\u0127\10\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\7\6\1\u0208\7\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u0209\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\12\6\1\u020a\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\13\6\1\u01d0\3\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\3\6\1\u020b\13\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\12\6\1\u020c\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u020d\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ - "\1\u0120\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\33\u0153\1\240\7\u0153\1\0"+ - "\120\u0153\3\236\1\u0157\4\236\3\u0153\1\0\75\u0153\1\236"+ - "\25\u0153\1\u0154\5\u0153\1\236\1\u0153\1\0\3\u0153\1\236"+ - "\30\u0153\1\236\17\u0153\2\236\5\u0153\1\236\4\u0153\33\0"+ - "\1\u0154\100\0\5\u0153\1\u0156\25\u0153\1\u0154\5\u0153\1\u0156"+ - "\1\u0153\1\0\3\u0153\1\u0156\30\u0153\1\u0156\17\u0153\2\u0156"+ - "\5\u0153\1\u0156\7\u0153\4\u020e\1\u0153\3\u020e\6\u0153\1\u020e"+ - "\2\u0153\1\u020e\6\u0153\1\240\5\u0153\1\u020e\1\u0153\1\0"+ - "\2\u0153\2\u020e\5\u0153\1\u020e\14\u0153\2\u020e\1\u0153\1\u020e"+ - "\2\u0153\1\u020e\17\u0153\2\u020e\4\u0153\2\u020e\4\u0153\3\243"+ - "\4\u020f\1\243\3\u020f\6\243\1\u020f\2\243\1\u020f\13\243"+ - "\1\u015b\1\u020f\2\243\1\u015c\1\243\2\u020f\5\243\1\u020f"+ - "\14\243\2\u020f\1\243\1\u020f\2\243\1\u020f\17\243\2\u020f"+ - "\4\243\2\u020f\47\243\1\0\70\243\1\4\6\6\1\0"+ - "\12\6\1\u013e\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u0210\3\6\1\u0211\6\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\3\126"+ - "\4\u015f\1\0\3\u015f\2\126\1\u0212\3\126\1\u015f\1\u0213"+ - "\1\126\1\u015f\2\126\11\0\1\126\1\u015f\1\126\2\0"+ - "\1\126\2\u015f\2\0\1\u0213\1\u0212\1\0\1\u015f\1\0"+ - "\3\126\4\0\2\126\1\0\1\126\2\u015f\1\126\1\u015f"+ - "\2\126\1\u015f\17\126\2\u015f\4\126\2\u015f\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\22\6\1\u0214\14\6\4\0\1\4"+ - "\5\6\1\u019d\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\15\6\1\151\21\6\4\0\1\4\5\6"+ - "\1\u0215\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\5\6\1\u019d\31\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\21\6\1\u0216\15\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ - "\1\u0217\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\5\6\1\u0218\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\7\4\1\0\2\4\1\266\14\4"+ - "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ - "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ - "\1\0\1\u0219\16\4\11\0\3\4\2\0\3\4\2\0"+ - "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ - "\37\4\4\0\7\4\1\0\3\4\1\u021a\2\4\1\u021b"+ - "\10\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ - "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\4\0"+ - "\7\4\1\0\7\4\1\u021c\7\4\11\0\3\4\2\0"+ - "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ - "\2\4\1\0\37\4\4\0\7\4\1\0\1\u021d\3\4"+ - "\1\u016f\12\4\11\0\3\4\2\0\3\4\2\0\2\4"+ - "\1\0\1\4\1\0\3\4\4\0\2\4\1\0\37\4"+ - "\4\0\7\4\1\0\11\4\1\u021e\5\4\11\0\3\4"+ - "\2\0\3\4\2\0\2\4\1\0\1\4\1\0\3\4"+ - "\4\0\2\4\1\0\37\4\4\0\7\4\1\0\4\4"+ - "\1\u021b\12\4\11\0\3\4\2\0\3\4\2\0\2\4"+ - "\1\0\1\4\1\0\3\4\4\0\2\4\1\0\37\4"+ - "\4\0\7\4\1\0\1\u021d\16\4\11\0\3\4\2\0"+ - "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ - "\2\4\1\0\37\4\4\0\7\4\1\0\14\4\1\u021f"+ - "\2\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ - "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\15\0"+ - "\1\u0220\136\0\1\u0221\1\u0222\1\0\1\u0223\126\0\1\u0224"+ - "\1\0\1\u0225\132\0\1\u0226\134\0\1\u0227\136\0\1\u0228"+ - "\114\0\1\4\6\6\1\0\7\6\1\u0229\7\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\6\1\u022a\15\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\16\6\1\151\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\4\6\1\u022b\12\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\10\6\1\u022c\3\6\1\u022d\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\4\6\1\u022e\11\6"+ - "\1\u0208\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\11\6\1\u022f"+ - "\5\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0230"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0231"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\5\6\1\u0232"+ - "\11\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\26\6"+ - "\1\u0233\10\6\4\0\1\4\6\6\1\0\15\6\1\u0234"+ - "\1\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0235"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\7\6"+ - "\1\u0236\27\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\13\6"+ - "\1\u0190\23\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ - "\1\u0190\33\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\6"+ - "\1\u0237\35\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\13\6"+ - "\1\u0238\23\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\10\6"+ - "\1\u0239\26\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ - "\1\u023a\5\6\1\u023b\23\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\5\6\1\u023c\31\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\3\6\1\u023d\33\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\3\6\1\u023e\14\6\1\u023f\16\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\4\6\1\u0240\32\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\15\6\1\u01bf\21\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\6\6\1\151\30\6\4\0\1\4"+ - "\5\6\1\u0241\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\u0242\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u0162\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\15\6\1\u0243\21\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\u0244\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\3\6\1\302\33\6\4\0\1\4\5\6\1\151"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\13\6\1\u0162\23\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\4\6\1\u0245\6\6\1\u0246\23\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\u0247\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\4\6\1\u0248\32\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\2\6\1\u0249\34\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\151\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\3\6\1\u024a\33\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\4\6\1\u024b\32\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\u024c\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\5\6\1\u024d\31\6\4\0\1\4\5\6"+ - "\1\u024e\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\5\6\1\u024f"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\5\6\1\u0216\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ - "\1\u0250\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\5\6\1\u0251\31\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\14\6\1\u0252\22\6\4\0\1\4\3\6\1\u0253\2\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\17\6\1\u0197\5\6\1\151\11\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\u0254\23\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\4\6\1\u0245\32\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\6\6\1\u0162\30\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\10\6\1\u0255\26\6\4\0"+ - "\1\4\6\6\1\0\7\6\1\u0256\7\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\15\6\1\u0257\21\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\u0258\1\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\5\6\1\u0259\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\305\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\u025a\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\1\6\1\u025b\3\6\1\u025c\31\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\14\6\1\u025d\22\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\4\6\1\u025e\32\6\4\0\1\4"+ - "\5\6\1\u025f\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\13\6\1\u0260\5\6\1\u0239\15\6\4\0"+ - "\1\4\5\6\1\u0261\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\u0262\23\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\21\6\1\151\15\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\1\u0197\1\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\u0263\1\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\20\6\1\u0236\16\6\4\0\1\4\3\6\1\u0264"+ - "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\20\6\1\u0265\1\u0266\15\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\14\6\1\u0267\22\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\u01b0\35\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\15\6\1\u0268\21\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\u0269\1\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\10\6\1\u0237\26\6\4\0\1\4"+ - "\6\6\1\0\7\6\1\u0207\7\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\25\6\1\u026a\11\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\14\6\1\u026b\22\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\17\6\1\u026c\17\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\u0236\23\6\15\0\1\u01c9"+ - "\212\0\1\u026d\66\0\1\u026e\164\0\1\u026f\70\0\1\u01cd"+ - "\212\0\1\u0270\66\0\1\u0271\164\0\1\u0272\57\0\3\126"+ - "\1\u01d1\1\126\1\u01d1\1\126\1\0\2\126\1\u0107\2\126"+ - "\1\u0107\11\126\11\0\1\126\1\u01d1\1\126\2\0\2\126"+ - "\1\u01d1\2\0\1\126\1\u0107\1\0\1\u0107\1\0\3\126"+ - "\4\0\2\126\1\0\7\126\1\u01d1\17\126\2\u01d1\4\126"+ - "\2\u01d1\7\0\1\u01d1\1\0\1\u01d1\33\0\1\u01d1\5\0"+ - "\1\u01d1\30\0\1\u01d1\17\0\2\u01d1\4\0\2\u01d1\4\0"+ - "\1\4\3\6\1\u0197\2\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\21\6\1\u0273\15\6\4\0"+ - "\1\4\5\6\1\u0274\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\5\6\1\u0275\21\6\1\u0276\7\6"+ - "\4\0\1\4\3\6\1\u0277\2\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ - "\1\u0278\10\6\1\u0279\1\u027a\21\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u027b\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\21\6\1\u027c\15\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\13\6\1\u027d\23\6\4\0\1\4\6\6"+ - "\1\0\16\6\1\u027e\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\u013e\16\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ - "\1\u027f\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u0280"+ - "\2\6\1\u0281\2\6\1\u0282\10\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u0283\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\10\6\1\u0284\6\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\27\6\1\u0276"+ - "\7\6\4\0\1\4\6\6\1\0\3\6\1\u0285\13\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\16\6\1\u0286\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\4\6\1\u0287\12\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\223\16\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\4\6\1\u0200\1\6\1\u0288\10\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u0289"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u011e"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\1\6\1\u028a\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\5\6\1\157\11\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\10\6\1\151\6\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\2\6\1\151\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\7\6\1\u028b\7\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\4\6\1\201\12\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\1\6\1\u01d0\15\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\23\6\1\151\13\6"+ - "\4\0\1\4\6\6\1\0\7\6\1\u028c\7\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u028d\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\1\151\2\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\1\6\1\u0115\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\11\6\1\u028e\5\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\7\6\1\u01e3\7\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\14\6\1\u028f\2\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\1\6\1\u0290\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\1\u01ec\2\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\7\6"+ - "\1\u0291\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u0292"+ - "\16\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\10\6\1\u0293"+ - "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0294"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\1\6\1\u0295\1\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0296"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u0297"+ - "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u0298"+ - "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0299"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\274"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\157"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0119"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u01ec"+ - "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\150"+ - "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0144"+ - "\6\6\1\u029a\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\10\6\1\u029b\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\12\6\1\151\24\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\u029c\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\151"+ - "\1\6\1\0\7\6\1\151\27\6\4\0\1\4\6\6"+ - "\1\0\6\6\1\u029d\10\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\14\6\1\u0119\2\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\1\6\1\u013e\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\u0256"+ - "\1\6\1\0\37\6\4\0\3\u0153\4\236\1\u0153\3\236"+ - "\6\u0153\1\236\2\u0153\1\236\6\u0153\1\240\5\u0153\1\236"+ - "\1\u0153\1\0\2\u0153\2\236\5\u0153\1\236\14\u0153\2\236"+ - "\1\u0153\1\236\2\u0153\1\236\17\u0153\2\236\4\u0153\2\236"+ - "\4\u0153\3\243\4\45\1\243\3\45\6\243\1\45\2\243"+ - "\1\45\13\243\1\u015b\1\45\2\243\1\u015c\1\243\2\45"+ - "\5\243\1\45\14\243\2\45\1\243\1\45\2\243\1\45"+ - "\17\243\2\45\4\243\2\45\4\243\1\4\6\6\1\0"+ - "\10\6\1\u011e\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\13\6\1\u029e\3\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\7\126\1\0\12\126"+ - "\1\u029f\4\126\11\0\3\126\2\0\3\126\2\0\1\u029f"+ - "\1\126\1\0\1\126\1\0\3\126\4\0\2\126\1\0"+ - "\37\126\4\0\7\126\1\0\5\126\1\u029f\11\126\11\0"+ - "\3\126\2\0\3\126\2\0\1\126\1\u029f\1\0\1\126"+ - "\1\0\3\126\4\0\2\126\1\0\37\126\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\1\u0240\1\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\10\6\1\u02a0\26\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\u0162\35\6\4\0\1\4\3\6"+ - "\1\302\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\3\6\1\u02a1\7\6\1\u0246\1\6\1\u02a2"+ - "\21\6\4\0\7\4\1\0\3\4\1\u021a\13\4\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ - "\2\4\1\u02a3\14\4\11\0\3\4\2\0\3\4\2\0"+ - "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ - "\37\4\4\0\7\4\1\0\1\4\1\u02a3\15\4\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ - "\10\4\1\u02a4\6\4\11\0\3\4\2\0\3\4\2\0"+ - "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ - "\37\4\4\0\7\4\1\0\1\4\1\u021a\15\4\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ - "\5\4\1\u02a5\11\4\11\0\3\4\2\0\3\4\2\0"+ - "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ - "\37\4\4\0\7\4\1\0\15\4\1\u02a6\1\4\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\16\0\1\u0174\131\0"+ - "\1\u02a7\136\0\1\u02a8\2\0\1\u02a9\134\0\1\u02aa\124\0"+ - "\1\u02ab\3\0\1\u0227\140\0\1\u02ac\126\0\1\u02a9\127\0"+ - "\1\u02ab\147\0\1\u02ad\107\0\1\4\6\6\1\0\14\6"+ - "\1\u02ae\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\5\6"+ - "\1\u02af\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\11\6"+ - "\1\151\5\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\12\6"+ - "\1\u02b0\4\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u013e"+ - "\1\0\12\6\1\151\24\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u02b1\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u027e"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u02b2"+ - "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\1\6\1\151\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u02b3\15\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\u02b4\16\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\u02b5\1\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\16\6\1\u0208\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\11\6\1\151\25\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\6\6\2\151\27\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\6\1\u02b6\35\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\20\6\1\u02b7\16\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\5\6\1\u0162\31\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\306\23\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\15\6\1\u02b8\21\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\22\6\1\151\14\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\10\6\1\u02b9\26\6\4\0\1\4"+ - "\5\6\1\u0236\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\16\6\1\151\20\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\15\6\1\u010c\21\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\4\6\1\u02ba\32\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u02bb\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\5\6\1\u02bc\31\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\353\35\6\4\0\1\4\5\6"+ - "\1\344\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\1\6\1\u02bd\35\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\14\6\1\u0110\22\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\3\6\1\u02be\33\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\u02bf"+ - "\1\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\1\6\1\u02c0\35\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\10\6\1\u0217\26\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\10\6\1\u02c1\26\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\31\6\1\u02c2\5\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\1\6\1\u02c3\35\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\16\6\1\u0240\20\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\1\6\1\u02c4\35\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\2\6\1\u02c5\34\6\4\0\1\4\3\6\1\u02c6\2\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\3\6\1\u02c7\2\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u02c8"+ - "\16\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ - "\1\151\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\1\6\1\344\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\31\6\1\u02c9"+ - "\5\6\4\0\1\4\5\6\1\u02ca\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\11\6\1\151\3\6"+ - "\1\u0197\21\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\1\u02cb\1\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\u02cc"+ - "\23\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u0273"+ - "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\31\6\1\151"+ - "\5\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u02cd"+ - "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\1\6\1\u02ce\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\4\6\1\151\32\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\3\6\1\u02cf\33\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\1\260\1\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\5\6\1\u019d\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\5\6\1\u02d0\31\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\5\6\1\u02d1\31\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\u0110\35\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\6\6\1\u0255\30\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\15\6\1\u0197\21\6"+ - "\4\0\1\4\3\6\1\u02d2\2\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\21\6\1\u0239\15\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\6\6\1\u02d3\30\6"+ - "\36\0\1\u02d4\117\0\1\u01c9\51\0\1\u026d\44\0\1\u026f"+ - "\1\u02d5\4\u026f\1\u02d5\17\u026f\3\u02d5\1\u026f\1\u02d5\2\0"+ - "\2\u02d5\1\0\2\u026f\2\0\3\u026f\1\0\1\u02d5\2\u026f"+ - "\1\u02d5\1\u026f\1\0\1\u02d5\1\u026f\5\u02d5\2\u026f\1\u02d5"+ - "\37\u026f\2\0\1\u02d5\33\0\1\u02d6\117\0\1\u01cd\51\0"+ - "\1\u0270\44\0\1\u0272\1\u02d7\4\u0272\1\u02d7\17\u0272\3\u02d7"+ - "\1\u0272\1\u02d7\2\0\2\u02d7\1\0\2\u0272\2\0\3\u0272"+ - "\1\0\1\u02d7\2\u0272\1\u02d7\1\u0272\1\0\1\u02d7\1\u0272"+ - "\5\u02d7\2\u0272\1\u02d7\37\u0272\2\0\1\u02d7\1\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\6\1\344\35\6\4\0\1\4"+ - "\5\6\1\302\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\u02d8\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\30\6\1\u01e9\6\6\4\0\1\4\5\6\1\u02d9\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\14\6\1\u02da\22\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\u02db"+ - "\1\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\13\6\1\u02dc\23\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\5\6\1\u02dd\31\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\15\6\1\u02ba\21\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\2\6\1\u0161\34\6\4\0\1\4\5\6\1\u0237\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\157"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\223"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u02de"+ - "\1\6\1\u02df\13\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u02e0\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\12\6\1\u02e1\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\10\6\1\u02e2\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\2\6\1\u02e3\14\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u028e\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\1\6\1\u0124\1\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ - "\1\u0207\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ - "\1\u02e4\13\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\12\6\1\u02e5\24\6\4\0\1\4\6\6\1\0\10\6"+ - "\1\u02e6\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u02e7"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u02e8"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u02e9"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\11\6\1\u013e"+ - "\5\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\13\6\1\151"+ - "\3\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u02ea"+ - "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\u02eb\11\6"+ - "\1\u0290\4\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\36\6\1\151\4\0\1\4\6\6\1\0"+ - "\12\6\1\u0142\4\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\223\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\6\1\u02ec\15\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u02ed\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\5\6\1\210\11\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\5\6\1\u02ee\11\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u02ef\1\0\37\6\4\0\1\4\6\6\1\0\7\6"+ - "\1\u029b\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u02f0"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\15\6\1\u013e"+ - "\1\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u02f1"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u02f2"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\15\6"+ - "\1\u02f3\21\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\14\6"+ - "\1\u02f4\22\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ - "\1\u02f5\25\6\4\0\7\4\1\0\7\4\1\u02a3\7\4"+ - "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ - "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ - "\1\0\12\4\1\u02f6\4\4\11\0\3\4\2\0\3\4"+ - "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ - "\1\0\37\4\4\0\7\4\1\0\16\4\1\u02f7\11\0"+ - "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ - "\3\4\4\0\2\4\1\0\37\4\17\0\1\u02a8\132\0"+ - "\1\u02f8\132\0\1\u02f8\142\0\1\u02f9\124\0\1\u02a8\137\0"+ - "\1\u02fa\143\0\1\u02fb\106\0\1\4\6\6\1\0\7\6"+ - "\1\u02fc\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ - "\1\u02fd\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\1\6\1\u02fe\1\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ - "\1\u02ff\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ - "\1\u01c3\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u0300"+ - "\5\6\1\151\10\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\u022d\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u0301\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\17\6\1\u0197\17\6\4\0\1\4\5\6\1\u0302\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\14\6"+ - "\1\u0303\22\6\4\0\1\4\5\6\1\u0304\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\u0305"+ - "\23\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\1\u0198\1\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\15\6\1\u0306\21\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\1\6\1\u0307\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\6\1\326\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\10\6\1\u0308\26\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\3\6\1\u0309\33\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\20\6\1\151\16\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\4\6\1\u0197\32\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\13\6\1\302\23\6\4\0\1\4"+ - "\5\6\1\u030a\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\3\6"+ - "\1\u030b\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\1\u02c2\1\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\36\6\1\151\4\0"+ - "\1\4\5\6\1\u02d9\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u02de\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\5\6\1\u030c\31\6\4\0\1\4"+ - "\3\6\1\u030d\2\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\3\6\1\151\33\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\2\6\1\u030e\34\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\u01c2\35\6"+ - "\4\0\1\4\5\6\1\u030f\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\u0310\35\6\4\0"+ - "\1\4\5\6\1\u0311\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\10\6\1\u02d1\26\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\15\6\1\u0312\21\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\6\1\u025b\35\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\15\6\1\u0313\21\6\36\0\1\u026f"+ - "\133\0\1\u0272\101\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ - "\1\u0314\7\6\1\u0315\1\u0316\14\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\u0317\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\151\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\2\6"+ - "\1\u0318\34\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ - "\1\u0314\7\6\1\u0315\1\u0316\1\6\1\u0319\12\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\u010e\23\6\4\0"+ - "\1\4\6\6\1\0\5\6\1\u031a\11\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\2\6\1\151\14\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\16\6\1\u031b\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\u031c\11\6\1\u031d"+ - "\10\6\1\u031e\13\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\1\6\1\u031f\1\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\4\6"+ - "\1\u0116\12\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\16\6"+ - "\1\u031b\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\12\6\1\u031d\10\6\1\u031e\13\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\33\6\1\u013e\3\6\4\0\1\4"+ - "\6\6\1\0\13\6\1\u013e\3\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\2\6\1\u0152\14\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\10\6\1\u022f\6\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\11\6\1\u0320\5\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\1\6\1\u0321\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u0152\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\10\6\1\u0322\6\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\1\6\1\u0323\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\15\6\1\151\1\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\163\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\6\1\u0324\15\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\3\6\1\u0325\13\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\7\6\1\u0326\7\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\7\6\1\u0327\7\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\5\6\1\u025e\31\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\32\6\1\u0197\4\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\20\6\1\u0197\16\6\4\0\7\4\1\0\1\u021b"+ - "\16\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ - "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\4\0"+ - "\7\4\1\0\14\4\1\u02a3\2\4\11\0\3\4\2\0"+ - "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ - "\2\4\1\0\37\4\23\0\1\u02f8\136\0\1\u0328\137\0"+ - "\1\u0329\105\0\1\4\6\6\1\0\11\6\1\u032a\5\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\12\6\1\u0124"+ - "\24\6\4\0\1\4\6\6\1\0\5\6\1\u013e\11\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\15\6\1\u0124\1\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\14\6\1\u032b\2\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\1\6\1\u032c\15\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\10\6\1\u032d"+ - "\26\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u032e"+ - "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\4\6\1\u032f"+ - "\32\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\17\6\1\151"+ - "\17\6\4\0\1\4\5\6\1\u0330\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\1\6\1\255\35\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\4\6\1\u0331\32\6"+ - "\4\0\1\4\5\6\1\u01bf\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\15\6\1\u0332\21\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\5\6\1\u0333\31\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\u01bf\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\u0334\35\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\1\6\1\u0197\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\17\6\1\u0161\17\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\11\6\1\u0161\25\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\10\6\1\u0335\26\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\14\6\1\u0336\22\6\4\0\1\4\5\6\1\u0337"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\37\6\4\0\1\4\5\6\1\326\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ - "\1\u0338\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\1\u0339\1\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u033a"+ - "\21\6\4\0\1\4\3\6\1\u033b\2\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\5\6\1\u033c\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u033d\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\10\6\1\u033e\6\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\1\6\1\u033f\15\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\1\6\1\210\15\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\12\6\1\u0340\4\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\1\u0341\16\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\3\6\1\u0342\13\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\1\u0119\36\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\u0343\36\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u0341\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\10\6\1\u0119\6\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\1\u0344\5\6"+ - "\1\0\1\u0345\16\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\14\6\1\u029b\2\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\14\0\1\u02a9\147\0\1\u02f8"+ - "\107\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\u0207\1\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\1\6\1\u0346\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\u0347\16\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\u02d1\35\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\14\6\1\u0348\22\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\13\6\1\u033b\23\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\6\6\1\u0237\30\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\24\6\1\u0349\12\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\24\6\1\u0110\12\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\15\6\1\u034a\21\6\4\0\1\4\3\6"+ - "\1\u034b\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\34\6\1\u034c\2\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\5\6\1\u0110\31\6\4\0"+ - "\1\4\3\6\1\u034d\2\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\13\6\1\u027b\23\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\u034e\35\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\151\35\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\1\6\1\u0269\35\6\4\0"+ - "\1\4\5\6\1\u034f\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\14\6\1\151\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\4\6\1\u0285\12\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u0350\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\14\6\1\u0351\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\14\6\1\u020c\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\6\6\1\u013e\10\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u0352\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\10\6\1\u0353\6\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\1\6\1\u0354\15\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\14\6\1\u0355\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\14\6\1\u0356\2\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\3\6\1\u0197\33\6\4\0\1\4"+ - "\5\6\1\u0357\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ - "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ - "\2\6\1\0\1\6\1\u0358\35\6\4\0\1\4\5\6"+ - "\1\u0359\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\5\6\1\u035a\31\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\1\6\1\u035b\35\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\10\6\1\u035c\26\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\25\6\1\151\11\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\26\6\1\151\10\6\4\0\1\4\6\6\1\0"+ - "\7\6\1\u035d\7\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\1\6\1\u0119\15\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\1\6\1\u035e\1\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\13\6\1\u035f\3\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\2\6\1\u0360\3\6\1\151\10\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\1\222"+ - "\2\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\5\6"+ - "\1\u0110\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\u0361\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\3\6\1\151\33\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\20\6\1\u0362\16\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\2\6\1\u0363\34\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\16\6\1\310\20\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\15\6\1\u0161\21\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\u0124\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u0364"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0365"+ - "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0366"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\14\6"+ - "\1\u0367\22\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\6"+ - "\1\u0368\35\6\4\0\1\4\6\6\1\0\17\6\11\0"+ - "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ - "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\15\6"+ - "\1\u0369\21\6\4\0\1\4\6\6\1\0\3\6\1\u036a"+ - "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\u036b"+ - "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u011a"+ - "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\37\6\4\0\1\4\5\6\1\u0166\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\10\6\1\u036c"+ - "\26\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u036d"+ - "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\1\6\1\u036e\1\0\37\6"+ - "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\1\6\1\u036f\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\15\6\1\u0370\21\6\4\0"+ - "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\15\6\1\u0371\21\6\4\0"+ - "\1\4\6\6\1\0\5\6\1\u027f\11\6\11\0\1\4"+ - "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ - "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ - "\1\4\6\6\1\0\16\6\1\u0372\11\0\1\4\2\6"+ - "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ - "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\21\6\1\u0373\15\6\4\0\1\4"+ - "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\1\6\1\u0274\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ - "\1\0\1\6\1\u0374\15\6\11\0\1\4\2\6\2\0"+ - "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ - "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\5\6"+ - "\1\u0375\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\4\6\1\u0376\12\6\11\0\1\4\2\6\2\0\3\6"+ - "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ - "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ - "\1\0\13\6\1\u0377\23\6\4\0\1\4\6\6\1\0"+ - "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ - "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ - "\1\223\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ - "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ - "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ - "\15\6\1\302\21\6\4\0"; + "\1\4\1\5\1\6\1\7\1\10\1\7\1\11\1\12"+ + "\1\13\1\14\1\15\1\16\1\17\1\20\1\21\1\22"+ + "\1\23\1\24\1\25\1\26\1\27\1\30\1\31\1\32"+ + "\1\33\1\34\1\35\1\36\1\37\1\40\1\41\1\42"+ + "\1\43\1\7\1\6\1\44\1\45\1\46\1\47\1\50"+ + "\1\51\1\33\1\52\1\53\1\54\1\55\1\56\1\57"+ + "\2\4\1\34\1\60\1\41\1\33\1\61\1\62\1\41"+ + "\1\63\1\64\1\65\1\66\1\67\1\70\1\71\1\7"+ + "\1\72\1\73\1\74\1\75\1\76\1\77\1\100\1\101"+ + "\1\102\1\103\1\104\1\105\1\106\2\6\2\7\3\6"+ + "\1\107\2\7\1\34\1\41\1\110\1\111\12\112\1\113"+ + "\30\112\1\114\5\112\1\115\14\112\1\116\2\112\1\117"+ + "\42\112\12\120\1\121\30\120\1\122\22\120\1\123\2\120"+ + "\1\124\42\120\7\4\1\0\17\4\11\0\3\4\2\0"+ + "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ + "\2\4\1\0\37\4\4\0\1\4\6\6\1\0\10\6"+ + "\1\125\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\3\126\1\7\1\126\1\7\1\127\1\0"+ + "\1\126\1\127\3\126\1\130\4\126\1\131\4\126\11\0"+ + "\1\126\1\7\1\126\2\0\2\126\1\7\2\0\1\131"+ + "\1\130\1\132\1\126\1\0\3\126\4\0\2\126\1\0"+ + "\7\126\1\7\17\126\2\7\4\126\2\7\4\0\1\4"+ + "\5\6\1\133\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\1\6\1\134\35\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\13\6\1\135\2\6\1\136"+ + "\12\6\1\137\5\6\13\0\1\41\20\0\1\41\103\0"+ + "\1\4\6\6\1\0\1\6\1\140\12\6\1\141\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\4\6\1\142\12\6"+ + "\11\0\1\4\1\6\1\143\2\0\1\144\2\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ + "\1\145\1\6\1\146\2\6\1\147\3\6\1\150\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\2\6\1\151\1\6"+ + "\1\152\1\6\1\153\10\6\11\0\1\4\1\154\1\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\10\6\1\155\1\6\1\156\4\6\11\0"+ + "\1\4\2\6\2\0\1\157\2\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\160\2\6"+ + "\1\151\3\6\1\161\1\162\1\163\1\6\1\164\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\165\1\6"+ + "\1\166\1\6\1\167\2\6\1\170\1\6\1\171\1\172"+ + "\3\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ + "\1\173\1\0\1\174\22\6\1\175\13\6\4\0\1\4"+ + "\6\6\1\0\1\6\1\176\1\6\1\177\4\6\1\200"+ + "\3\6\1\201\2\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\202\6\6\1\151\7\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\203\1\6\1\204\1\205\1\206\1\6"+ + "\1\207\1\210\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\1\211\1\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\4\6\1\212\5\6\1\213\1\214\3\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\3\6\1\151\3\6\1\215"+ + "\1\216\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\217"+ + "\3\6\1\202\1\6\1\220\1\221\1\6\1\222\5\6"+ + "\11\0\1\4\2\6\2\0\1\223\1\224\1\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\1\6\1\225\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\226\5\6\1\227\1\6\1\202\5\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\230\1\6\1\231"+ + "\4\6\1\232\3\6\1\233\2\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\33\0\1\234"+ + "\134\0\1\41\267\0\1\41\1\0\1\235\16\0\1\236"+ + "\62\0\27\237\1\240\3\237\1\241\4\237\1\242\2\237"+ + "\1\0\70\237\34\0\1\33\134\0\1\33\126\0\1\41"+ + "\6\0\1\41\74\0\40\45\1\243\2\45\1\244\1\245"+ + "\67\45\1\4\6\6\1\0\14\6\1\246\2\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\3\6\1\247\13\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\3\126\1\7\1\126\1\7\1\127\1\0\1\126"+ + "\1\127\3\126\1\130\4\126\1\131\4\126\11\0\1\126"+ + "\1\7\1\250\2\0\2\126\1\7\2\0\1\131\1\130"+ + "\1\132\1\126\1\0\3\126\4\0\2\126\1\0\7\126"+ + "\1\7\17\126\2\7\1\250\3\126\2\7\54\0\1\51"+ + "\63\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\1\251\1\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\252"+ + "\4\6\1\253\16\6\4\0\1\4\5\6\1\254\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\255"+ + "\1\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\256\2\6\1\257\1\260\5\6"+ + "\1\151\23\6\7\0\1\132\1\0\1\132\33\0\1\132"+ + "\5\0\1\132\30\0\1\132\17\0\2\132\4\0\2\132"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\1\6\1\261\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\262"+ + "\3\6\1\263\6\6\1\264\22\6\4\0\7\4\1\0"+ + "\1\265\1\266\1\4\1\267\1\4\1\270\4\4\1\271"+ + "\1\272\3\4\11\0\3\4\2\0\3\4\1\273\1\0"+ + "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ + "\37\4\4\0\1\4\6\6\1\0\3\6\1\274\4\6"+ + "\1\275\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\276\1\6\1\277\3\6\1\300\1\301\3\6\1\302"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\303"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\3\6\1\304\2\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\2\6\1\305\1\306\1\307\3\6\1\310\2\6"+ + "\1\311\1\6\1\312\1\313\20\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\314\22\6\4\0\1\4\5\6"+ + "\1\315\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\316\1\317\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\5\6\1\320\6\6\1\321"+ + "\1\322\2\6\1\323\1\6\1\324\1\6\1\325\12\6"+ + "\4\0\1\4\5\6\1\326\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\1\6\1\327\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\330\1\331\1\6\1\332\2\6\1\333\1\334\22\6"+ + "\4\0\1\4\3\6\1\311\2\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\10\6"+ + "\1\151\26\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\335\6\6\1\336\22\6\4\0\1\4\5\6\1\337"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\340\3\6\1\341\6\6\1\342"+ + "\22\6\4\0\1\4\5\6\1\343\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\344\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\1\345\1\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\5\6\1\346"+ + "\10\6\1\347\20\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\1\350\1\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\151\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\3\6\1\351\7\6\1\352\23\6\4\0\1\4"+ + "\5\6\1\353\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\1\6\1\354\3\6\1\355"+ + "\2\6\1\356\3\6\1\357\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\360\35\6\4\0\1\4\5\6"+ + "\1\361\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\4\6\1\311\3\6\1\362\26\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\5\6\1\363\2\6"+ + "\1\364\3\6\1\151\22\6\4\0\1\4\5\6\1\365"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\366\3\6\1\367\6\6\1\370"+ + "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\1\371\1\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\12\6\1\372\4\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\5\6\1\373\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\5\6\1\374\31\6\136\0"+ + "\1\41\134\0\1\41\12\112\1\0\30\112\1\0\5\112"+ + "\1\0\14\112\1\0\2\112\1\0\42\112\13\0\1\375"+ + "\53\0\1\376\76\0\1\377\170\0\1\u0100\135\0\1\u0101"+ + "\42\0\12\120\1\0\30\120\1\0\22\120\1\0\2\120"+ + "\1\0\42\120\13\0\1\u0102\53\0\1\u0103\133\0\1\u0104"+ + "\135\0\1\u0105\42\0\1\4\6\6\1\0\3\6\1\u0106"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\7\126\1\0\17\126\11\0\3\126"+ + "\2\0\3\126\2\0\2\126\1\0\1\126\1\0\3\126"+ + "\4\0\2\126\1\0\37\126\4\0\3\126\1\u0107\1\126"+ + "\1\u0107\1\126\1\u0108\17\126\10\0\1\u0108\1\126\1\u0107"+ + "\1\126\2\0\2\126\1\u0107\2\0\2\126\1\0\1\126"+ + "\1\0\3\126\4\0\2\126\1\0\7\126\1\u0107\17\126"+ + "\2\u0107\4\126\2\u0107\4\0\7\126\1\0\12\126\1\u0109"+ + "\4\126\11\0\3\126\2\0\3\126\2\0\1\u0109\1\126"+ + "\1\0\1\126\1\0\3\126\4\0\2\126\1\0\37\126"+ + "\4\0\7\126\1\0\5\126\1\u0109\11\126\11\0\3\126"+ + "\2\0\3\126\2\0\1\126\1\u0109\1\0\1\126\1\0"+ + "\3\126\4\0\2\126\1\0\37\126\4\0\3\126\1\132"+ + "\1\126\1\132\1\u010a\1\0\1\126\1\u010a\1\u010b\2\126"+ + "\1\u010b\11\126\11\0\1\126\1\132\1\126\2\0\2\126"+ + "\1\132\2\0\1\126\1\u010b\1\0\1\u010b\1\0\3\126"+ + "\4\0\2\126\1\0\7\126\1\132\17\126\2\132\4\126"+ + "\2\132\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\4\6\1\u010c"+ + "\12\6\1\u010d\17\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\11\6\1\u010e\3\6\1\u010f\21\6\4\0\1\4\3\6"+ + "\1\u0110\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\2\6\1\u0111\1\6\1\u0112"+ + "\6\6\1\u0113\5\6\1\u0114\15\6\4\0\1\4\5\6"+ + "\1\u0115\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\347\35\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\262\16\6\1\151\16\6"+ + "\4\0\1\4\6\6\1\0\11\6\1\u0116\3\6\1\u0117"+ + "\1\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u0118\1\0"+ + "\12\6\1\u0119\24\6\4\0\1\4\6\6\1\0\1\u011a"+ + "\3\6\1\u011b\4\6\1\u011c\4\6\1\u011d\11\0\1\4"+ + "\2\6\2\0\1\6\1\u011e\1\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\13\6\1\151\1\150"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u011f"+ + "\12\6\1\157\2\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\u0120\2\6\1\202\1\u0121\11\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\10\6\1\u0122\6\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\7\6\1\u0123\7\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\11\6\1\u0124\5\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\1\u0125\13\6\1\u0126\2\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\151\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\4\6\1\u0127\12\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\1\u0128\36\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\35\6"+ + "\1\u011f\1\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\151"+ + "\36\6\4\0\1\4\6\6\1\0\16\6\1\u0129\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\5\6\1\151\11\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\2\6\1\u0124\1\6\1\151"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ + "\1\151\1\0\37\6\4\0\1\4\6\6\1\0\15\6"+ + "\1\u012a\1\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\u012b\36\6\4\0\1\4\6\6\1\0"+ + "\16\6\1\151\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\4\6"+ + "\1\211\12\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\12\6\1\u012c\24\6\4\0\1\4\6\6\1\0\11\6"+ + "\1\u012d\5\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\23\6\1\151\13\6\4\0\1\4\6\6"+ + "\1\0\4\6\1\u012e\10\6\1\u011f\1\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\3\6\1\u012f\13\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\7\6\1\u0130\7\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\16\6\1\u0131\11\0\1\4\2\6"+ + "\2\0\1\6\1\u0132\1\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\5\6\1\u0133\11\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\u0134\13\6\1\u0135\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\3\6\1\u0136\13\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\5\6\1\151\1\6"+ + "\1\u0124\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\11\6"+ + "\1\u0137\1\6\1\u0138\1\6\1\u0139\1\u013a\11\0\1\4"+ + "\2\6\2\0\1\u013b\2\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\15\6\1\u013c\1\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\12\6\1\u013d\4\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\u013e"+ + "\36\6\4\0\1\4\6\6\1\0\1\u013f\3\6\1\u0140"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\151\16\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\3\6\1\u0141\13\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\7\6\1\u0142\7\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\16\6\1\u011d\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\14\6\1\u0143\2\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\10\6\1\u0144\6\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\u0145\3\6\1\u0146\1\u0147"+ + "\1\u012e\1\u0148\2\6\1\u0149\3\6\1\u014a\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\14\6\1\u014b\2\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\3\6\1\u014c\13\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\3\6\1\202\13\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\13\6\1\u012b\3\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\10\6\1\u014d\6\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\1\u012b\36\6\4\0\1\4"+ + "\6\6\1\0\1\u014e\16\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\3\6\1\u014f\13\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\7\6\1\u0150\7\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\10\6\1\u0151\1\u0152\5\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\1\6\1\u0153\15\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\6\6\1\151\10\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\14\6\1\u0154\2\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\1\6\1\u0155\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\u0156\15\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\u0157\16\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\u0158\3\6\1\u0159\12\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\151\3\6\1\u015a\11\6\1\151\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\13\6\1\u015b\3\6\11\0\1\4"+ + "\1\6\1\151\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\34\0\10\41\74\0\33\u015c\1\u015d\7\u015c\1\0\117\u015c"+ + "\1\u015e\3\u015c\1\u015d\7\u015c\1\0\75\u015c\1\u015f\4\u015c"+ + "\1\237\1\u015c\1\237\2\u015c\1\237\4\u015c\1\237\2\u015c"+ + "\1\237\3\u015c\1\u0160\4\u015c\1\237\1\u0161\1\u0162\1\0"+ + "\3\237\1\u0161\17\u015c\1\237\10\u015c\1\u0161\17\u015c\1\u0161"+ + "\1\u015f\1\u0162\4\u015c\1\u015f\4\u015c\5\244\1\45\4\244"+ + "\1\45\1\244\1\45\2\244\1\45\4\244\1\45\2\244"+ + "\1\45\3\244\1\45\4\244\2\45\1\u0163\1\0\4\45"+ + "\17\244\1\45\10\244\1\45\17\244\2\45\1\u0163\4\244"+ + "\1\45\44\244\1\u0164\3\244\1\u0165\67\244\1\4\6\6"+ + "\1\0\5\6\1\u0166\11\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\1\6\1\u0167\1\0\37\6\4\0\3\126\4\u0168\1\0"+ + "\3\u0168\6\126\1\u0168\2\126\1\u0168\2\126\11\0\1\126"+ + "\1\u0168\1\126\2\0\1\126\2\u0168\2\0\2\126\1\0"+ + "\1\u0168\1\0\3\126\4\0\2\126\1\0\1\126\2\u0168"+ + "\1\126\1\u0168\2\126\1\u0168\17\126\2\u0168\4\126\2\u0168"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\14\6\1\311\22\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0169\22\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\20\6\1\u016a\16\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\u016b\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\151\1\6"+ + "\1\151\21\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\13\6"+ + "\1\331\23\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ + "\1\u016c\25\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\21\6"+ + "\1\151\15\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\17\6"+ + "\1\u012a\4\6\1\u016a\12\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\5\6\1\u016d\31\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\4\6\1\u016b\32\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\10\6\1\u016e\26\6\4\0\1\4\5\6\1\u016f"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\1\6\1\u0170\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\13\6\1\311\23\6\4\0\7\4"+ + "\1\0\1\4\1\u0171\15\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\4\0\7\4\1\0\4\4\1\u0172\1\u0173"+ + "\1\4\1\u0174\7\4\11\0\3\4\2\0\3\4\2\0"+ + "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ + "\37\4\4\0\7\4\1\0\2\4\1\u0175\1\4\1\u0176"+ + "\12\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ + "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\4\0"+ + "\7\4\1\0\3\4\1\u0177\13\4\11\0\3\4\2\0"+ + "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ + "\2\4\1\0\37\4\4\0\7\4\1\0\4\4\1\u0178"+ + "\12\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ + "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\4\0"+ + "\7\4\1\0\7\4\1\u0179\7\4\11\0\3\4\2\0"+ + "\3\4\2\0\2\4\1\0\1\4\1\0\3\4\4\0"+ + "\2\4\1\0\37\4\14\0\1\u017a\1\u017b\1\0\1\u017c"+ + "\1\0\1\u017d\4\0\1\u017e\1\u017f\24\0\1\273\63\0"+ + "\1\4\6\6\1\0\1\6\1\u0180\15\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\12\6\1\u014b\4\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\1\6\1\u0181"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\16\6\1\u0145\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\u0182\1\6\1\162\6\6\1\u0183\4\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\u0184\2\6\1\u0185"+ + "\4\6\1\u0186\6\6\11\0\1\4\2\6\2\0\1\6"+ + "\1\u0187\1\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\u0188\1\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\4\6\1\u012e\12\6\11\0\1\4"+ + "\2\6\2\0\1\6\1\u0189\1\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u018a\1\6"+ + "\1\u018b\13\6\11\0\1\4\2\6\2\0\1\6\1\u018c"+ + "\1\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\3\6"+ + "\1\u018d\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\3\6\1\151\33\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u018e\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u018f\1\u0190\31\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\10\6\1\u0191\26\6\4\0\1\4"+ + "\3\6\1\151\2\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\u0192\35\6\4\0\1\4"+ + "\5\6\1\u0193\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u0194\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u0195\15\6\1\151\14\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\2\6\1\u0196\16\6\1\u0197"+ + "\15\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0198"+ + "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\10\6\1\u0199"+ + "\26\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\u019a"+ + "\3\6\1\u0115\17\6\4\0\1\4\3\6\1\u019b\2\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u019c\35\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\1\6\1\u019d\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ + "\1\151\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u016b\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u019e\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u019f\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u01a0\35\6\4\0\1\4\3\6"+ + "\1\u01a1\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\1\u01a2\1\u01a3\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\3\6\1\u019a\4\6"+ + "\1\u01a4\2\6\1\u01a5\5\6\1\u01a6\15\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\u01a7\35\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\5\6\1\u01a8\31\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\21\6\1\u0114\15\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\10\6\1\u01a9\26\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u01a7\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\5\6"+ + "\1\u01aa\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\4\6\1\u01ab\11\6\1\u01ac\1\u01ad\1\u01ae\1\u01af"+ + "\15\6\4\0\1\4\3\6\1\u01b0\2\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\13\6\1\u01b1\23\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\u01b2\1\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\24\6\1\u01b3\12\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\17\6\1\u01b4\17\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\1\6\1\u01b5\35\6\4\0\1\4\6\6\1\0"+ + "\14\6\1\u01b6\2\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\21\6\1\u01b7\15\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\24\6\1\151\12\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ + "\1\151\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\35\6\1\u0115\1\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\13\6\1\u01b8\10\6\1\u01b9\12\6\4\0\1\4\3\6"+ + "\1\u01ba\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\1\6\1\u01bb\13\6\1\151"+ + "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\31\6\1\u01bc"+ + "\5\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\2\6\1\u01bd"+ + "\10\6\1\u019a\23\6\4\0\1\4\3\6\1\u01be\2\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\2\6\1\u01bf\2\6\1\u01c0\1\u01c1\5\6"+ + "\1\u01c2\22\6\4\0\1\4\5\6\1\u01c3\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\u01c4\1\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\14\6\1\257\22\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\21\6\1\u01a1\15\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ + "\1\u01c5\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u01c6\21\6\4\0\1\4\5\6\1\u01c7\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\24\6"+ + "\1\u016a\12\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u01c8\31\6\4\0\1\4\3\6\1\u01c9\2\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\20\6"+ + "\1\u01ca\10\6\1\151\5\6\4\0\1\4\3\6\1\151"+ + "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\13\6\1\u01cb\5\6\1\151\15\6"+ + "\4\0\1\4\3\6\1\u01cc\2\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\13\6"+ + "\1\u01cd\23\6\4\0\1\4\5\6\1\u01ce\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u01cf\15\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\5\6\1\u01d0\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\2\6"+ + "\1\u01d1\11\6\1\u01d2\22\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\14\6\1\u01d3\22\6\21\0\1\u01d4\141\0\1\u01d5"+ + "\177\0\1\u01d6\135\0\1\u01d7\57\0\1\u01d8\141\0\1\u01d9"+ + "\177\0\1\u01da\135\0\1\u01db\42\0\1\4\6\6\1\0"+ + "\4\6\1\u01dc\12\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\3\126\1\u0107\1\126"+ + "\1\u0107\1\126\1\0\5\126\1\130\4\126\1\131\4\126"+ + "\11\0\1\126\1\u0107\1\126\2\0\2\126\1\u0107\2\0"+ + "\1\131\1\130\1\0\1\126\1\0\3\126\4\0\2\126"+ + "\1\0\7\126\1\u0107\17\126\2\u0107\4\126\2\u0107\7\0"+ + "\1\u0107\1\0\1\u0107\33\0\1\u0107\5\0\1\u0107\30\0"+ + "\1\u0107\17\0\2\u0107\4\0\2\u0107\4\0\3\126\1\u01dd"+ + "\1\126\1\u01dd\1\126\1\u01de\17\126\10\0\1\u01de\1\126"+ + "\1\u01dd\1\126\2\0\2\126\1\u01dd\2\0\2\126\1\0"+ + "\1\126\1\0\3\126\4\0\2\126\1\0\7\126\1\u01dd"+ + "\17\126\2\u01dd\4\126\2\u01dd\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\5\6\1\u01df\6\6\1\u01e0\22\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\10\6\1\u01e1\26\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\3\6\1\u01e2\12\6\1\100\20\6"+ + "\4\0\1\4\5\6\1\u01e3\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\5\6\1\u01e4\16\6\1\u01e5"+ + "\12\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\11\6\1\u01e6"+ + "\25\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\5\6\1\u01df"+ + "\31\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\1\u01e7\1\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\5\6\1\u01e8\31\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\151\23\6"+ + "\4\0\1\4\6\6\1\0\3\6\1\u01e9\4\6\1\u01ea"+ + "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\u01eb"+ + "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u01ec"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u01ed"+ + "\10\6\11\0\1\4\2\6\2\0\1\46\2\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ + "\1\u01ee\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\u01ef\36\6\4\0\1\4\6\6\1\0"+ + "\12\6\1\u01f0\4\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\10\6\1\u01ea\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\10\6\1\u01f1\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\12\6\1\u01f2\24\6\4\0\1\4\6\6\1\0"+ + "\4\6\1\151\12\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\5\6\1\u01f3\11\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\u01f4\15\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\10\6\1\u014b\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\16\6\1\u01f5\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\151"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u01f6"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\221"+ + "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u01f7"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\10\6\1\u01f8"+ + "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u01f9\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\1\u01fa\1\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\u014b\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\u01fb\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\10\6\1\u01fc\6\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\151\1\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\11\6\1\u01fd\5\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\1\6\1\u015b\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\3\6\1\u01fe\2\6\1\u01ff\4\6\1\u0200"+ + "\3\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u0201"+ + "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0124"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0202"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\u0203"+ + "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u0204\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\10\6\1\u0205\6\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u01f5\3\6"+ + "\1\u0206\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\u0207\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ + "\1\u0208\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\u0209\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\u0124\1\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u020a"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\11\6\1\u020b"+ + "\5\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u020c"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\u020d\14\6"+ + "\1\u0145\1\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\26\6\1\151\10\6\4\0\1\4\6\6"+ + "\1\0\5\6\1\u020e\11\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\11\6\1\u020f\5\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\6\6\1\224\10\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\6\6\1\u0210\10\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\151\15\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\11\6\1\u0211\5\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\4\6\1\u0212\4\6\1\u020b\5\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\7\6\1\u0213\7\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\4\6\1\u0214\12\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\1\6\1\u0215\1\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\7\6\1\151\7\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\23\6\1\u0216\13\6\4\0"+ + "\1\4\6\6\1\0\1\u0217\12\6\1\u0218\2\6\1\u0219"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\7\6\1\u01dc"+ + "\27\6\4\0\1\4\6\6\1\0\4\6\1\u012e\12\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\14\6\1\u021a\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\6\6\1\u012e\10\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\6\6\1\u021b\10\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\7\6\1\u021c\7\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\4\6\1\u021d\12\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\11\6\1\u021e\1\u021f"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\13\6\1\u01dc"+ + "\3\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u0220"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\11\6\1\u0221"+ + "\5\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u0222"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u0223\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\14\6\1\u0126\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\33\u015c\1\241\7\u015c\1\0\120\u015c\3\237"+ + "\1\u0160\4\237\3\u015c\1\0\75\u015c\1\237\25\u015c\1\u015d"+ + "\5\u015c\1\237\1\u015c\1\0\3\u015c\1\237\30\u015c\1\237"+ + "\17\u015c\2\237\5\u015c\1\237\4\u015c\33\0\1\u015d\100\0"+ + "\5\u015c\1\u015f\25\u015c\1\u015d\5\u015c\1\u015f\1\u015c\1\0"+ + "\3\u015c\1\u015f\30\u015c\1\u015f\17\u015c\2\u015f\5\u015c\1\u015f"+ + "\7\u015c\4\u0224\1\u015c\3\u0224\6\u015c\1\u0224\2\u015c\1\u0224"+ + "\6\u015c\1\241\5\u015c\1\u0224\1\u015c\1\0\2\u015c\2\u0224"+ + "\5\u015c\1\u0224\14\u015c\2\u0224\1\u015c\1\u0224\2\u015c\1\u0224"+ + "\17\u015c\2\u0224\4\u015c\2\u0224\4\u015c\3\244\4\u0225\1\244"+ + "\3\u0225\6\244\1\u0225\2\244\1\u0225\13\244\1\u0164\1\u0225"+ + "\2\244\1\u0165\1\244\2\u0225\5\244\1\u0225\14\244\2\u0225"+ + "\1\244\1\u0225\2\244\1\u0225\17\244\2\u0225\4\244\2\u0225"+ + "\47\244\1\0\70\244\1\4\6\6\1\0\12\6\1\u0145"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u0226"+ + "\3\6\1\u0227\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\3\126\4\u0168\1\0"+ + "\3\u0168\2\126\1\u0228\3\126\1\u0168\1\u0229\1\126\1\u0168"+ + "\2\126\11\0\1\126\1\u0168\1\126\2\0\1\126\2\u0168"+ + "\2\0\1\u0229\1\u0228\1\0\1\u0168\1\0\3\126\4\0"+ + "\2\126\1\0\1\126\2\u0168\1\126\1\u0168\2\126\1\u0168"+ + "\17\126\2\u0168\4\126\2\u0168\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\22\6\1\u022a\14\6\4\0\1\4\5\6\1\u01a7"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\151\21\6\4\0\1\4\5\6\1\u022b\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u01a7\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\21\6"+ + "\1\u022c\15\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\1\6\1\u022d\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\5\6\1\u022e\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\7\4\1\0\2\4\1\270\14\4\11\0\3\4"+ + "\2\0\3\4\2\0\2\4\1\0\1\4\1\0\3\4"+ + "\4\0\2\4\1\0\37\4\4\0\7\4\1\0\1\u022f"+ + "\16\4\11\0\3\4\2\0\3\4\2\0\2\4\1\0"+ + "\1\4\1\0\3\4\4\0\2\4\1\0\37\4\4\0"+ + "\7\4\1\0\3\4\1\u0230\2\4\1\u0231\10\4\11\0"+ + "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ + "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ + "\7\4\1\u0232\7\4\11\0\3\4\2\0\3\4\2\0"+ + "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ + "\37\4\4\0\7\4\1\0\1\u0233\3\4\1\u0178\12\4"+ + "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ + "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ + "\1\0\11\4\1\u0234\5\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\4\0\7\4\1\0\4\4\1\u0231\12\4"+ + "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ + "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ + "\1\0\1\u0233\16\4\11\0\3\4\2\0\3\4\2\0"+ + "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ + "\37\4\4\0\7\4\1\0\14\4\1\u0235\2\4\11\0"+ + "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ + "\3\4\4\0\2\4\1\0\37\4\15\0\1\u0236\136\0"+ + "\1\u0237\1\u0238\1\0\1\u0239\126\0\1\u023a\1\0\1\u023b"+ + "\132\0\1\u023c\134\0\1\u023d\136\0\1\u023e\114\0\1\4"+ + "\6\6\1\0\7\6\1\u023f\7\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\1\6\1\u0240\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\u0241\15\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\4\6\1\u0242\12\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\10\6\1\u0243\3\6\1\u0244\2\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\4\6\1\u0245\11\6\1\u021c\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\11\6\1\u0246\5\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\3\6\1\u0247\13\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\u0248\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\5\6\1\u0249\11\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\26\6\1\u024a\10\6"+ + "\4\0\1\4\6\6\1\0\15\6\1\u024b\1\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\3\6\1\u024c\13\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\7\6\1\u024d\27\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\u019a\23\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\3\6\1\u024e\33\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\3\6\1\u019a\33\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\1\6\1\u024f\35\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\u0250\23\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\10\6\1\u0251\26\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\5\6\1\u0252\5\6"+ + "\1\u0253\23\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u0254\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ + "\1\u0255\33\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ + "\1\u0256\10\6\1\u0257\3\6\1\u0258\16\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\4\6\1\u0259\32\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\15\6\1\u01ca\21\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\6\6\1\151\30\6\4\0\1\4"+ + "\5\6\1\u025a\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u025b\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u016b\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u025c\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\1\6\1\u025d\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\3\6\1\305\33\6\4\0\1\4\5\6\1\151"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\13\6\1\u025e\23\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\4\6\1\u025f\6\6\1\u0260\23\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u0261\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u0262\32\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\2\6\1\u0263\34\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\151\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\3\6\1\u0264\33\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u0265\32\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u0266\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\5\6\1\u0267\31\6\4\0\1\4\5\6"+ + "\1\u0268\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\5\6\1\u0269"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\5\6\1\u022c\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ + "\1\u026a\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\5\6\1\u026b\31\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\14\6\1\u026c\22\6\4\0\1\4\3\6\1\u026d\2\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\17\6\1\u01a1\5\6\1\151\11\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\13\6\1\u026e\23\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\4\6\1\u025f\32\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\6\6\1\u016b\30\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\10\6\1\u026f\26\6\4\0"+ + "\1\4\6\6\1\0\7\6\1\u0270\7\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\15\6\1\u0271\21\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\1\u0272\1\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\5\6\1\u0273\31\6\4\0\1\4"+ + "\5\6\1\u0274\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\310\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u0275\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\1\6\1\u0276\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\1\6\1\u0277\3\6\1\u0278\31\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\14\6\1\u0279\22\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\4\6\1\u027a\32\6\4\0\1\4"+ + "\5\6\1\u027b\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\u027c\5\6\1\u0251\15\6\4\0"+ + "\1\4\5\6\1\u027d\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\13\6\1\u027e\23\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u01a1\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\1\u027f\1\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\4\6\1\u0280\32\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\20\6\1\u024d\16\6\4\0\1\4"+ + "\3\6\1\u0281\2\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\20\6\1\u0282\1\u0283"+ + "\15\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0284"+ + "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u01bb"+ + "\35\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u0285"+ + "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\4\6\1\u0286"+ + "\32\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\1\u0287\1\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\10\6\1\u024f\26\6"+ + "\4\0\1\4\6\6\1\0\7\6\1\u021a\7\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\25\6\1\u0288\11\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0289\22\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\17\6\1\u028a\17\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\u024d\23\6"+ + "\15\0\1\u01d5\212\0\1\u028b\66\0\1\u028c\164\0\1\u028d"+ + "\70\0\1\u01d9\212\0\1\u028e\66\0\1\u028f\164\0\1\u0290"+ + "\57\0\3\126\1\u01dd\1\126\1\u01dd\1\126\1\0\2\126"+ + "\1\u010b\2\126\1\u010b\11\126\11\0\1\126\1\u01dd\1\126"+ + "\2\0\2\126\1\u01dd\2\0\1\126\1\u010b\1\0\1\u010b"+ + "\1\0\3\126\4\0\2\126\1\0\7\126\1\u01dd\17\126"+ + "\2\u01dd\4\126\2\u01dd\7\0\1\u01dd\1\0\1\u01dd\33\0"+ + "\1\u01dd\5\0\1\u01dd\30\0\1\u01dd\17\0\2\u01dd\4\0"+ + "\2\u01dd\4\0\1\4\3\6\1\u01a1\2\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\21\6\1\u0291"+ + "\15\6\4\0\1\4\5\6\1\u0292\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\5\6\1\u0293\21\6"+ + "\1\u0294\7\6\4\0\1\4\3\6\1\u0295\2\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\3\6\1\u0296\10\6\1\u0297\1\u0298\21\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\u0299\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u029a\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\3\6\1\u029b\33\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\21\6\1\u029c\15\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\u029d\23\6\4\0\1\4\6\6"+ + "\1\0\16\6\1\u029e\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\u0145\16\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\u029f\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u02a0"+ + "\2\6\1\u02a1\2\6\1\u02a2\10\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\u02a3\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\10\6\1\u02a4\6\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\27\6\1\u0294"+ + "\7\6\4\0\1\4\6\6\1\0\2\6\1\u02a5\14\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\3\6\1\u02a6\13\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\16\6\1\u02a7\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\4\6\1\u02a8\12\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\6\6\1\u02a9\10\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\224\16\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\4\6\1\u0212\1\6\1\u02aa\10\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u02ab"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0124"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\1\6\1\u02ac\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\5\6\1\157\11\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\7\6\1\u02ad\7\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\10\6\1\u02ae\6\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\2\6\1\151\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\7\6\1\u02af\7\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\4\6\1\202\12\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\u01dc\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\2\6\1\224\14\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\23\6\1\151\13\6"+ + "\4\0\1\4\6\6\1\0\7\6\1\u02b0\7\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\u02b1\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\1\151\2\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\1\6\1\u02b2\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\11\6\1\u02b3\5\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\7\6\1\u01f3\7\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\14\6\1\u02b4\2\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\1\6\1\u02b5\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\1\u01fd\2\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\7\6"+ + "\1\u02b6\7\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u02b7"+ + "\16\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\10\6\1\u02b8"+ + "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u02b9"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\1\6\1\u02ba\1\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u02bb"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\12\6\1\u02bc"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u02bd"+ + "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u02be"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\277"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\157"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u02bf\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\3\6\1\u011f\13\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\12\6\1\u01fd\4\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\12\6\1\150\4\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u014b\6\6"+ + "\1\u02c0\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ + "\1\u02c1\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\12\6\1\151\24\6\4\0\1\4\6\6\1\0\12\6"+ + "\1\162\4\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ + "\1\u02c2\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\151\1\6"+ + "\1\0\7\6\1\151\27\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\u02c3"+ + "\1\6\1\0\37\6\4\0\1\4\6\6\1\0\6\6"+ + "\1\u02c4\10\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ + "\1\u011f\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\211\1\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u0145\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\1\u0270\1\6\1\0\37\6"+ + "\4\0\3\u015c\4\237\1\u015c\3\237\6\u015c\1\237\2\u015c"+ + "\1\237\6\u015c\1\241\5\u015c\1\237\1\u015c\1\0\2\u015c"+ + "\2\237\5\u015c\1\237\14\u015c\2\237\1\u015c\1\237\2\u015c"+ + "\1\237\17\u015c\2\237\4\u015c\2\237\4\u015c\3\244\4\45"+ + "\1\244\3\45\6\244\1\45\2\244\1\45\13\244\1\u0164"+ + "\1\45\2\244\1\u0165\1\244\2\45\5\244\1\45\14\244"+ + "\2\45\1\244\1\45\2\244\1\45\17\244\2\45\4\244"+ + "\2\45\4\244\1\4\6\6\1\0\10\6\1\u0124\6\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\13\6\1\u02c5\3\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\7\126\1\0\12\126\1\u02c6\4\126\11\0"+ + "\3\126\2\0\3\126\2\0\1\u02c6\1\126\1\0\1\126"+ + "\1\0\3\126\4\0\2\126\1\0\37\126\4\0\7\126"+ + "\1\0\5\126\1\u02c6\11\126\11\0\3\126\2\0\3\126"+ + "\2\0\1\126\1\u02c6\1\0\1\126\1\0\3\126\4\0"+ + "\2\126\1\0\37\126\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\u0259\1\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\10\6"+ + "\1\u02c7\26\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\6"+ + "\1\u016b\35\6\4\0\1\4\3\6\1\305\2\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ + "\1\u02c8\7\6\1\u0260\1\6\1\u02c9\21\6\4\0\7\4"+ + "\1\0\3\4\1\u0230\13\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\4\0\7\4\1\0\2\4\1\u02ca\14\4"+ + "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ + "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ + "\1\0\1\4\1\u02ca\15\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\4\0\7\4\1\0\10\4\1\u02cb\6\4"+ + "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ + "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ + "\1\0\1\4\1\u0230\15\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\4\0\7\4\1\0\5\4\1\u02cc\11\4"+ + "\11\0\3\4\2\0\3\4\2\0\2\4\1\0\1\4"+ + "\1\0\3\4\4\0\2\4\1\0\37\4\4\0\7\4"+ + "\1\0\15\4\1\u02cd\1\4\11\0\3\4\2\0\3\4"+ + "\2\0\2\4\1\0\1\4\1\0\3\4\4\0\2\4"+ + "\1\0\37\4\16\0\1\u017d\131\0\1\u02ce\136\0\1\u02cf"+ + "\2\0\1\u02d0\134\0\1\u02d1\124\0\1\u02d2\3\0\1\u023d"+ + "\140\0\1\u02d3\126\0\1\u02d0\127\0\1\u02d2\147\0\1\u02d4"+ + "\107\0\1\4\6\6\1\0\14\6\1\u02d5\2\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\15\6\1\u02d6\1\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\5\6\1\u02d7\11\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\11\6\1\151\5\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\12\6\1\u02d8\4\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\u0145\1\0\12\6\1\151"+ + "\24\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\1\6\1\u02d9\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\u029e\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\4\6\1\u02da\12\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\1\6\1\151"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\1\6\1\u02db\15\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\1\u02dc\16\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\1\u02dd\1\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\16\6\1\u021c\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\257\1\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ + "\1\151\25\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\6\6"+ + "\2\151\27\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\6"+ + "\1\u02de\35\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\20\6"+ + "\1\u02df\16\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u016b\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\13\6"+ + "\1\311\23\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\15\6"+ + "\1\u02e0\21\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\22\6"+ + "\1\151\14\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\305"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\10\6\1\u02e1\26\6"+ + "\4\0\1\4\5\6\1\u024d\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\16\6\1\151\20\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\15\6\1\u02e2\21\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\4\6\1\u02e3\32\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\14\6\1\u02e4\22\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\15\6\1\u02e5\21\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\5\6\1\u02e6\31\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\1\6\1\357\35\6\4\0"+ + "\1\4\5\6\1\347\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\u02e7\35\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\14\6\1\u0115\22\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\3\6\1\u02e8\33\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u02e9\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u02ea\35\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u022d\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u02eb\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\31\6\1\u02ec\5\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u02ed\35\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\16\6\1\u0259\20\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u02ee\35\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\2\6\1\u02ef\34\6\4\0\1\4\3\6"+ + "\1\u02f0\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\3\6"+ + "\1\u02f1\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\u02f2\16\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\5\6\1\u02f3\31\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\6"+ + "\1\347\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\10\6\1\u02f4\26\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\31\6\1\u02f5\5\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\17\6\1\u02f6\17\6\4\0\1\4\5\6\1\u02f7\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\11\6"+ + "\1\151\3\6\1\u01a1\21\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\1\u02f8"+ + "\1\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\13\6\1\u02f9\23\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u0291\21\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\31\6\1\151\5\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u02fa\21\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\6\1\u02fb"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\4\6"+ + "\1\151\32\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ + "\1\u02fc\33\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\6\6"+ + "\1\u02fd\30\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\1\262\1\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\5\6\1\u01a7\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u02fe\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\5\6"+ + "\1\u02ff\31\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\6"+ + "\1\u0115\35\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\6\6"+ + "\1\u026f\30\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\6\6"+ + "\1\331\30\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\15\6"+ + "\1\u01a1\21\6\4\0\1\4\3\6\1\u0300\2\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\21\6"+ + "\1\u0251\15\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\6\6"+ + "\1\u0301\30\6\36\0\1\u0302\117\0\1\u01d5\51\0\1\u028b"+ + "\44\0\1\u028d\1\u0303\4\u028d\1\u0303\17\u028d\3\u0303\1\u028d"+ + "\1\u0303\2\0\2\u0303\1\0\2\u028d\2\0\3\u028d\1\0"+ + "\1\u0303\2\u028d\1\u0303\1\u028d\1\0\1\u0303\1\u028d\5\u0303"+ + "\2\u028d\1\u0303\37\u028d\2\0\1\u0303\33\0\1\u0304\117\0"+ + "\1\u01d9\51\0\1\u028e\44\0\1\u0290\1\u0305\4\u0290\1\u0305"+ + "\17\u0290\3\u0305\1\u0290\1\u0305\2\0\2\u0305\1\0\2\u0290"+ + "\2\0\3\u0290\1\0\1\u0305\2\u0290\1\u0305\1\u0290\1\0"+ + "\1\u0305\1\u0290\5\u0305\2\u0290\1\u0305\37\u0290\2\0\1\u0305"+ + "\1\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\1\6\1\347\35\6"+ + "\4\0\1\4\5\6\1\305\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\u0306\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\30\6\1\u01fa\6\6\4\0\1\4\5\6"+ + "\1\u0307\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\14\6\1\u0308\22\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u0309\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\u030a\23\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\5\6\1\u030b\31\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\21\6\1\u030c\15\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u02e3\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u030d\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\2\6\1\u016a\34\6\4\0\1\4\5\6"+ + "\1\u024f\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\14\6\1\157\2\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\224\15\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\u030e\1\6\1\u030f\13\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\4\6\1\u0310\12\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\12\6\1\u0311\4\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\10\6\1\u0312\6\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\2\6\1\u0313\14\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\16\6\1\u0314\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\1\6\1\u02b3\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\1\6\1\u012b\1\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\6\1\u021a\15\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ + "\1\u0315\1\0\37\6\4\0\1\4\6\6\1\0\3\6"+ + "\1\u0316\13\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\12\6\1\u0317\24\6\4\0\1\4\6\6\1\0\10\6"+ + "\1\u0318\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\26\6\1\u0319\10\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\33\6\1\u02b3\3\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u031a"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u031b"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u031c"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\u01ef"+ + "\36\6\4\0\1\4\6\6\1\0\11\6\1\u0145\5\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\13\6\1\151\3\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\6\6\1\u031d\10\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\u031e\11\6\1\u02b5"+ + "\4\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\36\6\1\151\4\0\1\4\6\6\1\0\12\6"+ + "\1\u031f\4\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\4\6"+ + "\1\224\12\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\u0320\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\4\6"+ + "\1\u0321\12\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\5\6"+ + "\1\211\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\5\6"+ + "\1\u0322\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u0323"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u01fe"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\7\6\1\u02c1"+ + "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u0324\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\15\6\1\u0145\1\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\14\6\1\u0315\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u0325\15\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u0326\15\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u0327"+ + "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0328"+ + "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\11\6\1\u0329"+ + "\25\6\4\0\7\4\1\0\7\4\1\u02ca\7\4\11\0"+ + "\3\4\2\0\3\4\2\0\2\4\1\0\1\4\1\0"+ + "\3\4\4\0\2\4\1\0\37\4\4\0\7\4\1\0"+ + "\12\4\1\u032a\4\4\11\0\3\4\2\0\3\4\2\0"+ + "\2\4\1\0\1\4\1\0\3\4\4\0\2\4\1\0"+ + "\37\4\4\0\7\4\1\0\16\4\1\u032b\11\0\3\4"+ + "\2\0\3\4\2\0\2\4\1\0\1\4\1\0\3\4"+ + "\4\0\2\4\1\0\37\4\17\0\1\u02cf\132\0\1\u032c"+ + "\132\0\1\u032c\142\0\1\u032d\124\0\1\u02cf\137\0\1\u032e"+ + "\143\0\1\u032f\106\0\1\4\6\6\1\0\7\6\1\u0330"+ + "\7\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0331"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0332"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\1\6\1\u0333\1\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0334"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u01cf"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\u0335\5\6"+ + "\1\151\10\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\14\6"+ + "\1\u0244\2\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u0336"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\17\6"+ + "\1\u01a1\17\6\4\0\1\4\5\6\1\u0337\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0338"+ + "\22\6\4\0\1\4\5\6\1\u0339\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\24\6\1\u01e5\12\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\u033a\23\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0257\22\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\1\u033b\1\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\15\6\1\u033c\21\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\1\6\1\u033d\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\6\1\331\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u033e\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\3\6\1\u033f\33\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\20\6\1\151\16\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u01a1\32\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\305\23\6\4\0\1\4\5\6"+ + "\1\u0340\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\3\6\1\u0341"+ + "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u02ec\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\36\6\1\151\4\0\1\4"+ + "\5\6\1\u0307\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\u030e\15\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\32\6\1\u02e3\4\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\25\6\1\u0342\11\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\5\6\1\u0343\31\6\4\0\1\4\5\6"+ + "\1\u0344\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\3\6\1\u0345"+ + "\2\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\3\6\1\151\33\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\2\6\1\u0346\34\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\u01ce\35\6\4\0\1\4"+ + "\5\6\1\u0347\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\1\6\1\u0348\35\6\4\0\1\4\5\6"+ + "\1\u0349\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\1\6\1\u030d\35\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\10\6\1\u02ff\26\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\15\6\1\u034a\21\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\1\6\1\u0277\35\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\15\6\1\u034b\21\6\36\0\1\u028d\133\0\1\u0290"+ + "\101\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\11\6\1\u034c\7\6"+ + "\1\u030c\1\u034d\14\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\1\6\1\u034e"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\151"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\2\6\1\u034f\34\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\11\6\1\u034c\7\6"+ + "\1\u030c\1\u034d\1\6\1\u0350\12\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\u0113\23\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\5\6\1\u0351\31\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u0352\26\6\4\0\1\4\6\6"+ + "\1\0\5\6\1\u0353\11\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\2\6\1\151\14\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\16\6\1\u0314\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\u0354\11\6\1\u0355\10\6\1\u0356"+ + "\13\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\1\6\1\u0357\1\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\4\6\1\u011b\12\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\16\6\1\u0314\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\12\6"+ + "\1\u0355\10\6\1\u0356\13\6\4\0\1\4\6\6\1\0"+ + "\10\6\1\u0358\6\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\7\6\1\u0359\7\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\33\6\1\u0145\3\6\4\0\1\4\6\6\1\0"+ + "\13\6\1\u0145\3\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\2\6\1\u015b\14\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\1\u0150\16\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\10\6"+ + "\1\u0246\6\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\11\6"+ + "\1\u035a\5\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u035b"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u015b"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\10\6\1\u035c"+ + "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u0124"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\1\6\1\u035d\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\15\6\1\151\1\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\14\6\1\164\2\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u035e\15\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\3\6\1\u035f\13\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\7\6\1\u0360\7\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\7\6\1\u0361\7\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\5\6\1\u027a"+ + "\31\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\32\6\1\u01a1"+ + "\4\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\20\6\1\u01a1"+ + "\16\6\4\0\7\4\1\0\1\u0231\16\4\11\0\3\4"+ + "\2\0\3\4\2\0\2\4\1\0\1\4\1\0\3\4"+ + "\4\0\2\4\1\0\37\4\4\0\7\4\1\0\14\4"+ + "\1\u02ca\2\4\11\0\3\4\2\0\3\4\2\0\2\4"+ + "\1\0\1\4\1\0\3\4\4\0\2\4\1\0\37\4"+ + "\23\0\1\u032c\136\0\1\u0362\137\0\1\u0363\105\0\1\4"+ + "\6\6\1\0\11\6\1\u0364\5\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\1\6\1\u0359\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\12\6\1\u012b\24\6\4\0\1\4\6\6"+ + "\1\0\5\6\1\u0145\11\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\15\6\1\u012b\1\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\14\6\1\u0365\2\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\1\6\1\u0366\15\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u0367\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u0368\21\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\4\6\1\u0369\32\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\17\6\1\151\17\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\13\6\1\u016b\23\6\4\0\1\4\5\6"+ + "\1\u036a\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\1\6\1\256\35\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\4\6\1\u036b\32\6\4\0\1\4\5\6\1\u01ca"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u036c\21\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\5\6\1\u036d\31\6\4\0\1\4\3\6\1\u0191\2\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\u01ca\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u0352"+ + "\21\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u036e"+ + "\35\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\1\6\1\u01a1\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\17\6\1\u016a\17\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\11\6\1\u016a\25\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\10\6\1\u036f\26\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\14\6\1\u0370\22\6"+ + "\4\0\1\4\5\6\1\u0371\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\37\6\4\0"+ + "\1\4\5\6\1\331\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\1\u0372\1\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\15\6\1\u0373\21\6\4\0\1\4\3\6"+ + "\1\u0374\2\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\5\6"+ + "\1\u0375\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\13\6\1\u029a\23\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\13\6\1\u024e\23\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ + "\1\u0376\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\u0377\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\6"+ + "\1\211\15\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\12\6"+ + "\1\u0378\4\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\1\u0379"+ + "\16\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u02a6"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\4\6\1\u021b"+ + "\12\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\3\6\1\u037a"+ + "\13\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\1\u011f"+ + "\36\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\u037b\36\6"+ + "\4\0\1\4\6\6\1\0\4\6\1\u0379\12\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\10\6\1\u011f\6\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\1\u037c\5\6\1\0\1\u037d\16\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\14\6\1\u02c1\2\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\14\0\1\u02d0\147\0\1\u032c\107\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\u021a"+ + "\1\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\1\6\1\u037e"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\u037f\16\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u02ff"+ + "\35\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\14\6\1\u0380"+ + "\22\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\13\6\1\u0374"+ + "\23\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\6\6\1\u024f"+ + "\30\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\24\6\1\u0381"+ + "\12\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\24\6\1\u0115"+ + "\12\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\15\6\1\u0382"+ + "\21\6\4\0\1\4\3\6\1\u0383\2\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\34\6\1\u0384\2\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\5\6\1\u0115\31\6\4\0\1\4\3\6\1\u0385\2\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\1\6\1\u0386\35\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\1\6\1\151\35\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\1\6\1\u0287\35\6\4\0\1\4\5\6\1\u0387\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\151"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u0388"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0389"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u0222"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\6\6\1\u0145"+ + "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u038a"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\10\6\1\u038b"+ + "\6\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\1\6\1\u038c"+ + "\15\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u038d"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\14\6\1\u038e"+ + "\2\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\3\6"+ + "\1\u01a1\33\6\4\0\1\4\5\6\1\u038f\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\17\6\11\0\1\4"+ + "\2\6\2\0\3\6\2\0\2\6\1\0\1\6\1\0"+ + "\1\4\1\6\1\4\4\0\2\6\1\0\1\6\1\u0390"+ + "\35\6\4\0\1\4\5\6\1\u0391\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\5\6\1\u0392\31\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\1\6\1\u0393\35\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\10\6\1\u0394\26\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\25\6\1\151\11\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\26\6\1\151\10\6"+ + "\4\0\1\4\6\6\1\0\7\6\1\u0395\7\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\1\6\1\u011f\15\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\1\6\1\u0396\1\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\13\6\1\u0397\3\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\2\6\1\u0398\3\6\1\151"+ + "\10\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\1\223\2\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\5\6\1\u0115\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\u0399\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\3\6\1\151\33\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\20\6\1\u039a\16\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\2\6\1\u039b\34\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\16\6\1\313\20\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\15\6\1\u016a\21\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\u012b\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\1\6\1\u039c\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\14\6\1\u039d\2\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\3\6\1\u039e\13\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\14\6\1\u039f\22\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\1\6\1\u03a0\35\6\4\0\1\4"+ + "\6\6\1\0\17\6\11\0\1\4\2\6\2\0\3\6"+ + "\2\0\2\6\1\0\1\6\1\0\1\4\1\6\1\4"+ + "\4\0\2\6\1\0\15\6\1\u03a1\21\6\4\0\1\4"+ + "\6\6\1\0\3\6\1\u03a2\13\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\7\6\1\u03a3\7\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\6\6\1\0\1\6\1\u0120\15\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\37\6\4\0\1\4"+ + "\5\6\1\u016f\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\37\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\10\6\1\u03a4\26\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\14\6\1\u03a5\22\6\4\0\1\4\6\6"+ + "\1\0\17\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\1\6\1\u03a6\1\0\37\6\4\0\1\4\6\6\1\0"+ + "\17\6\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\1\6"+ + "\1\u03a7\1\0\37\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u03a8\21\6\4\0\1\4\6\6\1\0\17\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\15\6\1\u03a9\21\6\4\0\1\4\6\6\1\0\5\6"+ + "\1\u029f\11\6\11\0\1\4\2\6\2\0\3\6\2\0"+ + "\2\6\1\0\1\6\1\0\1\4\1\6\1\4\4\0"+ + "\2\6\1\0\37\6\4\0\1\4\6\6\1\0\16\6"+ + "\1\u03aa\11\0\1\4\2\6\2\0\3\6\2\0\2\6"+ + "\1\0\1\6\1\0\1\4\1\6\1\4\4\0\2\6"+ + "\1\0\37\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\21\6"+ + "\1\u03ab\15\6\4\0\1\4\6\6\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\1\6\1\u0292\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\6\6\1\0\1\6\1\u03ac\15\6"+ + "\11\0\1\4\2\6\2\0\3\6\2\0\2\6\1\0"+ + "\1\6\1\0\1\4\1\6\1\4\4\0\2\6\1\0"+ + "\37\6\4\0\1\4\5\6\1\u03ad\1\0\17\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\4\6\1\u03ae\12\6\11\0"+ + "\1\4\2\6\2\0\3\6\2\0\2\6\1\0\1\6"+ + "\1\0\1\4\1\6\1\4\4\0\2\6\1\0\37\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\2\6\1\0\13\6\1\u03af\23\6"+ + "\4\0\1\4\6\6\1\0\17\6\11\0\1\4\2\6"+ + "\2\0\3\6\2\0\2\6\1\0\1\6\1\0\1\4"+ + "\1\6\1\4\4\0\1\6\1\224\1\0\37\6\4\0"+ + "\1\4\6\6\1\0\17\6\11\0\1\4\2\6\2\0"+ + "\3\6\2\0\2\6\1\0\1\6\1\0\1\4\1\6"+ + "\1\4\4\0\2\6\1\0\15\6\1\305\21\6\4\0"; private static int [] zzUnpackTrans() { - int [] result = new int[79028]; + int [] result = new int[84180]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -2672,9 +2849,9 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { /* error messages for the codes above */ private static final String ZZ_ERROR_MSG[] = { - "Unkown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" }; /** @@ -2683,17 +2860,17 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\3\0\30\1\1\11\4\1\1\11\2\1\1\11\11\1"+ - "\1\11\1\1\1\11\33\1\1\11\5\1\1\11\110\1"+ - "\1\0\2\11\2\1\1\11\3\1\1\11\24\1\1\0"+ - "\77\1\2\0\1\11\6\0\2\1\1\0\117\1\1\11"+ - "\7\1\1\11\24\1\6\0\121\1\10\0\2\1\1\0"+ - "\115\1\4\0\1\1\4\0\104\1\2\0\1\1\2\0"+ - "\65\1\7\0\46\1\4\0\40\1\1\11\3\0\54\1"+ - "\2\0\116\1"; + "\3\0\30\1\1\11\4\1\1\11\2\1\1\11\11\1"+ + "\1\11\1\1\1\11\33\1\1\11\5\1\1\11\111\1"+ + "\1\0\2\11\2\1\1\11\3\1\1\11\25\1\1\0"+ + "\101\1\2\0\1\11\6\0\2\1\1\0\124\1\1\11"+ + "\7\1\1\11\24\1\6\0\124\1\10\0\2\1\1\0"+ + "\127\1\4\0\1\1\4\0\114\1\2\0\1\1\2\0"+ + "\76\1\7\0\55\1\4\0\46\1\1\11\3\0\62\1"+ + "\2\0\114\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[887]; + int [] result = new int[943]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -2721,7 +2898,7 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { private int zzLexicalState = YYINITIAL; /** this buffer contains the current text to be matched and is - the source of the yytext() string */ + the source of the yytext() string */ private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; /** the textposition at the last accepting state */ @@ -2737,7 +2914,7 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { private int zzStartRead; /** endRead marks the last character in the buffer, that has been read - from input */ + from input */ private int zzEndRead; /** number of newlines encountered up to the start of the matched text */ @@ -2747,12 +2924,12 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { private int yychar; /** - * the number of characters from the last newline up to the start of the + * the number of characters from the last newline up to the start of the * matched text */ private int yycolumn; - /** + /** * zzAtBOL == true <=> the scanner is currently at the beginning of a line */ private boolean zzAtBOL = true; @@ -2762,165 +2939,163 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { /* user code: */ - /** - * Constructor. This must be here because JFlex does not generate a - * no-parameter constructor. - */ - public FormulaTokenMaker() { - super(); - } - - - /** - * Adds the token specified to the current linked list of tokens. - * - * @param tokenType The token's type. - * @see #addToken(int, int, int) - */ - private void addHyperlinkToken(int start, int end, int tokenType) { - int so = start + offsetShift; - addToken(zzBuffer, start,end, tokenType, so, true); - } - - - /** - * Adds the token specified to the current linked list of tokens. - * - * @param tokenType The token's type. - */ - private void addToken(int tokenType) { - addToken(zzStartRead, zzMarkedPos-1, tokenType); - } - - - /** - * Adds the token specified to the current linked list of tokens. - * - * @param tokenType The token's type. - */ - private void addToken(int start, int end, int tokenType) { - int so = start + offsetShift; - addToken(zzBuffer, start,end, tokenType, so); - } - - - /** - * Adds the token specified to the current linked list of tokens. - * - * @param array The character array. - * @param start The starting offset in the array. - * @param end The ending offset in the array. - * @param tokenType The token's type. - * @param startOffset The offset in the document at which this token - * occurs. - */ - @Override - public void addToken(char[] array, int start, int end, int tokenType, int startOffset) { - super.addToken(array, start,end, tokenType, startOffset); - zzStartRead = zzMarkedPos; - } - - - /** - * Returns the text to place at the beginning and end of a - * line to "comment" it in a this programming language. - * - * @return The start and end strings to add to a line to "comment" - * it out. - */ - @Override - public String[] getLineCommentStartAndEnd() { - return new String[] { "//", null }; - } - - - /** - * Returns the first token in the linked list of tokens generated - * from text. This method must be implemented by - * subclasses so they can correctly implement syntax highlighting. - * - * @param text The text from which to get tokens. - * @param initialTokenType The token type we should start with. - * @param startOffset The offset into the document at which - * text starts. - * @return The first Token in a linked list representing - * the syntax highlighted text. - */ - public Token getTokenList(Segment text, int initialTokenType, int startOffset) { - - resetTokenList(); - this.offsetShift = -text.offset + startOffset; - - // Start off in the proper state. - int state = Token.NULL; - switch (initialTokenType) { - case Token.COMMENT_MULTILINE: - state = MLC; - start = text.offset; - break; - default: - state = Token.NULL; - } - - s = text; - try { - yyreset(zzReader); - yybegin(state); - return yylex(); - } catch (IOException ioe) { - ioe.printStackTrace(); - return new TokenImpl(); - } - - } - - - /** - * Refills the input buffer. - * - * @return true if EOF was reached, otherwise - * false. - * @exception IOException if any I/O-Error occurs. - */ - private boolean zzRefill() throws java.io.IOException { - return zzCurrentPos>=s.offset+s.count; - } - - - /** - * Resets the scanner to read from a new input stream. - * Does not close the old reader. - * - * All internal variables are reset, the old input stream - * cannot be reused (internal buffer is discarded and lost). - * Lexical state is set to YY_INITIAL. - * - * @param reader the new input stream - */ - public final void yyreset(java.io.Reader reader) throws java.io.IOException { - // 's' has been updated. - zzBuffer = s.array; - /* - * We replaced the line below with the two below it because zzRefill - * no longer "refills" the buffer (since the way we do it, it's always - * "full" the first time through, since it points to the segment's - * array). So, we assign zzEndRead here. - */ - //zzStartRead = zzEndRead = s.offset; - zzStartRead = s.offset; - zzEndRead = zzStartRead + s.count - 1; - zzCurrentPos = zzMarkedPos = zzPushbackPos = s.offset; - zzLexicalState = YYINITIAL; - zzReader = reader; - zzAtBOL = true; - zzAtEOF = false; - } - - public final String test() { - return "abs|ABS|COUNT|count"; - } + /** + * Constructor. This must be here because JFlex does not generate a + * no-parameter constructor. + */ + public FormulaTokenMaker() { + super(); + } + + + /** + * Adds the token specified to the current linked list of tokens. + * + * @param tokenType The token's type. + * @see #addToken(int, int, int) + */ + private void addHyperlinkToken(int start, int end, int tokenType) { + int so = start + offsetShift; + addToken(zzBuffer, start,end, tokenType, so, true); + } + + + /** + * Adds the token specified to the current linked list of tokens. + * + * @param tokenType The token's type. + */ + private void addToken(int tokenType) { + addToken(zzStartRead, zzMarkedPos-1, tokenType); + } + + + /** + * Adds the token specified to the current linked list of tokens. + * + * @param tokenType The token's type. + */ + private void addToken(int start, int end, int tokenType) { + int so = start + offsetShift; + addToken(zzBuffer, start,end, tokenType, so); + } + + /** + * Adds the token specified to the current linked list of tokens. + * + * @param array The character array. + * @param start The starting offset in the array. + * @param end The ending offset in the array. + * @param tokenType The token's type. + * @param startOffset The offset in the document at which this token + * occurs. + */ + @Override + public void addToken(char[] array, int start, int end, int tokenType, int startOffset) { + super.addToken(array, start,end, tokenType, startOffset); + zzStartRead = zzMarkedPos; + } + + + /** + * Returns the text to place at the beginning and end of a + * line to "comment" it in a this programming language. + * + * @return The start and end strings to add to a line to "comment" + * it out. + */ + @Override + public String[] getLineCommentStartAndEnd() { + return new String[] { "//", null }; + } + + + /** + * Returns the first token in the linked list of tokens generated + * from text. This method must be implemented by + * subclasses so they can correctly implement syntax highlighting. + * + * @param text The text from which to get tokens. + * @param initialTokenType The token type we should start with. + * @param startOffset The offset into the document at which + * text starts. + * @return The first Token in a linked list representing + * the syntax highlighted text. + */ + public Token getTokenList(Segment text, int initialTokenType, int startOffset) { + + resetTokenList(); + this.offsetShift = -text.offset + startOffset; + + // Start off in the proper state. + int state = Token.NULL; + switch (initialTokenType) { + case Token.COMMENT_MULTILINE: + state = MLC; + start = text.offset; + break; + default: + state = Token.NULL; + } + + s = text; + try { + yyreset(zzReader); + yybegin(state); + return yylex(); + } catch (IOException ioe) { + ioe.printStackTrace(); + return new TokenImpl(); + } + + } + + + /** + * Refills the input buffer. + * + * @return true if EOF was reached, otherwise + * false. + * @throws IOException if any I/O-Error occurs. + */ + private boolean zzRefill() throws java.io.IOException { + return zzCurrentPos >= s.offset + s.count; + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to YY_INITIAL. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) throws java.io.IOException { + // 's' has been updated. + zzBuffer = s.array; + /* + * We replaced the line below with the two below it because zzRefill + * no longer "refills" the buffer (since the way we do it, it's always + * "full" the first time through, since it points to the segment's + * array). So, we assign zzEndRead here. + */ + //zzStartRead = zzEndRead = s.offset; + zzStartRead = s.offset; + zzEndRead = zzStartRead + s.count - 1; + zzCurrentPos = zzMarkedPos = zzPushbackPos = s.offset; + zzLexicalState = YYINITIAL; + zzReader = reader; + zzAtBOL = true; + zzAtEOF = false; + } + public final String test() { + return "abs|ABS|COUNT|count"; + } /** @@ -2943,7 +3118,7 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { this(new java.io.InputStreamReader(in)); } - /** + /** * Unpacks the compressed character translation table. * * @param packed the packed character translation table @@ -2961,8 +3136,6 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { return map; } - - /** * Closes the input stream. */ @@ -2976,6 +3149,7 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { + /** * Returns the current lexical state. */ @@ -3003,12 +3177,12 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { /** - * Returns the character at position pos from the - * matched text. - * + * Returns the character at position pos from the + * matched text. + * * It is equivalent to yytext().charAt(pos), but faster * - * @param pos the position of the character to fetch. + * @param pos the position of the character to fetch. * A value from 0 to yylength()-1. * * @return the character at position pos @@ -3029,8 +3203,8 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { /** * Reports an error that occured while scanning. * - * In a wellformed scanner (no or only correct usage of - * yypushback(int) and a match-all fallback rule) this method + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method * will only be called with things that "Can't Possibly Happen". * If this method is called, something is seriously wrong * (e.g. a JFlex bug producing a faulty scanner etc.). @@ -3050,7 +3224,7 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { } throw new Error(message); - } + } /** @@ -3097,13 +3271,13 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { zzAction = -1; zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - + zzState = zzLexicalState; zzForAction: { while (true) { - + if (zzCurrentPosL < zzEndReadL) zzInput = zzBufferL[zzCurrentPosL++]; else if (zzAtEOF) { @@ -3146,134 +3320,134 @@ public class FormulaTokenMaker extends AbstractJFlexCTokenMaker { zzMarkedPos = zzMarkedPosL; switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 25: - { addToken(Token.PREPROCESSOR); - } + case 25: + { addToken(Token.PREPROCESSOR); + } case 28: break; - case 7: - { addNullToken(); return firstToken; - } + case 7: + { addNullToken(); return firstToken; + } case 29: break; - case 22: - { addToken(Token.LITERAL_CHAR); - } + case 22: + { addToken(Token.LITERAL_CHAR); + } case 30: break; - case 21: - { yybegin(YYINITIAL); addToken(start,zzStartRead+1, Token.COMMENT_MULTILINE); - } + case 21: + { yybegin(YYINITIAL); addToken(start,zzStartRead+1, Token.COMMENT_MULTILINE); + } case 31: break; - case 17: - { start = zzMarkedPos-2; yybegin(MLC); - } + case 17: + { start = zzMarkedPos-2; yybegin(MLC); + } case 32: break; - case 9: - { addToken(Token.WHITESPACE); - } + case 9: + { addToken(Token.WHITESPACE); + } case 33: break; - case 24: - { addToken(Token.LITERAL_NUMBER_HEXADECIMAL); - } + case 24: + { addToken(Token.LITERAL_NUMBER_HEXADECIMAL); + } case 34: break; - case 18: - { addToken(Token.ERROR_CHAR); /*addNullToken(); return firstToken;*/ - } + case 18: + { addToken(Token.ERROR_CHAR); /*addNullToken(); return firstToken;*/ + } case 35: break; - case 23: - { addToken(Token.ERROR_STRING_DOUBLE); - } + case 23: + { addToken(Token.ERROR_STRING_DOUBLE); + } case 36: break; - case 14: - { addToken(Token.LITERAL_NUMBER_FLOAT); - } + case 14: + { addToken(Token.LITERAL_NUMBER_FLOAT); + } case 37: break; - case 15: - { addToken(Token.RESERVED_WORD); - } + case 15: + { addToken(Token.RESERVED_WORD); + } case 38: break; - case 5: - { addToken(Token.SEPARATOR); - } + case 5: + { addToken(Token.SEPARATOR); + } case 39: break; - case 2: - { addToken(Token.IDENTIFIER); - } + case 2: + { addToken(Token.IDENTIFIER); + } case 40: break; - case 12: - { addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; - } + case 12: + { addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; + } case 41: break; - case 16: - { start = zzMarkedPos-2; yybegin(EOL_COMMENT); - } + case 16: + { start = zzMarkedPos-2; yybegin(EOL_COMMENT); + } case 42: break; - case 6: - { addToken(Token.ERROR_CHAR); addNullToken(); return firstToken; - } + case 6: + { addToken(Token.ERROR_CHAR); addNullToken(); return firstToken; + } case 43: break; - case 8: - { addToken(Token.ERROR_STRING_DOUBLE); addNullToken(); return firstToken; - } + case 8: + { addToken(Token.ERROR_STRING_DOUBLE); addNullToken(); return firstToken; + } case 44: break; - case 1: - { addToken(Token.ERROR_IDENTIFIER); - } + case 1: + { addToken(Token.ERROR_IDENTIFIER); + } case 45: break; - case 19: - { addToken(Token.ERROR_CHAR); - } + case 19: + { addToken(Token.ERROR_CHAR); + } case 46: break; - case 20: - { addToken(Token.LITERAL_STRING_DOUBLE_QUOTE); - } + case 20: + { addToken(Token.LITERAL_STRING_DOUBLE_QUOTE); + } case 47: break; - case 27: - { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_EOL); start = zzMarkedPos; - } + case 27: + { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_EOL); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_EOL); start = zzMarkedPos; + } case 48: break; - case 26: - { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_MULTILINE); start = zzMarkedPos; - } + case 26: + { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_MULTILINE); start = zzMarkedPos; + } case 49: break; - case 13: - { addToken(Token.ERROR_NUMBER_FORMAT); - } + case 13: + { addToken(Token.ERROR_NUMBER_FORMAT); + } case 50: break; - case 3: - { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); - } + case 3: + { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); + } case 51: break; - case 4: - { addToken(Token.OPERATOR); - } + case 4: + { addToken(Token.OPERATOR); + } case 52: break; - case 10: - { - } + case 10: + { + } case 53: break; - case 11: - { addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); return firstToken; - } + case 11: + { addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); return firstToken; + } case 54: break; - default: + default: if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; switch (zzLexicalState) { - case EOL_COMMENT: { - addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; + case EOL_COMMENT: { + addToken(start,zzStartRead-1, Token.COMMENT_EOL); addNullToken(); return firstToken; + } + case 944: break; + case YYINITIAL: { + addNullToken(); return firstToken; + } + case 945: break; + case MLC: { + addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); return firstToken; + } + case 946: break; + default: + return null; } - case 888: break; - case YYINITIAL: { - addNullToken(); return firstToken; - } - case 889: break; - case MLC: { - addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); return firstToken; - } - case 890: break; - default: - return null; - } - } + } else { zzScanError(ZZ_NO_MATCH); } diff --git a/designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java b/designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java index 8355d4f97f..8fa88e9293 100644 --- a/designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java +++ b/designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java @@ -342,7 +342,7 @@ public class ReportletHyperNorthPane extends AbstractHyperNorthPane" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Front") + "\\/:*?\"<>|" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Back") + ""); + fileNameTipLabel = new UILabel("" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Front") + "\\/:*?\"<>|" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Back") + ""); fileNameTipLabel.setVisible(false); fileNameRadioGroup.addActionListener(new ActionListener() { @Override @@ -195,6 +197,59 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane parameterList = parameterViewPane.update(); + if (!parameterList.isEmpty()) { + Parameter[] parameters = new Parameter[parameterList.size()]; + parameterList.toArray(parameters); + js.setParameters(parameters); + } + } + } + } + public void populateSingleJavaScript(SingleJavaScript js){ + exportTypeComboBox.setSelectedItem(js.getExportType()); + fileNameRadioGroup.selectIndexButton(js.isDefaultFileName() ? 0 : 1); + if (!js.isDefaultFileName()) { + fileNameFormulaEditor.setEnabled(true); + fileNameFormulaEditor.setVisible(true); + fileNameTipLabel.setVisible(true); + fileNameFormulaEditor.setValue(BaseFormula.createFormulaBuilder().build(js.getFileName())); + } else { + fileNameFormulaEditor.setVisible(false); + fileNameFormulaEditor.setValue(BaseFormula.createFormulaBuilder().build()); + } + if (js.isExtendParameters()) { + extendParametersCheckBox.setSelected(true); + } else { + extendParametersCheckBox.setSelected(false); + if (this.parameterViewPane != null) { + List parameterList = this.parameterViewPane.update(); + parameterList.clear(); + ParameterProvider[] parameters = js.getParameters(); + this.parameterViewPane.populate(parameters); + } + } + } + private JPanel initExportTypePane() { + UILabel typeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Type") + ":"); + exportTypeComboBox = getComboBoxWithModel(new String[]{ExportJavaScript.EXPORT_PDF, ExportJavaScript.EXPORT_EXCEL_PAGE, ExportJavaScript.EXPORT_EXCEL_SIMPLE, ExportJavaScript.EXPORT_EXCEL_SHEET, ExportJavaScript.EXPORT_WORD, ExportJavaScript.EXPORT_IMAGE} + , EXPORT_TYPES_MAP); + Component[][] components = new Component[][]{{typeLabel, exportTypeComboBox}}; + + JPanel exportTypePane = TableLayoutHelper.createTableLayoutPane(components, new double[]{p}, new double[]{p, p}); + exportTypePane.setBorder(BorderFactory.createEmptyBorder(5, 2, 5, 2)); + return exportTypePane; + } @Override protected String title4PopupWindow() { @@ -213,10 +268,21 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane(new ExportJSTableModel()); + editorPane.setHeaderResizing(false); this.add(editorPane, BorderLayout.CENTER); } + public void reset() { + editorPane.populate(new SingleJavaScript[0]); + } + public void updateExportJavaScript(ExportJavaScript exportJavaScript){ + List javaScripts = editorPane.update(); + for (SingleJavaScript js : javaScripts) { + exportJavaScript.addOtherTemplateJS(js); + } + } + @Override protected String title4PopupWindow() { return Toolkit.i18nText("Fine-Design_Basic_Export_JS_Setting"); @@ -245,19 +311,21 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane { + if (e.getStateChange() == ItemEvent.SELECTED) { + final int row = table.getSelectedRow(); + if (row == -1) { + return; + } + SingleJavaScript js = getList().get(row); + Object ob = fileNameComboBox.getSelectedItem(); + if (ob != null) { + String value = ob.toString(); + js.setDefaultFileName(StringUtils.equals(value, DEFAULT)); + if (js.isDefaultFileName()) { + js.setFileName(StringUtils.EMPTY); + } + } + table.repaint(); + } + }); this.addCellEditorListener(new CellEditorListener() { @Override @@ -450,15 +543,6 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane { + if (e.getStateChange() == ItemEvent.SELECTED) { + final int row = table.getSelectedRow(); + if (row == -1) { + return; + } + SingleJavaScript js = getList().get(row); + Object ob = parameterSetting.getSelectedItem(); + if (ob != null) { + String value = ob.toString(); + js.setExtendParameters(StringUtils.equals(value, DEFAULT)); + } + // 单纯为了刷新表格,使某些联动生效 + table.repaint(); + } + }); this.addCellEditorListener(new CellEditorListener() { @Override @@ -537,15 +641,7 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane(Arrays.asList((ParameterProvider[]) value))); + if (getList().get(row) == null || getList().get(row).isExtendParameters()) { + return EMPTY_LABEL; + } + ParameterProvider[] providers = (ParameterProvider[]) value; + if (providers != null) { + paraSettingPane.refresh(new ArrayList<>(Arrays.asList(providers))); + } return paraButton; } @@ -621,6 +725,14 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane parameterList = this.parameterViewPane.update(); - parameterList.clear(); - ParameterProvider[] parameters = js.getParameters(); - this.parameterViewPane.populate(parameters); - } - } else { - OtherTemplatePane pane = (OtherTemplatePane) this.templatePanel.getComponent(1); - pane.editorPane.populate(ob.getJsList().toArray(new SingleJavaScript[ob.getJsList().size()])); - } + currentTemplatePane.populateSingleJavaScript(ob.getCurrentTemplateJavaScript()); + + OtherTemplatePane pane = (OtherTemplatePane) this.templatePanel.getComponent(1); + pane.editorPane.populate(ob.getJsListForOtherTemplates().toArray(new SingleJavaScript[ob.getJsListForOtherTemplates().size()])); } @Override @@ -766,31 +850,12 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane parameterList = parameterViewPane.update(); - if (!parameterList.isEmpty()) { - Parameter[] parameters = new Parameter[parameterList.size()]; - parameterList.toArray(parameters); - js.setParameters(parameters); - } - } - exportJavaScript.addJS(js); - } else { - List javaScripts = otherTemplatePane.editorPane.update(); - for (SingleJavaScript js : javaScripts) { - exportJavaScript.addJS(js); - } - } + SingleJavaScript js = new SingleJavaScript(); + js.setCurrentTemplate(selected); + currentTemplatePane.updateSingleJavaScript(js); + exportJavaScript.addCurrentTemplateJS(js); + + otherTemplatePane.updateExportJavaScript(exportJavaScript); } private String getFileName() { 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..31c45da762 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 @@ -1,10 +1,13 @@ package com.fr.design.javascript; +import com.fr.base.svg.IconUtils; 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; @@ -14,13 +17,23 @@ import com.fr.design.gui.icontainer.UIScrollPane; 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.i18n.Toolkit; 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 javax.swing.*; -import java.awt.*; +import com.fr.js.JavaScriptImpl; + +import javax.swing.JPanel; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +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; @@ -28,18 +41,124 @@ import java.awt.event.MouseEvent; import java.util.ArrayList; 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(); + if (needAdvancedEditor()) { + 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(Toolkit.i18nText("Fine-Design_Advanced_Editor"), IconUtils.readIcon("com/fr/design/images/edit/advancedEditor.svg"), 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.showWindowWithCustomSize(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + if (javaScript != null) { + newJavaScriptImplPane.updateBean(javaScript); + jsImplPopulateAction.populate(javaScript); + } + } + + @Override + public void doCancel() { + super.doCancel(); + } + },new Dimension(900,800)); + advancedEditorDialog.setModal(modal); + advancedEditorDialog.setResizable(true); + advancedEditorDialog.pack(); + advancedEditorDialog.setVisible(true); + } + advancedEditorDialog.requestFocus(); + } + }); + labelPane.add(advancedEditorLabel,BorderLayout.EAST); + } + + 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 +184,20 @@ public class JSContentPane extends BasicPane { } }); - //REPORT-10533 用户参数多达25个,导致JS没地方写,增加滚动条显示 + labelPane.add(label,BorderLayout.CENTER); 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) { @@ -228,4 +324,8 @@ public class JSContentPane extends BasicPane { return provider; } + + protected boolean needAdvancedEditor() { + return true; + } } \ No newline at end of file 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..8e8ef45b9f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java @@ -0,0 +1,924 @@ +package com.fr.design.javascript; + +import com.fr.base.svg.IconUtils; +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.PlaceholderTextField; +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.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +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 PlaceholderTextField keyWordTextField = new PlaceholderTextField(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 = "https://help.fanruan.com/finereport/api-helpdoc-title-"; + + private String currentValue; + + private static CardLayout card; + + private static final String RELOAD_CARD = "reloadCard"; + private static final String DOC_LIST_CARD = "docListCard"; + + 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); + } + + public void populate(String js) { + contentTextArea.setText(js); + ifHasBeenWriten = 1; + currentPosition = contentTextArea.getCaretPosition(); + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + } + + 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(); + } + }); + contentTextArea.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + insertPosition = contentTextArea.getCaretPosition(); + if (ifHasBeenWriten == 0) { + contentTextArea.setText(StringUtils.EMPTY); + ifHasBeenWriten = 1; + contentTextArea.setForeground(Color.black); + insertPosition = 0; + } + } + + @Override + public void mouseReleased(MouseEvent e) { + currentPosition = contentTextArea.getCaretPosition(); + if (currentPosition == insertPosition) { + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + } + } + }); + } + + @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))); + moduleTree.scrollPathToVisible(moduleTree.getSelectionPath()); + return true; + } + } + 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 = CloudCenter.getInstance().acquireUrlByKind("af.doc_search", 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) { + card = new CardLayout(); + JPanel mainPane = new JPanel(card); + initHelpDocumentList(); + UIScrollPane helpDOCScrollPane = new UIScrollPane(helpDOCList); + helpDOCScrollPane.setPreferredSize(new Dimension(200, 200)); + helpDOCScrollPane.setBorder(null); + mainPane.add(helpDOCScrollPane, DOC_LIST_CARD); + + UILabel imageLabel = new UILabel(); + imageLabel.setIcon(IconUtils.readIcon("com/fr/design/javascript/jsapi/images/connectFailed.svg")); + imageLabel.setPreferredSize(new Dimension(180, 65)); + JPanel imagePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + imagePane.setBorder(BorderFactory.createEmptyBorder(0, 42, 0, 0)); + imagePane.add(imageLabel); + imagePane.setBackground(Color.WHITE); + + UILabel failedLabel = new UILabel(Toolkit.i18nText("Fine-Design_Net_Connect_Failed"), 0); + failedLabel.setPreferredSize(new Dimension(180, 20)); + UILabel reloadLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Reload"), 0); + reloadLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + reloadLabel.setPreferredSize(new Dimension(180, 20)); + reloadLabel.setForeground(Color.blue); + JPanel labelPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, 0, 0, 0); + + labelPane.setBorder(BorderFactory.createEmptyBorder(35, 45, 0, 0)); + labelPane.setBackground(Color.WHITE); + labelPane.add(imagePane); + labelPane.add(failedLabel); + labelPane.add(reloadLabel); + JPanel containerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + containerPanel.add(labelPane, BorderLayout.CENTER); + reloadLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (isNetworkOk()) { + doHelpDocumentSearch(); + card.show(mainPane, DOC_LIST_CARD); + } + } + }); + mainPane.add(containerPanel, RELOAD_CARD); + if (isNetworkOk()) { + doHelpDocumentSearch(); + card.show(mainPane, DOC_LIST_CARD); + } else { + card.show(mainPane, RELOAD_CARD); + } + descriptionAndDocumentPanel.add(this.createNamePane(Toolkit.i18nText("Fine-Design_Relevant_Cases"), mainPane), BorderLayout.EAST); + } + + private void initHelpDocumentList() { + helpDOCList = new JList(new DefaultListModel()); + initHelpDOCListRender(); + initHelpDOCListListener(); + } + + 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(); + browse(url); + } + } + } + }); + } + + private void browse(String url){ + try { + Desktop.getDesktop().browse(new URI(url)); + } catch (IOException | 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() { + DefaultTreeModel defaultTreeModel = (DefaultTreeModel) moduleTree.getModel(); + TreeNode root = (TreeNode) defaultTreeModel.getRoot(); + while (root.getChildCount() > 0){ + root = root.getChildAt(0); + } + moduleTree.setSelectionPath(new TreePath(defaultTreeModel.getPathToRoot(root))); + } + + 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)); + keyWordTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Search_Interface")); + 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/JavaScriptActionPane.java b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java index 999a1a0295..be216a46fa 100644 --- a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java +++ b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java @@ -42,14 +42,13 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane { protected List> initPaneList() { List> paneList = new ArrayList>(); // JS脚本,表单提交,提交入库,流程管理,发送邮件. 703中去掉表单提交和流程管理 - paneList.add(new JavaScriptImplPane(getDefaultArgs())); + paneList.add(new JavaScriptImplPane(getDefaultArgs(),true)); // paneList.add(new FormSubmitJavaScriptPane(this)); contentDBManiPane = new ArrayList(); contentDBManiPane.add(createDBManipulationPane()); paneList.add(new Commit2DBJavaScriptPane(this, contentDBManiPane)); paneList.add(initEmaiPane()); - boolean workbook = DesignerContext.getDesignerFrame().getSelectedJTemplate().isJWorkBook(); - if (workbook) { + if (isWorkBookValid()) { paneList.add(new ExportJavaScriptPane()); } paneList.add(new MobilePopupPane()); @@ -66,6 +65,16 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane { return paneList; } + /** + * 选中的JTemplate是否有效并且是否是工作簿 + * + * @return 选中的JTemplate有效并且是工作簿则返回true + */ + private boolean isWorkBookValid() { + return DesignerContext.getDesignerFrame().getSelectedJTemplate() != null + && DesignerContext.getDesignerFrame().getSelectedJTemplate().isJWorkBook(); + } + protected EmailPane initEmaiPane() { return new EmailPane(); } 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..37bca2f6eb 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,18 +9,23 @@ 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; - import com.fr.js.JavaScriptImpl; import com.fr.stable.ParameterProvider; import com.fr.stable.StringUtils; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JPanel; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridLayout; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -28,11 +33,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 +55,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 +126,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,25 +141,9 @@ 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"))); - - 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(); + return importedJsPane; } /** @@ -140,10 +181,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 +201,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/beautify/JavaScriptFormatHelper.java b/designer-base/src/main/java/com/fr/design/javascript/beautify/JavaScriptFormatHelper.java index 8e794f1924..3634922d01 100644 --- a/designer-base/src/main/java/com/fr/design/javascript/beautify/JavaScriptFormatHelper.java +++ b/designer-base/src/main/java/com/fr/design/javascript/beautify/JavaScriptFormatHelper.java @@ -1,16 +1,13 @@ package com.fr.design.javascript.beautify; -import com.eclipsesource.v8.V8; -import com.eclipsesource.v8.V8Array; -import com.eclipsesource.v8.V8Object; -import com.eclipsesource.v8.utils.V8ObjectUtils; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.EncodeConstants; - import java.io.InputStream; -import java.io.UnsupportedEncodingException; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; public class JavaScriptFormatHelper { @@ -33,22 +30,14 @@ public class JavaScriptFormatHelper { * @see JSBeautify */ public static String beautify(String jsCode, BeautifyOption option) { - InputStream resourceAsStream = IOUtils.readResource("com/fr/design/javascript/beautify/beautify.js"); String result = jsCode; - V8 v8 = V8.createV8Runtime(); - try { - v8.executeVoidScript(IOUtils.inputStream2String(resourceAsStream, EncodeConstants.ENCODING_UTF_8)); - V8Array parameters = new V8Array(v8); - parameters.push(jsCode); - V8Object arg = V8ObjectUtils.toV8Object(v8, option.toFormatArgument()); - parameters.push(arg); - result = v8.executeStringFunction("js_beautify_global", parameters); - parameters.release(); - arg.release(); - } catch (UnsupportedEncodingException e) { + try (InputStream resourceAsStream = IOUtils.readResource("com/fr/design/javascript/beautify/beautify.js")) { + ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("JavaScript"); + nashorn.eval(IOUtils.inputStream2String(resourceAsStream, EncodeConstants.ENCODING_UTF_8)); + Invocable invocable = (Invocable) nashorn; + result = (String) invocable.invokeFunction("js_beautify_global", new Object[]{jsCode, option.toFormatArgument()}); + } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - } finally { - v8.release(true); } return result; } 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/layout/FRGUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java index 071feee6ac..417533465d 100644 --- a/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java +++ b/designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java @@ -13,6 +13,9 @@ import javax.swing.JRadioButton; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.LayoutManager; @@ -148,6 +151,53 @@ public class FRGUIPaneFactory { public static LayoutManager createNColumnGridLayout(int nColumn) { return new FRGridLayout(nColumn); } + + public static LayoutManager createCenterLayout(JComponent centerBody) { + return createCenterLayout(centerBody, 0.5d, 0.3d); + } + + /** + * 将 centerBody 为中心,创建一个布局 + * 注:只有当且仅当有一个组件,且希望组件 上下左右 居中时使用 + * @param centerBody 中心组件 + * @return 布局方式 + */ + public static LayoutManager createCenterLayout(JComponent centerBody, double factorX, double factorY) { + + return new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return centerBody.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + int width = parent.getParent().getWidth(); + int height = parent.getParent().getHeight(); + + // 这个时候大小是不确定的 + int bodyWidth = centerBody.getPreferredSize().width; + int bodyHeight = centerBody.getPreferredSize().height; + int labelX = (int) ((width - bodyWidth) * factorX); + int labelY = (int) ((height - bodyHeight) * factorY); + centerBody.setBounds(labelX, labelY, bodyWidth, bodyHeight); + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }; + } /** * 创建一个带标题边框面板 @@ -557,6 +607,24 @@ public class FRGUIPaneFactory { return jp; } + /** + * 创建垂直流布局,水平填充面板 + * + * @param isAlignLeft 是否左对齐 + * @param align the alignment value + * @param hgap the horizontal gap between components + * @param vgap the vertical gap between components + * @param hfill 水平填充组件 + * @return JPanel对象 + */ + public static JPanel createVerticalFlowLayout_F_Pane(boolean isAlignLeft, int align, int hgap, int vgap, boolean hfill) { + JPanel jp = new JPanel(); + VerticalFlowLayout layout = new VerticalFlowLayout(align, hgap, vgap, hfill); + layout.setAlignLeft(isAlignLeft); + jp.setLayout(layout); + return jp; + } + /** * 创建边框面板L * diff --git a/designer-base/src/main/java/com/fr/design/layout/VerticalFlowLayout.java b/designer-base/src/main/java/com/fr/design/layout/VerticalFlowLayout.java index c857c7301b..9f91fee506 100644 --- a/designer-base/src/main/java/com/fr/design/layout/VerticalFlowLayout.java +++ b/designer-base/src/main/java/com/fr/design/layout/VerticalFlowLayout.java @@ -95,6 +95,15 @@ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { */ protected int vgap; + + /** + * true: 水平填充组件 + * + * @see #isHfill() + * @see #setHfill(boolean) + */ + protected boolean hfill; + /** * Constructs a new FlowLayout with a centered alignment and a * default 5-unit horizontal and vertical gap. @@ -135,6 +144,14 @@ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { setAlignment(align); } + public VerticalFlowLayout(int align, int hgap, int vgap, boolean fill) { + this.hgap = hgap; + this.vgap = vgap; + this.hfill = fill; + + setAlignment(align); + } + /** * Gets the alignment for this layout. * Possible values are FlowLayout.TOP, @@ -219,6 +236,31 @@ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { * @param name the name of the component * @param comp the component to be added */ + + /** + * Gets the horizontal filling of components in the + * Container.The default is false. + * + * @return the horizontal filling of components in the + * Container + * @see #setHfill(boolean) + */ + public boolean isHfill() { + return hfill; + } + + /** + * Sets the horizontal filling of components in the + * Container.The default is false. + * + * @param hfill the horizontal filling of components in the + * Container + * @see #isHfill() + */ + public void setHfill(boolean hfill) { + this.hfill = hfill; + } + @Override public void addLayoutComponent(String name, Component comp) { } @@ -379,6 +421,7 @@ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { Insets insets = target.getInsets(); int maxlen = getMaxLen4LayoutContainer(target, insets); + int maxwidth = target.getWidth() - (insets.left + insets.right); int nmembers = target.getComponentCount(); int x = getX4LayoutContainer(insets), y = getY4LayoutContainer(insets); int roww = 0, start = 0; @@ -390,6 +433,9 @@ public class VerticalFlowLayout implements LayoutManager, java.io.Serializable { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = getPreferredSize(target, m); + if (hfill) { + d.width = maxwidth; + } m.setSize(d.width, d.height); rs = dealWithDim4LayoutContainer(target, insets, d, x, y, roww, start, maxlen, i, ltr); diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java new file mode 100644 index 0000000000..024f991ae5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/locale/impl/ShowOnlineWidgetMark.java @@ -0,0 +1,26 @@ +package com.fr.design.locale.impl; + +import com.fr.general.GeneralContext; +import com.fr.general.locale.LocaleMark; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class ShowOnlineWidgetMark implements LocaleMark { + private Map map = new HashMap<>(); + + public ShowOnlineWidgetMark() { + map.put(Locale.CHINA, true); + map.put(Locale.TAIWAN, true); + map.put(Locale.US, false); + map.put(Locale.KOREA, false); + map.put(Locale.JAPAN, false); + } + + @Override + public Boolean getValue() { + Boolean result = map.get(GeneralContext.getLocale()); + return result == null ? false : result; + } +} 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 new file mode 100644 index 0000000000..003215ca6c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java @@ -0,0 +1,126 @@ +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; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.utils.TemplateUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.general.IOUtils; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.base.UserInfo; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/2 + */ +public class LockInfoDialog extends JDialog { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"); + + public LockInfoDialog(UserInfo userInfo) { + super(DesignerContext.getDesignerFrame()); + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + panel.add(createContentPane(userInfo), BorderLayout.CENTER); + panel.add(createControlPane(), BorderLayout.SOUTH); + this.getContentPane().add(panel); + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Title_Hint")); + this.setSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.lock.LockInfoDialog")); + this.setResizable(false); + this.setModal(true); + GUICoreUtils.centerWindow(this); + this.setVisible(true); + } + + private JPanel createContentPane(UserInfo userInfo) { + JPanel contentPanel = new JPanel(new BorderLayout()); + contentPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + JPanel messagePane = new JPanel(new BorderLayout(13, 0)); + UILabel iconLabel = new UILabel(IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png")); + iconLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); + messagePane.add(iconLabel, BorderLayout.WEST); + UILabel tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Template_Lock_And_SaveAs_Tip")); + tipLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + messagePane.add(tipLabel, BorderLayout.CENTER); + contentPanel.add(messagePane, BorderLayout.NORTH); + JPanel detailInfoPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane(); + detailInfoPane.setBorder(BorderFactory.createEmptyBorder(0, 45, 0,0)); + if (userInfo != null && StringUtils.isNotEmpty(userInfo.getUserName())) { + UILabel label = createLabel(Toolkit.i18nText("Fine-Design_Template_Lock_Holder", userInfo.getUserName())); + label .setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + detailInfoPane.add(label); + } + if (userInfo != null && StringUtils.isNotEmpty(userInfo.getIp())) { + detailInfoPane.add(createLabel(Toolkit.i18nText("Fine-Design_Template_Lock_Holder_Ip", userInfo.getIp()) )); + } + detailInfoPane.add(createLabel(Toolkit.i18nText("Fine-Design_Template_Lock_Get_Time", FORMATTER.format(LocalDateTime.now())))); + contentPanel.add(detailInfoPane, BorderLayout.CENTER); + return contentPanel; + } + + private UILabel createLabel(String text) { + UILabel label = new UILabel(text); + label.setForeground(Color.GRAY); + label.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0)); + return label; + } + + private JPanel createControlPane() { + JPanel controlPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 5)); + controlPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0,5)); + UIButton saveAsButton = new UIButton(Toolkit.i18nText("Fine_Design_Template_Lock_Save_As")); + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")); + saveAsButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + FileNode node = TemplateTreePane.getInstance().getFileNode(); + if (node == null) { + return; + } + final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, TemplateTreePane.getInstance().getFilePath()); + TemplateUtils.createAndOpenTemplate( + Toolkit.i18nText("Fine_Design_Template_Lock_Copy"), + new FileNodeFILE(new FileNode(selectedFilePath, false)), + false, + true); + } + }); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + controlPane.add(saveAsButton); + controlPane.add(cancelButton); + return controlPane; + } + + + public static void show(UserInfo userInfo) { + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(TemplateTreePane.getInstance().getFileNode()); + new LockInfoDialog(userInfo); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/lock/LockInfoUtils.java b/designer-base/src/main/java/com/fr/design/lock/LockInfoUtils.java new file mode 100644 index 0000000000..52a2c526c7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/lock/LockInfoUtils.java @@ -0,0 +1,23 @@ +package com.fr.design.lock; + +import com.fr.report.lock.DefaultLockInfoOperator; +import com.fr.report.lock.LockInfoOperator; +import com.fr.start.server.FineEmbedServer; +import com.fr.workspace.WorkContext; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/8 + */ +public class LockInfoUtils { + + public static boolean isCompatibleOperator() { + LockInfoOperator lockInfoOperator = WorkContext.getCurrent().get(LockInfoOperator.class); + return lockInfoOperator instanceof DefaultLockInfoOperator; + } + + public static boolean unableGetLockInfo() { + return WorkContext.getCurrent().isLocal() && !FineEmbedServer.isRunning(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/login/DesignerLoginHelper.java b/designer-base/src/main/java/com/fr/design/login/DesignerLoginHelper.java index 2d2dd935d1..8976a07345 100644 --- a/designer-base/src/main/java/com/fr/design/login/DesignerLoginHelper.java +++ b/designer-base/src/main/java/com/fr/design/login/DesignerLoginHelper.java @@ -47,7 +47,7 @@ public class DesignerLoginHelper { } public static void showLoginDialog(DesignerLoginSource source, Map params, Window window) { - if (!SupportOSImpl.DESIGNER_LOGIN.support()) { + if (!SupportOSImpl.DESIGNER_LOGIN.support() || DesignerEnvManager.getEnvManager().isUseOldVersionLogin()) { WebViewDlgHelper.createLoginDialog(window); return; } diff --git a/designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java b/designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java new file mode 100644 index 0000000000..36988aa5ca --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java @@ -0,0 +1,48 @@ +package com.fr.design.login.config; + +import com.fr.log.FineLoggerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * @author Lanlan + * @version 10.0 + * Created by Lanlan on 2022/6/20 + */ +public class DefaultLoginKeys { + + private static final String FILENAME = "com/fr/design/config/default"; + + private static final DefaultLoginKeys INSTANCE = new DefaultLoginKeys(); + + public static DefaultLoginKeys getInstance() { + return INSTANCE; + } + + private final Map keys = new HashMap<>(); + + private DefaultLoginKeys() { + Properties properties = load(); + for (Map.Entry entry : properties.entrySet()) { + String name = entry.getKey().toString(); + keys.put(name, entry.getValue().toString()); + } + } + + public String getKey(String name) { + return keys.get(name); + } + + private Properties load() { + Properties properties = new Properties(); + try (InputStream inputStream = DefaultLoginKeys.class.getClassLoader().getResourceAsStream(FILENAME)) { + properties.load(inputStream); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return properties; + } +} diff --git a/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java b/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java index a0ab68109d..b0fb0e292a 100644 --- a/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java @@ -70,6 +70,10 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { * 插件管理第一次启动时的提醒 */ private boolean pluginRemindOnFirstLaunch = true; + /** + * 使用旧版登录 + */ + private boolean useOldVersionLogin = false; private DesignerLoginConfigManager() { @@ -98,6 +102,7 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { this.setLastLoginAccount(reader.getAttrAsString("lastLoginAccount", StringUtils.EMPTY)); this.setLoginRemindBeforeJumpBBS(reader.getAttrAsBoolean("loginRemindBeforeJumpBBS", true)); this.setPluginRemindOnFirstLaunch(reader.getAttrAsBoolean("pluginRemindOnFirstLaunch", true)); + this.setUseOldVersionLogin(reader.getAttrAsBoolean("useOldVersionLogin", false)); } } @@ -117,6 +122,7 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { writer.attr("lastLoginAccount", lastLoginAccount); writer.attr("loginRemindBeforeJumpBBS", loginRemindBeforeJumpBBS); writer.attr("pluginRemindOnFirstLaunch", pluginRemindOnFirstLaunch); + writer.attr("useOldVersionLogin", useOldVersionLogin); writer.end(); } @@ -223,4 +229,12 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { public void setPluginRemindOnFirstLaunch(boolean pluginRemindOnFirstLaunch) { this.pluginRemindOnFirstLaunch = pluginRemindOnFirstLaunch; } + + public boolean isUseOldVersionLogin() { + return useOldVersionLogin; + } + + public void setUseOldVersionLogin(boolean useOldVersionLogin) { + this.useOldVersionLogin = useOldVersionLogin; + } } diff --git a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java index b3513bb6da..3e4c0dae51 100644 --- a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java +++ b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java @@ -8,9 +8,7 @@ import com.fr.design.login.utils.DesignerLoginUtils; import com.fr.design.mainframe.DesignerContext; import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.update.push.DesignerPushUpdateManager; -import com.fr.general.CloudCenter; -import com.fr.general.CloudCenterConfig; -import com.fr.general.http.HttpToolbox; +import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import javax.swing.WindowConstants; @@ -39,7 +37,11 @@ public class DesignerGuideHelper { public static void prepareShowGuideDialog() { // 如果存在更新升级的弹窗,则不显示引导页面 - if (!DesignerLoginUtils.isOnline() || !SupportOSImpl.DESIGNER_LOGIN.support() || !FRContext.isChineseEnv() || DesignerPushUpdateManager.getInstance().isShouldPopUp()) { + if (!DesignerLoginUtils.isOnline() + || !SupportOSImpl.DESIGNER_LOGIN.support() + || !FRContext.isChineseEnv() + || DesignerPushUpdateManager.getInstance().isShouldPopUp() + || DesignerEnvManager.getEnvManager().isUseOldVersionLogin()) { return; } if (isActivatedForOneWeek()) { @@ -52,7 +54,11 @@ public class DesignerGuideHelper { DesignerContext.getDesignerFrame().addDesignerOpenedListener(new DesignerOpenedListener() { @Override public void designerOpened() { - showGuideDialog(); + try { + showGuideDialog(); + } catch (Throwable t) { + FineLoggerFactory.getLogger().warn(t.getMessage(), t); + } } }); } diff --git a/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java b/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java index d60b97d0f6..2353965581 100644 --- a/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java +++ b/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java @@ -1,5 +1,6 @@ package com.fr.design.login.socketio; +import com.fr.concurrent.NamedThreadFactory; import com.fr.design.DesignerEnvManager; import com.fr.design.login.DesignerLoginType; import com.fr.design.login.bean.BBSAccountLogin; @@ -11,7 +12,11 @@ import com.fr.third.socketio.Configuration; import com.fr.third.socketio.SocketIOClient; import com.fr.third.socketio.SocketIOServer; import com.fr.third.socketio.listener.DataListener; + import java.net.URLDecoder; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author Lanlan @@ -19,9 +24,11 @@ import java.net.URLDecoder; * Created by Lanlan on 2021/6/3 */ public class LoginAuthServer { + + private AtomicBoolean started = new AtomicBoolean(false); private SocketIOServer server; - + private static final String HOSTNAME = "localhost"; private static final int PORT = 41925; @@ -47,10 +54,27 @@ public class LoginAuthServer { } public void start() { + + // 只运行一次,不在乎成不成功 + if (started.compareAndSet(false, true)) { + asyncStart(); + } + } + + public void asyncStart() { + + ExecutorService asyncService = Executors.newSingleThreadExecutor(new NamedThreadFactory(LoginAuthServer.class.getName(), true)); + asyncService.submit(this::compatibleStart); + asyncService.shutdown(); + } + + @Deprecated + public void compatibleStart() { + try { server.start(); } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineLoggerFactory.getLogger().warn(e.getMessage(), e); } } diff --git a/designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java b/designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java index a39a0be4bf..8845f00e1f 100644 --- a/designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java +++ b/designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java @@ -1,6 +1,7 @@ package com.fr.design.login.utils; import com.fr.design.DesignerEnvManager; +import com.fr.design.login.config.DefaultLoginKeys; import com.fr.design.mainframe.toast.DesignerToastMsgUtil; import com.fr.general.CloudCenter; import com.fr.general.CloudCenterConfig; @@ -28,8 +29,6 @@ public class DesignerLoginUtils { private static final String PRODUCT_FINEREPORT = "product-finereport"; - private static final String KEY = "i7hP48WAcuTrmxfN"; - public static Map renderMap() { Map map4Tpl = new HashMap<>(); map4Tpl.put("language", GeneralContext.getLocale().toString()); @@ -86,7 +85,11 @@ public class DesignerLoginUtils { jo.put("username", manager.getDesignerLoginUsername()); jo.put("source", PRODUCT_FINEREPORT); byte[] iv = randomIv(); - return new String(Hex.encode(iv)) + encrypt(jo.toString(), KEY.getBytes(), iv); + return new String(Hex.encode(iv)) + encrypt( + jo.toString(), + DefaultLoginKeys.getInstance().getKey("Fine-Designer_Login").getBytes(), + iv + ); } private static byte[] randomIv() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/AbsoluteMeasureUIMode.java b/designer-base/src/main/java/com/fr/design/mainframe/AbsoluteMeasureUIMode.java new file mode 100644 index 0000000000..2085127d73 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/AbsoluteMeasureUIMode.java @@ -0,0 +1,37 @@ +package com.fr.design.mainframe; + +import com.fr.base.AutoChangeLineProvider; +import com.fr.base.DefaultAutoChangeLine; +import com.fr.base.ScreenResolution; +import com.fr.design.fun.ReportLengthUNITProvider; +import com.fr.design.unit.UnitConvertUtil; + +public class AbsoluteMeasureUIMode implements DesignerUIMode { + + private static class AbsoluteMeasureUIModeHolder { + private static final AbsoluteMeasureUIMode absoluteMeasureUIMode = new AbsoluteMeasureUIMode(); + } + + private AbsoluteMeasureUIMode() { + + } + + public static AbsoluteMeasureUIMode getInstance() { + return AbsoluteMeasureUIModeHolder.absoluteMeasureUIMode; + } + + @Override + public ReportLengthUNITProvider parseLengthUNIT(int unitType) { + return UnitConvertUtil.parseLengthUNIT(unitType); + } + + @Override + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return new DefaultAutoChangeLine(); + } + + @Override + public int getScreenResolution() { + return ScreenResolution.getScreenResolution(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java b/designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java index d3cff1ff95..dc36836c16 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java @@ -10,7 +10,7 @@ import javax.swing.JComponent; * Date: 13-7-15 * Time: 上午10:28 */ -public interface BaseJForm extends JTemplateProvider { +public interface BaseJForm extends JTemplateProvider, JDashboard { String XML_TAG = "JForm"; int FORM_TAB = 0; @@ -58,4 +58,9 @@ public interface BaseJForm extends JTemplateProvider { * @param ecContainer ElementCase所在container */ void tabChanged(int index, FormElementCaseContainerProvider ecContainer); + + @Override + default void switchToDashBoardEditor() { + tabChanged(FORM_TAB); + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java index d31b5ede09..b18b346525 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java @@ -4,7 +4,7 @@ import com.fr.design.DesignState; import com.fr.design.base.mode.DesignModeContext; import com.fr.design.constants.UIConstants; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.file.NewTemplatePane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.imenu.UIMenuHighLight; @@ -87,7 +87,7 @@ public class CenterRegionContainerPane extends JPanel { eastCenterPane.add(combineUp, BorderLayout.NORTH); templateTabPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); templateTabPane.add(newWorkBookPane = getToolBarMenuDock().getNewTemplatePane(), BorderLayout.WEST); - templateTabPane.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER); + templateTabPane.add(MultiTemplateTabPane.getInstance(), BorderLayout.CENTER); eastCenterPane.add(templateTabPane, BorderLayout.CENTER); eastPane.add(eastCenterPane, BorderLayout.CENTER); @@ -156,7 +156,7 @@ public class CenterRegionContainerPane extends JPanel { private void addExtraButtons() { JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (jt == null) { + if (!JTemplate.isValid(jt)) { return; } @@ -172,7 +172,7 @@ public class CenterRegionContainerPane extends JPanel { private void addCheckButton() { JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (jt == null) { + if (!JTemplate.isValid(jt)) { return; } combineUp.addSeparator(new Dimension(2, 16)); @@ -185,7 +185,7 @@ public class CenterRegionContainerPane extends JPanel { private void addShareButton() { JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (jt == null) { + if (!JTemplate.isValid(jt)) { return; } @@ -205,7 +205,7 @@ public class CenterRegionContainerPane extends JPanel { protected void checkCombineUp(boolean flag, ArrayList al) { //Yvan: 检查当前是否为WORK_SHEET状态,因为只有WORK_SHEET中含有格式刷组件,此时是不需要进行checkComponentsByNames的 JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (jTemplate != null) { + if (JTemplate.isValid(jTemplate)) { // 第一个条件满足后还需要添加一重判断,判断是编辑报表块还是参数面板,编辑报表块时则直接return if (jTemplate.getMenuState() == DesignState.WORK_SHEET && !jTemplate.isUpMode()) { return; @@ -220,7 +220,7 @@ public class CenterRegionContainerPane extends JPanel { * * @param plus 工具条中相关信息 */ - protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad) { + protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad, ToolKitConfigStrategy strategy) { resetCombineUpTooBar(ad.resetUpToolBar(plus), plus); @@ -230,28 +230,40 @@ public class CenterRegionContainerPane extends JPanel { // 颜色,字体那些按钮的工具栏 toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER); - - if (plus.hasToolBarPane()) { + if (strategy.hasToolBarPane(plus)) { this.add(toolbarPane, BorderLayout.NORTH); } else { this.remove(toolbarPane); } + if (strategy.hasTemplateTabPane(plus)) { + eastCenterPane.add(templateTabPane, BorderLayout.CENTER); + } else { + eastCenterPane.remove(templateTabPane); + } + + if (strategy.hasCombineUp(plus)) { + eastCenterPane.add(combineUp, BorderLayout.NORTH); + } else { + eastCenterPane.remove(combineUp); + } resetByDesignMode(); } private void resetByDesignMode() { if (DesignModeContext.isDuchampMode()) { eastPane.remove(largeToolbar); - eastCenterPane.remove(templateTabPane); - centerTemplateCardPane.refresh(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()); + //移除新建模板按钮 + templateTabPane.remove(newWorkBookPane); } else { eastPane.add(largeToolbar, BorderLayout.WEST); - eastCenterPane.add(templateTabPane, BorderLayout.CENTER); - } + templateTabPane.add(newWorkBookPane, BorderLayout.WEST); + } } + + JComponent getToolbarComponent() { return this.toolbarComponent; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java b/designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java index 2175804dcf..2dc77bb62c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java @@ -12,7 +12,7 @@ import com.fr.design.notification.SnapChatKey; * Created by kerry on 5/8/21 */ public class ComponentReuseNotifyUtil { - private static final String COMPONENT_SNAP_CHAT_KEY = "com.fr.component.share-components"; + public static final String COMPONENT_SNAP_CHAT_KEY = "com.fr.component.share-components"; private ComponentReuseNotifyUtil() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java b/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java new file mode 100644 index 0000000000..305c44aa21 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java @@ -0,0 +1,21 @@ +package com.fr.design.mainframe; + +import com.fr.design.base.mode.DesignModeContext; +import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; + +public class DefaultToolKitConfig implements ToolKitConfigStrategy { + @Override + public boolean hasTemplateTabPane(ToolBarMenuDockPlus plus) { + return !DesignModeContext.isDuchampMode(); + } + + @Override + public boolean hasCombineUp(ToolBarMenuDockPlus plus) { + return plus.hasToolBarPane(); + } + + @Override + public boolean hasToolBarPane(ToolBarMenuDockPlus plus) { + return plus.hasToolBarPane(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerContext.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerContext.java index 49fffa6cef..4079ae7b22 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerContext.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerContext.java @@ -7,6 +7,7 @@ import com.fr.base.Style; import com.fr.design.base.clipboard.DesignerClipboard; import com.fr.design.designer.TargetComponent; import com.fr.design.dialog.BasicDialog; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.log.FineLoggerFactory; import com.fr.stable.StableUtils; @@ -25,6 +26,8 @@ public class DesignerContext { private static Clipboard clipboard = null; //当前的剪贴板. private static int formatState = FORMAT_STATE_NULL; private static Style[][] referencedStyle = null; + private static String referencedStyleFromTemplatePath = null; + private static TargetComponent referencedElementCasePane; private static int referencedIndex = 0; private static ThreadLocal reportWriteThread = new ThreadLocal(); @@ -114,12 +117,19 @@ public class DesignerContext { public static void setReferencedStyle(Style[][] styles) { referencedStyle = styles; + + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + referencedStyleFromTemplatePath = currentTemplate != null ? currentTemplate.getPath() : null; } public static Style[][] getReferencedStyle() { return referencedStyle; } + public static String getReferencedStyleFromTemplatePath() { + return referencedStyleFromTemplatePath; + } + public static void setReferencedElementCasePane(TargetComponent t) { referencedElementCasePane = t; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java index 6270413f51..e88d0c946c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java @@ -4,6 +4,7 @@ package com.fr.design.mainframe; import com.fr.base.BaseUtils; +import com.fr.base.OptimizeUtil; import com.fr.design.DesignModelAdapter; import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; @@ -20,7 +21,7 @@ import com.fr.design.event.TargetModifiedEvent; import com.fr.design.event.TargetModifiedListener; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.file.TemplateTreePane; import com.fr.design.fun.OemProcessor; @@ -28,15 +29,20 @@ import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider; import com.fr.design.gui.iprogressbar.ProgressDialog; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockInfoDialog; +import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.design.menu.ShortCut; import com.fr.design.os.impl.MacOsAddListenerAction; import com.fr.design.os.impl.SupportOSImpl; +import com.fr.design.utils.TemplateUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.event.EventDispatcher; import com.fr.exception.DecryptTemplateException; +import com.fr.exception.TplLockedException; +import com.fr.exit.ConfigToPropMigrator; import com.fr.exit.DesignerExiter; import com.fr.file.FILE; import com.fr.file.FILEFactory; @@ -53,6 +59,7 @@ import com.fr.stable.os.OperatingSystem; import com.fr.stable.os.support.OSSupportCenter; import com.fr.stable.project.ProjectConstants; import com.fr.start.OemHandler; +import com.fr.start.common.DesignerOpenEmptyPanel; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; import com.fr.workspace.connect.WorkspaceConnectionInfo; @@ -95,6 +102,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; public class DesignerFrame extends JFrame implements JTemplateActionListener, TargetModifiedListener { @@ -153,23 +161,24 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta @Override public void windowClosing(WindowEvent e) { + // 检查mini商城是否存在未结束的后台任务 + if (!MiniShopDisposingChecker.check()) { + return; + } + // 关闭前check if (!TemplateSavingChecker.check()) { return; } //关闭前当前模板 停止编辑 - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing(); - SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true); - // 只有一个文件未保存时 - if (HistoryTemplateListCache.getInstance().getHistoryCount() == 1) { - int choose = saveSomeTempaltePane.saveLastOneTemplate(); - if (choose != JOptionPane.CANCEL_OPTION) { - DesignerFrame.this.exit(); - } - } else { - if (saveSomeTempaltePane.showSavePane()) { - DesignerFrame.this.exit(); - } + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + currentEditingTemplate.stopEditing(); + } + SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true); + // 全部保存成功才退出 + if (saveSomeTemplatePane.showSavePane()) { + DesignerFrame.this.exit(); } } @@ -296,10 +305,15 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } public void resizeFrame() { - - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().setComposite(); + + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + currentEditingTemplate.setComposite(); + } reCalculateFrameSize(); - HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().doResize(); + if (currentEditingTemplate != null) { + currentEditingTemplate.doResize(); + } } @Deprecated @@ -358,7 +372,12 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta public void fireDesignerOpened() { for (DesignerOpenedListener listener : designerOpenedListenerList) { - listener.designerOpened(); + // 捕获下异常 避免造成启动过程监听触发异常导致设计器闪退 + try { + listener.designerOpened(); + } catch (Throwable e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } } designerOpened = true; @@ -603,6 +622,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta * @param plus 工具条中相关信息 */ public void resetToolkitByPlus(ToolBarMenuDockPlus plus) { + resetToolkitByPlus(plus, new DefaultToolKitConfig()); + } + + public void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolKitConfigStrategy strategy) { if (plus == null) { plus = ToolBarMenuDock.NULLAVOID; @@ -610,7 +633,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta NorthRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad); - CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad); + CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad, strategy); this.checkToolbarMenuEnable(); this.validate(); @@ -673,12 +696,12 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta username = connection == null ? StringUtils.EMPTY : connection.getUserName(); } defaultTitleSB.append(username).append("@").append(envName).append("[").append(workspace.getDescription()).append("]"); - if (editingTemplate != null) { + if (JTemplate.isValid(editingTemplate)) { String path = editingTemplate.getPath(); if (!editingTemplate.getEditingFILE().exists()) { path = FILEFactory.MEM_PREFIX + path; } else if (path.startsWith(ProjectConstants.REPORTLETS_NAME)) { - path = workspace.getPath() + File.separator + path; + path = workspace.getPath() + File.separator + TemplateUtils.createLockeTemplatedName(editingTemplate, path); } defaultTitleSB.append(" ").append(path); } @@ -783,6 +806,24 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } } } + + public void showEmptyJTemplate() { + + DesignerOpenEmptyPanel designerOpenEmptyPanel = new DesignerOpenEmptyPanel(); + BorderLayout layout = (BorderLayout) basePane.getLayout(); + basePane.remove(layout.getLayoutComponent(BorderLayout.CENTER)); + basePane.remove(layout.getLayoutComponent(BorderLayout.EAST)); + basePane.add(designerOpenEmptyPanel, BorderLayout.CENTER); + + resetToolkitByPlus(ToolBarMenuDock.NULLAVOID); + + // 这里挺恶心的,是为了保证对插件的兼容性适配 + // 不然的话,插件就会 npe + // 见 https://work.fineres.com/browse/REPORT-76091 + HistoryTemplateListCache.getInstance().setCurrentEditingTemplate(JNullTemplate.NULL); + + layeredPane.repaint(); + } /** * 添加新建模板, 并激活. @@ -845,6 +886,54 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta layeredPane.repaint(); } + /** + * 激活模板 + *

+ * activateJTemplate需要模板存在,openTemplate需要模板保存过,该方法模板保存与未保存皆可激活,模板如果关闭,并且保存过,会重新打开 + * + * @param templatePath 模板路径 template.getPath() + */ + public void openOrActiveTemplate(String templatePath) { + //没保存过的模板如果要激活就要从当前历史模板列表里面找 + String templateName = getTemplateNameFromPath(templatePath); + if (isTemplateNeverSaved(templatePath)) { + int index = HistoryTemplateListCache.getInstance().contains(templateName); + //如果历史模板列表中存在则激活 + if (index != -1) { + DesignerContext.getDesignerFrame().activateJTemplate(HistoryTemplateListCache.getInstance().getTemplate(index)); + } + } else { + DesignerContext.getDesignerFrame().openTemplate(FILEFactory.createFILE(templatePath)); + } + } + + /** + * 指定路径的模板是否保存过 + * + * @param templatePath 模板路径 template.getPath() + * @return 如果模板没保存过则返回true + */ + private boolean isTemplateNeverSaved(String templatePath) { + FILE tplFile = FILEFactory.createFILE(templatePath); + //没保存过的模板获取到的templatePath所生成的FILE文件会不存在 + return tplFile == null || !tplFile.exists() || StringUtils.isEmpty(templatePath); + } + + /** + * 根据模板路径获取模板名称 + * @param templatePath 模板路径 template.getPath() + * @return 模板名 + */ + private String getTemplateNameFromPath(String templatePath) { + FILE tplFile = FILEFactory.createFILE(templatePath); + String templateName = StringUtils.EMPTY; + if (tplFile != null) { + templateName = tplFile.getName(); + } + return templateName; + } + + /** * 当前模板 停用失败 * @@ -962,6 +1051,11 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } } catch (Throwable t) { FineLoggerFactory.getLogger().error(t.getMessage(), t); + if (t.getCause() instanceof TplLockedException) { + TemplateTreePane.getInstance().getFileNode().setLock(UUID.randomUUID().toString()); + LockInfoDialog.show(null); + return; + } addAndActivateJTemplate(); } @@ -1016,7 +1110,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta // 新的form不往前兼容 if (inValidDesigner(jt)) { this.addAndActivateJTemplate(); - MutilTempalteTabPane.getInstance().setTemTemplate( + MultiTemplateTabPane.getInstance().setTemTemplate( HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()); } else { this.addAndActivateJTemplate(jt); @@ -1042,7 +1136,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta } JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (jt != null) { + if (JTemplate.isValid(jt)) { DesignerEnvManager.getEnvManager().setLastOpenFile(jt.getEditingFILE().getPath()); } @@ -1055,6 +1149,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta DesignerEnvManager.getEnvManager().setLastEastRegionContainerWidth( EastRegionContainerPane.getInstance().getContainerWidth()); + OptimizeUtil.open(() -> { + ConfigToPropMigrator.getInstance().execute(); + }); + DesignerEnvManager.getEnvManager().saveXMLFile(); } @@ -1181,6 +1279,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta /** * 判断是否正在进行服务器配置 + * * @return boolean */ public boolean isServerConfig() { @@ -1189,9 +1288,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta /** * 设置是否正在进行服务器配置 + * * @param serverConfig */ public void setServerConfig(boolean serverConfig) { this.serverConfig = serverConfig; } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java index 2925e03a84..8cfd263421 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java @@ -8,16 +8,20 @@ import com.fr.design.DesignModelAdapter; import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; +import com.fr.design.actions.file.DelFileAction; +import com.fr.design.actions.file.LocateAction; +import com.fr.design.actions.file.RenameAction; import com.fr.design.constants.UIConstants; import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.datapane.TableDataTreePane; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; import com.fr.design.data.tabledata.ResponseDataSourceChange; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.FileOperations; import com.fr.design.file.FileToolbarStateChangeListener; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.file.TemplateTreePane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; @@ -28,20 +32,22 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateTreeSearchToolbarPane; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.design.mainframe.vcs.ui.FileVersionsPanel; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; import com.fr.design.roleAuthority.RolesAlreadyEditedPane; +import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.event.Event; -import com.fr.event.EventDispatcher; -import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralContext; +import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fr.plugin.context.PluginContext; import com.fr.plugin.injectable.PluginModule; @@ -55,6 +61,7 @@ import com.fr.stable.project.ProjectConstants; import com.fr.third.org.apache.commons.io.FilenameUtils; import com.fr.workspace.WorkContext; +import com.fr.report.lock.LockInfoOperator; import javax.swing.BorderFactory; import javax.swing.JDialog; import javax.swing.JOptionPane; @@ -77,14 +84,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import static javax.swing.JOptionPane.WARNING_MESSAGE; public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarStateChangeListener, ResponseDataSourceChange { - public static final Event> TEMPLATE_RENAME = new Event>() { + + public static final com.fr.event.Event> TEMPLATE_RENAME = new Event>() { }; private static final String FILE = "file"; + public static final String FILE_NAME_LIMIT = "^[^/\\\\:<>\\*\\|\"\\?]+$"; private static volatile DesignerFrameFileDealerPane THIS; static { @@ -101,6 +111,23 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt return context.contain(PluginModule.ExtraDesign, ShortCut.TEMPLATE_TREE); } }); + GeneralContext.listenPluginRunningChanged(new PluginEventListener() { + @Override + public void on(PluginEvent event) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + DesignerFrameFileDealerPane.getInstance().refresh(); + DesignerFrameFileDealerPane.getInstance().stateChange(); + } + }); + } + }, new PluginFilter() { + @Override + public boolean accept(PluginContext context) { + return context.contain(PluginModule.ExtraDesign, App.MARK_STRING); + } + }); } private List otherToolbarStateChangeListeners = new ArrayList<>(); @@ -109,6 +136,8 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt private UIToolbar toolBar; + private UIToolbar rightToolBar; + private NewFolderAction newFolderAction = new NewFolderAction(); private RefreshTreeAction refreshTreeAction = new RefreshTreeAction(); @@ -121,6 +150,13 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt private VcsAction vcsAction = new VcsAction(); + //搜索 + private SwitchAction switchAction = new SwitchAction(); + private TemplateTreeSearchToolbarPane searchToolbarPane; + + //定位、收起 + private LocateAction locateAction = new LocateAction(); + private CollapseAllAction collapseAllAction = new CollapseAllAction(); private DesignerFrameFileDealerPane() { @@ -130,12 +166,15 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt toolBar.setBorderPainted(true); JPanel tooBarPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); JPanel parent = new JPanel(new BorderLayout()); - parent.add(toolBar, BorderLayout.CENTER); + parent.add(createUpToolBarPane(), BorderLayout.CENTER); parent.setBorder(BorderFactory.createEmptyBorder(3, 0, 4, 0)); tooBarPane.add(parent, BorderLayout.CENTER); tooBarPane.add(new UIMenuHighLight(), BorderLayout.SOUTH); - add(tooBarPane, BorderLayout.NORTH); + searchToolbarPane = new TemplateTreeSearchToolbarPane(toolBar); + searchToolbarPane.add(createUpToolBarPane(), BorderLayout.EAST); + searchToolbarPane.setPreferredSize(new Dimension(this.getWidth(), 23)); + add(searchToolbarPane, BorderLayout.NORTH); CardLayout card; JPanel cardPane = new JPanel(card = new CardLayout()); cardPane.add(TemplateTreePane.getInstance(), FILE); @@ -144,7 +183,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt card.show(cardPane, FILE); TemplateTreePane.getInstance().setToolbarStateChangeListener(this); - add(cardPane, BorderLayout.CENTER); stateChange(); } @@ -168,14 +206,76 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt selectedOperation.refresh(); } + /** + * 刷新根目录并退出搜索模式 + */ + public void refreshAndOutOfSearch() { + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + TemplateTreeSearchManager.getInstance().outOfSearchMode(); + } + refresh(); + } + + private JPanel createUpToolBarPane() { + JPanel panel = new JPanel(new BorderLayout()); + if (WorkContext.getCurrent().isRoot()) { + rightToolBar = new UIToolbar(FlowLayout.RIGHT); + rightToolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIConstants.TOOLBAR_BORDER_COLOR)); + rightToolBar.setBorderPainted(true); + UILabel tipLabel = new UILabel(Toolkit.i18nText("Fine_Design_Template_Lock_Status")); + tipLabel.setForeground(Color.GRAY); + rightToolBar.add(tipLabel); + UIButton button = new UIButton(IOUtils.readIcon("/com/fr/design/images/toolbarbtn/lock.png")); + button.setRolloverIcon(IOUtils.readIcon("/com/fr/design/images/toolbarbtn/unlock.png")); + button.setBorderPainted(false); + button.setContentAreaFilled(false); + button.set4ToolbarButton(); + button.setToolTipText(Toolkit.i18nText("Fine_Design_Template_Unlock_Tip")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine_Design_Template_UnLock_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png"), + new Object[] {Toolkit.i18nText("Fine_Design_Template_UnLock_I_Known"), Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")}, null); + if (option == JOptionPane.YES_OPTION) { + String path = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, TemplateTreePane.getInstance().getTemplateFileTree().getSelectedTemplatePath()); + boolean success = WorkContext.getCurrent().get(LockInfoOperator.class).unLockTpl(path); + if (success) { + FileNode fileNode = TemplateTreePane.getInstance().getFileNode(); + refreshRightToolBarBy(fileNode); + } else { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Template_Unlock_Failed"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.WARNING_MESSAGE); + FineLoggerFactory.getLogger().error("Unlock {} failed", path); + } + TemplateTreePane.getInstance().refresh(); + } + } + }); + rightToolBar.add(button); + refreshRightToolBarBy(TemplateTreePane.getInstance().getFileNode()); + panel.add(rightToolBar, BorderLayout.EAST); + } + return panel; + } + public final void setCurrentEditingTemplate(JTemplate jt) { DesignModelAdapter.setCurrentModelAdapter(jt.getModel()); fireDSChanged(); + if (TableDataTreeSearchManager.getInstance().isInSearchMode()) { + TableDataTreeSearchManager.getInstance().outOfSearchMode(); + } TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()); HistoryTemplateListPane.getInstance().setCurrentEditingTemplate(jt); //处理自动新建的模板 - MutilTempalteTabPane.getInstance().doWithtemTemplate(); + MultiTemplateTabPane.getInstance().doWithtemTemplate(); if (DesignerMode.isAuthorityEditing()) { RolesAlreadyEditedPane.getInstance().refreshDockingView(); } @@ -209,6 +309,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt toolbarDef.addShortCut(shortCut); } addVcsAction(toolbarDef); + toolbarDef.addShortCut(locateAction, collapseAllAction, switchAction); toolbarDef.updateToolBar(toolBar); resetActionStatus(); refresh(); @@ -326,7 +427,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt public NewFolderAction() { this.setName(KeySetUtils.NEW_FOLDER.getMenuKeySetName()); - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/new_folder"); + this.setSmallIcon("/com/fr/design/standard/newfolder/new_folder"); } @Override @@ -346,13 +447,45 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } + private class SwitchAction extends UpdateAction { + + public SwitchAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Search")); + this.setMnemonic('S'); + this.setSmallIcon("/com/fr/design/standard/search", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + // 交换层级 + searchToolbarPane.switchPane(TemplateTreeSearchToolbarPane.SEARCH_PANE); + refreshRightToolBarByContentPaneType(); + TemplateTreePane.getInstance().refreshDockingView(); + TemplateTreeSearchManager.getInstance().switchToSearch(TemplateTreePane.getInstance().getTemplateFileTree()); + } + } + + public class CollapseAllAction extends UpdateAction { + + public CollapseAllAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Collapse_All")); + this.setSmallIcon("/com/fr/design/standard/collapse_all", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + TemplateTreePane.getInstance().refreshDockingView(); + refreshDockingView(); + } + } + /** * 版本管理 */ private class VcsAction extends UpdateAction { public VcsAction() { - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/vcs_list"); + this.setSmallIcon("/com/fr/design/standard/vcslist/vcs_list"); } @Override @@ -414,10 +547,10 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt for (JTemplate jTemplate : HistoryTemplateListCache.getInstance().getHistoryList()) { if (ComparatorUtils.equals(jTemplate.getEditingFILE().getPath(), path)) { if (isCurrentEditing) { - MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(true); } - MutilTempalteTabPane.getInstance().closeFormat(jTemplate); - MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jTemplate); + MultiTemplateTabPane.getInstance().closeFormat(jTemplate); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(jTemplate); return; } } @@ -434,7 +567,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt public ShowInExplorerAction() { this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Show_In_Containing_Folder")); - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/view_folder"); + this.setSmallIcon("/com/fr/design/standard/viewfolder/view_folder"); } @Override @@ -451,7 +584,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt public RefreshTreeAction() { this.setName(Toolkit.i18nText("Fine-Design_Basic_Refresh")); - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/refresh"); + this.setSmallIcon("/com/fr/design/standard/refresh", false); } @Override @@ -461,288 +594,37 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } } - /* - * 重命名文件 + /** + * 搜索状态下不显示rightToolBar */ - private class RenameAction extends UpdateAction { - - public RenameAction() { - - this.setName(Toolkit.i18nText("Fine-Design_Basic_Rename")); - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/rename"); - } - - @Override - public void actionPerformed(ActionEvent evt) { - if (!selectedOperation.access()) { - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), - Toolkit.i18nText("Fine-Design_Basic_Alert"), - WARNING_MESSAGE); - return; + public void refreshRightToolBarByContentPaneType() { + if (rightToolBar != null) { + if (StringUtils.equals(TemplateTreeSearchToolbarPane.contentPaneType, TemplateTreeSearchToolbarPane.SEARCH_PANE)) { + rightToolBar.setVisible(false); } - - FileNode node = selectedOperation.getFileNode(); - String lock = node.getLock(); - if (lock != null && !lock.equals(node.getUserID())) { - // 提醒被锁定模板无法重命名 - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Basic_Unable_Rename_Locked_File"), - Toolkit.i18nText("Fine-Design_Basic_Alert"), - WARNING_MESSAGE); - return; - } - - new FileRenameDialog(node); - MutilTempalteTabPane.getInstance().repaint(); - stateChange(); } - } - /* - * 删除指定文件 - */ - private class DelFileAction extends UpdateAction { - - public DelFileAction() { - - this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove")); - this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/remove"); - } - - @Override - public void actionPerformed(ActionEvent evt) { - - if (!selectedOperation.access()) { - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), - Toolkit.i18nText("Fine-Design_Basic_Alert"), - WARNING_MESSAGE); - return; - } - selectedOperation.deleteFile(); - stateChange(); - DesignerContext.getDesignerFrame().setTitle(); - } + public void refreshRightToolBarBy(FileNode fileNode) { + refreshRightToolBarByNode(fileNode); + refreshRightToolBarByContentPaneType(); } /** - * 重命名对话框 - * 支持快捷键Enter,ESC + * 根据当前选中节点判断是否锁定状态 + * + * @param fileNode 选中文件节点 */ - private class FileRenameDialog extends JDialog { - - private UITextField nameField; - - private UILabel warnLabel; - - private UIButton confirmButton; - - /** - * 操作的节点 - */ - private FileNodeFILE fnf; - - - private FileRenameDialog(FileNode node) { - if (node == null) { - return; - } - fnf = new FileNodeFILE(node); - - String oldName = fnf.getName(); - String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); - oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY); - this.setLayout(new BorderLayout()); - this.setModal(true); - - // 输入框前提示 - UILabel newNameLabel = new UILabel(Toolkit.i18nText( - fnf.isDirectory() ? - "Fine-Design_Basic_Enter_New_Folder_Name" : "Fine-Design_Basic_Enter_New_File_Name") - ); - newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT); - newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); - //newNameLabel.setPreferredSize(new Dimension(118, 15)); - - // 重命名输入框 - nameField = new UITextField(oldName); - nameField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void changedUpdate(DocumentEvent e) { - validInput(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - validInput(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - validInput(); - } - }); - nameField.selectAll(); - nameField.setPreferredSize(new Dimension(170, 20)); - - JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); - topPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 0, 15)); - topPanel.add(newNameLabel); - topPanel.add(nameField); - - // 增加enter以及esc快捷键的支持 - nameField.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { - dispose(); - } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { - if (confirmButton.isEnabled()) { - confirmClose(); - } - } - } - }); - // 重名提示 - warnLabel = new UILabel(); - warnLabel.setPreferredSize(new Dimension(300, 50)); - warnLabel.setHorizontalAlignment(SwingConstants.LEFT); - warnLabel.setVerticalAlignment(SwingConstants.TOP); - warnLabel.setForeground(Color.RED); - warnLabel.setVisible(false); - - JPanel midPanel = new JPanel(new BorderLayout()); - midPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15)); - midPanel.add(warnLabel, BorderLayout.WEST); - - // 确认按钮 - confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm")); - confirmButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - confirmClose(); - } - }); - - // 取消按钮 - UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); - - cancelButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); - - - JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); - buttonsPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10)); - buttonsPane.add(confirmButton); - buttonsPane.add(cancelButton); - - this.add( - TableLayoutHelper.createTableLayoutPane( - new Component[][]{ - new Component[]{topPanel}, - new Component[]{midPanel}, - new Component[]{buttonsPane} - }, - new double[]{TableLayout.FILL, TableLayout.PREFERRED, TableLayout.PREFERRED}, - new double[]{TableLayout.FILL} - ), - BorderLayout.CENTER); - - - this.setSize(340, 200); - this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename")); - this.setResizable(false); - this.setAlwaysOnTop(true); - this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png")); - this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - GUICoreUtils.centerWindow(this); - this.setVisible(true); - } - - private void confirmClose() { - - String userInput = nameField.getText().trim(); - // 处理不合法的文件夹名称 - userInput = userInput.replaceAll("[\\\\/:*?\"<>|]", StringUtils.EMPTY); - - String path = FilenameUtils.standard(fnf.getPath()); - - String oldName = fnf.getName(); - String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); - oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY); - - // 输入为空或者没有修改 - if (ComparatorUtils.equals(userInput, oldName)) { - this.dispose(); - return; - } - - String parentPath = FilenameUtils.standard(fnf.getParent().getPath()); - - // 简单执行old new 替换是不可行的,例如 /abc/abc/abc/abc/ - String newPath = parentPath + CoreConstants.SEPARATOR + userInput + suffix; - this.dispose(); - - //模版重命名 - boolean success = selectedOperation.rename(fnf, path, newPath); - - if (success) { - EventDispatcher.fire(TEMPLATE_RENAME, new TwoTuple<>(path, newPath)); - HistoryTemplateListCache.getInstance().rename(fnf, path, newPath); - DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath); - selectedOperation.refresh(); - DesignerContext.getDesignerFrame().setTitle(); - } else { - FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design_Basic_Rename_Failure"), - Toolkit.i18nText("Fine-Design_Basic_Error"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.ERROR_MESSAGE); - } - } - - - private void validInput() { - - String userInput = nameField.getText().trim(); - - String oldName = fnf.getName(); - String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); - oldName = oldName.replaceAll(suffix, StringUtils.EMPTY); - - if (StringUtils.isEmpty(userInput)) { - confirmButton.setEnabled(false); - return; - } - - if (ComparatorUtils.equals(userInput, oldName)) { - warnLabel.setVisible(false); - confirmButton.setEnabled(true); - return; - } - - if (selectedOperation.duplicated(userInput, suffix)) { - nameField.selectAll(); - // 如果文件名已存在,则灰掉确认按钮 - warnLabel.setText( - Toolkit.i18nText(fnf.isDirectory() ? - "Fine-Design_Basic_Folder_Name_Duplicate" : - "Fine-Design_Basic_Template_File_Name_Duplicate", - userInput)); - warnLabel.setVisible(true); - confirmButton.setEnabled(false); - } else { - warnLabel.setVisible(false); - confirmButton.setEnabled(true); - } + public void refreshRightToolBarByNode(FileNode fileNode) { + if (rightToolBar != null) { + boolean locked = fileNode != null + && StringUtils.isNotEmpty(fileNode.getLock()) + && !ComparatorUtils.equals(fileNode.getLock(), fileNode.getUserID()); + boolean visible = locked + && WorkContext.getCurrent().isRoot() + && WorkContext.getCurrent().get(LockInfoOperator.class).isUnLockable() + && !WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(fileNode.getEnvPath()); + rightToolBar.setVisible(visible); } } @@ -878,19 +760,23 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt private void confirmClose() { String userInput = nameField.getText().trim(); - // 处理不合法的文件夹名称 - userInput = userInput.replaceAll("[\\\\/:*?\"<>|]", StringUtils.EMPTY); if (StringUtils.isEmpty(userInput)) { return; } //新建文件夹 - boolean success = selectedOperation.mkdir( - FilenameUtils.standard(selectedOperation.getFileNode().getParent() + CoreConstants.SEPARATOR + userInput) - ); + FileNode selectedFileNode = selectedOperation.getFileNode(); + String parentPath = selectedFileNode.getParent(); + if (selectedFileNode.isDirectory()) { + //目录的话,父目录就是所选目录 + parentPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + selectedFileNode.getName()); + } + String targetPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput); + boolean success = selectedOperation.mkdir(targetPath); selectedOperation.refresh(); this.dispose(); + LocateAction.gotoEditingTemplateLeaf(targetPath); if (!success) { FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Make_Failure"), @@ -910,13 +796,11 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt return; } - if (selectedOperation.duplicated(userInput, StringUtils.EMPTY)) { + String errorMsg = doCheck(userInput, StringUtils.EMPTY); + if (StringUtils.isNotEmpty(errorMsg)) { nameField.selectAll(); - // 如果文件名已存在,则灰掉确认按钮 - warnLabel.setText( - Toolkit.i18nText( - "Fine-Design_Basic_Folder_Name_Duplicate", - userInput)); + // 如果检测出错,则灰掉确认按钮并提示 + warnLabel.setText(errorMsg); warnLabel.setVisible(true); confirmButton.setEnabled(false); } else { @@ -926,6 +810,17 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } } + private String doCheck (String userInput, String suffix) { + String errorMsg = StringUtils.EMPTY; + if (selectedOperation.duplicated(userInput, suffix, true)) { + errorMsg = Toolkit.i18nText("Fine-Design_Basic_Folder_Name_Duplicate", userInput); + } + if (!Pattern.compile(FILE_NAME_LIMIT).matcher(userInput).matches()) { + errorMsg = Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal"); + } + return errorMsg; + } + private boolean isEnable() { List> templates = HistoryTemplateListCache.getInstance().getHistoryList(); for (JTemplate template : templates) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIMode.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIMode.java new file mode 100644 index 0000000000..801291125a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIMode.java @@ -0,0 +1,17 @@ +package com.fr.design.mainframe; + +import com.fr.base.AutoChangeLineProvider;; +import com.fr.design.fun.ReportLengthUNITProvider; + +/** + * 设计器上和展示相关配置 + */ +public interface DesignerUIMode { + + ReportLengthUNITProvider parseLengthUNIT(int unitType); + + AutoChangeLineProvider getAutoChangeLineStrategy(); + + int getScreenResolution(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java new file mode 100644 index 0000000000..cd99f728a2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerUIModeConfig.java @@ -0,0 +1,80 @@ +package com.fr.design.mainframe; + +import com.fr.base.AutoChangeLineProvider; +import com.fr.design.fun.ReportLengthUNITProvider; +import com.fr.general.ComparatorUtils; + +/** + * Created by kerry on 2020-06-05 + */ +public class DesignerUIModeConfig { + private DesignerUIMode mode = AbsoluteMeasureUIMode.getInstance(); + + private static class DesignerUIModeConfigHolder { + private static final DesignerUIModeConfig designerUIModeConfig = new DesignerUIModeConfig(); + } + + private DesignerUIModeConfig() { + + } + + public static DesignerUIModeConfig getInstance() { + return DesignerUIModeConfigHolder.designerUIModeConfig; + } + + + /** + * 判断是否是新ui模式 + * + * @return boolean + */ + public boolean simulateWebUIMode() { + return ComparatorUtils.equals(SimulateWebUIMode.getInstance(), mode); + } + + /** + * 设置新ui模式 + */ + public void setSimulateWebUIMode() { + this.mode = SimulateWebUIMode.getInstance(); + } + + public void setDesignerUIMode(DesignerUIMode mode) { + this.mode = mode; + } + + /** + * 设置老ui模式 + */ + public void setAbsoluteMeasureUIMode() { + this.mode = AbsoluteMeasureUIMode.getInstance(); + } + + /** + * 解析不同模式下的尺寸单位 + * + * @param unitType 尺寸类型 + * @return ReportLengthUNITProvider对象 + */ + public ReportLengthUNITProvider parseLengthUNIT(int unitType) { + return mode.parseLengthUNIT(unitType); + } + + /** + * 获取不同模式下的换行逻辑 + * @return AutoChangeLineProvider + */ + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return mode.getAutoChangeLineStrategy(); + } + + /** + * 获取不同模式下的屏幕分辨率 + * + * @return 分辨率 + */ + public int getScreenResolution() { + return mode.getScreenResolution(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java index 65a9a47d68..9757b0f0b5 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java @@ -11,9 +11,11 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.event.TargetModifiedEvent; import com.fr.design.event.TargetModifiedListener; import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.utils.LoadingUtils; import javax.swing.JComponent; import javax.swing.JLayeredPane; +import javax.swing.JPanel; import java.awt.BorderLayout; import java.awt.Component; import java.util.HashMap; @@ -30,12 +32,14 @@ public class DesktopCardPane extends BasicPane implements TargetModifiedListener private static final int TRANSPARENT_LAYER = 1; private static final int LOADING_LAYER = 2; private static final int FAILED_LAYER = 3; + private static final int FORBIDDEN_LAYER = 4; private static final long serialVersionUID = 1L; private JTemplate component; private TransparentPane transparentPane = new TransparentPane(); - private OpenLoadingPane loadingPane = new OpenLoadingPane(); + private JPanel loadingPane = LoadingUtils.createLoadingPane(); private OpenFailedPane failedPane = new OpenFailedPane(); + private ForbiddenPane forbiddenPane = new ForbiddenPane(); Map backUpToolbarComponentState = new HashMap<>(); @@ -52,6 +56,7 @@ public class DesktopCardPane extends BasicPane implements TargetModifiedListener setLayout(new BorderLayout()); layeredPane.add(transparentPane, TRANSPARENT_LAYER); layeredPane.add(failedPane, FAILED_LAYER); + layeredPane.add(forbiddenPane, FORBIDDEN_LAYER); add(layeredPane, BorderLayout.CENTER); } @@ -93,6 +98,8 @@ public class DesktopCardPane extends BasicPane implements TargetModifiedListener showOpenStatus(); } else if (jt.isOpenFailed()) { showOpenFailedCover(jt.getTemplateOpenFailedTip()); + } else if (jt.isForbidden()) { + showForbiddenStatus(); } else { hideCover(); } @@ -138,6 +145,13 @@ public class DesktopCardPane extends BasicPane implements TargetModifiedListener } } + public void showForbiddenStatus() { + component.setVisible(false); + layeredPane.moveToFront(forbiddenPane); + forbidToolBar(); + EastRegionContainerPane.getInstance().updateAllPropertyPane(); + } + public void hideCover() { recoverToolBar(); transparentPane.stop(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java index a6734da917..b033fa6171 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java @@ -13,7 +13,6 @@ import com.fr.design.gui.ibutton.UIButtonUI; import com.fr.design.gui.icontainer.UIEastResizableContainer; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.VerticalFlowLayout; -import com.fr.design.mainframe.reuse.ReuseGuideDialog; import com.fr.design.mainframe.reuse.SnapChatKeys; import com.fr.design.mainframe.share.collect.ComponentCollector; import com.fr.design.notification.SnapChat; @@ -288,11 +287,16 @@ public class EastRegionContainerPane extends UIEastResizableContainer { // 悬浮元素 PropertyItem floatElement = new PropertyItem(KEY_FLOAT_ELEMENT, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Float_Element"), "floatelement", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART}, - new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT}); + new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.POLY_REPORT}); // 控件设置 PropertyItem widgetSettings = new PropertyItem(KEY_WIDGET_SETTINGS, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Component_Settings"), "widgetsettings", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.FORM, PropertyMode.POLY}, - new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.FORM, PropertyMode.POLY_REPORT, PropertyMode.POLY_CHART}); + new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.FORM, PropertyMode.POLY_REPORT, PropertyMode.POLY_CHART}, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ComponentCollector.getInstance().clickComponentSetting(); + } + }); // 条件属性 PropertyItem conditionAttr = new PropertyItem(KEY_CONDITION_ATTR, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Condition_Attributes"), "conditionattr", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART}, @@ -350,12 +354,7 @@ public class EastRegionContainerPane extends UIEastResizableContainer { public void updateCellElementState(boolean isSelectedOneCell) { PropertyItem cellElement = propertyItemMap.get(KEY_CELL_ELEMENT); - if (isSelectedOneCell) { - enableCellElementPane(cellElement); - } else { // 如果选中多个单元格,禁用单元格元素 tab - disableCellElementPane(cellElement); - refreshRightPane(); - } + enableCellElementPane(cellElement); } // 禁用单元格元素tab @@ -538,9 +537,6 @@ public class EastRegionContainerPane extends UIEastResizableContainer { } public PromptWindow getWidgetLibPromptWindow() { - if (!getWidgetLibSnapChat().hasRead()) { - return new ReuseGuideDialog(DesignerContext.getDesignerFrame()); - } return null; } @@ -733,7 +729,7 @@ public class EastRegionContainerPane extends UIEastResizableContainer { private Set enableModes; // 完整icon路径为 ICON_BASE_DIR + btnIconName + iconSuffix - private static final String ICON_BASE_DIR = "/com/fr/design/images/buttonicon/propertiestab/"; + private static final String ICON_BASE_DIR = "/com/fr/design/standard/propertiestab/"; private static final String ICON_SUFFIX_NORMAL = "_normal.svg"; private static final String ICON_SUFFIX_DISABLED = "_disabled.svg"; private static final String ICON_SUFFIX_SELECTED = "_selected.svg"; 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 new file mode 100644 index 0000000000..9c33534c7b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/ForbiddenPane.java @@ -0,0 +1,190 @@ +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; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.workspace.WorkContext; +import com.fr.report.lock.LockInfoOperator; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/6 + */ +public class ForbiddenPane extends JPanel { + + private static final ImageIcon LOCK_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/mainframe/lock_template.png")); + private static final Color TIP_COLOR = new Color(108, 174, 235); + private static final Color BUTTON_COLOR = new Color(63, 155, 249); + private static final int Y_GAP = 10; + private static final int X_GAP = 10; + private static final int ARC = 4; + + private final UILabel lockLabel; + private final UILabel tipLabel; + private final JButton refreshButton; + + public ForbiddenPane() { + + setLayout(new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return parent.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + int width = parent.getParent().getWidth(); + int height = parent.getParent().getHeight(); + int lockLabelWidth = lockLabel.getPreferredSize().width; + int lockLabelHeight = lockLabel.getPreferredSize().height; + int lockLabelX = (width - lockLabelWidth) / 2; + int lockLabelY = (height - lockLabelHeight) / 2; + int tipLabelWidth = tipLabel.getPreferredSize().width; + int tipLabelHeight = tipLabel.getPreferredSize().height; + int tipLabelX = (width - tipLabelWidth) / 2 + X_GAP; + int tipLabelY = lockLabelY + lockLabelHeight; + int refreshButtonWidth = refreshButton.getPreferredSize().width; + int refreshButtonHeight = refreshButton.getPreferredSize().height; + int refreshButtonX = (width - refreshButtonWidth) / 2 + X_GAP; + int refreshButtonY = tipLabelY + refreshButtonHeight + Y_GAP; + lockLabel.setBounds(lockLabelX, lockLabelY, lockLabelWidth, lockLabelHeight); + tipLabel.setBounds(tipLabelX, tipLabelY, tipLabelWidth, tipLabelHeight); + refreshButton.setBounds(refreshButtonX, refreshButtonY, refreshButtonWidth, refreshButtonHeight); + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }); + setBackground(Color.WHITE); + lockLabel = new UILabel(LOCK_ICON); + tipLabel = new UILabel(Toolkit.i18nText("Fine_Design_Template_Has_Been_Locked_Tip")); + Font labelFont = tipLabel.getFont(); + tipLabel.setFont(new Font(labelFont.getName(), labelFont.getStyle(), 14)); + tipLabel.setForeground(TIP_COLOR); + refreshButton = new JButton(Toolkit.i18nText("Fine-Design_Basic_Refresh")) { + @Override + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(BUTTON_COLOR); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), ARC, ARC); + super.paintComponent(g2d); + } + }; + refreshButton.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.mainframe.ForbiddenPane.refreshButton")); + refreshButton.setForeground(Color.WHITE); + refreshButton.setBorderPainted(false); + refreshButton.setContentAreaFilled(false); + refreshButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + final JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (template == null) { + return; + } + // 展示下画面 + LoadingDialog loadingDialog = new LoadingDialog(); + loadingDialog.showDialog(); + new SwingWorker(){ + + @Override + protected Boolean doInBackground() throws Exception { + return WorkContext.getCurrent().get(LockInfoOperator.class).isTplLocked(template.getEditingFILE().getPath()); + } + + @Override + protected void done() { + boolean unLocked; + loadingDialog.hideDialog(); + try { + unLocked = !get(); + if (unLocked) { + template.whenClose(); + JTemplate newTemplate = JTemplateFactory.createJTemplate(template.getEditingFILE()); + HistoryTemplateListCache.getInstance().replaceCurrentEditingTemplate(newTemplate); + DesignerContext.getDesignerFrame().addAndActivateJTemplate(newTemplate); + } + } catch (Exception e) { + loadingDialog.hideDialog(); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + }.execute(); + } + }); + add(lockLabel); + add(tipLabel); + add(refreshButton); + } +} + +class LoadingDialog extends JDialog { + + private static final ImageIcon LOADING_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/mainframe/refreh_icon.png")); + + private GuideView guideView; + + public LoadingDialog() { + super(DesignerContext.getDesignerFrame()); + setLayout(new BorderLayout()); + this.getContentPane().setBackground(Color.WHITE); + this.setResizable(false); + this.setUndecorated(true); + this.setAlwaysOnTop(true); + this.setModal(false); + this.setSize(new Dimension(400, 100)); + this.add(new UILabel(LOADING_ICON, UILabel.CENTER), BorderLayout.NORTH); + this.add(new UILabel(Toolkit.i18nText(Toolkit.i18nText("Fine_Design_Template_Refresh")), UILabel.CENTER), BorderLayout.CENTER); + GUICoreUtils.centerWindow(this); + } + + public void showDialog() { + DesignerContext.getDesignerFrame().setExtendedState(JFrame.MAXIMIZED_BOTH); + guideView = new GuideView(DesignerContext.getDesignerFrame()); + GUICoreUtils.centerWindow(DesignerContext.getDesignerFrame(), guideView); + guideView.setBounds(DesignerContext.getDesignerFrame().getBounds()); + guideView.setVisible(true); + this.setVisible(true); + } + + public void hideDialog() { + this.dispose(); + guideView.dismissGuide(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JDashboard.java b/designer-base/src/main/java/com/fr/design/mainframe/JDashboard.java new file mode 100644 index 0000000000..e4e4e9be93 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/JDashboard.java @@ -0,0 +1,16 @@ +package com.fr.design.mainframe; + +import com.fr.report.worksheet.FormElementCase; + +import java.awt.Rectangle; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/3/1 + */ +public interface JDashboard { + void switchToDashBoardEditor(); + + Rectangle getElementCaseRectangle(FormElementCase elementCase); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JNullTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JNullTemplate.java new file mode 100644 index 0000000000..656344b186 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/JNullTemplate.java @@ -0,0 +1,217 @@ +package com.fr.design.mainframe; + +import com.fr.design.DesignModelAdapter; +import com.fr.design.designer.TargetComponent; +import com.fr.design.gui.frpane.HyperlinkGroupPane; +import com.fr.design.gui.frpane.HyperlinkGroupPaneActionProvider; +import com.fr.design.gui.imenu.UIMenuItem; +import com.fr.design.mainframe.template.info.TemplateProcessInfo; +import com.fr.design.menu.ShortCut; +import com.fr.design.menu.ToolBarDef; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; + +/** + * created by Harrison on 2022/08/09 + **/ +public class JNullTemplate extends JTemplate { + + public static final JTemplate NULL = new JNullTemplate(); + + @Override + public void copy() { + + } + + @Override + public boolean paste() { + return false; + } + + @Override + public boolean cut() { + return false; + } + + @Override + public AuthorityEditPane createAuthorityEditPane() { + return null; + } + + @Override + public JPanel getEastUpPane() { + return null; + } + + @Override + public JPanel getEastDownPane() { + return null; + } + + @Override + public ToolBarDef[] toolbars4Target() { + return new ToolBarDef[0]; + } + + @Override + public JComponent[] toolBarButton4Form() { + return new JComponent[0]; + } + + @Override + public void refreshEastPropertiesPane() { + + } + + @Override + public TargetComponent getCurrentElementCasePane() { + return null; + } + + @Override + public JComponent getCurrentReportComponentPane() { + return null; + } + + @Override + public TemplateProcessInfo getProcessInfo() { + return null; + } + + @Override + public void setJTemplateResolution(int resolution) { + + } + + @Override + public int getJTemplateResolution() { + return 0; + } + + @Override + protected JComponent createCenterPane() { + return null; + } + + @Override + public void removeTemplateSelection() { + + } + + @Override + public void refreshContainer() { + + } + + @Override + public void removeParameterPaneSelection() { + + } + + @Override + public void setScale(int resolution) { + + } + + @Override + public int getScale() { + return 0; + } + + @Override + public int selfAdaptUpdate() { + return 0; + } + + @Override + protected DesignModelAdapter createDesignModel() { + return null; + } + + @Override + public UIMenuItem[] createMenuItem4Preview() { + return new UIMenuItem[0]; + } + + @Override + protected BaseUndoState createUndoState() { + return null; + } + + @Override + protected void applyUndoState(BaseUndoState baseUndoState) { + + } + + @Override + public String suffix() { + return null; + } + + @Override + public ShortCut[] shortcut4TemplateMenu() { + return new ShortCut[0]; + } + + @Override + public ShortCut[] shortCuts4Authority() { + return new ShortCut[0]; + } + + @Override + public boolean isJWorkBook() { + return false; + } + + @Override + public HyperlinkGroupPane getHyperLinkPane(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider) { + return null; + } + + @Override + public HyperlinkGroupPane getHyperLinkPaneNoPop(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider) { + return null; + } + + @Override + public void setAuthorityMode(boolean isUpMode) { + + } + + @Override + public Icon getIcon() { + return null; + } + + @Override + public String route() { + return null; + } + + @Override + public JPanel[] toolbarPanes4Form() { + return new JPanel[0]; + } + + @Override + public JComponent toolBar4Authority() { + return null; + } + + @Override + public int getToolBarHeight() { + return 0; + } + + @Override + public String getPath() { + return null; + } + + @Override + public void refreshToolArea() { + DesignerContext.getDesignerFrame().resetToolkitByPlus(this); + } +} 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 c342cc3910..0082e091f3 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 @@ -1,17 +1,19 @@ package com.fr.design.mainframe; -import com.fr.base.BaseUtils; import com.fr.base.Parameter; +import com.fr.base.TRL; import com.fr.base.extension.FileExtension; import com.fr.base.io.BaseBook; import com.fr.base.iofile.attr.DesignBanCopyAttrMark; import com.fr.base.iofile.attr.TemplateIdAttrMark; import com.fr.base.iofile.attr.TemplateThemeAttrMark; +import com.fr.base.svg.IconUtils; +import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.TemplateThemeCompatible; +import com.fr.base.theme.TemplateThemeConfig; import com.fr.base.theme.ThemedTemplate; import com.fr.base.vcs.DesignerMode; -import com.fr.base.theme.TemplateTheme; -import com.fr.base.theme.TemplateThemeConfig; +import com.fr.decision.config.FSConfig; import com.fr.design.DesignModelAdapter; import com.fr.design.DesignState; import com.fr.design.DesignerEnvManager; @@ -52,39 +54,44 @@ import com.fr.design.mainframe.toolbar.VcsScene; import com.fr.design.menu.MenuDef; import com.fr.design.menu.NameSeparator; import com.fr.design.menu.ShortCut; +import com.fr.design.module.DesignModuleFactory; import com.fr.design.preview.PagePreview; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.DesignUtils; import com.fr.design.worker.save.CallbackSaveWorker; import com.fr.design.worker.save.EmptyCallBackSaveWorker; +import com.fr.design.worker.save.SaveFailureHandler; import com.fr.design.write.submit.DBManipulationInWidgetEventPane; import com.fr.design.write.submit.DBManipulationPane; import com.fr.event.EventDispatcher; import com.fr.file.FILE; import com.fr.file.FILEChooserPane; +import com.fr.file.FileFILE; 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; -import com.fr.general.IOUtils; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; +import com.fr.nx.app.designer.toolbar.TemplateTransformer; import com.fr.nx.app.designer.utils.CptAndCptxCompatibilityUtil; import com.fr.nx.app.designer.utils.CptCompileUtil; import com.fr.nx.cptx.entry.metadata.CptxMetadata; import com.fr.nx.cptx.utils.CptxFileUtils; import com.fr.plugin.context.PluginContext; import com.fr.plugin.context.PluginRuntime; -import com.fr.nx.app.designer.toolbar.CompileAction; -import com.fr.nx.app.designer.toolbar.TemplateTransformer; import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; import com.fr.plugin.observer.PluginEventType; import com.fr.plugin.observer.PluginListenerRegistration; +import com.fr.report.InconsistentLockException; +import com.fr.report.UnLockedException; import com.fr.report.cell.Elem; import com.fr.report.cell.cellattr.CellImage; +import com.fr.report.lock.LockInfoOperator; import com.fr.stable.ArrayUtils; import com.fr.stable.Filter; import com.fr.stable.ProductConstants; @@ -102,6 +109,8 @@ import javax.swing.undo.UndoManager; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FontMetrics; +import java.io.ByteArrayOutputStream; +import java.nio.file.Paths; import java.util.Set; import java.util.concurrent.Callable; @@ -123,6 +132,9 @@ public abstract class JTemplate> protected U undoState; protected U authorityUndoState = null; protected T template; // 当前模板 + private boolean isNewCreateTpl = false; //当前模板是否为新建模板 + private volatile boolean forbidden; + /** * 模板过程的相关信息 * @@ -179,6 +191,11 @@ public abstract class JTemplate> public JTemplate(T t, FILE file, boolean isNewFile, Parameter[] parameters) { super(t); + HistoryTemplateListCache.getInstance().setCurrentOpeningTemplate(this); + if (isNewFile) { + // REPORT-58486: 必须在初始的UndoState创建前设置主题,使得初始的UndoState就包含了主题效果 + setUpTheme4NewTemplate(); + } beforeInit(); // 判断是否切换设计器状态到禁止拷贝剪切 if (t.getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) { @@ -186,7 +203,7 @@ public abstract class JTemplate> } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) { DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL); } - this.template = t; + this.template = getTarget(); this.previewType = parserPreviewProvider(t.getPreviewType()); this.editingFILE = file; this.setLayout(FRGUIPaneFactory.createBorderLayout()); @@ -197,10 +214,7 @@ public abstract class JTemplate> designModel = createDesignModel(parameters); } addCenterPane(); - if (isNewFile) { - // REPORT-58486: 必须在初始的UndoState创建前设置主题,使得初始的UndoState就包含了主题效果 - setUpTheme4NewTemplate(); - } + isNewCreateTpl = isNewFile; this.undoState = createUndoState(); initAndStartPlugin(); @@ -314,7 +328,7 @@ public abstract class JTemplate> /** * 为另存的模板创建新的模板id */ - private void generateNewTemplateIdForSaveAs() { + protected void generateNewTemplateIdForSaveAs() { generateTemplateId(); } @@ -430,6 +444,42 @@ public abstract class JTemplate> stopListenThemeConfig(); } + /** + * 用于 切换工作目录 时的模板资源暂存 + * @return + */ + public FILE templateToStashFile4Envchange() { + FILE file = this.getEditingFILE(); + if (file.isEnvFile()) { + // 切换工作目录时,模板锁信息被清除,因此这里需要将环境相关模板文件转化为与环境无关的内存模板文件,再创建暂存文件 + return new StashedFILE(new MemFILE(file.getName()), exportBaseBook2ByteArray(), template.suffix()); + } else { + // 其它情况下,直接创建暂存文件 + return templateToStashFile(); + } + } + + public FILE templateToStashFile() { + FILE file = this.getEditingFILE(); + return new StashedFILE(file, exportBaseBook2ByteArray(), template.suffix()); + } + + private byte[] exportBaseBook2ByteArray() { + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + BaseBook target = this.getTarget(); + if (target != null) { + target.export(outputStream); + return outputStream.toByteArray(); + } + // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 + } catch (Exception e) { + FineLoggerFactory.getLogger().error("Export BaseBook to Byte Array Failed"); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return new byte[0]; + } + /** * 刷新内部资源 @@ -440,7 +490,9 @@ public abstract class JTemplate> */ @Deprecated public void refreshResource() { - refreshResource(this.editingFILE); + if (JTemplateFactory.isAvailable()) { + refreshResource(this.editingFILE); + } } public void refreshResource(FILE file) { @@ -449,22 +501,40 @@ public abstract class JTemplate> UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - // 先移除旧的。 - removeCenterPane(); - // 加入新的 - addCenterPane(); - - refreshToolArea(); - - TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView(); + refreshDesignerFromResource(); } }); } + protected void refreshDesignerFromResource() { + // 先移除旧的。 + removeCenterPane(); + // 加入新的 + addCenterPane(); + + refreshToolArea(); + + TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView(); + } + + /** + * 刷新 模板资源 和 EditingFILE + * 仅在切换工作目录,reload模板时使用 + * @param file + */ + public void refreshResourceAndEditingFILE(FILE file) { + // 这里替换EditingFILE是为了在切换工作目录后,将模板文件对象设置成环境无关文件对象 + this.editingFILE = file instanceof StashedFILE ? ((StashedFILE) file).getInsideFILE() : file; + refreshResource(file); + } + private void setTargetByFile(FILE file) { - this.template = JTemplateFactory.asIOFile(file, this.suffix()); - setTarget(this.template); + T newTemplate = JTemplateFactory.asIOFile(file, this.suffix()); + if (newTemplate != null) { + this.template = newTemplate; + setTarget(this.template); + } } private void addCenterPane() { @@ -633,9 +703,21 @@ public abstract class JTemplate> */ public void redo() { this.getUndoManager().redo(); + // 重做前模版使用主题可能已经被删除或修改,需要重置模版样式 + checkAndResetTheme(); fireSuperTargetModified(); } + public void undoToCurrent() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + BaseUndoState current = JTemplate.this.getUndoState(); + current.applyState(); + } + }); + } + /** * 模板更新 */ @@ -942,10 +1024,11 @@ public abstract class JTemplate> return false; } try { + checkBeforeSave(); export(); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage(), "Save Error", JOptionPane.ERROR_MESSAGE); + SaveFailureHandler.getInstance().process(e); return false; } this.editingFILE = editingFILE; @@ -956,6 +1039,35 @@ public abstract class JTemplate> return true; } + public boolean isNewCreateTpl() { + return isNewCreateTpl; + } + + protected void checkBeforeSave() throws Exception { + // 保存前校验下未解锁 + if (WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(getEditingFILE().getPath())) { + throw new UnLockedException(); + } + // 过滤掉本地文件 + boolean localFile = getEditingFILE() instanceof FileFILE; + boolean inconsistent = !localFile && getEditingFILE().exists() + && !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath()); + if (inconsistent) { + throw new InconsistentLockException(); + } + } + + public byte[] exportData() throws Exception { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + BaseBook target = getTarget(); + if (target != null) { + target.export(outputStream); + return outputStream.toByteArray(); + } + } + return new byte[0]; + } + protected boolean export() throws Exception { return this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(getEditingFILE())); @@ -998,6 +1110,10 @@ public abstract class JTemplate> tplMenu.addShortCut(shortCuts4Authority()); } + //查找替换 + tplMenu.addShortCut(new NameSeparator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Replace_Name_Separate"))); + tplMenu.addShortCut((ShortCut) DesignModuleFactory.getITReplaceAction()); + return new MenuDef[]{tplMenu}; } @@ -1037,6 +1153,20 @@ public abstract class JTemplate> this.listenerList.remove(JTemplateActionListener.class, l); } + /** + * 模板保存前触发 + */ + public void fireJTemplateSaveBefore() { + Object[] listeners = listenerList.getListenerList(); + + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == JTemplateActionListener.class) { + ((JTemplateActionListener) listeners[i + 1]).templateSaveBefore(this); + } + } + this.repaint(30); + } + /** * 触发模板关闭 */ @@ -1294,7 +1424,7 @@ public abstract class JTemplate> public Icon getPreviewLargeIcon() { PreviewProvider provider = getPreviewType(); String iconPath = provider.iconPathForLarge(); - return BaseUtils.readIcon(iconPath); + return IconUtils.readIcon(iconPath); } /** @@ -1442,7 +1572,7 @@ public abstract class JTemplate> } protected UIButton createTemplateThemeButton() { - UIButton button = new UIButton(IOUtils.readIcon("/com/fr/design/icon/icon_predefined_style.png")) { + UIButton button = new UIButton(IconUtils.readIcon("/com/fr/design/standard/template_theme")) { @Override public Dimension getPreferredSize() { FontMetrics metrics = getFontMetrics(getFont()); @@ -1484,18 +1614,18 @@ public abstract class JTemplate> /** * 设置新引擎后,有不支持的功能时,设计器中模板的标题需要加上“兼容模式”或者“不支持分页引擎”来提示用户 - * */ + */ private String compatibilityTip() { - if (!CptAndCptxCompatibilityUtil.isEngineXEnable(this.getTarget(), getEditingFILE().getPath())){ + if (!CptAndCptxCompatibilityUtil.isEngineXEnable(this.getTarget(), getEditingFILE().getPath())) { return StringUtils.EMPTY; } String path = this.getEditingFILE().getPath(); - CptxMetadata metadata = CptxFileUtils.getMetadata(path); + CptxMetadata metadata = Paths.get(path).isAbsolute() ? null : CptxFileUtils.getMetadata(path); //是否是兼容模式,兼容模式下,设置了新引擎的cpt和cptx的后缀不同 if (metadata != null && metadata.isForceCpt()) { - if (path.endsWith(".cptx")){ + if (path.endsWith(".cptx")) { return InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_Compatibility_Mode"); - } else if (path.endsWith(".cpt")){ + } else if (path.endsWith(".cpt")) { return InterProviderFactory.getProvider().getLocText("Fine-Plugin_Engine_Paging_Engine_Not_Work"); } } @@ -1547,6 +1677,7 @@ public abstract class JTemplate> } private CallbackSaveWorker save(boolean showLoc) { + fireJTemplateSaveBefore(); FILE editingFILE = this.getEditingFILE(); // carl:editingFILE没有,当然不存了,虽然不会有这种情况 if (editingFILE == null) { @@ -1592,15 +1723,27 @@ public abstract class JTemplate> } private boolean saveRealFile() throws Exception { - JTemplateAuthorityChecker jTemplateAuthorityChecker = new JTemplateAuthorityChecker(this); - if (jTemplateAuthorityChecker.isAuthority()) { + if (checkJTemplateAuthority()) { FILE editingFILE = this.getEditingFILE(); if (editingFILE == null || editingFILE instanceof MemFILE) { return false; } + checkBeforeSave(); export(); this.editingFILE = editingFILE; return true; + } else { + return false; + } + } + + private boolean checkJTemplateAuthority() { + if (!FSConfig.getInstance().getAuthorizeAttr().isDataConnectionAuthority()) { + return true; + } + JTemplateAuthorityChecker jTemplateAuthorityChecker = new JTemplateAuthorityChecker(this); + if (jTemplateAuthorityChecker.isAuthority()) { + return true; } else { jTemplateAuthorityChecker.showAuthorityFailPromptDialog(); return false; @@ -1641,7 +1784,7 @@ public abstract class JTemplate> @Override public void run() { boolean isChangedFile = !JTemplate.this.saved; - if (isChangedFile){ + if (isChangedFile) { CptCompileUtil.compile(JTemplate.this); } callBackForSave(); @@ -1650,7 +1793,8 @@ public abstract class JTemplate> HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().template.getTemplateID())) { refreshToolArea(); } - DesignerFrameFileDealerPane.getInstance().refresh(); + DesignerFrameFileDealerPane.getInstance().refreshAndOutOfSearch(); + DesignerFrameFileDealerPane.getInstance().stateChange(); } }); return worker; @@ -1708,7 +1852,7 @@ public abstract class JTemplate> * 2.在这三种情况下:1.cptx文件另存为cpt文件 2.cptx另存为cptx文件 3.设置了新引擎的cpt文件另存为cpt文件, * 因为文件的编译目录改变了,需要重新预编译,因此设置jTemplate的保存状态为false * */ - if (CptAndCptxCompatibilityUtil.needRecompile(oldName, this)){ + if (CptAndCptxCompatibilityUtil.needRecompile(oldName, this)) { this.saved = false; } result = this.saveRealFile(); @@ -1774,8 +1918,16 @@ public abstract class JTemplate> this.openFailed = openFailed; } + public boolean isForbidden() { + return forbidden; + } + + public void setForbidden(boolean forbidden) { + this.forbidden = forbidden; + } + public boolean checkEnable() { - return !isSaving() && !isOpening() && !isOpenFailed(); + return !isSaving() && !isOpening() && !isOpenFailed() && !isForbidden(); } public String getRuntimeId() { @@ -1784,10 +1936,10 @@ public abstract class JTemplate> protected void setUpTheme4NewTemplate() { TemplateTheme theme = getUsingTemplateThemeConfig().cachedFetchTheme4NewTemplate(); - TemplateThemeAttrMark themeAttrMark = template.getAttrMark(TemplateThemeAttrMark.XML_TAG); + TemplateThemeAttrMark themeAttrMark = getTarget().getAttrMark(TemplateThemeAttrMark.XML_TAG); if (themeAttrMark == null) { themeAttrMark = new TemplateThemeAttrMark(); - template.addAttrMark(themeAttrMark); + getTarget().addAttrMark(themeAttrMark); } themeAttrMark.setName(theme.getName()); themeAttrMark.setDark(theme.isDark()); @@ -1803,9 +1955,38 @@ public abstract class JTemplate> @Override public void setTemplateTheme(TemplateTheme newTheme, TemplateThemeCompatible compatible) { - ThemedTemplate.super.setTemplateTheme(newTheme, compatible); - String name = newTheme.getName(); - templateThemeButton.setText(name); - templateThemeButton.setToolTipText(name); + if (templateThemeButton != null) { + ThemedTemplate.super.setTemplateTheme(newTheme, compatible); + String name = newTheme.getName(); + templateThemeButton.setText(name); + templateThemeButton.setToolTipText(name); + } + } + + /** + * 定位 + * + * @param trl + */ + public void navigate(TRL trl) { + + } + + public void generateForBiddenTemplate() { + + } + + public void setDesignerUIMode() { + DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode(); + } + + /** + * 判断当前的模板是否是有效的模板 + * + * @param jt 模板 + * @return 是/否 + */ + public static boolean isValid(JTemplate jt) { + return jt != null && jt != JNullTemplate.NULL; } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java index 5e17873695..ecfd52dbe0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java @@ -4,9 +4,15 @@ import java.util.EventListener; public interface JTemplateActionListener extends EventListener { - public void templateOpened(JTemplate jt); + default void templateOpened(JTemplate jt) { + } - public void templateSaved(JTemplate jt); + default void templateSaved(JTemplate jt) { + } - public void templateClosed(JTemplate jt); + default void templateClosed(JTemplate jt) { + } + + default void templateSaveBefore(JTemplate jt) { + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java index 5e75cc64be..15895c06a8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java @@ -1,7 +1,12 @@ package com.fr.design.mainframe; import com.fr.base.io.BaseBook; +import com.fr.base.theme.FineColorGather; +import com.fr.base.theme.FineColorManager; +import com.fr.base.theme.FineColorSynchronizer; +import com.fr.base.theme.TemplateThemeCompatible; import com.fr.file.FILE; +import com.fr.form.main.Form; import com.fr.stable.CoreConstants; import com.fr.stable.StringUtils; @@ -34,10 +39,7 @@ public final class JTemplateFactory { String[] defaultAppExtensions = app.defaultExtensions(); for (String defaultAppExtension : defaultAppExtensions) { if (defaultAppExtension.equalsIgnoreCase(fileExtension)) { - JTemplate jt = app.openTemplate(file); - if (jt != null) { - return jt; - } + return app.openTemplate(file); } } } @@ -93,4 +95,7 @@ public final class JTemplateFactory { ALL_APP.remove(app); } } -} \ No newline at end of file + + public static boolean isAvailable() { + return !ALL_APP.isEmpty(); + }} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java index 22d5985ba9..0f245d8bb4 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java @@ -1,10 +1,12 @@ package com.fr.design.mainframe; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.TemplateTreePane; import com.fr.design.gui.itree.filetree.TemplateFileTree; import com.fr.stable.StringUtils; import javax.swing.tree.DefaultMutableTreeNode; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -18,8 +20,6 @@ public class JTemplateNameHelper { private static final int PREFIX_NUM = 3000; - private static short currentIndex = 0;// 此变量用于多次新建模板时,让名字不重复 - public static String newTemplateNameByIndex(String prefix) { // 用于获取左侧模板的文件名,如左侧已包含"WorkBook1.cpt, WorkBook12.cpt, WorkBook177.cpt" // 那么新建的文件名将被命名为"WorkBook178.cpt",即取最大数+1 @@ -27,23 +27,42 @@ public class JTemplateNameHelper { DefaultMutableTreeNode gen = (DefaultMutableTreeNode) tt.getModel().getRoot(); String[] str = new String[gen.getChildCount()]; - List reportNum = new ArrayList<>(); + List reportNum = new ArrayList<>(); for (int j = 0; j < gen.getChildCount(); j++) { str[j] = gen.getChildAt(j).toString(); //返回文件名中的index(算法中没有再匹配文件后缀了,因为DefaultMutableTreeNode中已经匹配过了) - Integer index = getFileNameIndex(prefix, str[j]); + BigInteger index = getFileNameIndex(prefix, str[j]); if (index != null) { reportNum.add(index); } } + //把当前编辑面板的模板名也加进来判断 + addHistoryTemplateName2List(reportNum, prefix); Collections.sort(reportNum); - int idx = reportNum.size() > 0 ? reportNum.get(reportNum.size() - 1) + 1 : 1; - - idx = idx + currentIndex; - currentIndex++; + BigInteger idx = reportNum.size() > 0 ? reportNum.get(reportNum.size() - 1).add(BigInteger.valueOf(1)) : BigInteger.valueOf(1); return prefix + idx; } + /** + * 将当前打开的模板列表的模板名处理一下加进来,以便于获取左侧模板文件名与当前模板列表的最大值 + * + * @param reportNum 存储后缀的列表 + * @param prefix 前缀 + */ + private static void addHistoryTemplateName2List(List reportNum, String prefix) { + int len = HistoryTemplateListCache.getInstance().getHistoryCount(); + for (int i = 0; i < len; i++) { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().get(i); + if (jTemplate != null) { + String templateName = jTemplate.getTemplateName(); + BigInteger index = getFileNameIndex(prefix, templateName); + if (index != null) { + reportNum.add(index); + } + } + } + } + /** * @return java.lang.Integer WorkBook11.cpt则返回11,如果没有找到index返回null * @Description 返回文件名中的index @@ -52,35 +71,56 @@ public class JTemplateNameHelper { * @Author Henry.Wang * @Date 2021/4/9 11:13 **/ - private static Integer getFileNameIndex(String prefix, String fileName) { - if (fileName.length() <= prefix.length()) { + private static BigInteger getFileNameIndex(String prefix, String fileName) { + //如果文件名长度小于等于前缀长度或者匹配前缀失败,直接返回就可以了 + if ((prefix.length() >= fileName.length()) || (!StringUtils.equals(prefix, fileName.substring(0, prefix.length())))) { return null; } - char[] chars = new char[fileName.length()]; - int i = 0; - for (; i < fileName.length(); i++) { + BigInteger integer = null; + integer = matchFileNameIndex(prefix, fileName); + return integer; + } + + /** + * 匹配文件名称的数字后缀Index + * @param prefix 前缀 + * @param fileName 文件名称全名 + * @return 返回对应的数字后缀Index + */ + private static BigInteger matchFileNameIndex(String prefix, String fileName) { + StringBuilder result = new StringBuilder(); + for (int i = prefix.length(); i < fileName.length(); i++) { char c = fileName.charAt(i); - //匹配前缀 - if (i < prefix.length()) { - if (c != prefix.charAt(i)) { - return null; - } + if (isDot(c)) { + break; } else { - if (c == '.') { - break; - } else { - //匹配0~9 - if (c < 48 || c > 57) { - return null; - } - chars[i - prefix.length()] = c; + if (isNotNumber(c)) { + return null; } + result.append(c); } } - String s = new String(chars).substring(0, i - prefix.length()); - if (StringUtils.isBlank(s)) { + if (StringUtils.isBlank(result.toString())) { return null; } - return Integer.valueOf(s); + return new BigInteger(result.toString(), 10); + } + + /** + * 是否不属于数字0-9 + * @param c 用于判断的char + * @return 返回对应判断结果 + */ + private static boolean isNotNumber(char c) { + return c < 48 || c > 57; + } + + /** + * 是否属于'.' + * @param c 用于判断的char + * @return 返回对应判断结果 + */ + private static boolean isDot(char c) { + return c == '.'; } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java index f15b3517f0..fcfa4292fa 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java @@ -17,6 +17,7 @@ import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; +import com.fr.plugin.observer.PluginEventType; import com.fr.stable.os.support.OSBasedAction; import com.fr.stable.os.support.OSSupportCenter; @@ -38,6 +39,17 @@ public class NorthRegionContainerPane extends JPanel { private JMenuBar menuBar; + private PluginFilter pluginFilter = new PluginFilter() { + + @Override + public boolean accept(PluginContext context) { + + return context.contain(PluginModule.ExtraDesign); + } + }; + + private volatile boolean existDesignExtraPlugin; + public static NorthRegionContainerPane getInstance() { if (THIS == null) { synchronized (NorthRegionContainerPane.class) { @@ -66,34 +78,63 @@ public class NorthRegionContainerPane extends JPanel { //hugh: private修改为protected方便oem的时候修改右上的组件构成 //顶部日志+登陆按钮 final JPanel northEastPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + initPluginListener(northEastPane, ad); + refreshNorthEastPane(northEastPane, ad); + return northEastPane; + } + + private void initPluginListener(JPanel northEastPane, ToolBarMenuDock ad) { //优先级为-1,保证最后全面刷新一次 - GeneralContext.listenPluginRunningChanged(new PluginEventListener(-1) { + PluginEventListener pluginOnRunOrStopListener = new PluginEventListener(-1) { @Override public void on(PluginEvent event) { - - refreshNorthEastPane(northEastPane, ad); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (DesignerContext.getDesignerFrame() == null) { - return; - } - DesignerContext.getDesignerFrame().refresh(); - DesignerContext.getDesignerFrame().repaint(); - } - }); + refreshAll(northEastPane, ad); } - }, new PluginFilter() { + }; + // 在设计器启动时仅在最后一个插件启用时候进行刷新一次 如果插件启用过程中存在实现了设计器接口的插件 + PluginEventListener afterAllPluginsActiveListener = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + //优先级为-1,保证最后全面刷新一次 + GeneralContext.listenPluginRunningChanged(pluginOnRunOrStopListener, pluginFilter); + // 在设计器启动时仅在最后一个插件启用时候进行刷新一次 如果插件启用过程中存在实现了设计器接口的插件 + if (existDesignExtraPlugin) { + refreshAll(northEastPane, ad); + } + } + }; + PluginEventListener beforeAllPluginStopListener = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + GeneralContext.stopListenPlugin(pluginOnRunOrStopListener); + } + }; + PluginEventListener pluginEventListener = new PluginEventListener() { @Override - public boolean accept(PluginContext context) { + public void on(PluginEvent event) { + existDesignExtraPlugin = true; + } + }; + GeneralContext.listenPluginRunningChanged(pluginEventListener, pluginFilter); + GeneralContext.listenPlugin(PluginEventType.AfterAllActive, afterAllPluginsActiveListener); + GeneralContext.listenPlugin(PluginEventType.BeforeAllStop, beforeAllPluginStopListener); - return context.contain(PluginModule.ExtraDesign); + } + + private void refreshAll(JPanel northEastPane, ToolBarMenuDock ad) { + refreshNorthEastPane(northEastPane, ad); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (DesignerContext.getDesignerFrame() == null) { + return; + } + DesignerContext.getDesignerFrame().refresh(); + DesignerContext.getDesignerFrame().repaint(); } }); - refreshNorthEastPane(northEastPane, ad); - return northEastPane; } private void refreshNorthEastPane(final JPanel northEastPane, final ToolBarMenuDock ad) { @@ -109,7 +150,7 @@ public class NorthRegionContainerPane extends JPanel { public void execute(Object... objects) { bbsLoginPane[0] = ad.createBBSLoginPane(); } - }, SupportOSImpl.USERINFOPANE); + }, SupportOSImpl. BBS_USER_LOGIN_PANE); processor.hold(northEastPane, LogMessageBar.getInstance(), bbsLoginPane[0]); } northEastPane.add(ad.createAlphaFinePane()); @@ -124,7 +165,7 @@ public class NorthRegionContainerPane extends JPanel { public void execute(Object... objects) { northEastPane.add(ad.createBBSLoginPane()); } - }, SupportOSImpl.USERINFOPANE); + }, SupportOSImpl.BBS_USER_LOGIN_PANE); } diff --git a/designer-form/src/main/java/com/fr/design/fit/PX.java b/designer-base/src/main/java/com/fr/design/mainframe/PX.java similarity index 94% rename from designer-form/src/main/java/com/fr/design/fit/PX.java rename to designer-base/src/main/java/com/fr/design/mainframe/PX.java index 720268ea6a..8fd9ac0edc 100644 --- a/designer-form/src/main/java/com/fr/design/fit/PX.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/PX.java @@ -1,4 +1,4 @@ -package com.fr.design.fit; +package com.fr.design.mainframe; import com.fr.stable.Constants; import com.fr.stable.unit.LEN_UNIT; diff --git a/designer-form/src/main/java/com/fr/design/fit/PXReportLengthUNIT.java b/designer-base/src/main/java/com/fr/design/mainframe/PXReportLengthUNIT.java similarity index 95% rename from designer-form/src/main/java/com/fr/design/fit/PXReportLengthUNIT.java rename to designer-base/src/main/java/com/fr/design/mainframe/PXReportLengthUNIT.java index 8d8f1de167..69d46480e9 100644 --- a/designer-form/src/main/java/com/fr/design/fit/PXReportLengthUNIT.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/PXReportLengthUNIT.java @@ -1,4 +1,4 @@ -package com.fr.design.fit; +package com.fr.design.mainframe; import com.fr.design.fun.impl.AbstractReportLengthUNITProvider; import com.fr.stable.unit.UNIT; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/SimulateWebUIMode.java b/designer-base/src/main/java/com/fr/design/mainframe/SimulateWebUIMode.java new file mode 100644 index 0000000000..a13bff759f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/SimulateWebUIMode.java @@ -0,0 +1,38 @@ +package com.fr.design.mainframe; + +import com.fr.base.AutoChangeLineProvider; +import com.fr.design.fun.ReportLengthUNITProvider; +import com.fr.form.fit.NewUIModeAutoChangeLine; +import com.fr.stable.Constants; + +public class SimulateWebUIMode implements DesignerUIMode { + + private static class SimulateWebUIModeHolder { + private static final SimulateWebUIMode simulateWebUIMode = new SimulateWebUIMode(); + } + + private SimulateWebUIMode() { + + } + + public static SimulateWebUIMode getInstance() { + return SimulateWebUIModeHolder.simulateWebUIMode; + } + + + @Override + public ReportLengthUNITProvider parseLengthUNIT(int unitType) { + return new PXReportLengthUNIT(); + } + + @Override + public AutoChangeLineProvider getAutoChangeLineStrategy() { + return new NewUIModeAutoChangeLine(); + } + + @Override + public int getScreenResolution() { + return Constants.DEFAULT_WEBWRITE_AND_SCREEN_RESOLUTION; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/ToolBarNewTemplatePane.java b/designer-base/src/main/java/com/fr/design/mainframe/ToolBarNewTemplatePane.java index 1f7cab6d6f..64d58bd8e5 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/ToolBarNewTemplatePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/ToolBarNewTemplatePane.java @@ -1,6 +1,6 @@ package com.fr.design.mainframe; -import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.design.file.NewTemplatePane; import javax.swing.Icon; @@ -21,16 +21,16 @@ public class ToolBarNewTemplatePane extends NewTemplatePane { @Override public Icon getNew() { - return BaseUtils.readIcon("/com/fr/design/images/buttonicon/addicon.png"); + return IconUtils.readIcon("/com/fr/design/standard/addicon/addicon"); } @Override public Icon getMouseOverNew() { - return BaseUtils.readIcon("/com/fr/design/images/buttonicon/add_press.png"); + return IconUtils.readIcon("/com/fr/design/standard/addicon/add_press.svg"); } @Override public Icon getMousePressNew() { - return BaseUtils.readIcon("/com/fr/design/images/buttonicon/add_press.png"); + return IconUtils.readIcon("/com/fr/design/standard/addicon/add_press.svg"); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java b/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java new file mode 100644 index 0000000000..67b1409b36 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java @@ -0,0 +1,27 @@ +package com.fr.design.mainframe; + +import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; + +public interface ToolKitConfigStrategy { + + /** + * 展示tabpane + * @param plus + * @return + */ + boolean hasTemplateTabPane(ToolBarMenuDockPlus plus); + + /** + * 展示模板操作按钮(复制、粘贴、保存等) + * @param plus + * @return + */ + boolean hasCombineUp(ToolBarMenuDockPlus plus); + + /** + * 展示工具栏pane + * @param plus + * @return + */ + boolean hasToolBarPane(ToolBarMenuDockPlus plus); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java b/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java index 8861a75919..26f2406985 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/TransparentPane.java @@ -1,58 +1,30 @@ package com.fr.design.mainframe; +import com.fr.design.components.loading.LoadingPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; + +import javax.swing.Timer; import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Component; -import java.awt.Composite; import java.awt.Container; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.LayoutManager; -import java.awt.RenderingHints; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.Timer; /** * @author hades * @version 10.0 * Created by hades on 2021/4/12 */ -public class TransparentPane extends JComponent implements ActionListener { +public class TransparentPane extends LoadingPane { private UILabel label; - private AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); - private volatile boolean mIsRunning; - private volatile boolean mIsFadingOut; - private Timer mTimer; - private int mAngle; - private int mFadeCount; - private int mFadeLimit = 15; - private int lines = 12; - private int maxAngle = 360; - private int angleAdd = 30; + private double prec = 0.56; public TransparentPane() { - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - // do nothing - } - }); - - setLayout(getCoverLayout()); - setBackground(null); - setOpaque(false); + super(); label = new UILabel(Toolkit.i18nText("Fine-Design_Saving_Template_Tip")); add(label); } @@ -91,72 +63,4 @@ public class TransparentPane extends JComponent implements ActionListener { }; } - - @Override - public void paint(Graphics g) { - int w = this.getWidth(); - int h = this.getHeight(); - super.paint(g); - if (!mIsRunning) { - return; - } - Graphics2D g2 = (Graphics2D) g.create(); - float fade = (float) mFadeCount / (float) mFadeLimit; - Composite urComposite = g2.getComposite(); - g2.setComposite(composite); - g2.fillRect(0, 0, w, h); - g2.setComposite(urComposite); - int s = Math.min(w, h) / 50; - int cx = w / 2; - int cy = h / 2; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.BLACK); - g2.rotate(Math.PI * mAngle / 180, cx, cy); - for (int i = 0; i < lines; i++) { - float scale = (11.0f - (float) i) / 11.0f; - g2.drawLine(cx + s, cy, cx + s * 2, cy); - g2.rotate(-Math.PI / 6, cx, cy); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, scale * fade)); - } - g2.dispose(); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (mIsRunning) { - repaint(); - mAngle += angleAdd; - if (mAngle >= maxAngle) { - mAngle = 0; - } - if (mIsFadingOut) { - if (--mFadeCount == 0) { - mIsRunning = false; - mTimer.stop(); - } - } else if (mFadeCount < mFadeLimit) { - mFadeCount++; - } - } - } - - public void start() { - if (mIsRunning) { - return; - } - mIsRunning = true; - mIsFadingOut = false; - mFadeCount = 0; - int fps = 24; - int tick = 1000 / fps; - mTimer = new Timer(tick, this); - mTimer.start(); - } - - public void stop() { - mIsRunning = false; - mIsFadingOut = true; - } - } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/AuthorityTargetObjectCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/AuthorityTargetObjectCollector.java new file mode 100644 index 0000000000..9972c7be37 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/AuthorityTargetObjectCollector.java @@ -0,0 +1,37 @@ +package com.fr.design.mainframe.authority; + +import com.fr.base.CloneCollector; +import com.fr.base.Formula; +import com.fr.data.impl.NameDatabaseConnection; +import com.fr.data.impl.NameTableData; +import com.fr.report.cell.cellattr.core.group.DSColumn; +import com.fr.stable.FCloneable; + + +import java.util.ArrayList; +import java.util.List; + +public class AuthorityTargetObjectCollector extends CloneCollector { + List targetObject = new ArrayList<>(); + + public AuthorityTargetObjectCollector(FCloneable rootObject) { + super(rootObject); + } + + @Override + public void collect(Object object) { + if (object instanceof DSColumn || object instanceof Formula + || object instanceof NameDatabaseConnection || object instanceof NameTableData) { + targetObject.add(object); + } + } + + public List collectTargetObject() { + CloneCollector.setCollector(this); + this.targetObject = new ArrayList<>(); + this.collect(); + CloneCollector.clearCollector(); + return targetObject; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java index d76031f654..b33f0665c9 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java @@ -1,24 +1,24 @@ package com.fr.design.mainframe.authority; +import com.fr.base.CloneCollector; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; -import com.fr.design.mod.ModClassFilter; import com.fr.file.ConnectionConfig; import com.fr.file.TableDataConfig; -import com.fr.invoke.ClassHelper; import com.fr.log.FineLoggerFactory; -import com.fr.stable.Filter; import com.fr.workspace.WorkContext; import com.fr.workspace.server.authority.user.UserAuthority; -import java.util.Collection; + +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -77,24 +77,21 @@ public class JTemplateAuthorityChecker { public boolean isAuthority() { long s = System.currentTimeMillis(); - //遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来 - Map> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet(), ClassFilter.getInstance()); - + List targetObjects = getTargetObjects(); //找到对应的checker,对对象进行检查 - for (String name : targetObjects.keySet()) { + for (Object targetObject : targetObjects) { + String name = targetObject.getClass().getName(); ElementAuthorityChecker checker = checkerMap.get(name); - for (Object object : targetObjects.get(name)) { - if (authConnectionNames != null) { - Set noAuthName = checker.getNoAuthConnectionNames(object, authConnectionNames); - if (noAuthName != null) { - authFailConnectionNames.addAll(noAuthName); - } + if (authConnectionNames != null) { + Set noAuthName = checker.getNoAuthConnectionNames(targetObject, authConnectionNames); + if (noAuthName != null) { + authFailConnectionNames.addAll(noAuthName); } - if (authDatasetNames != null) { - Set noAuthName = checker.getNoAuthDatasetNames(object, authDatasetNames); - if (noAuthName != null) { - authFailDatasetNames.addAll(noAuthName); - } + } + if (authDatasetNames != null) { + Set noAuthName = checker.getNoAuthDatasetNames(targetObject, authDatasetNames); + if (noAuthName != null) { + authFailDatasetNames.addAll(noAuthName); } } } @@ -104,6 +101,18 @@ public class JTemplateAuthorityChecker { return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0; } + private List getTargetObjects() { + List targetObjects = new ArrayList<>(); + try { + AuthorityTargetObjectCollector authorityTargetObjectCollector + = new AuthorityTargetObjectCollector(jTemplate.getTarget()); + targetObjects = authorityTargetObjectCollector.collectTargetObject(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return targetObjects; + } + public void showAuthorityFailPromptDialog() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure")); @@ -151,38 +160,5 @@ public class JTemplateAuthorityChecker { return stringBuffer.toString(); } - static class ClassFilter implements Filter { - - private static final Set FILTER_SET = new HashSet<>(); - private static final Set START_WITH_SET = new HashSet<>(); - private static final Filter INSTANCE = new ModClassFilter(); - - public static Filter getInstance() { - return INSTANCE; - } - - static { - FILTER_SET.add("java.awt.image.BufferedImage"); - FILTER_SET.add("sun.awt.AppContext"); - FILTER_SET.add("com.fr.poly.creator.ECBlockCreator"); - FILTER_SET.add("io.netty.channel.nio.SelectedSelectionKeySet"); - FILTER_SET.add("com.fr.form.ui.ElementCaseImage"); - FILTER_SET.add("this$0"); - START_WITH_SET.add("com.fr.design"); - } - - @Override - public boolean accept(String s) { - if (FILTER_SET.contains(s)) { - return true; - } - for (String start : START_WITH_SET) { - if (s.startsWith(start)) { - return true; - } - } - return false; - } - } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/ColorBackgroundQuickPane.java b/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/ColorBackgroundQuickPane.java index 2fbdb974e0..086a07da48 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/ColorBackgroundQuickPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/ColorBackgroundQuickPane.java @@ -16,13 +16,26 @@ public class ColorBackgroundQuickPane extends BackgroundQuickPane { private NewColorSelectBox colorSelectBox; - - public ColorBackgroundQuickPane() { + public ColorBackgroundQuickPane(boolean supportTransparent) { this.setLayout(FRGUIPaneFactory.createBorderLayout()); - colorSelectBox = new NewColorSelectBox(100); + colorSelectBox = new NewColorSelectBox(100, supportTransparent) { + @Override + public boolean shouldResponseChangeListener() { + // ColorBackgroundQuickPane注册监听器ChangeListenerImpl的逻辑不能丢,因为里面有修改字段backgroundChange的逻辑. + // 所以在监听器重复注册以及UndoState重复生成时,应该保留ChangeListenerImpl, 而放弃NewColorSelectBox内部自己注册 + // ChangeListener + // REPORT-63760 【主题切换】撤销以后,样式设置有问题 + // REPORT-64006 【模板主题】单元格自定义样式背景色设置不生效 + return false; + } + }; this.add(colorSelectBox, BorderLayout.NORTH); } + public ColorBackgroundQuickPane() { + this(false); + } + public void populateBean(Background background) { ColorBackground colorBackgroud = (ColorBackground) background; populateColor(colorBackgroud.getColor()); @@ -40,11 +53,6 @@ public class ColorBackgroundQuickPane extends BackgroundQuickPane { return this.colorSelectBox.getSelectObject(); } - /** - * 给组件登记一个观察者监听事件 - * - * @param listener 观察者监听事件 - */ @Override public void registerChangeListener(final UIObserverListener listener) { this.colorSelectBox.addSelectChangeListener(new ChangeListenerImpl(listener)); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java b/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java index 9a86a38c11..44a46d60a1 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java @@ -35,7 +35,7 @@ public class NullBackgroundQuickPane extends BackgroundQuickPane { @Override public boolean isBackgroundChange() { - return true; + return false; } /** diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java similarity index 63% rename from designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java rename to designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java index 23616a482a..51fe2f816a 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java @@ -1,6 +1,7 @@ package com.fr.design.mainframe.chart.mode; import com.fr.common.annotations.Open; +import com.fr.design.base.mode.DesignModeContext; /** * @author shine @@ -23,4 +24,13 @@ public class ChartEditContext { public static boolean normalMode() { return current == ChartEditMode.NORMAL; } + + /** + * 是否支持 主题样式 设置 + * + * @return duchamp大屏模板模式 不支持 图表组件&cpt组件中的图表 都不支持 + */ + public static boolean supportTheme() { + return !DesignModeContext.isDuchampMode(); + } } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java similarity index 100% rename from designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java rename to designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java diff --git a/designer-base/src/main/java/com/fr/design/mainframe/check/CheckButton.java b/designer-base/src/main/java/com/fr/design/mainframe/check/CheckButton.java index 0ec50ef248..1d09f24828 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/check/CheckButton.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/check/CheckButton.java @@ -1,6 +1,7 @@ package com.fr.design.mainframe.check; import com.fr.base.BaseUtils; +import com.fr.base.svg.IconUtils; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; @@ -44,7 +45,7 @@ public class CheckButton extends UIButton { private UILabel imageLabel; public CheckButton() { - this.setIcon(BaseUtils.readIcon("/com/fr/design/images/buttonicon/check.png")); + this.setIcon(IconUtils.readIcon("/com/fr/design/standard/font_miss_check")); this.setToolTipText(Toolkit.i18nText("Fine_Designer_Check_Font")); this.set4ToolbarButton(); this.addActionListener(checkListener); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/form/FormECDesignerProvider.java b/designer-base/src/main/java/com/fr/design/mainframe/form/FormECDesignerProvider.java index 88a4623071..2dc68704ec 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/form/FormECDesignerProvider.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/form/FormECDesignerProvider.java @@ -1,10 +1,6 @@ package com.fr.design.mainframe.form; -import java.awt.Dimension; -import java.awt.image.BufferedImage; - -import javax.swing.JComponent; - +import com.fr.base.TRL; import com.fr.design.designer.TargetComponent; import com.fr.design.mainframe.JTemplate; import com.fr.design.menu.MenuDef; @@ -12,6 +8,10 @@ import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; import com.fr.form.FormElementCaseProvider; +import javax.swing.JComponent; +import java.awt.Dimension; +import java.awt.image.BufferedImage; + public interface FormECDesignerProvider { String XML_TAG = "FormElementCaseDesigner"; @@ -92,4 +92,6 @@ public interface FormECDesignerProvider { void refreshPropertyPane(); void removeSelection(); + + default void navigate(TRL trl) {} } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java index 9469f931a1..c8d3e6801d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/Guide.java @@ -10,6 +10,8 @@ import com.fr.stable.StringUtils; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; public class Guide { private String id; @@ -101,7 +103,7 @@ public class Guide { } GuideManager.getInstance().setCurrentGuide(this); guideView.showLoading(); - + guideView.addHierarchyListener(loadingHierarchyListener); new SwingWorker() { @Override protected Boolean doInBackground() { @@ -135,6 +137,9 @@ public class Guide { public void start() { guideView.hideLoading(); + } + + private void startScene() { if (scene != null) { guideView.setScene(scene); guideView.showGuide(); @@ -161,6 +166,7 @@ public class Guide { if (lifecycle != null) { lifecycle.onTerminate(); } + guideView.removeHierarchyListener(loadingHierarchyListener); end(); } @@ -186,4 +192,12 @@ public class Guide { public void removeGuideLifecycle() { this.lifecycle = null; } + + private HierarchyListener loadingHierarchyListener = new HierarchyListener() { + @Override + public void hierarchyChanged(HierarchyEvent e) { + guideView.removeHierarchyListener(loadingHierarchyListener); + startScene(); + } + }; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java index aa277adbbf..6a9a60615f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/base/GuideView.java @@ -40,7 +40,6 @@ public class GuideView extends JDialog { this.setSize(window.getSize()); this.setLayout(FRGUIPaneFactory.createBorderLayout()); setBg(); - this.setGlassPane(new GuideLoadingGlassPane()); DesignerContext.getDesignerFrame().addWindowListener(new WindowAdapter() { @Override @@ -86,7 +85,12 @@ public class GuideView extends JDialog { updateGuideViewLocation(); this.setVisible(true); if (scene != null) { - scene.start(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + scene.start(); + } + }); } else { GuideManager.getInstance().getCurrentGuide().complete(); } @@ -106,12 +110,16 @@ public class GuideView extends JDialog { } public void showLoading() { + this.setGlassPane(GuideLoadingGlassPane.getInstance()); + GuideLoadingGlassPane.getInstance().startLoading(); updateGuideViewLocation(); this.setVisible(true); + this.invalidate(); this.getGlassPane().setVisible(true); } public void hideLoading() { + GuideLoadingGlassPane.getInstance().stopLoading(); this.getGlassPane().setVisible(false); repaint(); SwingUtilities.invokeLater(new Runnable() { @@ -124,6 +132,6 @@ public class GuideView extends JDialog { private void updateGuideViewLocation() { GUICoreUtils.centerWindow(window, this); - this.setSize(getSize()); + this.setBounds(window.getBounds()); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java index f0d74789d2..cdb1765ffb 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/AbstractGuideScene.java @@ -9,9 +9,11 @@ import com.fr.design.mainframe.guide.tip.BubbleTip; import com.fr.design.mainframe.guide.tip.GuideTip; import com.fr.stable.StringUtils; +import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import java.awt.AWTException; import java.awt.AlphaComposite; @@ -21,6 +23,7 @@ import java.awt.Composite; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; @@ -33,6 +36,7 @@ import java.util.List; public abstract class AbstractGuideScene extends JPanel implements GuideScene { private static final int DEFAULT_ARROW_HEIGHT = 12; private static final int DEFAULT_ARROW_WIDTH = 18; + public static final Insets DEFAULT_HIGHLIGHT_INSETS = new Insets(5, 5, 5, 5); private GuideScene nextScene; private SceneFilter sceneFilter; @@ -72,13 +76,16 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { if (component instanceof JComponent) { JComponent jComponent = (JComponent) component; image = ScreenImage.createImage(jComponent); + highlightList.add(getTargetComponentWithImage(image, rectangle, !(component.getParent() instanceof JPopupMenu))); } else if (component instanceof Window) { image = ScreenImage.createImage(component); + highlightList.add(getTargetComponentWithImage(image, rectangle, false)); } else { image = captureImage(component); + highlightList.add(getTargetComponentWithImage(image, rectangle,true)); } targetList.add(component); - highlightList.add(getTargetComponentWithImage(image, rectangle)); + return true; } catch (AWTException e) { e.printStackTrace(); @@ -96,7 +103,7 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { try { targetList.add(null); BufferedImage image = captureImage(rectangle); - highlightList.add(getTargetComponentWithImage(image, rectangle)); + highlightList.add(getTargetComponentWithImage(image, rectangle, true)); return true; } catch (AWTException e) { e.printStackTrace(); @@ -130,7 +137,7 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { image = ScreenImage.createImage(component).getSubimage(origin.x, origin.y, origin.width, origin.height); } targetList.add(component); - highlightList.add(getTargetComponentWithImage(image, rectangle)); + highlightList.add(getTargetComponentWithImage(image, rectangle, true)); return true; } catch (AWTException e) { e.printStackTrace(); @@ -167,11 +174,29 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { return highlightList; } - private UILabel getTargetComponentWithImage(BufferedImage image, Rectangle rectangle) { + private UILabel getTargetComponentWithImage(BufferedImage image, Rectangle rectangle, boolean showBorder) { ImageIcon ic = new ImageIcon(image); - UILabel label = new UILabel(ic); - label.setOpaque(true); - label.setBounds(rectangle); + UILabel label; + if (showBorder) { + label = new UILabel(ic){ + @Override + public Insets getInsets() { + return DEFAULT_HIGHLIGHT_INSETS; + } + }; + label.setBackground(Color.WHITE); + label.setOpaque(true); + label.setBounds(new Rectangle( + rectangle.x - DEFAULT_HIGHLIGHT_INSETS.left, + rectangle.y - DEFAULT_HIGHLIGHT_INSETS.top, + rectangle.width + DEFAULT_HIGHLIGHT_INSETS.left + DEFAULT_HIGHLIGHT_INSETS.right, + rectangle.height + DEFAULT_HIGHLIGHT_INSETS.top + DEFAULT_HIGHLIGHT_INSETS.bottom + )); + } else { + label = new UILabel(ic); + label.setBounds(rectangle); + } + return label; } @@ -307,9 +332,6 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { nextButton.setBounds((getSceneWidth() - 60) / 2, getSceneHeight() - 100, 60, 30); add(nextButton); } - - container.revalidate(); - container.repaint(); } showContainer(); if (lifecycle != null) { @@ -319,9 +341,7 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { @Override public void complete() { - container.getLayeredPane().remove(this); - container.repaint(); - + clear(); if (lifecycle != null && !lifecycle.onComplete()) { return; } @@ -386,13 +406,16 @@ public abstract class AbstractGuideScene extends JPanel implements GuideScene { return container.getLayeredPane().getHeight(); } - private void clear() { - targetList = new ArrayList<>(); - highlightList = new ArrayList<>(); + public void clear() { + targetList.clear(); + highlightList.clear(); + pointsList.clear(); this.nextButton = null; - this.removeAll(); - invalidate(); - repaint(); + if (this.getComponentCount() > 0) { + this.removeAll(); + invalidate(); + repaint(); + } } @Override diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java index 6217f41e7b..0d8b5711b0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/scene/ClickScene.java @@ -1,13 +1,15 @@ package com.fr.design.mainframe.guide.scene; +import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.mainframe.guide.base.GuideManager; import javax.swing.AbstractButton; -import javax.swing.ButtonModel; import javax.swing.SwingUtilities; import java.awt.Component; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -58,49 +60,60 @@ public class ClickScene extends AbstractGuideScene{ public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if ((e.getClickCount() == 1 && clickType == ClickType.LEFT) || (e.getClickCount() == 2 && clickType == ClickType.LEFT_DOUBLE)) { - if (isDispatch) { - redispatchMouseEvent(e, target); - } - complete(); + dealWithDispatchLeftClick(target, e, isDispatch); } } else if (e.getButton() == MouseEvent.BUTTON3 && clickType == ClickType.RIGHT) { - if (isDispatch) { - redispatchMouseEvent(e, target); - } - complete(); + clear(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (isDispatch) { + redispatchMouseEvent(e, target); + } + complete(); + } + }); } + } + @Override public void mousePressed(MouseEvent e) { - if (isDispatch) { - if (target instanceof AbstractButton) { - AbstractButton b = (AbstractButton) target; - b.setFocusable(false); + if ((target instanceof AbstractButton) && (target.getParent() instanceof UIButtonGroup)) { + if (isDispatch) { + redispatchMouseEvent(e, target); } - redispatchMouseEvent(e, target); - } - } - - @Override - public void mouseReleased(MouseEvent e) { - if (isDispatch) { - redispatchMouseEvent(e, target); } - } - @Override - public void mouseEntered(MouseEvent e) { - if (isDispatch) { - redispatchMouseEvent(e, target); - } } + }); + } + private void dealWithDispatchLeftClick(Component target, MouseEvent e, boolean isDispatch) { + clear(); + SwingUtilities.invokeLater(new Runnable() { @Override - public void mouseExited(MouseEvent e) { + public void run() { if (isDispatch) { - redispatchMouseEvent(e, target); + if (target instanceof AbstractButton) { + AbstractButton button = (AbstractButton) target; + ActionListener[] actionListeners= button.getActionListeners(); + for(int i = 0; i < actionListeners.length; i++) { + ActionListener actionListener = actionListeners[i]; + actionListener.actionPerformed(new ActionEvent( + button, + ActionEvent.ACTION_PERFORMED, + button.getActionCommand(), + e.getWhen(), + e.getModifiers() + )); + } + } else { + redispatchMouseEvent(e, target); + } } + complete(); } }); } @@ -114,7 +127,7 @@ public class ClickScene extends AbstractGuideScene{ @Override public void showScene() { // 交互类的 scene 如果没有高亮内容块载,需要及时终止Guide,否则就没法去掉模态框影响到设计器主功能的使用了 - if (this.getComponentCount() == 0) { + if (this.getComponentCount() == 0 && getHighlightList().isEmpty()) { GuideManager.getInstance().getCurrentGuide().terminate(); } else { super.showScene(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java index d3d1c040df..13e5dc28f0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java @@ -2,8 +2,6 @@ package com.fr.design.mainframe.guide.tip; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.i18n.Toolkit; -import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.DesignerFrame; import com.fr.design.mainframe.guide.base.Guide; import com.fr.design.mainframe.guide.base.GuideManager; import com.fr.design.mainframe.guide.ui.bubble.Bubble; @@ -16,9 +14,11 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class BubbleTip implements GuideTip { + private static final int GAP = 5; private BubbleWithClose bubbleBox; private Point anchor; + /** * * @param title 标题 @@ -70,12 +70,12 @@ public class BubbleTip implements GuideTip { int bubbleW = bubbleBox.getPreferredSize().width; int bubbleH = bubbleBox.getPreferredSize().height; if (bubbleBox.isTailHorizontal()) { - int x = bubbleBox.isTailLeft() ? anchor.x : anchor.x - bubbleW; + int x = bubbleBox.isTailLeft() ? anchor.x + GAP : anchor.x - bubbleW - GAP; int y = anchor.y - (int) (bubbleH * bubbleBox.getTailStart()); bubbleBox.setBounds(x, y, bubbleW, bubbleH); } else if (bubbleBox.isTailVertical()) { int x = anchor.x - (int) (bubbleW * bubbleBox.getTailStart()); - int y = bubbleBox.isTailTop() ? anchor.y : anchor.y - bubbleH; + int y = bubbleBox.isTailTop() ? anchor.y + GAP : anchor.y - bubbleH - GAP; bubbleBox.setBounds(x, y, bubbleW, bubbleH); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java index 56f978731b..79d49d1925 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/BubbleHint.java @@ -17,6 +17,7 @@ import java.awt.event.ActionListener; public class BubbleHint extends Bubble { private UIButton confirmButton; + private static final Color CONTENT_TEXT_COLOR = new Color(51, 51, 52); public BubbleHint() { super(TailDirection.TOP, 0.9f); @@ -38,21 +39,21 @@ public class BubbleHint extends Bubble { title.setHorizontalAlignment(SwingConstants.CENTER); title.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); - UILabel content1 = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content1")); - content1.setPreferredSize(new Dimension(190,20)); - content1.setHorizontalAlignment(SwingConstants.CENTER); + UILabel content1 = createContentLabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content1")); - UILabel content2 = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content2")); - content2.setPreferredSize(new Dimension(190,20)); - content2.setHorizontalAlignment(SwingConstants.CENTER); + UILabel content2 = createContentLabel(Toolkit.i18nText("Fine-Design_Guide_Tips_Content2")); JPanel buttonContainer= FRGUIPaneFactory.createCenterFlowZeroGapBorderPane(); - buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0)); + buttonContainer.setBorder(BorderFactory.createEmptyBorder(15, 0, 0, 0)); buttonContainer.setPreferredSize(new Dimension(190,40)); buttonContainer.setOpaque(false); - confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Guide_Tips_Know")); - confirmButton.setPreferredSize(new Dimension(78, 24)); + confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Guide_Tips_Know")) { + public Dimension getPreferredSize() { + return new Dimension(78, 24); + } + }; + buttonContainer.add(confirmButton); contentPane.add(title); @@ -71,4 +72,13 @@ public class BubbleHint extends Bubble { confirmButton.removeActionListener(listener); } + private UILabel createContentLabel(String text) { + UILabel content = new UILabel(text); + content.setPreferredSize(new Dimension(190,20)); + content.setHorizontalAlignment(SwingConstants.CENTER); + content.setFont(content.getFont().deriveFont(14.0f)); + content.setForeground(CONTENT_TEXT_COLOR); + return content; + } + } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java index c71a15ea7d..c4e6e01601 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ExpandPane.java @@ -30,7 +30,7 @@ public class ExpandPane extends JPanel { } private void initComponent() { - VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP, 10, 5); + VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP, 10, 0); layout.setAlignLeft(true); this.setLayout(layout); @@ -47,7 +47,7 @@ public class ExpandPane extends JPanel { private JPanel createHeader() { headerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - headerPane.setPreferredSize(new Dimension(200, 24)); + headerPane.setPreferredSize(new Dimension(200, 16)); UILabel headerTitle = new UILabel(this.title); headerTitle.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); arrow = new UILabel(downIcon); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java index 29316652da..1d5b907e3b 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideCompleteDialog.java @@ -7,6 +7,7 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.guide.utils.GuideUIUtils; import com.fr.design.utils.gui.GUIPaintUtils; import com.fr.general.IOUtils; @@ -22,6 +23,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; +import java.awt.Font; import java.awt.Graphics2D; import java.awt.Window; import java.awt.event.ActionEvent; @@ -34,12 +36,16 @@ public class GuideCompleteDialog extends JDialog { private static final int ICON_HEIGHT = 182; private static final Color FONT_COLOR = new Color(51, 51, 52); private static final Color BUTTON_BG_COLOR = new Color(65, 155,249); + private static final Font TITLE_FONT = new Font("Default", Font.BOLD, 22); + private static final Font CONTENT_FONT = new Font("Default", Font.PLAIN, 18); + private static final Font BUTTON_FONT = new Font("Default", Font.BOLD, 14); private static GuideCompleteDialog dialog; public static GuideCompleteDialog getInstance() { if (dialog == null) { dialog = new GuideCompleteDialog(DesignerContext.getDesignerFrame()); } + dialog = new GuideCompleteDialog(DesignerContext.getDesignerFrame()); return dialog; } @@ -65,17 +71,17 @@ public class GuideCompleteDialog extends JDialog { container.setBorder(BorderFactory.createEmptyBorder(15, 52, 25, 52)); UILabel title = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Complete_Confirm")); - title.setFont(title.getFont().deriveFont(22.0f)); + title.setFont(TITLE_FONT); title.setPreferredSize(new Dimension(190, 30)); title.setHorizontalAlignment(SwingConstants.CENTER); title.setForeground(FONT_COLOR); textArea = new UITextPane(); + textArea.setFont(CONTENT_FONT); + GuideUIUtils.setTextPaneLineHeight(textArea, 26); textArea.setEnabled(false); textArea.setOpaque(false); - textArea.setFont(textArea.getFont().deriveFont(18.0f)); textArea.setPreferredSize(new Dimension(236, 52)); - textArea.setBorder(null); textArea.setDisabledTextColor(FONT_COLOR); StyledDocument doc = textArea.getStyledDocument(); SimpleAttributeSet center = new SimpleAttributeSet(); @@ -83,7 +89,8 @@ public class GuideCompleteDialog extends JDialog { doc.setParagraphAttributes(0, doc.getLength(), center, false); JPanel buttonContainer= FRGUIPaneFactory.createCenterFlowZeroGapBorderPane(); - buttonContainer.setPreferredSize(new Dimension(190,38)); + buttonContainer.setPreferredSize(new Dimension(190,43)); + buttonContainer.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); buttonContainer.setOpaque(false); UIButton button = new UIButton(Toolkit.i18nText("Fine-Design_Guide_Complete_End")){ @@ -92,6 +99,7 @@ public class GuideCompleteDialog extends JDialog { return new Dimension(122, 38); } }; + button.setFont(BUTTON_FONT); button.setUI(confirmButtonUI); button.setRoundBorder(true); button.setForeground(Color.WHITE); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingGlassPane.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingGlassPane.java index 64017dfb70..44590540da 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingGlassPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingGlassPane.java @@ -9,11 +9,11 @@ import javax.swing.SwingConstants; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; public class GuideLoadingGlassPane extends JPanel { - private static final String loadingImagePath = "/com/fr/design/mainframe/guide/loading.gif"; private static GuideLoadingGlassPane loadingPane; public static GuideLoadingGlassPane getInstance() { @@ -32,16 +32,15 @@ public class GuideLoadingGlassPane extends JPanel { public void initComponent() { JPanel loadingView = FRGUIPaneFactory.createBorderLayout_S_Pane(); loadingView.setOpaque(false); - loadingView.setPreferredSize(new Dimension(130, 120)); + loadingView.setPreferredSize(new Dimension(150, 90)); JPanel imageContainer = FRGUIPaneFactory.createCenterFlowInnerContainer_S_Pane(); imageContainer.setOpaque(false); - ImagePanel imagePanel = new ImagePanel(loadingImagePath); - imagePanel.setOpaque(false); - imagePanel.setPreferredSize(new Dimension(84, 84)); - imageContainer.add(imagePanel); + + imageContainer.add(GuideLoadingPane.getInstance()); UILabel hintLabel = new UILabel(Toolkit.i18nText("Fine-Design_Guide_Loading_Wait")); + hintLabel.setFont(new Font("Default", Font.PLAIN, 14)); hintLabel.setHorizontalAlignment(SwingConstants.CENTER); hintLabel.setForeground(Color.WHITE); @@ -50,4 +49,12 @@ public class GuideLoadingGlassPane extends JPanel { this.add(loadingView, new GridBagConstraints()); } + + public void startLoading() { + GuideLoadingPane.getInstance().start(); + } + + public void stopLoading() { + GuideLoadingPane.getInstance().stop(); + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingPane.java new file mode 100644 index 0000000000..0a290c784c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideLoadingPane.java @@ -0,0 +1,98 @@ +package com.fr.design.mainframe.guide.ui; + +import javax.swing.JPanel; +import javax.swing.Timer; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Created by kerry on 2020-10-23 + */ +public class GuideLoadingPane extends JPanel { + private static final BasicStroke STROKE = new BasicStroke(4); + private static final int FPS = 30; + private static final int START_ANGLE = 90; + private static GuideLoadingPane imagePanel; + private Image image; + private int angle; + private Timer timer; + + public static GuideLoadingPane getInstance() { + if (imagePanel == null) { + imagePanel = new GuideLoadingPane(); + } + return imagePanel; + } + + public GuideLoadingPane() { + this.setOpaque(false); + this.setPreferredSize(new Dimension(50, 50)); + timer = new Timer(1000 / FPS, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + repaint(); + angle -= 180 / FPS; // 5 degrees per 100 ms = 50 degrees/second + if (angle > -270) { + angle += 2 * 360; + } + } + }); + } + + public void start() { + angle = START_ANGLE; + timer.start(); + } + + public void stop() { + timer.stop(); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + Composite oldComposite = g2.getComposite(); + Stroke oldStroke = g2.getStroke(); + + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + + int d = Math.min(getWidth(), getHeight()); + int r = d / 2; + Point circlePoint = new Point(getWidth() / 2, getHeight() / 2); + + g2.setColor(Color.WHITE); + g2.fillOval(circlePoint.x - r, circlePoint.y - r, d, d); + + g2.setColor(Color.BLACK); + int waitCircleD = d / 10; + int waitCircleR = waitCircleD / 2; + + g2.fillOval(circlePoint.x - r / 3 - waitCircleR, circlePoint.y - waitCircleR, waitCircleD, waitCircleD); + g2.fillOval(circlePoint.x - waitCircleR, circlePoint.y - waitCircleR, waitCircleD, waitCircleD); + g2.fillOval(circlePoint.x + r / 3 - waitCircleR, circlePoint.y - waitCircleR, waitCircleD, waitCircleD); + + + g2.setStroke(STROKE); + g2.setColor(Color.decode("#419BF9")); + + int lineWidth = (int) STROKE.getLineWidth(); + g2.drawArc(circlePoint.x - r + lineWidth / 2 , circlePoint.y - r + lineWidth / 2, d - lineWidth, d - lineWidth, angle, -90); + + g2.setStroke(oldStroke); + g2.setComposite(oldComposite); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java index 07059ad052..ca53613c46 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/GuideManageDialog.java @@ -1,6 +1,7 @@ package com.fr.design.mainframe.guide.ui; +import com.fr.base.svg.IconUtils; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; @@ -14,7 +15,6 @@ import com.fr.design.mainframe.guide.base.GuideManager; import com.fr.design.mainframe.guide.base.GuideVersion; import com.fr.design.mainframe.guide.collect.GuideCollector; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.IOUtils; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -31,9 +31,9 @@ import java.awt.event.ActionListener; public class GuideManageDialog extends JDialog { private static final int DEFAULT_HEIGHT = 400; private static final int DEFAULT_WIDTH = 600; - private static final Icon GROUP_COMPLETE_NONE = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_none.png"); - private static final Icon GROUP_COMPLETE_SOME = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_some.png"); - private static final Icon GROUP_COMPLETE_ALL = IOUtils.readIcon("/com/fr/design/mainframe/guide/complete_all.png"); + private static final Icon GROUP_COMPLETE_NONE = IconUtils.readIcon("/com/fr/design/mainframe/guide/complete_none.svg"); + private static final Icon GROUP_COMPLETE_SOME = IconUtils.readIcon("/com/fr/design/mainframe/guide/complete_some.svg"); + private static final Icon GROUP_COMPLETE_ALL = IconUtils.readIcon("/com/fr/design/mainframe/guide/complete_all.svg"); private static final Color BORDER_COLOR = new Color(224, 224, 225); private static final Color UNCOMPLETE_FONT_COLOR = new Color(51, 51, 52); private static final Color COMPLETE_FONT_COLOR = new Color(51,51,52,128); @@ -74,7 +74,7 @@ public class GuideManageDialog extends JDialog { } private JPanel createGuideVersionPane(GuideVersion guideVersion) { - JPanel expandContent = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 5); + JPanel expandContent = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 10); for (GuideGroup guideGroup : guideVersion.getGuideGroupList()) { JPanel guideGroupCard = createGuideGroupCard(guideGroup); expandContent.add(guideGroupCard); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ImagePanel.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ImagePanel.java deleted file mode 100644 index deaf974176..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/ImagePanel.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.fr.design.mainframe.guide.ui; - -import javax.swing.JPanel; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.Toolkit; - -/** - * Created by kerry on 2020-10-23 - */ -public class ImagePanel extends JPanel { - - - private Image image; - - public ImagePanel(String imagePath) { - image = Toolkit.getDefaultToolkit().createImage(ImagePanel.class - .getResource(imagePath)); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - if (image != null) { - g.drawImage(image, 0, 0, getWidth(), getHeight(), this); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java index ba8f3da05d..6851c09cd5 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java @@ -4,6 +4,7 @@ package com.fr.design.mainframe.guide.ui.bubble; import com.fr.base.GraphHelper; import com.fr.design.gui.frpane.UITextPane; import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.mainframe.guide.utils.GuideUIUtils; import com.fr.general.IOUtils; import com.fr.stable.StringUtils; @@ -18,7 +19,6 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.Graphics2D; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Rectangle; @@ -32,13 +32,21 @@ import java.text.AttributedCharacterIterator; import java.text.AttributedString; public class BubbleWithClose extends Bubble { - private static final Font FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 14); + private static final Font TITLE_FONT = new Font("Default", Font.PLAIN, 14); + private static final Font CONTENT_FONT = new Font("Default", Font.PLAIN, 12); + private static final int TITLE_LINE_HEIGHT = 22; + private static final int CONTENT_LINE_HEIGHT = 18; + private static final Icon ICON = IOUtils.readIcon("/com/fr/design/mainframe/guide/close.png"); - private static final int HEADER_HEIGHT = 24; - private static final Color HEADER_COLOR = new Color(245, 245, 246); private static final Color TITLE_COLOR = new Color(51, 51, 52); private static final Color CONTENT_COLOR = new Color(51,51,52,128); - private static final Insets DEFAULT_INSET = new Insets(10, 15, 10, 15); + private static final Color HIGHLIGHT_COLOR = new Color(65, 155, 249); + private static final Insets DEFAULT_INSET = new Insets(15, 15, 15, 15); + private static final int MIN_WIDTH = 140; + private static final int MAX_WIDTH = 275; + private static final int ICON_GAP = 10; + private static final int ICON_SIZE = 10; + private static final int TEXT_GAP = 5; private String title; @@ -46,6 +54,8 @@ public class BubbleWithClose extends Bubble { private UITextPane titleTextArea; private UITextPane contentTextArea; private UIButton closeButton; + private Dimension titleSize; + private Dimension contentSize; public BubbleWithClose(String title, String content) { this(title, content, TailDirection.LEFT, 0.5f); @@ -87,23 +97,17 @@ public class BubbleWithClose extends Bubble { @Override public void componentResized(ComponentEvent e) { Rectangle rectBounds = getRectBounds(); - Dimension buttonSize = closeButton.getPreferredSize(); - - closeButton.setBounds(getWidth() - 10 - buttonSize.width, rectBounds.y + (HEADER_HEIGHT - buttonSize.height) / 2, buttonSize.width, buttonSize.height); - Dimension titleSize = new Dimension(0,0); - Dimension contentSize = new Dimension(0, 0); + closeButton.setBounds(rectBounds.x + rectBounds.width - DEFAULT_INSET.right - ICON_SIZE, rectBounds.y + 21, ICON_SIZE, ICON_SIZE); if (titleTextArea != null) { - titleSize = calTextSize(titleTextArea, getTextAreaMaxWidth()); - int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - titleSize.width) / 2 + DEFAULT_INSET.left; - int y = rectBounds.y + HEADER_HEIGHT + DEFAULT_INSET.top; + int x = rectBounds.x + DEFAULT_INSET.left; + int y = rectBounds.y + DEFAULT_INSET.top; titleTextArea.setBounds(x, y, titleSize.width, titleSize.height); } if (contentTextArea != null) { - contentSize = calTextSize(contentTextArea, getTextAreaMaxWidth()); - int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - contentSize.width) / 2 + DEFAULT_INSET.left; - int y = rectBounds.y = HEADER_HEIGHT + DEFAULT_INSET.top + (titleSize.height == 0 ? 0 : titleSize.height + 10); + int x = rectBounds.x + DEFAULT_INSET.left; + int y = rectBounds.y + DEFAULT_INSET.top + (titleSize.height == 0 ? 0 : titleSize.height + getTextGap()); contentTextArea.setBounds(x,y, contentSize.width, contentSize.height); } setSize(getPreferredSize().width, getPreferredSize().height); @@ -116,7 +120,7 @@ public class BubbleWithClose extends Bubble { closeButton = new UIButton(); closeButton.setIcon(ICON); closeButton.set4ToolbarButton(); - closeButton.setPreferredSize(new Dimension(12, 12)); + closeButton.setPreferredSize(new Dimension(ICON_SIZE, ICON_SIZE)); closeButton.setRolloverEnabled(false); closeButton.setPressedPainted(false); this.add(closeButton); @@ -138,44 +142,69 @@ public class BubbleWithClose extends Bubble { private void createTitleTextArea() { if (StringUtils.isNotEmpty(title)) { - titleTextArea = createTextArea(title, FONT, TITLE_COLOR); + titleTextArea = createTextArea(title, TITLE_FONT, TITLE_LINE_HEIGHT, TITLE_COLOR); this.add(titleTextArea); } - + titleSize = calTextSize(titleTextArea, TITLE_LINE_HEIGHT, getTextAreaWidth(MAX_WIDTH), getTextAreaWidth(MIN_WIDTH)); } private void createContentTextArea() { if (StringUtils.isNotEmpty(content)) { - contentTextArea = createTextArea(content, FONT, CONTENT_COLOR); + contentTextArea = createTextArea(content, CONTENT_FONT, CONTENT_LINE_HEIGHT, CONTENT_COLOR); this.add(contentTextArea); } + contentSize = calTextSize(contentTextArea, CONTENT_LINE_HEIGHT, getTextAreaWidth(MAX_WIDTH), getTextAreaWidth(MIN_WIDTH)); } - private UITextPane createTextArea(String str, Font font, Color foreground) { - UITextPane textArea= new UITextPane(){ - @Override - public Insets getInsets() { - return new Insets(0, 0, 0, 0); - } - }; - textArea.setText(str); - textArea.setEnabled(false); - textArea.setDisabledTextColor(foreground); - textArea.setBorder(null); + private UITextPane createTextArea(String str, Font font, int lineHeight, Color foreground) { + UITextPane textArea= new UITextPane(); textArea.setFont(font); - textArea.setOpaque(false); + GuideUIUtils.setTextPaneLineHeight(textArea, lineHeight); + textArea.setEditable(false); textArea.setForeground(foreground); - StyledDocument doc = textArea.getStyledDocument(); - SimpleAttributeSet center = new SimpleAttributeSet(); - StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); - doc.setParagraphAttributes(0, doc.getLength(), center, false); + textArea.setDisabledTextColor(foreground); + textArea.setOpaque(false); + textArea.setText(str); + highlightText(textArea); return textArea; } + private void highlightText(JTextPane textArea) { + SimpleAttributeSet sas = new SimpleAttributeSet(); + StyleConstants.setForeground(sas, HIGHLIGHT_COLOR); + StyledDocument doc = textArea.getStyledDocument(); + String text = textArea.getText(); + int startPos = -1; + for (int i = 0; i < text.length(); i ++) { + char ch = text.charAt(i); + if (ch == '【') { + startPos = i; + } + if (ch == '】') { + if (startPos > 0) { + try { + doc.setCharacterAttributes(startPos, (i - startPos + 1), sas, false); + startPos = -1; + } catch (Exception e) { + } + } + } + } + + } + + @Override + protected int getDefaultWidth() { + return Math.max(titleSize.width, contentSize.width) + getHorizontalInsets() + ICON_GAP + ICON_SIZE + (isTailHorizontal() ? TAIL_HEIGHT : 0) ; + } + + @Override protected int getDefaultHeight() { - Dimension titleSize = calTextSize(titleTextArea, getDefaultTextAreaMaxWidth()); - Dimension contentSize = calTextSize(contentTextArea, getDefaultTextAreaMaxWidth()); - return (isTailVertical() ? TAIL_HEIGHT : 0) + HEADER_HEIGHT + titleSize.height + (titleSize.height == 0 ? 0 : 5) + contentSize.height + getVerticalInsets(); + return titleSize.height + contentSize.height + getTextGap() + getVerticalInsets() + (isTailVertical() ? TAIL_HEIGHT : 0); + } + + private int getTextGap() { + return (titleSize.height != 0 && contentSize.height != 0) ? TEXT_GAP : 0; } private LayoutManager getLayoutManager() { @@ -206,18 +235,6 @@ public class BubbleWithClose extends Bubble { }; } - @Override - protected void paintBubbleBg(Graphics2D g2) { - super.paintBubbleBg(g2); - paintHeaderBg(g2); - } - - private void paintHeaderBg(Graphics2D g2) { - g2.setColor(HEADER_COLOR); - Rectangle bounds = getRectBounds(); - g2.fillRoundRect(bounds.x, bounds.y, bounds.width, HEADER_HEIGHT, 10, 10); - } - private int countLines(JTextPane textArea, int max_width) { AttributedString text = new AttributedString(textArea.getText()); text.addAttribute(TextAttribute.FONT, textArea.getFont()); @@ -234,28 +251,26 @@ public class BubbleWithClose extends Bubble { return lines; } - private Dimension calTextSize(JTextPane textArea, int maxWidth) { + private Dimension calTextSize(JTextPane textArea, int lineHeight, int maxWidth, int minWidth) { if (textArea == null) { - return new Dimension(0, 0); + return new Dimension(minWidth, 0); } FontMetrics fontMetrics = GraphHelper.getFontMetrics(textArea.getFont()); int line = countLines(textArea, maxWidth); int width = maxWidth; if (line == 1) { - width = fontMetrics.stringWidth(textArea.getText()); + width = Math.max(fontMetrics.stringWidth(textArea.getText()), minWidth); } - int height = fontMetrics.getHeight() * line; + int height = lineHeight * line; return new Dimension(width, height); } - private int getTextAreaMaxWidth() { - return getWidth() - (isTailHorizontal() ? TAIL_HEIGHT : 0) -getHorizontalInsets(); - } - private int getDefaultTextAreaMaxWidth() { - return BUBBLE_WIDTH - getHorizontalInsets(); + private int getTextAreaWidth(int bubbleWidth) { + return bubbleWidth - getHorizontalInsets() - ICON_SIZE - ICON_GAP; } + private int getHorizontalInsets() { return DEFAULT_INSET.left + DEFAULT_INSET.right; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/GuideUIUtils.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/GuideUIUtils.java new file mode 100644 index 0000000000..bd6ee33102 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/utils/GuideUIUtils.java @@ -0,0 +1,28 @@ +package com.fr.design.mainframe.guide.utils; + +import com.fr.base.GraphHelper; + +import javax.swing.BorderFactory; +import javax.swing.JTextPane; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import java.awt.FontMetrics; +import java.awt.Insets; + +public class GuideUIUtils { + public static void setTextPaneLineHeight(JTextPane pane, int lineHeight) { + pane.selectAll(); + pane.setMargin(new Insets(0,0,0,0)); + MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes()); + FontMetrics fontMetrics = GraphHelper.getFontMetrics(pane.getFont()); + int delta = (lineHeight - fontMetrics.getHeight()) / 2 * 2 ; + if (delta > 0) { + StyleConstants.setLineSpacing(set, delta/ 2.0f / fontMetrics.getHeight()); + pane.setParagraphAttributes(set, false); + int dis = fontMetrics.getDescent() - fontMetrics.getLeading(); + int marginTop = dis > 0 ? ((delta - dis) / 2 + dis) : ((delta - dis) / 2); + pane.setBorder(BorderFactory.createEmptyBorder(marginTop, 0,0,0)); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogAppender.java b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogAppender.java index 118ea2e321..f965c21725 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogAppender.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogAppender.java @@ -1,41 +1,41 @@ package com.fr.design.mainframe.loghandler; - -import com.fr.third.apache.log4j.AppenderSkeleton; -import com.fr.third.apache.log4j.Level; -import com.fr.third.apache.log4j.spi.LoggingEvent; - +import com.fr.third.apache.logging.log4j.Level; +import com.fr.third.apache.logging.log4j.core.Filter; +import com.fr.third.apache.logging.log4j.core.Layout; +import com.fr.third.apache.logging.log4j.core.LogEvent; +import com.fr.third.apache.logging.log4j.core.appender.AbstractAppender; +import com.fr.third.apache.logging.log4j.core.config.Property; +import com.fr.third.apache.logging.log4j.core.layout.PatternLayout; +import java.io.Serializable; import java.util.Date; /** * Created by Administrator on 2017/7/18 0018. */ -public class DesignerLogAppender extends AppenderSkeleton { +public class DesignerLogAppender extends AbstractAppender { - public DesignerLogAppender() { - this.layout = new com.fr.third.apache.log4j.PatternLayout("%d{HH:mm:ss} %t %p [%c] %m%n"); + protected DesignerLogAppender(String name, Filter filter, + Layout layout, + boolean ignoreExceptions, + Property[] properties) { + super(name, filter, layout, ignoreExceptions, properties); } - protected void append(LoggingEvent event) { - this.subAppend(event); + public static DesignerLogAppender createDesignerLogAppender() { + return new DesignerLogAppender(DesignerLogAppender.class.getSimpleName(), null, PatternLayout.newBuilder().withPattern("%d{HH:mm:ss} %t %p [%c] %m%n %throwable{0}").build(), false, Property.EMPTY_ARRAY); } - public boolean requiresLayout() { - return true; + @Override + public void append(LogEvent event) { + this.subAppend(event); } - public synchronized void close() { - if (this.closed) { - return; - } - this.closed = true; - - } - public void subAppend(LoggingEvent event) { + public void subAppend(LogEvent event) { synchronized (DesignerLogHandler.getInstance()) { Level level = event.getLevel(); - String msg = this.layout.format(event); + String msg = (String) this.toSerializable(event); DesignerLogHandler.getInstance().printRemoteLog(msg, level, new Date()); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogHandler.java b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogHandler.java index 1d67c47df1..b36ca47294 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogHandler.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogHandler.java @@ -1,32 +1,46 @@ package com.fr.design.mainframe.loghandler; +import com.fr.stable.collections.combination.Pair; import com.fr.base.BaseUtils; +import com.fr.base.TRL; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.imenu.UIMenuItem; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; import com.fr.design.ui.util.UIUtil; +import com.fr.file.FILEFactory; import com.fr.general.ComparatorUtils; import com.fr.general.log.Log4jConfig; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; -import com.fr.third.apache.log4j.Level; -import com.fr.third.apache.log4j.spi.LoggingEvent; -import com.fr.third.apache.log4j.spi.ThrowableInformation; +import com.fr.stable.project.ProjectConstants; +import com.fr.third.apache.logging.log4j.Level; +import com.fr.third.apache.logging.log4j.core.LogEvent; +import com.fr.third.guava.base.Splitter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; +import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTextPane; import javax.swing.KeyStroke; +import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; +import javax.swing.text.Element; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; +import javax.swing.text.html.HTML; +import javax.swing.text.html.HTMLDocument; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; @@ -37,8 +51,14 @@ import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Date; +import java.util.Deque; +import java.util.List; +import java.util.regex.Pattern; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; @@ -62,6 +82,8 @@ public class DesignerLogHandler { private static final String ACTION_MAP_KEY = "clear"; + private static final Pattern pattern = Pattern.compile("\\([^(]*.(?>cpt|frm|cptx)[^)]*\\)"); + public static DesignerLogHandler getInstance() { return HOLDER.singleton; @@ -128,7 +150,7 @@ public class DesignerLogHandler { JPopupMenu jPopupMenu = new JPopupMenu(); - int logLevelInt = Log4jConfig.getInstance().getRootLevel().toInt(); + int logLevelInt = Log4jConfig.getInstance().getRootLevel().intLevel(); if (logLevelInt <= DesignerLogger.INFO_INT) { jPopupMenu.add(showInfo); jPopupMenu.add(showError); @@ -216,13 +238,61 @@ public class DesignerLogHandler { popup.show(jTextArea, event.getX(), event.getY()); checkEnabled(); } + if (event.getButton() == MouseEvent.BUTTON1) { + String url = findTplLinkFromMouseEvent(event); + if (StringUtils.isNotEmpty(url)) { + navigate(url); + } + } } }); } + /** + * 将模板定位链接导航到指定的位置 + * + * @param href 模板定位链接 + */ + private void navigate(String href) { + if (!href.startsWith(TRL.PREFIX)) { + return; + } + TRL trl = new TRL(href); + DesignerContext.getDesignerFrame().openTemplate(FILEFactory.createFILE(ProjectConstants.REPORTLETS_NAME + FILEFactory.SEPARATOR + trl.getTemplatePath())); + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentEditingTemplate != null) { + currentEditingTemplate.navigate(trl); + } + } + + /** + * 鼠标事件中定位到模板链接 + * + * @param event 鼠标事件 + * @return 模板链接 + */ + private String findTplLinkFromMouseEvent(MouseEvent event) { + JEditorPane editor = (JEditorPane) event.getSource(); + int pos = editor.getUI().viewToModel(editor, event.getPoint()); + if (pos >= 0 && editor.getDocument() instanceof HTMLDocument) { + HTMLDocument hdoc = (HTMLDocument) editor.getDocument(); + Element elem = hdoc.getCharacterElement(pos); + Object a = elem.getAttributes().getAttribute(HTML.Tag.A); + if (a instanceof AttributeSet) { + AttributeSet set = (AttributeSet) a; + String url = (String) set.getAttribute(HTML.Attribute.HREF); + if (StringUtils.isNotEmpty(url)) { + return url; + } + } + } + return StringUtils.EMPTY; + } + private JTextPane initLogJTextArea() { final JTextPane resultPane = new JTextPane(); + resultPane.setContentType("text/html"); InputMap inputMap = resultPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); @@ -240,23 +310,22 @@ public class DesignerLogHandler { return resultPane; } - public void printStackTrace(LoggingEvent event) { + public void printStackTrace(LogEvent event) { - int intLevel = event.getLevel().toInt(); - Date date = new Date(event.getTimeStamp()); - ThrowableInformation information = event.getThrowableInformation(); + int intLevel = event.getLevel().intLevel(); + Date date = new Date(event.getTimeMillis()); if (intLevel == DesignerLogger.INFO_INT && showInfo.isSelected()) { - printMessage(event.getRenderedMessage(), intLevel, date, information == null ? null : information.getThrowable()); + printMessage(event.getMessage().getFormattedMessage(), intLevel, date, event.getThrown()); } else if (intLevel == DesignerLogger.ERROR_INT && showError.isSelected()) { - printMessage(event.getRenderedMessage(), intLevel, date, information == null ? null : information.getThrowable()); + printMessage(event.getMessage().getFormattedMessage(), intLevel, date, event.getThrown()); } else if (intLevel == DesignerLogger.WARN_INT && showServer.isSelected()) { - printMessage(event.getRenderedMessage(), intLevel, date, information == null ? null : information.getThrowable()); + printMessage(event.getMessage().getFormattedMessage(), intLevel, date, event.getThrown()); } } public void printStackTrace(String message, Level level, Date date) { - int intLevel = level.toInt(); + int intLevel = level.intLevel(); if (intLevel == DesignerLogger.INFO_INT && showInfo.isSelected()) { printMessage(message, intLevel, date); } else if (intLevel == DesignerLogger.ERROR_INT && showError.isSelected()) { @@ -296,6 +365,9 @@ public class DesignerLogHandler { SimpleAttributeSet attrSet = new SimpleAttributeSet(); if (style == DesignerLogger.ERROR_INT) { + if (renderLink(str)) { + return; + } StyleConstants.setForeground(attrSet, Color.RED); StyleConstants.setBold(attrSet, true); } else if (style == DesignerLogger.WARN_INT) { @@ -316,6 +388,86 @@ public class DesignerLogHandler { } } + /** + * 渲染模板链接 + * + * @param str 可能包含模板链接字符串 + * @return 是否处理成功 + */ + private boolean renderLink(String str) { + Document doc = jTextArea.getStyledDocument(); + if (doc instanceof HTMLDocument) { + String[] tplLink = findTplLink(str); + return tplLink != null + && tplLink.length > 0 + && link2Html(str, tplLink); + } + return false; + } + + /** + * 处理模板链接 + * + * @param s 含有模板链接 + * @param tplLink 模板链接 + * @return 是否处理成功 + */ + private boolean link2Html(String s, String[] tplLink) { + List lineSeg = splitLineSeg(s, tplLink); + String html = buildHtml(lineSeg, tplLink); + try { + Document doc = jTextArea.getStyledDocument(); + HTMLDocument htmlDocument = (HTMLDocument) doc; + htmlDocument.insertAfterEnd(htmlDocument.getCharacterElement(doc.getLength()), html); + } catch (BadLocationException | IOException ignored) { + // 这里出问题不记录日志否则会导致死循环 + return false; + } + return true; + } + + @NotNull + private String buildHtml(List lineSeg, String[] tplLink) { + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < tplLink.length; i++) { + sb.append("") + .append(lineSeg.get(i)) + .append("") + .append(tplLink[i]) + .append(""); + } + if (lineSeg.size() > tplLink.length) { + sb.append("").append(lineSeg.get(lineSeg.size() - 1)).append(""); + } + sb.append(""); + return sb.toString(); + } + + /** + * 将非公式部分切割为数组 + */ + @NotNull + private List splitLineSeg(String s, String[] tplLink) { + String seg = s.replaceAll("\\n", "
"); + List lineSeg = new ArrayList<>(2); + List lineSegTmp = new ArrayList<>(); + String tmp = seg; + for (String link : tplLink) { + lineSegTmp = Splitter.on(link).omitEmptyStrings().splitToList(tmp); + lineSeg.add(lineSegTmp.get(0)); + if (lineSegTmp.size() > 1) { + tmp = lineSegTmp.get(1); + } + } + if (lineSegTmp.size() > 1) { + lineSeg.add(lineSegTmp.get(1)); + } + return lineSeg; + } + + private String appendLocaleMark(String str, int style) { if (style == DesignerLogger.ERROR_INT) { @@ -377,4 +529,34 @@ public class DesignerLogHandler { }; } + + /** + * 尝试找到模板链接 + * + * @param s 可能含有模板链接的字符串 + * @return 模板链接 + */ + @Nullable + public static String[] findTplLink(String s) { + List list = new ArrayList<>(); + // 栈配对 + Deque> stack = new ArrayDeque<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(') { + stack.push(new Pair<>(c, i)); + } else if (c == ')') { + Pair left = stack.peek(); + if (left != null && left.getFirst() == '(') { + Pair pop = stack.pop(); + String link = s.substring(pop.getSecond(), i + 1); + if (link.contains(ProjectConstants.CPT_SUFFIX) + || link.contains(ProjectConstants.FRM_SUFFIX)) { + list.add(link); + } + } + } + } + return list.toArray(new String[0]); + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogger.java b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogger.java index b2b35da1cd..3b6d4bf7a6 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogger.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/loghandler/DesignerLogger.java @@ -1,26 +1,25 @@ package com.fr.design.mainframe.loghandler; import com.fr.log.FineLoggerFactory; -import com.fr.third.apache.log4j.Level; -import com.fr.third.apache.log4j.spi.LoggingEvent; -import com.fr.third.apache.log4j.spi.ThrowableInformation; +import com.fr.third.apache.logging.log4j.Level; +import com.fr.third.apache.logging.log4j.core.LogEvent; /** * 设计器日志记录 */ public class DesignerLogger { - public static final int INFO_INT = Level.INFO.toInt(); + public static final int INFO_INT = Level.INFO.intLevel(); - public static final int ERROR_INT = Level.ERROR.toInt(); + public static final int ERROR_INT = Level.ERROR.intLevel(); - public static final int WARN_INT = Level.WARN.toInt(); + public static final int WARN_INT = Level.WARN.intLevel(); /** * 记录LoggingEvent对象 * * @param event */ - public static void log(LoggingEvent event) { + public static void log(LogEvent event) { if (event == null) { return; } @@ -30,29 +29,27 @@ public class DesignerLogger { public enum LogParser { DEFAULT(-1) { @Override - public void log(LoggingEvent event) { + public void log(LogEvent event) { } }, - INFO(Level.INFO.toInt()) { + INFO(Level.INFO.intLevel()) { @Override - public void log(LoggingEvent event) { - FineLoggerFactory.getLogger().info(event.getRenderedMessage()); + public void log(LogEvent event) { + FineLoggerFactory.getLogger().info(event.getMessage().getFormattedMessage()); } }, - WARN(Level.WARN.toInt()) { + WARN(Level.WARN.intLevel()) { @Override - public void log(LoggingEvent event) { - ThrowableInformation information = event.getThrowableInformation(); - FineLoggerFactory.getLogger().warn(event.getRenderedMessage(), information == null ? null : information.getThrowable()); + public void log(LogEvent event) { + FineLoggerFactory.getLogger().warn(event.getMessage().getFormattedMessage(), event.getThrown()); } }, - ERROR(Level.ERROR.toInt()) { + ERROR(Level.ERROR.intLevel()) { @Override - public void log(LoggingEvent event) { - ThrowableInformation information = event.getThrowableInformation(); - FineLoggerFactory.getLogger().error(event.getRenderedMessage(), information == null ? null : information.getThrowable()); + public void log(LogEvent event) { + FineLoggerFactory.getLogger().error(event.getMessage().getFormattedMessage(), event.getThrown()); } }; private int level; @@ -65,8 +62,8 @@ public class DesignerLogger { return level; } - public static LogParser parse(LoggingEvent event) { - int intLevel = event.getLevel().toInt(); + public static LogParser parse(LogEvent event) { + int intLevel = event.getLevel().intLevel(); for (LogParser logParser : values()) { if (logParser.getLevel() == intLevel) { return logParser; @@ -76,7 +73,7 @@ public class DesignerLogger { } - public void log(LoggingEvent event) { + public void log(LogEvent event) { } } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java new file mode 100644 index 0000000000..e8f822b9a8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java @@ -0,0 +1,66 @@ +package com.fr.design.mainframe.manager.clip; + +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模板复制黏贴 + */ +public class TemplateTreeClipboard { + + private List clip = new ArrayList<>(); + + private static class Holder { + private static final TemplateTreeClipboard INSTANCE = new TemplateTreeClipboard(); + } + + private TemplateTreeClipboard() { + } + + public static TemplateTreeClipboard getInstance() { + return TemplateTreeClipboard.Holder.INSTANCE; + } + + public List transferNameObjectArray2Map(ExpandMutableTreeNode[] selectedTreeNodes) { + List resultMap = new ArrayList<>(); + if (selectedTreeNodes == null) { + return resultMap; + } + for (ExpandMutableTreeNode selectTreeNode : selectedTreeNodes) { + ExpandMutableTreeNode cloned = (ExpandMutableTreeNode) selectTreeNode.clone(); + if (cloned != null) { + resultMap.add(cloned); + } + } + return resultMap; + } + + /** + * 添加选中的模板数据到剪切板,覆盖原本剪切板内数据 + * + * @param copyList + * @return + */ + public void addToClip(List copyList) { + this.clip = copyList; + } + + /** + * 取出剪切板内的所有模板数据,剪切板不清空 + * + * @return + */ + public List takeFromClip() { + return clip; + } + + /** + * 清空剪切板 + */ + public void reset() { + clip.clear(); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java new file mode 100644 index 0000000000..67e798f6fc --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java @@ -0,0 +1,205 @@ +package com.fr.design.mainframe.manager.search; + +import com.fr.design.file.TemplateDirTreePane; +import com.fr.design.gui.itree.filetree.TemplateDirTree; +import com.fr.design.mainframe.manager.search.searcher.TemplateDirTreeSearcher; +import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.view.TreeSearchRendererHelper; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import javax.swing.SwingUtilities; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class TemplateDirTreeSearchManager { + + /** + * 文件树搜索器 + */ + private TemplateTreeSearcher treeSearcher; + + /** + * 搜索任务的状态 + */ + private TreeSearchStatus treeSearchStatus; + + /** + * 缓存上次搜索文本,避免重复搜索 + */ + private String lastSearchText; + + /** + * 存储与复原 原本模板的UI + */ + private TreeSearchRendererHelper rendererHelper; + + /** + * 搜索状态变化监听 + */ + private List listeners = new ArrayList<>(); + + private TemplateDirTreeSearchManager() { + init(); + } + + private void init() { + this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE; + } + + private static class Holder { + private static final TemplateDirTreeSearchManager INSTANCE = new TemplateDirTreeSearchManager(); + } + + public static TemplateDirTreeSearchManager getInstance() { + return TemplateDirTreeSearchManager.Holder.INSTANCE; + } + + public TreeSearchStatus getTreeSearchStatus() { + return treeSearchStatus; + } + + public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) { + this.treeSearchStatus = treeSearchStatus; + // 每次设置搜索状态,都触发下监听,让页面跟随变化 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + for (TreeSearchStatusChangeListener listener : listeners) { + listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus)); + } + } + }); + } + + public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) { + listeners.add(listener); + } + + /** + * 获取当前的目录树 + * + * @return + */ + private TemplateDirTree getCurrentTemplateDirTree() { + return TemplateDirTreePane.getInstance().getTemplateDirTree(); + } + + public void beforeSearch(TemplateDirTree templateDirTree) { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + rendererHelper = new TreeSearchRendererHelper(); + rendererHelper.save(templateDirTree.getFileTreeCellRenderer()); + treeSearcher = new TemplateDirTreeSearcher(); + FineLoggerFactory.getLogger().debug("switch to template dir search"); + treeSearcher.beforeSearch(templateDirTree); + } + + /** + * 开始搜索 + * + * @param searchText + */ + public void startSearch(String searchText) { + if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) { + return; + } + setTreeSearchStatus(TreeSearchStatus.SEARCHING); + rendererHelper.replaceTreeRenderer(getCurrentTemplateDirTree(), searchText); + FineLoggerFactory.getLogger().debug("start template dir search for search text: {}", searchText); + treeSearcher.startSearch(searchText); + } + + /** + * 中断搜索 + */ + public void stopSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED); + FineLoggerFactory.getLogger().debug("stop template dir search for search text: {}", lastSearchText); + treeSearcher.stopSearch(); + } + + /** + * 搜索完成 + */ + public void completeSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED); + FineLoggerFactory.getLogger().debug("complete template dir search for search text: {}", lastSearchText); + treeSearcher.completeSearch(); + } + + /** + * 退出搜索模式 + */ + public void outOfSearchMode() { + setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE); + FineLoggerFactory.getLogger().info("out of template search"); + lastSearchText = null; + if (treeSearcher != null) { + treeSearcher.exitSearch(); + } + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTemplateDirTree()); + } + } + + /** + * 所有匹配的目录节点 + * @return + */ + public FileNode[] matchesNode() { + return treeSearcher.getMatchSets().toArray(new FileNode[0]); + } + + /** + * 当前目录树中搜索的目录节点 + * @return + */ + public Map allFileNodes() { + return treeSearcher.getAllTemplates(); + } + + /** + * 搜索结果是否为空 + * @return + */ + public boolean isMatchSetsEmpty() { + return treeSearcher.isMatchSetsEmpty(); + } + + /** + * 恢复到模板树面板 + */ + public void restoreTreePane() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + lastSearchText = null; + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTemplateDirTree()); + } + } + + /** + * 刷新树,更新搜索的结果 + */ + public void updateTemplateTree() { + getCurrentTemplateDirTree().refresh4TreeSearch(); + } + + private boolean isRepeatSearch(String searchText) { + boolean repeat = StringUtils.equals(lastSearchText, searchText); + lastSearchText = searchText; + return repeat; + } + + /** + * 当前是否处于搜索模式 + * @return + */ + public boolean isInSearchMode() { + return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java new file mode 100644 index 0000000000..2695c24436 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java @@ -0,0 +1,258 @@ +package com.fr.design.mainframe.manager.search; + +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.view.TreeSearchRendererHelper; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 文件树搜索管理器 + */ +public class TemplateTreeSearchManager { + + /** + * 文件树搜索器 + */ + private TemplateTreeSearcher treeSearcher; + + /** + * 搜索任务的状态 + */ + private TreeSearchStatus treeSearchStatus; + + /** + * 缓存上次搜索文本,避免重复搜索 + */ + private String lastSearchText; + + /** + * 存储与复原 原本模板的UI + */ + private TreeSearchRendererHelper rendererHelper; + + /** + * 是否在更新搜索结果的标识 + */ + private AtomicBoolean isRefreshing = new AtomicBoolean(false); + + /** + * 搜索状态变化监听 + */ + private List listeners = new ArrayList<>(); + + private TemplateTreeSearchManager() { + init(); + } + + private void init() { + this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE; + } + + private static class Holder { + private static final TemplateTreeSearchManager INSTANCE = new TemplateTreeSearchManager(); + } + + public static TemplateTreeSearchManager getInstance() { + return TemplateTreeSearchManager.Holder.INSTANCE; + } + + public TreeSearchStatus getTreeSearchStatus() { + return treeSearchStatus; + } + + public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) { + this.treeSearchStatus = treeSearchStatus; + // 每次设置搜索状态,都触发下监听,让页面跟随变化 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + for (TreeSearchStatusChangeListener listener : listeners) { + listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus)); + } + } + }); + } + + public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) { + listeners.add(listener); + } + + /** + * 工具栏处切换到搜索面板 + * + * @param templateFileTree + */ + public void switchToSearch(TemplateFileTree templateFileTree) { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + rendererHelper = new TreeSearchRendererHelper(); + rendererHelper.save(templateFileTree.getFileTreeCellRenderer()); + treeSearcher = new TemplateTreeSearcher(); + FineLoggerFactory.getLogger().debug("switch to template search"); + treeSearcher.beforeSearch(templateFileTree); + } + + /** + * 获取当前的模板树 + * + * @return + */ + private TemplateFileTree getCurrentTemplateTree() { + return TemplateTreePane.getInstance().getTemplateFileTree(); + } + + public boolean isMatchSetsEmpty() { + return treeSearcher.isMatchSetsEmpty(); + } + + /** + * 开始搜索 + * + * @param searchText + */ + public void startSearch(String searchText) { + if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) { + return; + } + setTreeSearchStatus(TreeSearchStatus.SEARCHING); + rendererHelper.replaceTreeRenderer(getCurrentTemplateTree(), searchText); + FineLoggerFactory.getLogger().debug("start template search for search text: {}", searchText); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + treeSearcher.startSearch(searchText); + return null; + } + }.execute(); + } + + /** + * 中断搜索 + */ + public void stopSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED); + FineLoggerFactory.getLogger().debug("stop template search for search text: {}", lastSearchText); + treeSearcher.stopSearch(); + } + + /** + * 搜索完成 + */ + public void completeSearch() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED); + setRefreshing(false); + FineLoggerFactory.getLogger().debug("complete template search for search text: {}", lastSearchText); + treeSearcher.completeSearch(); + } + + /** + * 刷新树,更新搜索的结果 + */ + public void updateTemplateTree() { + getCurrentTemplateTree().refresh4TreeSearch(); + } + + private boolean isRepeatSearch(String searchText) { + boolean repeat = StringUtils.equals(lastSearchText, searchText); + lastSearchText = searchText; + return repeat; + } + + /** + * 切换回工具栏,恢复数据集树UI + */ + public void restoreToolBarAndTreePane() { + setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE); + FineLoggerFactory.getLogger().info("out of template search"); + if (treeSearcher != null) { + treeSearcher.exitSearch(); + } + setRefreshing(false); + lastSearchText = null; + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTemplateTree()); + } + } + + /** + * 恢复文件树UI + */ + public void restoreTreePane() { + setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); + lastSearchText = null; + if (rendererHelper != null) { + rendererHelper.restore(getCurrentTemplateTree()); + } + } + + /** + * 所有匹配的目录节点 + * @return + */ + public FileNode[] matchesNode() { + if (treeSearcher.getMatchSets().size() == 0) { + return new FileNode[0]; + } + return treeSearcher.getMatchSets().toArray(new FileNode[0]); + } + + public void deleteMatchedNode(Set fileNodes) { + Set deleteNode = new HashSet<>(); + for (FileNode matchedNode : treeSearcher.getMatchSets()) { + if (fileNodes.stream().anyMatch(fileNode -> fileNode.getEnvPath().equals(matchedNode.getEnvPath()))) { + deleteNode.add(matchedNode); + } + } + treeSearcher.getMatchSets().removeAll(deleteNode); + } + + /** + * 当前模板树中的所有模板节点 + * @return + */ + public Map allFileNodes() { + return treeSearcher.getAllTemplates(); + } + + /** + * 是否处于搜索模式 + * @return + */ + public boolean isInSearchMode() { + return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE; + } + + /** + * 退出搜索模式 + */ + public void outOfSearchMode() { + restoreToolBarAndTreePane(); + } + + /** + * 搜索结果数是否处于更新状态 + * @return + */ + public boolean isRefreshing() { + return isRefreshing.get(); + } + + public void setRefreshing(boolean isRefreshing) { + this.isRefreshing.set(isRefreshing); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java new file mode 100644 index 0000000000..fcad773804 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java @@ -0,0 +1,195 @@ +package com.fr.design.mainframe.manager.search.searcher; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateDirSearchCallBack; +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask; +import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplateDirPreSearchTask; +import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack; +import com.fr.design.search.TreeSearchStatus; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.project.ProjectConstants; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * 目录搜索器 + */ +public class TemplateDirTreeSearcher extends TemplateTreeSearcher { + + private ExecutorService executorService; + + private final Map allDirs = new ConcurrentHashMap<>(); + + private final AtomicInteger outLayerDirCount = new AtomicInteger(0); + + private final Set notCalculatedSets = new HashSet<>(); + + private final Set calculatedSets = new HashSet<>(); + + private final Set matchSets = new HashSet<>(); + + private final Object lock = new Object(); + + public Set getMatchSets() { + return this.matchSets; + } + + public boolean isMatchSetsEmpty() { + return matchSets.isEmpty(); + } + + public int getAllDirSize() { + return allDirs.size(); + } + + public Map getAllTemplates() { + return allDirs; + } + + public int getCalculatedCount() { + return this.calculatedSets.size(); + } + + /** + * 将模板添加到已经计算过的集合中,不管模板是不是匹配 + * + * @param templateNames + */ + public synchronized void addToCalculatedSets(List templateNames) { + for (String templateName : templateNames) { + FileNode fileNode = allDirs.get(templateName); + if (fileNode == null) { + return; + } + calculatedSets.add(templateName); + } + } + + /** + * 将搜索匹配的目录添加到匹配的集合中 + * + * @param matchNodes + */ + public synchronized void addToMatchSets(List matchNodes) { + matchSets.addAll(matchNodes); + } + + /** + * 将目录添加到未计算的集合中 + * + * @param fileNodes + */ + public synchronized void addToNotCalculatedSets(List fileNodes) { + synchronized (lock) { + Map chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); + notCalculatedSets.addAll(chileMap.keySet()); + allDirs.putAll(chileMap); + outLayerDirCount.decrementAndGet(); + lock.notify(); + } + } + + /** + * 正式搜索前,预加载一下每个最外层目录里面的所有子节点 + * + */ + public void beforeSearch(TemplateFileTree templateFileTree) { + executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateDirTreeSearcher.class)); + collectOutLayerTemplate(templateFileTree); + preCalculateChild(); + } + + protected void preCalculateChild() { + for (String notCalculatedNode : notCalculatedSets) { + FileNode fileNode = allDirs.get(notCalculatedNode); + //计算最外层目录下的所有子节点 + if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) { + executorService.execute(new TemplateDirPreSearchTask(new TemplatePreSearchCallBack(this), fileNode)); + } + } + } + + /** + * 收集下此次搜索需要进行取数最外层的FileNode + * + * @param templateFileTree + */ + private void collectOutLayerTemplate(TemplateFileTree templateFileTree) { + FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME); + Map fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); + outLayerDirCount.addAndGet(fileNodes.length); + notCalculatedSets.addAll(fileNodeMap.keySet()); + allDirs.putAll(fileNodeMap); + } + + /** + * 开始搜索 + * + * @param searchText + */ + @Override + public void startSearch(String searchText) { + reset(); + do { + synchronized (lock) { + if (notCalculatedSets.isEmpty()) { + try { + lock.wait(100); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + for (String notCalculated : notCalculatedSets) { + FileNode fileNode = allDirs.get(notCalculated); + if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { + executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateDirSearchCallBack(this))); + } + } + FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size()); + notCalculatedSets.clear(); + } + } while (outLayerDirCount.get() != 0); + } + + /** + * 停止搜索 + */ + @Override + public void stopSearch() { + + } + + /** + * 完成搜索 + */ + @Override + public void completeSearch() { + + } + + private void reset() { + matchSets.clear(); + calculatedSets.clear(); + notCalculatedSets.addAll(allDirs.keySet()); + } + + /** + * 退出搜索时的处理 + */ + public void exitSearch() { + allDirs.clear(); + executorService.shutdownNow(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java new file mode 100644 index 0000000000..90611c2b21 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java @@ -0,0 +1,193 @@ +package com.fr.design.mainframe.manager.search.searcher; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchCallBack; +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask; +import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack; +import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchTask; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.TreeSearcher; +import com.fr.design.gui.itree.filetree.TemplateFileTree; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.project.ProjectConstants; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class TemplateTreeSearcher implements TreeSearcher { + + private ExecutorService executorService; + + private final Map allTemplates = new ConcurrentHashMap<>(); + + private final Object lock = new Object(); + + private final AtomicInteger outLayerDirCount = new AtomicInteger(0); + + private final Set calculatedSets = new HashSet<>(); + + private final Set notCalculatedSets = new HashSet<>(); + + private final Set matchSets = new HashSet<>(); + + public boolean isMatchSetsEmpty() { + return matchSets.isEmpty(); + } + + public int getAllTemplateSize() { + return allTemplates.size(); + } + + public Map getAllTemplates() { + return allTemplates; + } + + public Set getMatchSets() { + return this.matchSets; + } + + public int getCalculatedCount() { + return this.calculatedSets.size(); + } + + public int getOutLayerCount() { + return this.outLayerDirCount.get(); + } + + public synchronized void addToCalculatedSets(List templateNames) { + for (String templateName : templateNames) { + FileNode fileNode = allTemplates.get(templateName); + if (fileNode == null) { + return; + } + calculatedSets.add(templateName); + } + } + + /** + * 将搜索匹配的模板添加到匹配的集合中 + * + * @param matchNodes + */ + public synchronized void addToMatchSets(List matchNodes) { + matchSets.addAll(matchNodes); + } + + /** + * 将模板添加到未计算的集合中 + * + * @param fileNodes + */ + public synchronized void addToNotCalculatedSets(List fileNodes) { + synchronized (lock) { + Map chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); + notCalculatedSets.addAll(chileMap.keySet()); + allTemplates.putAll(chileMap); + outLayerDirCount.decrementAndGet(); + lock.notify(); + } + } + + /** + * 正式搜索前,预加载一下每个最外层目录里面的所有子节点 + * + */ + public void beforeSearch(TemplateFileTree templateFileTree) { + executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateTreeSearcher.class)); + collectOutLayerTemplate(templateFileTree); + preCalculateChild(); + } + + protected void preCalculateChild() { + for (String notCalculatedNode : notCalculatedSets) { + FileNode fileNode = allTemplates.get(notCalculatedNode); + //计算最外层目录下的所有子节点 + if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) { + executorService.execute(new TemplatePreSearchTask(new TemplatePreSearchCallBack(this), fileNode)); + } + } + } + + /** + * 收集下此次搜索需要进行取数最外层的FileNode + * + * @param templateFileTree + */ + private void collectOutLayerTemplate(TemplateFileTree templateFileTree) { + FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME); + Map fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); + long dirCount = Arrays.stream(fileNodes).filter(FileNode::isDirectory).count(); + outLayerDirCount.addAndGet((int) dirCount); + notCalculatedSets.addAll(fileNodeMap.keySet()); + allTemplates.putAll(fileNodeMap); + } + + /** + * 开始搜索 + * + * @param searchText + */ + @Override + public void startSearch(String searchText) { + reset(); + do { + synchronized (lock) { + if (notCalculatedSets.isEmpty()) { + try { + lock.wait(100); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + for (String notCalculated : notCalculatedSets) { + FileNode fileNode = allTemplates.get(notCalculated); + if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { + executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateSearchCallBack(this))); + } + } + FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size()); + notCalculatedSets.clear(); + } + } while (outLayerDirCount.get() != 0); + } + + /** + * 停止搜索 + */ + @Override + public void stopSearch() { + + } + + /** + * 完成搜索 + */ + @Override + public void completeSearch() { + + } + + private void reset() { + matchSets.clear(); + calculatedSets.clear(); + notCalculatedSets.addAll(allTemplates.keySet()); + } + + /** + * 退出搜索模式 + */ + public void exitSearch() { + allTemplates.clear(); + executorService.shutdownNow(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java new file mode 100644 index 0000000000..37853c9375 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java @@ -0,0 +1,53 @@ +package com.fr.design.mainframe.manager.search.searcher.control.common; + +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.TemplateDirTreeSearcher; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; + +import javax.swing.SwingUtilities; + +/** + * 目录树搜索回调处理 + */ +public class TemplateDirSearchCallBack implements TreeSearchCallback { + + protected TemplateDirTreeSearcher treeSearcher; + + public TemplateDirSearchCallBack(TemplateDirTreeSearcher treeSearcher) { + this.treeSearcher = treeSearcher; + } + + @Override + public void done(TreeSearchResult treeSearchResult) { + if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + // 添加结果 + addToTreeSearcher(treeSearchResult); + if (treeSearcher.getCalculatedCount() == treeSearcher.getAllDirSize()) { + updateTemplateTree(); + } + } + + /** + * 更新目录树搜索结果 + */ + protected void updateTemplateTree() { + SwingUtilities.invokeLater(() -> { + if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + TemplateDirTreeSearchManager.getInstance().updateTemplateTree(); + TemplateDirTreeSearchManager.getInstance().completeSearch(); + }); + } + + private void addToTreeSearcher(TreeSearchResult treeSearchResult) { + // 添加到已计算结果集 + treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated()); + // 添加到匹配结果集 + treeSearcher.addToMatchSets(((TemplateSearchResult)treeSearchResult).getAddToMatchNode()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java new file mode 100644 index 0000000000..5905ea9a34 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java @@ -0,0 +1,63 @@ +package com.fr.design.mainframe.manager.search.searcher.control.common; + +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher; +import javax.swing.SwingUtilities; + +/** + * 模板搜索回调处理 + */ +public class TemplateSearchCallBack implements TreeSearchCallback { + + protected TemplateTreeSearcher treeSearcher; + private static final int BATCH_SIZE = 500; + + public TemplateSearchCallBack(TemplateTreeSearcher treeSearcher) { + this.treeSearcher = treeSearcher; + } + + @Override + public void done(TreeSearchResult treeSearchResult) { + if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + // 添加结果 + addToTreeSearcher(treeSearchResult); + updateTemplateTree(); + } + + /** + * 更新目录树搜索结果 + */ + protected void updateTemplateTree() { + int calculatedCount = treeSearcher.getCalculatedCount(); + boolean allCalculated = calculatedCount == treeSearcher.getAllTemplateSize(); + boolean isFinish = allCalculated && treeSearcher.getOutLayerCount() == 0; + if (calculatedCount % BATCH_SIZE == 0 || allCalculated) { + // 更新UI + updateOrFinish(isFinish); + } + } + + protected void updateOrFinish(boolean isFinished) { + SwingUtilities.invokeLater(() -> { + if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) { + return; + } + TemplateTreeSearchManager.getInstance().updateTemplateTree(); + if (isFinished) { + TemplateTreeSearchManager.getInstance().completeSearch(); + } + }); + } + + protected void addToTreeSearcher(TreeSearchResult treeSearchResult) { + // 添加到已计算结果集 + treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated()); + // 添加到匹配结果集 + treeSearcher.addToMatchSets(((TemplateSearchResult)treeSearchResult).getAddToMatchNode()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java new file mode 100644 index 0000000000..65014f133f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java @@ -0,0 +1,130 @@ +package com.fr.design.mainframe.manager.search.searcher.control.common; + +import com.fr.design.search.control.TreeSearchResult; +import com.fr.file.filetree.FileNode; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模板搜索结果 + */ +public class TemplateSearchResult implements TreeSearchResult { + + private boolean success; + + private List addToExpand; + + private List addToCalculated; + + private List addToNotCalculated; + + private List addToMatchNode; + + protected TemplateSearchResult(TemplateSearchResult.Builder builder) { + this.success = builder.success; + this.addToMatchNode = builder.addToMatchNode; + this.addToExpand = builder.addToExpand; + this.addToCalculated = builder.addToCalculated; + this.addToNotCalculated = builder.addToNotCalculated; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public void setAddToMatchNode(List addToMatchNode) { + this.addToMatchNode = addToMatchNode; + } + + public void setAddToExpand(List addToExpand) { + this.addToExpand = addToExpand; + } + + public void setAddToCalculated(List addToCalculated) { + this.addToCalculated = addToCalculated; + } + + public void setAddToNotCalculated(List addToNotCalculated) { + this.addToNotCalculated = addToNotCalculated; + } + + @Override + public boolean isSuccess() { + return this.success; + } + + @Override + public List getAddToMatch() { + return new ArrayList<>(); + } + + public List getAddToMatchNode() { + return addToMatchNode; + } + + @Override + public List getAddToExpand() { + return this.addToExpand; + } + + @Override + public List getAddToCalculated() { + return this.addToCalculated; + } + + public List getAddToNotCalculated() { + return this.addToNotCalculated; + } + + public static class Builder { + + private boolean success; + + private List addToMatchNode; + + private List addToExpand; + + private List addToCalculated; + + private List addToNotCalculated; + + + public Builder() { + this.success = false; + this.addToMatchNode = new ArrayList<>(); + this.addToExpand = new ArrayList<>(); + this.addToCalculated = new ArrayList<>(); + this.addToNotCalculated = new ArrayList<>(); + } + + public TemplateSearchResult.Builder buildSuccess(boolean success) { + this.success = success; + return this; + } + + public TemplateSearchResult.Builder buildAddToMatch(List addToMatch) { + this.addToMatchNode = addToMatch; + return this; + } + + public TemplateSearchResult.Builder buildAddToExpand(List addToExpand) { + this.addToExpand = addToExpand; + return this; + } + + public TemplateSearchResult.Builder buildAddToCalculated(List addToCalculated) { + this.addToCalculated = addToCalculated; + return this; + } + + public TemplateSearchResult.Builder buildAddToNotCalculated(List addToNotCalculated) { + this.addToNotCalculated = addToNotCalculated; + return this; + } + + public TemplateSearchResult build() { + return new TemplateSearchResult(this); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java new file mode 100644 index 0000000000..b1cc743748 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java @@ -0,0 +1,79 @@ +package com.fr.design.mainframe.manager.search.searcher.control.common; + +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.search.control.TreeSearchTask; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * 模板搜索任务(比较模板路径与搜索关键字是否匹配) + */ +public class TemplateSearchTask implements TreeSearchTask { + + /** + * 用户搜索的文本 + */ + private String searchText; + + /** + * 目录节点 + */ + private FileNode fileNode; + + private TreeSearchCallback callback; + + public TemplateSearchTask(String searchText, FileNode fileNode, TreeSearchCallback callback) { + this.searchText = searchText; + this.fileNode = fileNode; + this.callback = callback; + } + + @Override + public void run() { + TreeSearchResult result; + try { + result = dealWithTemplateWrapper(fileNode); + FineLoggerFactory.getLogger().debug("calculate template: {} succeeded", fileNode.getName()); + } catch (Throwable e) { + FineLoggerFactory.getLogger().error(e, "calculate template: {} failed", fileNode.getName()); + result = dealWithErrorTemplateWrapper(fileNode); + } + callback.done(result); + } + + private TreeSearchResult dealWithTemplateWrapper(FileNode fileNode) { + String fileName = fileNode.getName(); + + boolean isNameMatch = isMatchSearch(fileName, searchText); + return new TemplateSearchResult.Builder() + .buildSuccess(true) + .buildAddToMatch(isNameMatch ? Arrays.asList(fileNode) : new ArrayList<>()) + .buildAddToExpand(fileNode.isDirectory() ? Arrays.asList(fileName) : new ArrayList<>()) + .buildAddToCalculated(Arrays.asList(fileNode.getEnvPath())) + .build(); + } + + /** + * 处理错误情况 + * + * @param fileNode + */ + private TreeSearchResult dealWithErrorTemplateWrapper(FileNode fileNode) { + return new TemplateSearchResult.Builder().buildSuccess(false) + .buildAddToCalculated(Arrays.asList(fileNode.getEnvPath())).build(); + } + + /** + * 判断是否匹配搜索文本,不区分大小写 + * + * @param str + * @return + */ + private boolean isMatchSearch(String str, String searchText) { + return str.toUpperCase().contains(searchText.toUpperCase()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java new file mode 100644 index 0000000000..9feefcb510 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java @@ -0,0 +1,213 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.itree.filetree.EnvFileTree; +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.FlowLayout; + +/** + * 目录树搜索提示面板:整合了目录树面板和搜索时的提示面板 + */ +public class TemplateDirSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener { + + private TemplateDirSearchRemindPane.RemindPane remindPane; + private TemplateDirSearchRemindPane.TreePane treePane; + + public TemplateDirSearchRemindPane(EnvFileTree templateFileTree) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + remindPane = new TemplateDirSearchRemindPane.RemindPane(); + treePane = new TemplateDirSearchRemindPane.TreePane(templateFileTree); + // 初始状态 + this.add(remindPane, BorderLayout.NORTH); + this.add(treePane, BorderLayout.CENTER); + TemplateDirTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + } + + /** + * 根据搜索状态变化,来调整自身面板的显示 + * + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + TreeSearchStatus status = event.getTreeSearchStatus(); + if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) { + remindPane.onNotBegin(); + treePane.onNotBegin(); + } else if (status == TreeSearchStatus.SEARCHING) { + remindPane.onInSearching(); + treePane.onInSearching(); + } else if (status == TreeSearchStatus.SEARCH_STOPPED) { + remindPane.onStoppedSearching(); + treePane.onStoppedSearching(); + } else { + boolean matchSetsEmpty = TemplateDirTreeSearchManager.getInstance().isMatchSetsEmpty(); + // 代表是否搜索出结果 + remindPane.onDoneSearching(matchSetsEmpty); + treePane.onDoneSearching(matchSetsEmpty); + } + this.revalidate(); + } + + private interface TreeSearchStatusChange { + + void onNotBegin(); + + void onInSearching(); + + void onStoppedSearching(); + + void onDoneSearching(boolean matchSetsEmpty); + } + + private class TreePane extends JPanel implements TemplateDirSearchRemindPane.TreeSearchStatusChange { + + private UIScrollPane scrollPane; + + private JPanel notFoundPane; + + private CardLayout cardLayout; + + private static final String SCROLL_PANE = "scrollPane"; + + private static final String NOT_FOUND_PANE = "notFoundPane"; + + public TreePane(EnvFileTree templateFileTree) { + init(templateFileTree); + } + + private void init(EnvFileTree templateFileTree) { + + scrollPane = new UIScrollPane(templateFileTree); + scrollPane.setBorder(null); + + notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(false, FlowLayout.CENTER, 0, 5); + UILabel emptyPicLabel = new UILabel(); + emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png")); + emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER); + emptyPicLabel.setPreferredSize(new Dimension(570, 100)); + UILabel textLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER); + textLabel.setForeground(Color.gray); + textLabel.setHorizontalAlignment(SwingConstants.CENTER); + textLabel.setPreferredSize(new Dimension(570, 20)); + notFoundPane.add(emptyPicLabel); + notFoundPane.add(textLabel); + + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + this.add(scrollPane, SCROLL_PANE); + this.add(notFoundPane, NOT_FOUND_PANE); + cardLayout.show(this, SCROLL_PANE); + } + + @Override + public void onNotBegin() { + switchPane(SCROLL_PANE); + } + + @Override + public void onInSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onStoppedSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + if (matchSetsEmpty) { + switchPane(NOT_FOUND_PANE); + } + } + + private void switchPane(String paneName) { + cardLayout.show(this, paneName); + } + } + + private static class RemindPane extends JPanel implements TemplateDirSearchRemindPane.TreeSearchStatusChange { + + private static final String IN_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching"); + private static final String STOP_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search"); + private static final String SEARCHING_STOPPED = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped"); + private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed"); + + private UILabel textLabel; + + private UILabel stopLabel; + + private MouseListener stopSearch; + + public RemindPane() { + init(); + } + + private void init() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); + // 初始情况下为Not_Begin + textLabel = new UILabel(); + textLabel.setForeground(Color.gray); + stopLabel = new UILabel(); + stopLabel.setForeground(UIConstants.NORMAL_BLUE); + stopSearch = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TemplateDirTreeSearchManager.getInstance().stopSearch(); + } + }; + stopLabel.addMouseListener(stopSearch); + this.add(textLabel); + this.add(stopLabel); + onNotBegin(); + } + + @Override + public void onNotBegin() { + this.setVisible(false); + } + + @Override + public void onInSearching() { + this.textLabel.setVisible(false); + this.stopLabel.setText(STOP_SEARCHING); + this.stopLabel.setVisible(true); + this.setVisible(true); + } + + @Override + public void onStoppedSearching() { + this.textLabel.setText(SEARCHING_STOPPED); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + this.textLabel.setText(DONE_SEARCHING); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java new file mode 100644 index 0000000000..07636ce631 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java @@ -0,0 +1,152 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.file.TemplateDirTreePane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Insets; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * 目录树搜索面板 + */ +public class TemplateDirTreeSearchPane extends JPanel implements TreeSearchStatusChangeListener { + + /** + * 搜索输入框 + */ + private UITextField searchTextField; + + /** + * 搜索面板 + */ + private JPanel searchPane; + + private final KeyAdapter enterPressed = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + TemplateDirTreeSearchManager.getInstance().startSearch(searchTextField.getText()); + } + } + }; + + public TemplateDirTreeSearchPane() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 10)); + initSearchPane(); + add(searchPane, BorderLayout.CENTER); + TemplateDirTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + TemplateDirTreePane.getInstance().refreshDockingView(); + TemplateDirTreeSearchManager.getInstance().beforeSearch(TemplateDirTreePane.getInstance().getTemplateDirTree()); + } + + private void initSearchPane() { + searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.setBackground(Color.WHITE); + // 左侧搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0)); + searchLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + }); + + // 中间输入框 + initSearchTextField(); + + // 右侧返回图标 + UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear")); + returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); + returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11)); + returnLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TemplateDirTreeSearchManager.getInstance().outOfSearchMode(); + TemplateDirTreePane.getInstance().refreshDockingView(); + } + }); + + searchPane.add(searchLabel, BorderLayout.WEST); + searchPane.add(searchTextField, BorderLayout.CENTER); + searchPane.add(returnLabel, BorderLayout.EAST); + } + + private void initSearchTextField() { + searchTextField = new UITextField(){ + @Override + public Insets getInsets() { + return new Insets(2, 4, 0, 4); + } + }; + searchTextField.setBorderPainted(false); + searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_Dir_Search_Press_Enter_For_Search")); + searchTextField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); + searchPane.repaint(); + } + + @Override + public void focusLost(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.repaint(); + } + }); + this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + } + + @Override + public void removeUpdate(DocumentEvent e) { + dealWithTextChange(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + this.searchTextField.addKeyListener(enterPressed); + } + + private void dealWithTextChange() { + if (StringUtils.isEmpty(searchTextField.getText()) && TemplateDirTreeSearchManager.getInstance().isInSearchMode()) { + // 如果是搜索模式下,看作是用户删除输入框文字,仅复原TemplateTreePane + TemplateDirTreeSearchManager.getInstance().restoreTreePane(); + TemplateDirTreePane.getInstance().refreshDockingView(); + } + } + + /** + * 目录树不涉及到工具栏和搜索栏的切换,无需实现 + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java new file mode 100644 index 0000000000..bdb6a32819 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java @@ -0,0 +1,228 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.itree.filetree.EnvFileTree; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.FlowLayout; + +/** + * 模板搜索提示面板:整合了模板树和提示面板 + */ +public class TemplateSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener { + + private TemplateSearchRemindPane.RemindPane remindPane; + private TemplateSearchRemindPane.TreePane treePane; + + public TemplateSearchRemindPane(EnvFileTree templateFileTree) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + remindPane = new TemplateSearchRemindPane.RemindPane(); + treePane = new TemplateSearchRemindPane.TreePane(templateFileTree); + // 初始状态 + this.add(remindPane, BorderLayout.NORTH); + this.add(treePane, BorderLayout.CENTER); + TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + } + + /** + * 根据搜索状态变化,来调整自身面板的显示 + * + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + TreeSearchStatus status = event.getTreeSearchStatus(); + if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) { + remindPane.onNotBegin(); + treePane.onNotBegin(); + } else if (status == TreeSearchStatus.SEARCHING) { + remindPane.onInSearching(); + treePane.onInSearching(); + } else if (status == TreeSearchStatus.SEARCH_STOPPED) { + remindPane.onStoppedSearching(); + treePane.onStoppedSearching(); + } else { + boolean matchSetsEmpty = TemplateTreeSearchManager.getInstance().isMatchSetsEmpty(); + // 代表是否搜索出结果 + remindPane.onDoneSearching(matchSetsEmpty); + treePane.onDoneSearching(matchSetsEmpty); + } + this.revalidate(); + } + + private interface TreeSearchStatusChange { + + /** + * 搜索未开始时 + */ + void onNotBegin(); + + /** + * 搜索中 + */ + void onInSearching(); + + /** + * 停止搜索 + */ + void onStoppedSearching(); + + /** + * 搜索结束 + * @param matchSetsEmpty + */ + void onDoneSearching(boolean matchSetsEmpty); + } + + private class TreePane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange { + + private UIScrollPane scrollPane; + + private JPanel notFoundPane; + + private CardLayout cardLayout; + + private static final String SCROLL_PANE = "scrollPane"; + + private static final String NOT_FOUND_PANE = "notFoundPane"; + + public TreePane(EnvFileTree templateFileTree) { + init(templateFileTree); + } + + private void init(EnvFileTree templateFileTree) { + + scrollPane = new UIScrollPane(templateFileTree); + scrollPane.setBorder(null); + + notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); + UILabel emptyPicLabel = new UILabel(); + emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png")); + emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER); + emptyPicLabel.setPreferredSize(new Dimension(240, 100)); + UILabel textLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER); + textLabel.setForeground(Color.gray); + textLabel.setHorizontalAlignment(SwingConstants.CENTER); + textLabel.setPreferredSize(new Dimension(240, 20)); + notFoundPane.add(emptyPicLabel); + notFoundPane.add(textLabel); + notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0)); + + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + this.add(scrollPane, SCROLL_PANE); + this.add(notFoundPane, NOT_FOUND_PANE); + cardLayout.show(this, SCROLL_PANE); + } + + @Override + public void onNotBegin() { + switchPane(SCROLL_PANE); + } + + @Override + public void onInSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onStoppedSearching() { + switchPane(SCROLL_PANE); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + if (matchSetsEmpty) { + switchPane(NOT_FOUND_PANE); + } + } + + private void switchPane(String paneName) { + cardLayout.show(this, paneName); + } + } + + private static class RemindPane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange { + + private static final String IN_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching"); + private static final String STOP_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search"); + private static final String SEARCHING_STOPPED = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped"); + private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed"); + + private UILabel textLabel; + + private UILabel stopLabel; + + private MouseListener stopSearch; + + public RemindPane() { + init(); + } + + private void init() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); + // 初始情况下为Not_Begin + textLabel = new UILabel(); + textLabel.setForeground(Color.gray); + stopLabel = new UILabel(); + stopLabel.setForeground(UIConstants.NORMAL_BLUE); + stopSearch = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TemplateTreeSearchManager.getInstance().stopSearch(); + } + }; + stopLabel.addMouseListener(stopSearch); + this.add(textLabel); + this.add(stopLabel); + onNotBegin(); + } + + @Override + public void onNotBegin() { + this.setVisible(false); + } + + @Override + public void onInSearching() { + this.textLabel.setVisible(false); + this.stopLabel.setText(STOP_SEARCHING); + this.stopLabel.setVisible(true); + this.setVisible(true); + } + + @Override + public void onStoppedSearching() { + this.textLabel.setText(SEARCHING_STOPPED); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + + @Override + public void onDoneSearching(boolean matchSetsEmpty) { + this.textLabel.setText(DONE_SEARCHING); + this.textLabel.setVisible(true); + this.stopLabel.setVisible(false); + this.setVisible(true); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java new file mode 100644 index 0000000000..ee9b861b1e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java @@ -0,0 +1,218 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pane; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.search.event.TreeSearchStatusChangeEvent; +import com.fr.design.search.event.TreeSearchStatusChangeListener; +import com.fr.design.search.TreeSearchStatus; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * 模板搜索工具栏 + */ +public class TemplateTreeSearchToolbarPane extends JPanel implements TreeSearchStatusChangeListener { + + public static final String TOOLBAR_PANE = "toolbarPane"; + + public static final String SEARCH_PANE = "searchPane"; + + /** + * 判断工具栏是处于搜索栏还是非搜索栏 + */ + public static String contentPaneType = "toolbarPane"; + + /** + * 工具栏 + */ + private UIToolbar toolbar; + + /** + * 工具栏面板 + */ + private JPanel toolbarPane; + + /** + * 搜索面板 + */ + private JPanel searchPane; + + /** + * 搜索输入框 + */ + private UITextField searchTextField; + + /** + * 内容面板 + */ + private JPanel contentPane; + + /** + * 卡片布局管理器 + */ + private CardLayout cardLayout; + + private final KeyAdapter enterPressed = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + TemplateTreeSearchManager.getInstance().startSearch(searchTextField.getText()); + } + } + }; + + public TemplateTreeSearchToolbarPane(UIToolbar toolbar) { + this.toolbar = toolbar; + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + initToolbarPane(); + initSearchPane(); + initContentPane(); + add(contentPane, BorderLayout.CENTER); + setPreferredSize(new Dimension(240, 30)); + TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); + } + + private void initContentPane() { + cardLayout = new CardLayout(); + contentPane = new JPanel(cardLayout); + contentPane.add(searchPane, SEARCH_PANE); + contentPane.add(toolbarPane, TOOLBAR_PANE); + cardLayout.show(contentPane, TOOLBAR_PANE); + } + + private void initSearchPane() { + searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.setBackground(Color.WHITE); + // 左侧搜索图标 + UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/search")); + searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0)); + searchLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // do nothing + } + }); + // 中间输入框 + initSearchTextField(); + // 右侧返回图标 + UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/clear")); + returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); + returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11)); + returnLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + TemplateTreeSearchManager.getInstance().outOfSearchMode(); + TemplateTreePane.getInstance().refreshDockingView(); + } + }); + + searchPane.add(searchLabel, BorderLayout.WEST); + searchPane.add(searchTextField, BorderLayout.CENTER); + searchPane.add(returnLabel, BorderLayout.EAST); + } + + private void initSearchTextField() { + searchTextField = new UITextField(){ + @Override + public Insets getInsets() { + return new Insets(2, 4, 0, 4); + } + }; + searchTextField.setBorderPainted(false); + searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_Search_Press_Enter_For_Search")); + searchTextField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); + searchPane.repaint(); + } + + @Override + public void focusLost(FocusEvent e) { + searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); + searchPane.repaint(); + } + }); + this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + } + + @Override + public void removeUpdate(DocumentEvent e) { + dealWithTextChange(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + this.searchTextField.addKeyListener(enterPressed); + } + + private void dealWithTextChange() { + if (StringUtils.isEmpty(searchTextField.getText()) && TemplateTreeSearchManager.getInstance().isInSearchMode()) { + // 如果是搜索模式下,看作是用户删除输入框文字,仅复原TemplateTreePane + TemplateTreeSearchManager.getInstance().restoreTreePane(); + TemplateTreePane.getInstance().refreshDockingView(); + } + } + + private void initToolbarPane() { + toolbarPane = new JPanel(); + toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout()); + toolbarPane.add(toolbar, BorderLayout.CENTER); + } + + /** + * 交换当前面板层级 + */ + public void switchPane(String name) { + cardLayout.show(contentPane, name); + contentPaneType = name; + } + + public void setPlaceHolder(String placeHolder) { + this.searchTextField.setPlaceholder(placeHolder); + } + + /** + * 根据搜索状态变化,来调整自身面板的显示 + * + * @param event + */ + @Override + public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { + TreeSearchStatus treeSearchStatus = event.getTreeSearchStatus(); + if (treeSearchStatus == TreeSearchStatus.NOT_IN_SEARCH_MODE) { + this.searchTextField.setText(StringUtils.EMPTY); + switchPane(TOOLBAR_PANE); + } else { + switchPane(SEARCH_PANE); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java new file mode 100644 index 0000000000..b6d626e62a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java @@ -0,0 +1,35 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pre; + +import com.fr.design.file.TemplateDirTreePane; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.file.filetree.FileNode; + +import java.util.List; + +/** + * 目录树搜索时的前置处理,跟模板搜索前置处理类似 + */ +public class TemplateDirPreSearchTask extends TemplatePreSearchTask { + + public TemplateDirPreSearchTask(TreeSearchCallback callback, FileNode fileNode) { + super(callback, fileNode); + } + + /** + * 加载最外层目录下所有的子节点 + * + * @param fileNodes + * @param fileNode + */ + protected void dealWithChildTemplate(List fileNodes, FileNode fileNode) { + FileNode[] childNodes = TemplateDirTreePane.getInstance().getTemplateDirTree().listFile(fileNode.getEnvPath()); + for (FileNode childNode : childNodes) { + if (childNode.isDirectory()) { + fileNodes.add(childNode); + dealWithChildTemplate(fileNodes, childNode); + } else { + fileNodes.add(childNode); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java new file mode 100644 index 0000000000..fd2c6853ba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java @@ -0,0 +1,33 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pre; + +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchCallBack; +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchResult; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher; + +/** + * 模板搜索前置回调处理 + * 主要是将最外层目录下的所有模板添加到未计算的集合中 + */ +public class TemplatePreSearchCallBack extends TemplateSearchCallBack { + + public TemplatePreSearchCallBack(TemplateTreeSearcher treeSearcher) { + super(treeSearcher); + } + + @Override + public void done(TreeSearchResult searchResult) { + addToTreeSearcher(searchResult); + } + + /** + * 将结果添加到未计算的集合中 + * + * @param searchResult + */ + @Override + protected void addToTreeSearcher(TreeSearchResult searchResult) { + TemplateSearchResult templateSearchResult = (TemplateSearchResult) searchResult; + treeSearcher.addToNotCalculatedSets(templateSearchResult.getAddToNotCalculated()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java new file mode 100644 index 0000000000..5eed450622 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java @@ -0,0 +1,62 @@ +package com.fr.design.mainframe.manager.search.searcher.control.pre; + +import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchResult; +import com.fr.design.search.control.TreeSearchCallback; +import com.fr.design.search.control.TreeSearchResult; +import com.fr.design.search.control.TreeSearchTask; +import com.fr.design.file.TemplateTreePane; +import com.fr.file.filetree.FileNode; +import com.fr.log.FineLoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模板搜索前置任务 + * 主要是计算最外层目录下面所有的子节点,并记录到结果集中 + */ +public class TemplatePreSearchTask implements TreeSearchTask { + + protected TreeSearchCallback callback; + + //最外层的目录节点 + protected FileNode fileNode; + + public TemplatePreSearchTask(TreeSearchCallback callback, FileNode fileNode) { + this.callback = callback; + this.fileNode = fileNode; + } + + @Override + public void run() { + TreeSearchResult result; + try { + List allChildNode = new ArrayList<>(); + dealWithChildTemplate(allChildNode, fileNode); + result = new TemplateSearchResult.Builder().buildAddToNotCalculated(allChildNode).buildSuccess(true).build(); + FineLoggerFactory.getLogger().info("[Template Search] calculate {} child nodes success. total child node num is: {}", fileNode.getEnvPath(), allChildNode.size()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("[Template Search] calculate {} child nodes failed", fileNode.getEnvPath()); + result = new TemplateSearchResult.Builder().buildAddToNotCalculated(new ArrayList<>()).buildSuccess(false).build(); + } + callback.done(result); + } + + /** + * 加载最外层目录下所有的子节点 + * + * @param fileNodes + * @param fileNode + */ + protected void dealWithChildTemplate(List fileNodes, FileNode fileNode) { + FileNode[] childNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(fileNode.getEnvPath()); + for (FileNode childNode : childNodes) { + if (childNode.isDirectory()) { + fileNodes.add(childNode); + dealWithChildTemplate(fileNodes, childNode); + } else { + fileNodes.add(childNode); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/SidebarMobileBookMarkStyleCustomDefinePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/SidebarMobileBookMarkStyleCustomDefinePane.java index ae79160bbd..0ed58fa351 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/SidebarMobileBookMarkStyleCustomDefinePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/SidebarMobileBookMarkStyleCustomDefinePane.java @@ -17,6 +17,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.style.color.ColorSelectBox; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.form.ui.mobile.MobileBookMarkStyle; import com.fr.form.ui.mobile.impl.SidebarMobileBookMarkStyle; @@ -161,7 +162,7 @@ public class SidebarMobileBookMarkStyleCustomDefinePane extends BasicBeanPane { private UICheckBox autoCommitCheckBox; + private UISpinner maxDirectShowCountSpinner; + private UILabel showCountTextField; + private static final int MAX_VALUE_AUTO = 4; + private static final int MAX_VALUE = 3; + private static final int MIN_VALUE = 1; + private static final int DEFAULT_DIERTA = 1; + private static final int DEFAULT_VALUE = 4; + private static final int GAP = 2; public MobileTopParamPane() { this.init(); @@ -21,19 +37,43 @@ public class MobileTopParamPane extends BasicBeanPane { JPanel panel = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Plugin-TopParam_Setting")); panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); autoCommitCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Plugin-TopParam_AutoCommit"), true); - panel.add(autoCommitCheckBox); + maxDirectShowCountSpinner = new UISpinner(MIN_VALUE, MAX_VALUE_AUTO, DEFAULT_DIERTA, DEFAULT_VALUE); + showCountTextField = new UILabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_Show_Count")); + Component[][] components = {{autoCommitCheckBox},{showCountTextField, maxDirectShowCountSpinner}}; + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double[] rowSize = {p, p}; + double[] columnSize = {p, f}; + JPanel paraPane = TableLayoutHelper.createCommonTableLayoutPane(components, rowSize, columnSize, GAP); + panel.add(paraPane); this.add(panel, BorderLayout.CENTER); + + autoCommitCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!autoCommitCheckBox.isSelected()) { + maxDirectShowCountSpinner.setMaxValue(MAX_VALUE); + if (maxDirectShowCountSpinner.getValue() >= MAX_VALUE_AUTO) { + maxDirectShowCountSpinner.setValue(MAX_VALUE); + } + } else { + maxDirectShowCountSpinner.setMaxValue(MAX_VALUE_AUTO); + } + } + }); } @Override public void populateBean(MobileTopParamStyle topParamStyle) { autoCommitCheckBox.setSelected(topParamStyle.isAutoCommit()); + maxDirectShowCountSpinner.setValue(topParamStyle.getMaxDirectShowCount()); } @Override public MobileTopParamStyle updateBean() { MobileTopParamStyle topParamStyle = new MobileTopParamStyle(); topParamStyle.setAutoCommit(autoCommitCheckBox.isSelected()); + topParamStyle.setMaxDirectShowCount((int) maxDirectShowCountSpinner.getValue()); return topParamStyle; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/FontConfigPane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/FontConfigPane.java index 6386e31e01..2b98479be2 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/FontConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/FontConfigPane.java @@ -5,6 +5,7 @@ import com.fr.base.Utils; import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.utils.DesignUtils; import com.fr.general.FRFont; import javax.swing.*; @@ -35,7 +36,7 @@ public class FontConfigPane extends JPanel { private void init() { this.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); - fontFamily = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontFamily = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); Vector integerList = new Vector<>(); for (int i = 1; i < 100; i++) { integerList.add(i); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/platform/ServicePlatformAction.java b/designer-base/src/main/java/com/fr/design/mainframe/platform/ServicePlatformAction.java new file mode 100644 index 0000000000..c6dc9a9b66 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/platform/ServicePlatformAction.java @@ -0,0 +1,30 @@ +package com.fr.design.mainframe.platform; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.i18n.Toolkit; +import com.fr.design.utils.BrowseUtils; +import com.fr.general.CloudCenter; +import com.fr.log.FineLoggerFactory; + +import java.awt.Desktop; +import java.awt.event.ActionEvent; +import java.net.URI; + +/** + * 帮助-服务平台 + * + * @author Destiny.Lin + * @version 11.0 + * created by Destiny.Lin on 2022-12-14 + */ +public class ServicePlatformAction extends UpdateAction { + public ServicePlatformAction() { + this.setName(Toolkit.i18nText("Fine-Design_Basic_Service_Platform_Title")); + this.setSmallIcon("/com/fr/design/images/platform/platform", false); + } + + @Override + public void actionPerformed(ActionEvent e) { + BrowseUtils.browser(CloudCenter.getInstance().acquireUrlByKind("service.platform")); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/PatternStyle.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/PatternStyle.java deleted file mode 100644 index c4ebcf225f..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/PatternStyle.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.fr.design.mainframe.predefined; - -import com.fr.config.predefined.PredefinedStyle; -//import com.fr.predefined.PredefinedPatternStyleManager; - - -/** - * Created by kerry on 2020-08-31 - */ -public enum PatternStyle { - DARK_STYLE(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Dark_Pattern")) { - @Override - public PredefinedStyle getPredefinedStyle() { -// return PredefinedPatternStyleManager.INSTANCE.getDarkMode(); - return new PredefinedStyle(); - } - }, - LIGHT_STYLE(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Light_Pattern")) { - @Override - public PredefinedStyle getPredefinedStyle() { -// return PredefinedPatternStyleManager.INSTANCE.getLightMode(); - return new PredefinedStyle(); - } - }; - - - private String name; - - - PatternStyle(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - public abstract PredefinedStyle getPredefinedStyle(); - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleBlock.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleBlock.java deleted file mode 100644 index 67b369a6c9..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleBlock.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - -import com.fr.base.BaseUtils; -import com.fr.base.GraphHelper; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.mainframe.predefined.ui.dialog.PredefinedStyleEditDialog; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.preview.PredefinedStylePreviewPane; -import com.fr.general.ComparatorUtils; -import com.fr.general.IOUtils; -import com.fr.stable.Constants; - -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -/** - * Created by kerry on 2020-08-25 - */ -public class PredefinedStyleBlock extends JPanel { - private PredefinedStyle previewObject; - private PredefinedStyleSelectPane parentPane; - private Icon markedMode = IOUtils.readIcon("/com/fr/design/form/images/marked.png"); - private static final Color BORDER_COLOR = new Color(141, 194, 249); - - private boolean mouseOver = false; - - private MouseListener mouseListener = new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - setSelect(); - } - - @Override - public void mousePressed(MouseEvent e) { - - } - - @Override - public void mouseReleased(MouseEvent e) { - - } - - @Override - public void mouseEntered(MouseEvent e) { - mouseOver = true; - PredefinedStyleBlock.this.repaint(); - } - - @Override - public void mouseExited(MouseEvent e) { - mouseOver = false; - PredefinedStyleBlock.this.repaint(); - } - }; - - - public PredefinedStyleBlock(PredefinedStyle previewObject, PredefinedStyleSelectPane selectPane, boolean supportEdit) { - this.previewObject = previewObject; - this.parentPane = selectPane; - initPane(supportEdit); - this.addMouseListener(mouseListener); - } - - private void setSelect() { - this.parentPane.setSelectedPreviewPane(this); - } - - @Override - public void paint(Graphics g) { - super.paint(g); - boolean isSelected = ComparatorUtils.equals(this, this.parentPane.getSelectedPreviewPane()); - if (ComparatorUtils.equals(this.parentPane.getCurrentApplicateStyle(), this.previewObject.getStyleName())) { - markedMode.paintIcon(this, g, 176, 0); - } - if (isSelected || this.mouseOver) { - g.setColor(BORDER_COLOR); - Rectangle rectangle = new Rectangle(1, 1, this.getWidth() - 2, this.getHeight() - 2); - GraphHelper.draw(g, rectangle, Constants.LINE_MEDIUM); - } - } - - - private void initPane(boolean supportEdit) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - PredefinedStylePreviewPane content = new PredefinedStylePreviewPane(0.387, 0.384); - content.setParent(this); - content.setPreferredSize(new Dimension(200, 180)); - UILabel label = new UILabel(previewObject.getStyleName()); - label.setToolTipText(previewObject.getStyleName()); - label.setPreferredSize(new Dimension(167, 25)); - - - JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - panel.setBorder(BorderFactory.createEmptyBorder(0,9,2,5)); - panel.add(label, BorderLayout.WEST); - if (supportEdit) { - addEditButton(panel); - } - - this.add(content, BorderLayout.CENTER); - this.add(panel, BorderLayout.SOUTH); - this.setPreferredSize(new Dimension(200, 210)); - panel.setBackground(Color.WHITE); - this.setBackground(Color.WHITE); - content.refresh(this.previewObject); - - } - - private void addEditButton(JPanel panel) { - UIButton editButton = new UIButton(BaseUtils.readIcon("/com/fr/design/icon/icon_edit.png")); - editButton.setPreferredSize(new Dimension(24, 24)); - editButton.setBorderPainted(false); - editButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - PredefinedStyleEditPane editPane = PredefinedStyleEditPane.createEditPane(parentPane); - PredefinedStyleEditDialog editDialog = new PredefinedStyleEditDialog( - SwingUtilities.getWindowAncestor(PredefinedStyleBlock.this), editPane, previewObject.isBuiltIn()); - editPane.populate(PredefinedStyleBlock.this.previewObject); - editDialog.setVisible(true); - } - }); - panel.add(editButton, BorderLayout.EAST); - - } - - public PredefinedStyle update() { - return this.previewObject; - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleEditPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleEditPane.java deleted file mode 100644 index 33698d7c1e..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleEditPane.java +++ /dev/null @@ -1,374 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - -import com.fr.base.ChartColorMatching; -import com.fr.base.ChartPreStyleConfig; -import com.fr.base.Style; -import com.fr.base.background.ColorBackground; -import com.fr.config.predefined.ColorFillStyle; -import com.fr.config.predefined.PredefinedCellStyle; -import com.fr.config.predefined.PredefinedCellStyleConfig; -import com.fr.config.predefined.PredefinedColorStyle; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.config.predefined.PredefinedStyleConfig; -import com.fr.config.ServerPreferenceConfig; -import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; -import com.fr.design.gui.frpane.AttributeChangeListener; -import com.fr.design.gui.frpane.UITabbedPane; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.itextfield.UITextField; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.detail.ChartStyleSettingPane; -import com.fr.design.mainframe.predefined.ui.detail.ColorFillStylePane; -import com.fr.design.mainframe.predefined.ui.detail.PredefinedBackgroundSettingPane; -import com.fr.design.mainframe.predefined.ui.detail.ComponentStyleSettingPane; -import com.fr.design.mainframe.predefined.ui.detail.CellStyleListControlPane; -import com.fr.design.mainframe.predefined.ui.preview.PredefinedStylePreviewPane; -import com.fr.design.ui.util.UIUtil; -import com.fr.design.utils.DesignUtils; -import com.fr.general.FRFont; -import com.fr.log.FineLoggerFactory; -import com.fr.stable.StringUtils; -import com.fr.transaction.Configurations; -import com.fr.transaction.WorkerFacade; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Created by kerry on 2020-08-26 - */ -public class PredefinedStyleEditPane extends AbstractAttrNoScrollPane { - private static final Color TIP_COLOR = Color.decode("#8F8F92"); - - private PredefinedStylePreviewPane previewPane; - private UITextField styleNameField; - private PredefinedBackgroundSettingPane backgroundSettingPane; - private CellStyleListControlPane cellStyleSettingPane; - private ComponentStyleSettingPane componentStyleSettingPane; - private ChartStyleSettingPane chartStyleSettingPane; - private PredefinedStyleSelectPane selectPane; - private ColorFillStylePane colorFillStylePane; - private boolean isPopulating = false; - private UITabbedPane uiTabbedPane; - - private boolean isLightMode = true; - - @Override - protected JPanel createContentPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.add(createLeftPane(), BorderLayout.WEST); - jPanel.add(createRightPane(), BorderLayout.CENTER); - - this.addAttributeChangeListener(new AttributeChangeListener() { - @Override - public void attributeChange() { - if (!isPopulating) { - valueChangeAction(); - } - } - }); - return jPanel; - } - - public void valueChangeAction() { - boolean displayFormBackground = backgroundSettingPane.currentFormBackground() || uiTabbedPane.getSelectedIndex() == 3; - previewPane.refresh(this.update(), displayFormBackground); - } - - @Override - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Edit"); - } - - private PredefinedStyleEditPane(PredefinedStyleSelectPane selectPane, boolean newEditPane) { - this.selectPane = selectPane; - this.styleNameField.setEnabled(newEditPane); - } - - public static PredefinedStyleEditPane createEditPane(PredefinedStyleSelectPane selectPane) { - return new PredefinedStyleEditPane(selectPane, false); - } - - public static PredefinedStyleEditPane createNewEditPane(PredefinedStyleSelectPane selectPane) { - return new PredefinedStyleEditPane(selectPane, true); - } - - - private JPanel createLeftPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel titlePane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Overall_Preview")); - previewPane = new PredefinedStylePreviewPane(); - previewPane.setPreferredSize(new Dimension(517, 500)); - - titlePane.add(previewPane); - jPanel.add(titlePane, BorderLayout.CENTER); - return jPanel; - } - - private JPanel createRightPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel styleNamePane = createStyleNamePane(); - jPanel.add(styleNamePane, BorderLayout.NORTH); - - JPanel basicSettingPane = createBasicSettingPane(); - jPanel.add(basicSettingPane, BorderLayout.CENTER); - - JPanel customDetailPane = createCustomDetailPane(); - jPanel.add(customDetailPane, BorderLayout.SOUTH); - return jPanel; - } - - private JPanel createStyleNamePane() { - JPanel jPanel = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(5, 26, 8); - jPanel.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Name"))); - this.styleNameField = new UITextField(); - this.styleNameField.setPreferredSize(new Dimension(160, 20)); - jPanel.add(this.styleNameField); - return jPanel; - } - - private JPanel createBasicSettingPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel titlePane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Basic_Setting")); - JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - colorFillStylePane = new ColorFillStylePane(); - contentPane.add(colorFillStylePane); - titlePane.add(contentPane); - jPanel.add(titlePane, BorderLayout.CENTER); - titlePane.setSize(new Dimension(348, 157)); - return jPanel; - } - - private JPanel createCustomDetailPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel titlePane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Custom_Detail")); - titlePane.setLayout(FRGUIPaneFactory.createLeftZeroLayout()); - jPanel.add(titlePane, BorderLayout.CENTER); - uiTabbedPane = new UITabbedPane(); - uiTabbedPane.addTab(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Template_Background"), createTemplateBackgroundSettingPane()); - uiTabbedPane.addTab(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Cell_Style"), createCellStyleSettingPane()); - uiTabbedPane.addTab(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Chart_Style"), createChartStyleSettingPane()); - uiTabbedPane.addTab(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Component_Style"), createComponentStyleSettingPane()); - uiTabbedPane.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - valueChangeAction(); - } - }); - titlePane.add(uiTabbedPane); - uiTabbedPane.setPreferredSize(new Dimension(323, 298)); - titlePane.setPreferredSize(new Dimension(333, 320)); - return jPanel; - } - - - private JPanel createTemplateBackgroundSettingPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); - this.backgroundSettingPane = new PredefinedBackgroundSettingPane(); - jPanel.setPreferredSize(new Dimension(309, 248)); - UIScrollPane scrollPane = new UIScrollPane(this.backgroundSettingPane); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - jPanel.add(new UIScrollPane(this.backgroundSettingPane)); - return jPanel; - } - - private JPanel createCellStyleSettingPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); - this.cellStyleSettingPane = new CellStyleListControlPane(); - this.cellStyleSettingPane.registerAttrChangeListener(new AttributeChangeListener() { - @Override - public void attributeChange() { - valueChangeAction(); - } - }); - jPanel.add(this.cellStyleSettingPane); - return jPanel; - } - - - private JPanel createChartStyleSettingPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); - this.chartStyleSettingPane = new ChartStyleSettingPane(); - jPanel.add(this.chartStyleSettingPane); - return jPanel; - } - - - private JPanel createComponentStyleSettingPane() { - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.setLayout(new BorderLayout(0, 5)); - jPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); - this.componentStyleSettingPane = new ComponentStyleSettingPane(); - UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_ComponentStyle_Setting_Tip")); - label.setForeground(TIP_COLOR); - jPanel.add(label, BorderLayout.NORTH); - jPanel.add(this.componentStyleSettingPane, BorderLayout.CENTER); - return jPanel; - } - - - public void populate(PredefinedStyle previewObject) { - isPopulating = true; - isLightMode = previewObject.isLightMode(); - styleNameField.setText(previewObject.getStyleName()); - this.backgroundSettingPane.populateBean(previewObject.getPredefinedBackground()); - this.cellStyleSettingPane.populateBean(previewObject.getCellStyleConfig()); - this.componentStyleSettingPane.populateBean(previewObject.getComponentStyle()); - this.colorFillStylePane.populateBean(previewObject.getPredefinedColorStyle()); - this.chartStyleSettingPane.populateBean(previewObject.getPredefinedChartStyle()); - previewPane.refresh(previewObject); - isPopulating = false; - } - - public PredefinedStyle update() { - PredefinedStyle predefinedStyle = new PredefinedStyle(); - predefinedStyle.setLightMode(isLightMode); - predefinedStyle.setStyleName(this.styleNameField.getText()); - PredefinedCellStyleConfig cellStyleConfig = this.cellStyleSettingPane.updateBean(); - predefinedStyle.setCellStyleConfig(cellStyleConfig); - - predefinedStyle.setPredefinedBackground(this.backgroundSettingPane.updateBean()); - predefinedStyle.setComponentStyle(this.componentStyleSettingPane.updateBean()); - - PredefinedColorStyle colorStyle = this.colorFillStylePane.update(); - updateCellStyleByColorStyle(colorStyle, cellStyleConfig); - predefinedStyle.setPredefinedColorStyle(colorStyle); - predefinedStyle.setPredefinedChartStyle(this.chartStyleSettingPane.updateBean()); - return predefinedStyle; - } - - private void updateCellStyleByColorStyle(PredefinedColorStyle colorStyle, PredefinedCellStyleConfig cellStyleConfig) { - PredefinedCellStyle headerStyle = cellStyleConfig.getStyle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); - PredefinedCellStyle highlightStyle = cellStyleConfig.getStyle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); - ColorFillStyle colorFillStyle = colorStyle.getColorFillStyle(); - List colorList = new ArrayList<>(); - if (colorFillStyle == null || colorFillStyle.getColorList().size() == 0){ - ChartPreStyleConfig config = ChartPreStyleConfig.getInstance(); - String defaultName = config.getCurrentStyle(); - ChartColorMatching defaultStyle = (ChartColorMatching) config.getPreStyle(defaultName); - if (defaultStyle != null) { - colorList = defaultStyle.getColorList(); - } - } else { - colorList = colorFillStyle.getColorList(); - } - if (colorList.size() < 2) { - return; - } - if (headerStyle != null) { - Style style = headerStyle.getStyle(); - Color color = colorList.get(0); - headerStyle.setStyle(style.deriveBackground(ColorBackground.getInstance(color))); - } - if (highlightStyle != null) { - Style style = highlightStyle.getStyle(); - Color color = colorList.get(1); - FRFont font = style.getFRFont(); - font.setForeground(color); - highlightStyle.setStyle(style.deriveFRFont(font)); - } - } - - public boolean saveStyle() { - PredefinedStyle previewObject; - try { - previewObject = update(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - return false; - } - if (this.styleNameField.isEnabled() && !validateRepeat(previewObject.getStyleName())) { - return false; - } - if (!saveStyle(previewObject)) { - return false; - } - HistoryTemplateListCache.getInstance().repaintCurrentEditingTemplate(); - return true; - } - - private boolean saveStyle(PredefinedStyle previewObject) { - PredefinedStyleConfig config = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig(); - if (StringUtils.isEmpty(previewObject.getStyleName())) { - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(PredefinedStyleEditPane.this), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Name_Cannot_Empty")); - - return false; - } - config.add(previewObject); - PredefinedStyleConfig sortedConfig = resortConfigStyles(previewObject, config); -// Configurations.modify(new WorkerFacade(ServerPreferenceConfig.class) { -// @Override -// public void run() { -// ServerPreferenceConfig.getInstance().setPreferenceStyleConfig(sortedConfig); -// } -// }); - selectPane.refreshPane(); - return true; - } - - public void saveAsNewStyle(String styleName) { - PredefinedStyle previewObject; - try { - previewObject = update(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - return; - } - previewObject.setStyleName(styleName); - if (validateRepeat(styleName)) { - saveStyle(previewObject); - } - } - - private boolean validateRepeat(String styleName) { - PredefinedStyleConfig config = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig(); - if (config.getStyle(styleName) != null) { - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(PredefinedStyleEditPane.this), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Name_Repeat")); - - return false; - } - return true; - } - - private PredefinedStyleConfig resortConfigStyles(PredefinedStyle priorityStyle, PredefinedStyleConfig config){ - PredefinedStyleConfig sortedConfig = new PredefinedStyleConfig(); - PredefinedStyle defaultStyle = config.getDefaultPredefinedStyle(); - if (defaultStyle != null) { - sortedConfig.add(defaultStyle); - config.removeStyle(defaultStyle.getStyleName()); - sortedConfig.setDefaultPredefinedStyle(defaultStyle.getStyleName()); - } - if (priorityStyle != null && !priorityStyle.isDefaultStyle()) { - sortedConfig.add(priorityStyle); - config.removeStyle(priorityStyle.getStyleName()); - } - Iterator iterator = config.getPredefinedStyleIterator(); - while (iterator.hasNext()) { - PredefinedStyle entry = iterator.next(); - sortedConfig.add(entry); - } - sortedConfig.setCompatibleStyleName(config.getCompatibleStyleName()); - return sortedConfig; - } - - - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSelectPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSelectPane.java deleted file mode 100644 index 227c9e30d0..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSelectPane.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - -import com.fr.config.ServerPreferenceConfig; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.dialog.BasicPane; -import com.fr.design.event.ChangeListener; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.layout.FRGUIPaneFactory; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import java.util.Iterator; -import java.awt.BorderLayout; -import java.awt.Dimension; - -/** - * Created by kerry on 2020-08-26 - */ -public class PredefinedStyleSelectPane extends BasicPane { - private PredefinedStyleBlock selectedBlock; - private boolean editable; - private JPanel contentPane; - private String currentApplicateStyle; - private ChangeListener changeListener; - - - public PredefinedStyleSelectPane(String currentApplicateStyle, boolean editable) { - this.editable = editable; - this.currentApplicateStyle = currentApplicateStyle; - initPane(); - } - - public void registerChangeListener(ChangeListener changeListener) { - this.changeListener = changeListener; - - } - - - private void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - contentPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(5, 8); - createContentPane(); - UIScrollPane scrollPane = new UIScrollPane(contentPane); - scrollPane.setPreferredSize(new Dimension(630, 480)); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - this.add(scrollPane, BorderLayout.CENTER); - } - - - public void createContentPane() { - contentPane.removeAll(); - Iterator iterator = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig().getPredefinedStyleIterator(); - int rowCount = (ServerPreferenceConfig.getInstance().getPreferenceStyleConfig().getPredefinedSize() +2)/ 3; - contentPane.setPreferredSize(new Dimension(618, 220 * rowCount)); - while (iterator.hasNext()) { - PredefinedStyle tmpStyle = iterator.next(); - - if (tmpStyle != null) { - PredefinedStyleBlock tmpPanel = - new PredefinedStyleBlock(tmpStyle, this, this.editable); - contentPane.add(tmpPanel); - } - } - } - - - public String getCurrentApplicateStyle() { - return currentApplicateStyle; - } - - public void refreshPane() { - createContentPane(); - this.validate(); - this.repaint(); - } - - @Override - protected String title4PopupWindow() { - return null; - } - - public void setSelectedPreviewPane(PredefinedStyleBlock selectedPreviewPane) { - this.selectedBlock = selectedPreviewPane; - if (changeListener != null) { - changeListener.fireChanged(null); - } - this.repaint(); - } - - public PredefinedStyleBlock getSelectedPreviewPane() { - return selectedBlock; - } - - public PredefinedStyle update() { - if (this.selectedBlock == null){ - return null; - } - return this.selectedBlock.update(); - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSettingPane.java deleted file mode 100644 index bd849414fe..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/PredefinedStyleSettingPane.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - -import com.fr.config.predefined.PredefinedNameStyleProvider; -import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; -import com.fr.design.gui.frpane.AttributeChangeListener; -import com.fr.design.gui.ibutton.UIRadioButton; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.JTemplate; -import com.fr.design.mainframe.predefined.ui.preview.StyleSettingPreviewPane; -import javax.swing.ButtonGroup; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * Created by kerry on 2020-09-02 - */ -public abstract class PredefinedStyleSettingPane extends AbstractAttrNoScrollPane { - protected StyleSettingPreviewPane previewPane; - protected UIRadioButton predefinedRadioBtn; - private UIRadioButton customRadioBtn; - private JPanel customDetailPane; - private JPanel predefinedSettingPane; - private CardLayout tabbedPane; - private JPanel center; - private boolean isPopulating = false; - - - public void setPopulating(boolean populating) { - isPopulating = populating; - } - - protected void initContentPane() { - leftContentPane = createContentPane(); - this.add(leftContentPane, BorderLayout.CENTER); - } - - @Override - protected JPanel createContentPane() { - JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - previewPane = createPreviewPane(); - JPanel previewTitlePane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview")); - if (previewPane != null) { - previewTitlePane.setPreferredSize(new Dimension(407, 527)); - previewTitlePane.add(previewPane); - contentPane.add(previewTitlePane, BorderLayout.WEST); - } - - customDetailPane = createCustomDetailPane(); - predefinedSettingPane = createPredefinedSettingPane(); - - JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel jPanel = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(10, 20, 10); - jPanel.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Style"))); - predefinedRadioBtn = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preference_Predefined")); - customRadioBtn = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Custom")); - - tabbedPane = new CardLayout(); - center = new JPanel(tabbedPane); - center.add(predefinedSettingPane, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preference_Predefined")); - center.add(customDetailPane, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Custom")); - predefinedRadioBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - populateCustomPane(); - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preference_Predefined")); - } - }); - customRadioBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Custom")); - } - }); - jPanel.add(predefinedRadioBtn); - jPanel.add(customRadioBtn); - - ButtonGroup layoutBG = new ButtonGroup(); - layoutBG.add(predefinedRadioBtn); - layoutBG.add(customRadioBtn); - centerPane.add(jPanel, BorderLayout.NORTH); - centerPane.add(center, BorderLayout.CENTER); - contentPane.add(centerPane, BorderLayout.CENTER); - this.addAttributeChangeListener(new AttributeChangeListener() { - @Override - public void attributeChange() { - if (isPopulating) { - return; - } - if (previewPane != null) { - previewPane.refresh(); - } - } - }); - return contentPane; - } - - - protected abstract StyleSettingPreviewPane createPreviewPane(); - - protected abstract JPanel createCustomDetailPane(); - - protected JPanel createPredefinedSettingPane() { - return new JPanel(); - } - - protected void populate(PredefinedNameStyleProvider nameStyle) { - this.predefinedRadioBtn.setSelected(nameStyle.usePredefinedStyle()); - this.customRadioBtn.setSelected(!nameStyle.usePredefinedStyle()); - if (nameStyle.usePredefinedStyle()) { - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preference_Predefined")); - } else { - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Custom")); - } - - } - - protected String getPredefinedStyleName() { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - return template.getTemplatePredefinedStyle(); - } - - - /** - * 用于在切换到预定义样式后重置自定义样式的设置 - */ - protected abstract void populateCustomPane(); - - - /** - * 展示数据 - * - * @param ob 待展示的对象 - */ - public abstract void populateBean(T ob); - - /** - * 保存数据 - * - * @return 待保存的对象 - */ - public abstract T updateBean(); - - /** - * 保存数据 - * - * @param ob 待保存的对象 - */ - public void updateBean(T ob) { - - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ReportPredefinedStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ReportPredefinedStylePane.java deleted file mode 100644 index b29e7ffdf9..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ReportPredefinedStylePane.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.dialog.BasicPane; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.JTemplate; - -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.FlowLayout; - -/** - * Created by kerry on 2020-08-28 - */ -public class ReportPredefinedStylePane extends BasicPane { - private PredefinedStyleSelectPane selectPane; - private JTemplate currentTemplate; - - public ReportPredefinedStylePane(JTemplate jTemplate) { - this.currentTemplate = jTemplate; - initPane(); - } - - private void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel jPanel = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Select")); - jPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); - JPanel subPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - this.selectPane = new PredefinedStyleSelectPane(currentTemplate.getTemplatePredefinedStyle(), false); - subPanel.add(this.selectPane, BorderLayout.CENTER); - jPanel.add(subPanel, BorderLayout.CENTER); - this.add(jPanel, BorderLayout.CENTER); - } - - public void update() { - PredefinedStyle style = selectPane.update(); - if (style != null) { -// currentTemplate.resetPredefinedStyle(style.getStyleName()); - } - } - - public void refresh() { - this.selectPane.refreshPane(); - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Template_Style"); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ServerPredefinedStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ServerPredefinedStylePane.java deleted file mode 100644 index cc0cbf15fd..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/ServerPredefinedStylePane.java +++ /dev/null @@ -1,218 +0,0 @@ -package com.fr.design.mainframe.predefined.ui; - - -import com.fr.base.BaseUtils; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.config.predefined.PredefinedStyleConfig; -import com.fr.config.ServerPreferenceConfig; -import com.fr.design.actions.UpdateAction; -import com.fr.design.event.ChangeEvent; -import com.fr.design.event.ChangeListener; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.mainframe.predefined.PatternStyle; -import com.fr.design.dialog.BasicPane; -import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.gui.itoolbar.UIToolbar; -import com.fr.design.i18n.Toolkit; -import com.fr.design.icon.IconPathConstants; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.dialog.PredefinedStyleEditDialog; -import com.fr.design.menu.MenuDef; -import com.fr.design.menu.ToolBarDef; -import com.fr.design.utils.DesignUtils; -import com.fr.stable.StringUtils; -import com.fr.transaction.Configurations; -import com.fr.transaction.WorkerFacade; - -import javax.swing.BorderFactory; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSeparator; -import javax.swing.SwingUtilities; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -/** - * Created by kerry on 2020-08-25 - */ -public class ServerPredefinedStylePane extends BasicPane { - - private static final Color TIP_COLOR = Color.decode("#8F8F92"); - private RemoveAction removeAction; - - private PredefinedStyleSelectPane selectPane; - - - public ServerPredefinedStylePane() { - initPane(); - } - - private void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel jPanel = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Manager")); - jPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); - jPanel.setLayout(FRGUIPaneFactory.createLeftZeroLayout()); - JPanel subPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - subPanel.add(createControlPane(), BorderLayout.NORTH); - PredefinedStyle style = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig().getDefaultPredefinedStyle(); - - this.selectPane = new PredefinedStyleSelectPane(style == null ? StringUtils.EMPTY : style.getStyleName(), true); - this.selectPane.registerChangeListener(new ChangeListener() { - @Override - public void fireChanged(ChangeEvent event) { - PredefinedStyle selectStyle = selectPane.getSelectedPreviewPane().update(); - removeAction.setEnabled(!selectStyle.isBuiltIn()); - } - }); - this.selectPane.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - if (selectPane.getSelectedPreviewPane() != null) { - removeAction.setEnabled(true); - } - } - - @Override - public void mousePressed(MouseEvent e) { - - } - - @Override - public void mouseReleased(MouseEvent e) { - - } - - @Override - public void mouseEntered(MouseEvent e) { - - } - - @Override - public void mouseExited(MouseEvent e) { - - } - }); - JSeparator jSeparator = new JSeparator(); - subPanel.add(jSeparator, BorderLayout.CENTER); - subPanel.add(this.selectPane, BorderLayout.SOUTH); - jPanel.add(subPanel); - this.add(jPanel, BorderLayout.CENTER); - this.repaint(); - } - - - private JPanel createControlPane() { - MenuDef addMenuDef = new MenuDef(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Action_Add")); - addMenuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH); - createAddMenuDef(addMenuDef); - ToolBarDef toolbarDef = new ToolBarDef(); - removeAction = new RemoveAction(); - removeAction.setEnabled(false); - toolbarDef.addShortCut(addMenuDef, removeAction); - UIToolbar toolBar = ToolBarDef.createJToolBar(); - toolBar.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); - toolbarDef.updateToolBar(toolBar); - JPanel toolbarPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - toolbarPane.add(toolBar, BorderLayout.CENTER); - UILabel tipLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Manager_Tip")); - tipLabel.setForeground(TIP_COLOR); - tipLabel.setHorizontalTextPosition(UILabel.RIGHT); - toolbarPane.add(tipLabel, BorderLayout.EAST); - toolbarPane.setPreferredSize(new Dimension(620, 30)); - return toolbarPane; - } - - private void createAddMenuDef(MenuDef addMenuDef) { - addMenuDef.setRePaint(true); - addMenuDef.addShortCut(new CreateStyleAction(PatternStyle.DARK_STYLE)); - addMenuDef.addShortCut(new CreateStyleAction(PatternStyle.LIGHT_STYLE)); - - } - - - public void update() { - PredefinedStyle style = selectPane.update(); - if (style != null) { - PredefinedStyleConfig config = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig(); - config.setDefaultPredefinedStyle(style.getStyleName()); -// Configurations.modify(new WorkerFacade(ServerPreferenceConfig.class) { -// @Override -// public void run() { -// ServerPreferenceConfig.getInstance().setPreferenceStyleConfig(config); -// } -// }); - } - - } - - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Server_Style"); - } - - private class RemoveAction extends UpdateAction { - - public RemoveAction() { - this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove")); - this.setMnemonic('R'); - this.setSmallIcon(BaseUtils.readIcon(IconPathConstants.TD_REMOVE_ICON_PATH)); - } - - @Override - public void actionPerformed(ActionEvent e) { - PredefinedStyle previewObject = ServerPredefinedStylePane.this.selectPane.update(); - int selVal = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(ServerPredefinedStylePane.this), - Toolkit.i18nText("Fine-Design_Predefined_Remove_Style_Confirm", previewObject.getStyleName()), - Toolkit.i18nText("Fine-Design_Basic_Delete"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (selVal == JOptionPane.YES_OPTION) { - removeStyle(previewObject.getStyleName()); - ServerPredefinedStylePane.this.selectPane.refreshPane(); - } - } - } - - - private class CreateStyleAction extends UpdateAction { - private PatternStyle style; - - public CreateStyleAction(PatternStyle style) { - this.style = style; - this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Create_Parttern_Style") + style.getName()); - this.setMnemonic('R'); - } - - @Override - public void actionPerformed(ActionEvent e) { - createNewPatternStylePane(); - } - - private void createNewPatternStylePane() { - PredefinedStyleEditPane editPane = PredefinedStyleEditPane.createNewEditPane(selectPane); - PredefinedStyleEditDialog editDialog = new PredefinedStyleEditDialog( - SwingUtilities.getWindowAncestor(ServerPredefinedStylePane.this), editPane); - PredefinedStyle predefinedStyle = style.getPredefinedStyle(); - predefinedStyle.setStyleName(StringUtils.EMPTY); - editPane.populate(predefinedStyle); - editDialog.setVisible(true); - } - } - - - private void removeStyle(String name) { - PredefinedStyleConfig config = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig(); - config.removeStyle(name); -// Configurations.modify(new WorkerFacade(ServerPreferenceConfig.class) { -// @Override -// public void run() { -// ServerPreferenceConfig.getInstance().setPreferenceStyleConfig(config); -// } -// }); - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/CellStyleListControlPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/CellStyleListControlPane.java deleted file mode 100644 index 3c966c3c49..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/CellStyleListControlPane.java +++ /dev/null @@ -1,308 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail; - -import com.fr.base.BaseUtils; -import com.fr.base.Style; -import com.fr.config.predefined.PredefinedCellStyle; -import com.fr.config.predefined.PredefinedCellStyleConfig; -import com.fr.design.actions.UpdateAction; -import com.fr.design.beans.BasicBeanPane; -import com.fr.design.dialog.BasicPane; -import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.gui.NameInspector; -import com.fr.design.gui.controlpane.JListControlPane; -import com.fr.design.gui.controlpane.NameObjectCreator; -import com.fr.design.gui.controlpane.NameableCreator; -import com.fr.design.gui.controlpane.ShortCut4JControlPane; -import com.fr.design.gui.controlpane.UnrepeatedNameHelper; -import com.fr.design.gui.frpane.AttributeChangeListener; -import com.fr.design.gui.ilist.ListModelElement; -import com.fr.design.gui.ilist.ModNameActionListener; -import com.fr.design.gui.style.AlignmentPane; -import com.fr.design.gui.style.FormatPane; -import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.detail.cell.CustomPredefinedStylePane; -import com.fr.design.menu.ShortCut; -import com.fr.general.ComparatorUtils; -import com.fr.general.NameObject; -import com.fr.invoke.Reflect; -import com.fr.log.FineLoggerFactory; -import com.fr.stable.Nameable; -import com.fr.stable.StringUtils; - -import javax.swing.BorderFactory; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSeparator; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -/** - * Created by kerry on 2020-09-27 - */ -public class CellStyleListControlPane extends JListControlPane { - private boolean namePermitted = true; - private AttributeChangeListener attributeChangeListener; - - - - public CellStyleListControlPane() { - super(); - this.addModNameActionListener(new ModNameActionListener() { - public void nameModed(int index, String oldName, String newName) { - if (ComparatorUtils.equals(oldName, newName) || ComparatorUtils.equals(newName, NameInspector.ILLEGAL_NAME_HOLDER)) { - return; - } - namePermitted = true; - String[] allNames = nameableList.getAllNames(); - allNames[index] = StringUtils.EMPTY; - if (StringUtils.isEmpty(newName)) { - showTipDialogAndReset(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Empty_Name"), index); - return; - } - if (isNameRepeated(new List[]{Arrays.asList(allNames)}, newName)) { - showTipDialogAndReset(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Duplicate_Name", newName), index); - return; - } - populateSelectedValue(); - } - }); - } - - - - public void registerAttrChangeListener(AttributeChangeListener listener){ - this.attributeChangeListener = listener; - } - - - private void showTipDialogAndReset(String content, int index) { - nameableList.stopEditing(); - - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(CellStyleListControlPane.this), - content, - Toolkit.i18nText("Fine-Design_Basic_Alert"), - JOptionPane.WARNING_MESSAGE); - setIllegalIndex(index); - namePermitted = false; - } - - @Override - public NameableCreator[] createNameableCreators() { - return new NameableCreator[]{ - new CellStyleNameObjectCreator(Toolkit.i18nText("Fine-Design_Predefined_Cell_New_Style"), - PredefinedCellStyle.class, CustomPredefinedStylePaneNoBorder.class) { - @Override - public boolean acceptDefaultNameObject(Object ob) { - return ((PredefinedCellStyle) ob).isDefaultStyle(); - } - }, - new CellStyleNameObjectCreator(Toolkit.i18nText("Fine-Design_Predefined_Cell_New_Style"), - PredefinedCellStyle.class, CustomPredefinedStylePane.class)}; - } - - @Override - public BasicBeanPane createPaneByCreators(NameableCreator creator) { - CustomPredefinedStylePane stylePane = (CustomPredefinedStylePane) super.createPaneByCreators(creator); - stylePane.registerAttrChangeListener(attributeChangeListener); - return stylePane; - } - - - - @Override - protected String title4PopupWindow() { - return StringUtils.EMPTY; - } - - protected void initComponentPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.setCreators(this.createNameableCreators()); - initCardPane(); - JPanel leftPane = getLeftPane(); - JSeparator jSeparator = new JSeparator(SwingConstants.VERTICAL); - leftPane.setPreferredSize(new Dimension(70, 0)); - jSeparator.setPreferredSize(new Dimension(2, 0)); - cardPane.setPreferredSize(new Dimension(238, 0)); - cardPane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); - JPanel mainSplitPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - mainSplitPane.add(leftPane, BorderLayout.WEST); - mainSplitPane.add(jSeparator, BorderLayout.CENTER); - mainSplitPane.add(cardPane, BorderLayout.EAST); - - this.add(mainSplitPane, BorderLayout.CENTER); - this.checkButtonEnabled(); - } - - protected ShortCut4JControlPane[] createShortcuts() { - return new ShortCut4JControlPane[]{ - createAddItemShortCut4JControlPane(), - new RemoveItemShortCut4JControlPane(new RemoveItemAction()) - }; - } - - - private static class CustomPredefinedStylePaneNoBorder extends CustomPredefinedStylePane { - @Override - protected List initPaneList() { - paneList = new ArrayList(); - paneList.add(new FormatPane()); - paneList.add(new AlignmentPane()); - return paneList; - } - - } - - - private ShortCut4JControlPane createAddItemShortCut4JControlPane (){ - ShortCut shortCut = shortCutFactory.createAddItemUpdateAction(new NameableCreator[]{ - new CellStyleNameObjectCreator(Toolkit.i18nText("Fine-Design_Predefined_Cell_New_Style"), - PredefinedCellStyle.class, CustomPredefinedStylePane.class)}); - return new AddItemShortCut4JControlPane(shortCut); - } - - private class AddItemShortCut4JControlPane extends ShortCut4JControlPane{ - AddItemShortCut4JControlPane(ShortCut shortCut) { - this.shortCut = shortCut; - } - - - @Override - public void checkEnable() { - this.shortCut.setEnabled(true); - } - } - - - private class RemoveItemShortCut4JControlPane extends ShortCut4JControlPane { - RemoveItemShortCut4JControlPane(ShortCut shortCut) { - this.shortCut = shortCut; - } - - @Override - public void checkEnable() { - ListModelElement selectModel = CellStyleListControlPane.this.getSelectedValue(); - if (selectModel != null) { - NameObject selectNameObject = (NameObject) selectModel.wrapper; - PredefinedCellStyle cellStyle = (PredefinedCellStyle) (selectNameObject.getObject()); - this.shortCut.setEnabled(!cellStyle.isBuiltIn() && !cellStyle.isDefaultStyle()); - } else { - this.shortCut.setEnabled(false); - } - - } - } - - - private class RemoveItemAction extends UpdateAction { - RemoveItemAction() { - this.setName(com.fr.design.i18n.Toolkit.i18nText(("Fine-Design_Basic_Action_Remove"))); - this.setMnemonic('R'); - this.setSmallIcon(BaseUtils - .readIcon("/com/fr/base/images/cell/control/remove.png")); - } - - @Override - public void actionPerformed(ActionEvent evt) { - CellStyleListControlPane.this.onRemoveItem(); - } - } - - - class CellStyleNameObjectCreator extends NameObjectCreator { - public CellStyleNameObjectCreator(String menuName, Class clazz, Class updatePane) { - super(menuName, clazz, updatePane); - } - - public Nameable createNameable(UnrepeatedNameHelper helper) { - Constructor constructor = null; - try { - constructor = clazzOfInitCase.getConstructor(); - PredefinedCellStyle cellStyle = constructor.newInstance(); - - cellStyle.setName(menuName); - cellStyle.setStyle(Style.getInstance()); - return new NameObject(helper.createUnrepeatedName(this.menuName()), cellStyle); - - } catch (NoSuchMethodException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } catch (IllegalAccessException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } catch (InstantiationException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } catch (InvocationTargetException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return null; - } - /** - * - * @param ob - * @return - */ - public Object acceptObject2Populate(Object ob) { - if (ob instanceof NameObject) { - ob = ((NameObject) ob).getObject(); - } - if (clazzOfObject != null && clazzOfObject.isInstance(ob) && acceptDefaultNameObject(ob)) { - doSthChanged4Icon(ob); - return ob; - } - return null; - } - - public boolean acceptDefaultNameObject(Object ob) { - return !((PredefinedCellStyle) ob).isDefaultStyle(); - } - } - - - /** - * Populate - */ - public void populateBean(PredefinedCellStyleConfig ob) { - if (ob == null) { - return; - } - - List nameStyleList = new ArrayList(); - - Iterator styleNameIterator = ob.getStyleNameIterator(); - while (styleNameIterator.hasNext()) { - String name = (String) styleNameIterator.next(); - PredefinedCellStyle tmpStyle = ob.getStyle(name); - - if (tmpStyle != null) { - nameStyleList.add(new NameObject(name, tmpStyle)); - } - } - - NameObject[] nameObjects = new NameObject[nameStyleList.size()]; - nameStyleList.toArray(nameObjects); - - populate(nameObjects); - } - - - public PredefinedCellStyleConfig updateBean() { - Nameable[] nameables = this.update(); - PredefinedCellStyleConfig styleConfig = new PredefinedCellStyleConfig(); - for (int i = 0; i < nameables.length; i++) { - PredefinedCellStyle tmpStyle = (PredefinedCellStyle) ((NameObject) nameables[i]).getObject(); - tmpStyle.setName(nameables[i].getName()); - styleConfig.addStyle(tmpStyle); - } - return styleConfig; - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ChartStyleSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ChartStyleSettingPane.java deleted file mode 100644 index 6eb155eb6d..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ChartStyleSettingPane.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.dialog.BasicPane; -import com.fr.design.dialog.MultiTabPane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartAxisStylePane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartBackgroundStylePane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartDataSheetStylePane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartLabelStylePane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartLegendStylePane; -import com.fr.design.mainframe.predefined.ui.detail.chart.ChartTitleStylePane; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartStyleSettingPane extends MultiTabPane { - - private ChartTitleStylePane chartTitleStylePane; - private ChartLegendStylePane chartLegendStylePane; - private ChartLabelStylePane chartLabelPane; - private ChartAxisStylePane chartAxisStylePane; - private ChartDataSheetStylePane chartDataSheetStylePane; - private ChartBackgroundStylePane chartBackgroundStylePane; - - public ChartStyleSettingPane() { - } - - @Override - protected void initLayout() { - super.initLayout(); - } - - @Override - protected List initPaneList() { - this.chartTitleStylePane = new ChartTitleStylePane(); - this.chartLegendStylePane = new ChartLegendStylePane(); - this.chartLabelPane = new ChartLabelStylePane(); - this.chartAxisStylePane = new ChartAxisStylePane(); - this.chartDataSheetStylePane = new ChartDataSheetStylePane(); - this.chartBackgroundStylePane = new ChartBackgroundStylePane(); - paneList = new ArrayList<>(); - paneList.add(this.chartTitleStylePane); - paneList.add(this.chartLegendStylePane); - paneList.add(this.chartLabelPane); - paneList.add(this.chartAxisStylePane); - paneList.add(this.chartDataSheetStylePane); - paneList.add(this.chartBackgroundStylePane); - return paneList; - } - - @Override - public void populateBean(PredefinedChartStyle ob) { - chartTitleStylePane.populate(ob); - chartLegendStylePane.populate(ob); - chartLabelPane.populate(ob); - chartAxisStylePane.populate(ob); - chartDataSheetStylePane.populate(ob); - chartBackgroundStylePane.populate(ob); - } - - @Override - public void updateBean(PredefinedChartStyle ob) { - - } - - - @Override - public PredefinedChartStyle updateBean() { - PredefinedChartStyle chartStyle = new PredefinedChartStyle(); - chartTitleStylePane.update(chartStyle); - chartLegendStylePane.update(chartStyle); - chartLabelPane.update(chartStyle); - chartAxisStylePane.update(chartStyle); - chartDataSheetStylePane.update(chartStyle); - chartBackgroundStylePane.update(chartStyle); - return chartStyle; - } - - - @Override - public boolean accept(Object ob) { - return false; - } - - @Override - public void reset() { - - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ComponentStyleSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ComponentStyleSettingPane.java deleted file mode 100644 index e2d306933c..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/ComponentStyleSettingPane.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail; - -import com.fr.config.predefined.PredefinedComponentStyle; -import com.fr.design.dialog.BasicPane; -import com.fr.design.dialog.MultiTabPane; -import com.fr.design.mainframe.predefined.ui.detail.component.ComponentFrameStylePane; -import com.fr.design.mainframe.predefined.ui.detail.component.ComponentTitleStylePane; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by kerry on 2020-09-01 - */ -public class ComponentStyleSettingPane extends MultiTabPane { - private ComponentFrameStylePane frameStylePane; - private ComponentTitleStylePane titleStylePane; - - public ComponentStyleSettingPane() { - } - - - @Override - protected List initPaneList() { - this.frameStylePane = new ComponentFrameStylePane(); - this.titleStylePane = ComponentTitleStylePane.createPredefinedSettingPane(); - paneList = new ArrayList(); - paneList.add(this.frameStylePane); - paneList.add(this.titleStylePane); - return paneList; - } - - @Override - public void populateBean(PredefinedComponentStyle ob) { - this.frameStylePane.populate(ob); - this.titleStylePane.populate(ob); - } - - @Override - public void updateBean(PredefinedComponentStyle ob) { - - } - - - @Override - public PredefinedComponentStyle updateBean() { - PredefinedComponentStyle componentStyle = new PredefinedComponentStyle(); - this.frameStylePane.update(componentStyle); - this.titleStylePane.update(componentStyle); - return componentStyle; - } - - - @Override - public boolean accept(Object ob) { - return false; - } - - @Override - public void reset() { - - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/PredefinedBackgroundSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/PredefinedBackgroundSettingPane.java deleted file mode 100644 index 05b02a5645..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/PredefinedBackgroundSettingPane.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail; - -import com.fr.config.predefined.PredefinedBackground; -import com.fr.design.beans.BasicBeanPane; -import com.fr.design.gui.ibutton.UIButtonGroup; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.detail.background.BackgroundSettingPane; -import com.fr.design.mainframe.predefined.ui.detail.background.BackgroundWithAlphaSettingPane; - -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * Created by kerry on 2020-08-31 - */ -public class PredefinedBackgroundSettingPane extends BasicBeanPane { - private UIButtonGroup buttonGroup; - private BackgroundSettingPane reportBackgroundSettingPane; - private BackgroundWithAlphaSettingPane formBackgroundSettingPane; - - - public PredefinedBackgroundSettingPane() { - initPane(); - } - - private void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - reportBackgroundSettingPane = new BackgroundSettingPane(); - formBackgroundSettingPane = new BackgroundWithAlphaSettingPane(); - CardLayout tabbedPane = new CardLayout(); - JPanel center = new JPanel(tabbedPane); - center.add(reportBackgroundSettingPane, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plain_Report")); - center.add(formBackgroundSettingPane, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Decision_Report")); - this.buttonGroup = new UIButtonGroup(new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plain_Report"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Decision_Report")}); - buttonGroup.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (buttonGroup.getSelectedIndex() == 0) { - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plain_Report")); - } else { - tabbedPane.show(center, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Decision_Report")); - } - } - }); - - - this.add(buttonGroup, BorderLayout.NORTH); - - this.add(center, BorderLayout.CENTER); - this.buttonGroup.setSelectedIndex(0); - } - - public boolean currentFormBackground() { - return buttonGroup.getSelectedIndex() == 1; - } - - @Override - public void populateBean(PredefinedBackground predefinedBackground) { - reportBackgroundSettingPane.populateBean(predefinedBackground.getReportBackground()); - formBackgroundSettingPane.populateBean(predefinedBackground.getFormBackground()); - } - - @Override - public PredefinedBackground updateBean() { - PredefinedBackground predefinedBackground = new PredefinedBackground(); - predefinedBackground.setReportBackground(reportBackgroundSettingPane.updateBean()); - predefinedBackground.setFormBackground(formBackgroundSettingPane.updateBean()); - return predefinedBackground; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Background_Setting"); - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/AbstractBackgroundDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/AbstractBackgroundDetailPane.java deleted file mode 100644 index 7cc1629bfa..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/AbstractBackgroundDetailPane.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.design.event.UIObserverListener; -import com.fr.design.mainframe.backgroundpane.BackgroundQuickPane; -import com.fr.general.Background; - -import javax.swing.event.ChangeListener; - -/** - * Created by kerry on 2020-09-14 - */ -public abstract class AbstractBackgroundDetailPane extends BackgroundQuickPane { - @Override - public boolean accept(Background background) { - return false; - } - - @Override - public void populateBean(Background background) { - this.populate((T) background); - } - - @Override - public Background updateBean() { - return this.update(); - } - - @Override - public String title4PopupWindow() { - return null; - } - - @Override - public void reset() { - - } - - @Override - public void registerChangeListener(UIObserverListener listener) { - - } - - public abstract void populate(T background); - - public abstract T update(); - - public void addChangeListener(ChangeListener changeListener) { - - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundSettingPane.java deleted file mode 100644 index 3efd0b447e..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundSettingPane.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.design.beans.BasicBeanPane; -import com.fr.design.event.UIObserverListener; -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.TableLayoutHelper; -import com.fr.design.mainframe.backgroundpane.BackgroundQuickPane; -import com.fr.general.Background; -import com.fr.log.FineLoggerFactory; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.ArrayList; - -/** - * Created by kerry on 2020-09-02 - */ -public class BackgroundSettingPane extends BasicBeanPane { - private ChangeListener changeListener = null; - private UIComboBox headCombobox; - private BackgroundQuickPane[] paneList; - - public BackgroundSettingPane() { - init(); - } - - private void init() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.add(createComboHeadPane(), BorderLayout.NORTH); - CardLayout cardlayout = new CardLayout(); - paneList = supportKindsOfBackgroundUI(); - final JPanel centerPane = new JPanel(cardlayout) { - @Override - public Dimension getPreferredSize() {// AUGUST:使用当前面板的的高度 - int index = headCombobox.getSelectedIndex(); - return new Dimension(super.getPreferredSize().width, paneList[index].getPreferredSize().height); - } - }; - centerPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); - for (BackgroundQuickPane pane : paneList) { - headCombobox.addItem(pane.title4PopupWindow()); - centerPane.add(pane, pane.title4PopupWindow()); - } - headCombobox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - cardlayout.show(centerPane, (String) headCombobox.getSelectedItem()); - } - }); - this.add(centerPane, BorderLayout.CENTER); - } - - public void addChangeListener(ChangeListener changeListener) { - this.changeListener = changeListener; - } - - - private JPanel createComboHeadPane() { - headCombobox = new UIComboBox(); - - JPanel jPanel = TableLayoutHelper.createGapTableLayoutPane( - new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Fill")), headCombobox}}, - TableLayoutHelper.FILL_NONE, 33, 5); - headCombobox.setPreferredSize(new Dimension(160, 20)); - jPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); - return jPanel; - } - - protected BackgroundQuickPane[] supportKindsOfBackgroundUI() { - java.util.List kinds = new ArrayList<>(); - kinds.add(new EmptyBackgroundPane()); - kinds.add(new ColorDetailPane()); - kinds.add(new TextureDetailObservePane()); - kinds.add(new PatternDetailPane()); - kinds.add(createImageSelectPane()); - kinds.add(new GradientDetailPane()); - return kinds.toArray(new BackgroundQuickPane[kinds.size()]); - } - - protected ImageDetailPane createImageSelectPane() { - ImageDetailPane imageDetailPane = new ImageDetailPane(); - imageDetailPane.registerChangeListener(new UIObserverListener() { - @Override - public void doChange() { - fireChangeListener(); - } - }); - return imageDetailPane; - } - - protected void fireChangeListener() { - if (changeListener != null) { - changeListener.stateChanged(null); - } - } - - - @Override - public void populateBean(Background background) { - for (int i = 0; i < paneList.length; i++) { - BackgroundQuickPane pane = paneList[i]; - if (pane.accept(background)) { - pane.populateBean(background); - headCombobox.setSelectedIndex(i); - return; - } - } - } - - @Override - public Background updateBean() { - int selectIndex = this.headCombobox.getSelectedIndex(); - try { - return paneList[selectIndex].updateBean(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return null; - } - - @Override - protected String title4PopupWindow() { - return null; - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundWithAlphaSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundWithAlphaSettingPane.java deleted file mode 100644 index dba0dce230..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/BackgroundWithAlphaSettingPane.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.config.predefined.BackgroundWithAlpha; -import com.fr.design.beans.BasicBeanPane; -import com.fr.design.designer.IntervalConstants; -import com.fr.design.gui.frpane.UINumberDragPane; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; - -/** - * Created by kerry on 2020-09-04 - */ -public class BackgroundWithAlphaSettingPane extends BasicBeanPane { - private BackgroundSettingPane backgroundSettingPane; - //透明度 - private UINumberDragPane numberDragPane; - - private double maxNumber = 100; - - - public BackgroundWithAlphaSettingPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - backgroundSettingPane = new FormBackgroundSettingPane(); - - JPanel eastpane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(2, 0); - this.numberDragPane = new UINumberDragPane(0, 100); - this.numberDragPane.setPreferredSize(new Dimension(148, 20)); - eastpane.add(numberDragPane); - eastpane.add(new UILabel("%")); - JPanel transparencyPane = TableLayoutHelper.createGapTableLayoutPane( - new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha")), - eastpane}}, TableLayoutHelper.FILL_LASTCOLUMN, 18, 5); - transparencyPane.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); - - - Component[][] components = new Component[][]{ - new Component[]{backgroundSettingPane}, - new Component[]{transparencyPane}}; - - JPanel panel = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_NONE, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); - this.add(panel, BorderLayout.CENTER); - } - - - public void addChangeListener(ChangeListener changeListener) { - this.backgroundSettingPane.addChangeListener(changeListener); - } - - - @Override - public void populateBean(BackgroundWithAlpha ob) { - backgroundSettingPane.populateBean(ob.getBackground()); - numberDragPane.populateBean(ob.getAlpha() * maxNumber); - } - - @Override - public BackgroundWithAlpha updateBean() { - BackgroundWithAlpha backgroundWithAlpha = new BackgroundWithAlpha(); - backgroundWithAlpha.setBackground(backgroundSettingPane.updateBean()); - backgroundWithAlpha.setAlpha((float) (numberDragPane.updateBean() / maxNumber)); - return backgroundWithAlpha; - } - - @Override - protected String title4PopupWindow() { - return null; - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ColorDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ColorDetailPane.java deleted file mode 100644 index 43d20d1bde..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ColorDetailPane.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.base.background.ColorBackground; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.style.color.NewColorSelectPane; -import com.fr.general.Background; -import java.awt.BorderLayout; - -/** - * Created by kerry on 2020-08-31 - */ -public class ColorDetailPane extends AbstractBackgroundDetailPane { - private ColorBackgroundSelectPane selectPane; - - - public ColorDetailPane() { - this.selectPane = new ColorBackgroundSelectPane(); - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.add(this.selectPane, BorderLayout.CENTER); - } - - @Override - public void populate(ColorBackground background) { - this.selectPane.setColor(background.getColor()); - } - - @Override - public ColorBackground update() { - return ColorBackground.getInstance(selectPane.getColor()); - } - - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Color"); - } - - @Override - public boolean accept(Background background) { - return background instanceof ColorBackground; - } - - class ColorBackgroundSelectPane extends NewColorSelectPane implements UIObserver { - protected UIObserverListener uiObserverListener; - - @Override - public void registerChangeListener(UIObserverListener listener) { - this.uiObserverListener = listener; - } - - @Override - public boolean shouldResponseChangeListener() { - return true; - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/EmptyBackgroundPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/EmptyBackgroundPane.java deleted file mode 100644 index 569db10231..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/EmptyBackgroundPane.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.general.Background; - -/** - * Created by kerry on 2020-09-01 - */ -public class EmptyBackgroundPane extends AbstractBackgroundDetailPane { - - @Override - public void populate(Background background) { - - } - - @Override - public Background update() { - return null; - } - - /** - * 名称 - * - * @return 名称 - */ - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Null"); - } - - public boolean accept(Background background) { - return background == null; - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/FormBackgroundSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/FormBackgroundSettingPane.java deleted file mode 100644 index 1a683df5cc..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/FormBackgroundSettingPane.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.design.ExtraDesignClassManager; -import com.fr.design.event.UIObserverListener; -import com.fr.design.fun.BackgroundQuickUIProvider; -import com.fr.design.mainframe.backgroundpane.BackgroundQuickPane; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Created by kerry on 2020-09-14 - */ -public class FormBackgroundSettingPane extends BackgroundSettingPane { - - public FormBackgroundSettingPane() { - super(); - } - - @Override - protected BackgroundQuickPane[] supportKindsOfBackgroundUI() { - ColorDetailPane colorDetailPane = new ColorDetailPane(); - ImageDetailPane imageDetailPane = createImageSelectPane(); - GradientDetailPane gradientPane = new GradientDetailPane(); - //hugh:表单支持背景接口 - List kinds = new ArrayList(); - - kinds.add(new EmptyBackgroundPane()); - kinds.add(colorDetailPane); - kinds.add(imageDetailPane); - kinds.add(gradientPane); - - Set providers = ExtraDesignClassManager.getInstance().getArray(BackgroundQuickUIProvider.MARK_STRING); - for (BackgroundQuickUIProvider provider : providers) { - BackgroundQuickPane newTypePane = provider.appearanceForBackground(); - newTypePane.registerChangeListener(new UIObserverListener() { - @Override - public void doChange() { - fireChangeListener(); - } - }); - kinds.add(newTypePane); - } - - return kinds.toArray(new BackgroundQuickPane[kinds.size()]); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/GradientDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/GradientDetailPane.java deleted file mode 100644 index 74851c38f2..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/GradientDetailPane.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.base.background.GradientBackground; -import com.fr.design.designer.IntervalConstants; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.design.gui.ibutton.UIRadioButton; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.style.background.gradient.GradientBar; -import com.fr.general.Background; - -import javax.swing.ButtonGroup; -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * 渐变色的面板,不是很pp,面板应用显得繁琐,有写可以写成控件类型,比如色彩选择的。。,可以做得花哨点 - * - * @author ben - */ -public class GradientDetailPane extends AbstractBackgroundDetailPane implements UIObserver { - private static final long serialVersionUID = -6854603990673031897L; - private UIObserverListener listener; - private UIRadioButton left2right, top2bottom; - private GradientBar gradientBar; - private ChangeListener changeListener = null; - - public GradientDetailPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - - JPanel gradientPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel blankJp = new JPanel(); - gradientBar = new GradientBar(4, 140); - blankJp.add(gradientBar); - - gradientPanel.add(gradientBar, BorderLayout.SOUTH); - - JPanel jp = new JPanel(new GridLayout(2, 1, 15, 10)); - - - left2right = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Page_Setup_Horizontal")); - jp.add(left2right); - left2right.setSelected(true); - left2right.addActionListener(reviewListener); - - top2bottom = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Page_Setup_Vertical")); - jp.add(top2bottom); - top2bottom.addActionListener(reviewListener); - - ButtonGroup toggle = new ButtonGroup(); - toggle.add(left2right); - toggle.add(top2bottom); - - Component[][] components = new Component[][]{ - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Gradient_Setting")), gradientPanel}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Gradient_Color")), jp} - }; - JPanel contentPane = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_LASTCOLUMN, - IntervalConstants.INTERVAL_W4, IntervalConstants.INTERVAL_L1); - this.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (listener != null) { - listener.doChange(); - } - } - }); - - - this.add(contentPane); - } - - @Override - public boolean accept(Background background) { - return background instanceof GradientBackground; - } - - - - public void populate(GradientBackground bg) { - this.gradientBar.getSelectColorPointBtnP1().setColorInner(bg.getStartColor()); - this.gradientBar.getSelectColorPointBtnP2().setColorInner(bg.getEndColor()); - if (bg.getDirection() == GradientBackground.LEFT2RIGHT) { - left2right.setSelected(true); - } else { - top2bottom.setSelected(true); - } - if (bg.isUseCell()) { - return; - } - double startValue = (double) bg.getBeginPlace(); - double endValue = (double) bg.getFinishPlace(); - gradientBar.setStartValue(startValue); - gradientBar.setEndValue(endValue); - this.gradientBar.repaint(); - } - - public GradientBackground update() { - GradientBackground gb = new GradientBackground( - gradientBar.getSelectColorPointBtnP1().getColorInner(), - gradientBar.getSelectColorPointBtnP2().getColorInner()); - if (left2right.isSelected()) { - gb.setDirection(GradientBackground.LEFT2RIGHT); - } else { - gb.setDirection(GradientBackground.TOP2BOTTOM); - } - if (gradientBar.isOriginalPlace()) { - gb.setUseCell(true); - } else { - gb.setUseCell(false); - gb.setBeginPlace((float) gradientBar.getStartValue()); - gb.setFinishPlace((float) gradientBar.getEndValue()); - } - return gb; - } - - - ActionListener reviewListener = new ActionListener() { - public void actionPerformed(ActionEvent e) { - fireChagneListener(); - } - }; - - public void addChangeListener(ChangeListener changeListener) { - this.changeListener = changeListener; - gradientBar.addChangeListener(changeListener); - } - - public void fireChagneListener() { - if (this.changeListener != null) { - ChangeEvent evt = new ChangeEvent(this); - this.changeListener.stateChanged(evt); - } - } - - @Override - public void registerChangeListener(UIObserverListener listener) { - this.listener = listener; - } - - @Override - public boolean shouldResponseChangeListener() { - return true; - } - - @Override - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Gradient_Color"); - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ImageDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ImageDetailPane.java deleted file mode 100644 index 5873755f57..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/ImageDetailPane.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.base.Style; -import com.fr.base.background.ImageBackground; -import com.fr.base.background.ImageFileBackground; -import com.fr.design.designer.IntervalConstants; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.design.gui.frpane.ImgChooseWrapper; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.ibutton.UIRadioButton; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.style.background.image.ImageFileChooser; -import com.fr.design.style.background.image.ImagePreviewPane; -import com.fr.general.Background; -import com.fr.stable.Constants; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * Image background pane. - */ -public class ImageDetailPane extends AbstractBackgroundDetailPane implements UIObserver { - private UIObserverListener listener; - protected ImagePreviewPane previewPane = null; - private Style imageStyle = null; - private ChangeListener changeListener = null; - private ImageFileChooser imageFileChooser = null; - - private UIRadioButton defaultRadioButton = null; - private UIRadioButton tiledRadioButton = null; - private UIRadioButton extendRadioButton = null; - private UIRadioButton adjustRadioButton = null; - - - public ImageDetailPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.add(initSelectFilePane(), BorderLayout.CENTER); - imageFileChooser = new ImageFileChooser(); - imageFileChooser.setMultiSelectionEnabled(false); - previewPane = new ImagePreviewPane(); - this.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (listener != null) { - listener.doChange(); - } - } - }); - } - - public JPanel initSelectFilePane() { - JPanel selectFilePane = FRGUIPaneFactory.createBorderLayout_L_Pane(); - selectFilePane.setBorder(BorderFactory.createEmptyBorder()); - UIButton selectPictureButton = new UIButton( - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Image_Select")); - selectPictureButton.setMnemonic('S'); - selectPictureButton.addActionListener(selectPictureActionListener); - selectPictureButton.setPreferredSize(new Dimension(160, 20)); - //布局 - defaultRadioButton = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Style_Alignment_Layout_Default")); - tiledRadioButton = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Style_Alignment_Layout_Image_Titled")); - extendRadioButton = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Style_Alignment_Layout_Image_Extend")); - adjustRadioButton = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Style_Alignment_Layout_Image_Adjust")); - - defaultRadioButton.addActionListener(layoutActionListener); - tiledRadioButton.addActionListener(layoutActionListener); - extendRadioButton.addActionListener(layoutActionListener); - adjustRadioButton.addActionListener(layoutActionListener); - - JPanel jp = new JPanel(new GridLayout(4, 1, 15, 10)); - for (UIRadioButton button : imageLayoutButtons()) { - jp.add(button); - } - - ButtonGroup layoutBG = new ButtonGroup(); - layoutBG.add(defaultRadioButton); - layoutBG.add(tiledRadioButton); - layoutBG.add(extendRadioButton); - layoutBG.add(adjustRadioButton); - - defaultRadioButton.setSelected(true); - - Component[][] components = new Component[][]{ - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Image")), selectPictureButton}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Fill_Mode")), jp} - }; - JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_NONE, - IntervalConstants.INTERVAL_L4, IntervalConstants.INTERVAL_L1); - selectFilePane.add(centerPane, BorderLayout.CENTER); - return selectFilePane; - } - - protected UIRadioButton[] imageLayoutButtons() { - return new UIRadioButton[]{ - defaultRadioButton, - tiledRadioButton, - extendRadioButton, - adjustRadioButton - }; - } - - @Override - public boolean accept(Background background) { - return background instanceof ImageBackground; - } - - - /** - * Select picture. - */ - ActionListener selectPictureActionListener = new ActionListener() { - - public void actionPerformed(ActionEvent evt) { - int returnVal = imageFileChooser.showOpenDialog(ImageDetailPane.this); - setImageStyle(); - ImgChooseWrapper.getInstance(previewPane, imageFileChooser, imageStyle, changeListener).dealWithImageFile(returnVal); - } - }; - - protected void setImageStyle() { - if (tiledRadioButton.isSelected()) { - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_TILED); - } else if (adjustRadioButton.isSelected()) { - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_ADJUST); - } else if (extendRadioButton.isSelected()) { - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_EXTEND); - } else { - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_CENTER); - } - } - - ActionListener layoutActionListener = new ActionListener() { - - @Override - public void actionPerformed(ActionEvent evt) { - setImageStyle(); - changeImageStyle(); - } - - private void changeImageStyle() { - previewPane.setImageStyle(ImageDetailPane.this.imageStyle); - previewPane.repaint(); - } - }; - - @Override - public void populate(ImageBackground imageBackground) { - if (imageBackground.getLayout() == Constants.IMAGE_CENTER) { - defaultRadioButton.setSelected(true); - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_CENTER); - } else if (imageBackground.getLayout() == Constants.IMAGE_EXTEND) { - extendRadioButton.setSelected(true); - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_EXTEND); - } else if (imageBackground.getLayout() == Constants.IMAGE_ADJUST) { - adjustRadioButton.setSelected(true); - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_ADJUST); - } else { - tiledRadioButton.setSelected(true); - imageStyle = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_TILED); - } - previewPane.setImageStyle(ImageDetailPane.this.imageStyle); - if (imageBackground.getImage() != null) { - previewPane.setImageWithSuffix(imageBackground.getImageWithSuffix()); - previewPane.setImage(imageBackground.getImage()); - } - - fireChagneListener(); - } - - @Override - public ImageBackground update() { - ImageBackground imageBackground = new ImageFileBackground(previewPane.getImageWithSuffix()); - setImageStyle(); - imageBackground.setLayout(imageStyle.getImageLayout()); - return imageBackground; - } - - @Override - public void addChangeListener(ChangeListener changeListener) { - this.changeListener = changeListener; - } - - private void fireChagneListener() { - if (this.changeListener != null) { - ChangeEvent evt = new ChangeEvent(this); - this.changeListener.stateChanged(evt); - } - } - - @Override - public void registerChangeListener(UIObserverListener listener) { - this.listener = listener; - } - - - @Override - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Image"); - } - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/PatternDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/PatternDetailPane.java deleted file mode 100644 index 05667021c6..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/PatternDetailPane.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.base.background.PatternBackground; -import com.fr.design.designer.IntervalConstants; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.style.background.impl.PatternBackgroundPane; -import com.fr.design.style.color.ColorSelectBox; -import com.fr.general.Background; -import com.fr.log.FineLoggerFactory; - -import javax.swing.BorderFactory; -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; -import java.awt.GridLayout; -import java.awt.LayoutManager; - -/** - * Created by kerry on 2020-08-31 - */ -public class PatternDetailPane extends AbstractBackgroundDetailPane implements UIObserver { - - private UIObserverListener listener; - private PatternNewBackgroundPane patternNewBackgroundPane; - - public PatternDetailPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - patternNewBackgroundPane = new PatternNewBackgroundPane(6); - this.add(patternNewBackgroundPane, BorderLayout.CENTER); - } - - @Override - public void registerChangeListener(UIObserverListener listener) { - this.listener = listener; - } - - @Override - public void populate(PatternBackground background) { - this.patternNewBackgroundPane.populate(background); - } - - @Override - public PatternBackground update() { - try { - return (PatternBackground) this.patternNewBackgroundPane.update(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return null; - } - @Override - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Pattern"); - } - - - @Override - public boolean accept(Background background) { - return background instanceof PatternBackground; - } - - - @Override - public boolean shouldResponseChangeListener() { - return true; - } - - class PatternNewBackgroundPane extends PatternBackgroundPane { - private PatternNewBackgroundPane(int nColumn) { - super(nColumn); - } - - protected LayoutManager layoutOfTypePane(int nColumn) { - return new GridLayout(0, nColumn, 2, 2); - } - - protected void initComponents(int nColumn) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.setBorder(BorderFactory.createEmptyBorder()); - JPanel jPanel = new JPanel(); - jPanel.setLayout(layoutOfTypePane(nColumn)); - setChildrenOfTypePane(jPanel); - - foregroundColorPane = new ColorSelectBox(80); - backgroundColorPane = new ColorSelectBox(80); - foregroundColorPane.setSelectObject(Color.lightGray); - backgroundColorPane.setSelectObject(Color.black); - UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Pattern")); - label.setVerticalAlignment(SwingConstants.TOP); - Component[][] components = new Component[][]{ - new Component[]{label, jPanel}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_ForeBackground_Color")), foregroundColorPane}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Pattern_Color")), backgroundColorPane} - }; - JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_LASTCOLUMN, - IntervalConstants.INTERVAL_W4, IntervalConstants.INTERVAL_L1); - JPanel jPanel1 = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); - jPanel1.add(centerPane); - jPanel1.setBorder(BorderFactory.createEmptyBorder()); - this.add(jPanel1, BorderLayout.NORTH); - this.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (listener != null) { - listener.doChange(); - } - } - }); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/TextureDetailObservePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/TextureDetailObservePane.java deleted file mode 100644 index 189b811d99..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/background/TextureDetailObservePane.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.background; - -import com.fr.base.background.TextureBackground; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.style.background.texture.TextureDetailPane; -import com.fr.general.Background; -import com.fr.log.FineLoggerFactory; - -import javax.swing.BorderFactory; -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.Component; -import java.awt.Dimension; - -/** - * Created by kerry on 2020-09-02 - */ -public class TextureDetailObservePane extends AbstractBackgroundDetailPane implements UIObserver { - private TextureDetailPane detailPane; - - private UIObserverListener listener; - - public TextureDetailObservePane() { - - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - detailPane = TextureDetailPane.createMiniTextureDetailPane(6); - - detailPane.setPreferredSize(new Dimension(160, 108)); - UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Texture")); - label.setPreferredSize(new Dimension(24, 108)); - label.setVerticalAlignment(SwingConstants.TOP); - JPanel jPanel = TableLayoutHelper.createGapTableLayoutPane( - new Component[][]{new Component[]{label, detailPane}}, TableLayoutHelper.FILL_LASTCOLUMN, 33, 5); - jPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 10)); - - - detailPane.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - if (listener != null) { - listener.doChange(); - } - } - }); - this.add(jPanel, BorderLayout.CENTER); - } - - @Override - public void registerChangeListener(UIObserverListener listener) { - this.listener = listener; - - } - - @Override - public boolean shouldResponseChangeListener() { - return true; - } - - @Override - public void populate(TextureBackground background) { - this.detailPane.populate(background); - } - - @Override - public TextureBackground update() { - try { - return (TextureBackground) this.detailPane.update(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return null; - } - - - @Override - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Background_Texture"); - } - - @Override - public boolean accept(Background background) { - return background instanceof TextureBackground; - } - - - @Override - public void addChangeListener(ChangeListener changeListener) { - - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/cell/CustomPredefinedStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/cell/CustomPredefinedStylePane.java deleted file mode 100644 index 5e66afb8aa..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/cell/CustomPredefinedStylePane.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.cell; - -import com.fr.base.ScreenResolution; -import com.fr.base.Style; -import com.fr.config.predefined.PredefinedCellStyle; -import com.fr.design.constants.UIConstants; -import com.fr.design.dialog.AttrScrollPane; -import com.fr.design.dialog.BasicPane; -import com.fr.design.dialog.BasicScrollPane; -import com.fr.design.dialog.MultiTabPane; -import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; -import com.fr.design.gui.frpane.AttributeChangeListener; -import com.fr.design.gui.style.AbstractBasicStylePane; -import com.fr.design.gui.style.AlignmentPane; -import com.fr.design.gui.style.BorderPane; -import com.fr.design.gui.style.FormatPane; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.utils.gui.GUICoreUtils; - -import javax.swing.BorderFactory; -import javax.swing.JComponent; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GridLayout; -import java.util.ArrayList; -import java.util.List; - - -/** - * 哎,复杂的原型图导致复杂的画法。非我所愿也 - * - * @author zhou - * @since 2012-5-24上午10:36:10 - */ -public class CustomPredefinedStylePane extends MultiTabPane { - private PredefinedCellStyle cellStyle; - private PreviewArea previewArea; - private boolean populating; - private AttributeChangeListener attributeChangeListener; - - - public CustomPredefinedStylePane() { - super(); - tabPane.setOneLineTab(true); - tabPane.setDrawLine(false); - tabPane.setBorder(BorderFactory.createLineBorder(UIConstants.SHADOW_GREY)); - tabPane.setLayout(new GridLayout(1, 3, 0, 0)); - } - - public void registerAttrChangeListener(AttributeChangeListener listener){ - this.attributeChangeListener = listener; - } - - private void fireAttrChangeListener() { - if (this.attributeChangeListener != null) { - this.attributeChangeListener.attributeChange(); - } - } - - /** - * @return - */ - public String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Custom_Style"); - } - - - /** - * - */ - public void reset() { - populateBean(null); - } - - @Override - /** - * - */ - public void populateBean(PredefinedCellStyle ob) { - this.populating = true; - this.cellStyle = ob; - for (int i = 0; i < paneList.size(); i++) { - ((AbstractBasicStylePane) paneList.get(i)).populateBean(ob.getStyle()); - previewArea.preview(ob.getStyle()); - } - this.populating = false; - } - - @Override - /** - * - */ - public PredefinedCellStyle updateBean() { - AbstractBasicStylePane basicStylePane = (AbstractBasicStylePane) paneList.get(tabPane.getSelectedIndex()); - this.cellStyle.setStyle(basicStylePane.update(this.cellStyle.getStyle())); - return this.cellStyle; - } - - - /** - * @param ob - * @return - */ - public boolean accept(Object ob) { - return ob instanceof PredefinedCellStyle; - } - - @Override - protected List initPaneList() { - paneList = new ArrayList(); - paneList.add(new FormatPane()); - paneList.add(new BorderPane()); - paneList.add(new AlignmentPane()); - return paneList; - } - - protected void initLayout() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - - JPanel jPanel = new JPanel(); - jPanel.setLayout(new BorderLayout(0, 4)); - - JPanel previewPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - previewArea = new PreviewArea(); - previewPane.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview"), null)); - previewPane.add(previewArea, BorderLayout.CENTER); - - this.add(previewPane, BorderLayout.NORTH); - - this.add(jPanel, BorderLayout.CENTER); - jPanel.add(tabPane, BorderLayout.NORTH); - JPanel attrListenerPane = new AbstractAttrNoScrollPane() { - - @Override - protected void initContentPane() { - leftContentPane = createContentPane(); - this.add(leftContentPane, BorderLayout.CENTER); - } - - @Override - protected JPanel createContentPane() { - this.addAttributeChangeListener(new AttributeChangeListener() { - @Override - public void attributeChange() { - if (populating) { - return; - } - PredefinedCellStyle cellStyle = updateBean(); - if (cellStyle != null) { - previewArea.preview(cellStyle.getStyle()); - } - fireAttrChangeListener(); - } - }); - BasicScrollPane basicScrollPane = new AttrScrollPane() { - @Override - protected JPanel createContentPane() { - return centerPane; - } - }; - return basicScrollPane; - } - }; - jPanel.add(attrListenerPane, BorderLayout.CENTER); - } - - @Override - /** - * - */ - public void updateBean(PredefinedCellStyle ob) { - return; - } - - - - - /** - * 预览Style的面板 - * - * @author richer - */ - private static class PreviewArea extends JComponent { - - private String paintText = "Report"; - private Style style = Style.DEFAULT_STYLE; - - public PreviewArea() { - setPreferredSize(new Dimension(40, 30)); - } - - public void preview(Style style) { - this.style = style; - repaint(); - } - - @Override - public void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - int resolution = ScreenResolution.getScreenResolution(); - - if (style == Style.DEFAULT_STYLE) { - // 如果是默认的style,就只写"Report"上去 - Style.paintContent(g2d, paintText, style, getWidth() - 3, getHeight() - 3, resolution); - return; - } - - Style.paintBackground(g2d, style, getWidth() - 3, getHeight() - 3); - - Style.paintContent(g2d, paintText, style, getWidth() - 3, getHeight() - 3, resolution); - - Style.paintBorder(g2d, style, getWidth() - 3, getHeight() - 3); - } - - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/AbstractChartStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/AbstractChartStylePane.java deleted file mode 100644 index 2fd47d6b29..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/AbstractChartStylePane.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.constants.LayoutConstants; -import com.fr.design.dialog.BasicPane; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Component; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-17 - */ -public abstract class AbstractChartStylePane extends BasicPane { - - public AbstractChartStylePane() { - initComponents(); - initPane(); - } - - protected abstract void initComponents(); - - protected void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - double e = 155; - double p = TableLayout.PREFERRED; - double[] columnSize = {p, e}; - JPanel gapTableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(getComponent(), getRows(p), columnSize, 20, LayoutConstants.VGAP_LARGE); - gapTableLayoutPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); - UIScrollPane rightTopPane = new UIScrollPane(gapTableLayoutPane); - rightTopPane.setBorder(BorderFactory.createEmptyBorder()); - this.add(rightTopPane, BorderLayout.CENTER); - } - - protected abstract Component[][] getComponent(); - - protected abstract double[] getRows(double p); - - public abstract void populate(PredefinedChartStyle chartStyle); - - public abstract void update(PredefinedChartStyle chartStyle); -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartAxisStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartAxisStylePane.java deleted file mode 100644 index 4c6fc16ddc..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartAxisStylePane.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.i18n.Toolkit; -import com.fr.design.style.color.ColorSelectBox; - -import java.awt.Component; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartAxisStylePane extends AbstractChartStylePane { - - //轴标题字体样式 - private ChartFontPane titleFontPane; - - //轴标签字体样式 - private ChartFontPane labelFontPane; - - //轴线颜色 - private ColorSelectBox axisLineColor; - - protected void initComponents() { - titleFontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Axis_Title_Character"); - } - }; - labelFontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Axis_Label_Character"); - } - }; - axisLineColor = new ColorSelectBox(100); - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{titleFontPane, null}, - new Component[]{labelFontPane, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Axis_Line_Color")), axisLineColor} - }; - } - - protected double[] getRows(double p) { - return new double[]{p, p, p}; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Axis"); - } - - public void populate(PredefinedChartStyle chartStyle) { - titleFontPane.populate(chartStyle.getAxisTitleFont()); - labelFontPane.populate(chartStyle.getAxisLabelFont()); - axisLineColor.setSelectObject(chartStyle.getAxisLineColor()); - } - - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setAxisTitleFont(titleFontPane.update()); - chartStyle.setAxisLabelFont(labelFontPane.update()); - chartStyle.setAxisLineColor(axisLineColor.getSelectObject()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartBackgroundStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartBackgroundStylePane.java deleted file mode 100644 index 0cb602eeaa..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartBackgroundStylePane.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.base.background.ImageBackground; -import com.fr.config.predefined.PredefinedChartStyle; -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.backgroundpane.BackgroundQuickPane; -import com.fr.design.mainframe.backgroundpane.ColorBackgroundQuickPane; -import com.fr.design.mainframe.backgroundpane.ImageBackgroundQuickPane; -import com.fr.design.mainframe.backgroundpane.NullBackgroundQuickPane; -import com.fr.design.mainframe.backgroundpane.VanChartGradientPane; -import com.fr.design.style.color.ColorSelectBox; -import com.fr.general.Background; -import com.fr.stable.Constants; - -import javax.swing.JPanel; -import java.util.ArrayList; -import java.util.List; -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-17 - */ -public class ChartBackgroundStylePane extends AbstractChartStylePane { - - private UIComboBox typeComboBox; - private List paneList; - private JPanel centerPane; - //网格线颜色 - private ColorSelectBox mainGridColor; - - protected void initComponents() { - mainGridColor = new ColorSelectBox(100); - - typeComboBox = new UIComboBox(); - final CardLayout cardlayout = new CardLayout(); - initList(); - - centerPane = new JPanel(cardlayout) { - @Override - public Dimension getPreferredSize() {// AUGUST:使用当前面板的的高度 - int index = typeComboBox.getSelectedIndex(); - return new Dimension(super.getPreferredSize().width, paneList.get(index).getPreferredSize().height); - } - }; - for (int i = 0; i < paneList.size(); i++) { - BackgroundQuickPane pane = paneList.get(i); - typeComboBox.addItem(pane.title4PopupWindow()); - centerPane.add(pane, pane.title4PopupWindow()); - } - - typeComboBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - cardlayout.show(centerPane, (String) typeComboBox.getSelectedItem()); - } - }); - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{null, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Area_Background_Color")), typeComboBox}, - new Component[]{null, centerPane}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Grid_Line_Color")), mainGridColor} - }; - } - - protected double[] getRows(double p) { - return new double[]{p, p, p, p}; - } - - private void initList() { - paneList = new ArrayList<>(); - paneList.add(new NullBackgroundQuickPane()); - paneList.add(new ColorBackgroundQuickPane()); - paneList.add(new ImageBackgroundQuickPane(false)); - paneList.add(new VanChartGradientPane()); - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Background"); - } - - public void populate(PredefinedChartStyle chartStyle) { - Background background = chartStyle.getChartBackground(); - for (int i = 0; i < paneList.size(); i++) { - BackgroundQuickPane pane = paneList.get(i); - if (pane.accept(background)) { - pane.populateBean(background); - typeComboBox.setSelectedIndex(i); - break; - } - } - mainGridColor.setSelectObject(chartStyle.getGridMainLineColor()); - } - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setChartBackground(paneList.get(typeComboBox.getSelectedIndex()).updateBean()); - if (chartStyle.getChartBackground() instanceof ImageBackground) { - ((ImageBackground) chartStyle.getChartBackground()).setLayout(Constants.IMAGE_EXTEND); - } - chartStyle.setGridMainLineColor(mainGridColor.getSelectObject()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartDataSheetStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartDataSheetStylePane.java deleted file mode 100644 index 2da8ee35f3..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartDataSheetStylePane.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.i18n.Toolkit; -import com.fr.design.style.color.ColorSelectBox; - -import java.awt.Component; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-17 - */ -public class ChartDataSheetStylePane extends AbstractChartStylePane { - - //字体样式 - private ChartFontPane fontPane; - - //边框颜色 - private ColorSelectBox borderColor; - - protected void initComponents() { - fontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_DataSheet_Character"); - } - }; - borderColor = new ColorSelectBox(100); - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{fontPane, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Border_Color")), borderColor} - }; - } - - protected double[] getRows(double p) { - return new double[]{p, p, p}; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Data_Sheet"); - } - - public void populate(PredefinedChartStyle chartStyle) { - fontPane.populate(chartStyle.getDataSheetFont()); - borderColor.setSelectObject(chartStyle.getDataSheetBorderColor()); - } - - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setDataSheetFont(fontPane.update()); - chartStyle.setDataSheetBorderColor(borderColor.getSelectObject()); - } -} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartFontPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartFontPane.java deleted file mode 100644 index 93c0f8a6b6..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartFontPane.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.base.BaseUtils; -import com.fr.base.FRContext; -import com.fr.base.Utils; -import com.fr.design.constants.LayoutConstants; -import com.fr.design.dialog.BasicPane; -import com.fr.design.event.UIObserverListener; -import com.fr.design.gui.ibutton.UIColorButton; -import com.fr.design.gui.ibutton.UIToggleButton; -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.TableLayout; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.FRFont; -import com.fr.general.GeneralUtils; - -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.FlowLayout; -import java.awt.Font; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartFontPane extends BasicPane { - - public static final int FONT_START = 6; - public static final int FONT_END = 72; - private UIComboBox fontNameComboBox; - private UIComboBox fontSizeComboBox; - private UIToggleButton bold; - private UIToggleButton italic; - private UIColorButton fontColor; - private static Integer[] FONT_SIZES = new Integer[FONT_END - FONT_START + 1]; - - static { - for (int i = FONT_START; i <= FONT_END; i++) { - FONT_SIZES[i - FONT_START] = i; - } - } - - public ChartFontPane() { - initState(); - initComponents(); - } - - private void initState() { - fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); - fontSizeComboBox = new UIComboBox(FONT_SIZES); - bold = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); - italic = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); - fontColor = new UIColorButton(); - } - - protected void initComponents() { - Component[] components = new Component[]{ - fontColor, italic, bold - }; - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(fontSizeComboBox, BorderLayout.CENTER); - buttonPane.add(GUICoreUtils.createFlowPane(components, FlowLayout.LEFT, LayoutConstants.HGAP_LARGE), BorderLayout.EAST); - - this.setLayout(new BorderLayout()); - this.add(getContentPane(buttonPane), BorderLayout.CENTER); - - populate(FRContext.getDefaultValues().getFRFont()); - } - - protected JPanel getContentPane(JPanel buttonPane) { - double e = 155; - double p = TableLayout.PREFERRED; - double[] rows = {p, p, p}; - double[] columnSize = {p, e}; - UILabel text = new UILabel(getUILabelText(), SwingConstants.LEFT); - Component[][] components = { - new Component[]{null, null}, - new Component[]{text, fontNameComboBox}, - new Component[]{null, buttonPane} - }; - - return TableLayoutHelper.createGapTableLayoutPane(components, rows, columnSize, 20, LayoutConstants.VGAP_LARGE); - } - - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Character"); - } - - public String title4PopupWindow() { - return null; - } - - public void populate(FRFont frFont) { - UIObserverListener listener = fontNameComboBox == null ? null : fontNameComboBox.getUiObserverListener(); - removeAllComboBoxListener(); - - if (frFont != null) { - fontNameComboBox.setSelectedItem(frFont.getFamily()); - bold.setSelected(frFont.isBold()); - italic.setSelected(frFont.isItalic()); - populateFontSize(frFont); - if (fontColor != null) { - fontColor.setColor(frFont.getForeground()); - } - } - - //更新结束后,注册监听器 - registerAllComboBoxListener(listener); - } - - private void populateFontSize(FRFont frFont) { - if (fontSizeComboBox != null) { - fontSizeComboBox.setSelectedItem(frFont.getSize()); - } - } - - private void removeAllComboBoxListener() { - fontNameComboBox.removeChangeListener(); - fontSizeComboBox.removeChangeListener(); - } - - private void registerAllComboBoxListener(UIObserverListener listener) { - fontNameComboBox.registerChangeListener(listener); - fontSizeComboBox.registerChangeListener(listener); - } - - /** - * 更新字 - * - * @return 更新字 - */ - public FRFont update() { - String name = GeneralUtils.objectToString(fontNameComboBox.getSelectedItem()); - - return FRFont.getInstance(name, updateFontStyle(), updateFontSize(), fontColor.getColor()); - } - - private int updateFontStyle() { - int style = Font.PLAIN; - if (bold.isSelected() && !italic.isSelected()) { - style = Font.BOLD; - } else if (!bold.isSelected() && italic.isSelected()) { - style = Font.ITALIC; - } else if (bold.isSelected() && italic.isSelected()) { - style = 3; - } - - return style; - } - - private float updateFontSize() { - return Float.parseFloat(GeneralUtils.objectToString(fontSizeComboBox.getSelectedItem())); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLabelStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLabelStylePane.java deleted file mode 100644 index b51535b82a..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLabelStylePane.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.gui.ibutton.UIButtonGroup; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.i18n.Toolkit; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartLabelStylePane extends AbstractChartStylePane { - - private UIButtonGroup autoButton; - //字体样式 - private ChartFontPane chartFontPane; - - protected void initComponents() { - autoButton = new UIButtonGroup<>(new String[]{Toolkit.i18nText("Fine-Design_Chart_Auto"), - Toolkit.i18nText("Fine-Design_Chart_Custom")}); - chartFontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Label_Character"); - } - }; - initListener(); - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{null, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Style_Setting")), autoButton}, - new Component[]{chartFontPane, null} - }; - } - - protected double[] getRows(double p) { - return new double[]{p, p, p}; - } - - private void initListener() { - autoButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkPreButton(); - } - }); - } - - private void checkPreButton() { - chartFontPane.setVisible(autoButton.getSelectedIndex() == 1); - chartFontPane.setPreferredSize(autoButton.getSelectedIndex() == 1 ? new Dimension(0, 60) : new Dimension(0, 0)); - } - - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Label"); - } - - public void populate(PredefinedChartStyle chartStyle) { - autoButton.setSelectedIndex(chartStyle.isAutoLabelFont() ? 0 : 1); - chartFontPane.populate(chartStyle.getLabelFont()); - checkPreButton(); - } - - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setAutoLabelFont(autoButton.getSelectedIndex() == 0); - chartStyle.setLabelFont(chartFontPane.update()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLegendStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLegendStylePane.java deleted file mode 100644 index c956dfcfd9..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartLegendStylePane.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.i18n.Toolkit; - -import java.awt.Component; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartLegendStylePane extends AbstractChartStylePane { - - //字体样式 - private ChartFontPane chartFontPane; - - protected void initComponents() { - chartFontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Legend_Character"); - } - }; - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{chartFontPane, null} - }; - } - - protected double[] getRows(double p) { - return new double[]{p}; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Legend"); - } - - public void populate(PredefinedChartStyle chartStyle) { - chartFontPane.populate(chartStyle.getLegendFont()); - } - - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setLegendFont(chartFontPane.update()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartTitleStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartTitleStylePane.java deleted file mode 100644 index d5bc56cd9e..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/chart/ChartTitleStylePane.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.chart; - -import com.fr.config.predefined.PredefinedChartStyle; -import com.fr.design.i18n.Toolkit; - -import java.awt.Component; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-16 - */ -public class ChartTitleStylePane extends AbstractChartStylePane { - - //字体样式 - private ChartFontPane chartFontPane; - - protected void initComponents() { - chartFontPane = new ChartFontPane() { - public String getUILabelText() { - return Toolkit.i18nText("Fine-Design_Chart_Title_Character"); - } - }; - } - - protected Component[][] getComponent() { - return new Component[][]{ - new Component[]{chartFontPane, null} - }; - } - - protected double[] getRows(double p) { - return new double[]{p}; - } - - @Override - protected String title4PopupWindow() { - return Toolkit.i18nText("Fine-Design_Report_Title"); - } - - public void populate(PredefinedChartStyle chartStyle) { - chartFontPane.populate(chartStyle.getTitleFont()); - } - - - public void update(PredefinedChartStyle chartStyle) { - chartStyle.setTitleFont(chartFontPane.update()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentFrameStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentFrameStylePane.java deleted file mode 100644 index 3d04a3cd5d..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentFrameStylePane.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.component; - -import com.fr.base.GraphHelper; -import com.fr.base.Utils; -import com.fr.config.predefined.PredefinedComponentStyle; -import com.fr.design.gui.frpane.UINumberDragPane; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.ibutton.UIButtonUI; -import com.fr.design.gui.ibutton.UIColorButton; -import com.fr.design.gui.icombobox.LineComboBox; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.ispinner.UISpinner; -import com.fr.design.gui.style.BackgroundSpecialPane; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.mainframe.backgroundpane.GradientBackgroundQuickPane; -import com.fr.general.act.BorderPacker; -import com.fr.stable.Constants; - -import javax.swing.BorderFactory; -import javax.swing.JComponent; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.geom.RoundRectangle2D; - -/** - * Created by kerry on 2020-09-01 - */ -public class ComponentFrameStylePane extends ComponentStylePane { - private final static String[] BORDER_STYLE = new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Common"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Shadow")}; - private static final double ALPHA_MAX_NUMBER = 100; - private final static int[] BORDER_LINE_STYLE_ARRAY = new int[]{ - Constants.LINE_NONE, - Constants.LINE_THIN, //1px - Constants.LINE_MEDIUM, //2px - Constants.LINE_THICK, //3px - }; - - //渲染风格 - private UIComboBox borderStyleCombo; - //边框粗细 - private LineComboBox currentLineCombo; - //边框圆角 - private UISpinner borderCornerSpinner; - //边框颜色 - private UIColorButton currentLineColorPane; - //主体背景 - private BackgroundSpecialPane backgroundPane; - //透明度 - private UINumberDragPane numberDragPane; - - public ComponentFrameStylePane() { - initPane(); - } - - protected void initPane() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.setBorder(BorderFactory.createEmptyBorder(6, 0, 0, 0)); - this.borderStyleCombo = new UIComboBox(BORDER_STYLE); - this.currentLineCombo = new LineComboBox(BORDER_LINE_STYLE_ARRAY); - this.currentLineColorPane = new UIColorButton(null); - this.borderCornerSpinner = new UISpinner(0, 1000, 1, 0); - currentLineColorPane.setUI(getButtonUI(currentLineColorPane)); - currentLineColorPane.set4ToolbarButton(); - currentLineColorPane.setPreferredSize(new Dimension(20, 20)); - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(currentLineColorPane, BorderLayout.WEST); - backgroundPane = new BackgroundSpecialPane(); - JPanel transparencyPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - this.numberDragPane = new UINumberDragPane(0, 100); - transparencyPane.add(numberDragPane, BorderLayout.CENTER); - transparencyPane.add(new UILabel(" %"), BorderLayout.EAST); - - double p = TableLayout.PREFERRED; - double[] rowSize = {p, p, p, p, p, p, p, p}; - double[] columnSize = {p, 157}; - JPanel rightTopContentPane = TableLayoutHelper.createCommonTableLayoutPane(new JComponent[][]{ - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Render_Style")), borderStyleCombo}, - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Border_Line")), currentLineCombo}, - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Border_Color")), buttonPane}, - getBorderCornerSpinnerComp(), - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget-Style_Body_Background")), backgroundPane}, - {new UILabel(""), new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha"))}, - {new UILabel(""), transparencyPane}, - }, rowSize, columnSize, 10); - UIScrollPane rightTopPane = new UIScrollPane(rightTopContentPane); - rightTopPane.setBorder(BorderFactory.createEmptyBorder()); - this.add(rightTopPane, BorderLayout.CENTER); - } - - - private JComponent[] getBorderCornerSpinnerComp() { - return new JComponent[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Radius") + ":"), borderCornerSpinner}; - } - - - protected UIButtonUI getButtonUI(final UIColorButton uiColorButton) { - return new UIButtonUI() { - - public void paint(Graphics g, JComponent c) { - UIButton b = (UIButton) c; - g.setColor(Color.black); - GraphHelper.draw(g, new RoundRectangle2D.Double(1, 1, b.getWidth() - 2, b.getHeight() - 2, 0, 0), 1); - - if (b.getModel().isEnabled()) { - g.setColor(uiColorButton.getColor()); - } else { - g.setColor(new Color(Utils.filterRGB(uiColorButton.getColor().getRGB(), 50))); - } - g.fillRect(2, 2, b.getWidth() - 3, b.getHeight() - 3); - } - }; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Frame"); - } - - - @Override - public void populate(PredefinedComponentStyle componentStyle) { - BorderPacker borderStyle = componentStyle.getBorderStyle(); - this.borderStyleCombo.setSelectedIndex(borderStyle.getBorderStyle()); - this.borderCornerSpinner.setValue(borderStyle.getBorderRadius()); - this.currentLineCombo.setSelectedLineStyle(borderStyle.getBorder()); - this.currentLineColorPane.setColor(borderStyle.getColor()); - this.backgroundPane.populateBean(borderStyle.getBackground()); - numberDragPane.populateBean(borderStyle.getAlpha() * ALPHA_MAX_NUMBER); - } - - @Override - public void update(PredefinedComponentStyle componentStyle) { - BorderPacker style = componentStyle.getBorderStyle(); - style.setBorderStyle(borderStyleCombo.getSelectedIndex()); - style.setBorderRadius((int) borderCornerSpinner.getValue()); - style.setBorder(currentLineCombo.getSelectedLineStyle()); - style.setColor(currentLineColorPane.getColor()); - style.setBackground(backgroundPane.update()); - style.setAlpha((float) (numberDragPane.updateBean() / ALPHA_MAX_NUMBER)); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentMarginStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentMarginStylePane.java deleted file mode 100644 index b36702fb71..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentMarginStylePane.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.component; - -import com.fr.config.predefined.PredefinedComponentStyle; -import com.fr.design.designer.IntervalConstants; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.ispinner.UISpinner; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import java.awt.BorderLayout; -import java.awt.Component; - -/** - * Created by kerry on 2020-09-01 - */ -public class ComponentMarginStylePane extends ComponentStylePane { - protected UISpinner top; - protected UISpinner bottom; - protected UISpinner left; - protected UISpinner right; - - public ComponentMarginStylePane() { - initBoundPane(0, 0, 0, 0); - } - - public void initBoundPane(int t, int b, int l, int r) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - top = new UISpinner(0, Integer.MAX_VALUE, 1, t); - bottom = new UISpinner(0, Integer.MAX_VALUE, 1, b); - left = new UISpinner(0, Integer.MAX_VALUE, 1, l); - right = new UISpinner(0, Integer.MAX_VALUE, 1, r); - top.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_Padding_Duplicate")); - bottom.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_Padding_Duplicate")); - left.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_Padding_Duplicate")); - right.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_Padding_Duplicate")); - UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_Padding_Duplicate")); - label.setBorder(BorderFactory.createEmptyBorder(IntervalConstants.INTERVAL_L1, 0, 0, 0)); - label.setVerticalAlignment(SwingConstants.TOP); - JPanel panel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{ - new Component[]{label, createRightPane()}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); - this.add(panel); - } - - - public JPanel createRightPane() { - double f = TableLayout.FILL; - double p = TableLayout.PREFERRED; - double[] rowSize = {p, p}; - double[] columnSize = {f, f}; - int[][] rowCount = {{1, 1}, {1, 1}}; - Component[][] components1 = new Component[][]{ - new Component[]{top, bottom}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Top"), SwingConstants.CENTER), new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Bottom"), SwingConstants.CENTER)} - }; - Component[][] components2 = new Component[][]{ - new Component[]{left, right}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Left"), SwingConstants.CENTER), new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Right"), SwingConstants.CENTER)} - }; - JPanel northPanel = TableLayoutHelper.createGapTableLayoutPane(components1, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_L6, IntervalConstants.INTERVAL_L6); - northPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, IntervalConstants.INTERVAL_L1, 0)); - JPanel centerPanel = TableLayoutHelper.createGapTableLayoutPane(components2, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_L6, IntervalConstants.INTERVAL_L6); - JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - panel.setBorder(BorderFactory.createEmptyBorder(IntervalConstants.INTERVAL_L1, 0, IntervalConstants.INTERVAL_L1, 0)); - panel.add(northPanel, BorderLayout.NORTH); - panel.add(centerPanel, BorderLayout.CENTER); - return panel; - } - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Base_Margin"); - } - - @Override - public void populate(PredefinedComponentStyle componentStyle) { - this.top.setValue(componentStyle.getTop()); - this.bottom.setValue(componentStyle.getBottom()); - this.left.setValue(componentStyle.getLeft()); - this.right.setValue(componentStyle.getRight()); - } - - @Override - public void update(PredefinedComponentStyle componentStyle) { - componentStyle.setTop((int) this.top.getValue()); - componentStyle.setBottom((int) this.bottom.getValue()); - componentStyle.setLeft((int) this.left.getValue()); - componentStyle.setRight((int) this.right.getValue()); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentStylePane.java deleted file mode 100644 index 9d858cfea0..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentStylePane.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.component; - -import com.fr.config.predefined.PredefinedComponentStyle; -import com.fr.design.dialog.BasicPane; - - -/** - * Created by kerry on 2020-09-01 - */ -public abstract class ComponentStylePane extends BasicPane { - - public abstract void populate(PredefinedComponentStyle componentStyle); - - public abstract void update(PredefinedComponentStyle componentStyle); -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentTitleStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentTitleStylePane.java deleted file mode 100644 index 73dc561064..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/detail/component/ComponentTitleStylePane.java +++ /dev/null @@ -1,253 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.detail.component; - -import com.fr.base.BaseUtils; -import com.fr.base.Utils; -import com.fr.config.predefined.PredefinedComponentStyle; -import com.fr.design.constants.LayoutConstants; -import com.fr.design.constants.UIConstants; -import com.fr.design.formula.TinyFormulaPane; -import com.fr.design.gui.ibutton.UIButtonGroup; -import com.fr.design.gui.ibutton.UIColorButton; -import com.fr.design.gui.ibutton.UIToggleButton; -import com.fr.design.gui.icombobox.LineComboBox; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.gui.icontainer.UIScrollPane; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.style.BackgroundNoImagePane; -import com.fr.design.gui.style.FRFontPane; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.layout.TableLayout; -import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.mainframe.backgroundpane.GradientBackgroundQuickPane; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.form.ui.LayoutBorderStyle; -import com.fr.form.ui.WidgetTitle; -import com.fr.general.FRFont; -import com.fr.general.act.BorderPacker; -import com.fr.general.act.TitlePacker; -import com.fr.stable.ArrayUtils; -import com.fr.stable.Constants; -import com.fr.stable.StringUtils; - -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Font; - -/** - * Created by kerry on 2020-09-01 - */ -public class ComponentTitleStylePane extends ComponentStylePane { - private final static Dimension BUTTON_SIZE = new Dimension(24, 20); - //标题内容 - private TinyFormulaPane formulaPane; - //标题格式 - private UIComboBox fontNameComboBox; - private UIComboBox fontSizeComboBox; - private UIColorButton colorSelectPane; - private UIToggleButton bold; - private UIToggleButton italic; - private UIToggleButton underline; - private LineComboBox underlineCombo; - //对齐方式 - private UIButtonGroup hAlignmentPane; - //标题背景 - private BackgroundNoImagePane titleBackgroundPane; - - public static ComponentTitleStylePane createPredefinedSettingPane(){ - return new ComponentTitleStylePane(true); - } - - public static ComponentTitleStylePane createStyleSettingPane(){ - return new ComponentTitleStylePane(false); - } - - private ComponentTitleStylePane(boolean isPredefined) { - initPane(isPredefined); - } - - protected void initPane(boolean isPredefined) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.setBorder(BorderFactory.createEmptyBorder(6, 0,0,0)); - formulaPane = new TinyFormulaPane(); - fontSizeComboBox = new UIComboBox(FRFontPane.FONT_SIZES); - fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); - fontNameComboBox.setPreferredSize(new Dimension(105 , 20)); - JPanel fontSizeTypePane = new JPanel(new BorderLayout(3, 0)); - fontSizeTypePane.add(fontSizeComboBox, BorderLayout.CENTER); - fontSizeTypePane.add(fontNameComboBox, BorderLayout.EAST); - - Icon[] hAlignmentIconArray = {BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/h_left_normal.png"), - BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/h_center_normal.png"), - BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/h_right_normal.png"),}; - Integer[] hAlignment = new Integer[]{Constants.LEFT, Constants.CENTER, Constants.RIGHT}; - hAlignmentPane = new UIButtonGroup(hAlignmentIconArray, hAlignment); - hAlignmentPane.setAllToolTips(new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_StyleAlignment_Left") - , com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_StyleAlignment_Center"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_StyleAlignment_Right")}); - JPanel hPaneContainer = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); - hPaneContainer.add(hAlignmentPane); - - titleBackgroundPane = new BackgroundNoImagePane(); - - double p = TableLayout.PREFERRED; - double[] rowSize = {p, p, p, p, p, p, p, p}; - double[] columnSize = {p, 157}; - JComponent[][] jComponents = new JComponent[][]{ - {new UILabel(com.fr.design.i18n.Toolkit.i18nText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Char"))), fontSizeTypePane}, - {new UILabel(""), initFontButtonPane()}, - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Alignment-Style")), hAlignmentPane}, - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Title_Background")), titleBackgroundPane}}; - - JComponent[][] displayComponents = createDisplayComponentArray(isPredefined, jComponents); - JPanel rightBottomContentPane = TableLayoutHelper.createCommonTableLayoutPane(displayComponents, rowSize, columnSize, 10); - - UIScrollPane jPanel = new UIScrollPane(rightBottomContentPane); - jPanel.setBorder(BorderFactory.createEmptyBorder()); - this.add(jPanel, BorderLayout.CENTER); - } - - private JComponent[][] createDisplayComponentArray(boolean isPredefined, JComponent[][] baseComponents) { - if (isPredefined) { - return baseComponents; - } - JComponent[][] titleComponent = new JComponent[][]{{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Title_Content")), formulaPane}}; - return ArrayUtils.addAll(titleComponent, baseComponents); - - } - - protected JPanel initFontButtonPane() { - colorSelectPane = new UIColorButton(); - bold = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); - italic = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); - underline = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/underline.png")); - bold.setPreferredSize(BUTTON_SIZE); - italic.setPreferredSize(BUTTON_SIZE); - underline.setPreferredSize(BUTTON_SIZE); - underline.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - underlineCombo.setVisible(underline.isSelected()); - } - }); - underlineCombo = new LineComboBox(UIConstants.BORDER_LINE_STYLE_ARRAY); - Component[] components_font = new Component[]{ - colorSelectPane, italic, bold, underline - }; - JPanel buttonPane = new JPanel(new BorderLayout()); - buttonPane.add(GUICoreUtils.createFlowPane(components_font, FlowLayout.LEFT, LayoutConstants.HGAP_SMALL)); - JPanel combinePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - combinePane.add(buttonPane, BorderLayout.WEST); - combinePane.add(underlineCombo, BorderLayout.CENTER); - initAllNames(); - setToolTips(); - return combinePane; - - } - - protected void initAllNames() { - fontNameComboBox.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Family")); - fontSizeComboBox.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Size")); - colorSelectPane.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Foreground")); - italic.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Italic")); - bold.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Bold")); - underline.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Underline")); - underlineCombo.setGlobalName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Line_Style")); - } - - protected void setToolTips() { - colorSelectPane.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Foreground")); - italic.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Italic")); - bold.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Bold")); - underline.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_FRFont_Underline")); - } - - - @Override - protected String title4PopupWindow() { - return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Title"); - } - - @Override - public void populate(PredefinedComponentStyle componentStyle) { - BorderPacker borderStyle = componentStyle.getBorderStyle(); - TitlePacker widgetTitle = borderStyle == null ? new WidgetTitle() : borderStyle.getTitle(); - widgetTitle = widgetTitle == null ? new WidgetTitle() : widgetTitle; - - populateFormula(widgetTitle); - populateFont(widgetTitle); - - hAlignmentPane.setSelectedItem(widgetTitle.getPosition()); - - titleBackgroundPane.populateBean(widgetTitle.getBackground()); - } - - private void populateFormula(TitlePacker widgetTitle) { - this.formulaPane.populateBean(widgetTitle.getTextObject().toString()); - } - - protected void populateFont(TitlePacker widgetTitle) { - FRFont frFont = widgetTitle.getFrFont(); - this.fontSizeComboBox.setSelectedItem(frFont.getSize()); - this.fontNameComboBox.setSelectedItem(frFont.getFamily()); - this.colorSelectPane.setColor(frFont.getForeground()); - this.colorSelectPane.repaint(); - bold.setSelected(frFont.isBold()); - italic.setSelected(frFont.isItalic()); - int line = frFont.getUnderline(); - if (line == Constants.LINE_NONE) { - underline.setSelected(false); - underlineCombo.setVisible(false); - } else { - underline.setSelected(true); - underlineCombo.setVisible(true); - this.underlineCombo.setSelectedLineStyle(line); - } - } - - @Override - public void update(PredefinedComponentStyle componentStyle) { - BorderPacker style = componentStyle.getBorderStyle(); - TitlePacker title = style.getTitle() == null ? new WidgetTitle() : style.getTitle(); - String titleText = formulaPane.updateBean(); - title.setTextObject(titleText); - style.setType(StringUtils.isEmpty(titleText) ? LayoutBorderStyle.STANDARD : LayoutBorderStyle.TITLE); - FRFont frFont = title.getFrFont(); - frFont = frFont.applySize((Integer) fontSizeComboBox.getSelectedItem()); - frFont = frFont.applyName(fontNameComboBox.getSelectedItem().toString()); - frFont = frFont.applyForeground(colorSelectPane.getColor()); - frFont = updateItalicBold(frFont); - int line = underline.isSelected() ? this.underlineCombo.getSelectedLineStyle() : Constants.LINE_NONE; - frFont = frFont.applyUnderline(line); - title.setFrFont(frFont); - title.setPosition((Integer) hAlignmentPane.getSelectedItem()); - title.setBackground(titleBackgroundPane.update()); - style.setTitle(title); - } - - private FRFont updateItalicBold(FRFont frFont) { - int italic_bold = frFont.getStyle(); - boolean isItalic = italic_bold == Font.ITALIC || italic_bold == (Font.BOLD + Font.ITALIC); - boolean isBold = italic_bold == Font.BOLD || italic_bold == (Font.BOLD + Font.ITALIC); - if (italic.isSelected() && !isItalic) { - italic_bold += Font.ITALIC; - } else if (!italic.isSelected() && isItalic) { - italic_bold -= Font.ITALIC; - } - frFont = frFont.applyStyle(italic_bold); - if (bold.isSelected() && !isBold) { - italic_bold += Font.BOLD; - } else if (!bold.isSelected() && isBold) { - italic_bold -= Font.BOLD; - } - frFont = frFont.applyStyle(italic_bold); - return frFont; - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/PredefinedStyleEditDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/PredefinedStyleEditDialog.java deleted file mode 100644 index 0bfe1f117b..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/PredefinedStyleEditDialog.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.dialog; - -import com.fr.config.ServerPreferenceConfig; -import com.fr.config.predefined.PredefinedStyleConfig; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.itextfield.UITextField; -import com.fr.design.mainframe.predefined.ui.PredefinedStyleEditPane; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.stable.StringUtils; - -import javax.swing.BorderFactory; -import javax.swing.JDialog; - -import javax.swing.JPanel; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -/** - * Created by kerry on 2020-08-26 - */ -public class PredefinedStyleEditDialog extends JDialog { - - public PredefinedStyleEditDialog(Window parent, PredefinedStyleEditPane contentPane) { - this(parent, contentPane, false); - } - - - public PredefinedStyleEditDialog(Window parent, PredefinedStyleEditPane contentPane, boolean isBuiltIn) { - super(parent, ModalityType.APPLICATION_MODAL); - - this.setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Edit")); - this.setResizable(false); - JPanel defaultPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); - this.setContentPane(defaultPane); - - UIButton saveBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Save")); - saveBtn.setEnabled(!isBuiltIn); - saveBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if(contentPane.saveStyle()){ - dialogExit(); - } - } - }); - UIButton saveAsBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Save_As_New")); - saveAsBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SaveAsNewStyleDialog saveAsNewStyleDialog = new SaveAsNewStyleDialog(PredefinedStyleEditDialog.this, contentPane); - saveAsNewStyleDialog.setVisible(true); - - } - }); - UIButton cancelBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cancel")); - cancelBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialogExit(); - } - }); - JPanel buttonPanel = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); - buttonPanel.add(saveBtn); - buttonPanel.add(saveAsBtn); - buttonPanel.add(cancelBtn); - - defaultPane.add(contentPane, BorderLayout.CENTER); - defaultPane.add(buttonPanel, BorderLayout.SOUTH); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dialogExit(); - } - }); - - - this.setSize(new Dimension(900, 600)); - GUICoreUtils.centerWindow(this); - } - - public void dialogExit() { - this.dispose(); - } - - class SaveAsNewStyleDialog extends JDialog { - private UITextField textField; - private UILabel tipLabel; - - public SaveAsNewStyleDialog(Window parent, PredefinedStyleEditPane editPane) { - super(parent, ModalityType.APPLICATION_MODAL); - - this.setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Save_As_New")); - this.setResizable(false); - UIButton confirm = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm")); - confirm.setEnabled(false); - confirm.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String name = textField.getText(); - if (valid(name)) { - editPane.saveAsNewStyle(name); - dialogExit(); - PredefinedStyleEditDialog.this.dialogExit(); - } else { - tipLabel.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Name_Repeat")); - } - } - }); - UIButton cancle = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cancel")); - cancle.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialogExit(); - } - }); - JPanel defaultPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); - JPanel buttonPanel = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); - buttonPanel.add(confirm); - buttonPanel.add(cancle); - - JPanel panel = createSaveAsPane(confirm); - - - defaultPane.add(panel, BorderLayout.CENTER); - defaultPane.add(buttonPanel, BorderLayout.SOUTH); - - this.setContentPane(defaultPane); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dialogExit(); - } - }); - - - this.setSize(new Dimension(300, 140)); - GUICoreUtils.centerWindow(this); - } - - private JPanel createSaveAsPane(UIButton confirm) { - JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - JPanel centerPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(20, 5); - centerPane.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Name"))); - textField = new UITextField(); - textField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - confirm.setEnabled(StringUtils.isNotEmpty(textField.getText())); - } - - @Override - public void removeUpdate(DocumentEvent e) { - - } - - @Override - public void changedUpdate(DocumentEvent e) { - - } - }); - textField.setPreferredSize(new Dimension(180, 20)); - centerPane.add(textField); - panel.add(centerPane, BorderLayout.CENTER); - tipLabel = new UILabel(); - tipLabel.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 0)); - tipLabel.setForeground(Color.RED); - panel.add(tipLabel, BorderLayout.SOUTH); - return panel; - - - } - - - public void dialogExit() { - this.dispose(); - } - - private boolean valid(String name) { - PredefinedStyleConfig config = ServerPreferenceConfig.getInstance().getPreferenceStyleConfig(); - return !config.containStyle(name); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ReportPredefinedStyleDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ReportPredefinedStyleDialog.java deleted file mode 100644 index 658032a683..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ReportPredefinedStyleDialog.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.dialog; - -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.predefined.ui.ReportPredefinedStylePane; -import com.fr.design.mainframe.predefined.ui.ServerPredefinedStylePane; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.workspace.WorkContext; - -import javax.swing.JDialog; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -/** - * Created by kerry on 2020-08-26 - */ -public class ReportPredefinedStyleDialog extends JDialog { - - - public ReportPredefinedStyleDialog(Window parent, ReportPredefinedStylePane contentPane) { - super(parent, ModalityType.APPLICATION_MODAL); - - this.setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Template_Style")); - this.setResizable(false); - JPanel defaultPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); - this.setContentPane(defaultPane); - UIButton managerBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Style_Manager")); - managerBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ServerPredefinedStylePane predefinedStylePane = new ServerPredefinedStylePane(); - ServerPredefinedStyleDialog dialog = new ServerPredefinedStyleDialog(ReportPredefinedStyleDialog.this, predefinedStylePane); - dialog.setVisible(true); - dialog.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - contentPane.refresh(); - } - }); - } - }); - - - UIButton settingBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Applicate_Style")); - settingBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - contentPane.update(); - dialogExit(); - } - }); - - UIButton cancelBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cancel")); - cancelBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialogExit(); - } - }); - JPanel southPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - - if (WorkContext.getCurrent().isRoot()){ - JPanel buttonPanel1 = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); - buttonPanel1.add(managerBtn); - southPane.add(buttonPanel1, BorderLayout.CENTER); - } - - JPanel buttonPanel2 = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); - buttonPanel2.add(settingBtn); - buttonPanel2.add(cancelBtn); - - southPane.add(buttonPanel2, BorderLayout.EAST); - - defaultPane.add(contentPane, BorderLayout.CENTER); - defaultPane.add(southPane, BorderLayout.SOUTH); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dialogExit(); - } - }); - - - this.setSize(new Dimension(660, 600)); - GUICoreUtils.centerWindow(this); - } - - public void dialogExit() { - this.dispose(); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ServerPredefinedStyleDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ServerPredefinedStyleDialog.java deleted file mode 100644 index 439bb3ec28..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/dialog/ServerPredefinedStyleDialog.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.dialog; - -import com.fr.design.mainframe.predefined.ui.ServerPredefinedStylePane; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.utils.gui.GUICoreUtils; - -import javax.swing.JDialog; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -/** - * Created by kerry on 2020-08-26 - */ -public class ServerPredefinedStyleDialog extends JDialog { - - - public ServerPredefinedStyleDialog(Window parent, ServerPredefinedStylePane contentPane) { - super(parent, ModalityType.APPLICATION_MODAL); - this.setTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Predefined_Server_Style")); - this.setResizable(false); - JPanel defaultPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); - this.setContentPane(defaultPane); - - UIButton settingBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Set_Default")); - settingBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - contentPane.update(); - dialogExit(); - } - }); - - UIButton cancelBtn = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cancel")); - cancelBtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialogExit(); - } - }); - JPanel buttonPanel = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); - buttonPanel.add(settingBtn); - buttonPanel.add(cancelBtn); - - defaultPane.add(contentPane, BorderLayout.CENTER); - defaultPane.add(buttonPanel, BorderLayout.SOUTH); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dialogExit(); - } - }); - - - this.setSize(new Dimension(660, 600)); - GUICoreUtils.centerWindow(this); - } - - public void dialogExit(){ - this.dispose(); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ChartPreStylePreView.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ChartPreStylePreView.java deleted file mode 100644 index 1ca9163cb4..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ChartPreStylePreView.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.preview; - -import com.fr.base.chart.BaseChartCollection; -import com.fr.base.chart.BaseChartPainter; -import com.fr.base.chart.chartdata.CallbackEvent; -import com.fr.base.chart.result.WebChartIDInfo; -import com.fr.chart.chartattr.ChartCollection; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.gui.chart.MiddleChartComponent; -import com.fr.general.Background; -import com.fr.script.Calculator; -import com.fr.stable.core.PropertyChangeListener; - -import javax.swing.BorderFactory; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; - -/** - * @author Bjorn - * @version 10.0 - * Created by Bjorn on 2020-09-28 - */ -public class ChartPreStylePreView extends MiddleChartComponent { - - private ChartCollection chartCollection; - - private double scaleX = 1.0; - private double scaleY = 1.0; - - private CallbackEvent callbackEvent; - - private static final int BOUNDS = 10; - - private Background componentBackground; - - public ChartPreStylePreView() { - } - - public ChartPreStylePreView(ChartCollection cc) { - this(cc, 1.0, 1.0); - } - - public ChartPreStylePreView(ChartCollection cc, double scaleX, double scaleY) { - this.scaleX = scaleX; - this.scaleY = scaleY; - this.setBorder(BorderFactory.createEmptyBorder(5, 10, 10, 10)); - populate(cc); - } - - public void setCallbackEvent(CallbackEvent callbackEvent) { - this.callbackEvent = callbackEvent; - } - - public void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.translate(BOUNDS, BOUNDS); - g2d.scale(scaleX, scaleY); - super.paintComponent(g); - drawChart(g2d); - g2d.scale(1 / scaleX, 1 / scaleY); - g2d.translate(-BOUNDS, -BOUNDS); - } - - private void drawChart(Graphics2D g2d) { - Dimension d = getBounds().getSize(); - int chartWidth = (int) (d.width / scaleX) - BOUNDS * 2; - int chartHeight = (int) (d.height / scaleX) - BOUNDS * 2; - if (componentBackground != null) { - Graphics clipg = g2d.create(0, 0, chartWidth, chartHeight); - componentBackground.paint(clipg, clipg.getClipBounds()); - } - BaseChartPainter painter = chartCollection.createResultChartPainterWithOutDealFormula(Calculator.createCalculator(), - WebChartIDInfo.createEmptyDesignerInfo(), chartWidth, chartHeight); - painter.paint(g2d, chartWidth, chartHeight, 0, null, callbackEvent); - } - - public void refresh(PredefinedStyle style) { - /*VanChart vanChart = chartCollection.getSelectedChartProvider(VanChart.class); - List chartThemeStyleProviders = vanChart.getChartPreStyleProvider(); - for (ChartThemeStyleProvider chartThemeStyleProvider : chartThemeStyleProviders) { - chartThemeStyleProvider.updateThemeStyle(style); - } - componentBackground = style.getComponentStyle().getBorderStyle().getBackground(); - vanChart.attrChange();*/ - } - - @Override - public void populate(BaseChartCollection cc) { - this.chartCollection = (ChartCollection) cc; - } - - @Override - public BaseChartCollection update() { - return this.chartCollection; - } - - @Override - public void addStopEditingListener(PropertyChangeListener l) { - - } - - - @Override - public void reset() { - - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ComponentPreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ComponentPreviewPane.java deleted file mode 100644 index 1c829c0ee6..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ComponentPreviewPane.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.preview; - -import com.fr.base.FRContext; -import com.fr.base.GraphHelper; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.general.Background; -import com.fr.general.FRFont; -import com.fr.general.act.BorderPacker; -import com.fr.general.act.TitlePacker; -import com.fr.stable.Constants; - -import javax.swing.BorderFactory; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; - -/** - * Created by kerry on 2020-09-04 - */ -public abstract class ComponentPreviewPane extends StyleSettingPreviewPane { - private PredefinedStyle style = new PredefinedStyle(); - private static final int SMALL_GAP = 10; - private static final int GAP = 10; - private JPanel contentPane; - private TitlePreviewPane titlePane; - - - public ComponentPreviewPane() { - this.setBackground(null); - this.setOpaque(false); - this.contentPane = createContentPane(); - this.titlePane = new TitlePreviewPane(); - this.titlePane.setPreferredSize(new Dimension(484, 35)); - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - this.setBorder(BorderFactory.createEmptyBorder(5, 10, 10, 10)); - - this.add(titlePane, BorderLayout.NORTH); - this.add(contentPane, BorderLayout.CENTER); - } - - protected abstract JPanel createContentPane(); - - public void refresh() { - this.repaint(); - } - - public void refresh(PredefinedStyle style) { - this.style = style; - } - - public void paintComponents(Graphics g) { - BorderPacker borderStyle = style.getComponentStyle().getBorderStyle(); - - updateBorders(g, borderStyle); - - paintTitle(g, borderStyle.getTitle()); - - paintContentPane(g, borderStyle); - - super.paintComponents(g); - } - - private void paintContentPane(Graphics g, BorderPacker borderStyle) { - - Graphics clipg; - clipg = g.create(10, 40, this.contentPane.getWidth(), this.contentPane.getHeight()); - if (borderStyle.getBackground() != null) { - borderStyle.getBackground().paint(clipg, clipg.getClipBounds()); - } - clipg.dispose(); - } - - private void paintTitle(Graphics g, TitlePacker titlePacker) { - Background background = titlePacker.getBackground(); - if (background != null) { - background.paint(g, new Rectangle2D.Double(10, 5, this.titlePane.getWidth(), this.titlePane.getHeight())); - } - titlePane.setTitleObject(titlePacker); - titlePane.paintComponent(g); - } - - private void updateBorders(Graphics g, BorderPacker borderStyle) { - if (borderStyle != null) { - borderStyle.paint(g, new Rectangle2D.Double(SMALL_GAP, SMALL_GAP, getWidth() - GAP, getHeight() - SMALL_GAP - GAP)); - } - } - - - private class TitlePreviewPane extends JPanel { - private FRFont frFont = null; - private int titlePosition = Constants.LEFT; - - public TitlePreviewPane() { - this.setBackground(null); - this.setOpaque(false); - frFont = FRContext.getDefaultValues().getFRFont(); - } - - @Override - public void paint(Graphics g) { - - } - - public void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - Dimension d = getSize(); - if (frFont == null) { - return; - } - FontMetrics fm = getFontMetrics(frFont); - if (this.isEnabled()) { - g2d.setColor(frFont.getForeground()); - } else { - g2d.setColor(new Color(237, 237, 237)); - } - g2d.setFont(frFont.applyResolutionNP(96)); - String paintText = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Predefined_Preview_Title_Text"); - int startY = 0, startX = 0; - startX = (d.width - fm.stringWidth(paintText)) / 2; - startY = (d.height - fm.getHeight()) / 2 + fm.getAscent(); - if (this.titlePosition == Constants.LEFT) { - startX = GAP; - } else if (this.titlePosition == Constants.RIGHT) { - startX = d.width - fm.stringWidth(paintText) - GAP - fm.getMaxAdvance(); - } - GraphHelper.drawString(g2d, paintText, startX, startY); - - } - - public void setTitleObject(TitlePacker titlePacker) { - this.frFont = titlePacker.getFrFont(); - this.titlePosition = titlePacker.getPosition(); - } - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ElementCasePreview.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ElementCasePreview.java deleted file mode 100644 index a7ec75e89c..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/ElementCasePreview.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.preview; - -import com.fr.base.ScreenResolution; -import com.fr.base.Style; -import com.fr.config.predefined.PredefinedCellStyle; -import com.fr.config.predefined.PredefinedCellStyleConfig; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.log.FineLoggerFactory; -import com.fr.third.javax.annotation.Nonnull; -import javax.swing.JComponent; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by kerry on 2020-09-04 - */ -public class ElementCasePreview extends ComponentPreviewPane { - private static final List PREVIEW_DATA_LIST = new ArrayList<>(); - private static final String BLANK_CHAR = " "; - private List gridRowPanes; - - static { - readPreviewData(); - } - - private static void readPreviewData() { - try { - InputStream inputStream = ElementCasePreview.class.getResourceAsStream("/com/fr/design/mainframe/predefined/previewData"); - BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, - StandardCharsets.UTF_8)); - String lineTxt = null; - while ((lineTxt = br.readLine()) != null) { - String[] data = lineTxt.split(BLANK_CHAR); - PREVIEW_DATA_LIST.add(data); - } - br.close(); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - } - - - @Override - protected JPanel createContentPane() { - gridRowPanes = new ArrayList<>(); - JPanel jPanel = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane(); - jPanel.setOpaque(false); - jPanel.setBackground(null); - for (int i = 0; i < PREVIEW_DATA_LIST.size(); i++) { - GridRowPane gridRowPane = new GridRowPane(PREVIEW_DATA_LIST.get(i), Style.DEFAULT_STYLE); - gridRowPanes.add(gridRowPane); - jPanel.add(gridRowPane); - } - return jPanel; - } - - - public void refresh(PredefinedStyle style) { - super.refresh(style); - PredefinedCellStyleConfig cellStyleConfig = style.getCellStyleConfig(); - for (int i = 0; i < gridRowPanes.size(); i++) { - Style renderStyle = getMainContentStyle(cellStyleConfig); - if (i == 0) { - renderStyle = getReportHeaderStyle(cellStyleConfig); - } - if (i == PREVIEW_DATA_LIST.size() - 1) { - renderStyle = getHighLightStyle(cellStyleConfig); - } - gridRowPanes.get(i).preview(renderStyle); - } - } - - - private Style getReportHeaderStyle(PredefinedCellStyleConfig config) { - return getCellStyle(config, Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); - } - - private Style getMainContentStyle(PredefinedCellStyleConfig config) { - return getCellStyle(config, Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Main_Text")); - } - - private Style getHighLightStyle(PredefinedCellStyleConfig config) { - return getCellStyle(config, Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); - } - - @Nonnull - private Style getCellStyle(PredefinedCellStyleConfig config, String styleName) { - PredefinedCellStyle cellStyle = config.getStyle(styleName); - if (cellStyle == null) { - return Style.DEFAULT_STYLE; - } - return cellStyle.getStyle(); - } - - - class GridRowPane extends JPanel { - private List gridPreviews = new ArrayList<>(); - - public GridRowPane(String[] data, Style style) { - this.setOpaque(false); - this.setBackground(null); - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel panel = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(4, 0, 0); - panel.setOpaque(false); - panel.setBackground(null); - for (String text : data) { - GridPreview gridPreview = new GridPreview(text); - gridPreviews.add(gridPreview); - panel.add(gridPreview); - } - this.add(panel, BorderLayout.CENTER); - preview(style); - } - - public void preview(Style style) { - for (GridPreview grid : gridPreviews) { - grid.preview(style); - } - } - } - - - private static class GridPreview extends JComponent { - - private Style style = Style.DEFAULT_STYLE; - private String value; - - public GridPreview(String value) { - this.value = value; - setPreferredSize(new Dimension(125, 30)); - } - - public void preview(Style style) { - this.style = style; - } - - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - int resolution = ScreenResolution.getScreenResolution(); - - if (style == Style.DEFAULT_STYLE) { - Style.paintContent(g2d, value, style, getWidth() - 3, getHeight() - 3, resolution); - return; - } - - Style.paintBackground(g2d, style, getWidth(), getHeight()); - - Style.paintContent(g2d, value, style, getWidth() - 3, getHeight() - 3, resolution); - - Style.paintBorder(g2d, style, getWidth() , getHeight() ); - } - - - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); - } - } - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/PredefinedStylePreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/PredefinedStylePreviewPane.java deleted file mode 100644 index 5b6d200491..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/PredefinedStylePreviewPane.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.preview; - -import com.fr.base.background.ColorBackground; -import com.fr.base.chart.chartdata.CallbackEvent; -import com.fr.chart.chartattr.ChartCollection; -import com.fr.chart.chartattr.Title; -import com.fr.chart.charttypes.ChartTypeManager; -import com.fr.config.predefined.PredefinedStyle; -import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.utils.ComponentUtils; -import com.fr.general.Background; -import com.fr.log.FineLoggerFactory; -import com.fr.plugin.chart.attr.axis.VanChartAxis; -import com.fr.plugin.chart.base.AttrLabel; -import com.fr.plugin.chart.base.VanChartTools; -import com.fr.plugin.chart.column.VanChartColumnPlot; -import com.fr.plugin.chart.vanchart.VanChart; - -import javax.swing.JComponent; -import javax.swing.JPanel; -import java.util.ArrayList; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; - -/** - * Created by kerry on 2020-09-06 - */ -public class PredefinedStylePreviewPane extends StyleSettingPreviewPane implements CallbackEvent { - private ElementCasePreview elementCasePreview; - private Background background; - private double scaleX = 1.0; - private double scaleY = 1.0; - private ChartPreStylePreView columnChartPane; - - private int COLUMN_CHART_WIDTH = 517; - private int COLUMN_CHART_HEIGHT = 290; - - private JPanel parent; - - public PredefinedStylePreviewPane() { - this(1.0, 1.0); - } - - public PredefinedStylePreviewPane(double scaleX, double scaleY) { - this.scaleX = scaleX; - this.scaleY = scaleY; - this.setBackground(Color.WHITE); - this.elementCasePreview = new ElementCasePreview(); - this.add(initChartPreViewPane()); - this.elementCasePreview.setPreferredSize(new Dimension(517, 200)); - this.add(this.elementCasePreview); - } - - public void setParent(JPanel parent) { - this.parent = parent; - } - - private JPanel initChartPreViewPane() { - columnChartPane = new ChartPreStylePreView(initVanColumnChart()); - columnChartPane.setPreferredSize(new Dimension(COLUMN_CHART_WIDTH, COLUMN_CHART_HEIGHT)); - columnChartPane.setCallbackEvent(this); - - JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - panel.add(columnChartPane); - return panel; - } - - //柱形图 - private ChartCollection initVanColumnChart() { - try { - VanChart chart = (VanChart) ChartTypeManager.getInstance().getCharts(VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID)[0].clone(); - VanChartTools vanChartTools = chart.getVanChartTools(); - vanChartTools.setSort(false); - vanChartTools.setExport(false); - vanChartTools.setFullScreen(false); - VanChartColumnPlot plot = chart.getPlot(); - AttrLabel defaultAttrLabel = plot.getDefaultAttrLabel(); - defaultAttrLabel.setEnable(true); - defaultAttrLabel.getAttrLabelDetail().getBorder().setBorderStyle(0); - defaultAttrLabel.getAttrLabelDetail().getBackground().setBackground(null); - plot.getConditionCollection().getDefaultAttr().addDataSeriesCondition(defaultAttrLabel); - plot.getLegend().setLegendVisible(false); - plot.getDataSheet().setVisible(true); - - VanChartAxis defaultYAxis = plot.getDefaultYAxis(); - Title title = new Title(); - title.setTextObject(Toolkit.i18nText("Fine-Design_Chart_Axis_Title")); - title.getTextAttr().setRotation(-90); - defaultYAxis.setTitle(title); - defaultYAxis.setShowAxisTitle(true); - - ChartCollection chartCollection = new ChartCollection(chart); - return chartCollection; - } catch (Exception ex) { - FineLoggerFactory.getLogger().error(ex.getMessage(), ex); - } - return null; - } - - @Override - public void refresh() { - - } - - @Override - public void paint(Graphics g) { - ((Graphics2D) g).scale(scaleX, scaleY); - // 禁止双缓冲 - ArrayList dbcomponents = new ArrayList(); - ComponentUtils.disableBuffer(this.elementCasePreview, dbcomponents); - - if (background == null) { - background = ColorBackground.getInstance(Color.WHITE); - } - background.paint(g, new Rectangle2D.Double(0, 0, 517, 500)); - this.columnChartPane.paintComponent(g); - - g.translate(0, COLUMN_CHART_HEIGHT); - this.elementCasePreview.paintComponents(g); - g.translate(0, -COLUMN_CHART_HEIGHT); - // 恢复双缓冲 - ComponentUtils.resetBuffer(dbcomponents); - - } - - @Override - public void paintComponents(Graphics g) { - super.paintComponents(g); - if (background != null) { - background.paint(g, new Rectangle2D.Double(0, 0, this.getWidth(), this.getHeight())); - } - } - - public void refresh(PredefinedStyle style) { - refresh(style, false); - } - - public void refresh(PredefinedStyle style, boolean displayFormBackground) { - elementCasePreview.refresh(style); - columnChartPane.refresh(style); - background = displayFormBackground ? style.getFormBackground().getBackground() : style.getReportBackground(); - this.repaint(); - } - - @Override - public void callback() { - if (parent != null) { - parent.repaint(); - } else { - this.repaint(); - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/StyleSettingPreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/StyleSettingPreviewPane.java deleted file mode 100644 index 4fff5841e8..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/predefined/ui/preview/StyleSettingPreviewPane.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.fr.design.mainframe.predefined.ui.preview; - -import javax.swing.JPanel; - -/** - * Created by kerry on 2020-08-31 - */ -public abstract class StyleSettingPreviewPane extends JPanel { - public StyleSettingPreviewPane() { - - } - - - public abstract void refresh(); - - -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfo.java b/designer-base/src/main/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfo.java index 3d305d8ace..ea8722f1b3 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfo.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfo.java @@ -1,6 +1,5 @@ package com.fr.design.mainframe.reuse; -import com.fr.design.DesignerEnvManager; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLable; import com.fr.stable.xml.XMLableReader; @@ -10,6 +9,7 @@ import com.fr.stable.xml.XMLableReader; */ public class ComponentReuseNotificationInfo implements XMLable { public static final String XML_TAG = "ComponentReuseNotificationInfo"; + private static final int INVALID_NUM = -1; private static final ComponentReuseNotificationInfo INSTANCE = new ComponentReuseNotificationInfo(); @@ -17,51 +17,66 @@ public class ComponentReuseNotificationInfo implements XMLable { return INSTANCE; } - private long lastNotifyTime = 0; + private boolean clickedWidgetLib = false; - private int notifiedNumber = 0; + private long firstDragEndTime = 0L; - private boolean clickedWidgetLib = false; + private boolean completeEmbedFilter = false; - private long lastGuidePopUpTime = 0; + private boolean firstDrag = true; private String historyCreatedReuses = "[]"; - public long getLastNotifyTime() { - return lastNotifyTime; + private boolean widgetLibHasRefreshed = false; + + private boolean completeFirstShowComponentLib = false; + + public boolean isClickedWidgetLib() { + return clickedWidgetLib; } - public void setLastNotifyTime(long lastNotifyTime) { - this.lastNotifyTime = lastNotifyTime; + public void setClickedWidgetLib(boolean clickedWidgetLib) { + this.clickedWidgetLib = clickedWidgetLib; } - public int getNotifiedNumber() { - return notifiedNumber; + public boolean isCompleteEmbedFilter() { + return completeEmbedFilter; } - public void setNotifiedNumber(int notifiedNumber) { - this.notifiedNumber = notifiedNumber; + public void setCompleteEmbedFilter(boolean completeEmbedFilter) { + this.completeEmbedFilter = completeEmbedFilter; } - public boolean isClickedWidgetLib() { - return clickedWidgetLib; + public long getFirstDragEndTime() { + return firstDragEndTime; } - public void setClickedWidgetLib(boolean clickedWidgetLib) { - this.clickedWidgetLib = clickedWidgetLib; + public void setFirstDragEndTime(long firstDragEndTime) { + this.firstDragEndTime = firstDragEndTime; } - public long getLastGuidePopUpTime() { - return lastGuidePopUpTime; + public boolean isFirstDrag() { + return firstDrag; } - public void setLastGuidePopUpTime(long lastGuidePopUpTime) { - this.lastGuidePopUpTime = lastGuidePopUpTime; + public void setFirstDrag(boolean firstDrag) { + this.firstDrag = firstDrag; } - public void updateLastGuidePopUpTime() { - this.setLastGuidePopUpTime(System.currentTimeMillis()); - DesignerEnvManager.getEnvManager().saveXMLFile(); + public boolean isWidgetLibHasRefreshed() { + return widgetLibHasRefreshed; + } + + public void setWidgetLibHasRefreshed(boolean widgetLibHasRefreshed) { + this.widgetLibHasRefreshed = widgetLibHasRefreshed; + } + + public boolean isCompleteFirstShowComponentLib() { + return completeFirstShowComponentLib; + } + + public void setCompleteFirstShowComponentLib(boolean completeFirstShowComponentLib) { + this.completeFirstShowComponentLib = completeFirstShowComponentLib; } public String getHistoryCreatedReuses() { @@ -72,23 +87,41 @@ public class ComponentReuseNotificationInfo implements XMLable { this.historyCreatedReuses = historyCreatedReuses; } + //兼容老版本云端埋点的记录 + public long getLastNotifyTime() { + return INVALID_NUM; + } + + public int getNotifiedNumber() { + return INVALID_NUM; + } + + public long getLastGuidePopUpTime() { + return INVALID_NUM; + } + @Override public void readXML(XMLableReader reader) { - this.setLastNotifyTime(reader.getAttrAsLong("lastNotifyTime", 0L)); - this.setNotifiedNumber(reader.getAttrAsInt("notifiedNumber", 0)); this.setClickedWidgetLib(reader.getAttrAsBoolean("clickedWidgetLib", false)); - this.setLastGuidePopUpTime(reader.getAttrAsLong("lastGuidePopUpTime", 0L)); + this.setCompleteEmbedFilter(reader.getAttrAsBoolean("completeEmbedFilter", false)); + this.setCompleteFirstShowComponentLib(reader.getAttrAsBoolean("completeFirstShowComponentLib", false)); + this.setWidgetLibHasRefreshed(reader.getAttrAsBoolean("widgetLibHasRefreshed", false)); + this.setFirstDrag(reader.getAttrAsBoolean("firstDrag", true)); this.setHistoryCreatedReuses(reader.getAttrAsString("historyCreatedReuses", "[]")); + this.setFirstDragEndTime(reader.getAttrAsLong("firstDragEndTime", 0L)); } @Override public void writeXML(XMLPrintWriter writer) { writer.startTAG("ComponentReuseNotificationInfo"); - writer.attr("lastNotifyTime", this.lastNotifyTime) - .attr("notifiedNumber", this.notifiedNumber) - .attr("clickedWidgetLib", this.clickedWidgetLib) - .attr("lastGuidePopUpTime", this.lastGuidePopUpTime) - .attr("historyCreatedReuses", this.historyCreatedReuses);; + writer.attr("clickedWidgetLib", this.clickedWidgetLib) + .attr("completeEmbedFilter", this.completeEmbedFilter) + .attr("completeFirstShowComponentLib", this.completeFirstShowComponentLib) + .attr("firstDrag", this.firstDrag) + .attr("widgetLibHasRefreshed", this.widgetLibHasRefreshed) + .attr("firstDragEndTime", this.firstDragEndTime) + .attr("historyCreatedReuses", this.historyCreatedReuses); + ; writer.end(); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/reuse/ReuseGuideDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/reuse/ReuseGuideDialog.java deleted file mode 100644 index a0e9166592..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/reuse/ReuseGuideDialog.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.fr.design.mainframe.reuse; - -import com.fr.base.background.ColorBackground; -import com.fr.design.dialog.UIDialog; -import com.fr.design.gui.ilable.UILabel; -import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.PromptWindow; -import com.fr.design.mainframe.share.collect.ComponentCollector; -import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.IOUtils; - -import javax.swing.BorderFactory; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JPanel; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dialog; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Font; -import java.awt.Frame; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.RenderingHints; -import java.awt.geom.RoundRectangle2D; - -public class ReuseGuideDialog extends UIDialog implements PromptWindow { - InnerDialog innerDialog; - private static final Dimension DEFAULT = new Dimension(735, 510); - - public ReuseGuideDialog(Frame parent) { - super(parent); - } - - @Override - public void showWindow() { - innerDialog = new InnerDialog(this); - JPanel backGroundPane = new JPanel() { - @Override - protected void paintComponent(Graphics g) { - Image icon = IOUtils.readImage("com/fr/base/images/share/background.png");// 003.jpg是测试图片在项目的根目录下 - g.drawImage(icon, 0, 0, getSize().width, getSize().height, this);// 图片会自动缩放 - } - }; - add(backGroundPane, BorderLayout.CENTER); - initStyle(); - innerDialog.showWindow(); - } - - private void initStyle() { - setSize(DEFAULT); - setUndecorated(true); - setBackground(new Color(0, 0, 0, 0)); - GUICoreUtils.centerWindow(this); - } - - @Override - public void hideWindow() { - ComponentReuseNotificationInfo.getInstance().updateLastGuidePopUpTime(); - this.setVisible(false); - if (innerDialog != null) { - innerDialog.setVisible(false); - innerDialog.dispose(); - innerDialog = null; - } - this.dispose(); - } - - @Override - public void checkValid() { - - } - - class InnerDialog extends UIDialog { - private final Dimension DEFAULT = new Dimension(700, 475); - private static final int TITLE_FONT_SIZE = 20; - - public InnerDialog(Dialog dialog) { - super(dialog); - } - - public void showWindow() { - add(createCenterPanel(), BorderLayout.CENTER); - add(createSouthPanel(), BorderLayout.SOUTH); - add(createNorthPanel(), BorderLayout.NORTH); - showDialog(); - } - - private JPanel createNorthPanel() { - JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); - - //右上角关闭按钮 - JButton button = new JButton(new ImageIcon(IOUtils.readImage("/com/fr/base/images/share/close.png").getScaledInstance(15, 15, Image.SCALE_SMOOTH))); - button.setBorder(null); - button.setOpaque(false); - button.addActionListener(e -> ReuseGuideDialog.this.hideWindow()); - - northPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 15)); - northPanel.setOpaque(false); - northPanel.add(button); - return northPanel; - } - - private JPanel createCenterPanel() { - JPanel centerPanel = new JPanel(new BorderLayout()); - - UILabel titleLabel = new UILabel(Toolkit.i18nText("Fine-Design_Share_Drag_And_Make_Component")); - UILabel imageLabel = new UILabel(new ImageIcon(IOUtils.readImage("com/fr/design/images/dashboard/guide.png").getScaledInstance(DEFAULT.width, DEFAULT.height, Image.SCALE_SMOOTH))); - titleLabel.setFont(new Font(titleLabel.getFont().getName(), Font.BOLD, TITLE_FONT_SIZE)); - titleLabel.setBorder(BorderFactory.createEmptyBorder()); - - JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER)); - panel.setOpaque(false); - panel.add(titleLabel); - - centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); - centerPanel.setOpaque(false); - centerPanel.add(imageLabel, BorderLayout.CENTER); - centerPanel.add(panel, BorderLayout.NORTH); - return centerPanel; - } - - private JPanel createSouthPanel() { - JPanel southPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - - JButton button = new JButton(Toolkit.i18nText("Fine-Design_Share_Try_Drag")) { - @Override - public void paint(Graphics g) { - ColorBackground buttonBackground = ColorBackground.getInstance(Color.decode("#419BF9")); - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - buttonBackground.paint(g2d, new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 8, 8)); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - super.paint(g); - } - }; - button.setBorder(null); - button.setForeground(Color.WHITE); - button.setOpaque(false); - button.addActionListener(e -> ReuseGuideDialog.this.hideWindow()); - - southPanel.setBorder(BorderFactory.createEmptyBorder(0, 290, 19, 290)); - southPanel.setPreferredSize(new Dimension(DEFAULT.width, 51)); - southPanel.setOpaque(false); - southPanel.add(button); - return southPanel; - } - - /** - * 显示窗口 - */ - private void showDialog() { - setSize(DEFAULT); - setUndecorated(true); - GUICoreUtils.centerWindow(this); - setModalityType(ModalityType.APPLICATION_MODAL); - ReuseGuideDialog.this.setVisible(true); - setVisible(true); - } - - @Override - public void checkValid() { - - } - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/ComponentShareUtil.java b/designer-base/src/main/java/com/fr/design/mainframe/share/ComponentShareUtil.java new file mode 100644 index 0000000000..2445826128 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/ComponentShareUtil.java @@ -0,0 +1,111 @@ +package com.fr.design.mainframe.share; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.locale.impl.ShowOnlineWidgetMark; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.reuse.ComponentReuseNotificationInfo; +import com.fr.form.share.constants.ComponentPath; +import com.fr.form.share.group.filter.ReuFilter; +import com.fr.design.DesignerCloudURLManager; +import com.fr.general.locale.LocaleCenter; +import com.fr.general.locale.LocaleMark; +import com.fr.workspace.WorkContext; + +/** + * Created by kerry on 2021/10/27 + */ +public class ComponentShareUtil { + private ComponentShareUtil() { + + } + + /** + * 判断是否需要切换到在线组件库 + * + * @return + */ + public static boolean needSwitch2OnlineTab() { + return DesignerCloudURLManager.getInstance().isConnected() && !hasTouched() && isCurrentTplNewCreate() && isShowOnlineWidgetRepoPane(); + } + + public static boolean isShowOnlineWidgetRepoPane() { + LocaleMark localeMark = LocaleCenter.getMark(ShowOnlineWidgetMark.class); + return localeMark.getValue(); + } + + public static boolean isShowMiniShopWindow() { + return isShowOnlineWidgetRepoPane(); + } + + /** + * 判断是否可触达 + * + * @return boolean + */ + public static boolean hasTouched() { + String sharePath = ComponentPath.SHARE_PATH.path(); + String[] components = WorkContext.getWorkResource().list(sharePath, new ReuFilter()); + return components != null && components.length > 6; + } + + /** + * 判断当前模板是否是新建模板 + * + * @return boolean + */ + public static boolean isCurrentTplNewCreate() { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + return jTemplate.isNewCreateTpl(); + } + + /** + * 判断是否在需要展示组件库界面 + * + * @return boolean + */ + public static boolean needShowEmbedFilterPane() { + return !ComponentReuseNotificationInfo.getInstance().isCompleteEmbedFilter() && !hasTouched() && isCurrentTplNewCreate(); + } + + public static boolean needShowComponentLib() { + return !ComponentReuseNotificationInfo.getInstance().isCompleteFirstShowComponentLib() && !hasTouched() && isCurrentTplNewCreate(); + } + + /** + * 判断是否需要展示首次拖拽动效 + * + * @return boolean + */ + public static boolean needShowFirstDragAnimate() { + return ComponentReuseNotificationInfo.getInstance().isFirstDrag(); + } + + /** + * 完成嵌入式筛选 + */ + public static void completeEmbedFilter() { + boolean changed = false; + if (!ComponentReuseNotificationInfo.getInstance().isWidgetLibHasRefreshed()) { + ComponentReuseNotificationInfo.getInstance().setWidgetLibHasRefreshed(true); + changed = true; + } + if (!ComponentReuseNotificationInfo.getInstance().isCompleteEmbedFilter()) { + ComponentReuseNotificationInfo.getInstance().setCompleteEmbedFilter(true); + changed = true; + } + if (changed) { + DesignerEnvManager.getEnvManager().saveXMLFile(); + } + } + + /** + * 记录组件库刷新 + */ + public static void recordWidgetLibHasRefreshed() { + if (!ComponentReuseNotificationInfo.getInstance().isWidgetLibHasRefreshed()) { + ComponentReuseNotificationInfo.getInstance().setWidgetLibHasRefreshed(true); + DesignerEnvManager.getEnvManager().saveXMLFile(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentCollector.java index 3ea805deb0..4776739784 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentCollector.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentCollector.java @@ -4,6 +4,7 @@ import com.fr.base.io.XMLReadHelper; import com.fr.config.MarketConfig; import com.fr.design.DesignerEnvManager; import com.fr.design.mainframe.reuse.ComponentReuseNotificationInfo; +import com.fr.design.mainframe.share.ComponentShareUtil; import com.fr.form.share.DefaultSharableWidget; import com.fr.form.share.SharableWidgetProvider; import com.fr.form.share.constants.ComponentPath; @@ -19,7 +20,6 @@ import com.fr.json.JSONException; import com.fr.json.JSONFactory; import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; -import com.fr.plugin.context.PluginContexts; import com.fr.stable.ProductConstants; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; @@ -48,10 +48,6 @@ import java.util.Iterator; public class ComponentCollector implements XMLable { private static final long ONE_MINUTE = 60 * 1000L; - private static final int REUSE_INFO_FIRST_POPUP = 1; - - private static final int REUSE_INFO_SECOND_POPUP = 2; - private static final String SIMPLE_DATE_PATTERN = "yyyy-MM-dd"; private static final String XML = "ComponentCollector"; @@ -98,11 +94,11 @@ public class ComponentCollector implements XMLable { private static final String MARKET_CLICK = "marketClick"; - private static final String PROMPT_JUMP = "promptJump"; + private static final String FIRST_SHOW_REACT = "firstShowReact"; - private static final String TOOLBAR_JUMP = "toolbarJump"; + private static final String EMBEDED_FILTER_REACT = "embededFilterReact"; - private static final String POPUP_JUMP = "popupJump"; + private static final String DYNAMIC_EFFECT_REACT = "dynamicEffectReact"; private static final String uuid = DesignerEnvManager.getEnvManager().getUUID(); @@ -116,11 +112,11 @@ public class ComponentCollector implements XMLable { private int cmpBoardClick = 0; - private int promptJump = 0; + private int firstShowReact = 0; - private int toolbarJump = 0; + private int embededFilterReact = 0; - private int popupJump = 0; + private int dynamicEffectReact = 0; private JSONArray activateRecord = JSONFactory.createJSON(JSON.ARRAY); @@ -288,12 +284,17 @@ public class ComponentCollector implements XMLable { private JSONArray getGroupingDetail() { JSONArray ja = JSONFactory.createJSON(JSON.ARRAY); - Group[] groups = DefaultShareGroupManager.getInstance().getAllGroup(); - for(Group group : groups) { - JSONObject jo = JSONFactory.createJSON(JSON.OBJECT); - jo.put(GROUP_NAME, group.getGroupName()); - jo.put(CONTAIN_AMOUNT, group.getAllBindInfoList().length); - ja.add(jo); + try { + DefaultShareGroupManager.getInstance().refresh(); + Group[] groups = DefaultShareGroupManager.getInstance().getAllGroup(); + for (Group group : groups) { + JSONObject jo = JSONFactory.createJSON(JSON.OBJECT); + jo.put(GROUP_NAME, group.getGroupName()); + jo.put(CONTAIN_AMOUNT, group.getAllBindInfoList().length); + ja.add(jo); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); } return ja; } @@ -333,41 +334,47 @@ public class ComponentCollector implements XMLable { saveInfo(); } - public void collectPromptJumpWhenJump(){ - if (ComponentReuseNotificationInfo.getInstance().getNotifiedNumber() == REUSE_INFO_FIRST_POPUP) { - this.promptJump = 1; - saveInfo(); - }else if(ComponentReuseNotificationInfo.getInstance().getNotifiedNumber() == REUSE_INFO_SECOND_POPUP){ - this.promptJump = 2; - saveInfo(); + public void collectFirstShowReact(int flag) { + if (this.firstShowReact == flag) { + return; } + this.firstShowReact = flag; + saveInfo(); } - - public void collectPromptJumpWhenShow() { - if (ComponentReuseNotificationInfo.getInstance().getNotifiedNumber() == REUSE_INFO_SECOND_POPUP) { - this.promptJump = -1; - saveInfo(); + public void clickComponentSetting() { + int firstShowReact = ComponentReuseNotificationInfo.getInstance().isWidgetLibHasRefreshed() ? 2 : -1; + if (this.firstShowReact != firstShowReact) { + collectFirstShowReact(firstShowReact); + } + if (this.embededFilterReact == 0 && ComponentReuseNotificationInfo.getInstance().isWidgetLibHasRefreshed()) { + collectEmbededFilterReact(-1); } } - public void collectToolbarJump() { - if (this.toolbarJump == 0) { - this.toolbarJump = 1; - saveInfo(); + public void collectEmbededFilterReact(int flag) { + if (this.embededFilterReact == flag) { + return; } - + this.embededFilterReact = flag; + saveInfo(); } - public void collectPopupJump() { - long currentTime = System.currentTimeMillis(); - long lastGuidePopUpTime = ComponentReuseNotificationInfo.getInstance().getLastGuidePopUpTime(); - if (currentTime - lastGuidePopUpTime <= ONE_MINUTE && this.popupJump == 0) { - this.popupJump = 1; - saveInfo(); + public void collectDynamicEffectReact() { + if (this.dynamicEffectReact == 1) { + return; } + if (System.currentTimeMillis() - ComponentReuseNotificationInfo.getInstance().getFirstDragEndTime() <= ONE_MINUTE) { + collectDynamicEffectReactFlag(1); + } + } + + public void collectDynamicEffectReactFlag(int flag) { + this.dynamicEffectReact = flag; + saveInfo(); } + public void clearSortType() { sortType = JSONFactory.createJSON(JSON.ARRAY); } @@ -463,6 +470,10 @@ public class ComponentCollector implements XMLable { this.generateCmpNumber = reader.getAttrAsInt("generateCmpNumber", 0); this.uploadCmpNumber = reader.getAttrAsInt("uploadCmpNumber", 0); + this.firstShowReact = reader.getAttrAsInt(FIRST_SHOW_REACT, 0); + this.embededFilterReact = reader.getAttrAsInt(EMBEDED_FILTER_REACT, 0); + this.dynamicEffectReact = reader.getAttrAsInt(DYNAMIC_EFFECT_REACT, 0); + String activateRecordStr = reader.getAttrAsString("activateRecord", StringUtils.EMPTY); activateRecord = parseJSONArray(activateRecordStr); String generateCmpRecordStr = reader.getAttrAsString("generateCmpRecord", StringUtils.EMPTY); @@ -470,13 +481,9 @@ public class ComponentCollector implements XMLable { this.helpConfigInfo = parseJSONArray(reader.getAttrAsString(HELP_CONFIG_INFO, StringUtils.EMPTY)); this.helpConfigUseInfo = parseJSONArray(reader.getAttrAsString(HELP_CONFIG_USE_INFO, StringUtils.EMPTY)); - this.searchContent = parseJSONArray(reader.getAttrAsString(SEARCH_CONTENT,StringUtils.EMPTY)); + this.searchContent = parseJSONArray(reader.getAttrAsString(SEARCH_CONTENT, StringUtils.EMPTY)); this.filterContent = parseJSONArray(reader.getAttrAsString(FILTER_CONTENT, StringUtils.EMPTY)); this.sortType = parseJSONArray(reader.getAttrAsString(SORT_TYPE, StringUtils.EMPTY)); - this.promptJump = reader.getAttrAsInt(PROMPT_JUMP, 0); - this.toolbarJump = reader.getAttrAsInt(TOOLBAR_JUMP, 0); - this.popupJump = reader.getAttrAsInt(POPUP_JUMP, 0); - } } @@ -510,9 +517,9 @@ public class ComponentCollector implements XMLable { .attr(SEARCH_CONTENT, searchContent.toString()) .attr(FILTER_CONTENT, filterContent.toString()) .attr(SORT_TYPE, sortType.toString()) - .attr(PROMPT_JUMP, promptJump) - .attr(TOOLBAR_JUMP, toolbarJump) - .attr(POPUP_JUMP, popupJump) + .attr(FIRST_SHOW_REACT, firstShowReact) + .attr(EMBEDED_FILTER_REACT, embededFilterReact) + .attr(DYNAMIC_EFFECT_REACT, dynamicEffectReact) .end(); } @@ -525,7 +532,7 @@ public class ComponentCollector implements XMLable { jo.put("userId", MarketConfig.getInstance().getBBSAttr().getBbsUid()); jo.put("uuid", uuid); jo.put("cmpBoardClickDaily", cmpBoardClickDaily()); - jo.put("pluginVersion", GeneralUtils.readBuildNO()); + jo.put("pluginVersion", GeneralUtils.getVersion()); jo.put("localCmpNumber", localCmpNumber); jo.put("remoteCmpNumber", remoteCmpNumber); jo.put("uploadCmpNumber", uploadCmpNumber); @@ -537,15 +544,9 @@ public class ComponentCollector implements XMLable { jo.put(SEARCH_CONTENT, searchContent.toString()); jo.put(FILTER_CONTENT, filterContent.toString()); jo.put(SORT_TYPE, sortType.toString()); - jo.put("guideInfo", assembleGuideInfo()); - return jo.toString(); - } - - private String assembleGuideInfo() { - JSONObject jo = JSONFactory.createJSON(JSON.OBJECT); - jo.put(PROMPT_JUMP, promptJump) - .put(TOOLBAR_JUMP, toolbarJump) - .put(POPUP_JUMP, popupJump); + jo.put(FIRST_SHOW_REACT, firstShowReact); + jo.put(EMBEDED_FILTER_REACT, embededFilterReact); + jo.put(DYNAMIC_EFFECT_REACT, dynamicEffectReact); return jo.toString(); } @@ -598,7 +599,7 @@ public class ComponentCollector implements XMLable { return JSONFactory.createJSON(JSON.ARRAY); } - public void clear(){ + public void clear() { clearActiveRecord(); clearGenerateCmpRecord(); clearFilterContent(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java b/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java index 5043e5fb7d..8941cfba80 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java @@ -17,13 +17,7 @@ public class ComponentSender { private static final String CLOUD_REUSE_URL = "https://cloud.fanruan.com/api/monitor/record_of_reusePlugin/single"; public static boolean send() { - - long start = System.currentTimeMillis(); - String content = ComponentCollector.getInstance().generateTotalInfo(); - - long end = System.currentTimeMillis(); - FineLoggerFactory.getLogger().error("cal time cost {} ms", end - start); return sendInfo(CLOUD_REUSE_URL, content); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java new file mode 100644 index 0000000000..dd76befe66 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java @@ -0,0 +1,37 @@ +package com.fr.design.mainframe.share.mini; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; + +import javax.swing.JOptionPane; +import java.awt.Component; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public class MiniShopDisposingChecker { + + public static boolean check() { + return check(DesignerContext.getDesignerFrame()); + } + + public static boolean check(Component optionParentComponent) { + if (MiniShopNativeTaskManager.getInstance().hasExecutingTasks()) { + int result = FineJOptionPane.showConfirmDialog( + optionParentComponent, + Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Close_Tip"), + "", + FineJOptionPane.YES_NO_OPTION + ); + if (result == JOptionPane.YES_OPTION) { + MiniShopNativeTaskManager.getInstance().cancelAllExecutingTasks(); + return true; + } + return false; + } + return true; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java new file mode 100644 index 0000000000..9144f2fa0d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java @@ -0,0 +1,11 @@ +package com.fr.design.mainframe.share.mini; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public interface MiniShopNativeTask { + void execute(); + void cancel(); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java new file mode 100644 index 0000000000..514ff84c82 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java @@ -0,0 +1,42 @@ +package com.fr.design.mainframe.share.mini; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public class MiniShopNativeTaskManager { + private MiniShopNativeTaskManager() { + } + private static class HOLDER { + private static final MiniShopNativeTaskManager singleton = new MiniShopNativeTaskManager(); + } + public static MiniShopNativeTaskManager getInstance() { + return MiniShopNativeTaskManager.HOLDER.singleton; + } + + + private static final Set executingTasks = new HashSet<>(); + + public void addStartedTask(MiniShopNativeTask task) { + executingTasks.add(task); + } + + public void removeCompletedTask(MiniShopNativeTask task) { + executingTasks.remove(task); + } + + public boolean hasExecutingTasks() { + return !executingTasks.isEmpty(); + } + + public void cancelAllExecutingTasks() { + for (MiniShopNativeTask executingTask: executingTasks) { + executingTask.cancel(); + } + executingTasks.clear(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/simple/SimpleDesignerConfig.java b/designer-base/src/main/java/com/fr/design/mainframe/simple/SimpleDesignerConfig.java new file mode 100644 index 0000000000..0f14fef756 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/simple/SimpleDesignerConfig.java @@ -0,0 +1,83 @@ +package com.fr.design.mainframe.simple; + +import com.fr.json.JSONObject; +import com.fr.stable.StringUtils; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Wei + * 一个简单属性(字符串)存储类,用于自定义简单属性的存储 + * 如:getInstance("FVSDesignerConfig")可在FineReportEnv.xml中定义一个存储FVS相关配置 + */ +public class SimpleDesignerConfig implements XMLable { + + private static final Map configs = new HashMap<>(); + + private SimpleDesignerConfig(String name) { + this.name = name; + } + + public static SimpleDesignerConfig getInstance(String name) { + SimpleDesignerConfig config = configs.get(name); + if (config == null) { + config = new SimpleDesignerConfig(name); + configs.put(name, config); + } + return config; + } + + private String name = ""; + + private JSONObject content = new JSONObject(); + + public void addAttr(String key, String value) { + content.put(key, value); + } + + public JSONObject getContent() { + return content; + } + + public void setContent(JSONObject content) { + this.content = content; + } + + + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + String rawContent = reader.getAttrAsString("content", null); + if (StringUtils.isNotBlank(rawContent)) { + this.content = new JSONObject(rawContent); + } + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(name); + if (this.content != null) { + writer.attr("content", this.content.toString()); + } + writer.end(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + SimpleDesignerConfig cloned = (SimpleDesignerConfig) super.clone(); + if (this.content != null) { + cloned.content = new JSONObject(this.content.toString()); + } + cloned.name = this.name; + return cloned; + } + + public String getName() { + return name; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java index 798bb73c59..eb15a657f5 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java @@ -4,12 +4,14 @@ import com.fr.base.theme.FormTheme; import com.fr.base.theme.TemplateThemeConfig; import com.fr.base.theme.settings.ThemedComponentStyle; import com.fr.base.theme.settings.ThemedFormBodyStyle; +import com.fr.design.ExtraDesignClassManager; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.theme.edit.ChartStyleFormEditPane; import com.fr.design.mainframe.theme.edit.ComponentStyleEditPane; import com.fr.design.mainframe.theme.edit.FormBodyStyleEditPane; import com.fr.design.mainframe.theme.preview.FormThemePreviewPane; +import com.fr.design.mainframe.theme.processor.ThemePreviewPaneProcessor; import javax.swing.JPanel; @@ -31,7 +33,11 @@ public class FormThemeProfilePane extends TemplateThemeProfilePane { } @Override - public FormThemePreviewPane createThemePreviewPane() { + public TemplateThemePreviewPane createThemePreviewPane() { + ThemePreviewPaneProcessor processor = ExtraDesignClassManager.getInstance().getSingle(ThemePreviewPaneProcessor.XML_TAG); + if (processor != null) { + return processor.createFormThemePreviewPane(); + } return new FormThemePreviewPane(); } @@ -61,6 +67,7 @@ public class FormThemeProfilePane extends TemplateThemeProfilePane { componentStyleSettingPane = new ComponentStyleEditPane(); addCustomEditorPane(i18nText("Fine-Design_Predefined_Component_Style"), componentStyleSettingPane); + refreshExtraAdvancedPane(); } @Override diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java index f0f25f677f..57e6ddf5f1 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java @@ -2,10 +2,11 @@ package com.fr.design.mainframe.theme; import com.fr.base.theme.ReportTheme; import com.fr.base.theme.TemplateThemeConfig; +import com.fr.design.ExtraDesignClassManager; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.theme.edit.ReportBodyStyleEditPane; import com.fr.design.mainframe.theme.preview.ReportThemePreviewPane; -import javax.swing.JPanel; +import com.fr.design.mainframe.theme.processor.ThemePreviewPaneProcessor; /** * @author Starryi @@ -20,7 +21,11 @@ public class ReportThemeProfilePane extends TemplateThemeProfilePane createThemePreviewPane() { + ThemePreviewPaneProcessor processor = ExtraDesignClassManager.getInstance().getSingle(ThemePreviewPaneProcessor.XML_TAG); + if (processor != null) { + return processor.createReportThemePreviewPane(); + } return new ReportThemePreviewPane(); } @@ -44,6 +49,7 @@ public class ReportThemeProfilePane extends TemplateThemeProfilePane extends J protected ColorListPane colorListPane; protected CellStyleListEditPane cellStyleSettingPane; protected ChartStyleEditPane chartStyleSettingPane; + protected final List> extraPaneList = new ArrayList<>(); protected boolean isPopulating = false; protected UITabbedPane uiTabbedPane; @@ -158,13 +165,9 @@ public abstract class TemplateThemeEditorPane extends J return container; } private void onColorSchemeChanged(List colors) { - FineColorManager.FineColorReplaceByColorScheme replaceByColorScheme = new FineColorManager.FineColorReplaceByColorScheme(colors); T theme = updateBean(); - FineColorFlushUtils.replaceCacheObject(theme, replaceByColorScheme); - FineColorManager.traverse(theme, replaceByColorScheme); + theme = (T) FineColorSynchronizer.flush(theme, colors); populateBean4CustomEditors(theme); - //图表渐变色 - chartStyleSettingPane.populateGradientBar(colors); this.repaint(); } @@ -175,7 +178,7 @@ public abstract class TemplateThemeEditorPane extends J uiTabbedPane = new UITabbedPane(); uiTabbedPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 1)); container.add(uiTabbedPane, BorderLayout.CENTER); - + initPluginListener(); return container; } @@ -196,6 +199,33 @@ public abstract class TemplateThemeEditorPane extends J }); uiTabbedPane.addTab(title, settingPane); } + + protected void refreshExtraAdvancedPane() { + extraPaneList.clear(); + Set> providers = ExtraDesignClassManager.getInstance().getArray(TemplateThemePaneProvider.XML_TAG); + for (TemplateThemePaneProvider provider : providers) { + insertShortCut(provider.getInsertPosition(extraPaneList.size()), provider.getTab()); + } + for (BasicBeanPane pane : extraPaneList) { + addCustomEditorPane(pane.getTitle(), pane); + } + } + + private void insertShortCut(int index, BasicBeanPane pane) { + int size = extraPaneList.size(); + index = Math.min(index, size); + extraPaneList.add(index, pane); + } + + private void initPluginListener() { + GeneralContext.listenPluginRunningChanged(new PluginEventListener() { + @Override + public void on(PluginEvent event) { + refreshExtraAdvancedPane(); + } + }, pluginContext -> pluginContext.getRuntime().contain(TemplateThemePaneProvider.XML_TAG)); + } + protected JPanel createCellStyleSettingPane() { JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); cellStyleSettingPane = new CellStyleListEditPane(); @@ -227,6 +257,9 @@ public abstract class TemplateThemeEditorPane extends J colorListPane.populate(theme.getColorScheme().getColors()); populateBean4CustomEditors(theme); + for (BasicBeanPane pane : extraPaneList) { + pane.populateBean(theme); + } isPopulating = false; } @@ -247,7 +280,9 @@ public abstract class TemplateThemeEditorPane extends J theme.setColorScheme(colorScheme); updateBean4CustomEditors(theme); - + for (BasicBeanPane pane : extraPaneList) { + pane.updateBean(theme); + } return theme; } @@ -267,6 +302,10 @@ public abstract class TemplateThemeEditorPane extends J return nameTextField.checkValid(); } + public String getThemeName() { + return nameTextField.getText(); + } + public List getCurrentColorScheme() { return colorListPane.update(); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java index f721923e94..cdbd6d10f2 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridControlPane.java @@ -22,6 +22,7 @@ import com.fr.design.menu.ToolBarDef; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import com.fr.third.javax.annotation.Nullable; import com.fr.transaction.CallBackAdaptor; import javax.swing.BorderFactory; @@ -43,6 +44,8 @@ import java.awt.Stroke; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import static com.fr.design.i18n.Toolkit.i18nText; @@ -63,27 +66,31 @@ public class TemplateThemeGridControlPane extends Basic private final AsyncThemeFetcher asyncThemeFetcher; - public static TemplateThemeGridControlPane createFormThemesManagerPane() { + private final Window window; + + public static TemplateThemeGridControlPane createFormThemesManagerPane(@Nullable Window window) { FormThemeConfig config = FormThemeConfig.getInstance(); FormThemeProfilePane editPane = new FormThemeProfilePane(config); - return new TemplateThemeGridControlPane<>(config, editPane); + return new TemplateThemeGridControlPane<>(window, config, editPane); } - public static TemplateThemeGridControlPane createReportThemesManagerPane() { + public static TemplateThemeGridControlPane createReportThemesManagerPane(@Nullable Window window) { ReportThemeConfig config = ReportThemeConfig.getInstance(); ReportThemeProfilePane editPane = new ReportThemeProfilePane(config); - return new TemplateThemeGridControlPane<>(config, editPane); + return new TemplateThemeGridControlPane<>(window, config, editPane); } - public TemplateThemeGridControlPane(TemplateThemeConfig config, TemplateThemeProfilePane profilePane) { + public TemplateThemeGridControlPane(@Nullable Window window, TemplateThemeConfig config, TemplateThemeProfilePane profilePane) { + this.window = window; this.config = config; this.profilePane = profilePane; - this.themeListPane = new TemplateThemeGridPane<>(true, config, profilePane); + this.themeListPane = new TemplateThemeGridPane<>(window, true, config, profilePane); this.removeAction = new RemoveThemeAction(false); this.setTheme4NewTemplateButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Pane_Default_Setting")); this.asyncThemeFetcher = new AsyncThemeFetcher<>(1, config); initializePane(); + registerWindowListener(); } public TemplateThemeConfig getConfig() { @@ -117,6 +124,18 @@ public class TemplateThemeGridControlPane extends Basic repaint(); } + private void registerWindowListener() { + if (window != null) { + window.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + super.windowClosed(e); + asyncThemeFetcher.shutdown(); + } + }); + } + } + private void resetEnableRemoveAction(T selectedTheme, RemoveThemeAction removeAction) { if (selectedTheme == null) { removeAction.setEnabled(false); @@ -254,7 +273,6 @@ public class TemplateThemeGridControlPane extends Basic setName(name); setMnemonic('R'); this.prototypeThemeName = prototypeThemeName; - asyncThemeFetcher.submit(prototypeThemeName, null); } @Override @@ -308,17 +326,4 @@ public class TemplateThemeGridControlPane extends Basic g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } } - - public void startListenThemeConfig() { - themeListPane.startListenThemeConfig(); - } - - public void stopListenThemeConfig() { - themeListPane.stopListenThemeConfig(); - } - - public void stopAsyncFetchTheme() { - asyncThemeFetcher.shutdown(); - themeListPane.stopAsyncFetchTheme(); - } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPagesPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPagesPane.java index 40838dbd83..36e962c6af 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPagesPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPagesPane.java @@ -22,6 +22,7 @@ import com.fr.design.mainframe.theme.provider.ThemeManageActionProvider; import com.fr.design.mainframe.theme.ui.BreadcrumbBar; import com.fr.stable.ArrayUtils; import com.fr.stable.unit.FU; +import com.fr.third.javax.annotation.Nullable; import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; @@ -38,6 +39,7 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Stroke; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; @@ -62,10 +64,14 @@ public class TemplateThemeGridPagesPane extends JPanel { private TemplateThemeGridPagePane currentTemplateThemeGridPagePane; public TemplateThemeGridPagesPane() { - initializePane(); + initializePane(null); } - private void initializePane() { + public TemplateThemeGridPagesPane(@Nullable Window window) { + initializePane(window); + } + + private void initializePane(@Nullable Window window) { setLayout(new BorderLayout()); setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10)); @@ -82,9 +88,9 @@ public class TemplateThemeGridPagesPane extends JPanel { add(contentPane, BorderLayout.CENTER); - themeUsingPane = new TemplateThemeUsingPane(); + themeUsingPane = new TemplateThemeUsingPane(window); contentPane.add(themeUsingPane, themeUsingPane.getTitle()); - themeManagingPane = new TemplateThemeManagingPane(); + themeManagingPane = new TemplateThemeManagingPane(window); contentPane.add(themeManagingPane, themeManagingPane.getTitle()); showThemeUsingPane(); @@ -133,7 +139,7 @@ public class TemplateThemeGridPagesPane extends JPanel { public UIButton[] createRightButtons() { UIButton[] buttons = new UIButton[] {}; buttons = ArrayUtils.addAll(buttons, createExtraButtons()); - buttons = ArrayUtils.addAll(buttons, createCompleteButton()); + buttons = ArrayUtils.addAll(buttons, createCloseButton()); return buttons; } @@ -174,8 +180,8 @@ public class TemplateThemeGridPagesPane extends JPanel { return uiButtonList.toArray(new UIButton[]{}); } - private UIButton createCompleteButton() { - UIButton button = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Dialog_Complete")); + private UIButton createCloseButton() { + UIButton button = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Dialog_Close")); button.setName(COMPLETE_BUTTON); button.addActionListener(new ActionListener() { @Override @@ -189,11 +195,6 @@ public class TemplateThemeGridPagesPane extends JPanel { return button; } - public void exit() { - themeUsingPane.exit(); - themeManagingPane.exit(); - } - public void setPageChangeListener(PageChangeListener changeListener) { this.pageChangeListener = changeListener; } @@ -232,15 +233,13 @@ public class TemplateThemeGridPagesPane extends JPanel { public abstract static class TemplateThemeGridPagePane extends BasicPane { public abstract TemplateThemeConfig getConfig(); - - public void exit() { } } public static class TemplateThemeUsingPane extends TemplateThemeGridPagePane { private final JTemplate template; public final TemplateThemeGridPane themeListPane; - public TemplateThemeUsingPane() { + public TemplateThemeUsingPane(@Nullable Window window) { super(); setLayout(new BorderLayout()); setBorder(new CompoundBorder( @@ -249,9 +248,7 @@ public class TemplateThemeGridPagesPane extends JPanel { template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); TemplateThemeConfig config = template.getUsingTemplateThemeConfig(); - themeListPane = new TemplateThemeGridPane<>(false, config, null); - - themeListPane.startListenThemeConfig(); + themeListPane = new TemplateThemeGridPane<>(window, false, config, null); themeListPane.setSelectedChangeListener(new ChangeListener() { @Override @@ -272,12 +269,6 @@ public class TemplateThemeGridPagesPane extends JPanel { return template.getUsingTemplateThemeConfig(); } - @Override - public void exit() { - themeListPane.stopListenThemeConfig(); - themeListPane.stopAsyncFetchTheme(); - } - @Override protected String title4PopupWindow() { return Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Using_Dialog_Title"); @@ -286,20 +277,16 @@ public class TemplateThemeGridPagesPane extends JPanel { public static class TemplateThemeManagingPane extends TemplateThemeGridPagePane { private final UITabbedPane tabbedPane; - private final TemplateThemeGridControlPane formThemesManagerPane; - private final TemplateThemeGridControlPane reportThemesManagerPane; - public TemplateThemeManagingPane() { + public TemplateThemeManagingPane(@Nullable Window window) { setLayout(FRGUIPaneFactory.createBorderLayout()); tabbedPane = new UITabbedPane(); tabbedPane.setTabBorderColor(new Color(0xE0E0E1)); add(tabbedPane, BorderLayout.CENTER); - formThemesManagerPane = TemplateThemeGridControlPane.createFormThemesManagerPane(); - formThemesManagerPane.startListenThemeConfig(); - reportThemesManagerPane = TemplateThemeGridControlPane.createReportThemesManagerPane(); - reportThemesManagerPane.startListenThemeConfig(); + TemplateThemeGridControlPane formThemesManagerPane = TemplateThemeGridControlPane.createFormThemesManagerPane(window); + TemplateThemeGridControlPane reportThemesManagerPane = TemplateThemeGridControlPane.createReportThemesManagerPane(window); tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Dialog_Form_Tab"), formThemesManagerPane); tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Dialog_Report_Tab"), reportThemesManagerPane); @@ -321,14 +308,6 @@ public class TemplateThemeGridPagesPane extends JPanel { } } - @Override - public void exit() { - formThemesManagerPane.stopListenThemeConfig(); - formThemesManagerPane.stopAsyncFetchTheme(); - reportThemesManagerPane.stopListenThemeConfig(); - reportThemesManagerPane.stopAsyncFetchTheme(); - } - @Override protected String title4PopupWindow() { return Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Manager_Dialog_Title"); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPane.java index 2af4950f53..bce8590519 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeGridPane.java @@ -8,9 +8,8 @@ import com.fr.design.event.ChangeEvent; import com.fr.design.event.ChangeListener; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.widget.FRWidgetFactory; -import com.fr.design.widget.WidgetBoundsPaneFactory; import com.fr.stable.StringUtils; +import com.fr.third.javax.annotation.Nullable; import javax.swing.BorderFactory; import javax.swing.JPanel; @@ -18,8 +17,11 @@ import javax.swing.ScrollPaneConstants; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; +import java.awt.Window; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,13 +55,17 @@ public class TemplateThemeGridPane extends BasicPane { private ChangeListener changeListener; - public TemplateThemeGridPane(boolean displayTheme4NewTemplateMarker, TemplateThemeConfig config, TemplateThemeProfilePane profilePane) { + private final Window window; + + public TemplateThemeGridPane(@Nullable Window window, boolean displayTheme4NewTemplateMarker, TemplateThemeConfig config, TemplateThemeProfilePane profilePane) { + this.window = window; this.displayTheme4NewTemplateMarker = displayTheme4NewTemplateMarker; this.config = config; this.profilePane = profilePane; this.contentListPane = new JPanel(); this.asyncThemeFetcher = new AsyncThemeFetcher<>(ASYNC_FETCH_THEME_THREAD_COUNT, config); initializePane(); + registerWindowListener(); } private void initializePane() { @@ -84,6 +90,26 @@ public class TemplateThemeGridPane extends BasicPane { } + private void registerWindowListener() { + if (window != null) { + window.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + startListenThemeConfig(); + asyncFetchThemes(); + } + + @Override + public void windowClosed(WindowEvent e) { + super.windowClosed(e); + stopListenThemeConfig(); + asyncThemeFetcher.shutdown(); + } + }); + } + } + public void fillContentListPane() { contentListPane.removeAll(); List names = config.getThemeNames(); @@ -97,6 +123,7 @@ public class TemplateThemeGridPane extends BasicPane { } } } + private TemplateThemeBlock createCachedTemplateThemeBlock(String name) { TemplateThemeBlock block = blockCache.get(name); if (block == null) { @@ -115,19 +142,6 @@ public class TemplateThemeGridPane extends BasicPane { setSelectedBlock(block); } }); - asyncThemeFetcher.submit(name, new AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter() { - @Override - public void beforeCachedFetch() { - super.beforeCachedFetch(); - block.setTheme(null); - } - - @Override - public void afterCachedFetch(T theme) { - super.afterCachedFetch(theme); - block.setTheme(theme); - } - }); return block; } @@ -154,6 +168,15 @@ public class TemplateThemeGridPane extends BasicPane { asyncThemeFetcher.submit(themeName, new AsyncThemeListItemFetchCallback(themeName)); } + private void asyncFetchThemes() { + List names = config.getThemeNames(); + for (String name: names) { + if (config.contains(name)) { + asyncThemeFetcher.submit(name, new AsyncThemeListItemFetchCallback(name)); + } + } + } + @Override protected String title4PopupWindow() { return null; @@ -163,7 +186,7 @@ public class TemplateThemeGridPane extends BasicPane { return selectedBlock != null ? selectedBlock.getTheme() : null; } - public void startListenThemeConfig() { + private void startListenThemeConfig() { if (themeConfigChangeListener == null) { themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() { @Override @@ -219,17 +242,13 @@ public class TemplateThemeGridPane extends BasicPane { } } - public void stopListenThemeConfig() { + private void stopListenThemeConfig() { if (themeConfigChangeListener != null) { config.removeThemeConfigChangeListener(themeConfigChangeListener); themeConfigChangeListener = null; } } - public void stopAsyncFetchTheme() { - asyncThemeFetcher.shutdown(); - } - private class AsyncThemeListItemFetchCallback extends AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter { private final String themeName; public AsyncThemeListItemFetchCallback(String themeName) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java index f3187acaab..92acb5c71e 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java @@ -60,6 +60,8 @@ public abstract class TemplateThemeProfilePane extends private UIButton saveButton = new UIButton(); private UIButton saveAsButton = new UIButton(); + private TemplateThemeProfileActionListener actionListener = new TemplateThemeProfileActionAdapter(); + public TemplateThemeProfilePane(TemplateThemeConfig config) { super(); this.config = config; @@ -112,6 +114,7 @@ public abstract class TemplateThemeProfilePane extends return; } saveButton.setEnabled(valid && isMutable); + actionListener.onThemeNameChecked(themeEditorPane.getThemeName(), valid); } }); @@ -138,6 +141,8 @@ public abstract class TemplateThemeProfilePane extends if (saveAsButton != null) { saveAsButton.setEnabled(StringUtils.isNotEmpty(name)); } + actionListener.onInitialize(theme); + isPopulating = false; } @@ -201,7 +206,7 @@ public abstract class TemplateThemeProfilePane extends }); } - public UIButton createSaveButton() { + public UIButton createSaveButton(final TemplateThemeProfileDialog profileDialog) { saveButton = new UIButton(); saveButton.setText(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save")); saveButton.setEnabled(false); @@ -214,7 +219,14 @@ public abstract class TemplateThemeProfilePane extends super.afterCommit(); saveButton.setEnabled(false); saveAsButton.setEnabled(true); - DesignerToastMsgUtil.toastPrompt(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save_Successfully")); + actionListener.onSaved(config.cachedFetch(getName())); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + DesignerToastMsgUtil.toastPrompt(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save_Successfully")); + profileDialog.exit(); + } + }); } }); } @@ -330,4 +342,29 @@ public abstract class TemplateThemeProfilePane extends this.dispose(); } } + + public void addProfileActionListener(TemplateThemeProfileActionListener actionListener) { + if (actionListener != null) { + this.actionListener = actionListener; + } + } + public interface TemplateThemeProfileActionListener { + + void onInitialize(TemplateTheme theme); + + void onThemeNameChecked(String name, boolean valid); + + void onSaved(TemplateTheme theme); + } + public static class TemplateThemeProfileActionAdapter implements TemplateThemeProfileActionListener { + + @Override + public void onInitialize(TemplateTheme theme) {} + + @Override + public void onThemeNameChecked(String name, boolean valid) { } + + @Override + public void onSaved(TemplateTheme theme) {} + } } \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/ThemedCellStyleListPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedCellStyleListPane.java similarity index 59% rename from designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/ThemedCellStyleListPane.java rename to designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedCellStyleListPane.java index 5843ea587d..b3362e5fb0 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/style/ThemedCellStyleListPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedCellStyleListPane.java @@ -1,22 +1,21 @@ -package com.fr.design.mainframe.cell.settingpane.style; +package com.fr.design.mainframe.theme; -import com.fr.base.NameStyle; -import com.fr.base.Style; import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.settings.ThemedCellStyle; import com.fr.design.beans.FurtherBasicBeanPane; -import com.fr.design.cell.CellStylePreviewPane; +import com.fr.design.cell.CellRectangleStylePreviewPane; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.ibutton.UIRadioButton; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerBean; -import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; import com.fr.general.ComparatorUtils; +import com.fr.general.IOUtils; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; +import javax.swing.Icon; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.ListCellRenderer; @@ -27,27 +26,28 @@ import javax.swing.event.ListSelectionListener; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; +import java.awt.Graphics; import java.io.Serializable; import java.util.List; -public class ThemedCellStyleListPane extends FurtherBasicBeanPane implements DesignerBean { +public class ThemedCellStyleListPane extends FurtherBasicBeanPane implements DesignerBean { private static final int LEFT_BORDER = 10; private static final int RIGHT_BORDER = 10; - private final DefaultListModel defaultListModel; - private final JList styleList; + private final DefaultListModel defaultListModel; + private final JList styleList; private ChangeListener changeListener; - public ThemedCellStyleListPane() { + public ThemedCellStyleListPane(boolean supportInnerBorder) { defaultListModel = new DefaultListModel<>(); styleList = new JList<>(defaultListModel); - styleList.setCellRenderer(new RadioButtonListCellRenderer()); + styleList.setCellRenderer(new RadioButtonListCellRangeRenderer(supportInnerBorder)); styleList.setOpaque(false); styleList.setBackground(null); styleList.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { - if (changeListener != null) { + if (e.getValueIsAdjusting() && changeListener != null) { changeListener.stateChanged(new ChangeEvent(styleList)); } } @@ -55,15 +55,8 @@ public class ThemedCellStyleListPane extends FurtherBasicBeanPane imp setLayout(FRGUIPaneFactory.createBorderLayout()); add(styleList, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(0 ,LEFT_BORDER, 0, RIGHT_BORDER)); - - DesignerContext.setDesignerBean("predefinedStyle", this); } - /** - * 添加改变监听 - * - * @param changeListener 监听事件 - */ public void addChangeListener(ChangeListener changeListener) { this.changeListener = changeListener; } @@ -77,7 +70,7 @@ public class ThemedCellStyleListPane extends FurtherBasicBeanPane imp } @Override - public void populateBean(NameStyle ob) { + public void populateBean(ThemedCellStyle ob) { refreshBeanElement(); if (ob == null) { styleList.setSelectedIndex(0); @@ -92,32 +85,21 @@ public class ThemedCellStyleListPane extends FurtherBasicBeanPane imp } @Override - public NameStyle updateBean() { + public ThemedCellStyle updateBean() { return styleList.getSelectedValue(); } - /** - * 获取面板标题 - * - * @return 标题 - */ + @Override public String title4PopupWindow() { return Toolkit.i18nText("Fine-Design_Report_Predefined_Style"); } - /** - * 是否可以接纳对象 - * - * @param ob 组件对象 - * @return 是否可以接纳对象 - */ + @Override public boolean accept(Object ob) { - return ob instanceof NameStyle; + return ob instanceof ThemedCellStyle; } - /** - * 刷新组件对象 - */ + @Override public void refreshBeanElement() { defaultListModel.removeAllElements(); JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); @@ -125,36 +107,48 @@ public class ThemedCellStyleListPane extends FurtherBasicBeanPane imp TemplateTheme theme = template.getTemplateTheme(); List styleList = theme.getCellStyleList().getCellStyleList(); for (ThemedCellStyle themedCellStyle: styleList) { - String name = themedCellStyle.getName(); - Style realStyle = themedCellStyle.getStyle(); - NameStyle nameStyle = NameStyle.getPassiveInstance(name, realStyle); - defaultListModel.addElement(nameStyle); + defaultListModel.addElement(themedCellStyle); } } styleList.setModel(defaultListModel); } - private static class RadioButtonListCellRenderer extends JPanel implements ListCellRenderer, Serializable { + private static class RadioButtonListCellRangeRenderer extends JPanel implements ListCellRenderer, Serializable { + + private static final Icon selectedMarkIcon = IOUtils.readIcon("/com/fr/design/form/images/marked.png"); - private final UIRadioButton button; - private final CellStylePreviewPane previewArea; + private final CellRectangleStylePreviewPane previewArea; + private boolean selected = false; - public RadioButtonListCellRenderer() { + public RadioButtonListCellRangeRenderer(boolean supportInnerBorder) { super(); - setLayout(new BorderLayout(20, 0)); - setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - setPreferredSize(new Dimension(getPreferredSize().width, 40)); - button = new UIRadioButton(); - previewArea = new CellStylePreviewPane(); - add(button, BorderLayout.WEST); + setLayout(new BorderLayout(5, 0)); + setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); + previewArea = new CellRectangleStylePreviewPane(supportInnerBorder); add(previewArea, BorderLayout.CENTER); } @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - button.setSelected(isSelected); - previewArea.setStyle((Style) value); + public Component getListCellRendererComponent(JList list, ThemedCellStyle value, int index, boolean isSelected, boolean cellHasFocus) { + this.selected = isSelected; + previewArea.setPlainText(value.getName()); + previewArea.setStyle(value.getStyle(), value.getCellBorderStyle()); + + int preferredWidth = list.getWidth() - 15; + preferredWidth = Math.max(0, preferredWidth); + int preferredHeight = 0; + previewArea.setPreferredSize(new Dimension(preferredWidth, preferredHeight)); + return this; } + + @Override + public void paint(Graphics g) { + super.paint(g); + + if (selected) { + selectedMarkIcon.paintIcon(this, g, getWidth() - selectedMarkIcon.getIconWidth(), 5); + } + } } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedFeatureController.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedFeatureController.java new file mode 100644 index 0000000000..47cf1bcdda --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedFeatureController.java @@ -0,0 +1,16 @@ +package com.fr.design.mainframe.theme; + +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.theme.ThemedCellBorderFeature; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/11/26 + */ +public class ThemedFeatureController { + public static boolean isCellStyleSupportInnerBorder() { + ThemedCellBorderFeature controller = WorkContext.getCurrent().get(ThemedCellBorderFeature.class); + return controller.isSupport(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeDialog.java index 875cc6bae6..1864a91b1f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeDialog.java @@ -28,15 +28,14 @@ public abstract class TemplateThemeDialog extends JDialog { private final JPanel contentContainer; private final JPanel actionContainer; + private final int dialogContentHeight; public TemplateThemeDialog(Window parent, String title, int contentWidth, int contentHeight) { super(parent, ModalityType.APPLICATION_MODAL); - setTitle(title); setResizable(false); setLayout(FRGUIPaneFactory.createBorderLayout()); - - int dialogContentHeight = contentHeight + DIALOG_BOTTOM_ACTION_BAR_HEIGHT; + dialogContentHeight = contentHeight + DIALOG_BOTTOM_ACTION_BAR_HEIGHT; int dialogWindowHeight = dialogContentHeight + DIALOG_TITLE_HEIGHT; setSize(new Dimension(contentWidth, dialogWindowHeight)); @@ -54,6 +53,12 @@ public abstract class TemplateThemeDialog extends JDialog { setContentPane(contentContainer); } + @Override + public void doLayout() { + this.setSize(new Dimension(this.getWidth(), dialogContentHeight + this.getInsets().top)); + super.doLayout(); + } + protected void setupContentPane() { contentContainer.add(createContentPane(), BorderLayout.CENTER, 0); } @@ -63,10 +68,11 @@ public abstract class TemplateThemeDialog extends JDialog { } protected UIButton[] createLeftButtons() { - return new UIButton[] {}; + return new UIButton[]{}; } + protected UIButton[] createRightButtons() { - return new UIButton[] {}; + return new UIButton[]{}; } public void setupActionButtons() { @@ -89,7 +95,7 @@ public abstract class TemplateThemeDialog extends JDialog { } private JPanel createActionsContainer(int align, UIButton... buttons) { - JPanel container = new JPanel(new FlowLayout(align, DIALOG_BOTTOM_ACTION_BUTTON_GAP, 0)); + JPanel container = new JPanel(new FlowLayout(align, DIALOG_BOTTOM_ACTION_BUTTON_GAP, 0)); int paddingVertical = getPaddingVertical(); container.setBorder(BorderFactory.createEmptyBorder(paddingVertical, 0, paddingVertical, 0)); @@ -97,7 +103,7 @@ public abstract class TemplateThemeDialog extends JDialog { return container; } - for (UIButton button: buttons) { + for (UIButton button : buttons) { if (button != null) { button.setPreferredSize(new Dimension(button.getPreferredSize().width, DIALOG_BOTTOM_ACTION_BUTTON_HEIGHT)); container.add(button); @@ -111,7 +117,7 @@ public abstract class TemplateThemeDialog extends JDialog { return createActionsContainer(FlowLayout.RIGHT, buttons); } - private int getPaddingVertical(){ + private int getPaddingVertical() { return (DIALOG_BOTTOM_ACTION_BAR_HEIGHT - DIALOG_BOTTOM_ACTION_BUTTON_HEIGHT) / 2; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeGridPagesDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeGridPagesDialog.java index 917f078d52..bf65b9be28 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeGridPagesDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeGridPagesDialog.java @@ -7,6 +7,7 @@ import com.fr.design.mainframe.theme.TemplateThemeGridPagesPane; import com.fr.design.mainframe.theme.TemplateThemeGridPane; import javax.swing.JPanel; +import java.awt.Window; /** * @author Starryi @@ -19,16 +20,20 @@ public class TemplateThemeGridPagesDialog extends TemplateThemeDialog implements protected TemplateThemeGridPagesPane overallPane; - public TemplateThemeGridPagesDialog() { - super(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Using_Dialog_Title"), CONTENT_WIDTH, CONTENT_HEIGHT); + public TemplateThemeGridPagesDialog(Window parentWindow) { + super(parentWindow, Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Using_Dialog_Title"), CONTENT_WIDTH, CONTENT_HEIGHT); setupContentPane(); setupActionButtons(); } + public TemplateThemeGridPagesDialog() { + this(DesignerContext.getDesignerFrame()); + } + @Override protected JPanel createContentPane() { - overallPane = new TemplateThemeGridPagesPane(); + overallPane = new TemplateThemeGridPagesPane(this); overallPane.setPageChangeListener(this); return overallPane; } @@ -43,12 +48,6 @@ public class TemplateThemeGridPagesDialog extends TemplateThemeDialog implements return overallPane.createRightButtons(); } - @Override - public void exit() { - overallPane.exit(); - super.exit(); - } - @Override public void onPageChangeListener() { setupActionButtons(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeProfileDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeProfileDialog.java index a76597f8e8..0a26a6691e 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeProfileDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeProfileDialog.java @@ -90,7 +90,7 @@ public class TemplateThemeProfileDialog extends Templat })); } - uiButtonList.add(profilePane.createSaveButton()); + uiButtonList.add(profilePane.createSaveButton(TemplateThemeProfileDialog.this)); uiButtonList.add(profilePane.createSaveAsButton(TemplateThemeProfileDialog.this)); uiButtonList.add(createCancelButton()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java index 420a7ed439..9818e60b5c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/dialog/TemplateThemeUsingDialog.java @@ -1,11 +1,18 @@ package com.fr.design.mainframe.theme.dialog; +import java.awt.Window; + /** * @author Starryi * @version 1.0 * Created by Starryi on 2021/8/13 */ public class TemplateThemeUsingDialog extends TemplateThemeGridPagesDialog { + public TemplateThemeUsingDialog(Window parentWindow) { + super(parentWindow); + overallPane.showThemeUsingPane(); + } + public TemplateThemeUsingDialog() { super(); overallPane.showThemeUsingPane(); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/CellStyleListEditPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/CellStyleListEditPane.java index 6b12c37d47..3f198f230a 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/CellStyleListEditPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/CellStyleListEditPane.java @@ -1,9 +1,7 @@ package com.fr.design.mainframe.theme.edit; -import com.fr.base.Style; import com.fr.base.theme.settings.ThemedCellStyle; import com.fr.base.theme.settings.ThemedCellStyleList; -import com.fr.config.predefined.PredefinedCellStyle; import com.fr.design.actions.UpdateAction; import com.fr.design.beans.BasicBeanPane; import com.fr.design.dialog.FineJOptionPane; @@ -32,9 +30,11 @@ import com.fr.stable.Nameable; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.ListModel; import javax.swing.SwingUtilities; import java.awt.BorderLayout; import java.awt.Component; @@ -103,26 +103,14 @@ public class CellStyleListEditPane extends JListControlPane { @Override protected JNameEdList createJNameList() { - JNameEdList nameEdList = super.createJNameList(); - nameEdList.setCellEditor(new DefaultListCellEditor(new UITextField()) { - @Override - public Component getListCellEditorComponent(JList list, Object value, boolean isSelected, int index) { - ListModelElement element = (ListModelElement) getModel().getElementAt(index); - if (element != null) { - NameObject selectNameObject = (NameObject) element.wrapper; - ThemedCellStyle cellStyle = (ThemedCellStyle) (selectNameObject.getObject()); - if (!cellStyle.isRemovable()) { - return null; - } - } - return super.getListCellEditorComponent(list, value, isSelected, index); - } - }); + JNameEdList nameEdList = new NoIconNamedList(new DefaultListModel()); + nameEdList.setCellEditor(new UnEditableListCellEditor(new UITextField())); + nameEdList.setCellRenderer(new NoIconNameableListCellRenderer()); return nameEdList; } @Override - public BasicBeanPane createPaneByCreators(NameableCreator creator) { + public BasicBeanPane createPaneByCreators(NameableCreator creator) { CellStyleEditPane stylePane = (CellStyleEditPane) super.createPaneByCreators(creator); stylePane.registerAttrChangeListener(attributeChangeListener); return stylePane; @@ -256,23 +244,15 @@ public class CellStyleListEditPane extends JListControlPane { this(CellStyleEditPane.class); } - public CellStyleNameObjectCreator(Class updatePane) { + public CellStyleNameObjectCreator(Class> updatePane) { super(i18nText("Fine-Design_Predefined_Cell_New_Style"), ThemedCellStyle.class, updatePane); } @Override public Nameable createNameable(UnrepeatedNameHelper helper) { - ThemedCellStyle cellStyle = new ThemedCellStyle(); + ThemedCellStyle cellStyle = ThemedCellStyle.createInstanceUsed4New(); cellStyle.setName(menuName); - cellStyle.setStyle(Style.getInstance()); - cellStyle.setRemovable(true); - cellStyle.setUse4Default(false); - cellStyle.setUse4BigTitle(false); - cellStyle.setUse4SmallTitle(false); - cellStyle.setUse4Header(false); - cellStyle.setUse4MainText(false); - cellStyle.setUse4SupportInfo(false); - cellStyle.setUse4HighlightText(false); + return new NameObject(helper.createUnrepeatedName(this.menuName()), cellStyle); } @@ -304,4 +284,46 @@ public class CellStyleListEditPane extends JListControlPane { return ((ThemedCellStyle) ob).isUse4Default(); } } + + private class NoIconNameableListCellRenderer extends NameableListCellRenderer { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (component instanceof NameableListCellRenderer) { + ((NameableListCellRenderer) component).setIcon(null); + ((NameableListCellRenderer) component).setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); + } + return component; + } + } + private class NoIconNamedList extends JNameEdList { + + public NoIconNamedList(ListModel dataModel) { + super(dataModel); + } + + @Override + public int getIconWidth() { + return 0; + } + } + private class UnEditableListCellEditor extends DefaultListCellEditor { + + public UnEditableListCellEditor(UITextField textField) { + super(textField); + } + + @Override + public Component getListCellEditorComponent(JList list, Object value, boolean isSelected, int index) { + ListModelElement element = (ListModelElement) getModel().getElementAt(index); + if (element != null) { + NameObject selectNameObject = (NameObject) element.wrapper; + ThemedCellStyle cellStyle = (ThemedCellStyle) (selectNameObject.getObject()); + if (!cellStyle.isRemovable()) { + return null; + } + } + return super.getListCellEditorComponent(list, value, isSelected, index); + } + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ChartStyleEditPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ChartStyleEditPane.java index 3830f02f15..4d75622aed 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ChartStyleEditPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ChartStyleEditPane.java @@ -13,7 +13,6 @@ import com.fr.design.mainframe.theme.edit.chart.ChartTitleAndBackgroundStylePane import javax.swing.BorderFactory; import java.util.ArrayList; import java.util.List; -import java.awt.Color; /** * @author Bjorn @@ -88,10 +87,6 @@ public class ChartStyleEditPane extends MultiTabPane { return chartStyle; } - public void populateGradientBar(List colors) { - chartSeriesStylePane.populateGradientBar(colors); - } - @Override public boolean accept(Object ob) { return false; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ReportBodyStyleEditPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ReportBodyStyleEditPane.java index ec36c29703..4a14460255 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ReportBodyStyleEditPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ReportBodyStyleEditPane.java @@ -8,13 +8,11 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.mainframe.predefined.ui.detail.background.BackgroundSettingPane; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; -import javax.swing.SwingConstants; import java.awt.BorderLayout; import java.awt.Component; 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 b2d182422e..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 @@ -1,7 +1,9 @@ package com.fr.design.mainframe.theme.edit.cell; +import com.fr.base.CellBorderStyle; +import com.fr.base.Style; import com.fr.base.theme.settings.ThemedCellStyle; -import com.fr.design.cell.CellStylePreviewPane; +import com.fr.design.cell.CellRectangleStylePreviewPane; import com.fr.design.constants.UIConstants; import com.fr.design.dialog.AttrScrollPane; import com.fr.design.dialog.BasicPane; @@ -14,6 +16,7 @@ import com.fr.design.gui.style.AlignmentPane; import com.fr.design.gui.style.BorderPane; import com.fr.design.gui.style.TextFontTippedPane; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.ThemedFeatureController; import com.fr.design.mainframe.theme.ui.BorderUtils; import javax.swing.BorderFactory; @@ -35,7 +38,7 @@ import static com.fr.design.i18n.Toolkit.i18nText; */ public class CellStyleEditPane extends MultiTabPane { private ThemedCellStyle cellStyle; - private CellStylePreviewPane previewArea; + private CellRectangleStylePreviewPane previewArea; private boolean populating; private AttributeChangeListener attributeChangeListener; @@ -74,17 +77,47 @@ public class CellStyleEditPane extends MultiTabPane { for (BasicPane basicPane : paneList) { ((AbstractBasicStylePane) basicPane).populateBean(ob.getStyle()); - previewArea.setStyle(ob.getStyle()); + previewArea.setPlainText(ob.getName()); + previewArea.setStyle(ob.getStyle(), ob.getCellBorderStyle()); + if (ThemedFeatureController.isCellStyleSupportInnerBorder() && basicPane instanceof BorderPane) { + ((BorderPane) basicPane).populateBean(ob.getCellBorderStyle(), true, false); + } } this.populating = false; } @Override public ThemedCellStyle updateBean() { - AbstractBasicStylePane basicStylePane = (AbstractBasicStylePane) paneList.get(tabPane.getSelectedIndex()); - this.cellStyle.setStyle(basicStylePane.update(this.cellStyle.getStyle())); + Style style = this.cellStyle.getStyle(); + CellBorderStyle borderStyle = createDefaultBorderStyleFromStyle(style); + for (BasicPane basicPane : paneList) { + style = ((AbstractBasicStylePane) basicPane).update(style); + if (ThemedFeatureController.isCellStyleSupportInnerBorder() && basicPane instanceof BorderPane) { + borderStyle = ((BorderPane) basicPane).update(); + } + } + + this.cellStyle.setStyle(style); + this.cellStyle.setCellBorderStyle(borderStyle); + return this.cellStyle; } + private CellBorderStyle createDefaultBorderStyleFromStyle(Style style) { + CellBorderStyle cellBorderStyle = new CellBorderStyle(); + cellBorderStyle.setTopStyle(style.getBorderTop()); + cellBorderStyle.setTopColor(style.getBorderTopColor()); + + cellBorderStyle.setBottomStyle(style.getBorderBottom()); + cellBorderStyle.setBottomColor(style.getBorderBottomColor()); + + cellBorderStyle.setLeftStyle(style.getBorderLeft()); + cellBorderStyle.setLeftColor(style.getBorderLeftColor()); + + cellBorderStyle.setRightStyle(style.getBorderRight()); + cellBorderStyle.setRightColor(style.getBorderRightColor()); + + return cellBorderStyle; + } @Override public boolean accept(Object ob) { @@ -102,21 +135,25 @@ public class CellStyleEditPane extends MultiTabPane { @Override protected void initLayout() { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - - JPanel jPanel = new JPanel(); - jPanel.setLayout(new BorderLayout(0, 4)); + this.setLayout(new BorderLayout(0, 10)); + this.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); JPanel previewPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); - previewArea = new CellStylePreviewPane(); - previewArea.setPreferredSize(new Dimension(223, 30)); - previewPane.setBorder(BorderUtils.createTitleBorder(i18nText("Fine-Design_Basic_Preview"))); - previewPane.add(previewArea, BorderLayout.CENTER); + previewArea = new CellRectangleStylePreviewPane(true); + previewArea.setPreferredSize(new Dimension(207, 48)); + previewPane.setBorder(BorderFactory.createCompoundBorder( + BorderUtils.createTitleBorder(i18nText("Fine-Design_Basic_Preview")), + BorderFactory.createEmptyBorder(4, 4, 4, 4))); + previewPane.add(previewArea, BorderLayout.NORTH); this.add(previewPane, BorderLayout.NORTH); - this.add(jPanel, BorderLayout.CENTER); - jPanel.add(tabPane, BorderLayout.NORTH); + JPanel settingsPane = new JPanel(); + this.add(settingsPane, BorderLayout.CENTER); + + settingsPane.setLayout(new BorderLayout(0, 4)); + + settingsPane.add(tabPane, BorderLayout.NORTH); JPanel attrListenerPane = new AbstractAttrNoScrollPane() { @Override @@ -135,23 +172,33 @@ public class CellStyleEditPane extends MultiTabPane { } ThemedCellStyle cellStyle = updateBean(); if (cellStyle != null) { - previewArea.setStyle(cellStyle.getStyle()); + previewArea.setPlainText(cellStyle.getName()); + previewArea.setStyle(cellStyle.getStyle(), cellStyle.getCellBorderStyle()); } fireAttrChangeListener(); } }); - BasicScrollPane basicScrollPane = new AttrScrollPane() { + return new EmptyBorderAttrScrollPane() { @Override protected JPanel createContentPane() { return centerPane; } }; - return basicScrollPane; } }; - jPanel.add(attrListenerPane, BorderLayout.CENTER); + settingsPane.add(attrListenerPane, BorderLayout.CENTER); } @Override public void updateBean(ThemedCellStyle ob) {} + + + private static abstract class EmptyBorderAttrScrollPane extends AttrScrollPane { + + @Override + protected void layoutContentPane() { + super.layoutContentPane(); + leftcontentPane.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 5, original)); + } + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java index ee04556c66..a70870a61b 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java @@ -13,6 +13,7 @@ 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.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; import com.fr.general.GeneralUtils; @@ -52,11 +53,15 @@ public class ChartFontPane extends BasicPane { } private void initState() { - fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontNameComboBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); fontSizeComboBox = new UIComboBox(FONT_SIZES); bold = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); italic = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); - fontColor = new UIColorButton(); + fontColor = getColorButton(); + } + + protected UIColorButton getColorButton() { + return new UIColorButton(); } protected void initComponents() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartLabelStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartLabelStylePane.java index 8eb736444f..c94dd6ef22 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartLabelStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartLabelStylePane.java @@ -2,6 +2,8 @@ package com.fr.design.mainframe.theme.edit.chart; import com.fr.base.theme.settings.ThemedChartStyle; import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.gui.ibutton.UIColorButton; +import com.fr.design.gui.ibutton.UIColorButtonWithAuto; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; @@ -25,6 +27,11 @@ public class ChartLabelStylePane extends AbstractChartStylePane { autoButton = new UIButtonGroup<>(new String[]{Toolkit.i18nText("Fine-Design_Chart_Auto"), Toolkit.i18nText("Fine-Design_Chart_Custom")}); chartFontPane = new ChartFontPane() { + @Override + protected UIColorButton getColorButton() { + return new UIColorButtonWithAuto(); + } + public String getUILabelText() { return Toolkit.i18nText("Fine-Design_Chart_Label_Character"); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartSeriesStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartSeriesStylePane.java index fbb8f64895..f9ca4edf32 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartSeriesStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartSeriesStylePane.java @@ -1,5 +1,6 @@ package com.fr.design.mainframe.theme.edit.chart; +import com.fr.base.FineColor; import com.fr.base.theme.settings.ThemedChartStyle; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ilable.UILabel; @@ -7,12 +8,12 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.theme.dialog.TemplateThemeProfileDialog; import com.fr.design.style.background.gradient.FixedGradientBar; -import java.util.List; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.List; /** * @author Bjorn @@ -66,7 +67,7 @@ public class ChartSeriesStylePane extends AbstractChartStylePane { if (chartStyle.getThemedChartSeriesColor().isCombineColor()) { List editingColorScheme = TemplateThemeProfileDialog.getEditingColorScheme(); colorTypeButton.setSelectedIndex(0); - gradientBar.updateColor(editingColorScheme.get(0), editingColorScheme.get(1)); + gradientBar.updateColor(new FineColor(0, 0, editingColorScheme.get(0)), new FineColor(1, 0, editingColorScheme.get(1))); } else { colorTypeButton.setSelectedIndex(1); gradientBar.updateColor(chartStyle.getThemedChartSeriesColor().getBeginColor(), chartStyle.getThemedChartSeriesColor().getEndColor()); @@ -74,12 +75,6 @@ public class ChartSeriesStylePane extends AbstractChartStylePane { checkTypeButton(); } - - public void populateGradientBar(List colors) { - gradientBar.updateColor(colors.get(0), colors.get(1)); - this.repaint(); - } - public void update(ThemedChartStyle chartStyle) { chartStyle.getThemedChartSeriesColor().setCombineColor(colorTypeButton.getSelectedIndex() == 0); chartStyle.getThemedChartSeriesColor().setBeginColor(gradientBar.getSelectColorPointBtnP1().getColorInner()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java index 6bac518763..5705935866 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java @@ -77,7 +77,7 @@ public class ChartTitleAndBackgroundStylePane extends AbstractChartStylePane { private void initList() { paneList = new ArrayList<>(); paneList.add(new NullBackgroundQuickPane()); - paneList.add(new ColorBackgroundQuickPane()); + paneList.add(new ColorBackgroundQuickPane(true)); paneList.add(new ImageBackgroundQuickPane(false)); paneList.add(new VanChartGradientPane()); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListExtendedPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListExtendedPane.java deleted file mode 100644 index 9d02180e7d..0000000000 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListExtendedPane.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.fr.design.mainframe.theme.edit.ui; - -import com.fr.base.theme.FineColorManager; -import com.fr.design.layout.FRGUIPaneFactory; - -import javax.swing.JPanel; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Starryi - * @version 1.0 - * Created by Starryi on 2021/8/7 - */ -public class ColorListExtendedPane extends JPanel implements MouseListener { - public static final int DEFAULT_COLOR_COUNT = 8; - public static final int DEFAULT_EXTENDED_COUNT = 5; - public static final int DEFAULT_COLOR_SIZE = 16; - public static final int DEFAULT_COLOR_GAP = 3; - - public static final ExtendedColorComputer DEFAULT_EXTENDED_COMPUTER = new ExtendedColorComputer() { - @Override - public Color computeExtendedColor(Color color, int index, int count) { - return FineColorManager.computeExtendedColor(color, index, count); - } - }; - - private final boolean selectable; - private final int colorCount; - private final int extendedCount; - private final int boxSize; - private final int boxGap; - - private final List colorList = new ArrayList<>(); - private ExtendedColorComputer extendedColorComputer = DEFAULT_EXTENDED_COMPUTER; - - private int selectedColorIndex = -1; - private int selectedExtendedIndex = -1; - - public ColorListExtendedPane() { - this(false, DEFAULT_COLOR_COUNT, DEFAULT_EXTENDED_COUNT, DEFAULT_COLOR_SIZE, DEFAULT_COLOR_GAP); - } - - public ColorListExtendedPane(boolean selectable, int colorCount, int extendedCount, int boxSize, int boxGap) { - setLayout(FRGUIPaneFactory.createBorderLayout()); - this.selectable = selectable; - this.colorCount = Math.max(1, colorCount); - this.extendedCount = extendedCount; - this.boxSize = boxSize; - this.boxGap = boxGap; - - for (int i = 0; i < colorCount; i++) { - colorList.add(Color.WHITE); - } - - int width = colorCount * boxSize + (colorCount - 1) * boxGap; - int height = extendedCount * boxSize + (extendedCount - 1) * boxGap; - setPreferredSize(new Dimension(width, height)); - } - - public void populate(List colors) { - if (colors.size() > 0) { - colorList.clear(); - colorList.addAll(colors); - repaint(); - } - } - - public List update() { - return new ArrayList<>(colorList); - } - - public void setExtendedColorComputer(ExtendedColorComputer extendedColorComputer) { - this.extendedColorComputer = extendedColorComputer; - } - - @Override - public void mouseClicked(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - - int colorIndex = x / (boxSize + boxGap); - int colorX = colorIndex * (boxSize + boxGap); - - int extendedIndex = y / boxSize; - int extendedY = extendedIndex * boxSize; - - if (colorX <= x && x <= colorX + boxSize && extendedY <= y && y <= extendedY + boxSize) { - selectedColorIndex = colorIndex; - selectedExtendedIndex = extendedIndex; - } else { - selectedColorIndex = -1; - selectedExtendedIndex = -1; - } - repaint(); - } - - @Override - public void mousePressed(MouseEvent e) { - - } - - @Override - public void mouseReleased(MouseEvent e) { - - } - - @Override - public void mouseEntered(MouseEvent e) { - - } - - @Override - public void mouseExited(MouseEvent e) { - - } - - public interface ExtendedColorComputer { - Color computeExtendedColor(Color color, int index, int count); - } - - @Override - public void paint(Graphics g) { - super.paint(g); - Color oldColor = g.getColor(); - - for (int i = 0; i < colorCount; i++) { - int x = i * (boxSize + boxGap); - for (int j = 0; j < extendedCount; j++) { - Color color = extendedColorComputer.computeExtendedColor(colorList.get(i), j, extendedCount); - g.setColor(color); - int y = j * (boxSize + boxGap); - g.fillRect(x, y, boxSize, boxSize); - } - } - - g.setColor(oldColor); - } -} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListPane.java index 5c282033f0..ab5d8a4ecf 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListPane.java @@ -139,7 +139,7 @@ public class ColorListPane extends JPanel implements UIObserver { return true; } - private static class ColorButton extends AbstractSelectBox { + public static class ColorButton extends AbstractSelectBox { private Color color; private NewColorSelectPane colorPane; private ChangeListener changeListener; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/LabelUtils.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/LabelUtils.java index 13769cfc64..53de406afe 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/LabelUtils.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/LabelUtils.java @@ -37,7 +37,7 @@ public class LabelUtils { Font newFont = FRFont.getInstance(tipLabel.getFont().getFontName(), Font.PLAIN, 12); tipLabel.setFont(newFont); tipLabel.setBorder(BorderFactory.createEmptyBorder()); - tipLabel.setEnabled(false); + tipLabel.setEditable(false); tipLabel.setText(title); tipLabel.setLineWrap(true); tipLabel.setWrapStyleWord(true); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ReportThemePreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ReportThemePreviewPane.java index 4ceec636d4..103b6ca6e0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ReportThemePreviewPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ReportThemePreviewPane.java @@ -41,12 +41,13 @@ public class ReportThemePreviewPane extends TemplateThemePreviewPane { - protected Style getReportBigTitleStyle(ThemedCellStyleList cellStyleList) { - return getCellStyle(cellStyleList.getUse4BigTitle()); - } - protected Style getReportHeaderStyle(ThemedCellStyleList cellStyleList) { - return getCellStyle(cellStyleList.getUse4Header()); - } - - protected Style getMainContentStyle(ThemedCellStyleList cellStyleList) { - return getCellStyle(cellStyleList.getUse4MainText()); - } - - protected Style getHighLightStyle(ThemedCellStyleList cellStyleList) { - return getCellStyle(cellStyleList.getUse4HighlightText()); - } - - protected Style getSmallTitleStyle(ThemedCellStyleList cellStyleList) { - return getCellStyle(cellStyleList.getUse4SmallTitle()); - } - private Style getCellStyle(ThemedCellStyle themedCellStyle) { if (themedCellStyle == null) { return Style.DEFAULT_STYLE; @@ -38,9 +20,19 @@ public abstract class AbstractECPreviewPane extends UINoOpaquePanel implements T return style != null ? style : Style.DEFAULT_STYLE; } - protected void refresh(List list, Style style) { + private CellBorderStyle getCellBorderStyle(ThemedCellStyle themedCellStyle) { + if (themedCellStyle == null) { + return null; + } + return themedCellStyle.getCellBorderStyle(); + } + + protected void refresh(List list, ThemedCellStyle themedCellStyle) { + Style style = getCellStyle(themedCellStyle); + CellBorderStyle borderStyle = getCellBorderStyle(themedCellStyle); + for (AbstractPreviewCell cell : list) { - cell.refresh(style); + cell.refresh(style, borderStyle); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECPreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECPreviewPane.java index 5f7725ffa3..2ac59af941 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECPreviewPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECPreviewPane.java @@ -1,5 +1,6 @@ package com.fr.design.mainframe.theme.preview.ecpreview; +import com.fr.base.CellBorderSourceFlag; import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.settings.ThemedCellStyleList; import com.fr.design.i18n.Toolkit; @@ -24,46 +25,90 @@ public class ECPreviewPane extends AbstractECPreviewPane { private final List headerCellList = new ArrayList<>(); private final List contentCellList = new ArrayList<>(); private final List highLightCellList = new ArrayList<>(); + private final List assistCellList = new ArrayList<>(); private static final int COL_COUNT = 5; private static final int CONTENT_ROW_COUNT = 2; public ECPreviewPane() { - this.setPreferredSize(new Dimension(517, 147)); + this.setPreferredSize(new Dimension(517, 158)); this.setBorder(BorderFactory.createEmptyBorder(0, 1, 2, 1)); this.setLayout(FRGUIPaneFactory.createBorderLayout()); JPanel titlePane = new UINoOpaquePanel(new GridLayout()); - this.add(titlePane, BorderLayout.NORTH); - for (int i = 0; i < COL_COUNT; i++) { + JPanel extCenterPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + this.add(extCenterPane, BorderLayout.CENTER); + extCenterPane.add(titlePane, BorderLayout.NORTH); + for (int c = 0; c < COL_COUNT; c++) { PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); cell.setPreferredSize(new Dimension(103, 36)); titlePane.add(cell); headerCellList.add(cell); } JPanel contentPane = new UINoOpaquePanel(new GridLayout(2, 5, 0, 0)); - this.add(contentPane, BorderLayout.CENTER); + extCenterPane.add(contentPane, BorderLayout.CENTER); for (int i = 0; i < COL_COUNT * CONTENT_ROW_COUNT; i++) { PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Main_Text")); - cell.setPreferredSize(new Dimension(103, 33)); + int r = i / COL_COUNT; + int c = i % COL_COUNT; + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r > 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r < CONTENT_ROW_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(103, 30)); contentPane.add(cell); contentCellList.add(cell); } JPanel endPane = new UINoOpaquePanel(new GridLayout()); - this.add(endPane, BorderLayout.SOUTH); - for (int i = 0; i < COL_COUNT; i++) { + extCenterPane.add(endPane, BorderLayout.SOUTH); + for (int c = 0; c < COL_COUNT; c++) { PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); - cell.setPreferredSize(new Dimension(103, 33)); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(103, 30)); endPane.add(cell); highLightCellList.add(cell); } + + JPanel extSouthPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + PreviewCell assistCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Assist_Text")); + assistCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + assistCell.setPreferredSize(new Dimension(123, 30)); + assistCellList.add(assistCell); + extSouthPane.add(assistCell); + this.add(extSouthPane, BorderLayout.SOUTH); } @Override public void refresh(TemplateTheme theme) { ThemedCellStyleList cellStyleConfig = theme.getCellStyleList(); - refresh(headerCellList, getReportHeaderStyle(cellStyleConfig)); - refresh(contentCellList, getMainContentStyle(cellStyleConfig)); - refresh(highLightCellList, getHighLightStyle(cellStyleConfig)); + refresh(headerCellList, cellStyleConfig.getUse4Header()); + refresh(contentCellList, cellStyleConfig.getUse4MainText()); + refresh(highLightCellList, cellStyleConfig.getUse4HighlightText()); + refresh(assistCellList, cellStyleConfig.getUse4SupportInfo()); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECReportPreviewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECReportPreviewPane.java index a933f39489..98f75538f1 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECReportPreviewPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/ECReportPreviewPane.java @@ -1,5 +1,6 @@ package com.fr.design.mainframe.theme.preview.ecpreview; +import com.fr.base.CellBorderSourceFlag; import com.fr.base.theme.ReportTheme; import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.settings.ThemedCellStyleList; @@ -22,11 +23,12 @@ import java.util.ArrayList; import java.util.List; public class ECReportPreviewPane extends UINoOpaquePanel implements ThemePreviewed { - private final List headerTitleCellList = new ArrayList<>(); - private final List headerCellList = new ArrayList<>(); - private final List titleCellList = new ArrayList<>(); - private final List contentCellList = new ArrayList<>(); - private final List highLightCellList = new ArrayList<>(); + private final List headerTitleCellList = new ArrayList<>(); // 大标题样式单元格 + private final List headerCellList = new ArrayList<>(); // 表头样式单元格 + private final List titleCellList = new ArrayList<>(); // 小标题样式单元格 + private final List contentCellList = new ArrayList<>(); // 正文样式单元格 + private final List highLightCellList = new ArrayList<>(); // 高亮文本样式单元格 + private final List assistCellList = new ArrayList<>(); // 辅助信息样式单元格 private static final int CONTENT_ROW_COUNT = 3; private static final int COL_COUNT = 5; @@ -49,43 +51,52 @@ public class ECReportPreviewPane extends UINoOpaquePanel implements ThemePreview public PreviewPane() { this.setPreferredSize(new Dimension(517, 270)); - this.setBorder(BorderFactory.createEmptyBorder(7, 10, 5, 10)); + this.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); this.setLayout(FRGUIPaneFactory.createBorderLayout()); JPanel northPane = createNorthPane(); JPanel centerPane = createCenterPane(); + JPanel southPane = createSouthPane(); this.add(northPane, BorderLayout.NORTH); this.add(centerPane, BorderLayout.CENTER); + this.add(southPane, BorderLayout.SOUTH); } private JPanel createNorthPane() { JPanel northPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); AbstractPreviewCell bigTitleCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Cell_Style_Big_Title")); + bigTitleCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); bigTitleCell.setPreferredSize(new Dimension(615, 46)); headerTitleCellList.add(bigTitleCell); northPane.add(bigTitleCell, BorderLayout.NORTH); CornerPreviewCell cornerCell = new CornerPreviewCell(new String[]{Toolkit.i18nText("Fine-Design_Basic_Column_Name"), Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_EC_Data"), Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Row_Name")}, new Point2D[]{new Point(159, 71), new Point(225, 49)}); + cornerCell.setBorderSourceFlag(CellBorderSourceFlag.INVALID_BORDER_SOURCE); cornerCell.setPreferredSize(new Dimension(225, 71)); - headerCellList.add(cornerCell); + titleCellList.add(cornerCell); northPane.add(cornerCell, BorderLayout.WEST); JPanel centerPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); northPane.add(centerPane, BorderLayout.CENTER); PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Small_Title")); + cell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); titleCellList.add(cell); cell.setPreferredSize(new Dimension(308, 38)); centerPane.add(cell, BorderLayout.NORTH); JPanel eastSouthPane = new UINoOpaquePanel(new GridLayout()); - PreviewCell cell1 = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); - PreviewCell cell2 = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); - PreviewCell cell3 = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); - headerCellList.add(cell1); - headerCellList.add(cell2); - headerCellList.add(cell3); - eastSouthPane.add(cell1); - eastSouthPane.add(cell2); - eastSouthPane.add(cell3); + for (int c = 0; c < CONTENT_ROW_COUNT; c++) { + PreviewCell headerCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < CONTENT_ROW_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + headerCell.setBorderSourceFlag(flag); + headerCellList.add(headerCell); + eastSouthPane.add(headerCell); + } centerPane.add(eastSouthPane, BorderLayout.CENTER); return northPane; } @@ -99,8 +110,16 @@ public class ECReportPreviewPane extends UINoOpaquePanel implements ThemePreview cell1.setPreferredSize(new Dimension(112, 153)); westPane.add(cell1, BorderLayout.WEST); JPanel gridPane = new UINoOpaquePanel(new GridLayout(5, 1)); - for (int i = 0; i < COL_COUNT; i++) { + for (int r = 0; r < COL_COUNT; r++) { PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r > 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); cell.setPreferredSize(new Dimension(113, 31)); headerCellList.add(cell); gridPane.add(cell); @@ -111,11 +130,36 @@ public class ECReportPreviewPane extends UINoOpaquePanel implements ThemePreview centerPane.add(innerCenterPane, BorderLayout.CENTER); for (int i = 0; i < COL_COUNT * CONTENT_ROW_COUNT; i++) { PreviewCell cell ; - if ((i + 1) % CONTENT_ROW_COUNT == 0) { + int r = i / CONTENT_ROW_COUNT; + int c = i % CONTENT_ROW_COUNT; + if (c == CONTENT_ROW_COUNT - 1) { cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r != 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r != COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); highLightCellList.add(cell); } else { cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Main_Text")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r > 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < CONTENT_ROW_COUNT - 2) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + contentCellList.add(cell); } cell.setPreferredSize(new Dimension(123, 31)); @@ -126,14 +170,25 @@ public class ECReportPreviewPane extends UINoOpaquePanel implements ThemePreview return centerPane; } + private JPanel createSouthPane(){ + JPanel southPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + PreviewCell assistCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Assist_Text")); + assistCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + assistCell.setPreferredSize(new Dimension(123, 30)); + assistCellList.add(assistCell); + southPane.add(assistCell, BorderLayout.CENTER); + return southPane; + } + @Override public void refresh(TemplateTheme theme) { ThemedCellStyleList cellStyleConfig = theme.getCellStyleList(); - refresh(headerTitleCellList, getReportBigTitleStyle(cellStyleConfig)); - refresh(headerCellList, getReportHeaderStyle(cellStyleConfig)); - refresh(contentCellList, getMainContentStyle(cellStyleConfig)); - refresh(titleCellList, getSmallTitleStyle(cellStyleConfig)); - refresh(highLightCellList, getHighLightStyle(cellStyleConfig)); + refresh(headerTitleCellList, cellStyleConfig.getUse4BigTitle()); + refresh(headerCellList, cellStyleConfig.getUse4Header()); + refresh(contentCellList, cellStyleConfig.getUse4MainText()); + refresh(titleCellList, cellStyleConfig.getUse4SmallTitle()); + refresh(highLightCellList, cellStyleConfig.getUse4HighlightText()); + refresh(assistCellList, cellStyleConfig.getUse4SupportInfo()); } } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/cell/AbstractPreviewCell.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/cell/AbstractPreviewCell.java index a8a5f18924..cfecccd61a 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/cell/AbstractPreviewCell.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ecpreview/cell/AbstractPreviewCell.java @@ -1,25 +1,47 @@ package com.fr.design.mainframe.theme.preview.ecpreview.cell; +import com.fr.base.CellBorderSourceFlag; +import com.fr.base.CellBorderStyle; import com.fr.base.Style; +import com.fr.stable.Constants; + import javax.swing.JComponent; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; public abstract class AbstractPreviewCell extends JComponent { + private static final double BORDER_INSET = 0.5D; protected Style style = Style.DEFAULT_STYLE; private static final int NO_SCALE_RESOLUTION = 100; + private int borderSourceFlag = CellBorderSourceFlag.INVALID_BORDER_SOURCE; + public void setBorderSourceFlag(int borderSourceFlag) { + this.borderSourceFlag = borderSourceFlag; + } - public void refresh(Style style) { - this.style = style; + public void refresh(Style style, CellBorderStyle borderStyle) { + this.style = CellBorderSourceFlag.deriveBorderedStyle(style, borderStyle, borderSourceFlag); } public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; Style.paintBackground(g2d, style, getWidth(), getHeight()); paintContent(g2d, NO_SCALE_RESOLUTION); - Style.paintBorder(g2d, style, getWidth(), getHeight()); + paintBorder(g2d); + } + + private void paintBorder(Graphics2D g2d) { + double width = getWidth(); + double height = getHeight(); + if (style.getBorderLeft() == Constants.LINE_SLIM || style.getBorderRight() == Constants.LINE_SLIM) { + width -= BORDER_INSET; + } + if (style.getBorderBottom() == Constants.LINE_SLIM || style.getBorderTop() == Constants.LINE_SLIM) { + height -= BORDER_INSET; + } + g2d.setClip(null); + Style.paintBorder(g2d, style, width, height); } protected abstract void paintContent(Graphics2D g2d, int resolution); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/AbstractThemePreviewPaneProcessor.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/AbstractThemePreviewPaneProcessor.java new file mode 100644 index 0000000000..839944d9fe --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/AbstractThemePreviewPaneProcessor.java @@ -0,0 +1,23 @@ +package com.fr.design.mainframe.theme.processor; + +import com.fr.stable.fun.mark.API; + +/** + * @author Bruce.Deng + * @version 11.0 + * Created by Bruce.Deng on 2023/2/14 + */ +@API(level = ThemePreviewPaneProcessor.CURRENT_LEVEL) +public abstract class AbstractThemePreviewPaneProcessor implements ThemePreviewPaneProcessor { + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public int layerIndex() { + return DEFAULT_LAYER_INDEX; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/ThemePreviewPaneProcessor.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/ThemePreviewPaneProcessor.java new file mode 100644 index 0000000000..93b17b8e92 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/processor/ThemePreviewPaneProcessor.java @@ -0,0 +1,35 @@ +package com.fr.design.mainframe.theme.processor; + +import com.fr.base.theme.FormTheme; +import com.fr.base.theme.ReportTheme; +import com.fr.design.mainframe.theme.TemplateThemePreviewPane; +import com.fr.stable.fun.mark.Immutable; + +/** + * 主题样式预览界面接口 + * + * @author Bruce.Deng + * @version 11.0 + * Created by Bruce.Deng on 2023/2/14 + */ +public interface ThemePreviewPaneProcessor extends Immutable { + + String XML_TAG = "ThemePreviewPaneProcessor"; + + int CURRENT_LEVEL = 1; + + /** + * 创建报表主题样式预览界面 + * + * @return 报表主题样式预览界面 + */ + TemplateThemePreviewPane createReportThemePreviewPane(); + + /** + * 创建决策报表主题样式预览界面 + * + * @return 决策报表主题样式预览界面 + */ + TemplateThemePreviewPane createFormThemePreviewPane(); + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/CellElementStylePaster.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/CellElementStylePaster.java new file mode 100644 index 0000000000..983beda5e8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/CellElementStylePaster.java @@ -0,0 +1,99 @@ +package com.fr.design.mainframe.theme.utils; + +import com.fr.base.CloneTransformer; +import com.fr.base.NameStyle; +import com.fr.base.Style; +import com.fr.base.theme.FineColorSynchronizer; +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.settings.ThemedCellStyle; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.mainframe.JTemplate; +import com.fr.log.FineLoggerFactory; +import com.fr.report.cell.TemplateCellElement; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/9/21 + * + * 如果粘贴到的模板主题单元格样式与复制过来的主题单元格样式不同,那么需要转换复制过来的主题单元格样式为自定义样式,以保持被复制的样式。 + * 转换非主题单元格样式内的主题色,以及单元格内的其他主题色,为自定义色 + */ +public class CellElementStylePaster { + + /** + * 为没有实现FCloneable接口的类而抽象出的clone方法包装接口, + * 使用者需要实现此接口方法,调用真正的clone方法. + * @param + */ + private interface CloneExecutor { + T clone(T o) throws Exception; + } + private static boolean needConvertThemedStyleToCustomStyle(NameStyle nameStyle) { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentOpeningOrEditingTemplate(); + if (template != null) { + TemplateTheme theme = template.getTemplateTheme(); + if (theme != null) { + ThemedCellStyle themedCellStyle = theme.getCellStyleList().find(nameStyle.getName()); + return !nameStyle.getRealStyle().equals(themedCellStyle.getStyle()); + } + } + return false; + } + + + private static T convertThemedColorToCustomColor(T o, CloneExecutor executor) { + CloneTransformer.setTransformer(new FineColorSynchronizer.FineColorTransformer(fineColor -> { + fineColor.setHor(-1); + fineColor.setVer(-1); + })); + + Object cloned = null; + try { + cloned = executor.clone(o); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + CloneTransformer.clearTransformer(); + return (T) cloned; + } + + /** + * + * @param cellElement 粘贴到的单元格 + * @return + * 如果粘贴到的模板主题单元格样式与复制过来的主题单元格样式不同,那么需要转换复制过来的主题单元格样式为自定义样式,以保持被复制的样式。 + * 转换非主题单元格样式内的主题色,以及单元格内的其他主题色,为自定义色 + */ + public static TemplateCellElement convertStyleAndColor(TemplateCellElement cellElement) { + Style backupStyle = cellElement.getStyle(); + cellElement = convertThemedColorToCustomColor(cellElement, o -> (TemplateCellElement) o.clone()); + + Style style = convertStyleAndColor(backupStyle); + cellElement.setStyle(style); + + return cellElement; + } + + /** + * + * @param style + * @return + * 如果粘贴到的模板主题单元格样式与复制过来的主题单元格样式不同,那么需要转换复制过来的主题单元格样式为自定义样式,以保持被复制的样式。 + * 转换非主题单元格样式内的主题色 + */ + public static Style convertStyleAndColor(Style style) { + if (style instanceof NameStyle) { + NameStyle nameStyle = (NameStyle) style; + if (needConvertThemedStyleToCustomStyle(nameStyle)) { + style = nameStyle.getRealStyle(); + } + } + if (!(style instanceof NameStyle)) { + style = convertThemedColorToCustomColor(style, o -> (Style) o.clone()); + } + + return style; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java index 67be5cc9aa..0923c7f659 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java @@ -3,8 +3,11 @@ package com.fr.design.mainframe.theme.utils; import com.fr.base.NameStyle; import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.settings.ThemedCellStyle; +import com.fr.design.base.mode.DesignModeContext; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.mainframe.JTemplate; +import com.fr.design.utils.DesignUtils; import com.fr.report.cell.DefaultTemplateCellElement; /** @@ -31,15 +34,19 @@ public class DefaultThemedTemplateCellElementCase { } private static DefaultTemplateCellElement themingCellElement(DefaultTemplateCellElement cellElement) { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (template != null) { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentOpeningOrEditingTemplate(); + if (JTemplate.isValid(template)) { TemplateTheme theme = template.getTemplateTheme(); ThemedCellStyle themedCellStyle = theme.getCellStyleList().getUse4Default(); if (themedCellStyle != null) { NameStyle nameStyle = NameStyle.getPassiveInstance(themedCellStyle.getName(), themedCellStyle.getStyle()); - cellElement.setStyle(nameStyle); + cellElement.setStyle(DesignModeContext.isDuchampMode() ? nameStyle.getRealStyle() : nameStyle); } } + DefaultValueAdjustProvider adjustProvider = DesignUtils.getValueAdjust(); + if (adjustProvider != null) { + adjustProvider.adjustCellElement(cellElement); + } return cellElement; } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java b/designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java index 4e69c34c56..fc326c60e6 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java @@ -6,17 +6,17 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.stable.Constants; -import java.awt.Dialog; -import java.awt.Frame; -import java.awt.Window; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.SwingConstants; import java.awt.BorderLayout; +import java.awt.Dialog; import java.awt.Dimension; import java.awt.Font; +import java.awt.Frame; +import java.awt.Window; /** * Created by kerry on 5/6/21 @@ -31,6 +31,13 @@ public class DesignerToastMsgUtil { } + public static ToastMsgDialog createPromptDialog(String text) { + return createDialog(PROMPT_ICON, toastPane(text), DesignerContext.getDesignerFrame()); + } + + public static ToastMsgDialog createPromptDialog(JPanel contentPane) { + return createDialog(PROMPT_ICON, contentPane, DesignerContext.getDesignerFrame()); + } public static void toastPrompt(JPanel contendPane) { toastPane(PROMPT_ICON, contendPane, DesignerContext.getDesignerFrame()); @@ -69,6 +76,11 @@ public class DesignerToastMsgUtil { } private static void toastPane(Icon icon, JPanel contendPane, Window parent) { + ToastMsgDialog dialog = createDialog(icon, contendPane, parent); + dialog.setVisible(true); + } + + private static ToastMsgDialog createDialog(Icon icon, JPanel contendPane, Window parent) { JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane(); UILabel uiLabel = new UILabel(icon); uiLabel.setVerticalAlignment(SwingConstants.TOP); @@ -83,7 +95,7 @@ public class DesignerToastMsgUtil { } else { dialog = new ToastMsgDialog((Frame) parent, pane); } - dialog.setVisible(true); + return dialog; } @@ -118,4 +130,4 @@ public class DesignerToastMsgUtil { .toString(); } -} +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java new file mode 100644 index 0000000000..3764cbcd83 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java @@ -0,0 +1,194 @@ +package com.fr.design.mainframe.toast; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.dialog.UIDialog; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.module.ModuleContext; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Window; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * toast弹窗 + * */ +public class SimpleToast extends UIDialog { + private static final int MIN_HEIGHT = 36; + private static final String TOAST_MSG_TIMER = "TOAST_MSG_TIMER"; + private static final long DEFAULT_DISAPPEAR_DELAY = 5000; + private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS; + + + private ScheduledExecutorService timer; + private int hideHeight = 0; + private JPanel contentPane; + private boolean show = false; + private Window parent; + private boolean autoDisappear; + + public SimpleToast(Window parent, Icon icon, String text, boolean autoDisappear) { + super(parent); + this.parent = parent; + this.autoDisappear = autoDisappear; + JPanel panel = createContentPane(icon, text); + init(panel); + } + + private JPanel createContentPane(Icon icon, String text) { + JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel iconLabel = new UILabel(icon); + iconLabel.setVerticalAlignment(SwingConstants.TOP); + iconLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0)); + + + UILabel textLabel = new UILabel(text); + pane.add(iconLabel, BorderLayout.WEST); + pane.add(textLabel, BorderLayout.CENTER); + pane.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15)); + + return pane; + } + + + private void init(JPanel panel) { + setFocusable(false); + setAutoRequestFocus(false); + setUndecorated(true); + contentPane = panel; + initComponent(); + } + + private void initComponent() { + this.getContentPane().setLayout(null); + this.getContentPane().add(contentPane); + Dimension dimension = calculatePreferSize(); + hideHeight = dimension.height; + setSize(new Dimension(dimension.width, 0)); + contentPane.setSize(dimension); + setRelativeLocation(dimension); + if (autoDisappear) { + disappear(contentPane); + } + } + + private void setRelativeLocation(Dimension dimension) { + int positionX = parent.getLocationOnScreen().x + (parent.getWidth() - dimension.width) / 2; + int positionY = parent.getLocationOnScreen().y + 10; + this.setLocation(positionX, positionY); + } + + private Dimension calculatePreferSize() { + Dimension contentDimension = contentPane.getPreferredSize(); + int height = Math.max(MIN_HEIGHT, contentDimension.height); + return new Dimension(contentDimension.width, height); + } + + + public void display(JPanel outerPanel) { + show = true; + outerPanel.setLocation(0, -hideHeight); + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + displayStep(outerPanel, tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + + } + + void displayStep(JPanel outerPanel, ScheduledExecutorService timer) { + Point point = outerPanel.getLocation(); + if (point.y >= 0 && !timer.isShutdown()) { + timer.shutdown(); + } + int showDistance = 5 + point.y < 0 ? 5 : -point.y; + outerPanel.setLocation(point.x, point.y + showDistance); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height + showDistance)); + } + + + + + + + private void disappear(JPanel outerPanel, long delay, TimeUnit timeUnit) { + timer = createToastScheduleExecutorService(); + timer.schedule(new DisappearMotion(outerPanel), delay, timeUnit); + } + + /** + * toast消失的动画效果 + * */ + class DisappearMotion implements Runnable { + JPanel panel; + + DisappearMotion(JPanel panel) { + this.panel = panel; + } + + @Override + public void run() { + ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService(); + tipToolTimer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(()->{ + disappearStep(tipToolTimer); + }); + } + }, 0, 50, TimeUnit.MILLISECONDS); + } + + void disappearStep(ScheduledExecutorService timer) { + Point point = panel.getLocation(); + if (point.y <= -hideHeight && !timer.isShutdown()) { + timer.shutdown(); + SimpleToast.this.setVisible(false); + SimpleToast.this.dispose(); + SimpleToast.this.show = false; + } + panel.setLocation(point.x, point.y - 5); + Dimension dimension = SimpleToast.this.getSize(); + SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height - 5)); + } + } + + private void disappear(JPanel outerPanel) { + disappear(outerPanel, DEFAULT_DISAPPEAR_DELAY, DEFAULT_TIME_UNIT); + } + + private ScheduledExecutorService createToastScheduleExecutorService() { + return ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory(TOAST_MSG_TIMER)); + } + + @Override + public void checkValid() throws Exception { + } + + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + display(contentPane); + } + } + + @Override + public void dispose() { + super.dispose(); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java index 00f4f95ead..83cd84e9cc 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java @@ -3,10 +3,11 @@ package com.fr.design.mainframe.toast; import com.fr.concurrent.NamedThreadFactory; import com.fr.design.dialog.UIDialog; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrame; import com.fr.module.ModuleContext; -import java.awt.Dialog; import javax.swing.JPanel; +import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; import java.awt.Point; @@ -24,6 +25,7 @@ public class ToastMsgDialog extends UIDialog { private ScheduledExecutorService TIMER; private int hide_height = 0; private JPanel contentPane; + private boolean show = false; public ToastMsgDialog(Frame parent, JPanel panel) { super(parent); @@ -50,12 +52,16 @@ public class ToastMsgDialog extends UIDialog { hide_height = dimension.height; setSize(new Dimension(dimension.width, 0)); contentPane.setSize(dimension); - setLocationRelativeTo(DesignerContext.getDesignerFrame().getContentFrame()); - int positionY = DesignerContext.getDesignerFrame().getContentFrame().getLocationOnScreen().y + 10; - setLocation((DesignerContext.getDesignerFrame().getWidth() - dimension.width) / 2, positionY); + setRelativeLocation(dimension); addMouseEvent(contentPane); } + private void setRelativeLocation(Dimension dimension) { + DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); + int positionX = designerFrame.getLocationOnScreen().x + (designerFrame.getWidth() - dimension.width) / 2; + int positionY = designerFrame.getContentFrame().getLocationOnScreen().y + 10; + this.setLocation(positionX, positionY); + } private Dimension calculatePreferSize() { Dimension contentDimension = contentPane.getPreferredSize(); @@ -65,6 +71,7 @@ public class ToastMsgDialog extends UIDialog { public void display(JPanel outerJPanel) { + show = true; outerJPanel.setLocation(0, -hide_height); ScheduledExecutorService TIP_TOOL_TIMER = createToastScheduleExecutorService(); TIP_TOOL_TIMER.scheduleAtFixedRate(new Runnable() { @@ -98,12 +105,13 @@ public class ToastMsgDialog extends UIDialog { TIP_TOOL_TIMER.shutdown(); ToastMsgDialog.this.setVisible(false); ToastMsgDialog.this.dispose(); + ToastMsgDialog.this.show = false; } outerJPanel.setLocation(point.x, point.y - 5); Dimension dimension = ToastMsgDialog.this.getSize(); ToastMsgDialog.this.setSize(new Dimension(dimension.width, dimension.height - 5)); } - }, 0,50, TimeUnit.MILLISECONDS); + }, 0, 50, TimeUnit.MILLISECONDS); } }, 5000, TimeUnit.MILLISECONDS); @@ -159,5 +167,7 @@ public class ToastMsgDialog extends UIDialog { super.dispose(); } - -} + public boolean isShow() { + return show; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index c4ad83ca7a..3c75eff39d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java @@ -17,6 +17,7 @@ import com.fr.design.actions.community.FacebookFansAction; import com.fr.design.actions.community.NeedAction; import com.fr.design.actions.community.QuestionAction; import com.fr.design.actions.community.SignAction; +import com.fr.design.actions.community.StudyPlanAction; import com.fr.design.actions.community.TechSolutionAction; import com.fr.design.actions.community.TechSupportAction; import com.fr.design.actions.community.TemplateStoreAction; @@ -55,14 +56,17 @@ import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.locale.impl.SupportLocaleImpl; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.ToolBarNewTemplatePane; +import com.fr.design.mainframe.platform.ServicePlatformAction; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; +import com.fr.design.module.DesignModuleFactory; import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.remote.action.RemoteDesignAuthManagerAction; import com.fr.design.update.actions.SoftwareUpdateAction; import com.fr.design.utils.ThemeUtils; +import com.fr.env.detect.ui.EnvDetectorAction; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralContext; import com.fr.general.locale.LocaleAction; @@ -500,10 +504,7 @@ public abstract class ToolBarMenuDock { addPluginManagerAction(menuDef); menuDef.addShortCut(new FunctionManagerAction()); - if (!DesignModeContext.isDuchampMode()) { - menuDef.addShortCut(new GlobalParameterAction()); - } - + menuDef.addShortCut(new GlobalParameterAction()); } @@ -572,6 +573,13 @@ public abstract class ToolBarMenuDock { shortCuts.add(new AlphaFineAction()); } + shortCuts.add(new EnvDetectorAction()); + //服务平台(仅针对中国大陆) + if (GeneralContext.getLocale().equals(Locale.CHINA)) { + shortCuts.add(new ServicePlatformAction()); + } + + shortCuts.add(SeparatorDef.DEFAULT); if (DesignerEnvManager.getEnvManager().isOpenDebug()) { OSSupportCenter.buildAction(objects -> shortCuts.add(new FineUIAction()), SupportOSImpl.FINEUI); @@ -579,6 +587,7 @@ public abstract class ToolBarMenuDock { } shortCuts.add(new AboutAction()); + return shortCuts.toArray(new ShortCut[0]); } @@ -601,6 +610,7 @@ public abstract class ToolBarMenuDock { shortCuts.add(new TutorialAction()); } }, SupportLocaleImpl.TUTORIAL_COMMUNITY); + shortCuts.add(new StudyPlanAction()); shortCuts.add(new QuestionAction()); shortCuts.add(new TechSolutionAction()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java index 0ec5b9c4f5..c72fa68dc4 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java @@ -13,6 +13,7 @@ import com.fr.design.mainframe.JTemplateActionListener; import com.fr.design.mainframe.vcs.VcsConfigManager; import com.fr.design.mainframe.vcs.ui.FileVersionTable; import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; import com.fr.plugin.context.PluginContext; import com.fr.plugin.manage.PluginManager; import com.fr.report.entity.VcsEntity; @@ -24,8 +25,10 @@ import com.fr.workspace.server.vcs.filesystem.VcsFileSystem; import com.fr.workspace.server.vcs.git.config.GcConfig; import javax.swing.Icon; +import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import java.awt.Color; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -49,6 +52,8 @@ public class VcsHelper implements JTemplateActionListener { public final static int OFFSET = 2; private static final int MINUTE = 60 * 1000; private final static String VCS_PLUGIN_ID = "com.fr.plugin.vcs.v10"; + private final static String VCS_FILE_SLASH = "/"; + private final static String SERVICE_NAME_MOVE = "moveVcs"; private static final VcsHelper INSTANCE = new VcsHelper(); public static VcsHelper getInstance() { @@ -97,7 +102,7 @@ public class VcsHelper implements JTemplateActionListener { } else if (editingFilePath.startsWith(vcsCacheDir)) { editingFilePath = editingFilePath.replaceFirst(vcsCacheDir, StringUtils.EMPTY); } - if (editingFilePath.startsWith("/")) { + if (editingFilePath.startsWith(VCS_FILE_SLASH)) { editingFilePath = editingFilePath.substring(1); } return editingFilePath; @@ -133,20 +138,18 @@ public class VcsHelper implements JTemplateActionListener { String fileName = getEditingFilename(); VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); VcsEntity entity = operator.getFileVersionByIndex(fileName, 0); + boolean replace = needDeleteVersion(entity); int latestFileVersion = 0; if (entity != null) { latestFileVersion = entity.getVersion(); } if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) { - operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1); + operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace); String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); - FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", ""))); + List updatedList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY)); + SwingUtilities.invokeLater(() -> FileVersionTable.getInstance().updateModel(1, updatedList)); } else { - operator.saveVersion(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1); - } - VcsEntity oldEntity = WorkContext.getCurrent().get(VcsOperator.class).getFileVersionByIndexAndUsername(fileName, getCurrentUsername(), 1); - if (needDeleteVersion(oldEntity)) { - operator.deleteVersion(oldEntity.getFilename(), oldEntity.getVersion()); + operator.saveVersion(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace); } if (GcConfig.getInstance().isGcEnable()) { operator.gc(); @@ -157,6 +160,33 @@ public class VcsHelper implements JTemplateActionListener { fireVcs.shutdown(); } + /** + * 移动Vcs + * @param oldName + * @param newName + */ + public void moveVcs(String oldName, String newName) { + ExecutorService moveVcs = Executors.newSingleThreadExecutor(new NamedThreadFactory(SERVICE_NAME_MOVE)); + moveVcs.execute(new Runnable() { + @Override + public void run() { + VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); + String oldPath = oldName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY); + List oldVcsEntities = operator.getVersions(oldPath); + + for (VcsEntity oldVcsEntity : oldVcsEntities) { + operator.saveVersion(oldVcsEntity.getUsername(), newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY), oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion()); + operator.deleteVersion(oldPath, oldVcsEntity.getVersion()); + } + FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, newName); + if (GcConfig.getInstance().isGcEnable()) { + operator.gc(); + } + } + }); + moveVcs.shutdown(); + } + @Override public void templateOpened(JTemplate jt) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java index bf5b8ba45b..8cff3ffbb1 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionCellEditor.java @@ -1,7 +1,7 @@ package com.fr.design.mainframe.vcs.ui; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.JTemplate; @@ -57,9 +57,9 @@ public class FileVersionCellEditor extends AbstractCellEditor implements TableCe jt.stopEditing(); //只有模板路径一致时关闭当前模板 if (ComparatorUtils.equals(fileOfVersion, jt.getPath())) { - MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); - MutilTempalteTabPane.getInstance().closeFormat(jt); - MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(true); + MultiTemplateTabPane.getInstance().closeFormat(jt); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(jt); } //再打开cache中的模板 diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java index 4d9b6e35e6..4dd14bce6d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/FileVersionsPanel.java @@ -5,7 +5,7 @@ import com.fr.design.base.mode.DesignModeContext; import com.fr.design.base.mode.DesignerMode; import com.fr.design.dialog.BasicPane; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; @@ -115,9 +115,9 @@ public class FileVersionsPanel extends BasicPane { // 关闭当前打开的版本 JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); - MutilTempalteTabPane.getInstance().closeFormat(jt); - MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(true); + MultiTemplateTabPane.getInstance().closeFormat(jt); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(jt); updateDesignerFrame(true); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/MobileTabFontConfPane.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/MobileTabFontConfPane.java index b4d678f985..8f10d21020 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/MobileTabFontConfPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/MobileTabFontConfPane.java @@ -5,6 +5,7 @@ import com.fr.base.Utils; import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.utils.DesignUtils; import com.fr.general.FRFont; import javax.swing.Icon; @@ -38,7 +39,7 @@ public class MobileTabFontConfPane extends JPanel { private void init() { this.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); - fontFamily = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontFamily = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); Vector integerList = new Vector(); for (int i = 1; i < 100; i++) { integerList.add(i); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AbstractTemplateStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AbstractTemplateStylePane.java index 482b2cebcd..399047a853 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AbstractTemplateStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AbstractTemplateStylePane.java @@ -7,4 +7,8 @@ public abstract class AbstractTemplateStylePane extends BasicPane { public abstract void populate(T ob); public abstract T update(); + + public AbstractTemplateStylePane generateCleanPane() { + return this; + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTemplateStyleEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTemplateStyleEditor.java index 195a92e8a9..4f863e28b8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTemplateStyleEditor.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTemplateStyleEditor.java @@ -32,6 +32,11 @@ public class AccessibleTemplateStyleEditor extends UneditableAccessibleEditor { setValue(stylePane.update()); fireStateChanged(); } + + @Override + public void doCancel() { + stylePane = stylePane.generateCleanPane(); + } }); stylePane.populate(getValue()); dlg.setVisible(true); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java index 5ce099c91f..5b04ef0143 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java @@ -23,7 +23,7 @@ public class AccessibleTreeModelEditor extends UneditableAccessibleEditor { @Override protected void showEditorPane() { if (treeSettingPane == null) { - treeSettingPane = new TreeSettingPane(false); + treeSettingPane = new TreeSettingPane(); } BasicDialog dlg = treeSettingPane.showWindow(SwingUtilities.getWindowAncestor(this)); treeSettingPane.populate(getValue()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/MobileTemplateStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/MobileTemplateStylePane.java index 38f70de814..55c543b8f8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/MobileTemplateStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/MobileTemplateStylePane.java @@ -44,12 +44,14 @@ public class MobileTemplateStylePane extends AbstractTemplateStylePane> extraStyle = new HashSet<>(); + private WCardTagLayout tagLayout; public MobileTemplateStylePane(WCardTagLayout tagLayout){ init(tagLayout); } public void init(WCardTagLayout tagLayout){ this.setLayout(FRGUIPaneFactory.createBorderLayout()); + this.tagLayout = tagLayout; listModel = new DefaultListModel(); card = new CardLayout(); right = FRGUIPaneFactory.createCardLayout_S_Pane(); @@ -147,4 +149,9 @@ public class MobileTemplateStylePane extends AbstractTemplateStylePane generateCleanPane() { + return new MobileTemplateStylePane(this.tagLayout); + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java index 8a2489407c..00171f3fb0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java @@ -6,8 +6,7 @@ import com.fr.data.impl.TreeNodeWrapper; import com.fr.design.Exception.ValidationException; import com.fr.design.designer.properties.Decoder; import com.fr.design.designer.properties.Encoder; - -import com.fr.general.NameObject; +import com.fr.form.ui.tree.LayerConfig; import com.fr.stable.StringUtils; public class TreeModelWrapper implements Encoder, Decoder { @@ -22,7 +21,7 @@ public class TreeModelWrapper implements Encoder, Decoder { } else if (v instanceof TreeNodeWrapper) { TreeNodeAttr[] treeNodeAttrs = ((TreeNodeWrapper) v).getTreeNodeAttrs(); return TemplateUtils.render(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Total_N_Grade"), new String[]{"N"}, new String[]{treeNodeAttrs.length + ""}); - } else if (v instanceof NameObject) { + } else if (v instanceof LayerConfig[]) { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DataTable_Build"); } else { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Auto_Build"); diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java b/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java index 6c8a123fd9..e66f4c9fd4 100644 --- a/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java +++ b/designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java @@ -1,32 +1,15 @@ package com.fr.design.mod; -import com.fr.base.Formula; -import com.fr.base.headerfooter.FormulaHFElement; -import com.fr.base.present.FormulaPresent; -import com.fr.chart.web.ChartHyperRelateCellLink; -import com.fr.chart.web.ChartHyperRelateFloatLink; -import com.fr.data.SimpleDSColumn; -import com.fr.data.condition.FormulaCondition; -import com.fr.data.impl.FormulaDictionary; -import com.fr.data.impl.NameTableData; import com.fr.design.mod.impl.repalce.JavaScriptContentReplacer; import com.fr.design.mod.impl.repalce.VanChartHtmlLabelContentReplacer; -import com.fr.form.main.FormHyperlink; -import com.fr.form.ui.CardSwitchButton; -import com.fr.form.ui.WidgetTitle; -import com.fr.invoke.ClassHelper; +import com.fr.form.ui.Widget; import com.fr.js.JavaScriptImpl; +import com.fr.log.FineLoggerFactory; import com.fr.plugin.chart.base.VanChartHtmlLabel; -import com.fr.report.cell.cellattr.CellExpandAttr; -import com.fr.report.cell.cellattr.CellGUIAttr; -import com.fr.report.cell.cellattr.core.RichChar; -import com.fr.report.cell.cellattr.core.group.DSColumn; -import com.fr.report.cell.cellattr.core.group.FunctionGrouper; -import com.fr.report.cell.cellattr.core.group.SelectCount; -import com.fr.stable.Filter; + +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import org.jetbrains.annotations.Nullable; @@ -49,53 +32,36 @@ public class ContentObjectManager { /** * 放置所有需要替换内容的对象 */ - private Map> objectMap; - - private final Set set = new HashSet<>(); + private Map> objectMap = new HashMap<>(); private final Map map = new HashMap<>(); + private boolean needCollect = false; + private ContentObjectManager() { - set.add(Formula.class.getName()); - set.add(JavaScriptImpl.class.getName()); - set.add(ChartHyperRelateCellLink.class.getName()); - set.add(ChartHyperRelateFloatLink.class.getName()); - set.add(VanChartHtmlLabel.class.getName()); - set.add(NameTableData.class.getName()); - set.add(SimpleDSColumn.class.getName()); - set.add(DSColumn.class.getName()); - set.add(FormHyperlink.class.getName()); - set.add(CellExpandAttr.class.getName()); - set.add(FormulaCondition.class.getName()); - set.add(FormulaDictionary.class.getName()); - set.add(FormulaHFElement.class.getName()); - set.add(FormulaPresent.class.getName()); - set.add(RichChar.class.getName()); - set.add(CardSwitchButton.class.getName()); - set.add(CellGUIAttr.class.getName()); - set.add(SelectCount.class.getName()); - set.add(WidgetTitle.class.getName()); - set.add(FunctionGrouper.class.getName()); map.put(JavaScriptImpl.class.getName(), new JavaScriptContentReplacer()); map.put(VanChartHtmlLabel.class.getName(), new VanChartHtmlLabelContentReplacer()); } - public void searchObject(Object ob) { - objectMap = ClassHelper.searchObject(ob, set, ModClassFilter.getInstance()); - } - - public void searchObject(Object ob, Filter filter) { - objectMap = ClassHelper.searchObject(ob, set, filter); + @Nullable + public Widget searchObject(Widget widget) { + try { + needCollect = true; + objectMap.clear(); + Widget clonedWidget = (Widget) widget.clone(); + needCollect = false; + return clonedWidget; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + // 防止抛出异常未重置 + needCollect = false; + } + return null; } - public void searchObject(Object ob, Set set, Filter filter) { - objectMap = ClassHelper.searchObject(ob, set, filter); - } public void clearObject() { - if (objectMap != null) { - objectMap.clear(); - } - objectMap = null; + objectMap.clear(); } @Nullable @@ -103,8 +69,15 @@ public class ContentObjectManager { return objectMap; } - public boolean needContentTip(Object ob, Set nameSet) { - objectMap = ClassHelper.searchObject(ob, set, ModClassFilter.getInstance()); + public void collect(Object ob) { + if (needCollect) { + Collection collection = objectMap.computeIfAbsent(ob.getClass().getName(), k -> new ArrayList<>()); + collection.add(ob); + } + } + + public boolean needContentTip(Widget ob, Set nameSet) { + collect(ob); for (Map.Entry> entry : objectMap.entrySet()) { for (Object o : entry.getValue()) { for (String name : nameSet) { diff --git a/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java b/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java index 91f9bf3dc7..917fff23a8 100644 --- a/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java +++ b/designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java @@ -70,9 +70,6 @@ public class ContentReplacerCenter { @Override public void on(Event event, ContentChangeItem param) { itemsMap.put(param.getChangeItem(), param); - long start = System.currentTimeMillis(); - ContentObjectManager.getInstance().searchObject(param.getObject()); - FineLoggerFactory.getLogger().debug("search object spend {} ms", (System.currentTimeMillis() - start)); FineLoggerFactory.getLogger().debug("search result: {}", ContentObjectManager.getInstance().getObjectMap() == null ? null : ContentObjectManager.getInstance().getObjectMap().keySet()); List itemsCopy = new ArrayList<>(itemsMap.values()); diff --git a/designer-base/src/main/java/com/fr/design/module/DesignModuleFactory.java b/designer-base/src/main/java/com/fr/design/module/DesignModuleFactory.java index 5ff882f642..cccd6f71e6 100644 --- a/designer-base/src/main/java/com/fr/design/module/DesignModuleFactory.java +++ b/designer-base/src/main/java/com/fr/design/module/DesignModuleFactory.java @@ -1,6 +1,7 @@ package com.fr.design.module; import com.fr.base.chart.BaseChartCollection; +import com.fr.design.actions.help.replace.ITReplaceOperator; import com.fr.design.gui.chart.BaseChartPropertyPane; import com.fr.design.gui.chart.MiddleChartComponent; import com.fr.design.gui.chart.MiddleChartDialog; @@ -18,6 +19,7 @@ import com.fr.log.FineLoggerFactory; import com.fr.plugin.solution.sandbox.collection.PluginSandboxCollections; import com.fr.stable.StableUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; import java.awt.Dialog; @@ -47,8 +49,10 @@ public class DesignModuleFactory { private Class autoChartDialogClass; private Class chartPropertyPaneClass; private Class newFormAction; + private Class ITReplaceAction; private Class formParaDesigner; private Class paraPropertyPane; + private static ITReplaceOperator replaceHelper; private Class formHierarchyPaneCls; private Class widgetPropertyPane; private Class buttonDetailPaneClass; @@ -69,7 +73,7 @@ public class DesignModuleFactory { @NotNull public static NameableCreator[] getCreators4Hyperlink() { - return instance.creators4Hyperlink == null? new NameableCreator[0]:instance.creators4Hyperlink; + return instance.creators4Hyperlink == null ? new NameableCreator[0] : instance.creators4Hyperlink; } public static void registerExtraWidgetOptions(WidgetOption[] options) { @@ -117,6 +121,48 @@ public class DesignModuleFactory { return instance.newFormAction; } + /** + * 注册一下查找替换 + * + * @param r + */ + public static void registerReplaceActionClass(Class r) { + instance.ITReplaceAction = r; + } + + /** + * 获取查找替换 + * + * @return ITReplaceAction + */ + @Nullable + public static Object getITReplaceAction() { + try { + if (instance.ITReplaceAction != null) { + return instance.ITReplaceAction.newInstance(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } + + /** + * 注册一下查找替换面板 + * @param + */ + public static void registerReplace(ITReplaceOperator replace) { + replaceHelper = replace; + } + + /** + * 获取查找替换面板的操作类 + * @return + */ + public static ITReplaceOperator getReplaceOperator() { + return replaceHelper; + } + public static void registerParaPropertyPaneClass(Class p) { instance.paraPropertyPane = p; } diff --git a/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java b/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java index 3faadf795a..12e3503a06 100644 --- a/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java +++ b/designer-base/src/main/java/com/fr/design/notification/NotificationCenter.java @@ -2,6 +2,8 @@ package com.fr.design.notification; import com.fr.design.notification.ui.NotificationCenterPane; +import com.fr.stable.StringUtils; + import java.util.ArrayList; import java.util.List; @@ -30,6 +32,15 @@ public class NotificationCenter { NotificationCenterPane.getNotificationCenterPane().refreshButton(); } + /** + * 通过messageId删除消息 + * @param messageID + */ + public void removeNotificationByMessageID(String messageID) { + notifications.removeIf(notification -> StringUtils.equals(notification.getMessageId(), messageID)); + NotificationCenterPane.getNotificationCenterPane().refreshButton(); + } + public Notification getNotification(int index){ return notifications.get(index); } diff --git a/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterDialog.java b/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterDialog.java index 10e10ecdbb..2541d04b43 100644 --- a/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterDialog.java +++ b/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterDialog.java @@ -2,6 +2,7 @@ package com.fr.design.notification.ui; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; import com.fr.design.notification.Notification; import com.fr.design.notification.NotificationCenter; import java.awt.BorderLayout; @@ -119,7 +120,7 @@ public class NotificationCenterDialog extends JDialog { if (winSize.width > screenSize.width) { winSize.width = screenSize.width; } - //这里设置位置:水平居中,竖直偏上 - win.setLocation(screenSize.width - winSize.width - 90, 50); + win.setLocation((DesignerContext.getDesignerFrame().getWidth() - winSize.width - 100 + DesignerContext.getDesignerFrame().getX()), + DesignerContext.getDesignerFrame().getY() + winSize.height); } } diff --git a/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterPane.java b/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterPane.java index 3ec5a53a98..8e5c3ff404 100644 --- a/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterPane.java +++ b/designer-base/src/main/java/com/fr/design/notification/ui/NotificationCenterPane.java @@ -1,5 +1,6 @@ package com.fr.design.notification.ui; +import com.fr.base.svg.IconUtils; import com.fr.design.constants.UIConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.ibutton.UIButton; @@ -20,7 +21,7 @@ public class NotificationCenterPane extends BasicPane { setPreferredSize(new Dimension(24, 24)); setLayout(new BorderLayout()); notificationCenterButton = new UIButton(); - notificationCenterButton.setIcon(IOUtils.readIcon("/com/fr/design/notification/ui/notificationCenter.png")); + notificationCenterButton.setIcon(IconUtils.readIcon("/com/fr/design/standard/notification/notification")); notificationCenterButton.setToolTipText(Toolkit.i18nText("Fine-Design_Basic_Show_Notification")); notificationCenterButton.set4ToolbarButton(); notificationCenterButton.setRolloverEnabled(false); @@ -41,9 +42,9 @@ public class NotificationCenterPane extends BasicPane { public void refreshButton() { if (NotificationCenter.getInstance().getNotificationsCount() > 0) { - notificationCenterButton.setIcon(IOUtils.readIcon("/com/fr/design/notification/ui/notificationCenterDot.png")); + notificationCenterButton.setIcon(IconUtils.readIcon("/com/fr/design/standard/notification/notification_dot.svg")); } else { - notificationCenterButton.setIcon(IOUtils.readIcon("/com/fr/design/notification/ui/notificationCenter.png")); + notificationCenterButton.setIcon(IconUtils.readIcon("/com/fr/design/standard/notification/notification")); } } diff --git a/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java b/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java index 990e73ee9c..16944da068 100644 --- a/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java +++ b/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java @@ -1,6 +1,7 @@ package com.fr.design.os.impl; import com.fr.config.ServerPreferenceConfig; +import com.fr.design.DesignerEnvManager; import com.fr.design.extra.WebViewDlgHelper; import com.fr.design.jdk.JdkVersion; import com.fr.design.upm.UpmFinder; @@ -23,7 +24,9 @@ public class PMDialogAction implements OSBasedAction { DesignUtils.visitEnvServerByParameters( PLUGIN_MANAGER_ROUTE,null,null); return; } - if (ServerPreferenceConfig.getInstance().isUseOptimizedUPM() || SupportOSImpl.MACOS_NEW_PLUGIN_MANAGEMENT.support()) { + if (ServerPreferenceConfig.getInstance().isUseOptimizedUPM() + || SupportOSImpl.MACOS_NEW_PLUGIN_MANAGEMENT.support() + || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()) { UpmFinder.showUPMDialog(); } else { WebViewDlgHelper.createPluginDialog(); diff --git a/designer-base/src/main/java/com/fr/design/os/impl/SupportOSImpl.java b/designer-base/src/main/java/com/fr/design/os/impl/SupportOSImpl.java index 949d770456..d8eda915b7 100644 --- a/designer-base/src/main/java/com/fr/design/os/impl/SupportOSImpl.java +++ b/designer-base/src/main/java/com/fr/design/os/impl/SupportOSImpl.java @@ -1,19 +1,25 @@ package com.fr.design.os.impl; import com.fr.base.FRContext; +import com.fr.design.config.DesignerProperties; import com.fr.design.jdk.JdkVersion; import com.fr.general.CloudCenter; import com.fr.general.GeneralContext; import com.fr.json.JSON; import com.fr.json.JSONFactory; import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.stable.os.Arch; import com.fr.stable.os.OperatingSystem; import com.fr.stable.os.support.SupportOS; import com.fr.workspace.WorkContext; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.Scanner; /** * @author pengda @@ -22,11 +28,11 @@ import java.util.Locale; public enum SupportOSImpl implements SupportOS { /** - * ARM下屏蔽登录 + * 屏蔽登录入口 */ - USERINFOPANE{ + BBS_USER_LOGIN_PANE { public boolean support(){ - return Arch.getArch() != Arch.ARM; + return Arch.getArch() != Arch.ARM && DesignerProperties.getInstance().isSupportLoginEntry(); } }, /** @@ -142,6 +148,51 @@ public enum SupportOSImpl implements SupportOS { } }, + OLD_STYLE_CHOOSER { + + @Override + public boolean support() { + boolean javafxExist = true; + try { + Class.forName("javafx.stage.FileChooser"); + } catch (ClassNotFoundException e) { + javafxExist = false; + } + return !javafxExist || (OperatingSystem.isLinux() && Arch.getArch() == Arch.ARM) || MACOS_12_VERSION_ADAPTER.support(); + } + }, + + MACOS_12_VERSION_ADAPTER { + @Override + public boolean support() { + return (OperatingSystem.isMacos() && getMacOsVersionNumber() >= macosMontereyVersionNum); + } + + private final int macosMontereyVersionNum = 12; + + /** + * System.getProperty("os.version") 在最新macos版本存在bug + * https://bugs.openjdk.java.net/browse/JDK-8253702 + * + * @return + */ + private int getMacOsVersionNumber() { + String result; + List command = new ArrayList<>(); + command.add("/usr/bin/sw_vers"); + command.add("-productVersion"); + try (InputStream inputStream = new ProcessBuilder(command).start().getInputStream(); + Scanner s = new Scanner(inputStream).useDelimiter("\\A")) { + result = s.hasNext() ? s.next() : StringUtils.EMPTY; + String[] versionSlice = result.split("\\."); + return Integer.parseInt(versionSlice[0]); + } catch (Exception e) { + FineLoggerFactory.getLogger().warn(e.getMessage(), e); + return 0; + } + } + }, + DESIGNER_LOGIN { @Override public boolean support() { diff --git a/designer-base/src/main/java/com/fr/design/parameter/ParameterArrayPane.java b/designer-base/src/main/java/com/fr/design/parameter/ParameterArrayPane.java index 2703a2a2b8..22211acff1 100644 --- a/designer-base/src/main/java/com/fr/design/parameter/ParameterArrayPane.java +++ b/designer-base/src/main/java/com/fr/design/parameter/ParameterArrayPane.java @@ -2,20 +2,16 @@ package com.fr.design.parameter; import com.fr.base.Parameter; import com.fr.base.ParameterConfig; -import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.controlpane.JListControlPane; import com.fr.design.gui.controlpane.NameableCreator; import com.fr.design.gui.controlpane.NameableSelfCreator; import com.fr.design.gui.controlpane.UnrepeatedNameHelper; import com.fr.design.i18n.Toolkit; -import com.fr.general.ComparatorUtils; import com.fr.stable.Nameable; -import com.fr.stable.StringUtils; import com.fr.stable.core.PropertyChangeAdapter; -import javax.swing.*; import java.util.Arrays; -import java.util.List; +import java.util.Collection; public class ParameterArrayPane extends JListControlPane { @@ -29,27 +25,25 @@ public class ParameterArrayPane extends JListControlPane { this.addModNameActionListener((index, oldName, newName) -> populateSelectedValue()); this.addEditingListener(new PropertyChangeAdapter() { public void propertyChange() { - Parameter[] parameters = ParameterConfig.getInstance().getGlobalParameters(); - String[] allListNames = nameableList.getAllNames(); - allListNames[editingIndex] = StringUtils.EMPTY; - String tempName = getEditingName(); - if (StringUtils.isEmpty(tempName)) { - nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(ParameterArrayPane.this), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Empty_Parameter_Name")); - setIllegalIndex(editingIndex); - return; - } - if (!ComparatorUtils.equals(tempName, selectedName) - && isNameRepeated(new List[]{Arrays.asList(parameters), Arrays.asList(allListNames)}, tempName)) { - nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(ParameterArrayPane.this), - Toolkit.i18nText("Fine-Design_Basic_Duplicate_Parameter_Name")); - setIllegalIndex(editingIndex); - } + checkName(); } }); } + @Override + public String getEmptyNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Empty_Parameter_Name"); + } + + @Override + public String getDuplicatedNameTip() { + return Toolkit.i18nText("Fine-Design_Basic_Duplicate_Parameter_Name"); + } + + @Override + public Collection getExtraItemsToCheckNameRepeat() { + return Arrays.asList(ParameterConfig.getInstance().getGlobalParameters()); + } @Override protected String title4PopupWindow() { diff --git a/designer-base/src/main/java/com/fr/design/parameter/ParameterInputNoneListenerPane.java b/designer-base/src/main/java/com/fr/design/parameter/ParameterInputNoneListenerPane.java new file mode 100644 index 0000000000..2484a4b206 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/parameter/ParameterInputNoneListenerPane.java @@ -0,0 +1,30 @@ +package com.fr.design.parameter; + +import com.fr.design.editor.ValueEditorPane; +import com.fr.stable.ParameterProvider; + +/** + * 与ParameterInputPane区别在于 输入参数不会触发模板修改事件 + * + * 适用于参数不需要存储在模板中的场景 + * + * @author hades + * @version 11.0 + * Created by hades on 2022/5/13 + */ +public class ParameterInputNoneListenerPane extends ParameterInputPane { + + public ParameterInputNoneListenerPane(ParameterProvider[] parameters) { + super(parameters); + } + + public ParameterInputNoneListenerPane(ParameterProvider[] parameters, boolean allowBlank) { + super(parameters, allowBlank); + } + + @Override + protected void initTextListener(ValueEditorPane textF) { + // 这边输入参数 不用联动模板变化激活保存按钮 相关参数并不存储在模板 + // do nothing + } +} diff --git a/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java new file mode 100644 index 0000000000..6ba1c115ba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginErrorDesignReminder.java @@ -0,0 +1,143 @@ +package com.fr.design.plugin.remind; + +import com.fr.design.dialog.NotificationDialogAction; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.notification.Notification; +import com.fr.design.notification.NotificationCenter; +import com.fr.plugin.error.PluginErrorRemindHandler; +import com.fr.plugin.error.PluginErrorReminder; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; +import com.fr.workspace.WorkContext; + +import javax.swing.SwingUtilities; +import java.util.List; + +/** + * 插件错误信息提醒-设计器模块 + * + * @author Yvan + */ +public class PluginErrorDesignReminder implements PluginErrorReminder { + + private static final String MESSAGE_ID = "plugin-invalidate-remind"; + public static final String COMMA = "、"; + public static final String COLON = ":"; + public static final String NEW_LINE_TAG = "
"; + private static final int MAX_PLUGIN_NAME_PER_LINE = 3; + + private static class Holder { + private static final PluginErrorDesignReminder INSTANCE = new PluginErrorDesignReminder(); + } + + private PluginErrorDesignReminder() {} + + public static PluginErrorDesignReminder getInstance() { + return Holder.INSTANCE; + } + + @Override + public void remindStartFailedPlugins() { + + if (!WorkContext.getCurrent().isLocal()) { + return; + } + String content = PluginErrorRemindHandler.pluginErrorContent(); + if (StringUtils.isNotEmpty(content)) { + // 该操作需要在当前awt操作之后执行,使用SwingUtilities.invokeLater将其置于awt操作对列末尾 + // 若使用UIUtil.invokeLaterIfNeeded,会立即执行,影响其他UI操作 + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + PluginStartFailedRemindDialog dialog = new PluginStartFailedRemindDialog(DesignerContext.getDesignerFrame(), content); + dialog.setVisible(true); + } + }); + } + } + + @Override + public void remindInvalidatePlugins() { + + if (!WorkContext.getCurrent().isLocal()) { + return; + } + // 获取失效插件名称列表 + List embedPluginNames = PluginErrorRemindHandler.getInvalidateEmbedPluginNames(); + if (!CollectionUtils.isEmpty(embedPluginNames)) { + // 构建消息 + String message = generateMessageContent(embedPluginNames); + Notification notification = generateNotification(message, embedPluginNames); + // 添加消息 + NotificationCenter.getInstance().addNotification(notification); + } + } + + /** + * 构建消息内容 + * @param invalidatePluginNames + * @return + */ + private String generateMessageContent(List invalidatePluginNames) { + return new StringBuilder() + .append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")) + .append(COLON) + .append(NEW_LINE_TAG) + .append(NEW_LINE_TAG) + .append(dealWithPluginNames(invalidatePluginNames)) + .append(NEW_LINE_TAG) + .append(NEW_LINE_TAG) + .append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")) + .append(NEW_LINE_TAG) + .toString(); + } + + /** + * 处理消息中的插件名称展示 + * 由于Notification那边展示的弹窗是随消息宽度变化的,所以插件名称很多时会变得很长。这里做个分行 + * @return + * @param invalidatePluginNames + */ + public String dealWithPluginNames(List invalidatePluginNames) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < invalidatePluginNames.size(); i++) { + String pluginName = invalidatePluginNames.get(i); + builder.append(pluginName); + if (i != invalidatePluginNames.size() - 1) { + builder.append(i % MAX_PLUGIN_NAME_PER_LINE == (MAX_PLUGIN_NAME_PER_LINE - 1) ? NEW_LINE_TAG : COMMA); + } + } + return builder.toString(); + } + + /** + * 构建通知对象 + * @param message + * @param invalidatePluginNames + * @return + */ + private Notification generateNotification(String message, List invalidatePluginNames) { + return new Notification( + MESSAGE_ID, + Notification.WARNING_MESSAGE, + message, + new NotificationDialogAction() { + @Override + public String name() { + return "plugin-invalidate-remind-show"; + } + + @Override + public void doClick() { + PluginInvalidateRemindDialog remindDialog = new PluginInvalidateRemindDialog( + DesignerContext.getDesignerFrame(), + invalidatePluginNames, + PluginErrorRemindHandler.getInvalidateEmbedPluginMarkers(), + MESSAGE_ID); + remindDialog.setVisible(true); + } + } + ); + } +} diff --git a/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java new file mode 100644 index 0000000000..0c9986951f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginInvalidateRemindDialog.java @@ -0,0 +1,211 @@ +package com.fr.design.plugin.remind; + +import com.fr.common.util.Collections; +import com.fr.design.actions.UpdateAction; +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.notification.NotificationCenter; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.FRFont; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginMarker; +import com.fr.plugin.manage.PluginManager; +import com.fr.plugin.manage.control.PluginTaskCallback; +import com.fr.plugin.manage.control.PluginTaskResult; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * @author Yvan + */ +public class PluginInvalidateRemindDialog extends JDialog implements ActionListener{ + + /** + * 因内置而失效的插件Marker列表 + */ + private List pluginMarkers; + + /** + * 因内置而失效的插件名称列表 + */ + private List pluginNames; + + /** + * 本弹窗对应的消息的id + * 方便弹窗逻辑执行完之后,删除通知中心的消息 + */ + private String messageID; + + + public PluginInvalidateRemindDialog(Frame parent, List pluginNames, List pluginMarkers, String messageId) { + super(parent, true); + this.pluginMarkers = pluginMarkers; + this.pluginNames = pluginNames; + this.messageID = messageId; + // 标题 + this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Tool_Tips")); + this.setResizable(false); + + this.add(initTopPane(), BorderLayout.NORTH); + this.add(initCenterPanel(), BorderLayout.CENTER); + this.add(initBottomPanel(), BorderLayout.SOUTH); + this.setSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog")); + + GUICoreUtils.centerWindow(this); + + } + + /** + * 上层的面板,用于解释插件内置 + * @return + */ + private JPanel initTopPane() { + JPanel topPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + // 图标面板 + JPanel imagePanel = new JPanel(); + Icon icon = IOUtils.readIcon("com/fr/design/images/warnings/icon_WarningIcon_normal.png"); + UILabel imageLabel = new UILabel(); + imageLabel.setIcon(icon); + imagePanel.add(imageLabel); + imagePanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); + + JPanel verticalPanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + UILabel noticeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")); + noticeLabel.setFont(FRFont.getInstance().applySize(16)); + UILabel adviceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Advice")); + UILabel descriptionLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")); + verticalPanel.add(noticeLabel); + verticalPanel.add(adviceLabel); + verticalPanel.add(descriptionLabel); + + topPane.add(imagePanel, BorderLayout.WEST); + topPane.add(verticalPanel, BorderLayout.CENTER); + topPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 20)); + return topPane; + } + + /** + * 中层面板,用于展示内置插件列表 + * @return + */ + private JPanel initCenterPanel() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + // "插件列表"标签面板 + UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_List")); + textLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); + + JTextPane textPane = new JTextPane(); + textPane.setEditable(false); + textPane.setBackground(Color.WHITE); + SimpleAttributeSet attributeSet = new SimpleAttributeSet(); + StyleConstants.setLineSpacing(attributeSet, 0.5f); + textPane.setParagraphAttributes(attributeSet, true); + textPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + textPane.setText(generatePluginListText(pluginNames)); + JScrollPane scrollPane = new JScrollPane(textPane); + + centerPane.add(textLabel, BorderLayout.NORTH); + centerPane.add(scrollPane, BorderLayout.CENTER); + centerPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); + centerPane.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane")); + return centerPane; + } + + /** + * 生成中间面板展示的插件列表 + * @param pluginNames + * @return + */ + private String generatePluginListText(List pluginNames) { + String space = " "; + StringBuilder sb = new StringBuilder(); + for (String pluginName : pluginNames) { + sb.append(space).append(pluginName).append("\n"); + } + return sb.toString(); + } + + /** + * 底层面板,用于处理用户操作 + * @return + */ + private JPanel initBottomPanel() { + JPanel bottomPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + + UIButton ignore = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Ignore")); + UIButton delete = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Delete_Plugins")); + UILabel emptyLabel = new UILabel(); + ignore.addActionListener(this); + delete.addActionListener(new DeleteEmbedPluginsAction(this)); + bottomPane.add(ignore, BorderLayout.WEST); + bottomPane.add(emptyLabel, BorderLayout.CENTER); + bottomPane.add(delete, BorderLayout.EAST); + return bottomPane; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.dispose(); + } + + private class DeleteEmbedPluginsAction extends UpdateAction { + + private JDialog dialog; + + + DeleteEmbedPluginsAction(JDialog dialog) { + this.dialog = dialog; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.dialog.dispose(); + // 删除插件 + deleteEmbedPlugins(pluginMarkers); + // 删除消息 + NotificationCenter.getInstance().removeNotificationByMessageID(messageID); + } + + /** + * 删除插件 + * @param toDelete + */ + private void deleteEmbedPlugins(List toDelete) { + if (Collections.isEmpty(toDelete)) { + return; + } + for (PluginMarker pluginMarker : toDelete) { + // 删除插件 + PluginManager.getController().uninstall(pluginMarker, false, new PluginTaskCallback() { + @Override + public void done(PluginTaskResult result) { + // 输出结果日志 + FineLoggerFactory.getLogger().info( + "Detele Embed Plugin(id = {}, version = {}) {}", + pluginMarker.getPluginID(), + pluginMarker.getVersion(), result.isSuccess() ? "Succeeded" : "Failed"); + } + }); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java similarity index 96% rename from designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java rename to designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java index 1558d72e95..639c7a2925 100644 --- a/designer-base/src/main/java/com/fr/env/PluginErrorRemindDialog.java +++ b/designer-base/src/main/java/com/fr/design/plugin/remind/PluginStartFailedRemindDialog.java @@ -1,4 +1,4 @@ -package com.fr.env; +package com.fr.design.plugin.remind; import com.fr.design.ExtraDesignClassManager; import com.fr.design.actions.UpdateAction; @@ -32,11 +32,11 @@ import java.util.Set; /** * 插件启动失败提示窗 */ -public class PluginErrorRemindDialog extends JDialog implements ActionListener { +public class PluginStartFailedRemindDialog extends JDialog implements ActionListener { private static final String SIM_HEI = "SimHei"; - public PluginErrorRemindDialog(Frame parent, String text) { + public PluginStartFailedRemindDialog(Frame parent, String text) { super(parent, true); //上面的标签面板 JPanel topPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); diff --git a/designer-base/src/main/java/com/fr/design/preview/FormPreview.java b/designer-base/src/main/java/com/fr/design/preview/FormPreview.java index 178779f518..83b8a353f2 100644 --- a/designer-base/src/main/java/com/fr/design/preview/FormPreview.java +++ b/designer-base/src/main/java/com/fr/design/preview/FormPreview.java @@ -18,12 +18,12 @@ public class FormPreview extends AbstractPreviewProvider { @Override public String iconPathForPopupItem() { - return "com/fr/design/images/buttonicon/runs.png"; + return "/com/fr/design/standard/preview/runs.svg"; } @Override public String iconPathForLarge() { - return "com/fr/design/images/buttonicon/run24.png"; + return "/com/fr/design/standard/preview/run24.svg"; } @Override diff --git a/designer-base/src/main/java/com/fr/design/preview/MobilePreview.java b/designer-base/src/main/java/com/fr/design/preview/MobilePreview.java index c0f9e973dc..a55eb25733 100644 --- a/designer-base/src/main/java/com/fr/design/preview/MobilePreview.java +++ b/designer-base/src/main/java/com/fr/design/preview/MobilePreview.java @@ -19,12 +19,12 @@ public class MobilePreview extends AbstractPreviewProvider { @Override public String iconPathForPopupItem() { - return "com/fr/design/images/buttonicon/mobile.png"; + return "/com/fr/design/standard/preview/mobile.svg"; } @Override public String iconPathForLarge() { - return "com/fr/design/images/buttonicon/mobileb24.png"; + return "/com/fr/design/standard/preview/mobileb24.svg"; } @Override diff --git a/designer-base/src/main/java/com/fr/design/preview/PagePreview.java b/designer-base/src/main/java/com/fr/design/preview/PagePreview.java index e46e1f06c9..c2f15c915a 100644 --- a/designer-base/src/main/java/com/fr/design/preview/PagePreview.java +++ b/designer-base/src/main/java/com/fr/design/preview/PagePreview.java @@ -17,12 +17,12 @@ public class PagePreview extends AbstractPreviewProvider { @Override public String iconPathForPopupItem() { - return "com/fr/design/images/buttonicon/pages.png"; + return "/com/fr/design/standard/preview/pages.svg"; } @Override public String iconPathForLarge() { - return "com/fr/design/images/buttonicon/pageb24.png"; + return "/com/fr/design/standard/preview/pageb24.svg"; } @Override diff --git a/designer-base/src/main/java/com/fr/design/preview/ViewPreview.java b/designer-base/src/main/java/com/fr/design/preview/ViewPreview.java index 02809ba38c..5df602649c 100644 --- a/designer-base/src/main/java/com/fr/design/preview/ViewPreview.java +++ b/designer-base/src/main/java/com/fr/design/preview/ViewPreview.java @@ -20,12 +20,12 @@ public class ViewPreview extends AbstractPreviewProvider { @Override public String iconPathForPopupItem() { - return "com/fr/design/images/buttonicon/anas.png"; + return "/com/fr/design/standard/preview/anas.svg"; } @Override public String iconPathForLarge() { - return "com/fr/design/images/buttonicon/anab24.png"; + return "/com/fr/design/standard/preview/anab24.svg"; } @Override diff --git a/designer-base/src/main/java/com/fr/design/preview/WritePreview.java b/designer-base/src/main/java/com/fr/design/preview/WritePreview.java index 3d027dca7d..8cac86f392 100644 --- a/designer-base/src/main/java/com/fr/design/preview/WritePreview.java +++ b/designer-base/src/main/java/com/fr/design/preview/WritePreview.java @@ -20,12 +20,12 @@ public class WritePreview extends AbstractPreviewProvider { @Override public String iconPathForPopupItem() { - return "com/fr/design/images/buttonicon/writes.png"; + return "/com/fr/design/standard/preview/writes.svg"; } @Override public String iconPathForLarge() { - return "com/fr/design/images/buttonicon/writeb24.png"; + return "/com/fr/design/standard/preview/writeb24.svg"; } @Override diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java new file mode 100644 index 0000000000..2397f05487 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java @@ -0,0 +1,45 @@ +package com.fr.design.record.analyzer; + +import com.fr.design.record.analyzer.advice.TimeAdvice; +import com.fr.design.record.analyzer.advice.TrackAdvice; +import com.fr.record.analyzer.AnalyzerConfiguration; +import com.fr.record.analyzer.AnalyzerUnit; +import com.fr.record.analyzer.Assistant; +import com.fr.record.analyzer.Metrics; +import com.fr.record.analyzer.Track; +import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; +import com.fr.stable.ArrayUtils; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.description.type.TypeDescription; +import com.fr.third.net.bytebuddy.dynamic.DynamicType; +import com.fr.third.net.bytebuddy.matcher.ElementMatchers; +import com.fr.third.net.bytebuddy.utility.JavaModule; + +/** + * created by Harrison on 2022/03/08 + **/ +public class DesignerAnalyzer { + + private static final AnalyzerUnit ANALYZER = new AnalyzerUnit(); + + public static synchronized void init(AnalyzerAssemblyFactory factory, AnalyzerConfiguration... configurations) { + + AnalyzerAssemblyFactory redefineFactory = factory.prepare(DesignerAssemblyFactory.getInstance()); + + AnalyzerConfiguration defaultConfiguration = AnalyzerConfiguration.create(new Assistant() { + @Override + public DynamicType.Builder supply(DynamicType.Builder builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { + return builder + .visit(Advice.to(TimeAdvice.class).on(ElementMatchers.isAnnotatedWith(Metrics.class))) + .visit(Advice.to(TrackAdvice.class).on(ElementMatchers.isAnnotatedWith(Track.class))); + } + }); + AnalyzerConfiguration[] allConfigurations = ArrayUtils.add(configurations, defaultConfiguration); + + // 准备监听 + ANALYZER.setAgentListener(new DesignerAnalyzerListener()); + + ANALYZER.init(redefineFactory, allConfigurations); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java new file mode 100644 index 0000000000..087a656ba6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java @@ -0,0 +1,158 @@ +package com.fr.design.record.analyzer; + +import com.fr.base.OptimizeUtil; +import com.fr.collect.Collect; +import com.fr.design.record.analyzer.Interceptor.CollectInterceptor; +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.constants.DesignerLaunchStatus; +import com.fr.design.record.analyzer.advice.CollectAdvice; +import com.fr.design.record.analyzer.advice.DBMonitorAdvice; +import com.fr.design.record.analyzer.advice.FaultToleranceAdvice; +import com.fr.design.record.analyzer.advice.FocusAdvice; +import com.fr.design.record.analyzer.advice.MonitorAdvice; +import com.fr.design.record.analyzer.advice.PerformancePointAdvice; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.event.Null; +import com.fr.intelli.metrics.Compute; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.PerformancePoint; +import com.fr.jvm.assist.FineAssist; +import com.fr.module.Activator; +import com.fr.module.extension.Prepare; +import com.fr.record.analyzer.AnalyzerConfiguration; +import com.fr.record.analyzer.AnalyzerKey; +import com.fr.record.analyzer.Assistant; +import com.fr.record.analyzer.DBMetrics; +import com.fr.record.analyzer.FineAnalyzer; +import com.fr.record.analyzer.advice.AnalyzerAdviceKey; +import com.fr.record.analyzer.advice.FineAdviceAssistant; +import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; +import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory; +import com.fr.stable.collections.CollectionUtils; +import com.fr.third.net.bytebuddy.description.type.TypeDescription; +import com.fr.third.net.bytebuddy.dynamic.DynamicType; +import com.fr.third.net.bytebuddy.implementation.MethodDelegation; +import com.fr.third.net.bytebuddy.matcher.ElementMatchers; +import com.fr.third.net.bytebuddy.utility.JavaModule; +import com.fr.tolerance.FaultTolerance; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * created by Harrison on 2022/03/04 + **/ +public class DesignerAnalyzerActivator extends Activator implements Prepare { + + @Override + public void start() { + + OptimizeUtil.open(OptimizeUtil.Module.ANALYZER,() -> { + + AnalyzerAssemblyFactory basicFactory = createBasicFactory(); + + // 兼容逻辑 + List backwardsConfigurations = findMutableBackwards(AnalyzerKey.KEY); + if (!CollectionUtils.isEmpty(backwardsConfigurations)) { + // 直接初始化,不添加默认值,防止和下面的冲突 + FineAnalyzer.initDirectly(FineAssist.findInstrumentation(), basicFactory, backwardsConfigurations.toArray(new AnalyzerConfiguration[0])); + } + + // 等页面完全打开后,再进行 retransform, 别影响了启动速度 + EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { + + @Override + public void on(Event event, Null param) { + + ExecutorService es = newSingleThreadExecutor(new NamedThreadFactory("designer-analyzer", true)); + try { + // 加入 retransform 部分的逻辑 + List adviceConfigurations = findMutable(AnalyzerAdviceKey.KEY); + + if (!CollectionUtils.isEmpty(adviceConfigurations)) { + AnalyzerConfiguration[] configurations = convertConfigurations(adviceConfigurations); + es.submit(() -> { + DesignerAnalyzer.init(basicFactory, configurations); + }); + } + } finally { + es.shutdown(); + } + } + }); + }); + } + + @NotNull + private AnalyzerConfiguration[] convertConfigurations(List list) { + + return list.stream() + .map(AnalyzerConfiguration::create) + .toArray(AnalyzerConfiguration[]::new); + } + + @Override + public void stop() { + + } + + @Override + public void prepare() { + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(Focus.class), + FocusAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(Compute.class), + MonitorAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(DBMetrics.class), + DBMonitorAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(PerformancePoint.class), + PerformancePointAdvice.class + )); + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(FaultTolerance.class), + FaultToleranceAdvice.class + )); + + // 保持M1 可用 + addMutable(AnalyzerKey.KEY, AnalyzerConfiguration.create(new Assistant() { + + @Override + public DynamicType.Builder supply(DynamicType.Builder builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { + + return builder + .method(ElementMatchers.isAnnotatedWith(Collect.class)) + .intercept(MethodDelegation.to(CollectInterceptor.class)); + } + })); + + addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( + ElementMatchers.isAnnotatedWith(Collect.class), + CollectAdvice.class + )); + + + } + + + private AnalyzerAssemblyFactory createBasicFactory() { + + AnalyzerAssemblyFactory factory = findSingleton(AnalyzerAssemblyFactory.class); + FineAnalyzerAssemblyFactory basicFactory = new FineAnalyzerAssemblyFactory(); + basicFactory.prepare(factory); + return basicFactory; + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java new file mode 100644 index 0000000000..301634aa6d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java @@ -0,0 +1,12 @@ +package com.fr.design.record.analyzer; + +import com.fr.record.analyzer.advice.AnalyzerAdvice; + +/** + * 仅作为标志 + * 没有方法 + * + * created by Harrison on 2022/03/04 + **/ +public interface DesignerAnalyzerAdvice extends AnalyzerAdvice { +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java new file mode 100644 index 0000000000..cd52cec38e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java @@ -0,0 +1,23 @@ +package com.fr.design.record.analyzer; + +import com.fr.log.FineLoggerFactory; +import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder; +import com.fr.third.net.bytebuddy.description.type.TypeDescription; +import com.fr.third.net.bytebuddy.dynamic.DynamicType; +import com.fr.third.net.bytebuddy.utility.JavaModule; + +/** + * created by Harrison on 2022/03/08 + **/ +public class DesignerAnalyzerListener extends AgentBuilder.Listener.Adapter { + + @Override + public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) { + FineLoggerFactory.getLogger().debug("Designer-Analyzer transform successfully:{}", typeDescription); + } + + @Override + public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) { + FineLoggerFactory.getLogger().warn("Designer-Analyzer transform error:" + typeName); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java new file mode 100644 index 0000000000..2e5fdc408e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java @@ -0,0 +1,91 @@ +package com.fr.design.record.analyzer; + +import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; +import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder; + +import java.util.List; +import java.util.Map; + +/** + * 装配 Agent 为后置启动 + *

必须在一个线程中处理 retransform 的事务,否则会阻塞整个的线程,导致效果不佳

+ * + * created by Harrison on 2022/03/07 + **/ +public class DesignerAssemblyFactory implements AnalyzerAssemblyFactory { + + /** + * 每次执行 1 个 class 的 retransform + */ + private static final int FIXED_SIZE = 1; + + /** + * 单位 ms + * 每次间隔 500 ms, 执行一次 + */ + private static final int DELAY_INTERVAL = 500; + + private final AgentBuilder.RedefinitionStrategy.BatchAllocator batchAllocator = AgentBuilder.RedefinitionStrategy.BatchAllocator.ForFixedSize.ofSize(FIXED_SIZE); + + private final AgentBuilder.RedefinitionStrategy.Listener redefinitionListener = new DelayListener(DELAY_INTERVAL); + + public static DesignerAssemblyFactory getInstance() { + return DesignerAssemblyFactoryHolder.INSTANCE; + } + + private static class DesignerAssemblyFactoryHolder { + private static final DesignerAssemblyFactory INSTANCE = new DesignerAssemblyFactory(); + } + + @Override + public AnalyzerAssemblyFactory prepare(Void material) { + + return this; + } + + @Override + public AgentBuilder assembly(AgentBuilder raw) { + + return raw.disableClassFormatChanges() + .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) + // 每次只 transform 一部分否则会导致 UI 变慢 + .with(batchAllocator) + .with(redefinitionListener) + .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE) + .with(AgentBuilder.TypeStrategy.Default.REDEFINE); + } + + private class DelayListener implements AgentBuilder.RedefinitionStrategy.Listener { + + /** + * 单位 ms + */ + private final int interval; + + public DelayListener(int interval) { + this.interval = interval; + } + + /** + * 执行完后,等待一段时间再执行。 + */ + @Override + public void onBatch(int index, List> batch, List> types) { + + try { + Thread.sleep(interval); + } catch (Exception ignore) { + } + } + + @Override + public Iterable>> onError(int index, List> batch, Throwable throwable, List> types) { + return null; + } + + @Override + public void onComplete(int amount, List> types, Map>, Throwable> failures) { + + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/Interceptor/CollectInterceptor.java b/designer-base/src/main/java/com/fr/design/record/analyzer/Interceptor/CollectInterceptor.java new file mode 100644 index 0000000000..e344ad467b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/Interceptor/CollectInterceptor.java @@ -0,0 +1,28 @@ +package com.fr.design.record.analyzer.Interceptor; + +import com.fr.design.mod.ContentObjectManager; +import com.fr.third.net.bytebuddy.implementation.bind.annotation.AllArguments; +import com.fr.third.net.bytebuddy.implementation.bind.annotation.Origin; +import com.fr.third.net.bytebuddy.implementation.bind.annotation.RuntimeType; +import com.fr.third.net.bytebuddy.implementation.bind.annotation.SuperCall; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * 收集 + * + * @author hades + * @version 11.0 + * Created by hades on 2022/6/17 + */ +public class CollectInterceptor { + + @RuntimeType + public static Object intercept(@Origin Method method, + @SuperCall Callable callable, + @AllArguments Object[] args) throws Exception { + Object result = callable.call(); + ContentObjectManager.getInstance().collect(result); + return result; + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/CollectAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/CollectAdvice.java new file mode 100644 index 0000000000..6e470b3fdb --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/CollectAdvice.java @@ -0,0 +1,26 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.mod.ContentObjectManager; +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import java.lang.reflect.Method; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2022/6/17 + */ +public class CollectAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception { + ContentObjectManager.getInstance().collect(result); + } + +} + + diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java new file mode 100644 index 0000000000..aba2c2bdf3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java @@ -0,0 +1,23 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.general.data.DataModel; +import com.fr.measure.DBMeterFactory; +import com.fr.measure.metric.DBMetric; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +/** + * created by Harrison on 2022/03/07 + **/ +public class DBMonitorAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args) { + + if (args.length > 1 && args[1] instanceof DataModel) { + DBMetric meter = ((DataModel) args[1]).getMetric(); + DBMeterFactory.getMeter().record(meter); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java new file mode 100644 index 0000000000..4f40ef9430 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java @@ -0,0 +1,46 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.record.analyzer.advice.AdviceContext; +import com.fr.record.analyzer.advice.DefaultAdviceCallable; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import com.fr.tolerance.FaultTolerance; +import com.fr.tolerance.FaultToleranceFactory; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * created by Harrison on 2022/03/07 + **/ +public class FaultToleranceAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) + public static boolean onMethodEnter(@Advice.Local("context") AdviceContext adviceContext) throws Exception { + + adviceContext = AdviceContext + .builder() + .onAdviceCall() + .build(); + // 如果是切面调用,则忽视当前方法 + return adviceContext.isOnAdviceCall(); + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Local("context")AdviceContext adviceContext) throws Exception { + + // 如果是切面调用,则忽视不继续 exit + if (adviceContext != null && adviceContext.isOnAdviceCall()) { + return; + } + + FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class); + Callable callable = new DefaultAdviceCallable<>(self, method, args); + result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java new file mode 100644 index 0000000000..7bc79cc6cf --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java @@ -0,0 +1,31 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.FocusPoint; +import com.fr.intelli.record.FocusPolicy; +import com.fr.log.counter.DefaultLimitedMetric; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class FocusAdvice implements DesignerAnalyzerAdvice { + + private static final String FOCUS_POINT_ID_PREFIX = "function_"; + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Origin Method method, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception { + + if (FocusPolicy.IGNORE == result) { + return; + } + Focus focus = method.getAnnotation(Focus.class); + String id = FOCUS_POINT_ID_PREFIX + focus.id(); + DefaultLimitedMetric.INSTANCE.submit(FocusPoint.create(id, focus.text(), focus.source()), id); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java new file mode 100644 index 0000000000..a4ddfcd4e8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java @@ -0,0 +1,132 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.general.GeneralUtils; +import com.fr.intelli.measure.Estimator; +import com.fr.intelli.metrics.Compute; +import com.fr.intelli.metrics.MessageRecorderFactory; +import com.fr.intelli.metrics.SessionBinder; +import com.fr.intelli.metrics.SupervisoryConfig; +import com.fr.intelli.record.Measurable; +import com.fr.intelli.record.MeasureObject; +import com.fr.intelli.record.MeasureUnit; +import com.fr.log.FineLoggerFactory; +import com.fr.log.message.AbstractMessage; +import com.fr.measure.DBMeterFactory; +import com.fr.stable.StringUtils; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import com.fr.web.session.SessionLocalManager; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * created by Harrison on 2022/03/07 + **/ +public class MonitorAdvice implements DesignerAnalyzerAdvice { + + private static final Pattern P = Pattern.compile("-?\\d+"); + private static final int MIN_ERROR_CODE = 10000000; + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Local("startTime") Long startTime, + @Advice.Local("sessionBinder") SessionBinder sessionBinder) { + + startTime = (System.currentTimeMillis()); + sessionBinder = new SessionBinder(); + sessionBinder.attachSession(method, args); + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e, + @Advice.Local("startTime") Long startTime, + @Advice.Local("sessionBinder") SessionBinder sessionBinder) throws Exception { + + String error = StringUtils.EMPTY; + try { + if (e != null) { + try { + error = getErrorContent(e); + } catch (Exception ignore) { + } + } + } finally { + try { + if (self instanceof Measurable) { + long consume = System.currentTimeMillis() - startTime; + Compute once = method.getAnnotation(Compute.class); + Measurable measurable = (Measurable) self; + MeasureObject measureObject = MeasureObject.create(); + recordMemory(once, measurable, measureObject); + recordSQL(once, measureObject); + measureObject.consume(consume); + measureObject.error(error); + String id = UUID.randomUUID().toString(); + List newArgs = new ArrayList<>(Arrays.asList(args)); + newArgs.add(id); + recordSQLDetail(id); + AbstractMessage message = null; + try { + message = measurable.durableEntity(measureObject, newArgs.toArray()); + } catch (Throwable throwable) { + FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable); + } + if (measurable instanceof Estimator) { + MessageRecorderFactory.getInstance().asyncSubmit(message); + } else { + MessageRecorderFactory.getInstance().syncSubmit(message); + } + } + } catch (Exception ignore) { + //埋点信息入库失败应该不能影响业务流程 + } finally { + sessionBinder.detachSession(); + } + } + } + + public static String getErrorContent(Exception e) { + int errorCode = GeneralUtils.objectToNumber( + extractCodeFromString(e.getMessage()) + ).intValue(); + // 提取字符串中的第一个数字,最小的错误码为10000000 + return e.getClass().getName() + ":" + (errorCode >= MIN_ERROR_CODE ? errorCode : StringUtils.EMPTY); + } + + public static String extractCodeFromString(String errorMsg) { + Matcher m = P.matcher(errorMsg); + if (m.find()) { + return m.group(); + } + return StringUtils.EMPTY; + } + + public static void recordSQLDetail(String uuid) { + DBMeterFactory.getMeter().submit(uuid); + } + + public static void recordSQL(Compute once, MeasureObject measureObject) { + if (SupervisoryConfig.getInstance().isEnableMeasureSql() && once.computeSql()) { + measureObject.sqlTime(SessionLocalManager.getSqlTime()); + measureObject.sql(SessionLocalManager.getSql()); + } + } + + public static void recordMemory(Compute once, Measurable measurable, MeasureObject measureObject) { + if (SupervisoryConfig.getInstance().isEnableMeasureMemory() && once.computeMemory()) { + MeasureUnit unit = measurable.measureUnit(); + measureObject.memory(unit.measureMemory()); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java new file mode 100644 index 0000000000..5b54f66538 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java @@ -0,0 +1,49 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.intelli.record.ConsumePoint; +import com.fr.intelli.record.MetricRegistry; +import com.fr.intelli.record.PerformancePoint; +import com.fr.intelli.record.PerformancePointRecord; +import com.fr.stable.StringUtils; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * created by Harrison on 2022/03/07 + **/ +public class PerformancePointAdvice implements DesignerAnalyzerAdvice { + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.Local("startTime") Long startTime) { + + startTime = (System.currentTimeMillis()); + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Local("startTime") Long startTime) { + + PerformancePoint point = method.getAnnotation(PerformancePoint.class); + String id = point.id(); + long endTime = System.currentTimeMillis(); + long consume = endTime - startTime; + if (self instanceof PerformancePointRecord) { + PerformancePointRecord measurable = (PerformancePointRecord) self; + List newArgs = new ArrayList(Arrays.asList(args)); + ConsumePoint consumePoint = ConsumePoint.create(id, startTime, endTime, consume, point.source()); + MetricRegistry.getMetric().submit(measurable.recordPoint(consumePoint, newArgs.toArray())); + } else { + if (StringUtils.isNotEmpty(id)) { + MetricRegistry.getMetric().submit(ConsumePoint.create(id, consume, point.source())); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java new file mode 100644 index 0000000000..b60b5c2d33 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java @@ -0,0 +1,36 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.design.record.analyzer.DesignerAnalyzerAdvice; +import com.fr.log.FineLoggerFactory; +import com.fr.record.analyzer.Metrics; +import com.fr.third.net.bytebuddy.asm.Advice; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/08 + **/ +public class TimeAdvice implements DesignerAnalyzerAdvice { + + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.Local("startTime") Long startTime) { + + startTime = (System.currentTimeMillis()); + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Origin Method method, + @Advice.Local("startTime") Long startTime) { + + Metrics metrics = method.getAnnotation(Metrics.class); + Object prefix; + String description = metrics.description(); + if ("".equals(description)) { + prefix = method.getDeclaringClass().getName() + "#" + method.getName(); + } else { + prefix = description; + } + FineLoggerFactory.getLogger().info("{} took {} ms.", prefix, System.currentTimeMillis() - startTime); + } +} diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java new file mode 100644 index 0000000000..bdebecc600 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java @@ -0,0 +1,25 @@ +package com.fr.design.record.analyzer.advice; + +import com.fr.intelli.record.MetricRegistry; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.util.List; + +/** + * created by Harrison on 2022/03/08 + **/ +public class TrackAdvice { + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) { + + if (result != null) { + Class clazz = result.getClass(); + if (clazz.getAnnotation(Entity.class) != null || result instanceof List) { + MetricRegistry.getMetric().submit(result); + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/remote/button/IconButton.java b/designer-base/src/main/java/com/fr/design/remote/button/IconButton.java index 598ec7f057..d2d04b8d4c 100644 --- a/designer-base/src/main/java/com/fr/design/remote/button/IconButton.java +++ b/designer-base/src/main/java/com/fr/design/remote/button/IconButton.java @@ -4,6 +4,7 @@ import com.fr.base.BaseUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.stable.StringUtils; +import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; @@ -15,14 +16,19 @@ import java.awt.Graphics2D; import java.awt.Point; public final class IconButton extends JButton { - public IconButton() { + + public IconButton(Icon icon) { super(StringUtils.EMPTY); setContentAreaFilled(false); setFocusPainted(false); - setIcon(BaseUtils.readIcon("com/fr/design/remote/images/icon_tab_close_normal.png")); + setIcon(icon); setBorder(null); } + public IconButton() { + this(BaseUtils.readIcon("com/fr/design/remote/images/icon_tab_close_normal.png")); + } + @Override protected void paintBorder(Graphics g) { } diff --git a/designer-realize/src/main/java/com/fr/design/report/SelectImagePane.java b/designer-base/src/main/java/com/fr/design/report/SelectImagePane.java similarity index 96% rename from designer-realize/src/main/java/com/fr/design/report/SelectImagePane.java rename to designer-base/src/main/java/com/fr/design/report/SelectImagePane.java index bcad15c76c..7781233aac 100644 --- a/designer-realize/src/main/java/com/fr/design/report/SelectImagePane.java +++ b/designer-base/src/main/java/com/fr/design/report/SelectImagePane.java @@ -13,22 +13,24 @@ import com.fr.report.cell.Elem; import com.fr.report.cell.cellattr.CellImage; import com.fr.report.cell.painter.CellImagePainter; import com.fr.stable.Constants; - -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JFileChooser; -import javax.swing.JPanel; -import javax.swing.JScrollPane; import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.JScrollPane; /** - * 这个类主要用于插入图片时的设置 - */ + *

这个类主要用于插入图片时的设置

+ *

这个类原本在designer-realize包下面,现在表单也可选择图片,所以应该抽为公用的base包。包名不变,应该不影响插件使用

+ * + * @author Jimmy.Zheng created on 2022/8/11 21:22 + **/ public class SelectImagePane extends BasicPane { private ImagePreviewPane previewPane = null; @@ -39,8 +41,31 @@ public class SelectImagePane extends BasicPane { private UIRadioButton adjustRadioButton = null; private Style imageStyle = null; + ActionListener layoutActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + setImageStyle(); + changeImageStyle(); + } + }; private File imageFile; + /** + * Select picture. + */ + ActionListener selectPictureActionListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent evt) { + int returnVal = imageFileChooser + .showOpenDialog(SelectImagePane.this); + if (returnVal != JFileChooser.CANCEL_OPTION) { + File selectedFile = imageFileChooser.getSelectedFile(); + imageFile = selectedFile; + ImgChooseWrapper.getInstance(previewPane, imageFileChooser, imageStyle, null).dealWithImageFile(returnVal); + } + } + }; public SelectImagePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); @@ -102,23 +127,6 @@ public class SelectImagePane extends BasicPane { imageFileChooser.setMultiSelectionEnabled(false); } - /** - * Select picture. - */ - ActionListener selectPictureActionListener = new ActionListener() { - - @Override - public void actionPerformed(ActionEvent evt) { - int returnVal = imageFileChooser - .showOpenDialog(SelectImagePane.this); - if (returnVal != JFileChooser.CANCEL_OPTION) { - File selectedFile = imageFileChooser.getSelectedFile(); - imageFile = selectedFile; - ImgChooseWrapper.getInstance(previewPane, imageFileChooser, imageStyle, null).dealWithImageFile(returnVal); - } - } - }; - // 调整图片样式,只有水平和垂直对齐以及拉伸。相对于背景,平铺不予考虑。 private void changeImageStyle() { previewPane.setImageStyle(this.imageStyle); @@ -137,15 +145,6 @@ public class SelectImagePane extends BasicPane { } } - ActionListener layoutActionListener = new ActionListener() { - - @Override - public void actionPerformed(ActionEvent evt) { - setImageStyle(); - changeImageStyle(); - } - }; - @Override protected String title4PopupWindow() { return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image"); diff --git a/designer-base/src/main/java/com/fr/design/report/WatermarkPane.java b/designer-base/src/main/java/com/fr/design/report/WatermarkPane.java index 48e988a826..e06046e079 100644 --- a/designer-base/src/main/java/com/fr/design/report/WatermarkPane.java +++ b/designer-base/src/main/java/com/fr/design/report/WatermarkPane.java @@ -47,7 +47,7 @@ import java.awt.FlowLayout; * Created by plough on 2018/5/15. */ public class WatermarkPane extends BasicPane { - private static final int MAX_WIDTH = 160; + private static final int MAX_WIDTH = 216; // 水印预览面板 private WatermarkPreviewPane watermarkPreviewPane; 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 0cc211c5f1..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 @@ -1,5 +1,6 @@ package com.fr.design.report; +import com.fr.base.iofile.attr.WaterMarkProvideConstant; import com.fr.base.iofile.attr.WatermarkAttr; import com.fr.design.dialog.AbstractTemplateServerSettingPane; import com.fr.report.core.ReportUtils; @@ -33,6 +34,7 @@ public class WatermarkSettingPane extends AbstractTemplateServerSettingPane { @Override protected void populateServerSettings() { WatermarkAttr watermarkAttr = ReportUtils.getWatermarkAttrFromServerConfig(); + watermarkAttr.setValid(true); watermarkPane.populate(watermarkAttr); } @@ -42,20 +44,21 @@ public class WatermarkSettingPane extends AbstractTemplateServerSettingPane { } public void populate(WatermarkAttr watermark) { - if (!watermark.isValid()) { + if (watermark.getWaterMarkProvider().equals(WaterMarkProvideConstant.TEMPLATE)) { + chooseComboBox.setSelectedIndex(SINGLE_SET); + watermarkPane.populate(watermark); + } else { chooseComboBox.setSelectedIndex(SERVER_SET); populateServerSettings(); - return; } - chooseComboBox.setSelectedIndex(SINGLE_SET); - watermarkPane.populate(watermark); } 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 2196b1d403..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() { @@ -26,7 +22,7 @@ public class AdaptiveFrmFitAttrModel extends AbstractFitAttrModelProvider { @Override public String getModelName() { - return Toolkit.i18nText("Fine-Design_New_Decision_Report"); + return Toolkit.i18nText("Fine-Design_Basic_Decision_Report"); } @Override 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 dbf078b68d..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,26 +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.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; @@ -34,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; @@ -63,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] = 80; - } else { - columnSize[i] = 100; - } - } - - 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..c43aa057d8 --- /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_Attr_Bidirectional_Adaptive"), WAbsoluteLayout.STATE_FIT), + new Item(com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Fit-No"), 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-Designer_Fit-No"), 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-Designer_Fit-No"), 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 258dfbf49c..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 @@ -12,12 +12,12 @@ public class FrmFitAttrModel implements FitAttrModel { @Override public String getModelName() { - return Toolkit.i18nText("Fine-Design_Basic_Decision_Report"); + return Toolkit.i18nText("Fine-Design_Old_Decision_Report"); } @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/report/fit/menupane/ReportFitAttrAction.java b/designer-base/src/main/java/com/fr/design/report/fit/menupane/ReportFitAttrAction.java index 36328d9bdd..ba37ea18b7 100644 --- a/designer-base/src/main/java/com/fr/design/report/fit/menupane/ReportFitAttrAction.java +++ b/designer-base/src/main/java/com/fr/design/report/fit/menupane/ReportFitAttrAction.java @@ -4,6 +4,7 @@ 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.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; @@ -66,14 +67,18 @@ public class ReportFitAttrAction extends JTemplateAction { private void showReportFitDialog(ReportFitAttr fitAttr, final JTemplate jwb, final FitProvider wbTpl, final BasicBeanPane attrPane) { attrPane.populateBean(fitAttr); - UIDialog dialog = attrPane.showMediumWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + UIDialog dialog = attrPane.showWindowWithCustomSize(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { @Override public void doOk() { - wbTpl.setReportFitAttr(attrPane.updateBean()); - jwb.fireTargetModified(); + fireEditingOk(jwb, wbTpl, attrPane.updateBean(), fitAttr); } - }); + }, DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.report.fit.templatePane.dialog")); 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-base/src/main/java/com/fr/design/search/TreeSearchStatus.java b/designer-base/src/main/java/com/fr/design/search/TreeSearchStatus.java new file mode 100644 index 0000000000..3b97a7d402 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/TreeSearchStatus.java @@ -0,0 +1,28 @@ +package com.fr.design.search; + +/** + * @author Yvan + */ +public enum TreeSearchStatus { + + /** + * 非搜索模式 + */ + NOT_IN_SEARCH_MODE, + /** + * 搜索未开始 + */ + SEARCH_NOT_BEGIN, + /** + * 搜索中 + */ + SEARCHING, + /** + * 搜索已停止 + */ + SEARCH_STOPPED, + /** + * 搜索已完成 + */ + SEARCH_COMPLETED; +} diff --git a/designer-base/src/main/java/com/fr/design/search/TreeSearcher.java b/designer-base/src/main/java/com/fr/design/search/TreeSearcher.java new file mode 100644 index 0000000000..bbc44e1adc --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/TreeSearcher.java @@ -0,0 +1,27 @@ +package com.fr.design.search; + + +/** + * 用于搜索RefreshableJTree数据的搜索器 + * + * @author Yvan + */ +public interface TreeSearcher { + + /** + * 开始搜索 + * + * @param text + */ + void startSearch(String text); + + /** + * 停止搜索 + */ + void stopSearch(); + + /** + * 搜索完成 + */ + void completeSearch(); +} diff --git a/designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java new file mode 100644 index 0000000000..3989902de7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java @@ -0,0 +1,12 @@ +package com.fr.design.search.control; + + +/** + * 搜索任务回调 + * + * @author Yvan + */ +public interface TreeSearchCallback { + + void done(TreeSearchResult treeSearchResult); +} diff --git a/designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java new file mode 100644 index 0000000000..69225de498 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java @@ -0,0 +1,38 @@ +package com.fr.design.search.control; + +import java.util.List; + +/** + * @author Yvan + */ +public interface TreeSearchResult { + + /** + * 任务结果是否成功 + * + * @return + */ + boolean isSuccess(); + + /** + * 数据匹配时,需要将名称添加到匹配结果集中 + * + * @return + */ + List getAddToMatch(); + + /** + * 数据匹配时,需要添加到展开结果集中 + * + * @return + */ + List getAddToExpand(); + + /** + * 数据完成计算后,需要添加到完成结果集中 + * + * @return + */ + List getAddToCalculated(); + +} diff --git a/designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java new file mode 100644 index 0000000000..e7e4407ae7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java @@ -0,0 +1,10 @@ +package com.fr.design.search.control; + +/** + * @author Yvan + */ +public interface TreeSearchTask extends Runnable { + + @Override + void run(); +} diff --git a/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java b/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java new file mode 100644 index 0000000000..34d21a018c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java @@ -0,0 +1,22 @@ +package com.fr.design.search.event; + +import com.fr.design.search.TreeSearchStatus; + +import java.util.EventObject; + +/** + * @author Yvan + */ +public class TreeSearchStatusChangeEvent extends EventObject { + + private TreeSearchStatus status; + + public TreeSearchStatusChangeEvent(Object source) { + super(source); + this.status = (TreeSearchStatus) source; + } + + public TreeSearchStatus getTreeSearchStatus() { + return status; + } +} diff --git a/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java b/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java new file mode 100644 index 0000000000..a5b1b88499 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java @@ -0,0 +1,11 @@ +package com.fr.design.search.event; + +import java.util.EventListener; + +/** + * @author Yvan + */ +public interface TreeSearchStatusChangeListener extends EventListener { + + void updateTreeSearchChange(TreeSearchStatusChangeEvent event); +} diff --git a/designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java b/designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java new file mode 100644 index 0000000000..0d2fd752c6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java @@ -0,0 +1,82 @@ +package com.fr.design.search.view; + +import com.fr.design.gui.itree.refreshabletree.RefreshableJTree; + +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; +import java.awt.Component; +import java.util.regex.Pattern; + +/** + * @author Yvan + */ +public class TreeSearchRendererHelper { + + /** + * 缓存下原来的渲染器 + */ + private TreeCellRenderer originTreeCellRenderer; + + public TreeSearchRendererHelper() { + } + + public TreeCellRenderer getOriginTreeCellRenderer() { + return originTreeCellRenderer; + } + + public void setOriginTreeCellRenderer(TreeCellRenderer originTreeCellRenderer) { + this.originTreeCellRenderer = originTreeCellRenderer; + } + + public void replaceTreeRenderer(RefreshableJTree tree, String searchText) { + tree.setCellRenderer(getNewTreeCellRenderer(searchText)); + } + + public void save(TreeCellRenderer originTreeCellRenderer) { + if (getOriginTreeCellRenderer() == null) { + setOriginTreeCellRenderer(originTreeCellRenderer); + } + } + + public void restore(RefreshableJTree tree) { + if (getOriginTreeCellRenderer() != null) { + tree.setCellRenderer(getOriginTreeCellRenderer()); + } + } + + /** + * 获取新树渲染器,也就是搜索结果树的TreeCellRenderer,主要是为了文本高亮 + * + * @param searchText + * @return + */ + private TreeCellRenderer getNewTreeCellRenderer(String searchText) { + return new DefaultTreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + Component treeCellRendererComponent = getOriginTreeCellRenderer().getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + if (treeCellRendererComponent instanceof DefaultTreeCellRenderer) { + DefaultTreeCellRenderer defaultTreeCellRenderer = (DefaultTreeCellRenderer) treeCellRendererComponent; + String text = defaultTreeCellRenderer.getText(); + defaultTreeCellRenderer.setText(getHighlightText(text, searchText)); + } + return treeCellRendererComponent; + } + }; + } + + private String getHighlightText(String text, String textToHighlight) { + String highLightTemplate = "$1"; + if (textToHighlight.length() == 0) { + return text; + } + try { + text = text.replaceAll("(?i)(" + Pattern.quote(textToHighlight) + ")", highLightTemplate); + } catch (Exception e) { + return text; + } + text = "" + text + ""; + return text; + } +} diff --git a/designer-base/src/main/java/com/fr/design/selection/Selectedable.java b/designer-base/src/main/java/com/fr/design/selection/Selectedable.java index 5e78482e82..8900054431 100644 --- a/designer-base/src/main/java/com/fr/design/selection/Selectedable.java +++ b/designer-base/src/main/java/com/fr/design/selection/Selectedable.java @@ -1,25 +1,29 @@ package com.fr.design.selection; +import com.fr.base.TRL; + /** - * * @author zhou * @since 2012-7-26上午10:20:32 */ public interface Selectedable { - public S getSelection(); + S getSelection(); + + void setSelection(S selectElement); - public void setSelection(S selectElement); + /** + * Adds a ChangeListener to the listener list. + */ + void addSelectionChangeListener(SelectionListener selectionListener); - /** - * Adds a ChangeListener to the listener list. - */ - public void addSelectionChangeListener(SelectionListener selectionListener); + /** + * removes a ChangeListener from the listener list. + */ + void removeSelectionChangeListener(SelectionListener selectionListener); - /** - * removes a ChangeListener from the listener list. - */ - public void removeSelectionChangeListener(SelectionListener selectionListener); + // august:这儿就不要加fireSelectionChangeListener方法了。因为这个方法一般要定义成私有的,不然外部随即的调用! + default void navigate(TRL trl) { - // august:这儿就不要加fireSelectionChangeListener方法了。因为这个方法一般要定义成私有的,不然外部随即的调用! + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java new file mode 100644 index 0000000000..b303d491ff --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java @@ -0,0 +1,33 @@ +package com.fr.design.startup; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public class FineStartupNotificationFactory { + private static final FineStartupNotificationProvider DEFAULT = Install4jStartupNotificationProvider.getInstance(); + private static FineStartupNotificationProvider provider; + + public FineStartupNotificationFactory() { + } + + public static FineStartupNotificationProvider getNotification() { + return provider; + } + + public static void setLogger(@NotNull FineStartupNotificationProvider provider) { + FineStartupNotificationFactory.provider = provider; + } + + public static void reset() { + provider = DEFAULT; + } + + + static { + provider = DEFAULT; + } +} diff --git a/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java new file mode 100644 index 0000000000..b90390a703 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java @@ -0,0 +1,14 @@ +package com.fr.design.startup; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public interface FineStartupNotificationProvider { + void registerStartupListener(Listener listener); + + interface Listener { + void startupPerformed(String parameters); + } +} diff --git a/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java b/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java new file mode 100644 index 0000000000..b239698897 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java @@ -0,0 +1,68 @@ +package com.fr.design.startup; + +import com.fr.invoke.Reflect; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public class Install4jStartupNotificationProvider implements FineStartupNotificationProvider { + + private Install4jStartupNotificationProvider() { + } + private static final Install4jStartupNotificationProvider INSTANCE = new Install4jStartupNotificationProvider(); + public static Install4jStartupNotificationProvider getInstance() { + return INSTANCE; + } + + @Override + public void registerStartupListener(Listener listener) { + Class StartupNotificationListenerClass = null; + try { + StartupNotificationListenerClass = Reflect.on("com.install4j.api.launcher.StartupNotification$Listener").type(); + } catch (Exception ignored) { + } + + if (StartupNotificationListenerClass == null) { + return; + } + + ListenerHandler mHandler = new ListenerHandler(listener); + Object listenerCallbackInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { StartupNotificationListenerClass }, mHandler); + try { + Reflect.on("com.install4j.api.launcher.StartupNotification").call("registerStartupListener", listenerCallbackInstance); + } catch (Exception ignored) { + } + } + + private static class ListenerHandler implements InvocationHandler { + private final Listener listener; + + public ListenerHandler(Listener listener) { + this.listener = listener; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (args[0] instanceof String) { + String parameters = (String) args[0]; + listener.startupPerformed(parameters); + } + return null; + } + } + + public static void main(String[] args) { + Install4jStartupNotificationProvider.getInstance().registerStartupListener(new Listener() { + @Override + public void startupPerformed(String parameters) { + + } + }); + } +} diff --git a/designer-base/src/main/java/com/fr/design/style/AbstractPopBox.java b/designer-base/src/main/java/com/fr/design/style/AbstractPopBox.java index 4df9b75144..9cff473c11 100644 --- a/designer-base/src/main/java/com/fr/design/style/AbstractPopBox.java +++ b/designer-base/src/main/java/com/fr/design/style/AbstractPopBox.java @@ -10,8 +10,6 @@ import javax.swing.JWindow; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.util.ArrayList; -import java.util.List; import java.awt.AWTEvent; import java.awt.Dimension; import java.awt.Point; @@ -21,6 +19,8 @@ import java.awt.Window; import java.awt.event.AWTEventListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; /** * @author kunsnat E-mail:kunsnat@gmail.com diff --git a/designer-base/src/main/java/com/fr/design/style/AbstractSelectBox.java b/designer-base/src/main/java/com/fr/design/style/AbstractSelectBox.java index cd2b8e47a8..e59ddfa579 100644 --- a/designer-base/src/main/java/com/fr/design/style/AbstractSelectBox.java +++ b/designer-base/src/main/java/com/fr/design/style/AbstractSelectBox.java @@ -1,30 +1,33 @@ package com.fr.design.style; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ibutton.UIButtonUI; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.style.background.BackgroundJComponent; +import com.fr.design.utils.gui.GUIPaintUtils; +import com.fr.stable.Constants; + +import javax.swing.AbstractButton; +import javax.swing.JPanel; +import javax.swing.JWindow; +import javax.swing.border.AbstractBorder; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import javax.swing.plaf.ButtonUI; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import javax.swing.AbstractButton; -import javax.swing.JPanel; -import javax.swing.border.AbstractBorder; -import javax.swing.event.AncestorEvent; -import javax.swing.event.AncestorListener; -import javax.swing.plaf.ButtonUI; - -import com.fr.design.constants.UIConstants; -import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.ibutton.UIButtonUI; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.utils.gui.GUIPaintUtils; -import com.fr.design.style.background.BackgroundJComponent; -import com.fr.stable.Constants; - /** * @author kunsnat E-mail:kunsnat@gmail.com * @version 创建时间:2011-10-31 下午03:28:31 类说明: 抽象出来的弹出box. 可以弹出颜色选择, 图案选择, 纹理选择. @@ -93,6 +96,34 @@ public abstract class AbstractSelectBox extends AbstractPopBox implements Mou hidePopupMenu(); } }); + + displayComponent.addMouseListener(new MouseAdapter() { + @Override + public void mouseExited(MouseEvent e) { + if (!isPopupVisible()) { + //如果弹出框==null 或者 弹出框不可见 直接return + return; + } + Point popMenuP = getControlWindow().getLocation(); + Point displayComponentP = displayComponent.getLocationOnScreen(); + if (popMenuP.getX() < displayComponentP.getX() - 1) { + //如果 弹出框横向超出屏幕 往左调整了 和displayComponent横向错开 就不处理了 + return; + } + + Rectangle rectangle = displayComponent.getBounds(); + boolean bottomPopAndExitTop = displayComponentP.getY() < popMenuP.getY() && e.getY() <= rectangle.y; + boolean topPopAndExitBottom = displayComponentP.getY() > popMenuP.getY() && e.getY() >= rectangle.y + rectangle.getHeight(); + boolean exitLeftOrRight = rectangle.x > e.getX() || rectangle.x + rectangle.getWidth() < e.getX(); + if (bottomPopAndExitTop || topPopAndExitBottom || exitLeftOrRight) { + //弹出框在displayComponent下面 且 鼠标是从displayComponent上面离开的,隐藏弹出界面。 + //弹出框在displayComponent上面 且 鼠标是从displayComponent下面离开的,隐藏弹出界面。 + //鼠标从displayComponent左边 或者 右边 离开,隐藏弹出界面。 + hidePopupMenu(); + } + + } + }); } public void setEnabled(boolean enabled) { diff --git a/designer-base/src/main/java/com/fr/design/style/FontFamilyPane.java b/designer-base/src/main/java/com/fr/design/style/FontFamilyPane.java index 37076c66fb..ba496ae138 100644 --- a/designer-base/src/main/java/com/fr/design/style/FontFamilyPane.java +++ b/designer-base/src/main/java/com/fr/design/style/FontFamilyPane.java @@ -3,6 +3,7 @@ package com.fr.design.style; import com.fr.base.Utils; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; @@ -26,7 +27,7 @@ public class FontFamilyPane extends JPanel { familyField = new UITextField(); familyField.setEditable(false); - familyList = new JList(Utils.getAvailableFontFamilyNames4Report()); + familyList = new JList(DesignUtils.getAvailableFontFamilyNames4Report()); familyList.setVisibleRowCount(4); familyList.addListSelectionListener(listener); diff --git a/designer-base/src/main/java/com/fr/design/style/FormatPane.java b/designer-base/src/main/java/com/fr/design/style/FormatPane.java index d1679561d7..f1d7a086bd 100644 --- a/designer-base/src/main/java/com/fr/design/style/FormatPane.java +++ b/designer-base/src/main/java/com/fr/design/style/FormatPane.java @@ -52,6 +52,7 @@ public class FormatPane extends BasicPane { private UIRadioButton numberRadioButton; private UIRadioButton currencyRadioButton; private UIRadioButton percentRadioButton; + private UIRadioButton thousandthsRadioButton; private UIRadioButton scientificRadioButton; private UIRadioButton dateRadioButton; private UIRadioButton timeRadioButton; @@ -99,6 +100,7 @@ public class FormatPane extends BasicPane { categoryButtonGroup.add(numberRadioButton); categoryButtonGroup.add(currencyRadioButton); categoryButtonGroup.add(percentRadioButton); + categoryButtonGroup.add(thousandthsRadioButton); categoryButtonGroup.add(scientificRadioButton); categoryButtonGroup.add(dateRadioButton); categoryButtonGroup.add(timeRadioButton); @@ -108,6 +110,7 @@ public class FormatPane extends BasicPane { leftControlPane.add(this.createRadioCenterPane(numberRadioButton)); leftControlPane.add(this.createRadioCenterPane(currencyRadioButton)); leftControlPane.add(this.createRadioCenterPane(percentRadioButton)); + leftControlPane.add(this.createRadioCenterPane(thousandthsRadioButton)); leftControlPane.add(this.createRadioCenterPane(scientificRadioButton)); leftControlPane.add(this.createRadioCenterPane(dateRadioButton)); leftControlPane.add(this.createRadioCenterPane(timeRadioButton)); @@ -136,6 +139,8 @@ public class FormatPane extends BasicPane { currencyRadioButton.setMnemonic('C'); percentRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.PERCENT)); percentRadioButton.setMnemonic('P'); + thousandthsRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.THOUSANDTHS)); + thousandthsRadioButton.setMnemonic('Q'); scientificRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.SCIENTIFIC)); scientificRadioButton.setMnemonic('S'); dateRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.DATE)); @@ -149,6 +154,7 @@ public class FormatPane extends BasicPane { numberRadioButton.addActionListener(radioActionListener); currencyRadioButton.addActionListener(radioActionListener); percentRadioButton.addActionListener(radioActionListener); + thousandthsRadioButton.addActionListener(radioActionListener); scientificRadioButton.addActionListener(radioActionListener); dateRadioButton.addActionListener(radioActionListener); timeRadioButton.addActionListener(radioActionListener); @@ -234,6 +240,9 @@ public class FormatPane extends BasicPane { } else if (pattern.endsWith("%")) { this.percentRadioButton.setSelected(true); this.applyRadioActionListener(this.percentRadioButton); + } else if (pattern.endsWith("‰")){ + this.thousandthsRadioButton.setSelected(true); + this.applyRadioActionListener(this.thousandthsRadioButton); } else if (pattern.indexOf("E") > 0) { this.scientificRadioButton.setSelected(true); this.applyRadioActionListener(this.scientificRadioButton); @@ -259,6 +268,7 @@ public class FormatPane extends BasicPane { scientificRadioButton.setEnabled(false); textRadioButton.setEnabled(false); percentRadioButton.setEnabled(false); + thousandthsRadioButton.setEnabled(false); nullRadioButton.setEnabled(false); dateRadioButton.setEnabled(false); timeRadioButton.setEnabled(false); @@ -285,6 +295,7 @@ public class FormatPane extends BasicPane { numberRadioButton.setEnabled(false); currencyRadioButton.setEnabled(false); percentRadioButton.addActionListener(radioActionListener); + thousandthsRadioButton.setEnabled(false); scientificRadioButton.setEnabled(false); dateRadioButton.setEnabled(false); timeRadioButton.setEnabled(false); @@ -333,6 +344,8 @@ public class FormatPane extends BasicPane { return FormatContents.CURRENCY; else if (percentRadioButton.isSelected()) return FormatContents.PERCENT; + else if (thousandthsRadioButton.isSelected()) + return FormatContents.THOUSANDTHS; else if (scientificRadioButton.isSelected()) return FormatContents.SCIENTIFIC; else if (dateRadioButton.isSelected()) @@ -453,6 +466,8 @@ public class FormatPane extends BasicPane { contents = FormatContents.CURRENCY; } else if (ComparatorUtils.equals(source,percentRadioButton)) { contents = FormatContents.PERCENT; + }else if (ComparatorUtils.equals(source,thousandthsRadioButton)){ + contents = FormatContents.THOUSANDTHS; } else if (ComparatorUtils.equals(source,scientificRadioButton)) { contents = FormatContents.SCIENTIFIC; } else if (ComparatorUtils.equals(source,dateRadioButton)) { diff --git a/designer-base/src/main/java/com/fr/design/style/background/gradient/FixedGradientBar.java b/designer-base/src/main/java/com/fr/design/style/background/gradient/FixedGradientBar.java index 8c502114bf..06a217f230 100644 --- a/designer-base/src/main/java/com/fr/design/style/background/gradient/FixedGradientBar.java +++ b/designer-base/src/main/java/com/fr/design/style/background/gradient/FixedGradientBar.java @@ -14,6 +14,12 @@ public class FixedGradientBar extends GradientBar { super(minvalue, maxvalue); } + @Override + protected void clickButton(int select) { + setColor(getList().get(select).getColorInner()); + super.clickButton(select); + } + @Override protected void addMouseDragListener() { //不添加拖拽事件 diff --git a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java index 9c5b1af4d1..739dc81d55 100644 --- a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java +++ b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java @@ -4,62 +4,47 @@ package com.fr.design.style.background.image; import com.fr.design.DesignerEnvManager; -import com.fr.design.gui.ifilechooser.FileSelectionMode; -import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser; -import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ifilechooser.FileChooserFactory; +import com.fr.design.gui.ifilechooser.FileChooserProvider; import com.fr.design.i18n.Toolkit; -import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.design.mainframe.share.collect.ComponentCollector; import com.fr.design.mainframe.toast.DesignerToastMsgUtil; -import javafx.stage.FileChooser; -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; + +import java.awt.Component; import java.io.File; +import javax.swing.SwingUtilities; /** * This class used to choose image files. */ public class ImageFileChooser { - - JavaFxNativeFileChooser javaFxNativeFileChooser; + private final FileChooserProvider fileChooserProvider; public ImageFileChooser() { - javaFxNativeFileChooser = - new JavaFxNativeFileChooser.Builder(). - fileSelectionMode(FileSelectionMode.FILE). - title(Toolkit.i18nText("Fine-Design_Basic_Open")). - filter(Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files"), "*.jpg", "*.gif", "*.png", "*.bmp"). - build(); + fileChooserProvider = FileChooserFactory.createImageFileChooser(); } public int showOpenDialog(Component parent, String approveButtonText) { - return showOpenDialog(parent); + return fileChooserProvider.showOpenDialog(parent, approveButtonText); } public int showOpenDialog(Component parent) { showImageCompressMoveTip(); - return javaFxNativeFileChooser.showDialog(parent); + return fileChooserProvider.showDialog(parent); } public void setCurrentDirectory(File file) { - javaFxNativeFileChooser.setCurrentDirectory(file); + fileChooserProvider.setCurrentDirectory(file); } public void setMultiSelectionEnabled(boolean multiple) { - if (multiple) { - javaFxNativeFileChooser.setSelectionMode(FileSelectionMode.MULTIPLE_FILE); - } else { - javaFxNativeFileChooser.setSelectionMode(FileSelectionMode.FILE); - } + fileChooserProvider.setMultiSelectionEnabled(multiple); } public File getSelectedFile() { - return javaFxNativeFileChooser.getSelectedFile(); + return fileChooserProvider.getSelectedFile(); } public boolean isCheckSelected() { diff --git a/designer-base/src/main/java/com/fr/design/style/color/ColorAdjustPane.java b/designer-base/src/main/java/com/fr/design/style/color/ColorAdjustPane.java index ad99b90835..f5ff739fa6 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/ColorAdjustPane.java +++ b/designer-base/src/main/java/com/fr/design/style/color/ColorAdjustPane.java @@ -1,6 +1,7 @@ package com.fr.design.style.color; import com.fr.base.BaseUtils; +import com.fr.chart.base.ChartConstants; import com.fr.design.DesignerEnvManager; import com.fr.design.event.UIObserver; import com.fr.design.event.UIObserverListener; @@ -12,8 +13,6 @@ import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.util.ArrayList; -import java.util.List; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; @@ -23,6 +22,8 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; /** * 配色方案选择组合色之后,可以调整颜色的组件 @@ -33,18 +34,7 @@ import java.awt.image.BufferedImage; */ public class ColorAdjustPane extends JPanel implements UIObserver { - public static final Color[] DEFAULT_COLORS = { - new Color(99, 178, 238), - new Color(118, 218, 145), - new Color(248, 203, 127), - new Color(248, 149, 136), - new Color(124, 214, 207), - new Color(145, 146, 171), - new Color(120, 152, 225), - new Color(239, 166, 102), - new Color(237, 221, 134), - new Color(153, 135, 206), - }; + public static final Color[] DEFAULT_COLORS = ChartConstants.NEW_FEATURES; private static final int COUNT_OF_ROW = 8; diff --git a/designer-base/src/main/java/com/fr/design/style/color/ColorCell.java b/designer-base/src/main/java/com/fr/design/style/color/ColorCell.java index 4cc3e41cea..acc26ca5aa 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/ColorCell.java +++ b/designer-base/src/main/java/com/fr/design/style/color/ColorCell.java @@ -100,11 +100,13 @@ public class ColorCell extends JComponent implements ColorSelectable { if (e == null || e.getID() == MouseEvent.MOUSE_RELEASED) { colorSelectable.setColor(this.getColor()); - colorSelectable.colorSetted(this); + // 先添加最近使用 if (this.getColor() != null) { int rgb = this.getColor().getRGB(); DesignerEnvManager.getEnvManager().getColorConfigManager().addToColorQueue(new Color(rgb)); } + // 这边会获取到最近使用颜色并更新 添加逻辑需要放到前面 否则不会及时更新 + colorSelectable.colorSetted(this); } if (e != null) { diff --git a/designer-base/src/main/java/com/fr/design/style/color/ColorFactory.java b/designer-base/src/main/java/com/fr/design/style/color/ColorFactory.java index b643752b39..0ab0d8f381 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/ColorFactory.java +++ b/designer-base/src/main/java/com/fr/design/style/color/ColorFactory.java @@ -3,7 +3,7 @@ package com.fr.design.style.color; import java.awt.Color; public interface ColorFactory { - + public static final Color MenuColors[] = { Color.black, new Color(153, 51, 0), @@ -72,17 +72,17 @@ public interface ColorFactory { }; public static final Color STANDARD_COLORS[] = { - new Color(166, 89, 66), - new Color(166, 123, 66), - new Color(166, 66, 66), - new Color(103, 166, 66), - new Color(66, 121, 166), - new Color(68, 66, 166), - new Color(98, 66, 166), - new Color(146, 66, 166), - new Color(75, 18, 89), - new Color(89, 18, 51) + new Color(234, 68, 49), + new Color(179, 96, 36), + new Color(232, 147, 37), + new Color(109, 214, 50), + new Color(51, 147, 219), + new Color(56, 54, 179), + new Color(93, 54, 179), + new Color(154, 54, 179), + new Color(127, 76, 217), + new Color(179, 36, 102) }; - -} \ No newline at end of file + +} diff --git a/designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java b/designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java index 93b9ba3fd0..067d82f9ce 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java +++ b/designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java @@ -4,6 +4,7 @@ package com.fr.design.style.color; * Created by plough on 2016/12/22. */ +import com.fr.design.DesignerEnvManager; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; @@ -66,16 +67,10 @@ public class ColorPicker extends JDialog implements ActionListener { hideCursor(); // 如果要求实时变化,确保先关闭弹窗,再截屏 - // 主要针对"图案"选项卡中的"前景"、"背景" if (this.setColorRealTime) { colorSelectable.setColor(Color.WHITE); // setColor 可以关闭弹窗 - try { - Thread.sleep(100); // 等待弹窗关闭 - } catch (InterruptedException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - Thread.currentThread().interrupt(); - } - colorPickerPanel.captureScreen(); + // REPORT-82110 确保关闭所有弹窗后截屏 + SwingUtilities.invokeLater(colorPickerPanel :: captureScreen); } } @@ -137,6 +132,7 @@ public class ColorPicker extends JDialog implements ActionListener { timer.stop(); if (setColor) { colorSelectable.setColor(colorToSet); + DesignerEnvManager.getEnvManager().getColorConfigManager().addToColorQueue(new Color(colorToSet.getRGB())); } this.dispose(); } diff --git a/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectBox.java b/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectBox.java index 04d368e6bc..59ef1e6e43 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectBox.java +++ b/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectBox.java @@ -20,13 +20,20 @@ public class NewColorSelectBox extends AbstractSelectBox implements UIObs private static final long serialVersionUID = 2782150678943960557L; private Color color; - private NewColorSelectPane colorPane = new NewColorSelectPane(false); + private NewColorSelectPane colorPane; private UIObserverListener uiObserverListener; private String newColorSelectBoxName = ""; private GlobalNameListener globalNameListener = null; + private boolean supportTransparent; public NewColorSelectBox(int preferredWidth) { - initBox(preferredWidth); + this(preferredWidth, false); + } + + public NewColorSelectBox(int preferredWidth, boolean supportTransparent) { + this.colorPane = new NewColorSelectPane(supportTransparent); + this.supportTransparent = supportTransparent; + initBox(preferredWidth); iniListener(); } @@ -58,7 +65,7 @@ public class NewColorSelectBox extends AbstractSelectBox implements UIObs */ public JPanel initWindowPane(double preferredWidth) { // 下拉的时候重新生成面板,以刷新最近使用颜色 - colorPane = new NewColorSelectPane(false); + colorPane = new NewColorSelectPane(this.supportTransparent); colorPane.setColor(this.getSelectObject()); colorPane.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { diff --git a/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectPane.java b/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectPane.java index 180055b3e0..e9c8b7a7d3 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectPane.java +++ b/designer-base/src/main/java/com/fr/design/style/color/NewColorSelectPane.java @@ -72,7 +72,7 @@ public class NewColorSelectPane extends BasicPane implements ColorSelectable { } public NewColorSelectPane(boolean isSupportTransparent) { - this(isSupportTransparent, true); + this(isSupportTransparent, !DesignerContext.getDesignerFrame().isServerConfig()); } /** @@ -169,7 +169,7 @@ public class NewColorSelectPane extends BasicPane implements ColorSelectable { Color.decode("#CCCCCC"), // 2列灰度色 - Color.decode("#333333"), + Color.decode("#000000"), Color.decode("#FFFFFF"), }; diff --git a/designer-base/src/main/java/com/fr/design/style/color/UIToolbarColorButton.java b/designer-base/src/main/java/com/fr/design/style/color/UIToolbarColorButton.java index 9a8640f627..c7c32f7956 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/UIToolbarColorButton.java +++ b/designer-base/src/main/java/com/fr/design/style/color/UIToolbarColorButton.java @@ -35,7 +35,7 @@ public class UIToolbarColorButton extends UICombinationButton implements PopupHi private UIObserverListener uiObserverListener; public UIToolbarColorButton(Icon icon) { - super(new UIColorButton(icon), new UIButton(IconUtils.readIcon("/com/fr/design/images/gui/popup"))); + super(new UIColorButton(icon), new UIButton(IconUtils.readIcon("/com/fr/design/standard/popup"))); getLeftButton().setEventBanned(true); getRightButton().addFocusListener(new FocusListener() { @@ -153,12 +153,23 @@ public class UIToolbarColorButton extends UICombinationButton implements PopupHi popupWin = null; } + /** + * 取色器取色时隐藏弹出框,与另一个hide的区别是无需经过macOS的判断,以规避REPORT-25645的mac适配bug + */ + public void hidePopupMenu4PickColor() { + if (popupWin != null) { + popupWin.setVisible(false); + } + popupWin = null; + } + private ColorControlWindow getColorControlWindow() { //find parant. if (this.popupWin == null) { this.popupWin = new ColorControlWindow(this.isCanBeNull(), UIToolbarColorButton.this) { @Override protected void colorChanged() { + hidePopupMenu4PickColor(); UIToolbarColorButton.this.setColor(this.getColor()); } diff --git a/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java b/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java index 09fa2bbc08..5a0ead41e7 100644 --- a/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java +++ b/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java @@ -203,6 +203,10 @@ public class ModernUIPane extends BasicPane { this.pane = new ModernUIPane<>(browserType); } + public Builder(ModernUIPane pane) { + this.pane = pane; + } + public Builder prepare(ScriptContextListener contextListener) { pane.browser.addScriptContextListener(contextListener); return this; diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java index d755d4e05f..59df782cde 100644 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java @@ -17,8 +17,11 @@ import com.teamdev.jxbrowser.engine.EngineOptions; import com.teamdev.jxbrowser.engine.RenderingMode; import com.teamdev.jxbrowser.event.Observer; import com.teamdev.jxbrowser.js.JsObject; +import com.teamdev.jxbrowser.net.Network; import com.teamdev.jxbrowser.net.Scheme; +import com.teamdev.jxbrowser.net.callback.VerifyCertificateCallback; import com.teamdev.jxbrowser.view.swing.BrowserView; +import org.jetbrains.annotations.Nullable; import java.awt.BorderLayout; @@ -108,6 +111,17 @@ public class NewModernUIPane extends ModernUIPane { } Engine engine = Engine.newInstance(builder.build()); + if (DesignerEnvManager.getEnvManager().isOpenDebug()) { + // 调试模式下,禁止HTTPS证书验证,使得可以正常访问商城测试服务器等 + Network network = engine.network(); + network.set(VerifyCertificateCallback.class, new VerifyCertificateCallback() { + @Nullable + @Override + public Response on(Params params) { + return VerifyCertificateCallback.Response.valid(); + } + }); + } browser = engine.newBrowser(); // 初始化的时候,就把命名空间对象初始化好,确保window.a.b.c("a.b.c"为命名空间)对象都是初始化过的 @@ -168,7 +182,7 @@ public class NewModernUIPane extends ModernUIPane { public void disposeBrowser() { if (browser != null) { - browser.close(); + browser.engine().close(); browser = null; } @@ -192,6 +206,10 @@ public class NewModernUIPane extends ModernUIPane { private NewModernUIPane pane = new NewModernUIPane<>(); + public Builder() { + super((ModernUIPane)null); + } + public NewModernUIPane.Builder prepare(InjectJsCallback callback) { pane.browser.set(InjectJsCallback.class, callback); return this; diff --git a/designer-base/src/main/java/com/fr/design/ui/util/GraphicsConfig.java b/designer-base/src/main/java/com/fr/design/ui/util/GraphicsConfig.java deleted file mode 100644 index 316b6ac242..0000000000 --- a/designer-base/src/main/java/com/fr/design/ui/util/GraphicsConfig.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.fr.design.ui.util; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.util.Map; - -/** - * 图形渲染配置 - * - * @author vito - * @version 10.0 - * Created by vito on 2019/9/18 - */ -public class GraphicsConfig { - private final Graphics2D myG; - private final Map myHints; - private final Composite myComposite; - private final Stroke myStroke; - - public GraphicsConfig(@NotNull Graphics g) { - myG = (Graphics2D) g; - myHints = (Map) myG.getRenderingHints().clone(); - myComposite = myG.getComposite(); - myStroke = myG.getStroke(); - } - - public GraphicsConfig setAntialiasing(boolean on) { - myG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, on ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); - return this; - } - - public GraphicsConfig setAlpha(float alpha) { - myG.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); - return this; - } - - public GraphicsConfig setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { - myG.setRenderingHint(hintKey, hintValue); - return this; - } - - public Graphics2D getG() { - return myG; - } - - public GraphicsConfig setComposite(Composite composite) { - myG.setComposite(composite); - return this; - } - - public GraphicsConfig setStroke(Stroke stroke) { - myG.setStroke(stroke); - return this; - } - - public GraphicsConfig setupAAPainting() { - return setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) - .setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); - } - - public GraphicsConfig disableAAPainting() { - return setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF) - .setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); - } - - public GraphicsConfig paintWithAlpha(float alpha) { - assert 0.0f <= alpha && alpha <= 1.0f : "alpha should be in range 0.0f .. 1.0f"; - return setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); - } - - public void restore() { - myG.setRenderingHints(myHints); - myG.setComposite(myComposite); - myG.setStroke(myStroke); - } -} diff --git a/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java b/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java index b7583d0dd9..86093a6d82 100644 --- a/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java +++ b/designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java @@ -1,9 +1,12 @@ package com.fr.design.ui.util; import com.fr.log.FineLoggerFactory; +import com.fr.third.guava.base.Stopwatch; +import com.fr.third.guava.base.Supplier; import org.jetbrains.annotations.NotNull; import javax.swing.SwingUtilities; +import java.util.concurrent.TimeUnit; /** * 一些常用的 GUI 工具。 @@ -52,4 +55,30 @@ public class UIUtil { } } } + + /** + * 有些时候,交互上需要有一些等待的效果, + * 如果没有等待到, 会让交互失去作用。 + * + * @param supplier 结果 + * @param timeout 超时 + * @param timeUnit 单位 + * @return 结果 + */ + public static T waitUntil(Supplier supplier, long timeout, TimeUnit timeUnit) { + + Stopwatch st = Stopwatch.createStarted(); + T result = supplier.get(); + long elapsed = st.elapsed(timeUnit); + long minus = timeout - elapsed; + if (minus > 0) { + long value = timeUnit.toMillis(minus); + try { + Thread.sleep(value); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + return result; + } } diff --git a/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java new file mode 100644 index 0000000000..56db4cee9e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java @@ -0,0 +1,34 @@ +package com.fr.design.update.actions; + + +import com.fr.common.util.Strings; +import com.fr.design.utils.BrowseUtils; +import com.fr.general.CloudCenter; +import com.fr.log.FineLoggerFactory; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +/** + * 帮助-更新升级 + * 点击查看新特性 + * */ +public class NewFeatureAction implements ActionListener { + + + public static String DEFAULT_UPDATE_DETAIL_URL = "https://help.fanruan.com/finereport/doc-view-4699.html"; + + @Override + public void actionPerformed(ActionEvent e) { + try { + String url = CloudCenter.getInstance().acquireConf("fr.latest.update.detil"); + if (Strings.isEmpty(url)) { + url = DEFAULT_UPDATE_DETAIL_URL; + } + BrowseUtils.browser(url); + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage()); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java index 9ea734e732..950d76d7b9 100644 --- a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java @@ -15,6 +15,7 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { private static DesignerPushUpdateConfigManager singleton; private boolean autoPushUpdateEnabled = true; // 是否开启自动推送更新 + private boolean cloudAnalyticsDelay = false; // 是否云端运维模块延迟启动 private String lastIgnoredVersion = StringUtils.EMPTY; // 最近一次跳过的更新版本 private DesignerPushUpdateConfigManager() { @@ -32,6 +33,7 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { if (reader.isAttr()) { this.setAutoPushUpdateEnabled(reader.getAttrAsBoolean("autoPushUpdateEnabled", true)); this.setLastIgnoredVersion(reader.getAttrAsString("lastIgnoredVersion", StringUtils.EMPTY)); + this.setCloudAnalyticsDelay(reader.getAttrAsBoolean("cloudAnalyticsDelay", false)); } } @@ -40,6 +42,7 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { writer.startTAG(XML_TAG); writer.attr("autoPushUpdateEnabled", autoPushUpdateEnabled); writer.attr("lastIgnoredVersion", lastIgnoredVersion); + writer.attr("cloudAnalyticsDelay", cloudAnalyticsDelay); writer.end(); } @@ -58,4 +61,12 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { public void setLastIgnoredVersion(String lastIgnoredVersion) { this.lastIgnoredVersion = lastIgnoredVersion; } + + public boolean isCloudAnalyticsDelay() { + return cloudAnalyticsDelay; + } + + public void setCloudAnalyticsDelay(boolean cloudAnalyticsDelay) { + this.cloudAnalyticsDelay = cloudAnalyticsDelay; + } } diff --git a/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java b/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java index 9a849ad4e9..033e2cb07f 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java @@ -9,6 +9,7 @@ import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.UIDialog; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.i18n.Toolkit; @@ -16,6 +17,7 @@ import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.DesignerContext; import com.fr.design.update.actions.FileProcess; +import com.fr.design.update.actions.NewFeatureAction; import com.fr.design.update.domain.UpdateInfoCachePropertyManager; import com.fr.design.update.utils.UpdateFileUtils; import com.fr.design.update.ui.widget.LoadingLabel; @@ -24,6 +26,7 @@ import com.fr.design.update.ui.widget.UpdateInfoTable; import com.fr.design.update.ui.widget.UpdateInfoTableCellRender; import com.fr.design.update.ui.widget.UpdateInfoTableModel; import com.fr.design.update.ui.widget.UpdateInfoTextAreaCellRender; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.*; import com.fr.general.http.HttpToolbox; @@ -83,7 +86,7 @@ public class UpdateMainDialog extends UIDialog { private static final String HYPHEN = "-"; - private final SimpleDateFormat CHANGELOG_FORMAT = new SimpleDateFormat("M/d/y, h:m:s a", Locale.ENGLISH); + private final SimpleDateFormat UPDATELOG_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); private final SimpleDateFormat UPDATE_INFO_TABLE_FORMAT = new SimpleDateFormat("yyyy.MM.dd"); private JSONObject downloadFileConfig; @@ -91,8 +94,6 @@ public class UpdateMainDialog extends UIDialog { private LoadingLabel loadingLabel; //更新按钮 private UIButton updateButton; - //有新版本提示标签 - private UILabel updateLabel; //jar包版本信息面板,包括当前版本和最新版本 private JPanel jarVersionInfoPane; @@ -117,6 +118,8 @@ public class UpdateMainDialog extends UIDialog { private ArrayList updateInfoList; + private Set titleSet; + private boolean getUpdateInfoSuccess; private UpdateInfoCachePropertyManager cacheProperty; @@ -155,13 +158,8 @@ public class UpdateMainDialog extends UIDialog { progressBar.setStringPainted(true); progressBar.setPreferredSize(PROGRESSBAR); - updateLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_New_Version_Available")); - updateLabel.setHorizontalAlignment(SwingConstants.RIGHT); - updateLabel.setVisible(false); - progressBarPane.add(GUICoreUtils.createBorderLayoutPane( - progressBar, BorderLayout.CENTER, - updateLabel, BorderLayout.EAST + progressBar, BorderLayout.CENTER ), BorderLayout.CENTER); updateActionPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ @@ -181,9 +179,9 @@ public class UpdateMainDialog extends UIDialog { double[] rowUpdatePaneSize = {UPDATE_PANE_ROW_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED}; double[] columnUpdatePaneSize = {TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED}; double[] rowUpdateContentPaneSize = {TableLayout.PREFERRED}; - double[] columnUpdateContentPaneSize = {TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED}; + double[] columnUpdateContentPaneSize = {TableLayout.PREFERRED, TableLayout.FILL}; double[] rowUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_ROW_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, UPDATE_CONTENT_PANE_ROW_SIZE}; - double[] columnUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_COLUMN_SIZE, TableLayout.FILL, TableLayout.PREFERRED}; + double[] columnUpdateSubContentPaneSize = {UPDATE_CONTENT_PANE_COLUMN_SIZE, TableLayout.PREFERRED, TableLayout.PREFERRED}; double[] columnUpdateSubContentPaneLabelSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; JPanel jarUpdateContentPane = new JPanel(); @@ -193,15 +191,15 @@ public class UpdateMainDialog extends UIDialog { JPanel jarUpdateContentPane2 = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ new Component[]{new UILabel(), new UILabel(), new UILabel()}, new Component[]{new UILabel(), updateVersionReminderPane, new UILabel()}, - new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_JAR_Version")), jarCurrentLabel), new UILabel()}, - new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Latest_JAR")), loadingLabel), new UILabel()}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_JAR_Version")), jarCurrentLabel), jarRestoreLabel}, + new Component[]{new UILabel(), initPaneContent(Color.WHITE, rowUpdateContentPaneSize, columnUpdateSubContentPaneLabelSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Latest_JAR")), loadingLabel), + getNewFeatureActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Latest_Feature_Detail"))}, new Component[]{new UILabel(), new UILabel(), new UILabel()} }, rowUpdateSubContentPaneSize, columnUpdateSubContentPaneSize, LayoutConstants.VGAP_LARGE); jarUpdateContentPane2.setBackground(Color.WHITE); jarUpdateContentPane.add(jarUpdateContentPane2); jarVersionInfoPane = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ new Component[]{new UILabel(), new UILabel(), new UILabel()}, - new Component[]{new UILabel(), initPaneContent(getBackground(), rowUpdateContentPaneSize, columnUpdateContentPaneSize, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_JarUpdate")), new UILabel(), jarRestoreLabel), new UILabel()}, new Component[]{new UILabel(), jarUpdateContentPane, new UILabel()} }, rowUpdatePaneSize, columnUpdatePaneSize, LayoutConstants.VGAP_LARGE); } @@ -219,7 +217,7 @@ public class UpdateMainDialog extends UIDialog { new Component[]{new UILabel(), new UILabel(), new UILabel()} }, searchRow, searchColumn, LayoutConstants.VGAP_LARGE); - String[] columnNames = {com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_SignHeader")}; + String[] columnNames = {com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Version"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_SignHeader")}; initUpdateInfoTable(columnNames); UIScrollPane uiScrollPane = new UIScrollPane(updateInfoTable); @@ -230,31 +228,32 @@ public class UpdateMainDialog extends UIDialog { } private void initUpdateInfoTable(String[] columnNames) { - int updateTimeColIndex = 0; - int updateTitleColIndex = 1; - int updateSignColIndex = 2; - updateInfoTable = new UpdateInfoTable(columnNames); updateInfoTable.setShowGrid(false); updateInfoTable.setCellSelectionEnabled(false); TableRowSorter sorter = new TableRowSorter<>(updateInfoTable.getDataModel()); - sorter.setSortable(updateTimeColIndex, true); - sorter.setSortable(updateTitleColIndex, false); - sorter.setSortable(updateSignColIndex, false); + sorter.setSortable(UpdateInfoTable.UPDATE_DATE_INDEX, true); + sorter.setSortable(UpdateInfoTable.UPDATE_VERSION_INDEX, true); + sorter.setSortable(UpdateInfoTable.UPDATE_TITLE_INDEX, false); + sorter.setSortable(UpdateInfoTable.SIGN_INDEX, false); updateInfoTable.setRowSorter(sorter); List sortKeys = new ArrayList<>(); - sortKeys.add(new RowSorter.SortKey(updateTimeColIndex, SortOrder.DESCENDING)); + sortKeys.add(new RowSorter.SortKey(UpdateInfoTable.UPDATE_DATE_INDEX, SortOrder.DESCENDING)); + sortKeys.add(new RowSorter.SortKey(UpdateInfoTable.UPDATE_VERSION_INDEX, SortOrder.DESCENDING)); sorter.setSortKeys(sortKeys); updateInfoTable.getTableHeader().setReorderingAllowed(false); - updateInfoTable.getColumnModel().getColumn(updateTimeColIndex).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); - updateInfoTable.getColumnModel().getColumn(updateTimeColIndex).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); - updateInfoTable.getColumnModel().getColumn(updateSignColIndex).setMaxWidth(0); - updateInfoTable.getColumnModel().getColumn(updateSignColIndex).setMinWidth(0); - updateInfoTable.getTableHeader().getColumnModel().getColumn(updateSignColIndex).setMaxWidth(0); - updateInfoTable.getTableHeader().getColumnModel().getColumn(updateSignColIndex).setMinWidth(0); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_DATE_INDEX).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_DATE_INDEX).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_VERSION_INDEX).setMaxWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.UPDATE_VERSION_INDEX).setMinWidth(UPDATE_INFO_TABLE_HEADER_TIME_WIDTH); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMaxWidth(0); + updateInfoTable.getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMinWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMaxWidth(0); + updateInfoTable.getTableHeader().getColumnModel().getColumn(UpdateInfoTable.SIGN_INDEX).setMinWidth(0); updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Date")).setCellRenderer(new UpdateInfoTableCellRender()); + updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Version")).setCellRenderer(new UpdateInfoTableCellRender()); updateInfoTable.getColumn(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Content")).setCellRenderer(new UpdateInfoTextAreaCellRender()); } @@ -270,6 +269,7 @@ public class UpdateMainDialog extends UIDialog { String keyword = searchUpdateInfoKeyword.getText(); if (ComparatorUtils.equals(keyword, StringUtils.EMPTY) && getUpdateInfoSuccess) { updateInfoList.clear(); + titleSet.clear(); getUpdateInfo(keyword).execute(); } } @@ -284,6 +284,7 @@ public class UpdateMainDialog extends UIDialog { public void actionPerformed(ActionEvent e) { if (getUpdateInfoSuccess) { updateInfoList.clear(); + titleSet.clear(); getUpdateInfo(searchUpdateInfoKeyword.getText()).execute(); } } @@ -298,18 +299,18 @@ public class UpdateMainDialog extends UIDialog { updateButton.setEnabled(false); double[] rowSize = {TableLayout.PREFERRED}; + double[] colSize = {TableLayout.PREFERRED}; + UILabel versionLabel = new UILabel(UpdateConstants.DEFAULT_APP_NAME + StringUtils.BLANK + ProductConstants.VERSION); + versionLabel.setFont(new Font("Default", Font.BOLD, 16)); + - double[] colSize = {UPDATE_CONTENT_PANE_LABEL_COLUMN_SIZE, TableLayout.PREFERRED}; updateVersionReminderPane = initPaneContent( - Color.WHITE, rowSize, colSize, - new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Designer_Version")), - new UILabel(UpdateConstants.DEFAULT_APP_NAME + StringUtils.BLANK + ProductConstants.VERSION) + Color.WHITE, rowSize, colSize, versionLabel ); String notInstallVersion = InterProviderFactory.getProvider().getLocText("Fine-Core_Basic_About_No_Build"); String versionBuildNo = GeneralUtils.getVersion() + HYPHEN + GeneralUtils.readBuildNO(); jarCurrentLabel = new UILabel(ComparatorUtils.equals(notInstallVersion, GeneralUtils.readBuildNO()) ? notInstallVersion : versionBuildNo, SwingConstants.CENTER); - UILabel noJarPreviousRevision = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_No_Previous_Version")); UpdateActionLabel jarRestorePreviousRevision = new UpdateActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Restore"), false); jarRestorePreviousRevision.setForeground(new Color(RESTORE_LABEL_COLOR)); jarRestorePreviousRevision.addActionListener(new ActionListener() { @@ -321,7 +322,7 @@ public class UpdateMainDialog extends UIDialog { }); //choose RestoreLabel to show boolean isNeedRestore = ArrayUtils.isNotEmpty(UpdateFileUtils.listBackupVersions()); - jarRestoreLabel = isNeedRestore ? jarRestorePreviousRevision : noJarPreviousRevision; + jarRestoreLabel = isNeedRestore ? jarRestorePreviousRevision : null; } private void initComponents() { @@ -350,7 +351,25 @@ public class UpdateMainDialog extends UIDialog { new SwingWorker() { @Override protected JSONObject doInBackground() throws Exception { - return new JSONObject(HttpToolbox.get(CloudCenter.getInstance().acquireUrlByKind("jar11.update"))); + try { + String url = CloudCenter.getInstance().acquireUrlByKind("jar11.update"); + return new JSONObject(HttpToolbox.get(url)); + } catch (SiteBlockedException e) { + stopLoading(); + FineJOptionPane.showConfirmDialogWithOkListener(null, + e.getMessage(), + Toolkit.i18nText("Fine-Design_Basic_Alert"), null, null, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignUtils.visitEnvServerByParameters( + "#management/system/normal", + null, + null); + } + }); + } + return null; } @Override @@ -373,6 +392,7 @@ public class UpdateMainDialog extends UIDialog { private SwingWorker getUpdateInfo(final String keyword) { updateInfoList = new ArrayList<>(); + titleSet = new HashSet<>(); lastUpdateCacheTime = UpdateConstants.CHANGELOG_X_START; String cacheConfigPath = getUpdateCacheConfig(); cacheProperty = new UpdateInfoCachePropertyManager(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres", cacheConfigPath)); @@ -397,18 +417,25 @@ public class UpdateMainDialog extends UIDialog { if (downloadFileConfig == null) { throw new Exception("network error."); } - HttpGet get = new HttpGet(CloudCenter.getInstance().acquireUrlByKind("changelog10") + "&start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); - httpClient = HttpToolbox.getHttpClient(CloudCenter.getInstance().acquireUrlByKind("changelog10") + "&start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + + HttpGet get = new HttpGet(CloudCenter.getInstance().acquireUrlByKind("updatelog") + "?start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + httpClient = HttpToolbox.getHttpClient(CloudCenter.getInstance().acquireUrlByKind("updatelog") + "?start=" + lastUpdateCacheTime + "&end=" + getLatestJARTimeStr()); + + response = httpClient.execute(get); String responseText = CommonIOUtils.inputStream2String(response.getEntity().getContent(),EncodeConstants.ENCODING_UTF_8).trim(); + JSONArray array = JSONArray.create(); //假如返回"-1",说明socket出错了 if (!ComparatorUtils.equals(responseText, "-1")) { - array = new JSONArray(responseText); + JSONObject respObject = new JSONObject(responseText); + if (respObject != null && "success".equals(respObject.get("status"))) { + array = respObject.getJSONArray("data"); + } } return array; } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage()); + FineLoggerFactory.getLogger().error(e, e.getMessage()); } return JSONArray.create(); } @@ -425,7 +452,7 @@ public class UpdateMainDialog extends UIDialog { updateCachedInfoFile(jsonArray); } catch (Exception e) { getUpdateInfoSuccess = true; - FineLoggerFactory.getLogger().error(e.getMessage()); + FineLoggerFactory.getLogger().error(e, e.getMessage()); } } }; @@ -439,7 +466,7 @@ public class UpdateMainDialog extends UIDialog { } //从文件中读取缓存的更新信息 - private void getCachedUpdateInfo(String keyword) throws Exception { + private void getCachedUpdateInfo(String keyword) { String cacheInfoPath = getUpdateCacheInfo(); File cacheFile = new File(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres", cacheInfoPath)); if (!ComparatorUtils.equals(lastUpdateCacheState, "success")) { @@ -452,26 +479,37 @@ public class UpdateMainDialog extends UIDialog { String readStr, updateTimeStr; while ((readStr = br.readLine()) != null) { String[] updateInfo = readStr.split("\\t"); - if (updateInfo.length == 2) { - updateTimeStr = updateInfo[0]; - Date updateTime = CHANGELOG_FORMAT.parse(updateTimeStr); + if (updateInfo.length == 3) { + updateTimeStr = updateInfo[UpdateInfoTable.UPDATE_DATE_INDEX]; + Date updateTime = UPDATELOG_FORMAT.parse(updateTimeStr); + + //形如 Build#release-2018.07.31.03.03.52.80 String currentNO = GeneralUtils.readBuildNO(); Date curJarDate = UPDATE_INFO_TABLE_FORMAT.parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); if (!ComparatorUtils.equals(keyword, StringUtils.EMPTY)) { - if (!containsKeyword(UPDATE_INFO_TABLE_FORMAT.format(updateTime), keyword) && !containsKeyword(updateInfo[1], keyword)) { + keyword.replace('.','-'); + if (!containsKeyword(UPDATELOG_FORMAT.format(updateTime), keyword) && !containsKeyword(updateInfo[UpdateInfoTable.UPDATE_TITLE_INDEX], keyword)) { continue; } } - if (isValidLogInfo(updateInfo[1])) { - updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateInfo[1], updateTime.after(curJarDate)}); + if (isValid(updateInfo, GeneralUtils.objectToString(curJarDate))) { + titleSet.add(updateInfo[UpdateInfoTable.UPDATE_TITLE_INDEX]); + updateInfoList.add(new Object[]{UPDATELOG_FORMAT.format(updateTime), updateInfo[UpdateInfoTable.UPDATE_VERSION_INDEX], updateInfo[UpdateInfoTable.UPDATE_TITLE_INDEX], updateTime.after(curJarDate)}); } } } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); } } } + + private boolean isValid(String[] updateInfo, String curJarDate) { + return isValidLogInfo(updateInfo[UpdateInfoTable.UPDATE_TITLE_INDEX]) && curJarDate != null && curJarDate.compareTo(updateInfo[UpdateInfoTable.UPDATE_DATE_INDEX]) <= 0 && !titleSet.contains(updateInfo[UpdateInfoTable.UPDATE_TITLE_INDEX]); + } + private void updateCachedInfoFile(JSONArray jsonArray) throws Exception { String cacheDirPath = StableUtils.pathJoin(WorkContext.getCurrent().getPath(), "resources", "offlineres"); File cacheFileDir = new File(cacheDirPath); @@ -496,7 +534,7 @@ public class UpdateMainDialog extends UIDialog { try (BufferedWriter bufferWriter = new BufferedWriter(writerStream)) { for (int i = 0; i < jsonArray.length(); i++) { JSONObject jo = (JSONObject) jsonArray.get(i); - bufferWriter.write((String) jo.get("update") + '\t' + jo.get("title")); + bufferWriter.write((String) jo.get("updateTime") + '\t' + jo.get("version") + '\t' + jo.get("jiraId") + " " + jo.get("info")); bufferWriter.newLine(); bufferWriter.flush(); } @@ -511,27 +549,35 @@ public class UpdateMainDialog extends UIDialog { private ArrayList generateUpdateInfoList(JSONArray jsonArray, String keyword) throws Exception { for (int i = 0; i < jsonArray.length(); i++) { JSONObject jo = (JSONObject) jsonArray.get(i); - String updateTitle = (String) jo.get("title"); - String updateTimeStr = (String) jo.get("update"); - Date updateTime = CHANGELOG_FORMAT.parse(updateTimeStr); + String updateTitle = (String) jo.get("jiraId") + " " + jo.get("info"); + String updateVersionStr = (String) jo.get("version"); + String updateTimeStr = (String) jo.get("updateTime"); + Date updateTime = UPDATELOG_FORMAT.parse(updateTimeStr); //形如 Build#release-2018.07.31.03.03.52.80 String currentNO = GeneralUtils.readBuildNO(); Date curJarDate = UPDATE_INFO_TABLE_FORMAT.parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); if (curJarDate == null) { curJarDate = updateTime; } - if (!ComparatorUtils.equals(keyword, StringUtils.EMPTY)) { - if (!containsKeyword(UPDATE_INFO_TABLE_FORMAT.format(updateTime), keyword) && !containsKeyword(updateTitle, keyword)) { + if (!ComparatorUtils.equals(keyword, StringUtils.EMPTY) && keyword != null) { + keyword.replace('.', '-'); + if (!containsKeyword(UPDATELOG_FORMAT.format(updateTime), keyword) && !containsKeyword(updateTitle, keyword)) { continue; } } - if (isValidLogInfo(updateTitle)) { - updateInfoList.add(new Object[]{UPDATE_INFO_TABLE_FORMAT.format(updateTime), updateTitle, updateTime.after(curJarDate)}); + Date curDate = UPDATE_INFO_TABLE_FORMAT.parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); + if (isValid4GenerateInfo(updateTitle, GeneralUtils.objectToString(curDate), updateTimeStr)) { + titleSet.add(updateTitle); + updateInfoList.add(new Object[]{updateTimeStr, updateVersionStr, updateTitle, updateTime.after(curJarDate)}); } } return new ArrayList<>(updateInfoList); } + private boolean isValid4GenerateInfo(String updateTitle, String curDate, String updateTimeStr) { + return isValidLogInfo(updateTitle) && curDate.compareTo(updateTimeStr) <= 0 && !titleSet.contains(updateTitle); + } + private boolean containsKeyword(String str, String keyword) { return str.toUpperCase().contains(keyword.toUpperCase()); } @@ -559,14 +605,12 @@ public class UpdateMainDialog extends UIDialog { Date currentDate = (new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss")).parse(currentNO, new ParsePosition(currentNO.indexOf("-") + 1)); if (DateUtils.subtractDate(jarDate, currentDate, DateUtils.SECOND) > 0) { updateButton.setEnabled(true); - updateLabel.setVisible(true); loadingLabel.stopLoading(buildNO.contains("-") ? buildNO.substring(buildNO.lastIndexOf("-") + 1) : buildNO); } else { loadingLabel.stopLoading(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Already_Latest_Version")); } } else { updateButton.setEnabled(true); - updateLabel.setVisible(true); loadingLabel.stopLoading(buildNO.contains("-") ? buildNO.substring(buildNO.lastIndexOf("-") + 1) : buildNO); } @@ -588,41 +632,7 @@ public class UpdateMainDialog extends UIDialog { * jar包更新按钮监听器 */ private void addActionListenerForUpdateBtn() { - updateButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")}; - int a = JOptionPane.showOptionDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Information"), - Toolkit.i18nText("Fine-Design_Update_Info_Title"),JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, UIManager.getIcon("OptionPane.warningIcon"), option, 1); - if (a == 0) { - progressBar.setVisible(true); - progressBar.setString(Toolkit.i18nText("Fine-Design_Update_Info_Wait_Message")); - UpdateCallBack callBack = new UpdateProgressCallBack(progressBar); - updateButton.setEnabled(false); - updateLabel.setVisible(false); - RestoreResultDialog.deletePreviousPropertyFile(); - final String installLib = StableUtils.pathJoin(StableUtils.getInstallHome(), ProjectConstants.LOGS_NAME, UpdateConstants.INSTALL_LIB); - final JFrame frame = DesignerContext.getDesignerFrame(); - final RestartHelper helper = new RestartHelper(); - FineProcessContext.getParentPipe().fire(FineProcessEngineEvent.DESTROY); - new FileProcess(callBack) { - @Override - public void onDownloadSuccess() { - progressBar.setVisible(false); - deleteForDesignerUpdate(installLib); - helper.restartForUpdate(frame); - } - @Override - public void onDownloadFailed() { - progressBar.setVisible(false); - deleteForDesignerUpdate(installLib); - FineJOptionPane.showMessageDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Failed_Message")); - helper.restartForUpdate(frame); - } - }.execute(); - } - } - }); + updateButton.addActionListener(new UpdateAction()); } private void deleteForDesignerUpdate(String installLib) { @@ -668,6 +678,13 @@ public class UpdateMainDialog extends UIDialog { return false; } + private ActionLabel getNewFeatureActionLabel(final String text){ + ActionLabel actionLabel = new ActionLabel(text, new Color(RESTORE_LABEL_COLOR)); + actionLabel.setDrawUnderLine(false); + actionLabel.addActionListener(new NewFeatureAction()); + return actionLabel; + } + /** * 显示窗口 */ @@ -685,4 +702,41 @@ public class UpdateMainDialog extends UIDialog { @Override public void checkValid() throws Exception { } -} \ No newline at end of file + + + private class UpdateAction implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")}; + int a = JOptionPane.showOptionDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Information"), + Toolkit.i18nText("Fine-Design_Update_Info_Title"),JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, UIManager.getIcon("OptionPane.warningIcon"), option, 1); + if (a == 0) { + progressBar.setVisible(true); + progressBar.setString(Toolkit.i18nText("Fine-Design_Update_Info_Wait_Message")); + UpdateCallBack callBack = new UpdateProgressCallBack(progressBar); + updateButton.setEnabled(false); + RestoreResultDialog.deletePreviousPropertyFile(); + final String installLib = StableUtils.pathJoin(StableUtils.getInstallHome(), ProjectConstants.LOGS_NAME, UpdateConstants.INSTALL_LIB); + final JFrame frame = DesignerContext.getDesignerFrame(); + final RestartHelper helper = new RestartHelper(); + FineProcessContext.getParentPipe().fire(FineProcessEngineEvent.DESTROY); + new FileProcess(callBack) { + @Override + public void onDownloadSuccess() { + progressBar.setVisible(false); + deleteForDesignerUpdate(installLib); + helper.restartForUpdate(frame); + } + @Override + public void onDownloadFailed() { + progressBar.setVisible(false); + deleteForDesignerUpdate(installLib); + FineJOptionPane.showMessageDialog(getParent(), Toolkit.i18nText("Fine-Design_Update_Info_Failed_Message")); + helper.restartForUpdate(frame); + } + }.execute(); + } + + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java index c7690f3d55..1b704826f7 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTable.java @@ -10,6 +10,12 @@ import java.util.Vector; * Created by XINZAI on 2018/8/21. */ public class UpdateInfoTable extends JTable { + + public static int UPDATE_DATE_INDEX = 0; + public static int UPDATE_VERSION_INDEX = 1; + public static int UPDATE_TITLE_INDEX = 2; + public static int SIGN_INDEX = 3; + private UpdateInfoTableModel dataModel; public UpdateInfoTable(TableModel dm) { diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java index 9a853762e8..21998babad 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTableCellRender.java @@ -18,11 +18,11 @@ public class UpdateInfoTableCellRender extends DefaultTableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); cell.setBackground((row & 1) != 0 ? new Color(0xf0f0f0) : Color.WHITE); - if ((Boolean) table.getValueAt(row, 2)) { + if ((Boolean) table.getValueAt(row, UpdateInfoTable.SIGN_INDEX)) { cell.setBackground(new Color(0xdfecfd)); } - if (column == 0) { - //设置首列日期居中显示 + if (column == UpdateInfoTable.UPDATE_DATE_INDEX || column == UpdateInfoTable.UPDATE_VERSION_INDEX) { + //设置日期,版本居中显示 setHorizontalAlignment(JLabel.CENTER); for (int i = 1; row - i >= 0; i++) { diff --git a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java index 4f9836d4c4..93edd98392 100644 --- a/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java +++ b/designer-base/src/main/java/com/fr/design/update/ui/widget/UpdateInfoTextAreaCellRender.java @@ -35,9 +35,9 @@ public class UpdateInfoTextAreaCellRender extends JTextArea implements TableCell setText(value == null ? "" : value.toString()); setBackground((row & 1) != 0 ? new Color(0xf0f0f0) : Color.WHITE); - if ((Boolean) table.getValueAt(row, 2)) { + if ((Boolean) table.getValueAt(row, UpdateInfoTable.SIGN_INDEX)) { setBackground(new Color(0xdfecfd)); } return this; } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java index fee07ac467..01369116d7 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java @@ -14,9 +14,10 @@ import com.fr.design.extra.exe.GetPluginPrefixExecutor; import com.fr.design.extra.exe.PluginLoginExecutor; import com.fr.design.extra.exe.ReadUpdateOnlineExecutor; import com.fr.design.extra.exe.SearchOnlineExecutor; +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.FileSelectionMode; -import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser; import com.fr.design.i18n.Toolkit; import com.fr.design.locale.impl.BbsRegisterMark; import com.fr.design.locale.impl.BbsResetMark; @@ -39,11 +40,12 @@ import com.teamdev.jxbrowser.chromium.Browser; import com.teamdev.jxbrowser.chromium.JSArray; import com.teamdev.jxbrowser.chromium.JSFunction; import com.teamdev.jxbrowser.chromium.JSObject; -import javafx.stage.FileChooser; -import javax.swing.*; +import java.awt.Desktop; +import javax.swing.JFileChooser; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; import java.io.File; import java.net.URI; import java.util.ArrayList; @@ -312,10 +314,10 @@ public class UpmBridge { RunnableFuture future = new FutureTask<>(new Callable() { @Override public String call() { - FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder(). - fileSelectionMode(FileSelectionMode.FILE). - filter(des, filter). - build(); + FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser( + FileChooserArgs.newBuilder(). + setFileSelectionMode(FileSelectionMode.FILE). + setFilter(des, filter).build()); int result = fileChooserProvider.showDialog(UpmFinder.getDialog()); if (result == JFileChooser.APPROVE_OPTION) { return fileChooserProvider.getSelectedFile().getAbsolutePath(); diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java b/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java index f3284c11e5..576c5a9b96 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java @@ -1,6 +1,6 @@ package com.fr.design.upm; -import com.fr.base.FRContext; +import com.fr.decision.webservice.v10.plugin.helper.category.impl.BaseResourceLoader; import com.fr.decision.webservice.v10.plugin.helper.category.impl.UpmResourceLoader; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.UIDialog; @@ -12,8 +12,11 @@ import com.fr.design.update.ui.dialog.UpdateMainDialog; import com.fr.event.Event; import com.fr.event.EventDispatcher; import com.fr.event.Listener; +import com.fr.general.CommonIOUtils; import com.fr.general.GeneralContext; +import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; +import com.fr.plugin.PluginStoreConstants; import com.fr.stable.StableUtils; import com.fr.workspace.Workspace; import com.fr.workspace.WorkspaceEvent; @@ -33,7 +36,7 @@ public class UpmFinder { private static final String MAIN_RESOURCE_PATH = UPM_DIR + "/plugin_design.html"; private static final String JXBROWSER = "com.teamdev.jxbrowser.browser.Browser"; - public static String installHome = FRContext.getCommonOperator().getWebRootPath(); + public static String installHome = PluginStoreConstants.getLocalInstallHome(); private static UIDialog dialog = null; @@ -41,7 +44,8 @@ public class UpmFinder { EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener() { @Override public void on(Event event, Workspace param) { - installHome = FRContext.getCommonOperator().getWebRootPath(); + installHome = PluginStoreConstants.getLocalInstallHome(); + UpmResourceLoader.INSTANCE.checkOldShopFile(); } }); } @@ -75,24 +79,24 @@ public class UpmFinder { } private static void showUpmPane() { - if (!checkUPMResourcesExist()){ + if (!checkUPMResourcesExist()) { // upm下载 int val = FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Plugin_Shop_Need_Install"), Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); - if (val == JOptionPane.OK_OPTION){ + if (val == JOptionPane.OK_OPTION) { try { UpmResourceLoader.INSTANCE.download(); - UpmResourceLoader.INSTANCE.install(); + installUpmResource(); + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Plugin_Shop_Installed"), Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE); - } catch (Exception e){ + } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Updater_Download_Failed"), Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE); } } - } - else { + } else { UpmShowPane upmPane = new UpmShowPane(); if (dialog == null) { dialog = new UpmShowDialog(DesignerContext.getDesignerFrame(), upmPane); @@ -102,6 +106,15 @@ public class UpmFinder { } } + private static void installUpmResource() { + String installHome = PluginStoreConstants.getLocalInstallHome(); + File scriptZip = new File(BaseResourceLoader.SCRIPT_DOWNLOAD_PATH); + if (scriptZip.exists()) { + IOUtils.unzip(scriptZip, installHome); + CommonIOUtils.deleteFile(scriptZip); + } + } + private static void showUpdatePane() { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Update_Info_Plugin_Message")); if (!GeneralContext.getLocale().equals(Locale.JAPANESE) && !GeneralContext.getLocale().equals(Locale.JAPAN) diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java b/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java index 0384b5c291..23a712508e 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java @@ -32,23 +32,14 @@ public class UpmShowPane extends BasicPane { UpmShowPane() { setLayout(new BorderLayout()); - modernUIPane = ModernUIPaneFactory.modernUIPaneBuilder() - .prepareForV6(new ScriptContextAdapter() { + modernUIPane = new ModernUIPane.Builder<>() + .prepare(new ScriptContextAdapter() { @Override public void onScriptContextCreated(ScriptContextEvent event) { - // 6.x JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); } }) - .prepareForV7(params -> { - // 7.x - JsObject window = params.frame().executeJavaScript("window"); - if (window != null) { - window.putProperty("PluginHelper", NewUpmBridge.getBridge(window)); - } - return InjectJsCallback.Response.proceed(); - }) .withURL(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()) .build(); EventDispatcher.listen(DownloadEvent.UPDATE, new Listener() { @@ -57,6 +48,12 @@ public class UpmShowPane extends BasicPane { modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); } }); + EventDispatcher.listen(DownloadEvent.UPDATE, new Listener() { + @Override + public void on(Event event, String param) { + modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); + } + }); add(modernUIPane, BorderLayout.CENTER); } } diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java b/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java index e97a5826a1..3d8252b759 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java @@ -37,7 +37,7 @@ public class UpmUtils { } private static String fetchLatestVersion() { - String version = CloudCenter.getInstance().acquireUrlByKind("upm.script.version"); + String version = CloudCenter.getInstance().acquireUrlByKind("upm.script.version.v11"); if (StringUtils.isBlank(version)) { version = "1.0"; } diff --git a/designer-base/src/main/java/com/fr/design/utils/ColorUtils.java b/designer-base/src/main/java/com/fr/design/utils/ColorUtils.java new file mode 100644 index 0000000000..f189ccc300 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/ColorUtils.java @@ -0,0 +1,73 @@ +package com.fr.design.utils; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.util.Arrays; + +/** + * created by Harrison on 2022/05/29 + **/ +public class ColorUtils { + + /** + * 递归的同步颜色 + * + * @param color 颜色 + */ + public static void syncBackground(Component component, Color color) { + + component.setBackground(color); + + if (component instanceof Container) { + Container container = (Container) component; + Component[] components = container.getComponents(); + if (components != null) { + Arrays.stream(components).forEach((e) -> syncBackground(e, color)); + } + } + } + + /** + * 递归的同步颜色,如何组件的背景颜色等于默认颜色的话,变更为 replaceColor + * + * @param component 组件 + * @param replaceColor 替换颜色 + * @param defaultColor 默认颜色 + */ + public static void syncBackgroundIfAbsent(Component component, Color replaceColor, Color defaultColor) { + + if (component.getBackground() != defaultColor) { + return; + } + component.setBackground(replaceColor); + if (component instanceof Container) { + Container container = (Container) component; + Component[] components = container.getComponents(); + if (components != null) { + Arrays.stream(components).forEach((e) -> syncBackgroundIfAbsent(e, replaceColor, defaultColor)); + } + } + } + + /** + * 使背景透明 + * + * @param component 组件 + */ + public static void transparentBackground(Component component) { + + syncBackgroundIfAbsent(component, new Color(0,0,0,0), ThemeUtils.BACK_COLOR); + } + + public static boolean isDarkColor(Color color) { + if(color == null) { + return false; + } + int red = color.getRed(); + int green = color.getGreen(); + int blue = color.getBlue(); + int greyLevel = (int)(red * 0.299 + green * 0.587 + blue * 0.114); + return greyLevel < 192; + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java index f066d648a2..4779f91916 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java @@ -2,10 +2,13 @@ package com.fr.design.utils; import com.fr.base.FeedBackInfo; import com.fr.base.ServerConfig; +import com.fr.base.Utils; import com.fr.concurrent.NamedThreadFactory; import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; +import com.fr.design.deeplink.DeepLinkCore; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.fun.DesignerEnvProcessor; import com.fr.design.gui.UILookAndFeel; import com.fr.design.i18n.Toolkit; @@ -17,15 +20,21 @@ import com.fr.general.ComparatorUtils; import com.fr.general.FRFont; import com.fr.general.GeneralContext; import com.fr.log.FineLoggerFactory; +import com.fr.plugin.injectable.PluginModule; import com.fr.stable.ArrayUtils; import com.fr.stable.CommonCodeUtils; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; +import com.fr.stable.bridge.ObjectHolder; import com.fr.stable.os.OperatingSystem; +import com.fr.stable.plugin.ExtraDesignClassManagerProvider; import com.fr.start.ServerStarter; +import com.fr.start.common.DesignerStartupContext; +import com.fr.start.common.DesignerStartupUtil; import com.fr.value.NotNullLazyValue; import com.fr.workspace.WorkContext; import org.jetbrains.annotations.NotNull; + import javax.swing.SwingUtilities; import javax.swing.UIManager; import java.awt.Desktop; @@ -44,6 +53,7 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.Locale; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -210,9 +220,30 @@ public class DesignUtils { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { + DesignerStartupContext context = DesignerStartupContext.getInstance(); + + // 如果在启动页展示中 + if (DesignerStartupUtil.openTemplateIfOnWaiting(f)) { + return; + } + // 如果是在启动中 + if (context.isOnStartup()) { + // 之前就有这样的问题 + return; + } + + // 打开模板 DesignerContext.getDesignerFrame().openTemplate(new FileFILE(f)); } }); + } else { + String url = line; + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + DeepLinkCore.getInstance().receiveDeeplink2(url); + } + }); } } } @@ -438,4 +469,29 @@ public class DesignUtils { return xmlDesignerVersion; } + public static DefaultValueAdjustProvider getValueAdjust() { + ExtraDesignClassManager extraDesignClassManager = PluginModule.getAgent(PluginModule.ExtraDesign); + if (extraDesignClassManager != null) { + Set providers = extraDesignClassManager.getArray(DefaultValueAdjustProvider.MARK_STRING); + for (DefaultValueAdjustProvider provider : providers) { + if (provider.selector().accept(new ObjectHolder())) { + return provider; + } + } + } + return null; + } + + /** + * 获取设计器可用字体 + * @return + */ + public static String[] getAvailableFontFamilyNames4Report() { + DefaultValueAdjustProvider valueAdjust = DesignUtils.getValueAdjust(); + if (valueAdjust != null) { + return valueAdjust.getAvailableFontFamilyNames4Report(); + } + return Utils.getAvailableFontFamilyNames4Report(); + } + } diff --git a/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java b/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java index 28ab5e4c14..b57c54fbcd 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java +++ b/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java @@ -4,7 +4,6 @@ import com.fr.common.report.ReportState; import com.fr.design.DesignerEnvManager; import com.fr.design.RestartHelper; import com.fr.design.dialog.TipDialog; -import com.fr.design.fun.DesignerPortProvider; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; @@ -18,16 +17,20 @@ import com.fr.general.IOUtils; import com.fr.process.engine.core.CarryMessageEvent; import com.fr.process.engine.core.FineProcessContext; import com.fr.stable.StringUtils; -import com.fr.stable.bridge.StableFactory; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLWriter; import com.fr.stable.xml.XMLableReader; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java b/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java new file mode 100644 index 0000000000..666d17b84a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java @@ -0,0 +1,80 @@ +package com.fr.design.utils; + +import com.fr.design.gui.ilable.UILabel; +import com.fr.stable.StringUtils; + +import javax.swing.JComponent; +import java.awt.Color; +import java.awt.Font; + +/** + * created by Harrison on 2022/05/24 + **/ +public class LinkStrUtils { + + public static final UILabel LABEL = new UILabel(); + + public static UILabel generateLabel(String html, JComponent templateLabel) { + + String style = generateStyle(templateLabel.getBackground(), templateLabel.getFont(), templateLabel.getForeground()); + String fullHtml = generateHtmlTag(style, html); + return new UILabel(fullHtml); + } + + public static String generateHtmlTag(String html) { + + String defaultStyle = generateDefaultStyle(); + return generateHtmlTag(defaultStyle, html); + } + + public static String generateHtmlTag(String style, String html) { + + if (StringUtils.isEmpty(style)) { + throw new NullPointerException("style"); + } + if (StringUtils.isEmpty(html)) { + throw new NullPointerException("html"); + } + return "" + html + ""; + } + + public static String generateLinkTag(String link, String text) { + + return "" + text + ""; + } + + public static String generateLinkTagWithoutUnderLine(String link, String text) { + return "" + text + ""; + } + + public static String generateStyle(Color backgroundColor, Font font, Color fontColor) { + + // 构建相同风格样式 + StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); + + style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); + style.append("font-size:").append(font.getSize()).append("pt;"); + style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); + style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");"); + + return style.toString(); + } + + public static String generateStyle(Font font, Color fontColor) { + + // 构建相同风格样式 + StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); + + style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); + style.append("font-size:").append(font.getSize()).append("pt;"); + style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); + return style.toString(); + } + + + + public static String generateDefaultStyle() { + + return generateStyle(LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/OpenLoadingPane.java b/designer-base/src/main/java/com/fr/design/utils/LoadingUtils.java similarity index 78% rename from designer-base/src/main/java/com/fr/design/mainframe/OpenLoadingPane.java rename to designer-base/src/main/java/com/fr/design/utils/LoadingUtils.java index adc30b2bff..a5a6803d3f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/OpenLoadingPane.java +++ b/designer-base/src/main/java/com/fr/design/utils/LoadingUtils.java @@ -1,35 +1,29 @@ -package com.fr.design.mainframe; +package com.fr.design.utils; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.general.IOUtils; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.LayoutManager; -import javax.swing.ImageIcon; -import javax.swing.JPanel; - -/** - * @author hades - * @version 10.0 - * Created by hades on 2021/4/9 - */ -public class OpenLoadingPane extends JPanel { - private static final ImageIcon LOADING_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/mainframe/openloading.png")); +public class LoadingUtils { + private static final ImageIcon LOADING_ICON = new ImageIcon(IOUtils.readImage("/com/fr/design/images/mainframe/loading.png")); private static final Color TIP_COLOR = new Color(108, 174, 235); private static final int Y_GAP = 50; private static final int X_GAP = 10; - private UILabel loadingLabel; - private UILabel tipLabel; - - public OpenLoadingPane() { - - setLayout(new LayoutManager() { - + public static JPanel createLoadingPane() { + JPanel jPanel = new JPanel(); + UILabel loadingLabel = new UILabel(LOADING_ICON); + UILabel tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Loading")); + tipLabel.setForeground(TIP_COLOR); + jPanel.setLayout(new LayoutManager() { @Override public void removeLayoutComponent(Component comp) { } @@ -64,12 +58,10 @@ public class OpenLoadingPane extends JPanel { public void addLayoutComponent(String name, Component comp) { } }); - setBackground(Color.WHITE); - loadingLabel = new UILabel(LOADING_ICON); - tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Open_Template_Loading")); - tipLabel.setForeground(TIP_COLOR); - add(loadingLabel); - add(tipLabel); + jPanel.setBackground(Color.WHITE); + jPanel.add(loadingLabel); + jPanel.add(tipLabel); + return jPanel; } } diff --git a/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java b/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java new file mode 100644 index 0000000000..fdb460eb41 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java @@ -0,0 +1,28 @@ +package com.fr.design.utils; + +import com.fr.base.svg.SVGLoader; +import com.fr.base.svg.SystemScaleUtils; +import java.awt.Graphics2D; + +/** + * 用于绘制svg图片缩放(高分屏下) + * + * @author hades + * @version 11.0 + * Created by hades on 2022/5/6 + */ +public class SvgPaintUtils { + + public static void beforePaint(Graphics2D g2) { + if (SystemScaleUtils.isJreHiDPIEnabled()) { + g2.scale(1 / SVGLoader.SYSTEM_SCALE, 1 / SVGLoader.SYSTEM_SCALE); + } + } + + public static void afterPaint(Graphics2D g2) { + if (SystemScaleUtils.isJreHiDPIEnabled()) { + g2.scale(SVGLoader.SYSTEM_SCALE, SVGLoader.SYSTEM_SCALE); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java b/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java new file mode 100644 index 0000000000..9fb1e632af --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java @@ -0,0 +1,171 @@ +package com.fr.design.utils; + +import com.fr.base.extension.FileExtension; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.worker.save.SaveFailureHandler; +import com.fr.file.FILE; +import com.fr.file.FILEChooserPane; +import com.fr.file.filetree.FileNode; +import com.fr.file.filter.ChooseFileFilter; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.stable.CoreConstants; +import com.fr.stable.ProductConstants; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.lock.TplOperator; + +import javax.swing.SwingWorker; +import java.io.OutputStream; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/5 + */ +public class TemplateUtils { + + /** + * 创建新的模板文件并打开模板 + * @param prefix 模板文件名称前缀 + * @param file 模板文件 + * @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板 + * 为true时以CurrentEditingTemplate为准创建新模板 + * 为false时以传入的File文件为准创建新模板,此文件可以不是编辑状态 + * @param openNewTemplate 是否需要在创建后打开模板 + */ + public static void createAndOpenTemplate(String prefix, FILE file, boolean createByEditingTemplate, boolean openNewTemplate) { + String fileName = file.getName(); + String oldPath = file.getPath(); + int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT); + if (indexOfLastDot < 0) { + return; + } + String suffix = fileName.substring(indexOfLastDot + 1); + FILEChooserPane fileChooserPane = FILEChooserPane.getInstance(true, true); + fileChooserPane.setFileNameTextField(prefix + fileName, suffix); + FileExtension fileExtension = FileExtension.parse(suffix); + fileChooserPane.addChooseFILEFilter(new ChooseFileFilter(fileExtension, ProductConstants.APP_NAME + Toolkit.i18nText("Fine-Design_Report_Template_File"))); + fileChooserPane.disableFileNameTextFiled(); + int result = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame(), suffix); + fileChooserPane.enableFileNameTextFiled(); + + if (isCancel(result)) { + return; + } + + if (isOk(result)) { + file = fileChooserPane.getSelectedFILE(); + _createAndOpenTemplate(file, oldPath, createByEditingTemplate, openNewTemplate); + } + } + + + private static void _createAndOpenTemplate(FILE file, String oldPath, boolean createByEditingTemplate, boolean openNewTemplate){ + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + byte[] content = new byte[0]; + if (createByEditingTemplate) { + // 从当前编辑模板中生成备份文件 + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + content = template.exportData(); + } else { + content = WorkContext.getWorkResource().readFully(oldPath); + } + if (ArrayUtils.isEmpty(content)) { + throw new Exception(oldPath + " content is empty" ); + } + OutputStream out = null; + try { + // 加锁 + WorkContext.getCurrent().get(TplOperator.class).saveAs(file.getPath()); + out = file.asOutputStream(); + out.write(content); + } finally { + try { + if (out != null) { + out.close(); + } + } finally { + // 解锁 + WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(file.getPath()); + } + + } + return null; + } + + @Override + protected void done() { + try { + get(); + if (openNewTemplate) { + DesignerContext.getDesignerFrame().openTemplate(file); + } + // 备份成功刷新下目录树 展示出来备份的模板 + TemplateTreePane.getInstance().refresh(); + } catch (Exception e) { + SaveFailureHandler.getInstance().process(e); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + }.execute(); + + } + + private static boolean isCancel(int result) { + return result == FILEChooserPane.CANCEL_OPTION || + result == FILEChooserPane.JOPTIONPANE_CANCEL_OPTION; + } + + private static boolean isOk(int result) { + return result == FILEChooserPane.JOPTIONPANE_OK_OPTION || + result == FILEChooserPane.OK_OPTION; + } + + public static String createLockeTemplatedName(JTemplate template, String name) { + int index = name.lastIndexOf(CoreConstants.DOT); + if (index < 0 || !template.isForbidden()) { + return name; + } + return name.substring(0, index) + Toolkit.i18nText("Fine_Design_Template_Has_Been_Locked") + name.substring(index); + } + + /** + * 检测当前所选模板是否已经被打开 + * + * @return + */ + public static boolean checkSelectedTemplateIsEditing() { + return checkTemplateIsEditing(TemplateTreePane.getInstance().getTemplateFileTree().getSelectedTreeNodes()); + } + + /** + * 检测指定模板节点是否已经被打开 + * + * @param treeNodes + * @return + */ + public static boolean checkTemplateIsEditing(ExpandMutableTreeNode[] treeNodes) { + if (ArrayUtils.isEmpty(treeNodes)) { + return false; + } + List> jTemplates = HistoryTemplateListCache.getInstance().getHistoryList(); + List openedFile = jTemplates.stream().map(JTemplate::getPath).collect(Collectors.toList()); + for (ExpandMutableTreeNode treeNode : treeNodes) { + String templatePath = ((FileNode) (treeNode.getUserObject())).getEnvPath(); + if (openedFile.contains(templatePath)) { + return true; + } + } + return false; + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java b/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java index abae997e39..c3c087b4db 100644 --- a/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java @@ -17,30 +17,63 @@ public class AdjustWorkBookDefaultStyleUtils { private static final Color TEMPLATE_BACKGROUND = new Color(16, 11, 43); private static final Color CELL_ELEMENT_BORDER = new Color(110, 110, 110); + private static final Color CELL_ELEMENT_FONT_FOREGROUND = Color.WHITE; + + private static Color currentStoryBack = null; + + public static void setCurrentStoryBack(Color color) { + currentStoryBack = color; + } + + private static Color getCurrentStoryBack() { + return currentStoryBack == null ? TEMPLATE_BACKGROUND : currentStoryBack; + } public static void adjustCellElement(CellElement cellElement) { if (DesignModeContext.isDuchampMode()) { Style style = cellElement.getStyle(); - style = style.deriveFRFont(style.getFRFont().applyForeground(Color.WHITE)); + style = adjustCellElement(style); + cellElement.setStyle(style); + } + } + + public static Style adjustCellElement(Style style) { + if (DesignModeContext.isDuchampMode()) { + style = style.deriveFRFont(style.getFRFont().applyForeground(CELL_ELEMENT_FONT_FOREGROUND)); style = style.deriveBorder(0, CELL_ELEMENT_BORDER, 0, CELL_ELEMENT_BORDER, 0, CELL_ELEMENT_BORDER, 0, CELL_ELEMENT_BORDER); - cellElement.setStyle(style); } + return style; + } + + public static Color adjustCellElementFontForeground(Color color) { + return DesignModeContext.isDuchampMode() ? CELL_ELEMENT_FONT_FOREGROUND : color; } public static void adjustFloatElement(FloatElement floatElement) { if (DesignModeContext.isDuchampMode()) { Style style = floatElement.getStyle(); - style = style.deriveBackground(ColorBackground.getInstance(TEMPLATE_BACKGROUND)); + style = style.deriveBackground(ColorBackground.getInstance(getCurrentStoryBack())); style = style.deriveFRFont(style.getFRFont().applyForeground(Color.WHITE)); floatElement.setStyle(style); } } public static Color adjustBack(Color color) { - return DesignModeContext.isDuchampMode() ? TEMPLATE_BACKGROUND : color; + return DesignModeContext.isDuchampMode() ? getCurrentStoryBack() : color; + } + + /** + * cpt模板是否支持跟随主题选项 + * 单元格样式 + * 悬浮元素样式 + * 纸张背景入口大屏模板屏蔽掉了 忽略 + * @return 大屏模板中cpt组件不支持 + */ + public static boolean supportTheme() { + return !DesignModeContext.isDuchampMode(); } } diff --git a/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java b/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java index ac75786314..d90f2af422 100644 --- a/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java @@ -17,6 +17,7 @@ import com.fr.design.actions.UpdateAction; import com.fr.design.actions.core.ActionFactory; import com.fr.design.border.UITitledBorder; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icheckbox.UICheckBox; @@ -32,6 +33,7 @@ import com.fr.design.style.color.ColorCell; import com.fr.design.style.color.ColorFactory; import com.fr.design.style.color.ColorSelectBox; import com.fr.design.style.color.ColorSelectable; +import com.fr.design.utils.DesignUtils; import com.fr.general.FRFont; import com.fr.stable.AssistUtils; import com.fr.stable.Constants; @@ -171,6 +173,10 @@ public final class GUICoreUtils { FRFont frFont = style.getFRFont(); textField.setFont(new Font(frFont.getFontName(), frFont.getStyle(), frFont.getShowSize(resolution))); + DefaultValueAdjustProvider valueAdjust = DesignUtils.getValueAdjust(); + if (valueAdjust != null) { + textField.setFont(valueAdjust.transformFontByResolution(frFont, resolution)); + } textField.setForeground(style.getFRFont().getForeground()); if (style.getBackground() instanceof ColorBackground) { diff --git a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java index e5624c4531..a6a2d7896a 100644 --- a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java +++ b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java @@ -52,6 +52,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import javax.swing.SwingWorker; /** * @author pengda @@ -64,6 +65,12 @@ public class VersionCheckUtils { private static final String ID = "id"; private static final String VERSION = "version"; private static final String NAME = "name"; + private static final String RUNNING = "running"; + private static final String SYNC = "sync"; + private static final String GROUP = "group"; + private static final String BI = "bi"; + private static final String BIPREFIX = "com.finebi"; + private static final String DEVELOP_BRANCH_MARK = "#"; private static final Set pluginsNeedIgnore = new HashSet<>(); static { pluginsNeedIgnore.addAll(Arrays.asList( @@ -82,7 +89,23 @@ public class VersionCheckUtils { public static boolean versionCheck(String envName) { - return checkLocalAndRemoteJartime(envName) && checkLocalAndRemotePlugin().size() == 0; + if (needCheckConsistency(envName)) { + return checkLocalAndRemoteJartime(envName) && checkLocalAndRemotePlugin().size() == 0; + } + return true; + } + + /** + * 判断是否需要检查Jartime和插件的一致性 + * + * @param selectedEnvName 当前工作目录名称 + * @return + */ + private static boolean needCheckConsistency(String selectedEnvName) { + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(selectedEnvName); + // 当前工作目录为远程工作目录时,需要检查 + return selectedEnv.getType() == DesignerWorkspaceType.Remote; } public static boolean versionCheck(DesignerWorkspaceInfo selectedEnv) { @@ -90,9 +113,23 @@ public class VersionCheckUtils { } public static void showVersionCheckDialog(String envName) { - if (!VersionCheckUtils.versionCheck(envName)) { - showNotificationDialog(envName); - } + new SwingWorker() { + @Override + protected Boolean doInBackground() { + return !VersionCheckUtils.versionCheck(envName); + } + + @Override + protected void done() { + try { + if (get()) { + showNotificationDialog(envName); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().warn(e.getMessage(), e); + } + } + }.execute(); } private static void showNotificationDialog(String envName) { @@ -119,21 +156,17 @@ public class VersionCheckUtils { } public static boolean checkLocalAndRemoteJartime(DesignerWorkspaceInfo selectedEnv) { - //是否需要做服务校验 - if (needCheckBranch(selectedEnv)) { - String localBranch; - String remoteBranch = getRemoteBranch(selectedEnv); - localBranch = GeneralUtils.readFullBuildNO(); - //通过是否包含#来避免当前版本为非安装版本(主要是内部开发版本) - if (localBranch.contains("#") && ComparatorUtils.equals(localBranch, remoteBranch)) { - //说明版本一致,仅做日志记录 - FineLoggerFactory.getLogger().info("Remote Designer version consistency"); - return true; - } else { - return false; - } + String localBranch; + String remoteBranch = getRemoteBranch(selectedEnv); + localBranch = GeneralUtils.readFullBuildNO(); + // 通过是否包含"#"来避免当前版本为非安装版本(主要是内部开发版本) + if (localBranch.contains(DEVELOP_BRANCH_MARK) && ComparatorUtils.equals(localBranch, remoteBranch)) { + //说明版本一致,仅做日志记录 + FineLoggerFactory.getLogger().info("Remote Designer version consistency"); + return true; + } else { + return false; } - return true; } public static List getNoExistServiceDescription(String envName) { @@ -247,10 +280,6 @@ public class VersionCheckUtils { return df.format(jarDate); } - private static boolean needCheckBranch(DesignerWorkspaceInfo selectedEnv) { - return selectedEnv.getType() == DesignerWorkspaceType.Remote; - } - public static JSONArray checkLocalAndRemotePlugin() { JSONArray differentPlugins = new JSONArray(); JSONArray remotePlugins = FRContext.getCommonOperator().getPluginStatus(); @@ -263,13 +292,10 @@ public class VersionCheckUtils { Map pluginsNameMap = ReportHelper.getPluginNameMap(); for (int i = 0; i < remotePlugins.size(); i++) { remotePlugin = remotePlugins.getJSONObject(i); - if (ComparatorUtils.equals(remotePlugin.getString("running"), "false") || (remotePlugin.containsKey("sync") && !remotePlugin.getBoolean("sync"))) { + if (isPluginNeedIgnore(remotePlugin)) { continue; } String remotePluginID = remotePlugin.getString(ID); - if (pluginsNeedIgnore.contains(remotePluginID)) { - continue; - } if (localPluginsMap.containsKey(remotePluginID)) { if (ComparatorUtils.equals(localPluginsMap.get(remotePluginID).getVersion(), remotePlugin.getString(VERSION))) { continue; @@ -290,6 +316,12 @@ public class VersionCheckUtils { return differentPlugins; } + private static boolean isPluginNeedIgnore(JSONObject remotePlugin) { + return ComparatorUtils.equals(remotePlugin.getString(RUNNING), "false") || (remotePlugin.containsKey(SYNC) && !remotePlugin.getBoolean(SYNC)) + || (remotePlugin.containsKey(GROUP) && ComparatorUtils.equals(remotePlugin.containsKey(GROUP), BI) || remotePlugin.getString(ID).startsWith(BIPREFIX) + || pluginsNeedIgnore.contains(remotePlugin.getString(ID))); + } + public static JSONArray syncPlugins(JSONArray differentPlugins) { Set uninstallFailed = uninstallPlugins(differentPlugins); List plugins = getSyncPlugins(differentPlugins, uninstallFailed); 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/widget/WidgetBoundsPaneFactory.java b/designer-base/src/main/java/com/fr/design/widget/WidgetBoundsPaneFactory.java index ae3dfc2557..2b2dcc532c 100644 --- a/designer-base/src/main/java/com/fr/design/widget/WidgetBoundsPaneFactory.java +++ b/designer-base/src/main/java/com/fr/design/widget/WidgetBoundsPaneFactory.java @@ -46,12 +46,12 @@ public class WidgetBoundsPaneFactory { private static final int RIGHT_PANE_WIDTH = 145; - public static UIExpandablePane createBoundsPane(UISpinner width, UISpinner height, JComponent ratioLocked) { + public static UIExpandablePane createBoundsPane(UISpinner width, UISpinner height, JComponent ratioLocked, NameAttribute nameAttribute) { JPanel boundsPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); double f = TableLayout.FILL; double p = TableLayout.PREFERRED; Component[][] components = new Component[][]{ - new Component[]{FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Basic_Component_Size")), + new Component[]{FRWidgetFactory.createLineWrapLabel(nameAttribute.getSizeName()), ratioLocked != null ? createRightPane(width, ratioLocked, height) : createRightPane(width, height)}, new Component[]{null, createRightPane(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Tree_Width"), SwingConstants.CENTER), new UILabel(Toolkit.i18nText("Fine-Design_Basic_Tree_Height"), SwingConstants.CENTER))}, }; @@ -65,7 +65,7 @@ public class WidgetBoundsPaneFactory { } public static UIExpandablePane createBoundsPane(UISpinner width, UISpinner height) { - return createBoundsPane(width, height, null); + return createBoundsPane(width, height, null, NameAttribute.DEFAULT); } public static JPanel createRightPane(Component com1, Component com2) { diff --git a/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java b/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java index d77e1e9000..7fd88dd957 100644 --- a/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java +++ b/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java @@ -1,6 +1,10 @@ package com.fr.design.widget.component; +import com.fr.design.ExtraDesignClassManager; +import com.fr.design.beans.ErrorMsgTextFieldAdapter; +import com.fr.design.beans.UITextFieldAdapter; import com.fr.design.designer.IntervalConstants; +import com.fr.design.fun.TextFieldAdapterProvider; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ispinner.UISpinner; @@ -9,6 +13,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.form.ui.NumberEditor; +import com.fr.log.FineLoggerFactory; import com.fr.stable.AssistUtils; import com.fr.stable.StringUtils; @@ -35,7 +40,7 @@ public class NumberEditorValidatePane extends JPanel { private UISpinner minValueSpinner; private UISpinner decimalLength; private JPanel limitNumberPane; - private UITextField errorMsgTextField; + private ErrorMsgTextFieldAdapter errorMsgTextField; private JPanel errorMsgTextFieldPane; private ActionListener allowDecimalsListener; @@ -100,9 +105,20 @@ public class NumberEditorValidatePane extends JPanel { } private void initErrorMsgPane() { - errorMsgTextField = new UITextField(); + TextFieldAdapterProvider provider = ExtraDesignClassManager.getInstance().getSingle(TextFieldAdapterProvider.XML_TAG); + if (provider != null) { + try { + errorMsgTextField = provider.createTextFieldAdapter(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + errorMsgTextField = new UITextFieldAdapter(); + } + } else { + errorMsgTextField = new UITextFieldAdapter(); + } + errorMsgTextFieldPane = TableLayoutHelper.createGapTableLayoutPane( - new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Error_Tip")), errorMsgTextField}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1); + new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Error_Tip")), errorMsgTextField.getErrorMsgTextField()}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1); } diff --git a/designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java b/designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java similarity index 50% rename from designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java rename to designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java index 9a76352f94..4f3b93a539 100644 --- a/designer-base/src/main/java/com/fr/design/widget/component/CheckBoxDictPane.java +++ b/designer-base/src/main/java/com/fr/design/widget/component/ReturnTypePane.java @@ -1,32 +1,29 @@ package com.fr.design.widget.component; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - import com.fr.design.designer.IntervalConstants; import com.fr.design.gui.ibutton.UIButtonGroup; -import com.fr.design.gui.ilable.UILabel; - -import javax.swing.*; - import com.fr.design.gui.icombobox.DictionaryComboBox; import com.fr.design.gui.icombobox.DictionaryConstants; +import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; -import com.fr.form.ui.CheckBoxGroup; -import com.fr.form.ui.ComboCheckBox; +import com.fr.form.ui.ReturnTypeProvider; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +public class ReturnTypePane extends JPanel { -public class CheckBoxDictPane extends JPanel { - - private DictionaryComboBox delimiterComboBox; - private UIButtonGroup returnTypeComboBox; - private DictionaryComboBox startComboBox; - private DictionaryComboBox endComboBox; - private JPanel returnStringPane; - - public CheckBoxDictPane() { + private final DictionaryComboBox delimiterComboBox; + private final UIButtonGroup returnTypeComboBox; + private final DictionaryComboBox startComboBox; + private final DictionaryComboBox endComboBox; + private final JPanel returnStringPane; + + public ReturnTypePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); delimiterComboBox = new DictionaryComboBox(DictionaryConstants.delimiters, DictionaryConstants.delimiterDisplays); delimiterComboBox.setEditable(true); @@ -36,18 +33,13 @@ public class CheckBoxDictPane extends JPanel { endComboBox.setEditable(true); Component[][] components = new Component[][]{ new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Delimiter")), delimiterComboBox}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_Start_Symbol")),startComboBox}, - new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_End_Symbol")),endComboBox} + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_Start_Symbol")), startComboBox}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Combo_CheckBox_End_Symbol")), endComboBox} }; returnStringPane = TableLayoutHelper.createGapTableLayoutPane(components, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W2, IntervalConstants.INTERVAL_L1); returnTypeComboBox = new UIButtonGroup(new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Array"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_String")}); - returnTypeComboBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkVisible(returnTypeComboBox.getSelectedIndex()); - } - }); + returnTypeComboBox.addActionListener(e -> checkVisible(returnTypeComboBox.getSelectedIndex())); JPanel headPane = TableLayoutHelper.createGapTableLayoutPane( new Component[][]{new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Date_Selector_Return_Type")), returnTypeComboBox}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1); JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); @@ -57,34 +49,33 @@ public class CheckBoxDictPane extends JPanel { this.add(jPanel); } - public void checkVisible(int selectIndex){ - returnStringPane.setVisible(selectIndex == 1); + public void setReturnType(ReturnType returnType) { + int selectIndex = returnType == ReturnType.ARRAY ? 0 : 1; + returnTypeComboBox.setSelectedIndex(selectIndex,true); + checkVisible(selectIndex); } - public void populate(ComboCheckBox comboCheckBox) { - this.delimiterComboBox.setSelectedItem(comboCheckBox.getDelimiter()); - this.returnTypeComboBox.setSelectedIndex(comboCheckBox.isReturnString() ? 1 : 0); - this.startComboBox.setSelectedItem(comboCheckBox.getStartSymbol()); - this.endComboBox.setSelectedItem(comboCheckBox.getEndSymbol()); - checkVisible(this.returnTypeComboBox.getSelectedIndex()); + public void checkVisible(int selectIndex) { + returnStringPane.setVisible(selectIndex == 1); } - public void update(ComboCheckBox comboCheckBox) { - comboCheckBox.setDelimiter((String)this.delimiterComboBox.getSelectedItem()); - comboCheckBox.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); - comboCheckBox.setStartSymbol((String)this.startComboBox.getSelectedItem()); - comboCheckBox.setEndSymbol((String)this.endComboBox.getSelectedItem()); + + public void update(ReturnTypeProvider returnTypeProvider) { + returnTypeProvider.setDelimiter((String) this.delimiterComboBox.getSelectedItem()); + returnTypeProvider.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); + returnTypeProvider.setStartSymbol((String) this.startComboBox.getSelectedItem()); + returnTypeProvider.setEndSymbol((String) this.endComboBox.getSelectedItem()); } - public void populate(CheckBoxGroup checkBoxGroup) { - this.delimiterComboBox.setSelectedItem(checkBoxGroup.getDelimiter()); - this.returnTypeComboBox.setSelectedIndex(checkBoxGroup.isReturnString() ? 1 : 0); - this.startComboBox.setSelectedItem(checkBoxGroup.getStartSymbol()); - this.endComboBox.setSelectedItem(checkBoxGroup.getEndSymbol()); + + public void populate(ReturnTypeProvider returnTypeProvider) { + this.delimiterComboBox.setSelectedItem(returnTypeProvider.getDelimiter()); + this.returnTypeComboBox.setSelectedIndex(returnTypeProvider.isReturnString() ? 1 : 0); + this.startComboBox.setSelectedItem(returnTypeProvider.getStartSymbol()); + this.endComboBox.setSelectedItem(returnTypeProvider.getEndSymbol()); checkVisible(this.returnTypeComboBox.getSelectedIndex()); } - public void update(CheckBoxGroup checkBoxGroup) { - checkBoxGroup.setDelimiter((String)this.delimiterComboBox.getSelectedItem()); - checkBoxGroup.setReturnString(this.returnTypeComboBox.getSelectedIndex() != 0); - checkBoxGroup.setStartSymbol((String)this.startComboBox.getSelectedItem()); - checkBoxGroup.setEndSymbol((String)this.endComboBox.getSelectedItem()); + + public enum ReturnType { + STRING, + ARRAY } } diff --git a/designer-base/src/main/java/com/fr/design/worker/open/OpenWorker.java b/designer-base/src/main/java/com/fr/design/worker/open/OpenWorker.java index 40e6683eb5..d9c8568bf9 100644 --- a/designer-base/src/main/java/com/fr/design/worker/open/OpenWorker.java +++ b/designer-base/src/main/java/com/fr/design/worker/open/OpenWorker.java @@ -3,18 +3,23 @@ package com.fr.design.worker.open; import com.fr.base.chart.exception.ChartNotFoundException; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MultiTemplateTabPane; +import com.fr.design.file.TemplateTreePane; import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockInfoDialog; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.JTemplate; import com.fr.design.utils.DesignUtils; import com.fr.design.worker.WorkerManager; import com.fr.exception.DecryptTemplateException; +import com.fr.exception.TplLockedException; import com.fr.file.FILE; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import java.util.UUID; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import javax.swing.UIManager; @@ -81,6 +86,11 @@ public class OpenWorker extends SwingWorker { JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon")); } + if (cause.getCause() instanceof TplLockedException) { + MultiTemplateTabPane.getInstance().closeCurrentTpl(); + TemplateTreePane.getInstance().getFileNode().setLock(UUID.randomUUID().toString()); + LockInfoDialog.show(null); + } FineLoggerFactory.getLogger().error(t.getMessage(), t); return; } 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/java/com/fr/design/worker/save/SaveFailureHandler.java b/designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java new file mode 100644 index 0000000000..080b9ddbcd --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java @@ -0,0 +1,149 @@ +package com.fr.design.worker.save; + +import com.fr.common.exception.ThrowableHandler; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.ui.util.UIUtil; +import com.fr.design.utils.TemplateUtils; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.general.IOUtils; +import com.fr.report.UnLockedException; +import com.fr.workspace.exception.DiskSpaceFullException; +import com.fr.report.InconsistentLockException; +import java.awt.Frame; +import javax.swing.JOptionPane; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2021/12/7 + */ +@SuppressWarnings("all") +public class SaveFailureHandler implements ThrowableHandler { + + private static final SaveFailureHandler INSTANCE = new SaveFailureHandler(); + + public static SaveFailureHandler getInstance() { + return INSTANCE; + } + + @Override + public boolean process(Throwable e) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + for (Handler handler : Handler.values()) { + try { + if (handler.process(e)) { + break; + } + } catch (Exception ignored) { + } + } + } + }); + return true; + } + + public enum Handler implements ThrowableHandler { + + FullDisk { + @Override + public boolean process(Throwable e) { + if (e.getCause() instanceof DiskSpaceFullException + || e instanceof DiskSpaceFullException + || e.getCause().getCause() instanceof DiskSpaceFullException) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine_Design_Template_Save_Failed_By_Full_Disk"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.WARNING_MESSAGE, + IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png")); + return true; + } + return false; + } + }, + UnLocked { + @Override + public boolean process(Throwable e) { + if (e.getCause() instanceof UnLockedException || e instanceof UnLockedException) { + processUnLocked(Toolkit.i18nText("Fine_Design_Template_Has_Been_UnLocked")); + return true; + } + return false; + } + }, + + InconsistentLock { + @Override + public boolean process(Throwable e) { + if (e.getCause() instanceof InconsistentLockException || e instanceof InconsistentLockException) { + processInconsistentLock(Toolkit.i18nText("Fine_Design_Template_Save_Failed_By_Lock_Inconsistency")); + return true; + } + return false; + } + }, + + Other { + @Override + public boolean process(Throwable e) { + boolean minimized = (DesignerContext.getDesignerFrame().getExtendedState() & Frame.ICONIFIED ) != 0; + FineJOptionPane.showMessageDialog( + minimized ? null : DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design-Basic_Save_Failure"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + JOptionPane.ERROR_MESSAGE); + return true; + } + }; + + + protected void processUnLocked(String tip) { + int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(), + tip, + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png"), + new Object[] {Toolkit.i18nText("Fine_Design_Template_SaveAs_Backup"), Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")}, null); + if (option == JOptionPane.YES_OPTION) { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (template != null) { + TemplateUtils.createAndOpenTemplate( + Toolkit.i18nText("Fine_Design_Template_Backup"), + new FileNodeFILE(new FileNode(template.getPath(), false)), + true, + false); + } + } + } + + protected void processInconsistentLock(String tip) { + int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(), + tip, + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png"), + new Object[] {Toolkit.i18nText("Fine_Design_Template_SaveAs_Backup"), Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")}, null); + if (option == JOptionPane.YES_OPTION) { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (template != null) { + TemplateUtils.createAndOpenTemplate( + Toolkit.i18nText("Fine_Design_Template_Backup"), + new FileNodeFILE(new FileNode(template.getPath(), false)), + true, + true); + // 创建并打开备份模板后,关闭原模板 + HistoryTemplateListCache.getInstance().closeSelectedReport(template); + } + } + } + + } +} diff --git a/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java b/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java index 51a79bbad9..60d797c3e9 100644 --- a/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java +++ b/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java @@ -1,8 +1,6 @@ package com.fr.design.worker.save; -import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.EastRegionContainerPane; @@ -10,11 +8,9 @@ import com.fr.design.mainframe.JTemplate; import com.fr.design.worker.WorkerManager; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; -import java.awt.Frame; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import javax.swing.JOptionPane; import javax.swing.SwingWorker; /** @@ -55,12 +51,7 @@ public class SaveWorker extends SwingWorker { } catch (Exception e) { processResult(); FineLoggerFactory.getLogger().error(e.getMessage(), e); - boolean minimized = (DesignerContext.getDesignerFrame().getExtendedState() & Frame.ICONIFIED ) != 0; - FineJOptionPane.showMessageDialog( - minimized ? null : DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design-Basic_Save_Failure"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.ERROR_MESSAGE); + SaveFailureHandler.getInstance().process(e); return; } processResult(); diff --git a/designer-base/src/main/java/com/fr/env/EnvPrepare.java b/designer-base/src/main/java/com/fr/env/EnvPrepare.java new file mode 100644 index 0000000000..288d2f09c6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/EnvPrepare.java @@ -0,0 +1,27 @@ +package com.fr.env; + +import com.fr.env.detect.EnvDetectorCenter; +import com.fr.module.Activator; + +/** + * 设计器环境准备 + * 更多的是一些钩子,需要在环境启动、切换时进行处理 + * 使用监听 {@link com.fr.workspace.WorkspaceEvent} 只能满足 + * before -> stop -> start -> after + * 现在支持 => + * before -> stop -> prepare -> start -> after + * + * created by Harrison on 2022/05/29 + **/ +public class EnvPrepare extends Activator { + + @Override + public void start() { + EnvDetectorCenter.getInstance().init(); + } + + @Override + public void stop() { + EnvDetectorCenter.getInstance().destroy(); + } +} diff --git a/designer-base/src/main/java/com/fr/env/HelpLink.java b/designer-base/src/main/java/com/fr/env/HelpLink.java index c717ce6ea6..9bc4316368 100644 --- a/designer-base/src/main/java/com/fr/env/HelpLink.java +++ b/designer-base/src/main/java/com/fr/env/HelpLink.java @@ -24,6 +24,8 @@ public class HelpLink { map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Cert_Error_Solution"), link); map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Connection_Unknown_Error_Solution"), link); map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_NetWork_Connection_Error_Solution"), link); + map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Redirect_Solution"), link); + map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_NetWork_Config_Solution"), link); return map.get(solution); } diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java index 56f90e804e..31bdaa979b 100644 --- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java +++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java @@ -9,9 +9,10 @@ import com.fr.design.fun.DesignerEnvProcessor; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icheckbox.UICheckBox; 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.FileSelectionMode; -import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ipasswordfield.UIPassWordField; import com.fr.design.gui.ipasswordfield.UIPasswordFieldWithFixedLength; @@ -564,7 +565,8 @@ public class RemoteEnvPane extends BasicBeanPane { fileChooserButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { - FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder().fileSelectionMode(FileSelectionMode.FILE).build(); + FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser(FileChooserArgs.newBuilder(). + setFileSelectionMode(FileSelectionMode.FILE).build()); int saveValue = fileChooserProvider.showDialog(SwingUtilities.getWindowAncestor(RemoteEnvPane.this)); if (saveValue == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooserProvider.getSelectedFile(); diff --git a/designer-base/src/main/java/com/fr/env/RemoteWorkspaceURL.java b/designer-base/src/main/java/com/fr/env/RemoteWorkspaceURL.java index 4ea950e845..1dcd2220f6 100644 --- a/designer-base/src/main/java/com/fr/env/RemoteWorkspaceURL.java +++ b/designer-base/src/main/java/com/fr/env/RemoteWorkspaceURL.java @@ -1,13 +1,20 @@ package com.fr.env; +import com.fr.log.FineLoggerFactory; import com.fr.stable.AssistUtils; import com.fr.stable.FCloneable; import com.fr.stable.StringUtils; +import java.net.URI; +import java.net.URISyntaxException; +import com.fr.third.guava.base.Strings; /** * @author yaohwu */ public class RemoteWorkspaceURL implements FCloneable { + private static final String IPV6_JUDGE_SYMBOL = "["; + + private static final String IPV6_JUDGE_SYMBOL2 = "]"; public static final String SYSTEM_LOGIN_PATH = "#management/system/login"; @@ -98,6 +105,8 @@ public class RemoteWorkspaceURL implements FCloneable { parserWebAndServlet(lefts); } } + //判断一下IPV6 + this.refreshIPV6Format(); } public boolean hasDefaultHostName() { @@ -129,6 +138,27 @@ public class RemoteWorkspaceURL implements FCloneable { return this.url; } + /** + * IPV6地址格式不同,处理字符串的方式不同,需要处理的是port和host + * 形如 http://[XXXX::XXXX:XXXX:XXXX:XXXX]:8080/webroot/decision + */ + public void refreshIPV6Format() { + String url = this.url; + if (Strings.isNullOrEmpty(url)) { + return; + } + if (!url.contains(IPV6_JUDGE_SYMBOL) || !url.contains(IPV6_JUDGE_SYMBOL2)) { + return; + } + URI uri = null; + try { + uri = new URI(url); + this.host = uri.getHost(); + this.port = String.valueOf(uri.getPort()); + } catch (URISyntaxException ignored) { + + } + } public void setHttps(boolean https) { isHttps = https; diff --git a/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java b/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java new file mode 100644 index 0000000000..1fb2665b28 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java @@ -0,0 +1,226 @@ +package com.fr.env.detect; + +import com.fr.common.util.Collections; +import com.fr.design.components.notification.NotificationDialog; +import com.fr.design.components.notification.NotificationDialogProperties; +import com.fr.design.components.notification.NotificationModel; +import com.fr.design.constants.DesignerLaunchStatus; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.ui.util.UIUtil; +import com.fr.env.detect.base.DetectorBridge; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.base.EnvDetectorConfig; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorStatus; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.event.Null; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.core.UUID; +import com.fr.task.Once; +import com.fr.update.delay.DelayHelper; +import com.fr.workspace.Workspace; +import com.fr.workspace.WorkspaceEvent; + +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 环境检测中心 + * + * created by Harrison on 2022/05/27 + **/ +public class EnvDetectorCenter { + + private final Listener START_UP_COMPLETE_LISTENER = new Listener() { + + @Override + public void on(Event event, Null param) { + // startup 的监听,执行一次即可 + EventDispatcher.stopListen(this); + FineLoggerFactory.getLogger().debug("startup complete, start detecting env"); + stop(); + } + }; + private final Listener AFTER_SWITCH_LISTENER = new Listener() { + @Override + public void on(Event event, Workspace param) { + FineLoggerFactory.getLogger().debug("switch env complete, start detecting env"); + stop(); + } + }; + + private final Once launchOnce = new Once(() -> { + + // 添加启动完成监听 + EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, START_UP_COMPLETE_LISTENER); + // 切换完成后的监听 + EventDispatcher.listen(WorkspaceEvent.AfterSwitch, AFTER_SWITCH_LISTENER); + }); + + private final AtomicReference PROCESS = new AtomicReference<>(); + + /** + * 当前还有什么动作未执行 + * 如果切换环境,这里的动作是要被清空的 + * 从而防止切换环境后, 上一个动作的环境延续过来 + */ + private final Set pendingActions = new HashSet<>(); + + public static EnvDetectorCenter getInstance() { + return EnvDetectorCenterHolder.INSTANCE; + } + + private static class EnvDetectorCenterHolder { + private static final EnvDetectorCenter INSTANCE = new EnvDetectorCenter(); + } + + /** + * 初始化 + */ + public void init() { + + // 如果已经启动了,则不再启动 + if (PROCESS.get() != null) { + return; + } + + start(); + // 默认是启动 + PROCESS.set(DetectorProcess.DESIGN_LAUNCH); + + launchOnce.run(); + } + + + /** + * 销毁,一般用在模块关闭中 + */ + public void destroy() { + + // 清空 + pendingActions.clear(); + + // 重置内容 + DetectorBridge.getInstance().reset(); + // 关闭逻辑 + DetectorBridge.getInstance().stop(); + + PROCESS.set(null); + } + + /** + * 启动 + */ + public void start() { + + DetectorBridge.getInstance().start(); + } + + /** + * 关闭 + */ + public void stop() { + + // 结束 + DetectorBridge.getInstance().stop(); + + // id值 + String uuid = UUID.randomUUID().toString(); + // 确认当前的 action 是否有效 + Supplier validAction = () -> pendingActions.contains(uuid); + + // 30s后执行 + Runnable detectorAction = () -> { + + // 如果当前没开启,则直接返回 + if (!EnvDetectorConfig.getInstance().isEnabled()) { + return; + } + + // 如果当前不包含这个 id, 就不执行 + if (!validAction.get()) { + return; + } + Stream resultStream = DetectorBridge.getInstance().detect().stream(); + + // 展示效果 + NotificationDialogProperties properties = new NotificationDialogProperties(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title")); + List notificationModels = resultStream + .filter(Objects::nonNull) + .filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION) + .map(DetectorUtil::convert2Notification) + .collect(Collectors.toList()); + if (Collections.isEmpty(notificationModels)) { + FineLoggerFactory.getLogger().debug("detector not found any exception"); + return; + } + + UIUtil.invokeLaterIfNeeded(() -> { + + // 如果当前不包含这个 id, 就不执行 + if (!validAction.get()) { + return; + } + NotificationDialog dialog = new NotificationDialog(properties, notificationModels); + dialog.open(); + + // 执行完移除 + pendingActions.remove(uuid); + }); + + }; + + // 添加 + pendingActions.add(uuid); + + + DelayHelper.delayCall(EnvDetectorCenter.class.getName(), detectorAction, 30, TimeUnit.SECONDS); + + } + + /** + * 使用预期外的错误进行展示 + * + * @param throwable 异常 + * @return + */ + public List terminate(Throwable throwable) { + + Stream resultStream = DetectorBridge.getInstance().detect(throwable).stream(); + return resultStream + .filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION) + .collect(Collectors.toList()); + } + + /** + * 预期外的终止 + * + * @return 检测结果 + */ + public List terminateUnexpectedly() { + + Stream resultStream = DetectorBridge.getInstance().detect().stream(); + return resultStream + .filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION) + .collect(Collectors.toList()); + } + + + private enum DetectorProcess { + + /** + * 设计器启动 + */ + DESIGN_LAUNCH, + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java new file mode 100644 index 0000000000..5414ba6489 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java @@ -0,0 +1,19 @@ +package com.fr.env.detect.base; + +import com.fr.env.detect.bean.DetectorType; + +/** + * created by Harrison on 2022/05/13 + **/ +public abstract class AbstractExceptionDetector implements ExceptionDetector { + + private DetectorType type; + + public AbstractExceptionDetector(DetectorType type) { + this.type = type; + } + + public DetectorType type() { + return type; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java new file mode 100644 index 0000000000..0dbce9c003 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java @@ -0,0 +1,55 @@ +package com.fr.env.detect.base; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.thowable.ThrowableConverter; +import com.fr.env.detect.thowable.ThrowableStore; + +import java.util.List; + +/** + * created by Harrison on 2022/05/13 + **/ +public abstract class CatchExceptionDetector extends AbstractExceptionDetector { + + private ThrowableStore throwableStore; + + private ThrowableConverter throwableConverter; + + public CatchExceptionDetector(DetectorType type, ThrowableConverter throwableConverter) { + super(type); + this.throwableStore = ThrowableStore.getInstance(); + this.throwableConverter = throwableConverter; + } + + public CatchExceptionDetector(DetectorType type, ThrowableStore throwableStore, ThrowableConverter throwableConverter) { + super(type); + this.throwableStore = throwableStore; + this.throwableConverter = throwableConverter; + } + + public ThrowableStore getThrowableStore() { + return throwableStore; + } + + public ThrowableConverter getThrowableConverter() { + return throwableConverter; + } + + @Override + public DetectorResult detect() { + + List throwableList = throwableStore.getAll(); + for (Throwable throwable : throwableList) { + if (throwableConverter.accept(throwable)) { + + DetectorResult result = throwableConverter.convert(throwable); + if (result == null) { + result = DetectorResult.normal(type()); + } + return result; + } + } + return DetectorResult.normal(type()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java new file mode 100644 index 0000000000..09ff9fe89d --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java @@ -0,0 +1,157 @@ +package com.fr.env.detect.base; + +import com.fr.common.annotations.Careful; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.impl.DetectorChain; +import com.fr.env.detect.impl.FineDbDirtyDetector; +import com.fr.env.detect.impl.FineDbLockedDetector; +import com.fr.env.detect.impl.FineDbPermissionDetector; +import com.fr.env.detect.impl.JarConflictDetector; +import com.fr.env.detect.impl.JarInconsistentDetector; +import com.fr.env.detect.impl.JarLackDetector; +import com.fr.env.detect.thowable.ThrowableLogAppender; +import com.fr.env.detect.thowable.ThrowableStore; +import com.fr.log.FineLoggerFactory; +import com.fr.value.NotNullLazyValue; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 检测器桥接逻辑 + * [detect-core] - bridge - ui + * 标记为谨慎类。目前埋点依赖于包名、方法名、方法特征,不能随意更改 + * + * created by Harrison on 2022/05/13 + **/ +@Careful +public class DetectorBridge { + + public static DetectorBridge getInstance() { + + return DetectorBridgeHolder.INSTANCE; + } + + private static class DetectorBridgeHolder { + + private static final DetectorBridge INSTANCE = new DetectorBridge(); + } + + private final NotNullLazyValue detectorManager = new NotNullLazyValue() { + + @Override + protected @NotNull DetectorManager compute() { + + DetectorManager manager = new DetectorManager(); + + // 按照顺序构造检测链 + manager.register(DetectorChain.construct( + new FineDbLockedDetector(), + new FineDbPermissionDetector(), + new FineDbDirtyDetector())); + + manager.register(new JarInconsistentDetector()); + manager.register(new JarLackDetector()); + manager.register(new JarConflictDetector()); + return manager; + } + }; + + private final AtomicBoolean hasStarted = new AtomicBoolean(false); + + public void start() { + + if (!hasStarted.get() && EnvDetectorConfig.getInstance().isEnabled()) { + // 开始注册异常处理 + ThrowableLogAppender.getInstance().enable(); + hasStarted.set(true); + } + } + + public void stop() { + + if (hasStarted.compareAndSet(true, false)) { + // 关闭异常处理 + ThrowableLogAppender.getInstance().disable(); + } + } + + public void reset() { + + ThrowableStore.getInstance().reset(); + } + + /** + * 针对某一项进行检测 + * 主要用于手动检测时 + * + * @param type 检测类型 + * @return 检测结果 + */ + @NotNull + public DetectorResult detect(DetectorType type) { + + try { + return detectorManager.getValue().detect(type); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("detect failed", e); + // 返回未知错误信息 + return DetectorResult.unknown(type); + } + } + + /** + * 针对某一项 \ 某一个异常进行检测 + * + * @param type 类型 + * @param throwable 异常 + * @return 结果 + */ + @NotNull + public DetectorResult detect(DetectorType type, Throwable throwable) { + + ThrowableStore.getInstance().add(throwable); + + DetectorResult result = detect(type); + + ThrowableStore.getInstance().reset(); + + return result; + + } + + /** + * 异常检测 + * 对异常统一检测 + * + * @return 能够检测出的异常情况 + */ + @NotNull + public Collection detect() { + + Stream results = detectorManager.getValue().detect(); + return results.collect(Collectors.toList()); + } + + /** + * 异常检测 + * 当遇到异常时,且异常难以处理,直接导致服务器启动失败时,调用 + * 将异常添加进来,统一检测 + * + * @param throwable 异常 + * @return 检测结果 + */ + @NotNull + public Collection detect(Throwable throwable) { + + ThrowableStore.getInstance().add(throwable); + Collection result = detect(); + ThrowableStore.getInstance().reset(); + + return result; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java new file mode 100644 index 0000000000..4e4592dcde --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java @@ -0,0 +1,18 @@ +package com.fr.env.detect.base; + +/** + * created by Harrison on 2022/05/25 + **/ +public class DetectorConstants { + + public static final String JAR_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4700.html?source=3"; + + public static final String FINE_DB_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4701.html?source=3"; + + public static final String SEPARATOR = "、"; + public static final String BR_TAG = "
"; + + public static final String WEB_LIB_PATH = "%FR_HOME%\\webapps\\webroot\\WEB-INF\\lib:"; + + public static final String FR_HOME_LIB = "%FR_HOME%\\lib:"; +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java new file mode 100644 index 0000000000..2ebbf331ea --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java @@ -0,0 +1,82 @@ +package com.fr.env.detect.base; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.impl.DetectorChain; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 检测器中心 + * + * created by Harrison on 2022/05/24 + **/ +class DetectorManager { + + /** + * 检测链的列表 + */ + private List chains = new ArrayList<>(); + + /** + * 单纯的检测器的列表 + */ + private List detectors = new ArrayList<>(); + + public void register(DetectorChain chain) { + + if (chain != null) { + chains.add(chain); + } + } + + public void register(ExceptionDetector detector) { + + if (detector != null) { + detectors.add(detector); + } + } + + public Stream detect() { + + Stream results = detectors.stream() + .map(ExceptionDetector::detect) + .filter(Objects::nonNull); + + Stream chainResults = chains.stream() + .map(DetectorChain::detect) + .filter(Objects::nonNull); + + List resultList = Stream.concat(results, chainResults) + .collect(Collectors.toList()); + + resultList.forEach(DetectorResult::log); + + return resultList.stream(); + } + + public DetectorResult detect(DetectorType type) { + + Stream chainDetectors = chains.stream() + .map(DetectorChain::getDetectors) + .flatMap(Collection::stream); + + Stream allDetectors = Stream.concat(detectors.stream(), chainDetectors); + + Optional result = allDetectors + .filter((detector -> type == detector.type())) + .findFirst() + .map(ExceptionDetector::detect); + + // 记录日志 + result.ifPresent(DetectorResult::log); + + return result.orElse(DetectorResult.normal(type)); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java new file mode 100644 index 0000000000..b9253ed4cc --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java @@ -0,0 +1,166 @@ +package com.fr.env.detect.base; + +import com.fr.base.function.ThrowableRunnable; +import com.fr.common.util.Collections; +import com.fr.design.components.notification.NotificationAction; +import com.fr.design.components.notification.NotificationMessage; +import com.fr.design.components.notification.NotificationModel; +import com.fr.design.components.notification.NotificationType; +import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.utils.LinkStrUtils; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.env.detect.bean.Message; +import com.fr.env.detect.bean.SolutionAction; +import com.fr.general.build.BuildInfo; +import com.fr.third.org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.JComponent; +import java.awt.Desktop; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import static com.fr.env.detect.base.DetectorConstants.BR_TAG; +import static com.fr.env.detect.base.DetectorConstants.FR_HOME_LIB; +import static com.fr.env.detect.base.DetectorConstants.SEPARATOR; +import static com.fr.env.detect.base.DetectorConstants.WEB_LIB_PATH; + +/** + * created by Harrison on 2022/05/25 + **/ +public class DetectorUtil { + + /** + * 是否是设计器的 jar + * + * @param info 信息 + * @return 是/否 + */ + public static boolean isDesignerJar(BuildInfo info) { + + if (info == null) { + return false; + } + return StringUtils.contains(info.getJar(), "fine-report-designer"); + } + + /** + * 将结果转化为提醒的数据 + * + * @param result 结果 + * @return 数据 + */ + public static NotificationModel convert2Notification(DetectorResult result) { + + List messages = new ArrayList<>(); + + Function> convert2NotificationMsg = message -> { + + NotificationMessage notificationMessage = null; + if (message != null) { + Message.Type type = message.getType(); + switch (type) { + case SIMPLE: + notificationMessage = (new NotificationMessage.SimpleMessage(message.get())); + break; + case LINK: + Message.Link linkMsg = (Message.Link) message; + notificationMessage = new NotificationMessage.LinkMessage(linkMsg.getText(), linkMsg.getLink()); + break; + default: + break; + } + } + return Optional.ofNullable(notificationMessage); + }; + + ExceptionTips tips = result.getTips(); + if (tips != null) { + convert2NotificationMsg + .apply(tips.getMessage()) + .ifPresent(messages::add); + } + + ExceptionSolution solution = result.getSolution(); + if (solution != null) { + convert2NotificationMsg.apply(solution.getMessage()) + .ifPresent(messages::add); + } + + NotificationAction notificationAction = null; + if (solution != null) { + SolutionAction solutionAction = solution.getAction(); + if (solutionAction != null) { + notificationAction = new NotificationAction() { + @Override + public String name() { + return solutionAction.name(); + } + + @Override + public void run(Object... args) { + solutionAction.run(); + } + }; + } + } + + return new NotificationModel(NotificationType.WARNING, notificationAction, messages); + } + + /** + * 将信息转化为展示的组件 + * + * @param message 信息 + * @return 组件 + */ + public static JComponent convert2TextComponent(@NotNull Message message, JComponent template) { + + if (message.getType() == Message.Type.LINK) { + Message.Link linkMsg = (Message.Link) message; + return new MessageWithLink(linkMsg.getText(), ThrowableRunnable.toRunnable(() -> { + Desktop.getDesktop().browse(URI.create(linkMsg.getLink())); + })); + } + return LinkStrUtils.generateLabel(message.get(), template); + } + + /** + * 将 lib 转化成合适的格式 + * %FR_HOME%/lib + * %FR_HOME%/webapps/webroot/WEB-INF/lib + * + * @param libMap jar 路径, key为前缀 + * @return 信息 + */ + public static String concatLibFormatMsg(Map> libMap) { + + String webLibPath = WEB_LIB_PATH; + String homeLibPath = FR_HOME_LIB; + + StringBuilder sb = new StringBuilder(); + + List homeLibs = libMap.get(homeLibPath); + if (!Collections.isEmpty(homeLibs)) { + sb.append(homeLibPath); + sb.append(StringUtils.join(homeLibs, SEPARATOR)); + } + + List webLibs = libMap.get(webLibPath); + if (!Collections.isEmpty(webLibs)) { + if (sb.length() != 0) { + sb.append(BR_TAG); + } + sb.append(webLibPath); + sb.append(StringUtils.join(webLibs, SEPARATOR)); + } + return sb.toString(); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java b/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java new file mode 100644 index 0000000000..eda399efad --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java @@ -0,0 +1,52 @@ +package com.fr.env.detect.base; + +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; + +/** + * created by Harrison on 2022/05/13 + **/ +public class EnvDetectorConfig implements XMLable { + + public static final String XML_TAG = "EnvDetectorConfig"; + + private static final long serialVersionUID = -8170289826729582122L; + + private static final EnvDetectorConfig INSTANCE = new EnvDetectorConfig(); + + public static EnvDetectorConfig getInstance() { + + return INSTANCE; + } + + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + this.setEnabled(reader.getAttrAsBoolean("isEnabled", true)); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.attr("isEnabled", this.isEnabled()); + writer.end(); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java b/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java new file mode 100644 index 0000000000..7713ef739e --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java @@ -0,0 +1,25 @@ +package com.fr.env.detect.base; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; + +/** + * created by Harrison on 2022/05/13 + **/ +public interface ExceptionDetector { + + /** + * 检测类型 + * + * @return TYPE + */ + DetectorType type(); + + /** + * 检测结果 + * + * @return 结果 + */ + DetectorResult detect(); + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java b/designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java new file mode 100644 index 0000000000..c8ef7a02c8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java @@ -0,0 +1,40 @@ +package com.fr.env.detect.base; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.thowable.ThrowableConverter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * created by Harrison on 2022/05/13 + **/ +class ThrowableBridge { + + private List throwableConverters = new ArrayList<>(); + + public void register(ThrowableConverter throwableConverter) { + + if (throwableConverter != null) { + throwableConverters.add(throwableConverter); + } + } + + /** + * 将 throwable 转化成检测的结果 + * + * @param throwable 异常 + * @return 结果 + */ + public Optional convert(Throwable throwable) { + + return throwableConverters + .stream() + .filter((e) -> e.accept(throwable)) + .map((e) -> e.convert(throwable)) + .filter(Objects::nonNull) + .findFirst(); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/base/package-info.java b/designer-base/src/main/java/com/fr/env/detect/base/package-info.java new file mode 100644 index 0000000000..12fef30e19 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/base/package-info.java @@ -0,0 +1,4 @@ +/** + * 设计器环境检测 见 {@see https://kms.fineres.com/pages/viewpage.action?pageId=388333688} + */ +package com.fr.env.detect.base; diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java new file mode 100644 index 0000000000..aa9a007bbb --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java @@ -0,0 +1,147 @@ +package com.fr.env.detect.bean; + +import org.jetbrains.annotations.Nullable; + +/** + * 检测结果 + * + * created by Harrison on 2022/05/13 + **/ +public class DetectorResult { + + private DetectorType type; + + private DetectorStatus status; + + private ExceptionTips tips; + + private ExceptionSolution solution; + + private ExceptionLog log; + + private DetectorResult(DetectorType type) { + this.type = type; + } + + private DetectorResult(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) { + + this.type = type; + this.tips = tips; + this.solution = solution; + this.log = log; + } + + public static DetectorResult unknown(DetectorType type) { + DetectorResult result = new DetectorResult(type); + result.status = DetectorStatus.UNKNOWN; + return result; + } + + public static DetectorResult normal(DetectorType type) { + + DetectorResult result = new DetectorResult(type); + result.status = DetectorStatus.NORMAL; + return result; + } + + public static DetectorResult exception(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) { + + DetectorResult result = new DetectorResult(type, tips, solution, log); + result.status = DetectorStatus.EXCEPTION; + return result; + } + + public DetectorStatus getStatus() { + return status; + } + + public DetectorType getType() { + return type; + } + + @Nullable + public ExceptionTips getTips() { + return tips; + } + + @Nullable + public ExceptionSolution getSolution() { + return solution; + } + + public void log() { + + if (log != null) { + log.log(); + } + } + + public static DetectorResultBuilder builder() { + + return new DetectorResultBuilder() + .withStatus(DetectorStatus.EXCEPTION); + } + + public static final class DetectorResultBuilder { + + private DetectorType type; + private DetectorStatus status; + private ExceptionTips tips; + private ExceptionSolution solution; + private ExceptionLog log; + + private DetectorResultBuilder() { + } + + public DetectorResultBuilder withType(DetectorType type) { + this.type = type; + return this; + } + + public DetectorResultBuilder withStatus(DetectorStatus status) { + this.status = status; + return this; + } + + public DetectorResultBuilder withTips(ExceptionTips tips) { + this.tips = tips; + return this; + } + + public DetectorResultBuilder withTips(String message) { + + Message.Simple simple = new Message.Simple(message); + this.tips = new ExceptionTips(simple); + return this; + } + + public DetectorResultBuilder withSolution(ExceptionSolution solution) { + this.solution = solution; + return this; + } + + public DetectorResultBuilder withSolution(String content, String link) { + + Message.Link message = new Message.Link(content, link); + this.solution = new ExceptionSolution(message, null); + return this; + } + + public DetectorResultBuilder withLog(String log, Object... args) { + + this.log = ExceptionLog.create(log, args); + return this; + } + + public DetectorResultBuilder withLog(ExceptionLog log) { + this.log = log; + return this; + } + + public DetectorResult build() { + DetectorResult detectorResult = new DetectorResult(type, tips, solution, log); + detectorResult.status = this.status; + return detectorResult; + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java new file mode 100644 index 0000000000..b7e5df818c --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java @@ -0,0 +1,22 @@ +package com.fr.env.detect.bean; + +/** + * created by Harrison on 2022/05/27 + **/ +public enum DetectorStatus { + + /** + * 正常 + */ + NORMAL, + + /** + * 异常 + */ + EXCEPTION, + + /** + * 未知 + */ + UNKNOWN, +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java new file mode 100644 index 0000000000..1dc8e4d62a --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java @@ -0,0 +1,159 @@ +package com.fr.env.detect.bean; + +import com.fr.design.i18n.Toolkit; + +/** + * 检测的原生数据 + * 其实这里可以继续拆分到不同的逻辑下面的, 比如实际生成 DetectorResult 的地方 {@link com.fr.env.detect.base.ExceptionDetector}。 + * 不过目前没有必要。先这样处理。 + * + * created by Harrison on 2022/05/13 + **/ +public enum DetectorType { + + /** + * 缺少 JAR + */ + LACK_OF_JAR(Kind.JAR, WorkType.LOCAL, + "Fine_Design_Basic_Jar_Lacked_Desc", + "Fine_Design_Basic_Jar_Lack", + "Fine_Design_Basic_Jar_Solution", + "Fine_Design_Basic_Log_Jar_Lack"), + + + /** + * JAR 包版本不一致 + */ + JAR_IN_CONSISTENCE(Kind.JAR, WorkType.SIMPLE, + "Fine_Design_Basic_Jar_InConsistent_Desc", + "Fine_Design_Basic_Jar_InConsistent", + "Fine_Design_Basic_Jar_Solution", + "Fine_Design_Basic_Log_Jar_InConsistent"), + + /** + * JAR 包冲突 + */ + JAR_CONFLICT(Kind.JAR, WorkType.REMOTE, + "Fine_Design_Basic_Jar_Problem_Desc", + "Fine_Design_Basic_Jar_Problem", + "Fine_Design_Basic_Jar_Solution", + "Fine_Design_Basic_Log_Jar_Problem"), + + /** + * FineDB 权限问题 + */ + FINE_DB_PERMISSION(Kind.FINE_DB, WorkType.LOCAL, + "Fine_Design_Basic_FineDB_Permission_Occupied_Desc", + "Fine_Design_Basic_FineDB_Permission_Occupied", + "Fine_Design_Basic_FineDB_Solution", + "Fine_Design_Basic_Log_FineDB_Permission_Occupied"), + + /** + * FineDB 锁 + */ + FINE_DB_LOCKED(Kind.FINE_DB, WorkType.LOCAL, + "Fine_Design_Basic_FineDB_Locked_Desc", + "Fine_Design_Basic_FineDB_Locked", + "Fine_Design_Basic_FineDB_Solution", + "Fine_Design_Basic_Log_FineDB_Locked"), + + /** + * FineDB 脏数据 + */ + FINE_DB_DIRTY(Kind.FINE_DB, WorkType.SIMPLE, + "Fine_Design_Basic_FineDB_Dirty_Data_Desc", + "Fine_Design_Basic_FineDB_Dirty_Data", + "Fine_Design_Basic_FineDB_Dirty_Solution", + "Fine_Design_Basic_Log_FineDB_Dirty_Data") + ; + + private final Kind kind; + + private final WorkType workType; + + private final String descLocale; + + private final String tipsLocale; + + private final String solutionLocale; + + private final String logLocale; + + DetectorType(Kind kind, WorkType workType, String descLocale, String tipsLocale, String solutionLocale, String logLocale) { + + this.kind = kind; + this.workType = workType; + this.descLocale = descLocale; + this.tipsLocale = tipsLocale; + this.solutionLocale = solutionLocale; + this.logLocale = logLocale; + } + + public String getDescription() { + return Toolkit.i18nText(descLocale); + } + + public String getDescLocale() { + return descLocale; + } + + public Kind getKind() { + return kind; + } + + public WorkType getWorkType() { + return workType; + } + + public String getTipsLocale() { + return tipsLocale; + } + + public String getSolutionLocale() { + return solutionLocale; + } + + public String getLogLocale() { + return logLocale; + } + + public enum Kind { + + /** + * JAR 类型 + */ + JAR("Fine_Design_Basic_Jar_Kind_Desc"), + + /** + * FineDB 类型 + */ + FINE_DB("Fine_Design_Basic_FineDB_Kind_Desc"); + + private final String locale; + + Kind(String locale) { + this.locale = locale; + } + + public String getDescription() { + return Toolkit.i18nText(this.locale); + } + } + + public enum WorkType { + + /** + * 本地 + */ + LOCAL, + /** + * 远程 + */ + REMOTE, + /** + * 全部 + */ + SIMPLE + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java new file mode 100644 index 0000000000..521e903452 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java @@ -0,0 +1,36 @@ +package com.fr.env.detect.bean; + +import com.fr.log.FineLoggerFactory; + +/** + * created by Harrison on 2022/05/13 + **/ +public class ExceptionLog { + + private final String template; + + private final Object[] args; + + private ExceptionLog(String template, Object... args) { + this.template = template; + this.args = args; + } + + public static ExceptionLog create(String template, Object... args) { + + return new ExceptionLog(template, args); + } + + public void log() { + + FineLoggerFactory.getLogger().error(template, args); + } + + public String getTemplate() { + return template; + } + + public Object[] getArgs() { + return args; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java new file mode 100644 index 0000000000..b4f549f679 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java @@ -0,0 +1,32 @@ +package com.fr.env.detect.bean; + +import org.jetbrains.annotations.Nullable; + +/** + * created by Harrison on 2022/05/13 + **/ +public class ExceptionSolution { + + private Message message; + + @Nullable + private SolutionAction action; + + public static ExceptionSolution create(String text, String link, SolutionAction action) { + + return new ExceptionSolution(new Message.Link(text, link), action); + } + + public ExceptionSolution(Message message, @Nullable SolutionAction action) { + this.message = message; + this.action = action; + } + + public Message getMessage() { + return message; + } + + public @Nullable SolutionAction getAction() { + return action; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java new file mode 100644 index 0000000000..b7ab6c63fa --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java @@ -0,0 +1,24 @@ +package com.fr.env.detect.bean; + +/** + * 异常提示 + * + * created by Harrison on 2022/05/13 + **/ +public class ExceptionTips { + + private Message message; + + public static ExceptionTips create(String text) { + + return new ExceptionTips(new Message.Simple(text)); + } + + public ExceptionTips(Message message) { + this.message = message; + } + + public Message getMessage() { + return message; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/Message.java b/designer-base/src/main/java/com/fr/env/detect/bean/Message.java new file mode 100644 index 0000000000..2acdec8b84 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/Message.java @@ -0,0 +1,83 @@ +package com.fr.env.detect.bean; + +/** + * created by Harrison on 2022/05/24 + **/ +public interface Message { + + /** + * 消息类型 + * + * @return 类型 + */ + Type getType(); + + /** + * 返回内容 + * + * @return 内容 + */ + String get(); + + enum Type { + + /** + * 简单 + */ + SIMPLE, + + /** + * 链接 + */ + LINK + } + + class Simple implements Message { + + private String message; + + public Simple(String message) { + this.message = message; + } + + @Override + public String get() { + return message; + } + + @Override + public Type getType() { + return Type.SIMPLE; + } + } + + class Link implements Message { + + private String text; + + private String link; + + public Link(String text, String link) { + this.text = text; + this.link = link; + } + + @Override + public String get() { + return getText(); + } + + public String getText() { + return text; + } + + public String getLink() { + return link; + } + + @Override + public Type getType() { + return Type.LINK; + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java b/designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java new file mode 100644 index 0000000000..4b959053bd --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java @@ -0,0 +1,11 @@ +package com.fr.env.detect.bean; + +/** + * created by Harrison on 2022/05/24 + **/ +public interface SolutionAction { + + String name(); + + void run(); +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/DetectorChain.java b/designer-base/src/main/java/com/fr/env/detect/impl/DetectorChain.java new file mode 100644 index 0000000000..352e72c6b8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/DetectorChain.java @@ -0,0 +1,46 @@ +package com.fr.env.detect.impl; + +import com.fr.env.detect.base.ExceptionDetector; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 检测链 + * 责任链模式, 有先后顺序,哪一个先获得,哪一个先终止。 + * + * created by Harrison on 2022/06/16 + **/ +public class DetectorChain { + + private List detectors = new ArrayList<>(); + + public static DetectorChain construct(ExceptionDetector... detectors) { + + DetectorChain detectorChain = new DetectorChain(); + detectorChain.detectors = Arrays.stream(detectors).collect(Collectors.toList()); + return detectorChain; + } + + @Nullable + public DetectorResult detect() { + + for (ExceptionDetector detector : detectors) { + DetectorResult result = detector.detect(); + if (result != null && result.getStatus() == DetectorStatus.EXCEPTION) { + return result; + } + } + return null; + } + + public List getDetectors() { + + return this.detectors; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java new file mode 100644 index 0000000000..6e33eda43b --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java @@ -0,0 +1,106 @@ +package com.fr.env.detect.impl; + +import com.fr.config.ConfigContext; +import com.fr.config.Configuration; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.AbstractExceptionDetector; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.Message; +import com.fr.env.detect.bean.SolutionAction; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.third.org.hibernate.exception.GenericJDBCException; + +import javax.swing.JOptionPane; +import java.util.Iterator; +import java.util.function.Function; + +/** + * created by Harrison on 2022/05/25 + **/ +public class FineDbDirtyDetector extends AbstractExceptionDetector { + + public FineDbDirtyDetector() { + + super(DetectorType.FINE_DB_DIRTY); + } + + @Override + public DetectorResult detect() { + + Iterator tableNames = ConfigContext.getConfigNames(); + while (tableNames.hasNext()) { + String tableName = tableNames.next(); + Class configClass = ConfigContext.getConfigClass(tableName); + Configuration configuration = ConfigContext.getConfigInstance(configClass); + try { + + // 尝试获取每一个值 + configuration.mirror(); + } catch (Throwable e) { + + Function isDirtyExFunction = throwable -> { + while (throwable != null) { + if (throwable instanceof GenericJDBCException) { + return true; + } + throwable = throwable.getCause(); + } + return false; + }; + boolean isDirtyEx = isDirtyExFunction.apply(e); + + if (isDirtyEx) { + DetectorType detectorType = DetectorType.FINE_DB_DIRTY; + DetectorResult.DetectorResultBuilder builder = DetectorResult + .builder() + .withType(detectorType); + + String tipsLocale = Toolkit.i18nText(detectorType.getTipsLocale(), tableName); + + String solutionLocale = detectorType.getSolutionLocale(); + ExceptionSolution exceptionSolution = new ExceptionSolution(new Message.Link(Toolkit.i18nText(solutionLocale, DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK), new SolutionAction() { + @Override + public String name() { + return Toolkit.i18nText("Fine-Design_Basic_Reset_Immediately"); + } + + @Override + public void run() { + boolean success = false; + try { + ResourceIOUtils.copy(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME), + StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_BAK_NAME)); + success = ResourceIOUtils.delete(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME)); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + // todo 最好的逻辑是,这里应该和 UI 隔离开的 + if (!success) { + FineJOptionPane.showMessageDialog(null, + Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset_Result", + ResourceIOUtils.getRealPath(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME))), + Toolkit.i18nText("Fine-Design_Basic_Error"), + JOptionPane.ERROR_MESSAGE); + } + } + }); + builder.withTips(tipsLocale) + .withSolution(exceptionSolution) + .withLog(Toolkit.i18nText(detectorType.getLogLocale(), tableName)); + + return builder.build(); + } + + } + } + + return DetectorResult.normal(DetectorType.FINE_DB_DIRTY); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java new file mode 100644 index 0000000000..c312ce3288 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java @@ -0,0 +1,16 @@ +package com.fr.env.detect.impl; + +import com.fr.env.detect.base.CatchExceptionDetector; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.impl.converter.FineDbLockedConverter; + +/** + * created by Harrison on 2022/05/26 + **/ +public class FineDbLockedDetector extends CatchExceptionDetector { + + public FineDbLockedDetector() { + super(DetectorType.FINE_DB_LOCKED, new FineDbLockedConverter()); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java new file mode 100644 index 0000000000..4e3a18cedd --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java @@ -0,0 +1,15 @@ +package com.fr.env.detect.impl; + +import com.fr.env.detect.base.CatchExceptionDetector; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.impl.converter.FineDbPermissionConverter; + +/** + * created by Harrison on 2022/05/26 + **/ +public class FineDbPermissionDetector extends CatchExceptionDetector { + + public FineDbPermissionDetector() { + super(DetectorType.FINE_DB_PERMISSION, new FineDbPermissionConverter()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java new file mode 100644 index 0000000000..2eb38d94ef --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java @@ -0,0 +1,15 @@ +package com.fr.env.detect.impl; + +import com.fr.env.detect.base.CatchExceptionDetector; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.impl.converter.ClassConflictConvertor; + +/** + * created by Harrison on 2022/05/26 + **/ +public class JarConflictDetector extends CatchExceptionDetector { + + public JarConflictDetector() { + super(DetectorType.JAR_CONFLICT, new ClassConflictConvertor()); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java new file mode 100644 index 0000000000..2a744046a1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java @@ -0,0 +1,156 @@ +package com.fr.env.detect.impl; + +import com.fr.common.util.Collections; +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.AbstractExceptionDetector; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.bean.ExceptionLog; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.env.detect.bean.Message; +import com.fr.general.build.BuildInfo; +import com.fr.general.build.BuildInfoManager; +import com.fr.general.build.BuildInfoOperator; +import com.fr.general.build.impl.BuildInfoOperatorImpl; +import com.fr.third.guava.collect.MapDifference; +import com.fr.third.guava.collect.Maps; +import com.fr.third.org.apache.commons.lang3.StringUtils; +import com.fr.workspace.WorkContext; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * created by Harrison on 2022/05/25 + **/ +public class JarInconsistentDetector extends AbstractExceptionDetector { + + public static final String SEPARATOR = ","; + + public JarInconsistentDetector() { + + super(DetectorType.JAR_IN_CONSISTENCE); + } + + /** + * 本地 + * 先获取 Designer, 然后对其他的 JAR 信息匹配 + *

+ * 远程 + * 两边一一对应匹配 + * + * @return 结果 + */ + @Override + public DetectorResult detect() { + + if (WorkContext.getCurrent().isLocal()) { + return detectLocal(); + } else { + return detectLocalAndRemote(); + } + } + + @NotNull + private DetectorResult detectLocalAndRemote() { + + // 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包 + BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class); + List buildInfos = buildInfoOperator.getBuildInfos(); + + // 远程情况 + List localInfos = BuildInfoManager.getInstance().getInfos(); + Map localMap = groupBy(localInfos); + + List remoteInfos = buildInfos; + Map remoteMap = groupBy(remoteInfos); + + MapDifference difference = Maps.difference(localMap, remoteMap); + // 获取本地远程不一样的部分 + Map> diffs = difference.entriesDiffering(); + + if (diffs.isEmpty()) { + return DetectorResult.normal(type()); + } + + Set inConsistentJars = diffs.keySet(); + + String message = StringUtils.join(inConsistentJars, SEPARATOR); + Message.Simple tipsMessage = new Message.Simple(Toolkit.i18nText("Fine_Design_Basic_Detect_Server") + Toolkit.i18nText(type().getTipsLocale()) + message); + + return DetectorResult.exception(type(), + new ExceptionTips(tipsMessage), + new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale(),DetectorConstants.JAR_HELP_LINK) + , DetectorConstants.JAR_HELP_LINK), null), + ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message)); + } + + @NotNull + private DetectorResult detectLocal() { + + // 本地的获取方式 + BuildInfoOperator operator = new BuildInfoOperatorImpl(); + List buildInfos = operator.getBuildInfos(); + + // 获取设计器的 build + Optional designerBuild = buildInfos.stream() + .filter(DetectorUtil::isDesignerJar) + .map(BuildInfo::getGroupBuild) + .filter(StringUtils::isNotEmpty) + .findFirst(); + + // 如果 build + if (!designerBuild.isPresent()) { + return DetectorResult.normal(type()); + } + + // 获取所有的不一致的 build + List inConsistentInfos = buildInfos.stream() + .filter((e) -> { + // 不为空,且不相等 + return StringUtils.isNotEmpty(e.getGroupBuild()) + && !StringUtils.equals(designerBuild.get(), e.getGroupBuild()); + }) + .collect(Collectors.toList()); + + // 没有直接返回 + if (Collections.isEmpty(inConsistentInfos)) { + return DetectorResult.normal(type()); + } + + // 有的话 + List inConsistentJars = inConsistentInfos.stream() + .map(BuildInfo::getJar) + .collect(Collectors.toList()); + String message = StringUtils.join(inConsistentJars, SEPARATOR); + String tipsMessage = Toolkit.i18nText("Fine_Design_Basic_Detect_Local") + Toolkit.i18nText(type().getTipsLocale()) + message; + + return DetectorResult.exception(type(), + new ExceptionTips(new Message.Simple(tipsMessage)), + new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK), null), + ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message)); + } + + private Map groupBy(List localInfos) { + + Map localMap = new HashMap<>(); + for (BuildInfo localInfo : localInfos) { + String jar = localInfo.getJar(); + String groupContent = localInfo.getGroupBuild(); + // 不一致的 JAR 检测,忽视缺少的情况 + if (StringUtils.isNotEmpty(groupContent)) { + localMap.put(jar, groupContent); + } + } + return localMap; + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java b/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java new file mode 100644 index 0000000000..8e28116e51 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java @@ -0,0 +1,164 @@ +package com.fr.env.detect.impl; + +import com.fr.common.util.Collections; +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.AbstractExceptionDetector; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.bean.ExceptionLog; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.env.detect.bean.Message; +import com.fr.general.build.BuildInfo; +import com.fr.general.build.BuildInfoManager; +import com.fr.general.build.BuildInfoOperator; +import com.fr.general.build.impl.BuildInfoOperatorImpl; +import com.fr.third.guava.collect.Lists; +import com.fr.third.org.apache.commons.lang3.StringUtils; +import com.fr.workspace.WorkContext; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static com.fr.env.detect.base.DetectorConstants.FR_HOME_LIB; +import static com.fr.env.detect.base.DetectorConstants.WEB_LIB_PATH; + +/** + * created by Harrison on 2022/05/24 + **/ +public class JarLackDetector extends AbstractExceptionDetector { + + public JarLackDetector() { + + super(DetectorType.LACK_OF_JAR); + } + + @Override + public DetectorResult detect() { + + List lackInfos; + + // 远程 + if (!WorkContext.getCurrent().isLocal()) { + // 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包 + BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class); + // 远程情况 + List remoteInfos = buildInfoOperator.getBuildInfos(); + // 本地情况 + List localInfos = BuildInfoManager.getInstance().getInfos(); + + // 说明远程环境并不存在对应的 info.json, 直接忽略 + if (Collections.isEmpty(remoteInfos)) { + return DetectorResult.normal(type()); + } + + Set remoteSet = remoteInfos.stream() + .filter(this::isExistInfo) + .map(BuildInfo::getJar) + .collect(Collectors.toSet()); + + Predicate remoteNotContains = (e) -> !remoteSet.contains(e.getJar()); + + lackInfos = localInfos.stream() + .filter(this::isExistInfo) + // 不是设计器的 JAR + .filter((e) -> !DetectorUtil.isDesignerJar(e)) + .filter(remoteNotContains) + .collect(Collectors.toList()); + + } else { + // 本地 + // 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包 + BuildInfoOperator buildInfoOperator = new BuildInfoOperatorImpl(); + List buildInfos = buildInfoOperator.getBuildInfos(); + lackInfos = buildInfos.stream() + .filter(this::isLackInfo) + .collect(Collectors.toList()); + } + + if (Collections.isEmpty(lackInfos)) { + return DetectorResult.normal(type()); + } + + Message tipsMsg = tipsMessage(lackInfos); + ExceptionLog exceptionLog = exceptionLog(lackInfos); + + return DetectorResult.exception(type(), + new ExceptionTips(tipsMsg), + new ExceptionSolution( + new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK), + null), exceptionLog); + } + + private ExceptionLog exceptionLog(List lackInfos) { + + List jarInfos = lackInfos.stream() + .map(BuildInfo::getJar) + .collect(Collectors.toList()); + String message = StringUtils.join(jarInfos, ","); + return ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message); + } + + private boolean isExistInfo(BuildInfo e) { + + return !isLackInfo(e); + } + + private boolean isLackInfo(BuildInfo e) { + + return StringUtils.isEmpty(e.getGroupBuild()); + } + + private Message tipsMessage(List infos) { + + Map> libMap = groupByPath(infos, FR_HOME_LIB, WEB_LIB_PATH); + + String content = DetectorUtil.concatLibFormatMsg(libMap); + DetectorType type = this.type(); + String header = Toolkit.i18nText(type.getTipsLocale()); + return new Message.Simple(header + content); + } + + @NotNull + private Map> groupByPath(List infos, String homeLibPath, String webLibPath) { + + Map> libMap = new HashMap<>(); + for (BuildInfo info : infos) { + String key; + if (inHomeLib(info)) { + key = homeLibPath; + } else { + key = webLibPath; + } + libMap.compute(key, (keyA, value) -> { + if (Collections.isEmpty(value)) { + value = Lists.newArrayList(info.getJar()); + } else { + value.add(info.getJar()); + } + return value; + }); + } + return libMap; + } + + /** + * 在 %FR_HOME%\lib + * 否则都是在 %FR_HOME%\webapps\webroot\WEB-INF\lib + * + * @param info JAR 信息 + * @return 是否位于 HOME\LIB + */ + private boolean inHomeLib(BuildInfo info) { + + return DetectorUtil.isDesignerJar(info); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java new file mode 100644 index 0000000000..6cd92e4039 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java @@ -0,0 +1,216 @@ +package com.fr.env.detect.impl.converter; + +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.bean.ExceptionLog; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.env.detect.thowable.ThrowableConverter; +import com.fr.stable.EncodeConstants; +import com.fr.stable.resource.ResourceLoader; +import org.jetbrains.annotations.NotNull; + +import javax.el.MethodNotFoundException; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 类抛出异常的转换 + * 原则:可以找不到,但不要误报 + * + * created by Harrison on 2022/05/24 + **/ +public class ClassConflictConvertor implements ThrowableConverter { + + public static final String CLASSES = "classes"; + public static final String SEPARATOR = "、"; + /** + * 获取对应的 JAR 包名称 + */ + private static final Pattern JAR_NAME_PATTERN = Pattern.compile("([\\w+-\\.]*\\.jar)"); + + private static final String WEB_INF_STRING = "WEB-INF"; + private static final String JAR_URL_SUFFIX = ".jar!"; + private static final String JAR_FILE_SUFFIX = ".jar"; + private static final String FILE_URL_PREFIX = "file:"; + private static final String PLUGINS_DIR_NAME = "plugins"; + + private final Map, ClassNameConverter> throwableMap = new HashMap<>(); + + public ClassConflictConvertor() { + + // 类异常 + this.throwableMap.put(ClassNotFoundException.class, Converter.CLASS); + this.throwableMap.put(NoClassDefFoundError.class, Converter.CLASS); + this.throwableMap.put(ClassCastException.class, Converter.CLASS); + this.throwableMap.put(IncompatibleClassChangeError.class, Converter.CLASS); + + // 方法异常 + this.throwableMap.put(MethodNotFoundException.class, Converter.METHOD); + this.throwableMap.put(NoSuchMethodException.class, Converter.METHOD); + this.throwableMap.put(NoSuchMethodError.class, Converter.METHOD); + } + + @Override + public boolean accept(Throwable throwable) { + + Throwable sign = throwable; + while (sign != null) { + if (throwableMap.containsKey(sign.getClass())) { + return true; + } + sign = sign.getCause(); + } + return false; + } + + @Override + public DetectorResult convert(Throwable throwable) { + + Iterable classNames = Collections.emptyList(); + Throwable sign = throwable; + while (sign != null) { + if (throwableMap.containsKey(sign.getClass())) { + classNames = throwableMap.get(sign.getClass()) + .converter(throwable); + } + sign = sign.getCause(); + } + + Map> libMap = new HashMap<>(); + libMap.put(DetectorConstants.FR_HOME_LIB, new ArrayList<>()); + libMap.put(DetectorConstants.WEB_LIB_PATH, new ArrayList<>()); + + Set allPath = new HashSet<>(); + for (String className : classNames) { + String classFile = convertClass2Path(className); + try { + Enumeration urls = ResourceLoader.getResources(classFile, this.getClass()); + List urlList = new ArrayList<>(); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + urlList.add(url); + } + for (URL url : urlList) { + String file = url.getFile(); + String decodeFileStr = URLDecoder.decode(file, EncodeConstants.ENCODING_UTF_8); + if (decodeFileStr.contains(PLUGINS_DIR_NAME)) { + continue; + } + if (decodeFileStr.contains(JAR_URL_SUFFIX)) { + String jarPath = decodeFileStr.substring(FILE_URL_PREFIX.length(), decodeFileStr.indexOf(JAR_URL_SUFFIX) + JAR_FILE_SUFFIX.length()); + String jar = new File(jarPath).getName(); + if (allPath.add(jar)) { + List libPath; + if (file.contains(WEB_INF_STRING)) { + libPath = libMap.get(DetectorConstants.WEB_LIB_PATH); + } else { + libPath = libMap.get(DetectorConstants.FR_HOME_LIB); + } + libPath.add(jar); + } + } + } + } catch (IOException ignore) { + } + } + + // 如果少于两个,则不需要提示 + if (allPath.size() < 2) { + return null; + } + + String msg = DetectorUtil.concatLibFormatMsg(libMap); + + DetectorType type = DetectorType.JAR_CONFLICT; + return DetectorResult.exception(type, + ExceptionTips.create(Toolkit.i18nText(type.getTipsLocale()) + msg), + ExceptionSolution.create(Toolkit.i18nText(type.getSolutionLocale()), DetectorConstants.JAR_HELP_LINK, null), + ExceptionLog.create(Toolkit.i18nText(type.getLogLocale()) + msg)); + } + + @NotNull + private String convertClass2Path(String className) { + + return "/" + className.replaceAll("\\.", "/") + ".class"; + } + + private interface ClassNameConverter { + + /** + * 将异常解析为类名,可能有多个 + * + * @param throwable 异常 + * @return 类名 + */ + Iterable converter(Throwable throwable); + } + + public enum Converter implements ClassNameConverter { + + /** + * 类匹配 + */ + CLASS { + + /** + * 匹配 111.222.333 + * 至少有一个 111. + * 至少有一个 333 + */ + private final Pattern CLASS_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))"); + + @Override + public Iterable converter(Throwable throwable) { + + String message = throwable.getMessage(); + Matcher matcher = CLASS_PATTERN.matcher(message); + List names = new ArrayList<>(); + while (matcher.find()) { + String className = matcher.group(); + names.add(className); + } + return names; + } + }, + + /** + * 方法匹配 + */ + METHOD { + + /** + * 后面有 .method()xxxx + */ + private final Pattern METHOD_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))(\\.\\w+\\(\\))"); + + @Override + public Iterable converter(Throwable throwable) { + + String message = throwable.getMessage(); + Matcher matcher = METHOD_PATTERN.matcher(message); + List names = new ArrayList<>(); + while (matcher.find()) { + String className = matcher.group(); + names.add(className); + } + return names; + } + } + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java new file mode 100644 index 0000000000..2b627a7b22 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java @@ -0,0 +1,69 @@ +package com.fr.env.detect.impl.converter; + +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.thowable.ThrowableConverter; +import com.fr.third.org.apache.commons.lang3.StringUtils; +import com.fr.third.org.hsqldb.HsqlException; +import com.fr.workspace.WorkContext; + +/** + * created by Harrison on 2022/05/24 + **/ +public class FineDbLockedConverter implements ThrowableConverter { + + public static final String LOCK_FILE = "lockFile"; + + @Override + public boolean accept(Throwable throwable) { + + Throwable sign = throwable; + while (sign != null) { + if (sign.getClass() == HsqlException.class) { + return true; + } + sign = sign.getCause(); + } + return false; + } + + /** + * 检测 FineDB 是否锁住 + * + * @param throwable 异常 + * @return 结果 + */ + @Override + public DetectorResult convert(Throwable throwable) { + + // 远程不执行 + if (!WorkContext.getCurrent().isLocal()) { + return null; + } + + Throwable sign = throwable; + while (sign != null && sign.getClass() != HsqlException.class) { + sign = sign.getCause(); + } + + if (sign == null) { + return null; + } + + DetectorType type = DetectorType.FINE_DB_LOCKED; + + String message = sign.getMessage(); + if (StringUtils.containsIgnoreCase(message, LOCK_FILE)) { + + return DetectorResult.builder() + .withType(type) + .withTips(Toolkit.i18nText(type.getTipsLocale())) + .withSolution(Toolkit.i18nText(type.getSolutionLocale(),DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK) + .withLog(Toolkit.i18nText(type.getLogLocale())) + .build(); + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java new file mode 100644 index 0000000000..d34e7c245d --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java @@ -0,0 +1,84 @@ +package com.fr.env.detect.impl.converter; + +import com.fr.design.i18n.Toolkit; +import com.fr.env.detect.base.DetectorConstants; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.thowable.ThrowableConverter; +import com.fr.stable.project.ProjectConstants; +import com.fr.third.org.apache.commons.io.FileUtils; +import com.fr.third.org.hsqldb.HsqlException; +import com.fr.workspace.WorkContext; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.RandomAccessFile; +import java.util.Collection; + +/** + * HSQL 下的权限检测 + *

+ * created by Harrison on 2022/05/24 + **/ +public class FineDbPermissionConverter implements ThrowableConverter { + + public static final String EMBED_DB_NAME = "finedb"; + + @Override + public boolean accept(Throwable throwable) { + + Throwable sign = throwable; + while (sign != null) { + if (sign.getClass() == HsqlException.class) { + return true; + } + sign = sign.getCause(); + } + return false; + } + + @Override + public DetectorResult convert(Throwable throwable) { + + // 远程不执行 + if (!WorkContext.getCurrent().isLocal()) { + return null; + } + + Throwable sign = throwable; + while (sign != null && sign.getClass() != HsqlException.class) { + sign = sign.getCause(); + } + + if (sign == null) { + return null; + } + + String fineDbDirectory = WorkContext.getCurrent().getPath() + File.separator + ProjectConstants.EMBED_DB_DIRECTORY + File.separator + EMBED_DB_NAME; + Collection files = FileUtils.listFiles(new File(fineDbDirectory), null, true); + Boolean isPermitted = files.stream() + .map((file -> { + try { + // 进行权限判断 + new RandomAccessFile(file, "rw"); + return true; + } catch (FileNotFoundException e) { + return false; + } + })) + .reduce((a, b) -> a & b) + .orElse(Boolean.FALSE); + + if (!isPermitted) { + DetectorType type = DetectorType.FINE_DB_PERMISSION; + return DetectorResult.builder() + .withType(type) + .withTips(Toolkit.i18nText(type.getTipsLocale())) + .withSolution(Toolkit.i18nText(type.getSolutionLocale(), DetectorConstants.FINE_DB_HELP_LINK), + DetectorConstants.FINE_DB_HELP_LINK) + .withLog(type.getLogLocale()) + .build(); + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java new file mode 100644 index 0000000000..6843cb2a80 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java @@ -0,0 +1,28 @@ +package com.fr.env.detect.thowable; + +import com.fr.env.detect.bean.DetectorResult; +import org.jetbrains.annotations.Nullable; + +/** + * created by Harrison on 2022/05/13 + **/ +public interface ThrowableConverter { + + /** + * 是否支持该异常 + * + * @param throwable 异常 + * @return 是/否 + */ + boolean accept(Throwable throwable); + + /** + * 将异常转化为结果 + * + * @param throwable 异常 + * @return 转化结果 + */ + @Nullable + DetectorResult convert(Throwable throwable); + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java new file mode 100644 index 0000000000..3348052f4d --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java @@ -0,0 +1,72 @@ +package com.fr.env.detect.thowable; + +import com.fr.general.FRLogger; +import com.fr.log.LogHandler; +import com.fr.third.apache.logging.log4j.Level; +import com.fr.third.apache.logging.log4j.core.Filter; +import com.fr.third.apache.logging.log4j.core.Layout; +import com.fr.third.apache.logging.log4j.core.LogEvent; +import com.fr.third.apache.logging.log4j.core.appender.AbstractAppender; +import com.fr.third.apache.logging.log4j.core.config.Property; + +import java.io.Serializable; + +/** + * created by Harrison on 2022/05/13 + **/ +public class ThrowableLogAppender extends AbstractAppender { + + public ThrowableLogAppender(String name, Filter filter, Layout layout, boolean ignoreExceptions, Property[] properties) { + super(name, filter, layout, ignoreExceptions, properties); + } + + public static ThrowableLogAppender getInstance() { + return ExceptionLogAppenderHolder.INSTANCE; + } + + private static class ExceptionLogAppenderHolder { + private static final ThrowableLogAppender INSTANCE = new ThrowableLogAppender("exception-detect-appender", null, null, false, null); + } + + private final LogHandler logHandler = toHandler(); + + @Override + public void append(LogEvent logEvent) { + + try { + if (logEvent.getLevel() == Level.ERROR) { + Throwable thrown = logEvent.getThrown(); + if (thrown != null) { + ThrowableStore.getInstance().add(thrown); + } + } + } catch (Throwable ignore) { + } + } + + private LogHandler toHandler() { + + final ThrowableLogAppender appender = this; + appender.start(); + LogHandler handler = new LogHandler() { + @Override + public ThrowableLogAppender getHandler() { + return appender; + } + }; + return handler; + } + + + public void enable() { + + // 初始化一下,别出问题 + logHandler.getHandler().start(); + FRLogger.getLogger().addExtendLogAppender(logHandler); + } + + public void disable() { + + FRLogger.getLogger().removeExtendLogAppender(logHandler); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java new file mode 100644 index 0000000000..346e218991 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java @@ -0,0 +1,36 @@ +package com.fr.env.detect.thowable; + +import java.util.ArrayList; +import java.util.List; + +/** + * 异常存储中心 + * + * created by Harrison on 2022/05/13 + **/ +public class ThrowableStore { + + public static ThrowableStore getInstance() { + return ThrowableStoreHolder.INSTANCE; + } + + private static class ThrowableStoreHolder { + private static final ThrowableStore INSTANCE = new ThrowableStore(); + } + + private List exceptions = new ArrayList<>(); + + public void add(Throwable throwable) { + if (throwable != null) { + exceptions.add(throwable); + } + } + + public List getAll() { + return exceptions; + } + + public void reset() { + exceptions.clear(); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java new file mode 100644 index 0000000000..e636524c87 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java @@ -0,0 +1,159 @@ +package com.fr.env.detect.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.RestartHelper; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.utils.ColorUtils; +import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.env.detect.bean.Message; +import com.fr.exit.DesignerExiter; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * 未知错误框 + * todo 其实这里可以将多个 error-dialog 抽象在一起的。 时间不够, 简单写写 + * 见 {@link com.fr.design.dialog.ErrorDialog} + * + * created by Harrison on 2022/05/29 + **/ +public class DetectorErrorDialog extends JDialog implements ActionListener { + + public static final float FONT_BOLD_HEIGHT = 16f; + private UIButton okButton; + private UIButton restartButton; + + public DetectorErrorDialog(Frame parent, List results) { + + super(parent, true); + + // 可能是还没初始化 UI 的时候出现的问题,初始化一下 UI + DesignUtils.initLookAndFeel(); + + JPanel northPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + JPanel headerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + headerPane.setLayout(new BorderLayout(15, 0)); + + UILabel iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_warning_window.svg")); + headerPane.add(iconLabel, BorderLayout.WEST); + + JPanel messagePane = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); + { + UILabel boldHeader = new UILabel(Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message")); + Font font = boldHeader.getFont(); + Font boldFont = font.deriveFont(FONT_BOLD_HEIGHT); + boldHeader.setFont(boldFont); + messagePane.add(boldHeader); + + UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Send_Report_To_Us")); + messagePane.add(description); + } + headerPane.add(messagePane, BorderLayout.CENTER); + + northPane.add(headerPane); + + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + centerPane.setLayout(new BorderLayout(0, 5)); + + UILabel detailDesc = new UILabel(Toolkit.i18nText("Fine-Design_Problem_Detail_Message")); + centerPane.add(detailDesc, BorderLayout.NORTH); + + JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 10, 10)); + detailPanel.setLayout(new BorderLayout(0, 8)); + + for (DetectorResult result : results) { + JPanel detailItemPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + detailItemPanel.setLayout(new BorderLayout(0, 8)); + ExceptionTips tips = result.getTips(); + + UILabel template = new UILabel(); + template.setBackground(Color.white); + + if (tips != null) { + Message tipsMsg = tips.getMessage(); + detailItemPanel.add(DetectorUtil.convert2TextComponent(tipsMsg, template), BorderLayout.NORTH); + } + ExceptionSolution solution = result.getSolution(); + if (solution != null) { + Message solutionMsg = solution.getMessage(); + detailItemPanel.add(DetectorUtil.convert2TextComponent(solutionMsg, template), BorderLayout.CENTER); + } + detailPanel.add(detailItemPanel, BorderLayout.CENTER); + } + + JScrollPane detailPanelWrapper = new JScrollPane(detailPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + ColorUtils.syncBackground(detailPanelWrapper, Color.WHITE); + centerPane.add(detailPanelWrapper, BorderLayout.CENTER); + + JPanel southPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + JPanel controlPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); + okButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Ok")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + okEvent(); + } + }); + buttonPane.add(okButton); + restartButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Restart")); + restartButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + restartEvent(); + } + }); + buttonPane.add(restartButton); + controlPane.add(buttonPane, BorderLayout.EAST); + southPane.add(controlPane); + + this.setTitle(Toolkit.i18nText("Fine-Design_Error_Start_Report")); + this.setResizable(false); + this.add(northPane, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + this.add(southPane, BorderLayout.SOUTH); + this.setSize(new Dimension(650, 500)); + GUICoreUtils.centerWindow(this); + + } + + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + + protected void okEvent() { + + dispose(); + DesignerExiter.getInstance().execute(); + } + + protected void restartEvent() { + + dispose(); + RestartHelper.restart(); + } + +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java new file mode 100644 index 0000000000..42ab6306ac --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java @@ -0,0 +1,28 @@ +package com.fr.env.detect.ui; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; + +import java.awt.event.ActionEvent; + +/** + * 工具栏里面的行为 + * + * created by Harrison on 2022/05/29 + **/ +public class EnvDetectorAction extends UpdateAction { + + public EnvDetectorAction() { + + this.setName(Toolkit.i18nText("Fine-Design_Basic_Carton_Toolbox_Title")); + this.setSmallIcon("com/fr/env/detect/detect_normal.svg"); + } + + @Override + public void actionPerformed(ActionEvent e) { + + EnvDetectorDialog dialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame()); + dialog.setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java new file mode 100644 index 0000000000..48dfecd7b3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java @@ -0,0 +1,596 @@ +package com.fr.env.detect.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.components.notification.NotificationDialog; +import com.fr.design.components.notification.NotificationDialogProperties; +import com.fr.design.components.notification.NotificationModel; +import com.fr.design.components.table.TablePanel; +import com.fr.design.constants.DesignerColor; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ibutton.UIButtonUI; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.ui.util.UIUtil; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.design.utils.gui.GUIPaintUtils; +import com.fr.env.detect.base.DetectorBridge; +import com.fr.env.detect.base.DetectorUtil; +import com.fr.env.detect.base.EnvDetectorConfig; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorStatus; +import com.fr.env.detect.bean.DetectorType; +import com.fr.log.FineLoggerFactory; +import com.fr.design.carton.FeedbackToolboxDialog; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.SwingWorker; +import javax.swing.plaf.ButtonUI; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Cursor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * created by Harrison on 2022/05/26 + **/ +public class EnvDetectorDialog extends JDialog { + + private static final ImageIcon LOADING_ICON = getLoadingIcon(); + private static final int TIMEOUT = 1000; + + private static final Color SUCCESS_COLOR = new Color(22, 193, 83); + private static final Color DETAIL_FONT_COLOR = new Color(65, 155, 249); + + private final JPanel body; + + private final JPanel headerPanel; + private UIButton detectButton; + private JPanel resultSummaryPane; + + private final TablePanel tablePanel; + + private final JPanel tailPanel; + + /* 数据 model */ + + private EnvDetectorModel model; + + /* 流程 model */ + + /** + * 默认是第一个要检测 + */ + private int currentDetectIndex = 0; + + private EnvDetectorButtonStatus buttonStatus = EnvDetectorButtonStatus.START; + + private SwingWorker detectWorker = null; + + /* config model */ + + private boolean detectOpen = EnvDetectorConfig.getInstance().isEnabled(); + + public EnvDetectorDialog(Frame owner) { + this(owner, null); + } + + public EnvDetectorDialog(Frame owner, EnvDetectorModel model) { + super(owner); + + configProperties(); + + if (model == null) { + this.model = new EnvDetectorModel(); + } else { + this.model = model; + } + + this.body = FRGUIPaneFactory.createBorderLayout_L_Pane(); + Color backgroundColor = new Color(240, 240, 243, 1); + this.body.setBackground( backgroundColor); + + this.headerPanel = createHeaderPanel(); + body.add(headerPanel, BorderLayout.NORTH); + + this.tablePanel = createTablePanel(); + body.add(tablePanel, BorderLayout.CENTER); + + /* tailPanel*/ + this.tailPanel = createTailPanel(); + body.add(tailPanel, BorderLayout.SOUTH); + + add(body); + + + Dimension preferredSize = body.getPreferredSize(); + setSize(preferredSize); + + repaint(); + pack(); + GUICoreUtils.centerWindow(this); + } + + /* header */ + + @NotNull + private JPanel createHeaderPanel() { + + JPanel headerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + headerPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 12, 0)); + this.detectButton = new UIButton(buttonStatus.getDesc()) { + @Override + public ButtonUI getUI() { + + return new UIButtonUI() { + @Override + protected void doExtraPainting(UIButton b, Graphics2D g2d, int w, int h, String selectedRoles) { + if (isPressed(b) && b.isPressedPainted()) { + GUIPaintUtils.fillPressed(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), + DesignerColor.Button.Primary.PRESSED); + } else if (isRollOver(b)) { + GUIPaintUtils.fillRollOver(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(), + DesignerColor.Button.Primary.HOVER); + } else if (b.isNormalPainted()) { + GUIPaintUtils.fillNormal(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(), + DesignerColor.Button.Primary.NORMAL); + } + } + }; + } + }; + detectButton.setForeground(Color.WHITE); + detectButton.addActionListener(event -> { + if (buttonStatus.isNotExecuting()) { + startDetecting(); + } else { + stopDetecting(detectButton); + } + }); + detectButton.setPreferredSize(new Dimension(68, 20)); + detectButton.setBorderPainted(false); + detectButton.setContentAreaFilled(false); + headerPanel.add(detectButton, BorderLayout.WEST); + + UILabel openUtilBoxLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Feedback_ToolBox")); + openUtilBoxLabel.setForeground(UIConstants.FLESH_BLUE); + + openUtilBoxLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + setVisible(false); + FeedbackToolboxDialog myDialog = new FeedbackToolboxDialog(DesignerContext.getDesignerFrame()); + myDialog.setVisible(true); + dispose(); + } + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + headerPanel.add(openUtilBoxLabel, BorderLayout.EAST); + return headerPanel; + } + + private void startDetecting() { + + // 重新检测的时候需要处理一些逻辑 + if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { + reInit(); + } + // 执行前 + buttonStatus = buttonStatus.next(); + UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshHeader); + detectWorker = new SwingWorker() { + + @Override + protected Void doInBackground() { + List items = model.getItems(); + // 执行刷新 + for (int i = currentDetectIndex; i < items.size(); i++) { + + // 看一下是否关闭了, 有可能已经关闭了。 + if (buttonStatus.isNotExecuting()) { + return null; + } + + // 刷新一下面板-开始执行啦 + UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); + + EnvDetectorItem item = items.get(i); + DetectorType type = item.getType(); + + // 执行检测, UI-当前在检测中 + DetectorResult result = UIUtil.waitUntil( + () -> DetectorBridge.getInstance().detect(type), + TIMEOUT, TimeUnit.MILLISECONDS); + // 获取结果 + item.setResult(result); + + // 更新UI + // 只有还在运行中,才会真正的刷新面板 + if (buttonStatus.isExecuting()) { + // 在刷新一下面板 + UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); + currentDetectIndex++; + } + + } + return null; + } + + @Override + protected void done() { + + try { + this.get(); + if (buttonStatus.isExecuting()) { + // 执行结束 + buttonStatus = EnvDetectorButtonStatus.A_NEW; + UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshHeader); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("detect failed", e); + } + } + }; + // 开始执行 + detectWorker.execute(); + } + + private void reInit() { + currentDetectIndex = 0; + for (EnvDetectorItem e : model.getItems()) { + e.setResult(null); + } + // 刷新一下面板-开始执行啦 + UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); + } + + private void stopDetecting(UIButton detectButton) { + + buttonStatus = buttonStatus.next(); + + // 先停止 + detectWorker.cancel(false); + // 更改-UI + // 执行中 + UIUtil.invokeLaterIfNeeded(() -> { + // 刷新按钮 + detectButton.setText(buttonStatus.getDesc()); + // 刷新面板 + refreshBody(); + }); + } + + private void updateHeaderPanel() { + + // 刷新按钮 + detectButton.setText(buttonStatus.getDesc()); + if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { + this.resultSummaryPane = new JPanel(); + this.resultSummaryPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + this.resultSummaryPane.setLayout(new BorderLayout(5, 0)); + Boolean success = model.getResults() + .map((e) -> { + if (e != null && e.getStatus() == DetectorStatus.NORMAL) { + return Boolean.TRUE; + } + return Boolean.FALSE; + }).reduce((a, b) -> a && b) + .orElse(Boolean.FALSE); + + if (success) { + resultSummaryPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Label")), BorderLayout.WEST); + UILabel successLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Success")); + successLabel.setForeground(SUCCESS_COLOR); + resultSummaryPane.add(successLabel, BorderLayout.CENTER); + } else { + resultSummaryPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Label")), BorderLayout.WEST); + UILabel resultLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Error")); + resultLabel.setForeground(Color.RED); + resultSummaryPane.add(resultLabel, BorderLayout.CENTER); + } + this.headerPanel.add(BorderLayout.CENTER, resultSummaryPane); + } else { + if (resultSummaryPane != null) { + this.headerPanel.remove(resultSummaryPane); + } + } + } + + /* table */ + + + @NotNull + private TablePanel createTablePanel() { + + TablePanel tablePanel = new TablePanel(18, 3); + tablePanel.updateHeaders(new String[] { + Toolkit.i18nText("Fine-Design_Basic_Detect_Kind"), + Toolkit.i18nText("Fine-Design_Basic_Detect_Item"), + Toolkit.i18nText("Fine-Design_Basic_Detect_Result")}); + + updateTable(tablePanel); + + return tablePanel; + } + + private void updateTable(TablePanel tablePanel) { + + Map> itemMap = model.getItemMap(); + + // 行号, 这边更新是通过 行/列 。 不是索引 + int row = 1; + for (Map.Entry> entry : itemMap.entrySet()) { + + DetectorType.Kind kind = entry.getKey(); + List items = entry.getValue(); + for (int i = 0; i < items.size(); i++) { + if (i == 0) { + tablePanel.updateCell(row, 1, kind.getDescription()); + } + EnvDetectorItem item = items.get(i); + tablePanel.updateCell(row, 2, new UILabel(item.getDescription())); + DetectorResult result = item.getResult(); + + int detectRow = currentDetectIndex + 1; + + if (result == null) { + // 处于非正在检测状态 或者 索引不等于当前行号的时候 + UILabel label; + if (buttonStatus.isExecuting() && detectRow == row) { + // 正在检测索引 + label = new UILabel(LOADING_ICON, UILabel.LEADING); + } else { + label = new UILabel("-"); + } + tablePanel.updateCell(row, 3, label); + } else { + Component resultComponent = createResultComponent(result); + tablePanel.updateCell(row, 3, resultComponent); + } + row++; + } + } + } + + private Component createResultComponent(DetectorResult result) { + + JPanel statusPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + if (result.getStatus() == DetectorStatus.NORMAL) { + statusPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_success.svg")), BorderLayout.WEST); + statusPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Normal")), BorderLayout.CENTER); + } else { + JPanel infoPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + { + infoPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_error.svg")), BorderLayout.WEST); + infoPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Exception")), BorderLayout.CENTER); + } + statusPanel.add(infoPanel, BorderLayout.WEST); + + // 如果结果是检测出的异常,则出现详细信息。 + if (result.getStatus() == DetectorStatus.EXCEPTION) { + JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + { + detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + UILabel detailLabel = new UILabel(Toolkit.i18nText("Fine_Designer_Look_Detail")); + detailLabel.setForeground(DETAIL_FONT_COLOR); + detailLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent mouseEvent) { + NotificationDialogProperties properties = new NotificationDialogProperties((Frame) EnvDetectorDialog.this.getOwner(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title")); + Stream results = model.getResults(); + List notificationModels = results + .filter(Objects::nonNull) + .filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION) + .map(DetectorUtil::convert2Notification) + .collect(Collectors.toList()); + + NotificationDialog dialog = new NotificationDialog(properties, notificationModels); + dialog.open(); + } + }); + detailPanel.add(detailLabel, BorderLayout.CENTER); + } + statusPanel.add(detailPanel, BorderLayout.CENTER); + } + + } + return statusPanel; + } + + /* tail */ + + @NotNull + private JPanel createTailPanel() { + + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tailPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0)); + + JPanel configPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + { + UICheckBox checkBox = new UICheckBox(); + checkBox.setSelected(this.detectOpen); + checkBox.addChangeListener(e -> { + UICheckBox source = (UICheckBox) e.getSource(); + EnvDetectorDialog.this.detectOpen = source.isSelected(); + }); + configPanel.add(checkBox, BorderLayout.WEST); + UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Switch")); + configPanel.add(description, BorderLayout.EAST); + } + tailPanel.add(configPanel, BorderLayout.WEST); + + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + { + UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm")); + confirmButton.addActionListener((e) -> { + setVisible(false); + dispose(); + // 配置处理 + EnvDetectorConfig.getInstance().setEnabled(this.detectOpen); + }); + actionsPanel.add(confirmButton, BorderLayout.WEST); + + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.addActionListener((e) -> { + setVisible(false); + dispose(); + }); + actionsPanel.add(cancelButton, BorderLayout.EAST); + } + tailPanel.add(actionsPanel, BorderLayout.EAST); + return tailPanel; + } + + private void refreshHeader() { + + updateHeaderPanel(); + pack(); + repaint(); + } + + private void refreshBody() { + + updateTable(this.tablePanel); + pack(); + repaint(); + } + + private static ImageIcon getLoadingIcon() { + + URL resource = EnvDetectorDialog.class.getResource("/com/fr/design/standard/loading/loading-120.gif"); + if (resource == null) { + return null; + } + ImageIcon loadingIcon = new ImageIcon(resource); + int width = 16; + int height = 16; + loadingIcon.setImage(loadingIcon.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT)); + return loadingIcon; + } + + private void configProperties() { + + setTitle(Toolkit.i18nText("Fine-Design_Basic_Detect_Title")); + setModal(false); + setFocusable(false); + setAutoRequestFocus(false); + setResizable(false); + } + + /** + * 按钮的当前状态 + */ + private enum EnvDetectorButtonStatus { + + /** + * 开始 -> 停止 + */ + START("Fine-Design_Basic_Detect_Start") { + @Override + public EnvDetectorButtonStatus next() { + return STOP; + } + }, + + /** + * 停止 -> 继续 + */ + STOP("Fine-Design_Basic_Detect_Stop") { + @Override + public EnvDetectorButtonStatus next() { + return CONTINUE; + } + }, + + /** + * 继续 -> 停止 + */ + CONTINUE("Fine-Design_Basic_Detect_Continue") { + @Override + public EnvDetectorButtonStatus next() { + return STOP; + } + }, + + /** + * 重新 -> 停止 + */ + A_NEW("Fine-Design_Basic_Detect_A_New") { + @Override + public EnvDetectorButtonStatus next() { + return STOP; + } + } + + ; + + private String descLocale; + + EnvDetectorButtonStatus(String descLocale) { + + this.descLocale = descLocale; + } + + public String getDesc() { + + return Toolkit.i18nText(descLocale); + } + + /** + * 在执行中 + * + * @return 是/否 + */ + public boolean isExecuting() { + + return this == EnvDetectorButtonStatus.STOP; + }; + + /** + * 不在执行中 + * + * @return 是/否 + */ + public boolean isNotExecuting() { + + return !isExecuting(); + } + + public abstract EnvDetectorButtonStatus next(); + } + + private class EnvDetectorHeaderPanel extends JPanel { + + + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java new file mode 100644 index 0000000000..0f9075313d --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java @@ -0,0 +1,40 @@ +package com.fr.env.detect.ui; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; + +/** + * 环境检测条目 + * + * created by Harrison on 2022/05/27 + **/ +public class EnvDetectorItem { + + private DetectorType type; + + private DetectorResult result; + + public EnvDetectorItem(DetectorType detectorType) { + this.type = detectorType; + } + + public DetectorType getType() { + return type; + } + + public String getKind() { + return this.type.getKind().getDescription(); + } + + public String getDescription() { + return this.type.getDescription(); + } + + public DetectorResult getResult() { + return result; + } + + public void setResult(DetectorResult result) { + this.result = result; + } +} diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java new file mode 100644 index 0000000000..457734d0bd --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java @@ -0,0 +1,70 @@ +package com.fr.env.detect.ui; + +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.third.guava.collect.Lists; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 环境检测数据格式 + * + * created by Harrison on 2022/05/27 + **/ +public class EnvDetectorModel { + + /** + * 类型 -> list [{type-result}] + */ + private final Map> itemMap = new LinkedHashMap<>(); + + public EnvDetectorModel() { + + itemMap.put(DetectorType.Kind.JAR, Lists.newArrayList( + new EnvDetectorItem(DetectorType.LACK_OF_JAR), + new EnvDetectorItem(DetectorType.JAR_IN_CONSISTENCE), + new EnvDetectorItem(DetectorType.JAR_CONFLICT))); + + itemMap.put(DetectorType.Kind.FINE_DB, Lists.newArrayList( + new EnvDetectorItem(DetectorType.FINE_DB_LOCKED), + new EnvDetectorItem(DetectorType.FINE_DB_PERMISSION), + new EnvDetectorItem(DetectorType.FINE_DB_DIRTY))); + } + + public void update(DetectorType type, DetectorResult result) { + + List items = itemMap.get(type.getKind()); + items.stream() + .filter((e) -> e.getType() == type) + .findFirst() + .ifPresent((e) -> { + e.setResult(result); + }); + } + + public Stream getResults() { + + return getItems().stream() + .map(EnvDetectorItem::getResult); + } + + public List getItems() { + + return itemMap.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + public Map> getItemMap() { + + return this.itemMap; + } + +} + + diff --git a/designer-base/src/main/java/com/fr/env/utils/WorkspaceUtils.java b/designer-base/src/main/java/com/fr/env/utils/WorkspaceUtils.java new file mode 100644 index 0000000000..3979b4eee8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/env/utils/WorkspaceUtils.java @@ -0,0 +1,27 @@ +package com.fr.env.utils; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.LocalDesignerWorkspaceInfo; +import com.fr.stable.StringUtils; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2022/3/10 + */ +public class WorkspaceUtils { + + private static final String SPECIFY_WORKSPACE = "fr.designer.workspace"; + + public static DesignerWorkspaceInfo getWorkspaceInfo() { + String workspacePath; + String current = DesignerEnvManager.getEnvManager().getCurEnvName(); + if (StringUtils.isNotEmpty(workspacePath = System.getProperty(SPECIFY_WORKSPACE))) { + return LocalDesignerWorkspaceInfo.create(StringUtils.EMPTY, workspacePath); + } else { + return DesignerEnvManager.getEnvManager().getWorkspaceInfo(current); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java b/designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java new file mode 100644 index 0000000000..ea3e72c3f5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java @@ -0,0 +1,120 @@ +package com.fr.exit; + +import com.fr.config.dao.PropertiesConstants; +import com.fr.design.DesignerEnvManager; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.CommonUtils; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.sql.Blob; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +/** + * 设计器关闭前的配置缓存一份到Properties + * + * @author hades + * @version 11.0 + * Created by hades on 2022/3/1 + */ +public class ConfigToPropMigrator { + + private static final String SELECT_FOR_ENTITY = "select id, value from fine_conf_entity"; + + private static final String SELECT_FOR_CLASSNAME = "select id, classname from fine_conf_classname"; + + private static final String SELECT_FOR_XML_ENTITY = "select id, value from fine_conf_xmlentity"; + + private static final ConfigToPropMigrator INSTANCE = new ConfigToPropMigrator(); + + public static ConfigToPropMigrator getInstance() { + return INSTANCE; + } + + public void execute() { + try { + _execute(); + } catch (Throwable throwable) { + FineLoggerFactory.getLogger().warn(throwable.getMessage(), throwable); + } + } + + private void _execute() { + if (WorkContext.getCurrent().isLocal()) { + + String url = "jdbc:hsqldb:file://" + WorkContext.getCurrent().getPath() + "/" + ProjectConstants.EMBED_DB_DIRECTORY + "/finedb/db;hsqldb.tx=mvcc"; + + try { + Class.forName("com.fr.third.org.hsqldb.jdbcDriver"); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return ; + } + + initDirectory(); + + try (Connection c = DriverManager.getConnection(url); + OutputStreamWriter xmlEntityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH), StandardCharsets.UTF_8); + OutputStreamWriter entityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH), StandardCharsets.UTF_8); + OutputStreamWriter classHelperOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.CLASS_NAME_PROP_PATH), StandardCharsets.UTF_8)) { + + processClassOrEntity(c, new Properties(), SELECT_FOR_ENTITY, entityOut); + processClassOrEntity(c, new Properties(), SELECT_FOR_CLASSNAME, classHelperOut); + processXmlEntity(c, new Properties(), xmlEntityOut); + DesignerEnvManager.getEnvManager().setPropertiesUsable(true); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + deletePropertiesCache(); + } + } + } + + private void initDirectory() { + File directory = new File(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.PROPERTIES_CACHE_FOR_CONFIG)); + if (!directory.exists()) { + directory.mkdir(); + } + } + + private void processClassOrEntity(Connection c, Properties map, String sql, OutputStreamWriter writer) throws SQLException, IOException { + PreparedStatement query = c.prepareStatement(sql); + ResultSet resultSet = query.executeQuery(); + while (resultSet.next()) { + String id = resultSet.getString(1); + String value = resultSet.getString(2); + if (id != null && value != null) { + map.setProperty(id, value); + } + } + map.store(writer, null); + } + + private void processXmlEntity(Connection c, Properties map, OutputStreamWriter writer) throws SQLException, IOException { + PreparedStatement query = c.prepareStatement(SELECT_FOR_XML_ENTITY); + ResultSet resultSet = query.executeQuery(); + while (resultSet.next()) { + String id = resultSet.getString(1); + Blob value = resultSet.getBlob(2); + byte[] bytes = value.getBytes(1L, (int) value.length()); + map.setProperty(id, new String(bytes, StandardCharsets.UTF_8)); + } + map.store(writer, null); + } + + public void deletePropertiesCache() { + CommonUtils.deleteFile(new File(PropertiesConstants.ENTITY_PROP_PATH)); + CommonUtils.deleteFile(new File(PropertiesConstants.XML_ENTITY_PROP_PATH)); + CommonUtils.deleteFile(new File(PropertiesConstants.CLASS_NAME_PROP_PATH)); + } + +} diff --git a/designer-base/src/main/java/com/fr/exit/DesignerExiter.java b/designer-base/src/main/java/com/fr/exit/DesignerExiter.java index cda2e015b0..babadc5fe8 100644 --- a/designer-base/src/main/java/com/fr/exit/DesignerExiter.java +++ b/designer-base/src/main/java/com/fr/exit/DesignerExiter.java @@ -1,10 +1,26 @@ package com.fr.exit; +import com.fr.common.util.Collections; +import com.fr.design.RestartHelper; +import com.fr.design.dialog.ErrorDialog; import com.fr.design.env.DesignerWorkspaceGenerator; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector; +import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage; import com.fr.design.monitor.DesignerLifecycleMonitorContext; +import com.fr.env.detect.EnvDetectorCenter; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.ui.DetectorErrorDialog; +import com.fr.log.FineLoggerFactory; import com.fr.process.engine.core.FineProcessContext; import com.fr.process.engine.core.FineProcessEngineEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + /** * @author hades * @version 10.0 @@ -17,7 +33,79 @@ public class DesignerExiter { public static DesignerExiter getInstance() { return INSTANCE; } - + + /** + * 预期外的退出 + * 首先检测是否有检测到的异常。如果没有,则运行默认行为 + * + * @param defaultAction 默认行为 + */ + public void exitUnexpectedly(Runnable defaultAction) { + + // 尝试进行检测 + List results = runAndGet(() -> EnvDetectorCenter.getInstance().terminateUnexpectedly(), ArrayList::new); + try { + if (!Collections.isEmpty(results)) { + showNewExitDialog(results); + } + } finally { + // 正常的话上面会直接退出, system.exit(0) + // 只有异常,或者不命中,才会走到这里 + defaultAction.run(); + } + } + + public void exit(Throwable throwable) { + + doThrowableAction(() -> { + FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable); + }, () -> { + throwable.printStackTrace(System.err); + }); + + doThrowableAction(() -> { + StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(), + DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(), + throwable.getMessage()); + }); + + // 尝试进行检测 + List results = runAndGet(() -> EnvDetectorCenter.getInstance().terminate(throwable), ArrayList::new); + + if (Collections.isEmpty(results)) { + // 为空,则 + showOldExitDialog(throwable); + } else { + showNewExitDialog(results); + } + } + + private void showNewExitDialog(List results) { + DesignerFrame designerFrame = DesignerContext.getDesignerFrame(); + DetectorErrorDialog errorDialog = new DetectorErrorDialog(designerFrame, results); + errorDialog.setVisible(true); + } + + private void showOldExitDialog(Throwable throwable) { + + ErrorDialog dialog = new ErrorDialog(null, Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"), + Toolkit.i18nText("Fine-Design_Error_Start_Report"), + throwable.getMessage()) { + @Override + protected void okEvent() { + dispose(); + DesignerExiter.getInstance().execute(); + } + + @Override + protected void restartEvent() { + dispose(); + RestartHelper.restart(); + } + }; + dialog.setVisible(true); + } + public void execute() { DesignerLifecycleMonitorContext.getMonitor().beforeStop(); beforeExit(); @@ -30,4 +118,31 @@ public class DesignerExiter { private void beforeExit() { DesignerWorkspaceGenerator.stop(); } + + /* 忽视异常的调用方法 */ + + private void doThrowableAction(Runnable runnable) { + doThrowableAction(runnable, null); + } + + private void doThrowableAction(Runnable runnable, Runnable defaultRunnable) { + + try { + runnable.run(); + } catch (Throwable ignore) { + if (defaultRunnable != null) { + defaultRunnable.run(); + } + } + } + + private T runAndGet(Supplier supplier, Supplier defaultCallable) { + + try { + return supplier.get(); + } catch (Exception ignore) { + return defaultCallable.get(); + } + } + } diff --git a/designer-base/src/main/java/com/fr/file/FILEChooserPane.java b/designer-base/src/main/java/com/fr/file/FILEChooserPane.java index c21c82c75a..0561319db4 100644 --- a/designer-base/src/main/java/com/fr/file/FILEChooserPane.java +++ b/designer-base/src/main/java/com/fr/file/FILEChooserPane.java @@ -27,6 +27,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.JTemplate; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.event.Event; @@ -47,9 +48,9 @@ import com.fr.stable.StringUtils; import com.fr.stable.os.windows.WindowsDetector; import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; - import com.fr.workspace.Workspace; import com.fr.workspace.WorkspaceEvent; + import javax.swing.AbstractAction; import javax.swing.AbstractListModel; import javax.swing.ActionMap; @@ -104,6 +105,9 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static javax.swing.JOptionPane.DEFAULT_OPTION; +import static javax.swing.JOptionPane.WARNING_MESSAGE; + /* * FileChooserPane要高亮显示某Button,以显示当前路径 * 边距要调整 @@ -202,6 +206,17 @@ public class FILEChooserPane extends BasicPane { return INSTANCE; } + public static FILEChooserPane getInstanceWithDesignatePath(String path, FILEFilter filter, String topPath) { + INSTANCE.showLoc = false; + INSTANCE.showEnv = false; + INSTANCE.showWebReport = false; + INSTANCE.setTopPath(topPath); + INSTANCE.setDesignateModel(path); + INSTANCE.removeAllFilter(); + INSTANCE.addChooseFILEFilter(filter, 0); + return INSTANCE; + } + public static FILEChooserPane getMultiEnvInstance(boolean showLoc, boolean showWebReport) { INSTANCE.showEnv = true; INSTANCE.showLoc = showLoc; @@ -499,7 +514,7 @@ public class FILEChooserPane extends BasicPane { } private String calProperFileName(String fileName, ChooseFileFilter fileFilter) { - if(fileFilter == null){ + if (fileFilter == null) { return fileName; } String filterExtension = fileFilter.getExtensionString(); @@ -516,10 +531,10 @@ public class FILEChooserPane extends BasicPane { return fileNameWithOutExtension + filterExtension; } - private boolean isMapping(String fromExtension, String toExtension){ - if(FileExtension.CPTX.matchExtension(fromExtension)){ + private boolean isMapping(String fromExtension, String toExtension) { + if (FileExtension.CPTX.matchExtension(fromExtension)) { return FileExtension.CPT.matchExtension(toExtension); - }else if(FileExtension.CPT.matchExtension(fromExtension)){ + } else if (FileExtension.CPT.matchExtension(fromExtension)) { return FileExtension.CPTX.matchExtension(toExtension); } return false; @@ -623,6 +638,9 @@ public class FILEChooserPane extends BasicPane { this.filterList.clear(); } + public void removeTopPath() { + this.setTopPath(StringUtils.EMPTY); + } /** * 设置filter,刷新右侧subFileList中的items @@ -664,11 +682,21 @@ public class FILEChooserPane extends BasicPane { fileNameTextField.setFilter(new DefaultCompletionFilter(names)); } + public void disableFileNameTextFiled() { + fileNameTextField.setEditable(false); + fileNameTextField.setEnabled(false); + } + + public void enableFileNameTextFiled() { + fileNameTextField.setEditable(true); + fileNameTextField.setEnabled(true); + } + /** * 移除文件后缀的方法 * 解决cptx文件的另存为操作默认会出现双后缀的bug(xxx.cptx.cpt) **/ - private String removeSuffix(String text){ + private String removeSuffix(String text) { return FileExtension.CPTX.matchExtension(text) ? text.substring(0, text.length() - FileExtension.CPTX.getSuffix().length()) : text; } @@ -773,7 +801,7 @@ public class FILEChooserPane extends BasicPane { ChooseFileFilter supportedTypes = new ChooseFileFilter(FRContext.getFileNodes().getSupportedTypes(), appName + Toolkit.i18nText("Fine-Design_Report_Template_File")); Set providers = ExtraReportClassManager.getInstance().getArray(ReportSupportedFileProvider.XML_TAG); for (ReportSupportedFileProvider provider : providers) { - for (FileExtension fileExtension : provider.getFileExtensions()){ + for (FileExtension fileExtension : provider.getFileExtensions()) { supportedTypes.addExtension(fileExtension.getExtension()); } } @@ -863,7 +891,7 @@ public class FILEChooserPane extends BasicPane { private void doOK() { // 如果没有写文件名,不允许打开 or save - if (fileNameTextField.getText().length() == 0) { + if (fileNameTextField.getText().length() == 0 || !validInput()) { return; } if (type == JFileChooser.OPEN_DIALOG) { @@ -874,7 +902,7 @@ public class FILEChooserPane extends BasicPane { saveDictionary(); dialogExit(); } else { - FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Basic_App_Template_Report_Not_Exist")); + FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Basic_App_File_Not_Exist")); return; } } @@ -894,6 +922,19 @@ public class FILEChooserPane extends BasicPane { } } + private boolean validInput() { + String name = fileNameTextField.getText().trim(); + if (!Pattern.compile(DesignerFrameFileDealerPane.FILE_NAME_LIMIT).matcher(name).matches()) { + FineJOptionPane.showConfirmDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal"), + Toolkit.i18nText("Fine-Design_Basic_Error"), + DEFAULT_OPTION, + WARNING_MESSAGE); + return false; + } + return true; + } + private void saveDialog() { String filename = fileNameTextField.getText(); @@ -905,7 +946,7 @@ public class FILEChooserPane extends BasicPane { if (access(selectedFile) && access(currentDirectory)) { if (selectedFile.exists()) { int selVal = FineJOptionPane.showConfirmDialog(dialog, Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Cover_The_Current_File") + " ?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (selVal == JOptionPane.YES_OPTION) { option = JOPTIONPANE_OK_OPTION; saveDictionary(); @@ -1021,6 +1062,19 @@ public class FILEChooserPane extends BasicPane { setPlaceListModel(new PlaceListModel()); } + private void setDesignateModel(String path) { + if (placesList == null) { + return; + } + + setPlaceListModel(new DesignateRemotePlaceListModel(path)); + } + + private void setTopPath(String path) { + this.locationBtnPane.setTopPath(path); + } + + private void setMultiPlaceListModel() { if (placesList == null) { return; @@ -1115,6 +1169,7 @@ public class FILEChooserPane extends BasicPane { private abstract class AbstractPlaceListModel extends AbstractListModel { + private static final long serialVersionUID = 8473695327688235386L; protected List filesOfSystem = new ArrayList(); protected void processSystemFile() { @@ -1147,7 +1202,8 @@ public class FILEChooserPane extends BasicPane { protected void setCD(final FILE lastDirectory) { for (int i = 0; i < this.getSize(); i++) { FILE file = this.getElementAt(i); - if (ComparatorUtils.equals(lastDirectory.prefix(), file.prefix())) { + //前缀相同不代表能用啊,比如说 repolets 和 resource ,都是 env下的,但就不该去显示resource下的文件呀 + if (ComparatorUtils.equals(lastDirectory.prefix(), file.prefix()) && lastDirectory.getPath() != null && lastDirectory.getPath().startsWith(file.getPath())) { setCurrentDirectory(lastDirectory); return; } @@ -1156,7 +1212,60 @@ public class FILEChooserPane extends BasicPane { } } + /** + * 一个简单的指定远程目录的 placelistmodel + */ + private class DesignateRemotePlaceListModel extends AbstractPlaceListModel { + private static final long serialVersionUID = -6340666958714469249L; + + private FileNodeFILE envFILE; + + public DesignateRemotePlaceListModel(String path) { + envFILE = new DesignateFileNodeFILE(new FileNode(path, true)) { + @Override + public String getName() { + return Toolkit.i18nText("Fine-Design_Basic_Utils_Report_Env_Directory_Designate"); + } + }; + } + + @Override + public FILE getElementAt(int index) { + if (index < 1) { + return envFILE; + } + throw new IndexOutOfBoundsException(); + } + + @Override + public int getSize() { + return 1; + } + + @Override + protected void setCD(FILE lastDirectory) { + setCurrentDirectory(envFILE); + } + + /** + * 简单的重写了标签的FileNodeFILE + */ + private class DesignateFileNodeFILE extends FileNodeFILE { + + public DesignateFileNodeFILE(FileNode node) { + super(node); + } + + @Override + public Icon getIcon() { + return BaseUtils.readIcon("/com/fr/base/images/oem/logo.png"); + } + } + } + + private class PlaceListModel extends AbstractPlaceListModel { + private static final long serialVersionUID = 6138969918807381364L; private FileNodeFILE envFILE; private FileNodeFILE webReportFILE; @@ -1207,6 +1316,7 @@ public class FILEChooserPane extends BasicPane { private class MultiLocalEnvPlaceListModel extends AbstractPlaceListModel { + private static final long serialVersionUID = 6300018896958532154L; private List envFiles = new ArrayList(); private FileNodeFILE webReportFILE; @@ -1301,6 +1411,8 @@ public class FILEChooserPane extends BasicPane { private List buttonList = new ArrayList<>(); private int pathIndex = 0; private int maxPathIndex = 0; + // 对顶层目录进行的限制 + private String topPath; public LocationButtonPane() { this.setLayout(FRGUIPaneFactory.createBoxFlowLayout()); @@ -1346,6 +1458,10 @@ public class FILEChooserPane extends BasicPane { }); } + public void setTopPath(String path) { + this.topPath = path; + } + public void highLightButton(FILE dir) { for (int i = 0; i < this.buttonList.size(); i++) { this.buttonList.get(i).setForeground(null); @@ -1387,6 +1503,7 @@ public class FILEChooserPane extends BasicPane { } Matcher matcher = SEPARATOR_PATTERN.matcher(path); int node_start = 0; + boolean needTopPath = !StringUtils.isEmpty(topPath); while (matcher.find()) { int start = matcher.start(); String btn_text = path.substring(node_start, start); @@ -1394,11 +1511,14 @@ public class FILEChooserPane extends BasicPane { if (StringUtils.isBlank(btn_text) && isWebAppNamePath) { btn_text = webAppName; } + node_start = matcher.end(); + if (needTopPath && topPath.equals(btn_text)) { + needTopPath = false; + } this.buttonList.add(createBlankButton((new SetDirectoryAction(btn_text + '/', // alex:dir.prefix不和btn_path一起参与pathJoin,因为btn_path是否以/打头在unix,linux // OS中意义很不一样 - FILEFactory.createFolder(dir.prefix() + StableUtils.pathJoin(btn_path, "/")))))); - node_start = matcher.end(); + FILEFactory.createFolder(dir.prefix() + StableUtils.pathJoin(btn_path, "/")), !needTopPath)))); } maxPathIndex = calculateMaxPathIndex(); @@ -1499,6 +1619,7 @@ public class FILEChooserPane extends BasicPane { private class SetDirectoryAction extends UpdateAction { private FILE dir; + private boolean response = true; public SetDirectoryAction(String name) { this.setName(name); @@ -1510,9 +1631,15 @@ public class FILEChooserPane extends BasicPane { this.dir = file; } + public SetDirectoryAction(String name, FILE file, boolean response) { + this.setName(name); + this.dir = file; + this.response = response; + } + @Override public void actionPerformed(ActionEvent evt) { - if (dir != null) { + if (dir != null && response) { setSelectedDirectory(dir); } } diff --git a/designer-base/src/main/java/com/fr/file/FILEFactory.java b/designer-base/src/main/java/com/fr/file/FILEFactory.java index 3d48bab341..d558483784 100644 --- a/designer-base/src/main/java/com/fr/file/FILEFactory.java +++ b/designer-base/src/main/java/com/fr/file/FILEFactory.java @@ -1,6 +1,5 @@ package com.fr.file; -import com.fr.base.FRContext; import com.fr.design.file.NodeAuthProcessor; import com.fr.file.filetree.FileNode; import com.fr.workspace.WorkContext; @@ -10,6 +9,7 @@ public class FILEFactory { public static final String FILE_PREFIX = "file://"; public static final String ENV_PREFIX = "env://"; public static final String WEBREPORT_PREFIX = "webreport://"; + public static final String SEPARATOR = "/"; private FILEFactory() { } diff --git a/designer-base/src/main/java/com/fr/file/FileNodeFILE.java b/designer-base/src/main/java/com/fr/file/FileNodeFILE.java index bcf1ff7686..d0fd628969 100644 --- a/designer-base/src/main/java/com/fr/file/FileNodeFILE.java +++ b/designer-base/src/main/java/com/fr/file/FileNodeFILE.java @@ -2,6 +2,7 @@ package com.fr.file; import com.fr.base.BaseUtils; import com.fr.base.FRContext; +import com.fr.base.svg.IconUtils; import com.fr.design.file.TemplateResourceManager; import com.fr.io.FineEncryptUtils; import com.fr.base.io.XMLEncryptUtils; @@ -168,7 +169,7 @@ public class FileNodeFILE implements FILE { } if (ComparatorUtils.equals(node.getEnvPath(), ProjectConstants.REPORTLETS_NAME)) { - return BaseUtils.readIcon("/com/fr/base/images/oem/logo.png"); + return IconUtils.readIcon("/com/fr/base/images/oem/logo.svg"); } else { if (!hasFullAuth) { diff --git a/designer-base/src/main/java/com/fr/file/StashedFILE.java b/designer-base/src/main/java/com/fr/file/StashedFILE.java index 454433874e..a73dd612d0 100644 --- a/designer-base/src/main/java/com/fr/file/StashedFILE.java +++ b/designer-base/src/main/java/com/fr/file/StashedFILE.java @@ -1,5 +1,9 @@ package com.fr.file; +import com.fr.base.io.XMLEncryptUtils; +import com.fr.io.EncryptUtils; +import com.fr.io.FineEncryptUtils; +import com.fr.stable.StringUtils; import javax.swing.Icon; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -11,10 +15,16 @@ public class StashedFILE extends AbstractFILE { private FILE file; private byte[] content; + private String suffix; public StashedFILE(FILE file, byte[] content) { + this(file, content, null); + } + + public StashedFILE(FILE file, byte[] content, String suffix) { this.file = file; this.content = content; + this.suffix = suffix; } @Override @@ -54,7 +64,12 @@ public class StashedFILE extends AbstractFILE { @Override public InputStream asInputStream() throws Exception { - return new ByteArrayInputStream(content); + ByteArrayInputStream in = new ByteArrayInputStream(content); + return needDecode() ? XMLEncryptUtils.decodeInputStream(EncryptUtils.decodeInputStream(FineEncryptUtils.decode(in))) : in; + } + + private boolean needDecode() { + return StringUtils.isNotEmpty(suffix) && (suffix.endsWith(".cpt") || suffix.endsWith(".frm")); } @Override @@ -72,6 +87,14 @@ public class StashedFILE extends AbstractFILE { return false; } + /** + * 获取内部FILE对象 + * @return + */ + public FILE getInsideFILE() { + return file; + } + @Override public String toString() { return FILEFactory.MEM_PREFIX + getName(); diff --git a/designer-base/src/main/java/com/fr/file/filter/ChooseFileFilter.java b/designer-base/src/main/java/com/fr/file/filter/ChooseFileFilter.java index 147e1946d4..0f6057d0ab 100644 --- a/designer-base/src/main/java/com/fr/file/filter/ChooseFileFilter.java +++ b/designer-base/src/main/java/com/fr/file/filter/ChooseFileFilter.java @@ -31,6 +31,15 @@ public class ChooseFileFilter extends FileFilter implements FILEFilter, java.io. this(extension, null); } + public ChooseFileFilter(boolean noRestrict) { + if (noRestrict) { + this.filters = null; + this.fullDescription = FileExtension.ALL.getExtension(); + } else { + this.filters = new ArrayList<>(); + } + } + public ChooseFileFilter(String extension, String description) { this(); if (extension != null) { @@ -314,4 +323,4 @@ public class ChooseFileFilter extends FileFilter implements FILEFilter, java.io. return (o instanceof ChooseFileFilter) && ComparatorUtils.equals(((ChooseFileFilter) o).getDescription(), getDescription()); } -} \ No newline at end of file +} diff --git a/designer-base/src/main/java/com/fr/nx/app/designer/toolbar/TemplateTransformer.java b/designer-base/src/main/java/com/fr/nx/app/designer/toolbar/TemplateTransformer.java index 42490fe7d5..1a6e2bf1c8 100644 --- a/designer-base/src/main/java/com/fr/nx/app/designer/toolbar/TemplateTransformer.java +++ b/designer-base/src/main/java/com/fr/nx/app/designer/toolbar/TemplateTransformer.java @@ -2,7 +2,7 @@ package com.fr.nx.app.designer.toolbar; import com.fr.base.extension.FileExtension; import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; import com.fr.file.FILE; @@ -103,9 +103,9 @@ public enum TemplateTransformer { DesignerContext.getDesignerFrame().openTemplate(file); return; } - MutilTempalteTabPane.getInstance().setIsCloseCurrent(true); - MutilTempalteTabPane.getInstance().closeFormat(jt); - MutilTempalteTabPane.getInstance().closeSpecifiedTemplate(jt); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(true); + MultiTemplateTabPane.getInstance().closeFormat(jt); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(jt); DesignerContext.getDesignerFrame().openTemplate(file); } diff --git a/designer-base/src/main/java/com/fr/nx/app/designer/utils/CptAndCptxCompatibilityUtil.java b/designer-base/src/main/java/com/fr/nx/app/designer/utils/CptAndCptxCompatibilityUtil.java index 0b1a65657a..df0303a65d 100644 --- a/designer-base/src/main/java/com/fr/nx/app/designer/utils/CptAndCptxCompatibilityUtil.java +++ b/designer-base/src/main/java/com/fr/nx/app/designer/utils/CptAndCptxCompatibilityUtil.java @@ -3,7 +3,9 @@ package com.fr.nx.app.designer.utils; import com.fr.base.extension.FileExtension; import com.fr.design.mainframe.JTemplate; import com.fr.file.FILE; +import com.fr.main.FineBook; import com.fr.main.TemplateWorkBook; +import com.fr.report.core.ReportUtils; import com.fr.report.report.Report; import com.fr.report.stable.LayerReportAttr; import com.fr.report.worksheet.WorkSheet; @@ -30,7 +32,7 @@ public class CptAndCptxCompatibilityUtil { } /** - * 判断是不是cptx模板或者开启了的新引擎的cpt模板的另存为操作 + * 判断是不是cptx模板或者开启了新引擎的cpt模板的另存为操作 **/ private static boolean isSaveAs(JTemplate jTemplate, String oldName, String newName){ return isEngineXEnable(jTemplate.getTarget(), newName) && ((FileExtension.CPTX.matchExtension(oldName) && FileExtension.CPTX.matchExtension(newName)) || (FileExtension.CPT.matchExtension(oldName) && FileExtension.CPT.matchExtension(newName))); @@ -40,7 +42,7 @@ public class CptAndCptxCompatibilityUtil { * cptx另存为cpt需要修改报表引擎属性 **/ private static boolean setFrEngineAttr(JTemplate jTemplate){ - WorkSheet workSheet = gainWorkSheet(jTemplate.getTarget()); + WorkSheet workSheet = getFirstWorkSheet(jTemplate.getTarget()); if (workSheet == null){ return false; }else { @@ -49,8 +51,7 @@ public class CptAndCptxCompatibilityUtil { layerReportAttr = new LayerReportAttr(); workSheet.setLayerReportAttr(layerReportAttr); } - layerReportAttr.setClientPaging(true); - layerReportAttr.setEngineState(0); + layerReportAttr.enableEngineX(); return true; } } @@ -60,29 +61,17 @@ public class CptAndCptxCompatibilityUtil { * cptx自动走新引擎(非兼容模式),cpt需要进行设置 * */ public static boolean isEngineXEnable(Object workBook, String fileName){ - WorkSheet workSheet = gainWorkSheet(workBook); - LayerReportAttr layerReportAttr = gainLayerReportAttr(workSheet); - return isEngineXEnable(layerReportAttr, fileName); - } - - private static LayerReportAttr gainLayerReportAttr(WorkSheet workSheet){ - if (workSheet != null){ - LayerReportAttr layerReportAttr = workSheet.getLayerReportAttr(); - return layerReportAttr; - } else { - return null; + if (workBook == null || !(workBook instanceof FineBook)){ + return false; } + return ReportUtils.hasEngineXReport4Template((FineBook) workBook) || FileExtension.CPTX.matchExtension(fileName); } - private static WorkSheet gainWorkSheet(Object workBook){ + private static WorkSheet getFirstWorkSheet(Object workBook){ if (workBook == null || !(workBook instanceof TemplateWorkBook)){ return null; } Report report = ((TemplateWorkBook) workBook).getReport(0); return report instanceof WorkSheet ? (WorkSheet)report : null; } - - private static boolean isEngineXEnable(LayerReportAttr layerReportAttr, String fileName){ - return (layerReportAttr!= null && layerReportAttr.isClientPaging() && layerReportAttr.getEngineState() == LayerReportAttr.ENGINE_X) || FileExtension.CPTX.matchExtension(fileName); - } } diff --git a/designer-base/src/main/java/com/fr/start/BaseDesigner.java b/designer-base/src/main/java/com/fr/start/BaseDesigner.java index 1c4c611264..44228c2a4a 100644 --- a/designer-base/src/main/java/com/fr/start/BaseDesigner.java +++ b/designer-base/src/main/java/com/fr/start/BaseDesigner.java @@ -8,15 +8,17 @@ import com.fr.design.DesignerEnvManager; import com.fr.design.ExtraDesignClassManager; import com.fr.design.constants.DesignerLaunchStatus; import com.fr.design.file.HistoryTemplateListPane; -import com.fr.design.file.MutilTempalteTabPane; +import com.fr.design.file.MultiTemplateTabPane; import com.fr.design.file.TemplateTreePane; import com.fr.design.fun.DesignerStartOpenFileProcessor; import com.fr.design.fun.impl.DesignerStartWithEmptyFile; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.monitor.DesignerLifecycleMonitorContext; import com.fr.design.ui.util.UIUtil; +import com.fr.design.versioncheck.VersionCheckUtils; import com.fr.event.Event; import com.fr.event.EventDispatcher; import com.fr.event.Listener; @@ -24,17 +26,21 @@ import com.fr.event.Null; import com.fr.exit.DesignerExiter; import com.fr.file.FILE; import com.fr.file.FILEFactory; -import com.fr.file.FileFILE; -import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.process.ProcessEventPipe; import com.fr.process.engine.core.CarryMessageEvent; import com.fr.process.engine.core.FineProcessContext; import com.fr.stable.OperatingSystem; +import com.fr.start.common.DesignerStartupContext; +import com.fr.start.common.DesignerStartupUtil; +import com.fr.start.event.LazyStartupEvent; +import com.fr.workspace.base.WorkspaceStatus; +import org.jetbrains.annotations.Nullable; import java.awt.Window; -import java.io.File; import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; /** * The main class of Report Designer. @@ -45,6 +51,9 @@ public abstract class BaseDesigner extends ToolBarMenuDock { private final String[] args; + //判断是否是通过打开指定模板来启动设计器,如果是则置false + private Boolean openFlag = true; + public BaseDesigner(String[] args) { this.args = args; @@ -84,11 +93,22 @@ public abstract class BaseDesigner extends ToolBarMenuDock { if (eventPipe != null) { eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue())); } + EventDispatcher.fire(WorkspaceStatus.Prepared); + EventDispatcher.asyncFire(LazyStartupEvent.INSTANCE); collectUserInformation(); + checkVersion(); } }); } + private void checkVersion() { + try { + VersionCheckUtils.showVersionCheckDialog(DesignerEnvManager.getEnvManager().getCurEnvName()); + } catch (Exception e) { + FineLoggerFactory.getLogger().warn("Check Service Failed"); + } + } + public void show() { UIUtil.invokeLaterIfNeeded(this::refreshTemplateTree); } @@ -109,70 +129,134 @@ public abstract class BaseDesigner extends ToolBarMenuDock { try { FILE file = null; if (args != null && args.length > 0) { - // p:需要打开这个报表文件,这个代码不能删除. - for (String arg : args) { - if (ComparatorUtils.equals("demo", arg)) { - file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); - break; - } - File f = new File(arg); - String path = f.getAbsolutePath(); - boolean pathends1 = path.endsWith(".cpt") - || path.endsWith(".xls"); - boolean pathends2 = path.endsWith(".xlsx") - || path.endsWith(".frm"); - boolean pathends3 = path.endsWith(".form") - || path.endsWith(".cht"); - boolean pathends4 = pathends1 || pathends2 || pathends3; - if (pathends4 || path.endsWith(".chart")) { - file = new FileFILE(f); - } - } + file = DesignerStartupUtil.convertArgs2FILE(args); + setOpenFlag(false); } else { - file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); + file = getLastOpenFile(); } DesignerFrame df = DesignerContext.getDesignerFrame(); isException = openFile(df, isException, file); df.fireDesignerOpened(); + FineLoggerFactory.getLogger().info("Designer showed.Time used {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS)); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); if (!isException) { showDesignerFrame(true); } else { - DesignerExiter.getInstance().execute(); + DesignerExiter.getInstance().exit(e); } } } - + + @Nullable + private FILE getLastOpenFile() { + + FILE file = DesignerStartupContext.getInstance().getStartingTemplateFile(); + if (file == null) { + file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); + } + return file; + } + private boolean openFile(final DesignerFrame df, boolean isException, FILE file) { - + + AtomicBoolean isExWrapper = new AtomicBoolean(isException); + openTemplate(df, isExWrapper, file); + + if (OperatingSystem.isMacOS()) { + enableFullScreenMode(df); + } + + JTemplate selectedJTemplate = df.getSelectedJTemplate(); + if (selectedJTemplate != null) { + selectedJTemplate.requestGridFocus(); + } + return isExWrapper.get(); + } + + private void openTemplate(DesignerFrame df, AtomicBoolean isException, FILE file) { + + // 如果是起始页启动中 + if (openTemplateOnStartup(df, isException, file)) { + return; + } + + openTemplate0(df, isException, file); + } + + private void openTemplate0(DesignerFrame df, AtomicBoolean isException, FILE file) { + + file = getExtraFILE(isException, file); + + if (file != null && file.exists() && !isException.get()) { + df.openTemplate(file); + } else { + df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 + MultiTemplateTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + } + } + + private FILE getExtraFILE(AtomicBoolean isException, FILE file) { + //启动时打开指定文件的接口 DesignerStartOpenFileProcessor processor = ExtraDesignClassManager.getInstance().getSingle(DesignerStartOpenFileProcessor.XML_TAG); // 如果插件没有,且又开启了启动时打开空文件,则使用启动时打开空文件 - if (processor == null && DesignerEnvManager.getEnvManager().isStartWithEmptyFile()) { + if (processor == null && DesignerEnvManager.getEnvManager().isStartWithEmptyFile() && isOpenAppoint()) { processor = DesignerStartWithEmptyFile.getInstance(); + setOpenFlag(true); } if (processor != null) { FILE f = processor.fileToShow(); if (f != null) { file = f;//避免null } else { - isException = true;//此时有文件nullpointer异常,执行打开空文件 + isException.set(true);//此时有文件nullpointer异常,执行打开空文件 } } - if (file != null && file.exists() && !isException) { - df.openTemplate(file); - } else { - df.addAndActivateJTemplate(); - MutilTempalteTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); - } - if (OperatingSystem.isMacOS()) { - enableFullScreenMode(df); + return file; + } + + private boolean openTemplateOnStartup(DesignerFrame df, AtomicBoolean isException, FILE file) { + + boolean onStartup = DesignerStartupContext.getInstance().isSupport(); + if (onStartup) { + DesignerStartupContext context = DesignerStartupContext.getInstance(); + if (context.isCreateNew()) { + return createNewTemplate(df); + } + if (isOpenTemplate(isException, file, context)) { + return openTemplate(df, file); + } + if (context.isOpenEmpty()) { + return openEmpty(df); + } } - df.getSelectedJTemplate().requestGridFocus(); - return isException; + return false; } - + + private boolean isOpenTemplate(AtomicBoolean isException, FILE file, DesignerStartupContext context) { + + return context.isOpenLastFile() && file != null && file.exists() && !isException.get(); + } + + private boolean openEmpty(DesignerFrame df) { + df.showEmptyJTemplate(); + return true; + } + + private boolean openTemplate(DesignerFrame df, FILE file) { + df.openTemplate(file); + return true; + } + + private boolean createNewTemplate(DesignerFrame df) { + df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 + MultiTemplateTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + return true; + } + private void enableFullScreenMode(Window window) { String className = "com.apple.eawt.FullScreenUtilities"; String methodName = "setWindowCanFullScreen"; @@ -186,6 +270,14 @@ public abstract class BaseDesigner extends ToolBarMenuDock { } } + public Boolean isOpenAppoint() { + return openFlag; + } + + public void setOpenFlag(Boolean openFlag) { + this.openFlag = openFlag; + } + // 收集用户信息码 protected void collectUserInformation() { diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java new file mode 100644 index 0000000000..b42cc4ed8f --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java @@ -0,0 +1,79 @@ +package com.fr.start.common; + +import com.fr.base.svg.IconUtils; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.HistoryTemplateListPane; +import com.fr.design.file.MultiTemplateTabPane; +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; +import com.fr.design.mainframe.DesignerFrame; +import com.fr.design.utils.ColorUtils; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * created by Harrison on 2022/07/09 + **/ +public class DesignerOpenEmptyPanel extends JPanel { + + private static final Color BUTTON_COLOR = new Color(63, 155, 249); + private static final int ARC = 4; + + private final JPanel body; + + public DesignerOpenEmptyPanel() { + + this.body = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + UILabel createIcon = new UILabel(IconUtils.readIcon("/com/fr/design/startup/create_new_template.svg")); + JButton createButton = new JButton(Toolkit.i18nText("Fine-Design_New_Template")) { + @Override + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(BUTTON_COLOR); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), ARC, ARC); + super.paintComponent(g2d); + } + }; + createButton.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.start.common.DesignerOpenEmptyPanel.createButton")); + createButton.setForeground(Color.WHITE); + createButton.setBorderPainted(false); + createButton.setContentAreaFilled(false); + createButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignerFrame df = DesignerContext.getDesignerFrame(); + HistoryTemplateListCache.getInstance().setCurrentEditingTemplate(null); + df.addAndActivateJTemplate(); + // 如果没有模板,则需要确认一下 + MultiTemplateTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); + } + }); + createButton.setBorder(new EmptyBorder(0, 10, 0, 10)); + JPanel createButtonPanel = new JPanel(FRGUIPaneFactory.createCenterFlowLayout()); + createButtonPanel.add(createButton); + createButtonPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + createButtonPanel.setBackground(Color.WHITE); + this.body.add(createIcon, BorderLayout.NORTH); + this.body.add(createButtonPanel, BorderLayout.SOUTH); + + setLayout(FRGUIPaneFactory.createCenterLayout(this.body, 0.4d, 0.4d)); + + ColorUtils.syncBackground(this, Color.WHITE); + + add(this.body); + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java new file mode 100644 index 0000000000..6afef4f3b6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java @@ -0,0 +1,59 @@ +package com.fr.start.common; + +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; + +public class DesignerStartupConfig implements XMLable { + + public static final String XML_TAG = "DesignerStartupConfig"; + + private static final long serialVersionUID = -8170289826729582122L; + + private static final DesignerStartupConfig INSTANCE = new DesignerStartupConfig(); + + /** + * 加上版本,不然回滚到 1107 会有兼容问题 + */ + private static final String TAG_ENABLED = "isEnabled1108"; + + public static DesignerStartupConfig getInstance() { + + return INSTANCE; + } + + /** + * 默认值是 false + */ + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public Object clone() throws CloneNotSupportedException { + DesignerStartupConfig config = new DesignerStartupConfig(); + config.setEnabled(enabled); + return config; + } + + @Override + public void readXML(XMLableReader reader) { + if (reader.isAttr()) { + this.setEnabled(reader.getAttrAsBoolean(TAG_ENABLED, true)); + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG(XML_TAG); + writer.attr(TAG_ENABLED, this.isEnabled()); + writer.end(); + } + +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java new file mode 100644 index 0000000000..b42a6c65bd --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java @@ -0,0 +1,229 @@ +package com.fr.start.common; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceType; +import com.fr.file.FileFILE; +import com.fr.start.module.StartupArgs; +import com.fr.startup.metric.DesignerMetrics; +import com.fr.startup.ui.StartupPageModel; +import com.fr.third.guava.collect.Lists; +import com.fr.third.org.apache.commons.lang3.time.StopWatch; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * 启动页上下文 + * + * created by Harrison on 2022/06/22 + **/ +public class DesignerStartupContext { + + /** + * 可以启动 + * 当遇到 mac 双击启动时,需要将这里置为 false, 见 {@link FileOpen4MacDeepLink} + */ + private boolean enabled = true; + + /** + * 启动参数 + */ + private StartupArgs startupArgs; + + /** + * 启动数据 + */ + private StartupPageModel startupPageModel; + + /** + * 设计器启动埋点 + */ + private final DesignerMetrics designerMetrics = new DesignerMetrics(); + + /** + * 是否在起始页打开的等待过程中 + */ + private boolean onWaiting = false; + + /** + * 是否在启动中 + */ + private boolean onStartup = true; + + /** + * 是否在预热中 + */ + private boolean onWarmup = false; + + /** + * 打开上一次的文件 + */ + private boolean openLastFile; + + /** + * 打开空设计器 + */ + private boolean openEmpty; + + /** + * 直接创建一个新模板 + */ + private boolean createNew; + + /** + * 启动的模板 + */ + private FileFILE startingTemplateFile; + + /** + * 时间记录 + */ + private static StopWatch STOP_WATCH = new StopWatch(); + + public static DesignerStartupContext getInstance() { + return StartupContextHolder.INSTANCE; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + private static class StartupContextHolder { + private static final DesignerStartupContext INSTANCE = new DesignerStartupContext(); + } + + public static StopWatch getRecorder() { + return STOP_WATCH; + } + + public DesignerMetrics getDesignerMetrics() { + return designerMetrics; + } + + /* 启动模式 */ + + public FileFILE getStartingTemplateFile() { + return startingTemplateFile; + } + + public void setStartingTemplateFile(FileFILE startingTemplateFile) { + this.startingTemplateFile = startingTemplateFile; + } + + /** + * 展示启动页 + * 1. 判断当前的工作目录数量为空或者为1 + * 2. 判断是否是 demo、还是打开目标文件 + * 3. 功能是否开启 + * + * @return 是/否 + */ + public boolean isShowStartupPage() { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + return !startupArgs.isDemo() && DesignerStartupUtil.convertArgs2FILE(startupArgs.get()) == null + // 见该 field 的注释 + && enabled + && isWorkspaceValid() + && envManager.isStartupPageEnabled(); + } + + private boolean isWorkspaceValid() { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + Iterator envNameIterator = envManager.getEnvNameIterator(); + ArrayList envs = Lists.newArrayList(envNameIterator); + return !envs.isEmpty() && (envs.size() != 1); + } + + /* 预热相关 */ + + public boolean onWarmup() { + + return this.onWarmup; + } + + public boolean canWarmup() { + + String curEnvName = DesignerEnvManager.getEnvManager().getCurEnvName(); + DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(curEnvName); + boolean valid = false; + try { + valid = workspaceInfo.checkValid(); + } catch (Exception ignore) { + } + return workspaceInfo.getType() == DesignerWorkspaceType.Local && valid; + } + + public void setStartupPageModel(StartupPageModel startupPageModel) { + this.startupPageModel = startupPageModel; + } + + public StartupPageModel getStartupPageModel() { + + return startupPageModel; + } + + public boolean isOnWaiting() { + return onWaiting; + } + + public void setOnWaiting(boolean onWaiting) { + this.onWaiting = onWaiting; + } + + public boolean isSupport() { + return onStartup && isShowStartupPage(); + } + + public boolean isOnStartup() { + return onStartup; + } + + public void setOnStartup(boolean onStartup) { + this.onStartup = onStartup; + } + + /* 文件相关*/ + + public boolean isOpenLastFile() { + + return this.openLastFile; + } + + public boolean isOpenEmpty() { + + return this.openEmpty; + } + + /* set */ + + public void setOnWarmup(boolean onWarmup) { + this.onWarmup = onWarmup; + } + + public void setOpenLastFile(boolean openLastFile) { + this.openLastFile = openLastFile; + } + + public void setOpenEmpty(boolean openEmpty) { + this.openEmpty = openEmpty; + } + + public boolean isCreateNew() { + return createNew; + } + + public void setCreateNew(boolean createNew) { + this.createNew = createNew; + } + + public void setStartupArgs(StartupArgs startupArgs) { + this.startupArgs = startupArgs; + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java new file mode 100644 index 0000000000..b4358f047b --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupExecutor.java @@ -0,0 +1,22 @@ +package com.fr.start.common; + +/** + * created by Harrison on 2022/07/03 + **/ +public class DesignerStartupExecutor { + + public void execute(Runnable runnable) { + + if (!DesignerStartupContext.getInstance().onWarmup()) { + runnable.run(); + } + } + + public static DesignerStartupExecutor getInstance() { + return DesignerStartupExecutorHolder.INSTANCE; + } + + private static class DesignerStartupExecutorHolder { + private static final DesignerStartupExecutor INSTANCE = new DesignerStartupExecutor(); + } +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java new file mode 100644 index 0000000000..6625a5a31b --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupPool.java @@ -0,0 +1,39 @@ +package com.fr.start.common; + +import com.fr.concurrent.FineExecutors; +import com.fr.concurrent.NamedThreadFactory; + +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * created by Harrison on 2022/07/03 + **/ +public class DesignerStartupPool { + + private static final int MAX_THREAD_COUNT = Runtime.getRuntime().availableProcessors() * 2; + + private static final Executor COMMON_EXECUTOR = FineExecutors.newThreadPoolExecutor(MAX_THREAD_COUNT, MAX_THREAD_COUNT, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("startup-common")); + + private static final Executor DESIGNER_EXECUTOR = FineExecutors.newThreadPoolExecutor(MAX_THREAD_COUNT, MAX_THREAD_COUNT, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("startup-designer")); + + /** + * + * @return 启动通用线程池 + */ + public static Executor common() { + + return COMMON_EXECUTOR; + } + + /** + * + * @return 启动设计器线程池 + */ + public static Executor designer() { + + return DESIGNER_EXECUTOR; + } + +} diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java new file mode 100644 index 0000000000..1bcf8be95a --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupUtil.java @@ -0,0 +1,79 @@ +package com.fr.start.common; + +import com.fr.base.extension.FileExtension; +import com.fr.design.DesignerEnvManager; +import com.fr.file.FILE; +import com.fr.file.FILEFactory; +import com.fr.file.FileFILE; +import com.fr.general.ComparatorUtils; +import com.fr.startup.ui.StartupPageModel; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Optional; + +/** + * created by Harrison on 2022/07/09 + **/ +public class DesignerStartupUtil { + + /** + * 如果是在启动页中 + * + * @param file 文件 + * @return 成功/失败 + */ + public static boolean openTemplateIfOnWaiting(File file) { + + DesignerStartupContext context = DesignerStartupContext.getInstance(); + // 如果在启动页展示中 + if (context.isOnWaiting()) { + FileFILE fileFILE = new FileFILE(file); + // 设置上一次启动模板为当前模板 + DesignerStartupContext.getInstance().setStartingTemplateFile(fileFILE); + StartupPageModel model = context.getStartupPageModel(); + Optional.ofNullable(model) + .ifPresent((e) -> { + // 执行上一次模板的启动 + Runnable openLastTemplateRunnable = e.getOpenLastTemplateRunnable(); + openLastTemplateRunnable.run(); + }); + return true; + } + return false; + } + + @Nullable + public static FILE convertArgs2FILE(String[] args) { + + // p:需要打开这个报表文件,这个代码不能删除. + FILE file = null; + for (String arg : args) { + if (ComparatorUtils.equals("demo", arg)) { + file = FILEFactory.createFILE(FILEFactory.ENV_PREFIX + DesignerEnvManager.getEnvManager().getLastOpenFile()); + break; + } + File f = new File(arg); + String path = f.getAbsolutePath(); + if (isAcceptFilePathEnd(path)) { + file = new FileFILE(f); + } + } + return file; + } + + private static boolean isAcceptFilePathEnd(String path) { + FileExtension[] acceptFileExtensions = new FileExtension[]{ + FileExtension.CPT, FileExtension.XLS, FileExtension.XLSX, FileExtension.FRM, FileExtension.CHT, FileExtension.VIS + }; + for (FileExtension acceptFileExtension : acceptFileExtensions) { + String[] extensions = acceptFileExtension.getExtensions(); + for (String extension : extensions) { + if (path.endsWith("." + extension)) { + return true; + } + } + } + return false; + } +} diff --git a/designer-base/src/main/java/com/fr/start/event/LazyStartupEvent.java b/designer-base/src/main/java/com/fr/start/event/LazyStartupEvent.java new file mode 100644 index 0000000000..fcef2ffc1b --- /dev/null +++ b/designer-base/src/main/java/com/fr/start/event/LazyStartupEvent.java @@ -0,0 +1,14 @@ +package com.fr.start.event; + +import com.fr.event.Event; +import com.fr.event.Null; + +/** + * @author hades + * @version 11.0 + * Created by hades on 2022/3/7 + */ +public enum LazyStartupEvent implements Event { + + INSTANCE +} diff --git a/designer-realize/src/main/java/com/fr/start/module/StartupArgs.java b/designer-base/src/main/java/com/fr/start/module/StartupArgs.java similarity index 100% rename from designer-realize/src/main/java/com/fr/start/module/StartupArgs.java rename to designer-base/src/main/java/com/fr/start/module/StartupArgs.java diff --git a/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java b/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java index e977884427..e70804c4dc 100644 --- a/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java +++ b/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java @@ -7,11 +7,17 @@ import com.fr.module.ModuleContext; * Created by juhaoyu on 2018/6/6. */ public abstract class FineEmbedServer { + + /** + * 是否正在启动中 + */ + private static volatile boolean onStarting = false; public synchronized static void start() { - + onStarting = true; EventDispatcher.fire(EmbedServerEvent.BeforeStart); ModuleContext.getModule(FineEmbedServerActivator.class).start(); + onStarting = false; EventDispatcher.fire(EmbedServerEvent.AfterStart); } @@ -26,4 +32,8 @@ public abstract class FineEmbedServer { return ModuleContext.getModule(FineEmbedServerActivator.class).isRunning(); } + + public static boolean isOnStarting() { + return onStarting; + } } diff --git a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java index 854d260bf5..35e2090d93 100644 --- a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java +++ b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java @@ -8,8 +8,10 @@ import com.fr.stable.EncodeConstants; import com.fr.stable.ProductConstants; import com.fr.stable.StringUtils; import com.fr.startup.FineWebApplicationInitializer; +import com.fr.third.guava.collect.Sets; import com.fr.third.springframework.web.SpringServletContainerInitializer; import com.fr.third.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import com.fr.web.socketio.WebSocketEndpoint; import com.fr.workspace.WorkContext; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; @@ -17,6 +19,7 @@ import org.apache.catalina.Wrapper; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.webresources.StandardRoot; +import org.apache.tomcat.websocket.server.WsSci; import java.io.File; import java.util.HashSet; @@ -92,6 +95,7 @@ public class FineEmbedServerActivator extends Activator { Set> classes = new HashSet>(); classes.add(FineWebApplicationInitializer.class); context.addServletContainerInitializer(initializer, classes); + context.addServletContainerInitializer(new WsSci(), Sets.newHashSet(WebSocketEndpoint.class)); } // tomcat的maxPostSize会影响到post参数获取,默认2M diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java new file mode 100644 index 0000000000..aa7391df7e --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java @@ -0,0 +1,23 @@ +package com.fr.startup.metric; + +/** + * created by Harrison on 2022/08/12 + **/ +public class DesignerMetrics { + + private DesignerStartupModel model = new DesignerStartupModel(); + + private DesignerStartupPageStatistic statistic = new DesignerStartupPageStatistic(); + + public DesignerMetrics() { + } + + public DesignerStartupModel getModel() { + return model; + } + + public DesignerStartupPageStatistic getStatistic() { + return statistic; + } + +} diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java new file mode 100644 index 0000000000..5ed94d82eb --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java @@ -0,0 +1,194 @@ +package com.fr.startup.metric; + +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.manage.PluginManager; +import com.fr.stable.os.AbstractOperatingSystem; +import com.fr.stable.os.OperatingSystem; +import com.fr.start.common.DesignerStartupContext; +import com.fr.workspace.WorkContext; + +import java.lang.management.ManagementFactory; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 设计器启动数据 + * + * created by Harrison on 2022/08/12 + **/ +public class DesignerStartupModel { + + /** + * landingTime:用户从双击图标/.bat启动等,到出现起始页的时间 + */ + private long landingTime; + + /** + * startingTime:用户从起始页进入设计器,完全可用的时间 + */ + private long startingTime; + + /** + * info:设计器环境的详细信息。记录环境信息、机器信息、远程or本地、插件信息。 + */ + private MachineInfo info; + + /** + * mode:模式,0-有设计器起动页;1-无设计器起始页 + */ + private int mode; + + public DesignerStartupModel() { + } + + public DesignerStartupModel(long landingTime, long startingTime, MachineInfo info, int mode) { + this.landingTime = landingTime; + this.startingTime = startingTime; + this.info = info; + this.mode = mode; + } + + public long getLandingTime() { + return landingTime; + } + + public void setLandingTime(long landingTime) { + this.landingTime = landingTime; + } + + public long getStartingTime() { + return startingTime; + } + + public void setStartingTime(long startingTime) { + this.startingTime = startingTime; + } + + public MachineInfo getInfo() { + return info; + } + + public void setInfo(MachineInfo info) { + this.info = info; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + + private void fillInfo() { + + MachineInfo info = new MachineInfo(); + AbstractOperatingSystem operatingSystem = OperatingSystem.getOperatingSystem(); + info.setSystem(operatingSystem.getDisplayString()); + + try { + final int byteToMb = 1024 * 1024; + com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + long free = operatingSystemMXBean.getFreePhysicalMemorySize() / byteToMb; + long total = operatingSystemMXBean.getTotalPhysicalMemorySize() / byteToMb; + long used = total - free; + JSONObject jo = new JSONObject(); + jo.put("free", free); + jo.put("used", used); + jo.put("total", total); + info.setMachine(jo.toString()); + } catch (Exception ignored) { + } + + boolean local = WorkContext.getCurrent().isLocal(); + info.setWork(local ? 1 : 0); + + List contexts = PluginManager.getContexts(); + List contextNames = contexts.stream() + .map(PluginContext::getName) + .collect(Collectors.toList()); + JSONArray contextNameJa = new JSONArray(contextNames); + info.setPlugins(contextNameJa.toString()); + this.setInfo(info); + + } + + private void fillMode() { + + // 这里需要使用 showStartupPage , 表示是否存在启动页 + this.setMode(DesignerStartupContext.getInstance().isShowStartupPage() ? 0 : 1); + } + + public void fill() { + + fillInfo(); + fillMode(); + } + + private static class MachineInfo { + + /** + * 系统信息 + */ + private String system; + + /** + * 机器信息 + */ + private String machine; + + /** + * work:0-远程;1-本地; + */ + private int work; + + /** + * 插件列表 + */ + private String plugins; + + public MachineInfo() { + } + + public MachineInfo(String system, String machine, int work, String plugins) { + this.system = system; + this.machine = machine; + this.work = work; + this.plugins = plugins; + } + + public String getSystem() { + return system; + } + + public void setSystem(String system) { + this.system = system; + } + + public String getMachine() { + return machine; + } + + public void setMachine(String machine) { + this.machine = machine; + } + + public int getWork() { + return work; + } + + public void setWork(int work) { + this.work = work; + } + + public String getPlugins() { + return plugins; + } + + public void setPlugins(String plugins) { + this.plugins = plugins; + } + } +} diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java new file mode 100644 index 0000000000..b68ea73351 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java @@ -0,0 +1,199 @@ +package com.fr.startup.metric; + +import com.fr.stable.StringUtils; +import com.fr.start.common.DesignerStartupContext; +import com.fr.startup.ui.StartupPageModel; +import com.fr.startup.ui.StartupWorkspaceBean; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * 设计器启动页使用数据 + * + * created by Harrison on 2022/08/12 + **/ +public class DesignerStartupPageStatistic { + + private final Deque operations = new ArrayDeque<>(); + + /** + * 见 {@link OperationType} 的注释 + */ + public void recordOpenEmptyTemplate() { + + Operation operation = OperationType.DO_OPEN_EMPTY_TEMPLATE.create(); + StartupPageModel pageModel = DesignerStartupContext.getInstance().getStartupPageModel(); + operation.setWorkspace(pageModel.getSelectWorkspaceInfo().getName()); + operation.setWorkspaceNum(pageModel.getWorkspaceInfos().size()); + pushOperation(operation); + } + + /** + * 见 {@link OperationType} 的注释 + */ + public void recordSwitchWorkspace(StartupWorkspaceBean lastWorkspaceInfo, StartupWorkspaceBean currentWorkspace) { + + if (lastWorkspaceInfo != null && StringUtils.equals(lastWorkspaceInfo.getName(), currentWorkspace.getName())) { + return; + } + Operation operation = OperationType.DO_SWITCH_WORKSPACE.create(); + StartupPageModel pageModel = DesignerStartupContext.getInstance().getStartupPageModel(); + operation.setWorkspace(currentWorkspace.getName()); + operation.setWorkspaceNum(pageModel.getWorkspaceInfos().size()); + pushOperation(operation); + } + + /** + * 见 {@link OperationType} 的注释 + */ + public void recordShowAllAction() { + + Operation operation = OperationType.DO_SHOW_ALL_ACTION.create(); + StartupPageModel pageModel = DesignerStartupContext.getInstance().getStartupPageModel(); + operation.setWorkspaceNum(pageModel.getWorkspaceInfos().size()); + pushOperation(operation); + } + + /** + * 见 {@link OperationType} 的注释 + */ + public void recordOpenLastTemplate(String lastOpenFile) { + + Operation operation = OperationType.DO_OPEN_LAST_TEMPLATE_ACTION.create(); + StartupPageModel pageModel = DesignerStartupContext.getInstance().getStartupPageModel(); + operation.setWorkspaceNum(pageModel.getWorkspaceInfos().size()); + operation.setTemplate(lastOpenFile); + pushOperation(operation); + } + + /** + * 添加操作 + * + * @param operation 操作 + */ + public void pushOperation(Operation operation) { + + this.operations.push(operation); + } + + /** + * 获取操作 + * + * @return 操作 + */ + public Deque getOperations() { + + return this.operations; + } + + public enum OperationType { + + /** + * 双击工作目录进入 或 点击蓝色箭头进入 + */ + DO_OPEN_EMPTY_TEMPLATE(0), + + /** + * 切换其他工作目录 + */ + DO_SWITCH_WORKSPACE(1), + + /** + * 点击展开全部 + */ + DO_SHOW_ALL_ACTION(2), + + /** + * 点击工作目录中的模版直接打开 或 直接点击蓝色箭头进入 + */ + DO_OPEN_LAST_TEMPLATE_ACTION(3); + + private final int sign; + + OperationType(int sign) { + this.sign = sign; + } + + public int getSign() { + return sign; + } + + public Operation create() { + + Operation operation = new Operation(); + operation.setOperateType(this); + return operation; + } + } + + public static class Operation { + + /** + * operate:0-双击工作目录进入 或 点击蓝色箭头进入;1-切换其他工作目录;2-点击展开全部;3-点击工作目录中的模版直接打开 或 直接点击蓝色箭头进入 + */ + private int operate; + + /** + * workplace:工作目录名称,当operate为 0或1时记录 + */ + private String workspace; + + /** + * workplaceNumber:工作目录的个数,当operate为 0或1或2或3时记录 + */ + private int workspaceNum; + + /** + * template:模板名称,当operate为 3时记录 + */ + private String template; + + public Operation(int operate, String workspace, int workspaceNum, String template) { + this.operate = operate; + this.workspace = workspace; + this.workspaceNum = workspaceNum; + this.template = template; + } + + public Operation() { + } + + public int getOperate() { + return operate; + } + + public void setOperateType(OperationType operateType) { + this.operate = operateType.getSign(); + } + + public void setOperate(int operate) { + this.operate = operate; + } + + public String getWorkspace() { + return workspace; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } + + public int getWorkspaceNum() { + return workspaceNum; + } + + public void setWorkspaceNum(int workspaceNum) { + this.workspaceNum = workspaceNum; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + } + +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupLoadingPanel.java b/designer-base/src/main/java/com/fr/startup/ui/StartupLoadingPanel.java new file mode 100644 index 0000000000..59f86fc467 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupLoadingPanel.java @@ -0,0 +1,118 @@ +package com.fr.startup.ui; + +import com.fr.concurrent.FineExecutors; +import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.gui.iprogressbar.ProgressDialog; +import com.fr.design.i18n.Toolkit; +import com.fr.design.ui.util.UIUtil; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.module.ModuleEvent; + +import java.awt.Frame; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 启动加载面板 + * + * @author Harrison + * @version 11.0 + * created by Harrison on 2022/11/08 + **/ +public class StartupLoadingPanel { + + /** + * 每次更新的步伐 + */ + private static final int STEP = 1; + + /** + * 40ms更新进度 + */ + private static final int STEP_HEARTBEAT = 40; + + private final Listener MODULE_LISTENER = new Listener() { + @Override + public void on(Event event, String param) { + moduleId = param; + } + }; + + private ProgressDialog progressDialog; + private String moduleId; + private int progress; + + public StartupLoadingPanel(Frame frame) { + this.progressDialog = new ProgressDialog(frame); + this.moduleId = Toolkit.i18nText("Fine-Design_Basic_Initializing"); + + initListeners(); + } + + /** + * 隐藏 + */ + public void hide() { + this.progress = progressDialog.getProgressMaximum(); + } + + /** + * 展示 + */ + public void show() { + + final ScheduledExecutorService scheduler = FineExecutors.newScheduledThreadPool(1, + new NamedThreadFactory("StartupLoadingPanel")); + scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + UIUtil.invokeAndWaitIfNeeded(() -> { + if (isComplete()) { + scheduler.shutdown(); + progressDialog.dispose(); + resetListeners(); + return; + } + if (!progressDialog.isVisible()) { + progressDialog.setVisible(true); + String moduleId = getModuleId(); + progressDialog.updateLoadingText(moduleId); + } + progressDialog.setProgressValue(incrementProgress()); + }); + } + }, 0, STEP_HEARTBEAT, TimeUnit.MILLISECONDS); + + } + + private void initListeners() { + + EventDispatcher.listen(ModuleEvent.MajorModuleStarting, MODULE_LISTENER); + } + + private void resetListeners() { + + EventDispatcher.stopListen(MODULE_LISTENER); + } + + private boolean isComplete() { + return this.progress >= progressDialog.getProgressMaximum(); + } + + private String getModuleId() { + + return this.moduleId; + } + + private int incrementProgress() { + + if (progress != progressDialog.getProgressMaximum()) { + progress += STEP; + } + return progress; + } + + +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java new file mode 100644 index 0000000000..8c414cecfe --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageConstants.java @@ -0,0 +1,29 @@ +package com.fr.startup.ui; + +import java.awt.Color; + +/** + * created by Harrison on 2022/07/07 + **/ +public class StartupPageConstants { + + /** + * 圆弧长度 + */ + public static final int ARC_DIAMETER = 20; + + /** + * 内容宽度 + */ + public static final int CONTENT_WIDTH = 850; + + /** + * 边框的颜色 + */ + public static final Color BORDER_COLOR = Color.WHITE; + + /** + * 透明的颜色 + */ + public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0); +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java new file mode 100644 index 0000000000..a461ee33b5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageModel.java @@ -0,0 +1,131 @@ +package com.fr.startup.ui; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceType; +import com.fr.stable.StringUtils; +import com.fr.third.guava.collect.Lists; +import com.fr.workspace.connect.WorkspaceConnectionInfo; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * created by Harrison on 2022/07/06 + **/ +public class StartupPageModel { + + private StartupWorkspaceBean selectWorkspaceInfo; + + private List workspaceInfos = new ArrayList<>(); + + private Map> recentFilesMap = new HashMap<>(); + + private Runnable openLastTemplateRunnable; + + private Runnable createNewTemplateRunnable; + + private Runnable openEmptyTemplateRunnable; + + public static StartupPageModel create() { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + String curEnvName = envManager.getCurEnvName(); + Iterator envNameIterator = envManager.getEnvNameIterator(); + + Comparator startupWorkspaceBeanComparator = convertComparator(curEnvName); + List infos = Lists.newArrayList(envNameIterator) + .stream() + .map((e) -> { + DesignerWorkspaceInfo workspaceInfo = envManager.getWorkspaceInfo(e); + if (workspaceInfo.getType() == DesignerWorkspaceType.Remote) { + WorkspaceConnectionInfo connection = workspaceInfo.getConnection(); + String remoteAddress = StartupPageUtil.getRemoteAddress(connection.getUrl()); + return new StartupWorkspaceBean(e, remoteAddress, workspaceInfo.getType()); + } else { + return new StartupWorkspaceBean(e, workspaceInfo.getPath(), workspaceInfo.getType()); + } + }) + .sorted(startupWorkspaceBeanComparator) + .collect(Collectors.toList()); + Map> recentFileMap = new HashMap<>(); + for (StartupWorkspaceBean info : infos) { + String name = info.getName(); + List recentFiles = envManager.getRecentOpenedFilePathList4Env(name); + recentFileMap.put(name, recentFiles); + } + return new StartupPageModel(infos, recentFileMap); + } + + public StartupPageModel(List workspaceInfos, Map> recentFilesMap) { + this.selectWorkspaceInfo = workspaceInfos.get(0); + this.workspaceInfos = workspaceInfos; + this.recentFilesMap = recentFilesMap; + } + + public StartupWorkspaceBean getSelectWorkspaceInfo() { + return selectWorkspaceInfo; + } + + public void setSelectWorkspaceInfo(StartupWorkspaceBean selectWorkspaceInfo) { + this.selectWorkspaceInfo = selectWorkspaceInfo; + } + + public List getWorkspaceInfos() { + return workspaceInfos; + } + + public void setWorkspaceInfos(List workspaceInfos) { + this.workspaceInfos = workspaceInfos; + } + + public Map> getRecentFilesMap() { + return recentFilesMap; + } + + public void setRecentFilesMap(Map> recentFilesMap) { + this.recentFilesMap = recentFilesMap; + } + + public Runnable getOpenLastTemplateRunnable() { + return openLastTemplateRunnable; + } + + public void setOpenLastTemplateRunnable(Runnable openLastTemplateRunnable) { + this.openLastTemplateRunnable = openLastTemplateRunnable; + } + + public Runnable getCreateNewTemplateRunnable() { + return createNewTemplateRunnable; + } + + public void setCreateNewTemplateRunnable(Runnable createNewTemplateRunnable) { + this.createNewTemplateRunnable = createNewTemplateRunnable; + } + + public Runnable getOpenEmptyTemplateRunnable() { + return openEmptyTemplateRunnable; + } + + public void setOpenEmptyTemplateRunnable(Runnable openEmptyTemplateRunnable) { + this.openEmptyTemplateRunnable = openEmptyTemplateRunnable; + } + + private static Comparator convertComparator(String curEnvName) { + + return (o1, o2) -> { + if (StringUtils.equals(curEnvName, o1.getName())) { + return -1; + } + if (StringUtils.equals(curEnvName, o2.getName())) { + return 1; + } + return 0; + }; + } +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java new file mode 100644 index 0000000000..153aa4ce0e --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageUtil.java @@ -0,0 +1,86 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.SVGIcon; +import com.fr.design.env.DesignerWorkspaceType; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JRootPane; +import java.net.URL; + +/** + * created by Harrison on 2022/07/11 + **/ +public class StartupPageUtil { + + public static final int INVALID_PORT = -1; + public static final String COLON = ":"; + + /** + * 获取最近区域的 ICON + * + * @param workspaceBean 工作目录 + * @return 图标 + */ + public static Icon getIcon4RecentAreaByWorkspace(StartupWorkspaceBean workspaceBean) { + + if (workspaceBean.getType() == DesignerWorkspaceType.Local) { + return SVGIcon.readSVGIcon("/com/fr/design/startup/local_server_background_36.svg", 36, 36); + } + return SVGIcon.readSVGIcon("/com/fr/design/startup/remote_server_background_36.svg", 36, 36); + } + + /** + * 获取工作目录描述区域的 ICON + * + * @param workspaceBean 工作目录 + * @return 图标 + */ + public static Icon getIcon4DescAreaByWorkspace(StartupWorkspaceBean workspaceBean) { + + if (workspaceBean.getType() == DesignerWorkspaceType.Local) { + return SVGIcon.readSVGIcon("/com/fr/design/startup/local_server_background_28.svg", 28, 28); + } + return SVGIcon.readSVGIcon("/com/fr/design/startup/remote_server_background_28.svg", 28, 28); + } + + /** + * 返回 ip : port + * + * @param urlStr 完整的 url 值,例如 https://localhost:3090/xxx + * @return localhost:3090 + */ + public static String getRemoteAddress(String urlStr) { + + try { + if (StringUtils.isEmpty(urlStr)) { + return StringUtils.EMPTY; + } + URL url = new URL(urlStr); + String host = url.getHost(); + int port = url.getPort(); + if (port == INVALID_PORT) { + return host; + } + return host + COLON + port; + } catch (Exception e) { + FineLoggerFactory.getLogger().debug(e.getMessage(), e); + return urlStr; + } + } + + /** + * 透明的背景,需要从根节点重绘 + * + * @param component 组件 + */ + public static void repaintAll(JComponent component) { + + JRootPane rootPane = component.getRootPane(); + if (rootPane != null) { + rootPane.repaint(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java new file mode 100644 index 0000000000..43d2fd9709 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java @@ -0,0 +1,428 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.DesignerEnvManager; +import com.fr.design.dialog.UIExpandDialog; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.ui.util.UIUtil; +import com.fr.design.utils.ColorUtils; +import com.fr.design.utils.ThemeUtils; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.exit.DesignerExiter; +import com.fr.general.GeneralUtils; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ProductConstants; +import com.fr.stable.collections.CollectionUtils; +import com.fr.stable.os.OperatingSystem; +import com.fr.start.common.DesignerStartupContext; +import com.fr.startup.metric.DesignerMetrics; +import org.jetbrains.annotations.NotNull; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.LayoutManager; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.util.List; +import java.util.Map; + +/** + * 启动页 + * 见设计文档 + *

+ * created by Harrison on 2022/07/06 + **/ +public class StartupPageWindow extends JFrame { + + private static final Color HOVER_COLOR = new Color(65, 155, 249); + private static final Color SEP_COLOR = new Color(224, 224, 225); + + private static final int GROUP_WIDTH = 600; + private static final int RECENT_FILE_LIMIT = 6; + private static final int RECENT_FILE_SCROLL = RECENT_FILE_LIMIT + 1; + private static final int WORKSPACE_PANEL_WIDTH = 180; + private static final int TITLE_FONT_SIZE = 24; + private static final int ITEM_VERTICAL_GAP = 5; + + private static final Dimension SCREEN_SIZE = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); + + private static final BufferedImage BACKGROUND_IMAGE = IOUtils.readImage("com/fr/design/startup/startup_page_background.jpg"); + + private StartupPageWorkspacePanel workspacePanel; + + private JPanel recentOpenPanel; + + private JPanel contentPane; + + private JPanel body; + + public StartupPageWindow(StartupPageModel pageModel) { + + patchUIAction(pageModel); + + setLayout(new BorderLayout()); + + initCenter(pageModel); + + // Workspace-detail + setSize(SCREEN_SIZE); + setDefaultTitle(); + addDefaultListeners(); + + repaint(); + validate(); + revalidate(); + + setFullScreen(); + + } + + private void initCenter(StartupPageModel pageModel) { + + initHeaderPanel(); + + initWorkspacePanel(pageModel); + + initRecentOpenPanel(pageModel); + initContentPanel(); + } + + private void initHeaderPanel() { + this.body = FRGUIPaneFactory.createBorderLayout_S_Pane(); + this.body.setBackground(new Color(0, 0, 0, 0)); + JPanel headerPanel = createHeader(); + this.body.add(headerPanel, BorderLayout.NORTH); + } + + private void initRecentOpenPanel(StartupPageModel pageModel) { + + this.recentOpenPanel = generateRecentOpenPanel(pageModel); + this.body.add(recentOpenPanel, BorderLayout.SOUTH); + } + + private void initContentPanel() { + this.contentPane = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(BACKGROUND_IMAGE, 0, 0, SCREEN_SIZE.width, SCREEN_SIZE.height, this); + } + }; + this.contentPane.setLayout(getCenterLayout(body)); + this.contentPane.add(this.body, BorderLayout.CENTER); + this.contentPane.setPreferredSize(this.body.getPreferredSize()); + + add(this.contentPane, BorderLayout.CENTER); + } + + private void initWorkspacePanel(StartupPageModel pageModel) { + + // Workspace-description + this.workspacePanel = generateWorkspacePanel(pageModel); + this.body.add(workspacePanel, BorderLayout.CENTER); + + workspacePanel.setSelectWorkspaceRunnable(new Runnable() { + @Override + public void run() { + JPanel newPanel = generateRecentOpenPanel(pageModel); + + body.remove(recentOpenPanel); + recentOpenPanel = newPanel; + body.add(recentOpenPanel, BorderLayout.SOUTH); + validate(); + repaint(); + } + }); + } + + @NotNull + private static JPanel createHeader() { + + // Header + UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Select_Workspace")); + Font font = label.getFont(); + Font titleFont = font.deriveFont(font.getStyle(), TITLE_FONT_SIZE); + label.setFont(titleFont); + JPanel headerPanel = new JPanel(); + LayoutManager centerFlowLayout = FRGUIPaneFactory.createCenterFlowLayout(); + headerPanel.setLayout(centerFlowLayout); + headerPanel.add(label); + headerPanel.setBackground(new Color(0, 0, 0, 0)); + return headerPanel; + } + + /** + * 1-mac启动时全屏 + * 2-windows 则居中处理 + */ + private void setFullScreen() { + + if (OperatingSystem.isMacos()) { + this.setLocation(0, 0); + this.setSize(SCREEN_SIZE.width, SCREEN_SIZE.height); + } else { + GUICoreUtils.setWindowFullScreen(this); + } + } + + private void addDefaultListeners() { + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + DesignerExiter.getInstance().execute(); + } + }); + } + + private void setDefaultTitle() { + + StringBuilder sb = new StringBuilder(); + sb.append(ProductConstants.APP_NAME); + sb.append(" "); + sb.append(GeneralUtils.getVersion()); + sb.append(" "); + sb.append(ProductConstants.BRANCH); + sb.append(" "); + sb.append(Toolkit.i18nText("Fine-Design_Startup_Page_Title")); + setTitle(sb.toString()); + } + + private void patchUIAction(StartupPageModel pageModel) { + + Runnable selectAndOpenLastTemplateRunnable = pageModel.getOpenLastTemplateRunnable(); + pageModel.setOpenLastTemplateRunnable(() -> { + enterWorkspace(selectAndOpenLastTemplateRunnable); + }); + + Runnable createNewTemplateRunnable = pageModel.getCreateNewTemplateRunnable(); + pageModel.setCreateNewTemplateRunnable(() -> { + enterWorkspace(createNewTemplateRunnable); + }); + + Runnable openEmptyTemplateRunnable = pageModel.getOpenEmptyTemplateRunnable(); + pageModel.setOpenEmptyTemplateRunnable(() -> { + enterWorkspace(openEmptyTemplateRunnable); + }); + } + + private void enterWorkspace(Runnable action) { + + UIUtil.invokeAndWaitIfNeeded(() -> { + + // 必须直接初始化 + // 见 https://work.fineres.com/browse/REPORT-85293 + StartupLoadingPanel loadingPanel = new StartupLoadingPanel(this); + loadingPanel.show(); + setEnabled(false); + + SwingWorker task = new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + action.run(); + return null; + } + + @Override + protected void done() { + + try { + Void result = get(); + setVisible(false); + } catch (Exception e) { + // 处理错误 + UIUtil.invokeLaterIfNeeded(() -> { + UIExpandDialog.Builder() + .owner(StartupPageWindow.this) + .title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try")) + .message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")) + .messageType(UIExpandDialog.WARNING_MESSAGE) + .detail(e.getMessage()) + .expand(true) + .modal(false) + .build() + .setVisible(true); + setEnabled(true); + }); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } finally { + loadingPanel.hide(); + } + } + }; + task.execute(); + }); + } + + private JPanel generateRecentOpenPanel(StartupPageModel pageModel) { + + JPanel recentOpenPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setColor(Color.WHITE); + g2d.fillRoundRect(0, 0, getWidth(), getHeight(), StartupPageConstants.ARC_DIAMETER, StartupPageConstants.ARC_DIAMETER); + } + }; + recentOpenPanel.setLayout(new BorderLayout()); + recentOpenPanel.setBorder(BorderFactory.createEmptyBorder(25, 25, 25, 6)); + + StartupWorkspaceBean workspaceInfo = pageModel.getSelectWorkspaceInfo(); + JPanel workspaceWrapperYPanel = new JPanel(); + workspaceWrapperYPanel.setName("workspace-wrapper"); + { + workspaceWrapperYPanel.setLayout(new VerticalFlowLayout()); + + JPanel workspaceWrapperXPanel = new JPanel(); + workspaceWrapperXPanel.setLayout(new FlowLayout()); + workspaceWrapperXPanel.setBorder(BorderFactory.createEmptyBorder()); + + JPanel workspacePanel = new JPanel(); + workspacePanel.setLayout(new BorderLayout(0, 15)); + + UILabel workspaceIcon = new UILabel(StartupPageUtil.getIcon4RecentAreaByWorkspace(workspaceInfo)); + workspacePanel.add(workspaceIcon, BorderLayout.NORTH); + + UILabel nameLabel = new UILabel(workspaceInfo.getName()); + nameLabel.setHorizontalAlignment(SwingConstants.CENTER); + workspacePanel.add(nameLabel, BorderLayout.SOUTH); + workspaceWrapperXPanel.add(workspacePanel); + Dimension preferredSize = workspaceWrapperXPanel.getPreferredSize(); + workspaceWrapperXPanel.setPreferredSize(new Dimension(WORKSPACE_PANEL_WIDTH, (int) preferredSize.getHeight())); + + workspaceWrapperYPanel.add(workspaceWrapperXPanel); + } + recentOpenPanel.add(workspaceWrapperYPanel, BorderLayout.WEST); + + JPanel separatorPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + { + JSeparator sep = new JSeparator(); + sep.setOrientation(JSeparator.VERTICAL); + sep.setForeground(SEP_COLOR); + separatorPanel.add(sep, BorderLayout.CENTER); + } + recentOpenPanel.add(separatorPanel, BorderLayout.CENTER); + + JComponent recentOpenGroupPanel = generateRecentOpenGroupPanel(pageModel, workspaceInfo); + recentOpenPanel.add(recentOpenGroupPanel, BorderLayout.EAST); + + ColorUtils.syncBackground(recentOpenPanel, Color.WHITE); + + Dimension preferredSize = recentOpenPanel.getPreferredSize(); + recentOpenPanel.setPreferredSize(new Dimension(StartupPageConstants.CONTENT_WIDTH, (int) preferredSize.getHeight())); + + JPanel recentOpenWrapperPanel = new JPanel(); + recentOpenWrapperPanel.setName("recentOpenWrapper"); + recentOpenWrapperPanel.setLayout(new BorderLayout(0, 0)); + recentOpenWrapperPanel.setBorder(new EmptyBorder(0, 0, 0, 20)); + recentOpenWrapperPanel.add(recentOpenPanel, BorderLayout.CENTER); + + ColorUtils.syncBackgroundIfAbsent(recentOpenWrapperPanel, new Color(0,0,0,0), ThemeUtils.BACK_COLOR); + return recentOpenWrapperPanel; + } + + @NotNull + private JComponent generateRecentOpenGroupPanel(StartupPageModel pageModel, StartupWorkspaceBean workspaceInfo) { + + JPanel recentOpenGroupPanel = new JPanel(); + Map> recentFilesMap = pageModel.getRecentFilesMap(); + + boolean needScroll = false; + double itemHeight = 0.0d; + if (!CollectionUtils.isEmpty(recentFilesMap)) { + String name = workspaceInfo.getName(); + List recentFiles = recentFilesMap.get(name); + if (!CollectionUtils.isEmpty(recentFiles)) { + recentOpenGroupPanel.setLayout(new GridLayout(recentFiles.size(), 1, 50, 5)); + needScroll = recentFiles.size() > RECENT_FILE_LIMIT; + for (String recentFile : recentFiles) { + JPanel recentItemPanel = new JPanel(); + recentItemPanel.setLayout(new FlowLayout(FlowLayout.LEFT, ITEM_VERTICAL_GAP, 0)); + recentItemPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/cpt"))); + UILabel recentFileLabel = new UILabel(recentFile); + Color recentFileLabelForeground = recentFileLabel.getForeground(); + recentItemPanel.add(recentFileLabel); + recentItemPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + recentFileLabel.setForeground(HOVER_COLOR); + StartupPageUtil.repaintAll(recentOpenGroupPanel); + } + + @Override + public void mouseExited(MouseEvent e) { + recentFileLabel.setForeground(recentFileLabelForeground); + StartupPageUtil.repaintAll(recentOpenGroupPanel); + } + + @Override + public void mouseClicked(MouseEvent e) { + doOpenLastTemplateAction(recentFile, pageModel); + } + }); + Dimension preferredSize = recentItemPanel.getPreferredSize(); + itemHeight = preferredSize.getHeight(); + recentOpenGroupPanel.add(recentItemPanel); + } + } + } + Dimension preferredSize = recentOpenGroupPanel.getPreferredSize(); + recentOpenGroupPanel.setPreferredSize(new Dimension(GROUP_WIDTH, (int) preferredSize.getHeight())); + + if (needScroll) { + int scrollHeight = (int) Math.round(itemHeight * RECENT_FILE_LIMIT + ITEM_VERTICAL_GAP * (RECENT_FILE_LIMIT)); + UIScrollPane scrollPane = new UIScrollPane(recentOpenGroupPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + scrollPane.setPreferredSize(new Dimension(GROUP_WIDTH, scrollHeight)); + return scrollPane; + } + return recentOpenGroupPanel; + } + + private StartupPageWorkspacePanel generateWorkspacePanel(StartupPageModel pageModel) { + + StartupPageWorkspacePanel startupPageWorkspacePanel = new StartupPageWorkspacePanel(pageModel); + ColorUtils.syncBackgroundIfAbsent(startupPageWorkspacePanel, new Color(0, 0, 0, 0), ThemeUtils.BACK_COLOR); + return startupPageWorkspacePanel; + } + + protected LayoutManager getCenterLayout(JComponent centerBody) { + + return FRGUIPaneFactory.createCenterLayout(centerBody); + } + + private void doOpenLastTemplateAction(String recentFile, StartupPageModel pageModel) { + + DesignerEnvManager.getEnvManager().setLastOpenFile(recentFile); + pageModel.getOpenLastTemplateRunnable().run(); + + DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); + designerMetrics.getStatistic().recordOpenLastTemplate(recentFile); + } + +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java new file mode 100644 index 0000000000..e41304e23b --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWorkspacePanel.java @@ -0,0 +1,629 @@ +package com.fr.startup.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.components.tooltip.ModernToolTip; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.FRGraphics2D; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.utils.ColorUtils; +import com.fr.start.common.DesignerStartupContext; +import com.fr.startup.metric.DesignerMetrics; +import com.fr.third.guava.collect.Lists; +import org.jetbrains.annotations.NotNull; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToolTip; +import javax.swing.JViewport; +import javax.swing.RepaintManager; +import javax.swing.ScrollPaneConstants; +import javax.swing.border.EmptyBorder; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.ImageObserver; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static com.fr.startup.ui.StartupPageConstants.ARC_DIAMETER; + +/** + * created by Harrison on 2022/07/06 + **/ +public class StartupPageWorkspacePanel extends JPanel { + + /* color */ + + private static final Color SHALLOW_WHITE_COLOR = new Color(248, 250, 254); + private static final Color HOVER_COLOR = new Color(65, 155, 249); + private static final Color PATH_COLOR = new Color(51, 51, 52, (int) Math.round(255 * 0.5)); + + /* 长度 */ + + private static final int SCROLL_BAR_WIDTH = 20; + + private static final int CONTENT_WIDTH = StartupPageConstants.CONTENT_WIDTH + SCROLL_BAR_WIDTH; + private static final int BORDER_THIN = 2; + + private static final int ITEM_VERTICAL_GAP = 20; + private static final int SINGLE_ITEM_HEIGHT = 72; + private static final int SCROLL_HEIGHT = SINGLE_ITEM_HEIGHT * 4 + ITEM_VERTICAL_GAP * 4; + + private static final int NAME_LABEL_SIZE = 15; + private static final int PATH_LABEL_SIZE = 10; + + private static final Dimension LABEL_DIMENSION = new Dimension(28, 28); + private static final Dimension PATH_DIMENSION = new Dimension(100, 20); + private static final Dimension SELECT_WORKSPACE_DIMENSION = new Dimension(210, 72); + private static final Dimension SELECT_CREATE_DIMENSION = new Dimension(60, 72); + + private static final int COLUMN_LIMIT = 3; + private static final int DOUBLE_CLICK_COUNT = 2; + public static final int PARTITION_LIMIT = 2; + + /* model */ + + private final StartupPageModel pageModel; + + private final List> partitions; + + private Runnable selectWorkspaceRunnable; + + private final Runnable createNewTemplateRunnable; + + private final Runnable openEmptyTemplateRunnable; + + private JComponent contentPanel; + + private JPanel tailPanel; + + private boolean showMore = true; + + public StartupPageWorkspacePanel(StartupPageModel pageModel) { + + this.setLayout(new BorderLayout(0, 0)); + this.setBorder(new EmptyBorder(15, 0, 20, 0)); + + this.pageModel = pageModel; + + List workspaceInfos = pageModel.getWorkspaceInfos(); + this.partitions = Lists.partition(workspaceInfos, COLUMN_LIMIT); + + this.contentPanel = generateLimitContentPanel(partitions); + this.add(contentPanel, BorderLayout.NORTH); + + if (partitions.size() > PARTITION_LIMIT) { + this.tailPanel = generateTailPanel(); + this.add(tailPanel, BorderLayout.SOUTH); + } + + this.createNewTemplateRunnable = pageModel.getCreateNewTemplateRunnable(); + this.openEmptyTemplateRunnable = pageModel.getOpenEmptyTemplateRunnable(); + + this.repaint(); + } + + public void showLessContent() { + + this.remove(this.contentPanel); + + this.contentPanel = generateLimitContentPanel(this.partitions); + this.add(contentPanel, BorderLayout.NORTH); + } + + public void showMoreContent() { + + this.remove(this.contentPanel); + + this.contentPanel = generateUnLimitContentPanel(this.partitions); + this.add(contentPanel, BorderLayout.NORTH); + } + private JComponent generateUnLimitContentPanel(List> partitions) { + + JComponent panel = generateUnLimitContentPanel0(partitions); + ColorUtils.transparentBackground(panel); + return panel; + } + + private JComponent generateUnLimitContentPanel0(List> partitions) { + + JPanel workspaceDescWrapper = new JPanel(); + workspaceDescWrapper.setLayout(new BorderLayout(0, 0)); + workspaceDescWrapper.setBorder(new EmptyBorder(0, 0, 0, 0)); + + JPanel workspaceDescPanel = new JPanel(); + workspaceDescPanel.setLayout(new GridLayout(partitions.size(), 1, 0, 0)); + for (List partition : partitions) { + JPanel partitionPanel = generatePartitionPanel(partition); + workspaceDescPanel.add(partitionPanel); + } + boolean needScroll = partitions.size() > 4; + if (needScroll) { + return generateScrollUnLimitContentPanel(workspaceDescWrapper, workspaceDescPanel); + } + workspaceDescWrapper.add(workspaceDescPanel, BorderLayout.CENTER); + + return workspaceDescWrapper; + } + + @NotNull + private JPanel generateScrollUnLimitContentPanel(JPanel workspaceDescWrapper, JPanel workspaceDescPanel) { + + // 滚动条 + UIScrollPane scrollPane = new UIScrollPane(workspaceDescPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + JViewport viewport = scrollPane.getViewport(); + JViewport scrollViewport = new TransparentScrollViewPort(); + // 动态画图 + scrollViewport.addChangeListener(e -> repaintAll()); + scrollViewport.setView(viewport.getView()); + scrollPane.setViewport(scrollViewport); + scrollPane.setBorder(new EmptyBorder(10, 0, 0, 0)); + scrollPane.setPreferredSize(new Dimension(CONTENT_WIDTH, SCROLL_HEIGHT)); + workspaceDescWrapper.add(scrollPane, BorderLayout.CENTER); + + return workspaceDescWrapper; + } + + private JPanel generateLimitContentPanel(List> partitions) { + + JPanel workspaceDescPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEFT, 0, 0); + int limit = 2; + for (int i = 0; i < partitions.size(); i++) { + if (i >= limit) { + break; + } + List partition = partitions.get(i); + + JPanel partitionPanel = generatePartitionPanel(partition); + workspaceDescPanel.add(partitionPanel); + } + + ColorUtils.transparentBackground(workspaceDescPanel); + + return workspaceDescPanel; + } + + @NotNull + private JPanel generateTailPanel() { + + AtomicReference hoverBackColorRef = new AtomicReference<>(); + + JPanel tailPanel = new JPanel(); + { + tailPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); + tailPanel.setBorder(new EmptyBorder(0, 0, 0, 20)); + JPanel showAllPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + if (hoverBackColorRef.get() != null) { + g.setColor(hoverBackColorRef.get()); + Dimension preferredSize = getPreferredSize(); + g.fillRoundRect(0, 0, preferredSize.width, preferredSize.height, 5, 5); + } + } + }; + showAllPanel.setLayout(new BorderLayout(5, 0)); + showAllPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + + UILabel fontLabel = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Expand_All")); + fontLabel.setForeground(HOVER_COLOR); + showAllPanel.setBackground(new Color(0, 0, 0, 0)); + showAllPanel.add(fontLabel, BorderLayout.WEST); + + UILabel iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/startup/show_more.svg")); + showAllPanel.add(iconLabel, BorderLayout.EAST); + + Color showAllBackground = showAllPanel.getBackground(); + + showAllPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + Color hoverBackColor = new Color(217, 235, 254); + hoverBackColorRef.set(hoverBackColor); + repaintAll(); + } + + @Override + public void mouseExited(MouseEvent e) { + hoverBackColorRef.set(null); + ColorUtils.syncBackground(showAllPanel, showAllBackground); + repaintAll(); + } + + @Override + public void mousePressed(MouseEvent e) { + doShowAllAction(fontLabel, iconLabel); + } + }); + tailPanel.add(showAllPanel); + Dimension preferredSize = tailPanel.getPreferredSize(); + tailPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, (int) preferredSize.getHeight())); + } + return tailPanel; + } + + @NotNull + private JPanel generatePartitionPanel(List partition) { + + JPanel partitionPanelWrapper = new JPanel(); + partitionPanelWrapper.setBorder(new EmptyBorder(10,0,10,0)); + partitionPanelWrapper.setLayout(new BorderLayout()); + + JPanel partitionPanel = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(0, 20, 0); + partitionPanel.setName("partitionPanel"); + + for (StartupWorkspaceBean workspaceInfo : partition) { + + JPanel workspaceItemDesc = FRGUIPaneFactory.createBorderLayout_S_Pane(); + + layoutSelectWorkspacePanel(workspaceInfo, workspaceItemDesc); + + layoutSelectAndCreatePanel(workspaceInfo, workspaceItemDesc); + + partitionPanel.add(workspaceItemDesc); + + Dimension preferredSize = partitionPanel.getPreferredSize(); + partitionPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, (int) preferredSize.getHeight())); + } + + partitionPanelWrapper.add(partitionPanel, BorderLayout.CENTER); + return partitionPanelWrapper; + } + + private void layoutSelectWorkspacePanel(StartupWorkspaceBean workspaceInfo, JPanel workspaceItemDesc) { + + // 选择工作目录 + // 图标 / 分隔符 / 说明-进入 + // 选择并新建 + AtomicReference borderColorRef = new AtomicReference<>(null); + + JPanel selectWorkspacePanel = new JPanel() { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color borderColor = borderColorRef.get(); + + Color backColor = Color.WHITE; + g2d.setColor(backColor); + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + // 填充一个直角 + g2d.fillRoundRect(0, 0, getWidth() - rectOffset, getHeight(), ARC_DIAMETER, ARC_DIAMETER); + // 填充一个圆角 + g2d.fillRoundRect(getWidth() - roundOffset, 0, roundOffset, getHeight(), 0, 0); + paintBorderIfHover(g2d, borderColor, backColor); + } + + /** + * 当悬浮的时候,将边框展示出来 + * 会叠合,然后填充中间 + * + * |----【-|--】 + * | A 【C| B】 + * |----【-|--】 + * + * 见上面有两种线,分别是 A-| 和 B-【 + * 这里会将 A 和 B 叠在一起,中间则存在 C,然后将 C 的部分扩大一点,然后填充上背景 + * 则形成下面这种图形 + * + * |----】 + * |----】 + * + * @param g2d 绘画 + * @param borderColor 边框颜色 + * @param backColor 背景颜色 + */ + private void paintBorderIfHover(Graphics2D g2d, Color borderColor, Color backColor) { + + if (borderColor != null) { + g2d.setColor(borderColor); + g2d.setStroke(new BasicStroke(BORDER_THIN)); + // 需要一个修正值 + int strokeOffset = BORDER_THIN / 2; + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + // 画一个圆角 + int fixRoundWidth = getWidth() - rectOffset; + int fixRoundHeight = getHeight() - BORDER_THIN; + g2d.drawRoundRect(strokeOffset, strokeOffset, fixRoundWidth, fixRoundHeight, ARC_DIAMETER, ARC_DIAMETER); + + g2d.setColor(backColor); + + // 绘制一个矩形,覆盖住多余的相交线 + // 需要考虑上下的线宽 + int coverHeight = getHeight() - (BORDER_THIN * 2); + // 偏左一点的 fixedX + int fixedX = getWidth() - roundOffset - BORDER_THIN; + // 圆角和直角相交的区域 + int coverWidth = 15; + g2d.fillRect(fixedX, BORDER_THIN, coverWidth, coverHeight); + + g2d.setColor(borderColor); + g2d.drawLine(getWidth() / 2, strokeOffset, getWidth(), strokeOffset); + g2d.drawLine(getWidth() / 2, getHeight() - strokeOffset, getWidth(), getHeight() - strokeOffset); + g2d.drawLine(getWidth() - strokeOffset, strokeOffset, getWidth() - strokeOffset, getHeight() - strokeOffset); + } + } + }; + selectWorkspacePanel.setLayout(new BorderLayout(0,0)); + selectWorkspacePanel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Double_Click_Enter_Workspace")); + selectWorkspacePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + { + + JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + iconPanel.setBorder(new EmptyBorder(0, 10, 0, 10)); + Icon icon = StartupPageUtil.getIcon4DescAreaByWorkspace(workspaceInfo); + UILabel label = new UILabel(icon); + label.setPreferredSize(LABEL_DIMENSION); + iconPanel.add(label, BorderLayout.CENTER); + selectWorkspacePanel.add(iconPanel, BorderLayout.WEST); + + // desc / >箭头 + JPanel descPanel = new JPanel(); + descPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + descPanel.setBorder(new EmptyBorder(0, 10, 0, 0)); + + JPanel simpleDescPanelWrapper = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.CENTER, 0, 0); + JPanel simpleDescPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + UILabel nameLabel = new UILabel(workspaceInfo.getName()); + Font font = nameLabel.getFont(); + Font newSizeFont = font.deriveFont(font.getStyle(), NAME_LABEL_SIZE); + nameLabel.setFont(newSizeFont); + nameLabel.setPreferredSize(PATH_DIMENSION); + Color nameForeground = nameLabel.getForeground(); + simpleDescPanel.add(nameLabel,BorderLayout.NORTH); + + UILabel pathLabel = new UILabel(workspaceInfo.getPath()); + pathLabel.setPreferredSize(PATH_DIMENSION); + Font pathFont = pathLabel.getFont(); + pathLabel.setFont(pathFont.deriveFont(pathFont.getStyle(), PATH_LABEL_SIZE)); + Color pathColor = PATH_COLOR; + pathLabel.setForeground(pathColor); + simpleDescPanel.add(pathLabel, BorderLayout.SOUTH); + simpleDescPanelWrapper.add(simpleDescPanel); + + descPanel.add(simpleDescPanelWrapper, BorderLayout.WEST); + + MouseAdapter selectWorkspaceMouseListener = new MouseAdapter() { + + @Override + public void mouseEntered(MouseEvent e) { + Color hoverColor = HOVER_COLOR; + borderColorRef.set(hoverColor); + nameLabel.setForeground(hoverColor); + pathLabel.setForeground(hoverColor ); + repaintAll(); + } + + @Override + public void mouseExited(MouseEvent e) { + borderColorRef.set(Color.WHITE); + nameLabel.setForeground(nameForeground); + pathLabel.setForeground(pathColor); + repaintAll(); + } + + @Override + public void mousePressed(MouseEvent e) { + + int clickCount = e.getClickCount(); + if (clickCount == DOUBLE_CLICK_COUNT) { + doOpenEmptyTemplate(workspaceInfo); + return; + } + doSwitchWorkspace(workspaceInfo); + } + + }; + + UILabel arrowLabel = new UILabel(IconUtils.readIcon("/com/fr/design/startup/more.svg")) { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + }; + arrowLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Enter_Workspace")); + arrowLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + arrowLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/more_hover.svg")); + selectWorkspaceMouseListener.mouseEntered(e); + } + + @Override + public void mouseExited(MouseEvent e) { + arrowLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/more.svg")); + selectWorkspaceMouseListener.mouseExited(e); + } + + @Override + public void mousePressed(MouseEvent e) { + doOpenEmptyTemplate(workspaceInfo); + } + }); + descPanel.add(arrowLabel, BorderLayout.EAST); + + selectWorkspacePanel.add(descPanel, BorderLayout.CENTER); + selectWorkspacePanel.addMouseListener(selectWorkspaceMouseListener); + } + + ColorUtils.syncBackground(selectWorkspacePanel, Color.WHITE); + selectWorkspacePanel.setPreferredSize(SELECT_WORKSPACE_DIMENSION); + workspaceItemDesc.add(selectWorkspacePanel, BorderLayout.WEST); + } + + private void layoutSelectAndCreatePanel(StartupWorkspaceBean workspaceInfo, JPanel workspaceItemDesc) { + + // 选择并新建 + AtomicReference borderColorRef = new AtomicReference<>(null); + JPanel selectAndCreatePanel = new JPanel() { + @Override + public JToolTip createToolTip() { + return new ModernToolTip(); + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color borderColor = borderColorRef.get(); + + Color backColor = SHALLOW_WHITE_COLOR; + g2d.setColor(backColor); + + // 见 layoutSelectWorkspacePanel 部分的分析 + // 直角和圆角上下叠合在一起 + int rectOffset = 10; + int roundOffset = 15; + int strokeOffset = BORDER_THIN / 2; + int fixedRoundOffset = roundOffset + strokeOffset; + g2d.fillRoundRect(0, 0, getWidth() - rectOffset, getHeight(), 0, 0); + g2d.fillRoundRect(getWidth() - fixedRoundOffset, 0, roundOffset, getHeight(), ARC_DIAMETER, ARC_DIAMETER); + if (borderColor != null) { + g2d.setColor(borderColor); + g2d.setStroke(new BasicStroke(BORDER_THIN)); + + int borderOffset = BORDER_THIN * 2; + // 画画的笔触需要调整一下 + g2d.drawRoundRect(strokeOffset, strokeOffset, getWidth() - borderOffset, getHeight() - BORDER_THIN, ARC_DIAMETER, ARC_DIAMETER); + g2d.setColor(backColor); + int fillWidth = 15; + g2d.fillRect(0, 0, fillWidth, getHeight()); + + g2d.setColor(borderColor); + g2d.drawLine(strokeOffset, strokeOffset, fillWidth, strokeOffset); + g2d.drawLine(strokeOffset, getHeight() - strokeOffset, fillWidth, getHeight() - strokeOffset); + g2d.drawLine(strokeOffset, strokeOffset, strokeOffset, getHeight() - strokeOffset); + } + } + + }; + selectAndCreatePanel.setToolTipText(Toolkit.i18nText("Fine-Design_Startup_Page_Enter_Workspace_And_Create")); + selectAndCreatePanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + selectAndCreatePanel.setLayout(new BorderLayout()); + { + UILabel label = new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/add")); + label.setPreferredSize(new Dimension(ARC_DIAMETER, ARC_DIAMETER)); + label.setForeground(HOVER_COLOR); + selectAndCreatePanel.add(label, BorderLayout.CENTER); + selectAndCreatePanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + borderColorRef.set(HOVER_COLOR); + label.setIcon(IconUtils.readIcon("/com/fr/design/standard/system/add_hover.svg")); + repaintAll(); + } + + @Override + public void mouseExited(MouseEvent e) { + borderColorRef.set(null); + label.setIcon(IconUtils.readIcon("/com/fr/design/standard/system/add")); + repaintAll(); + } + @Override + public void mousePressed(MouseEvent e) { + pageModel.setSelectWorkspaceInfo(workspaceInfo); + createNewTemplateRunnable.run(); + } + }); + } + ColorUtils.syncBackground(selectAndCreatePanel, Color.GREEN); + selectAndCreatePanel.setPreferredSize(SELECT_CREATE_DIMENSION); + workspaceItemDesc.add(selectAndCreatePanel, BorderLayout.EAST); + } + + public void setSelectWorkspaceRunnable(Runnable selectWorkspaceRunnable) { + + this.selectWorkspaceRunnable = selectWorkspaceRunnable; + } + + private void doOpenEmptyTemplate(StartupWorkspaceBean workspaceInfo) { + + pageModel.setSelectWorkspaceInfo(workspaceInfo); + openEmptyTemplateRunnable.run(); + + DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); + designerMetrics.getStatistic().recordOpenEmptyTemplate(); + } + + private void doSwitchWorkspace(StartupWorkspaceBean workspaceInfo) { + + StartupWorkspaceBean lastWorkspaceInfo = pageModel.getSelectWorkspaceInfo(); + // selectWorkspaceRunnable + pageModel.setSelectWorkspaceInfo(workspaceInfo); + selectWorkspaceRunnable.run(); + + DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); + designerMetrics.getStatistic().recordSwitchWorkspace(lastWorkspaceInfo, workspaceInfo); + } + + private void doShowAllAction(UILabel fontLabel, UILabel iconLabel) { + + if (showMore) { + fontLabel.setText(Toolkit.i18nText("Fine-Design_Startup_Page_Collapse_Workspace")); + iconLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/show_less.svg")); + showMoreContent(); + showMore = !showMore; + } else { + fontLabel.setText(Toolkit.i18nText("Fine-Design_Startup_Page_Expand_All")); + iconLabel.setIcon(IconUtils.readIcon("/com/fr/design/startup/show_more.svg")); + showLessContent(); + showMore = !showMore; + } + DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); + designerMetrics.getStatistic().recordShowAllAction(); + + repaintAll(); + } + + private void repaintAll() { + + this.getRootPane().repaint(); + } + + /** + * 支持透明的滚动视图 + */ + private class TransparentScrollViewPort extends JViewport { + + /** + * 从而屏蔽掉 {@link RepaintManager.PaintManager#paintDoubleBuffered(JComponent, Image, Graphics, int, int, int, int)} + * + * @return 创建一个不会实际画图的 Graphics + */ + @Override + public Graphics getGraphics() { + + Graphics graphics = super.getGraphics(); + return new FRGraphics2D((Graphics2D) graphics) { + @Override + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return true; + } + }; + } + } +} diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java b/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java new file mode 100644 index 0000000000..04d660db95 --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupWorkspaceBean.java @@ -0,0 +1,49 @@ +package com.fr.startup.ui; + +import com.fr.design.env.DesignerWorkspaceType; + +/** + * created by Harrison on 2022/07/07 + **/ +public class StartupWorkspaceBean { + + private String name; + + private String path; + + private DesignerWorkspaceType type; + + public StartupWorkspaceBean(String name, String path, DesignerWorkspaceType type) { + this.name = name; + this.path = path; + this.type = type; + } + + public static StartupWorkspaceBean create(String name, String path) { + return new StartupWorkspaceBean(name, path, DesignerWorkspaceType.Local); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public DesignerWorkspaceType getType() { + return type; + } + + public void setType(DesignerWorkspaceType type) { + this.type = type; + } +} diff --git a/designer-base/src/main/resources/com/fr/design/config/default b/designer-base/src/main/resources/com/fr/design/config/default new file mode 100644 index 0000000000..f808a82379 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/config/default @@ -0,0 +1 @@ +Fine-Designer_Login=i7hP48WAcuTrmxfN diff --git a/designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex b/designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex index f73852366f..aa2c854dad 100644 --- a/designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex +++ b/designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex @@ -584,7 +584,31 @@ FunctionNames = "ABS"| "QUERY"| "query"| "WEBIMAGE"| - "webimage" + "webimage"| + "ACCSUM"| + "accsum"| + "COUNTIFS"| + "countifs"| + "SUMIFS"| + "sumifs"| + "ENDOFMONTH"| + "endofmonth"| + "NUMTOZH"| + "numtozh"| + "MIDCHAR"| + "midchar"| + "ISWORKDAY"| + "isworkday"| + "ENBYSTRNUM"| + "enbystrnum"| + "TEXTGETNUM"| + "textgetnum"| + "GETCHARNUM"| + "getcharnum"| + "GCD"| + "gcd"| + "LCM"| + "lcm" %state MLC 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 b69ede5ea8..5098bc3c97 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 @@ -1,6 +1,6 @@ com.fr.design.mainframe.check.CheckButton=305*118 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=630*185 -com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=630*31 +com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=570*31 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=630*280 com.fr.design.report.ReportColumnsPane=800*600 com.fr.env.RemoteEnvPane.dialog=458*132 @@ -8,4 +8,20 @@ com.fr.design.version.check.dialog=490*95 com.fr.design.version.detail.label=750*30 com.fr.design.version.detail.dialog=900*500 com.fr.env.SyncFailedPluginsDialog.messageWithLink=316*36 -com.fr.design.web.pane.text.field=450*20 \ No newline at end of file +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 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=75*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=120*24 +com.fr.design.cell.expand.sort.pane=257*185 +com.fr.design.sort.rule.item=125*20 +com.fr.design.ds.column.sort.pane=250*180 +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 +com.fr.design.report.WatermarkSettingPane=720*600 +com.fr.design.file.MultiTemplateTabPane.popUpMenu=350*65 +com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 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 7d09dee4d0..6c3ac0e58c 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 @@ -1,10 +1,26 @@ com.fr.design.mainframe.check.CheckButton=280*118 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=610*185 -com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=610*31 +com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=550*31 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=610*280 com.fr.env.RemoteEnvPane.dialog=458*132 com.fr.design.version.check.dialog=430*95 com.fr.design.version.detail.label=650*30 com.fr.design.version.detail.dialog=800*500 com.fr.env.SyncFailedPluginsDialog.messageWithLink=316*36 -com.fr.design.web.pane.text.field=400*20 \ No newline at end of file +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 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 +com.fr.design.cell.expand.sort.pane=257*170 +com.fr.design.sort.rule.item=125*20 +com.fr.design.ds.column.sort.pane=250*165 +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 +com.fr.design.report.WatermarkSettingPane=720*600 +com.fr.design.file.MultiTemplateTabPane.popUpMenu=240*65 +com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 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 28823bf1ad..eaa75e14a0 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 @@ -1,10 +1,26 @@ com.fr.design.mainframe.check.CheckButton=230*118 -com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=490*185 +com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=550*185 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=490*35 -com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=490*280 +com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=550*280 com.fr.env.RemoteEnvPane.dialog=458*132 com.fr.design.version.check.dialog=450*95 com.fr.design.version.detail.label=700*30 com.fr.design.version.detail.dialog=850*500 com.fr.env.SyncFailedPluginsDialog.messageWithLink=316*36 -com.fr.design.web.pane.text.field=450*20 \ No newline at end of file +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 +com.fr.design.lock.LockInfoDialog=500*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=80*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 +com.fr.design.cell.expand.sort.pane=267*165 +com.fr.design.sort.rule.item=125*20 +com.fr.design.ds.column.sort.pane=250*180 +com.fr.design.sort.expand.header.pane=95*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 +com.fr.design.report.WatermarkSettingPane=720*600 +com.fr.design.file.MultiTemplateTabPane.popUpMenu=240*65 +com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 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 56998f7f7e..d1e84b4618 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 @@ -1,11 +1,26 @@ # \u9ED8\u8BA4\u4E3A\u7C7B\u7684\u5168\u9650\u5B9A\u540D\uFF08\u53EF\u81EA\u5B9A\u4E49key\uFF09= width * height com.fr.design.mainframe.check.CheckButton=250*118 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=385*185 -com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=385*31 +com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=325*31 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=385*280 com.fr.env.RemoteEnvPane.dialog=308*132 com.fr.design.version.check.dialog=230*95 com.fr.design.version.detail.label=450*30 com.fr.design.version.detail.dialog=600*500 com.fr.env.SyncFailedPluginsDialog.messageWithLink=316*20 -com.fr.design.web.pane.text.field=450*20 \ No newline at end of file +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 +com.fr.design.lock.LockInfoDialog=400*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 +com.fr.design.cell.expand.sort.pane=227*155 +com.fr.design.sort.rule.item=80*20 +com.fr.design.ds.column.sort.pane=220*150 +com.fr.design.sort.expand.header.pane=108*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 +com.fr.design.report.WatermarkSettingPane=720*600 +com.fr.design.file.MultiTemplateTabPane.popUpMenu=170*65 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 58e6ae1216..82f86a3a43 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 @@ -1,10 +1,25 @@ com.fr.design.mainframe.check.CheckButton=250*118 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=385*185 -com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=385*31 +com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=325*31 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=385*280 com.fr.env.RemoteEnvPane.dialog=308*132 com.fr.design.version.check.dialog=230*95 com.fr.design.version.detail.label=450*30 com.fr.design.version.detail.dialog=600*500 com.fr.env.SyncFailedPluginsDialog.messageWithLink=316*20 -com.fr.design.web.pane.text.field=450*20 \ No newline at end of file +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 +com.fr.design.lock.LockInfoDialog=400*180 +com.fr.design.mainframe.ForbiddenPane.refreshButton=68*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 +com.fr.design.cell.expand.sort.pane=227*155 +com.fr.design.sort.rule.item=80*20 +com.fr.design.ds.column.sort.pane=220*150 +com.fr.design.sort.expand.header.pane=108*10 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 +com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 +com.fr.design.report.WatermarkSettingPane=720*600 +com.fr.design.file.MultiTemplateTabPane.popUpMenu=170*65 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/FileDealerPaneIcon/collapse-all.png b/designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/collapse-all.png new file mode 100644 index 0000000000..935503e65e Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/collapse-all.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/locate.png b/designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/locate.png new file mode 100644 index 0000000000..0773525e3d Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/locate.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan.png b/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan.png new file mode 100644 index 0000000000..1a27244653 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan_normal.svg b/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan_normal.svg new file mode 100644 index 0000000000..0237b2e459 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/bbs/studyPlan_normal.svg @@ -0,0 +1 @@ +l \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/ds_column_summary.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/ds_column_summary.png new file mode 100644 index 0000000000..1d7e13aa48 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/buttonicon/ds_column_summary.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/replace_help.svg b/designer-base/src/main/resources/com/fr/design/images/buttonicon/replace_help.svg new file mode 100644 index 0000000000..fdbd5eca5e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/buttonicon/replace_help.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_disabled.svg b/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_disabled.svg new file mode 100644 index 0000000000..b21c206a3a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_normal.svg b/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_normal.svg new file mode 100644 index 0000000000..60a2855aa5 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/buttonicon/select_normal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/widget/picture_widget_16.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/widget/picture_widget_16.png new file mode 100644 index 0000000000..fbf334ad22 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/buttonicon/widget/picture_widget_16.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_disabled.svg b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_disabled.svg new file mode 100644 index 0000000000..ed225a99b9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_normal.svg b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_normal.svg new file mode 100644 index 0000000000..c81b5419aa --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_off_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_disabled.svg b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_disabled.svg new file mode 100644 index 0000000000..23d8c5da55 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_normal.svg b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_normal.svg new file mode 100644 index 0000000000..13f924d88b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/control/batch_esd_on_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/control/dot-line.png b/designer-base/src/main/resources/com/fr/design/images/control/dot-line.png deleted file mode 100644 index 874408025b..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/control/dot-line.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/control/refresh_normal.svg b/designer-base/src/main/resources/com/fr/design/images/control/refresh_normal.svg new file mode 100644 index 0000000000..e83a52740e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/control/refresh_normal.svg @@ -0,0 +1,7 @@ + + + icon_刷新_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg b/designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg new file mode 100644 index 0000000000..8b22bc1821 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg @@ -0,0 +1,9 @@ + + + icon_返回_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg b/designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg new file mode 100644 index 0000000000..11f60a5530 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg @@ -0,0 +1,10 @@ + + + icon_关闭_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg b/designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg new file mode 100644 index 0000000000..dc036ac53c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg @@ -0,0 +1,9 @@ + + + icon_搜索_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/edit/advancedEditor.svg b/designer-base/src/main/resources/com/fr/design/images/edit/advancedEditor.svg new file mode 100644 index 0000000000..6ddc105cb9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/edit/advancedEditor.svg @@ -0,0 +1,10 @@ + + + 高级编辑 + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png new file mode 100644 index 0000000000..9e731c557b Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/gui/file_lock.png b/designer-base/src/main/resources/com/fr/design/images/gui/file_lock.png new file mode 100644 index 0000000000..a0b08e6e27 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/gui/file_lock.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cht_file_icon_16x16.png b/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cht_file_icon_16x16.png deleted file mode 100644 index a1e244a9bb..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cht_file_icon_16x16.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cpt_file_icon_16x16.png b/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cpt_file_icon_16x16.png deleted file mode 100644 index 15966d96d1..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_cpt_file_icon_16x16.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_frm_file_icon_16x16.png b/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_frm_file_icon_16x16.png deleted file mode 100644 index 6258f4baf4..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/gui/modern_style_frm_file_icon_16x16.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/lookandfeel/FileIcon.svg b/designer-base/src/main/resources/com/fr/design/images/lookandfeel/FileIcon.svg new file mode 100644 index 0000000000..8b3b40bbef --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/lookandfeel/FileIcon.svg @@ -0,0 +1,8 @@ + + + icon_列表_文件_normal + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/m_edit/move.png b/designer-base/src/main/resources/com/fr/design/images/m_edit/move.png new file mode 100644 index 0000000000..9d924c78d4 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/m_edit/move.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/m_file/formula.png b/designer-base/src/main/resources/com/fr/design/images/m_file/formula.png new file mode 100644 index 0000000000..7e495da1b2 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/m_file/formula.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/m_file/param.png b/designer-base/src/main/resources/com/fr/design/images/m_file/param.png new file mode 100644 index 0000000000..011c395813 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/m_file/param.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/openloading.png b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading.png similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/mainframe/openloading.png rename to designer-base/src/main/resources/com/fr/design/images/mainframe/loading.png diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/lock_template.png b/designer-base/src/main/resources/com/fr/design/images/mainframe/lock_template.png new file mode 100644 index 0000000000..f75bfe4799 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/lock_template.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/refreh_icon.png b/designer-base/src/main/resources/com/fr/design/images/mainframe/refreh_icon.png new file mode 100644 index 0000000000..99b4e53740 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/refreh_icon.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/platform/platform_normal.svg b/designer-base/src/main/resources/com/fr/design/images/platform/platform_normal.svg new file mode 100644 index 0000000000..ab95e95f3c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/platform/platform_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/replace/change_normal.svg b/designer-base/src/main/resources/com/fr/design/images/replace/change_normal.svg new file mode 100644 index 0000000000..88d9e7772b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/replace/change_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/replace/replace.png b/designer-base/src/main/resources/com/fr/design/images/replace/replace.png new file mode 100644 index 0000000000..b9a41125c5 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/replace/replace.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/replace/replace_normal.svg b/designer-base/src/main/resources/com/fr/design/images/replace/replace_normal.svg new file mode 100644 index 0000000000..f11cdc07b0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/replace/replace_normal.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/add.png b/designer-base/src/main/resources/com/fr/design/images/sort/add.png new file mode 100644 index 0000000000..a14e2a40b8 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/sort/add.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/down_arrow.png b/designer-base/src/main/resources/com/fr/design/images/sort/down_arrow.png new file mode 100644 index 0000000000..84b4909efc Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/sort/down_arrow.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/left_arrow.png b/designer-base/src/main/resources/com/fr/design/images/sort/left_arrow.png new file mode 100644 index 0000000000..9166a9c96d Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/sort/left_arrow.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/sort/sequence.png b/designer-base/src/main/resources/com/fr/design/images/sort/sequence.png new file mode 100644 index 0000000000..ac321ae174 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/sort/sequence.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/lock.png b/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/lock.png new file mode 100644 index 0000000000..882bbaeb32 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/lock.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/unlock.png b/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/unlock.png new file mode 100644 index 0000000000..69def397ee Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/toolbarbtn/unlock.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/transparent_background.png b/designer-base/src/main/resources/com/fr/design/images/transparent_background.png index 4f942536f8..3db1fd14f2 100644 Binary files a/designer-base/src/main/resources/com/fr/design/images/transparent_background.png and b/designer-base/src/main/resources/com/fr/design/images/transparent_background.png differ 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..ece3628ab5 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/category.json @@ -0,0 +1,46 @@ +{ + "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_Tab": {} + } +} \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/javascript/jsapi/images/connectFailed.svg b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/images/connectFailed.svg new file mode 100644 index 0000000000..6b0dfbc665 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/javascript/jsapi/images/connectFailed.svg @@ -0,0 +1,8 @@ + + + + + + + + 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..dcad373927 --- /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", "getShowIndex", "setTitleVisible"] +} \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_en_US.js b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_en_US.js index 162f7d1b35..ce14a01bab 100644 --- a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_en_US.js +++ b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_en_US.js @@ -54,6 +54,7 @@ var Store = { 'Designer-BBS_Username_Is_Register': 'The user has been registered', 'Designer-BBS_Please_Enter_Correct_Phone': 'Please enter the correct phone number', 'Designer-Login_Network_Connected_Failed': 'Network connection failed', + 'Designer-Login_Failed_Exceed_Limit': 'Too many password errors, please try again after 24 hours', }} window.Store = Store; \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ja_JP.js b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ja_JP.js index 455998282c..391ee7fa62 100644 --- a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ja_JP.js +++ b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ja_JP.js @@ -54,6 +54,7 @@ var Store = { 'Designer-BBS_Username_Is_Register': 'このユーザは登録済みです。', 'Designer-BBS_Please_Enter_Correct_Phone': '正確な携帯番号を入力してください。', 'Designer-Login_Network_Connected_Failed': 'インターネット接続失敗', + 'Designer-Login_Failed_Exceed_Limit': 'パスワードを連続で間違えています。24時間にもう一度試してください。', }} window.Store = Store; \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ko_KR.js b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ko_KR.js index 162f7d1b35..ce14a01bab 100644 --- a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ko_KR.js +++ b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_ko_KR.js @@ -54,6 +54,7 @@ var Store = { 'Designer-BBS_Username_Is_Register': 'The user has been registered', 'Designer-BBS_Please_Enter_Correct_Phone': 'Please enter the correct phone number', 'Designer-Login_Network_Connected_Failed': 'Network connection failed', + 'Designer-Login_Failed_Exceed_Limit': 'Too many password errors, please try again after 24 hours', }} window.Store = Store; \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_CN.js b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_CN.js index 5181aa4351..2bff62a558 100644 --- a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_CN.js +++ b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_CN.js @@ -54,6 +54,7 @@ var Store = { 'Designer-BBS_Username_Is_Register': '该用户已被注册', 'Designer-BBS_Please_Enter_Correct_Phone': '请输入正确的手机号', 'Designer-Login_Network_Connected_Failed': '网络连接失败', + 'Designer-Login_Failed_Exceed_Limit': '密码错误次数过多,请24小时后重试', }} window.Store = Store; \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_TW.js b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_TW.js index 2cef831517..8a716ea671 100644 --- a/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_TW.js +++ b/designer-base/src/main/resources/com/fr/design/login/lib/locale/login_zh_TW.js @@ -54,6 +54,7 @@ var Store = { 'Designer-BBS_Username_Is_Register': '該帳號已被註冊', 'Designer-BBS_Please_Enter_Correct_Phone': '請輸入正確的手機號', 'Designer-Login_Network_Connected_Failed': '網路連線失敗', + 'Designer-Login_Failed_Exceed_Limit': '密碼錯誤次數過多,請24小時後重試', }} window.Store = Store; \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/login/login.js b/designer-base/src/main/resources/com/fr/design/login/login.js index 8691cf1e57..7f5d4111b8 100644 --- a/designer-base/src/main/resources/com/fr/design/login/login.js +++ b/designer-base/src/main/resources/com/fr/design/login/login.js @@ -1 +1 @@ -!function(e){var t={};function i(o){if(t[o])return t[o].exports;var s=t[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,i),s.l=!0,s.exports}i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)i.d(o,s,function(t){return e[t]}.bind(null,s));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=4)}([function(e,t,i){"use strict";var o=this&&this.__createBinding||(Object.create?function(e,t,i,o){o===undefined&&(o=i),Object.defineProperty(e,o,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,o){o===undefined&&(o=i),e[o]=t[i]}),s=this&&this.__exportStar||function(e,t){for(var i in e)"default"===i||t.hasOwnProperty(i)||o(t,e,i)};Object.defineProperty(t,"__esModule",{value:!0}),s(i(5),t)},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=window.DesignerLoginHelper,s=function(){function e(){}return e.prototype.getParams=function(){return{designerLoginSource:window.designerLoginSource||"0",lastLoginType:window.lastLoginType||"-1",lastLoginAccount:window.lastLoginAccount||""}},e.prototype.closeWindow=function(e){o&&o.closeWindow(e)},e.prototype.serviceHref=function(){o?o.serviceHref():window.open("https://bbs.fanruan.com/thread-102821-1-1.html")},e.prototype.forgetHref=function(){o?o.forgetHref():window.open("https://id.fanruan.com/forget/forget.php?clue=activityf")},e.prototype.normalLogin=function(e,t,i){o?o.normalLogin(e,t,i):i(-1)},e.prototype.sendCaptcha=function(e,t,i){o?o.sendCaptcha(e,t,i):i(-1)},e.prototype.smsLogin=function(e,t,i,s){o?o.smsLogin(e,t,i,s):s(null)},e.prototype.smsRegister=function(e,t,i,s,n){o?o.smsRegister(e,t,i,s,n):n(-1)},e.prototype.resize=function(e,t){o&&o.resize(e,t)},e}();t["default"]=new s},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BBS_ERROR_CODE=t.NORMAL_LOGIN_RESULT=t.REGION=t.LOGIN=void 0,t.LOGIN={NORMAL_METHOD:"normal",SMS_METHOD:"sms",TABS:{LOGIN:"login",FORGET_PASSWORD:"forget",RESET_PASSWORD:"reset",REGISTER:"register"}},t.REGION=[{value:"+86",text:"Designer-Basic_Chinese_Mainland"},{value:"+886",text:"Designer-Basic_Chinese_Taiwan"},{value:"+852",text:"Designer-Basic_Chinese_Hong_Kong"},{value:"+853",text:"Designer-Basic_Chinese_Macao"},{value:"+90",text:"Designer-Basic_Turkey"},{value:"+82",text:"Designer-Basic_South_Korea"},{value:"+81",text:"Designer-Basic_Japan"},{value:"+65",text:"Designer-Basic_Singapore"},{value:"+60",text:"Designer-Basic_Malaysia"}],t.NORMAL_LOGIN_RESULT=[{status:0,message:"Designer-Login_Internal_Error"},{status:-1,message:"Designer-Login_Store_User_Not_Exist"},{status:-2,message:"Designer-Login_Store_User_Password_Error"},{status:-3,message:"Designer-Login_Unexpected_Error"},{status:-4,message:"Designer-Login_Network_Connected_Failed"}],t.BBS_ERROR_CODE=[{status:0,message:"Designer-Login_Internal_Error"},{status:-1,message:"Designer-BBS_Register_Timeout"},{status:-2,message:"Designer-BBS_Phone_Is_Register"},{status:-3,message:"Designer-BBS_Captcha_Send_Exceed_Limit"},{status:-4,message:"Designer-BBS_Phone_Format_Error"},{status:-100,message:"Designer-BBS_Captcha_Out_Of_Date"},{status:-101,message:"Designer-BBS_Captcha_Try_Exceed_Limit"},{status:-102,message:"Designer-BBS_Captcha_Error"},{status:-104,message:"Designer-BBS_Username_Format_Error"},{status:-103,message:"Designer-BBS_Please_Enter_Correct_Phone"},{status:-105,message:"Designer-BBS_Username_Too_Short"},{status:-106,message:"Designer-BBS_Username_Too_Long"},{status:-107,message:"Designer-BBS_Phone_Is_Register"},{status:-108,message:"Designer-BBS_Username_Is_Register"}]},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getError=void 0,t.getError=function(e,t){var i=BI.find(e,(function(e,i){return i.status===t}));return i&&i.message?i.message:""}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=i(0),s=i(6);BI.addI18n(Store.i18n),BI.createWidget({type:o.Vertical,element:"body",items:[{type:s["default"]}]})},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ListView=t.VirtualGroup=t.LeftRightVerticalAdapt=t.Left=t.Horizontal=t.Vertical=t.Absolute=t.Layout=t.Htape=t.CenterAdapt=t.Vtape=t.HorizontalAdapt=t.VerticalAdapt=t.BubbleCombo=t.Img=t.Tab=t.SingleSelectInsertCombo=t.SingleSelectRadioItem=t.MultiTreePopupView=t.Editor=t.NicEditor=t.RichEditor=t.MultiTreeCombo=t.DynamicDateTimeCombo=t.DynamicDateCombo=t.BarPopOver=t.MultiSelectItem=t.TextAreaEditor=t.AllValueChooserCombo=t.ButtonGroup=t.MultiSelectInsertCombo=t.TextEditor=t.Button=t.SignEditor=t.MultiFileEditor=t.SmallTextEditor=t.HtmlLabel=t.Label=t.DownListCombo=t.TextButton=t.IconChangeButton=t.IconButton=t.IconTextIconItem=t.IconTextItem=void 0,t.IconTextItem="bi.icon_text_item",t.IconTextIconItem="bi.icon_text_icon_item",t.IconButton="bi.icon_button",t.IconChangeButton="bi.icon_change_button",t.TextButton="bi.text_button",t.DownListCombo="bi.down_list_combo",t.Label="bi.label",t.HtmlLabel="bi.html_label",t.SmallTextEditor="bi.small_text_editor",t.MultiFileEditor="bi.multifile_editor",t.SignEditor="bi.sign_editor",t.Button="bi.button",t.TextEditor="bi.text_editor",t.MultiSelectInsertCombo="bi.multi_select_insert_combo",t.ButtonGroup="bi.button_group",t.AllValueChooserCombo="bi.all_value_chooser_combo",t.TextAreaEditor="bi.textarea_editor",t.MultiSelectItem="bi.multi_select_item",t.BarPopOver="bi.bar_popover",t.DynamicDateCombo="bi.dynamic_date_combo",t.DynamicDateTimeCombo="bi.dynamic_date_time_combo",t.MultiTreeCombo="bi.multi_tree_combo",t.RichEditor="bi.rich_editor",t.NicEditor="bi.nic_editor",t.Editor="bi.editor",t.MultiTreePopupView="bi.multi_tree_popup_view",t.SingleSelectRadioItem="bi.single_select_radio_item",t.SingleSelectInsertCombo="bi.single_select_insert_combo",t.Tab="bi.tab",t.Img="bi.img",t.BubbleCombo="bi.bubble_combo",t.VerticalAdapt="bi.vertical_adapt",t.HorizontalAdapt="bi.horizontal_adapt",t.Vtape="bi.vtape",t.CenterAdapt="bi.center_adapt",t.Htape="bi.htape",t.Layout="bi.layout",t.Absolute="bi.absolute",t.Vertical="bi.vertical",t.Horizontal="bi.horizontal",t.Left="bi.left",t.LeftRightVerticalAdapt="bi.left_right_vertical_adapt",t.VirtualGroup="bi.virtual_group",t.ListView="bi.list_view"},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(7),n=i(8),r=i(9),a=i(11);i(25),t.className="designer.login.login",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login",width:420},_store:function(){return BI.Models.getModel(s["default"])},watch:{loading:function(e){this.loading.setVisible(e)}},render:function(){return{type:o.Vertical,cls:"designer-login",items:[{el:{type:o.HorizontalAdapt,items:[{type:n["default"],rgap:14,tgap:14}]}},{el:{type:o.Vertical,items:[{type:r["default"]},{type:a["default"]}]},lgap:15,rgap:15,bgap:15}]}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});BI.model("designer.login.login.model",BI.inherit(Fix.Model,{childContext:["loading"],state:function(){return{loading:!1}}})),t["default"]="designer.login.login.model"},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(1);t.className="designer.login.login.close.button",t.Widget=BI.inherit(BI.Widget,{render:function(){return{type:o.TextButton,text:String.fromCharCode(10005),cls:"background-login-close",width:18.38,height:18.38,handler:function(){s["default"].closeWindow(!1)}}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0);i(10),t.className="designer.login.login.title",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-title"},render:function(){return{type:o.Label,text:BI.i18nText("Designer-Login_Title"),cls:"bi-font-bold",bgap:10}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(12);i(13);var n=i(14),r=i(16),a=i(18),l=i(2),u=i(1),d=249.64,g=331.64,c=422,p=478,h=560;t.className="designer.login.login.body",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(s["default"])},watch:{loginMethod:function(e){this.tabOption.setValue(e),this.tab.setSelect(e),this.foot.setLoginMethod(e),this.refreshLoginButton(),e===l.LOGIN.NORMAL_METHOD?(this.tab.setHeight(d),u["default"].resize(c,p)):this.model.expand&&(u["default"].resize(c,h),this.tab.setHeight(g))},approve:function(e){this.refreshLoginButton()},expand:function(e){e&&(u["default"].resize(c,h),this.tab.setHeight(g))}},render:function(){var e=this;return{type:o.Vertical,cls:"designer-login-body",items:[{type:o.ButtonGroup,value:this.model.loginMethod,ref:function(t){e.tabOption=t},layouts:[{type:o.HorizontalAdapt}],items:[{cls:"designer-login-change-mode bi-list-item-effect bi-border-bottom bi-font-bold",width:70,height:28,value:l.LOGIN.SMS_METHOD,text:BI.i18nText("Designer-Login_Sms")},{cls:"designer-login-change-mode bi-list-item-effect bi-border-bottom bi-font-bold",width:70,height:28,value:l.LOGIN.NORMAL_METHOD,text:BI.i18nText("Designer-Login_Normal")}],listeners:[{eventName:BI.ButtonGroup.EVENT_CHANGE,action:function(t){e.store.setLoginMethod(t)}}],tgap:24,lgap:75,rgap:75},{type:o.CenterAdapt,tgap:35,items:[{type:o.Tab,cardCreator:BI.bind(this.createCard,this),showIndex:this.model.loginMethod,ref:function(t){e.tab=t},height:d,width:280}]},{type:n["default"],lgap:50,rgap:50,bgap:30,ref:function(t){e.foot=t},refreshStatus:function(t){e.store.setApprove(t)}}]}},mounted:function(){var e=u["default"].getParams(),t=e.designerLoginSource,i=e.lastLoginType;if("2"===t){var o="0"===i?l.LOGIN.NORMAL_METHOD:l.LOGIN.SMS_METHOD;this.store.setLoginMethod(o)}},createCard:function(e){var t=this;switch(e){case l.LOGIN.NORMAL_METHOD:return{type:r["default"],ref:function(e){t.normalMethod=e}};case l.LOGIN.SMS_METHOD:default:return{type:a["default"],ref:function(e){t.smsMethod=e},expand:function(){t.store.setExpand(!0)}}}},refreshLoginButton:function(){this.model.loginMethod===l.LOGIN.NORMAL_METHOD?this.normalMethod.setApprove(this.model.approve):this.smsMethod.setApprove(this.model.approve)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0;var o=i(2);t.className="designer.login.model.login.body",t.Model=BI.inherit(Fix.Model,{context:["loading"],state:function(){return{loginMethod:o.LOGIN.SMS_METHOD,approve:!0,expand:!1}},actions:{setLoginMethod:function(e){this.model.loginMethod=e},setApprove:function(e){this.model.approve=e},setExpand:function(e){this.model.expand=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(1),s=i(0);i(15);var n=i(2);t.className="designer.login.login.foot",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-foot"},render:function(){var e=this,t=this.options;return{type:s.LeftRightVerticalAdapt,items:{left:[{type:s.MultiSelectItem,width:30,selected:!0,handler:function(){t.refreshStatus(this.isSelected())}},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:BI.i18nText("Designer-Login_I_Have_Read")},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:"《"},{type:s.TextButton,cls:"login-link",textAlign:"left",text:BI.i18nText("Designer-Login_Service_Terms"),handler:function(){o["default"].serviceHref()}},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:"》"}],right:[{type:s.TextButton,cls:"login-link",textAlign:"right",text:BI.i18nText("Designer-Login_Forget_Password"),invisible:!0,tgap:2,ref:function(t){e.forgetPassword=t},handler:function(){o["default"].forgetHref()}}]}}},setLoginMethod:function(e){e===n.LOGIN.NORMAL_METHOD?this.forgetPassword.setVisible(!0):this.forgetPassword.setVisible(!1)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(3),n=i(1),r=i(17),a=i(2);t.className="designer.login.login.normal",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(r["default"])},watch:{errMessage:function(e){this.errMessage.setText(e)}},render:function(){var e=this;return{type:o.Vertical,items:[{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_User_Name"),bgap:3},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-username",watermark:BI.i18nText("Designer-Login_User_Name_Hint"),inputType:"text",allowBlank:!0,height:40,ref:function(t){e.userName=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Password"),bgap:3},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Password_Hint"),inputType:"password",allowBlank:!0,height:40,ref:function(t){e.password=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,cls:"designer-login-error-message",textAlign:"center",text:"",height:20,bgap:10,ref:function(t){e.errMessage=t}},{type:o.Button,cls:"login-login-button bi-font-bold",text:BI.i18nText("Designer-Login"),level:"common",height:40,ref:function(t){e.loginButton=t},handler:function(){e.login()}}]}},mounted:function(){var e=this;this.element.keyup((function(t){13===t.keyCode&&e.login()}));var t=n["default"].getParams(),i=t.designerLoginSource,o=t.lastLoginType,s=t.lastLoginAccount;"2"===i&&"0"===o&&e.userName.setValue(s)},checkUsername:function(){var e=this.userName.getValue();e&&this.userName.setValue(e.replace(/\s+/g,""))},login:function(){var e=this;e.checkUsername();var t=this.userName.getValue(),i=this.password.getValue();t?i?n["default"].normalLogin(t,i,(function(t){var i=parseInt(t,10);if(i>0)n["default"].closeWindow(!0);else{var o=s.getError(a.NORMAL_LOGIN_RESULT,i);o&&e.store.setErrMessage(BI.i18nText(o))}})):this.store.setErrMessage(BI.i18nText("Designer-Login_Password_Not_Null")):this.store.setErrMessage(BI.i18nText("Designer-Login_Username_Not_Null"))},setApprove:function(e){this.loginButton.setEnable(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0,t.className="designer.login.model.normal_method",t.Model=BI.inherit(Fix.Model,{context:[""],state:function(){return{errMessage:""}},actions:{setErrMessage:function(e){this.model.errMessage=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(19),n=i(22),r=i(23),a=i(2),l=i(24),u=i(1),d=i(3);t.className="designer.login.login.sms",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(l["default"])},watch:{errMessage:function(e){this.errMessage.setText(e)},isRegister:function(e){var t=this.options;e&&(t.expand(),this.password.setVisible(!0),this.passwordLabel.setVisible(!0))}},render:function(){var e=this,t=this;return{type:o.Vertical,items:[{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Phone"),bgap:3},{type:o.HorizontalAdapt,bgap:7,items:[{type:s["default"],height:42,textFormatter:function(e){var i=t.getNumberTypeItem(e);return{value:i.value,text:BI.i18nText(i.text)}},value:a.REGION[0].value,items:BI.map(a.REGION,(function(e,t){return{type:n["default"],value:t.value,label:BI.i18nText(t.text),text:t.value}})),ref:function(t){e.regionCode=t}},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-username",watermark:BI.i18nText("Designer-Login_Phone_Hint"),inputType:"text",allowBlank:!0,height:40,ref:function(t){e.phone=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Code"),bgap:3},{type:o.Horizontal,bgap:7,items:[{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Code_Hint"),inputType:"text",allowBlank:!0,height:40,width:190,ref:function(t){e.code=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:r["default"],height:40,width:90,ref:function(t){e.accountCaptcha=t},listeners:[{eventName:"EVENT_SEND",action:function(){t.sendCaptcha()}}]}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Password"),bgap:3,invisible:!0,ref:function(t){e.passwordLabel=t}},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Password_Setting_Hint"),inputType:"password",allowBlank:!0,height:40,invisible:!0,ref:function(t){e.password=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,cls:"designer-login-error-message",textAlign:"center",text:"",height:20,bgap:11,ref:function(t){e.errMessage=t}},{type:o.Button,cls:"login-login-button bi-font-bold",text:BI.i18nText("Designer-Login_Register_Or_Login"),level:"common",height:40,ref:function(t){e.loginButton=t},handler:function(){e.login()}}]}},mounted:function(){var e=this;this.element.keyup((function(t){13===t.keyCode&&e.login()}));var t=u["default"].getParams(),i=t.designerLoginSource,o=t.lastLoginType,s=t.lastLoginAccount;if("2"===i&&"1"===o){var n=s.split("-")[0],r=s.split("-")[1];e.regionCode.setValue(n),e.phone.setValue(r)}},getNumberTypeItem:function(e){return BI.find(a.REGION,(function(t,i){return e===i.value}))||{}},checkPhone:function(){var e=this.phone.getValue();e&&this.phone.setValue(e.replace(/\s+/g,""))},login:function(){var e=this,t=this;t.checkPhone();var i=this.phone.getValue(),o=this.code.getValue();if(i)if(o)if(6==o.length){var s=this.regionCode.getValue();if(this.model.isRegister){var n=this.password.getValue();if(!n)return void this.store.setErrMessage(BI.i18nText("Designer-Login_Password_Not_Null"));var r=this.model.regToken;if(!r)return void this.store.setErrMessage(BI.i18nText("Designer-Login_Token_Request_Failed"));u["default"].smsRegister(s,i,n,r,(function(e){var i=parseInt(e,10);if(i>0)u["default"].closeWindow(!0);else{var o=d.getError(a.BBS_ERROR_CODE,i);o&&t.store.setErrMessage(BI.i18nText(o))}}))}else u["default"].smsLogin(s,i,o,(function(i){var o=JSON.parse(i);if(o.status>0)if(!0===o.register){var s=o.regtoken;s?(t.store.setRegister(!0),t.store.setRegToken(s)):e.store.setErrMessage(BI.i18nText("Designer-Login_Token_Request_Failed"))}else u["default"].closeWindow(!0);else{var n=d.getError(a.BBS_ERROR_CODE,o.status);n&&t.store.setErrMessage(BI.i18nText(n))}}))}else this.store.setErrMessage(BI.i18nText("Designer-BBS_Captcha_Error"));else this.store.setErrMessage(BI.i18nText("Designer-Login_Code_Not_Null"));else this.store.setErrMessage(BI.i18nText("Designer-Login_Phone_Not_Null"))},sendCaptcha:function(){var e=this;e.checkPhone();var t=this.phone.getValue();if(!t)return e.accountCaptcha.setButtonEnable(!0),void this.store.setErrMessage(BI.i18nText("Designer-Login_Phone_Not_Null"));var i=this.regionCode.getValue();u["default"].sendCaptcha(i,t,(function(t){var i=parseInt(t,10);if(1===i)e.accountCaptcha.regainCaptcha();else{if(e.accountCaptcha.setButtonEnable(!0),0===i)return void e.store.setErrMessage(BI.i18nText("Designer-BBS_Please_Enter_Correct_Phone"));var o=d.getError(a.BBS_ERROR_CODE,i);o&&e.store.setErrMessage(BI.i18nText(o))}}))},setApprove:function(e){this.loginButton.setEnable(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(20),s=i(21);t.className="designer.left_right_text_value_combo",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"",height:24,chooseType:BI.ButtonGroup.CHOOSE_TYPE_SINGLE,textFormatter:function(e){return e},value:""},render:function(){var e=this,t=this.options;return{type:s["default"],container:t.container,adjustLength:2,ref:function(t){e.combo=t},el:{type:o["default"],cls:"text-value-trigger",items:t.items,height:t.height-2,value:t.textFormatter(t.value),ref:function(t){e.trigger=t}},popup:{el:{type:"bi.text_value_combo_popup",chooseType:t.chooseType,value:t.value,items:t.items,ref:function(t){e.popup=t},listeners:[{eventName:BI.TextValueComboPopup.EVENT_CHANGE,action:function(){e.setValue(e.getValue()),e.combo.hideView(),e.fireEvent("EVENT_CHANGE",arguments)}},{eventName:BI.Controller.EVENT_CHANGE,action:function(){e.fireEvent(BI.Controller.EVENT_CHANGE,arguments)}}]},value:t.value,maxHeight:240,minHeight:25}}},setValue:function(e){this.combo.setValue(e),this.trigger.setValue(this.options.textFormatter(e))},getValue:function(){var e=this.combo.getValue();return BI.isNull(e)?"":BI.isArray(e)?e[0]:e},populate:function(e){this.options.items=e,this.combo.populate(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0,t.className="designer.left_right_text_value_combo_trigger",t.Widget=BI.inherit(BI.Trigger,{props:{baseCls:"",value:{}},render:function(){var e=this,t=this.options,i=t.value;return{type:"bi.htape",cls:"bi-border-bottom bi-border-radius",items:[{type:"bi.label",text:i.text,title:function(){return e.textRow.getText()},height:t.height,hgap:3,textAlign:"left",ref:function(t){e.textRow=t}},{type:"bi.label",text:i.value,height:t.height,width:32,textAlign:"right",ref:function(t){e.valueRow=t}},{type:"bi.trigger_icon_button",width:t.triggerWidth||t.height}]}},setValue:function(e){this.textRow.setText(e.text),this.valueRow.setText(e.value)},setText:function(e){this.textRow.setText(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o={};t.className="designer.login_combo",t.Widget=BI.inherit(BI.Widget,{_defaultConfig:function(){var e=BI.Combo.superclass._defaultConfig.apply(this,arguments);return BI.extend(e,{baseCls:(e.baseCls||"")+" bi-combo"+(BI.isIE()?" hack":""),attributes:{tabIndex:-1},trigger:"click",toggle:!0,direction:"bottom",logic:{dynamic:!0},container:null,isDefaultInit:!1,destroyWhenHide:!1,hideWhenAnotherComboOpen:!1,isNeedAdjustHeight:!0,isNeedAdjustWidth:!0,stopEvent:!1,stopPropagation:!1,adjustLength:0,adjustXOffset:0,adjustYOffset:0,hideChecker:BI.emptyFn,offsetStyle:"left",el:{},popup:{},comboClass:"bi-combo-popup",hoverClass:"bi-combo-hover",belowMouse:!1})},_init:function(){BI.Combo.superclass._init.apply(this,arguments);var e=this,t=this.options;this._initCombo(),this._initPullDownAction(),this.combo.on(BI.Controller.EVENT_CHANGE,(function(t,i,o){e.isEnabled()&&e.isValid()&&(t===BI.Events.EXPAND&&e._popupView(),t===BI.Events.COLLAPSE&&e._hideView(),t===BI.Events.EXPAND&&(e.fireEvent(BI.Controller.EVENT_CHANGE,arguments),e.fireEvent(BI.Combo.EVENT_EXPAND)),t===BI.Events.COLLAPSE&&(e.fireEvent(BI.Controller.EVENT_CHANGE,arguments),e.isViewVisible()&&e.fireEvent(BI.Combo.EVENT_COLLAPSE)),t===BI.Events.CLICK&&e.fireEvent(BI.Combo.EVENT_TRIGGER_CHANGE,o))})),e.element.on("mouseenter."+e.getName(),(function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&e.element.addClass(t.hoverClass)})),e.element.on("mouseleave."+e.getName(),(function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&e.element.removeClass(t.hoverClass)})),BI.createWidget(BI.extend({element:this},BI.LogicFactory.createLogic("vertical",BI.extend(t.logic,{items:[{el:this.combo}]})))),t.isDefaultInit&&this._assertPopupView(),BI.Resizers.add(this.getName(),BI.bind((function(e){this.isViewVisible()&&(BI.isNotNull(e)?this._hideIf(e):this._hideView())}),this))},_toggle:function(e){this._assertPopupViewRender(),this.popupView.isVisible()?this._hideView(e):this.isEnabled()&&this._popupView(e)},_initPullDownAction:function(){var e=this,t=this.options,i=(this.options.trigger||"").split(","),o=function(e){t.stopEvent&&e.stopEvent(),t.stopPropagation&&e.stopPropagation()},s=!1;function n(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&!0===t.toggle&&(e._hideView(i),e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.COLLAPSE,"",e.combo),e.fireEvent(BI.Combo.EVENT_COLLAPSE)),e.popupView&&e.popupView.element.off("mouseenter."+e.getName()).off("mouseleave."+e.getName()),s=!1}BI.each(i,(function(i,r){switch(r){case"hover":e.element.on("mouseenter."+e.getName(),(function(t){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(e._popupView(t),e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND))})),e.element.on("mouseleave."+e.getName(),(function(t){e.popupView&&(e.popupView.element.on("mouseenter."+e.getName(),(function(t){s=!0,e.popupView.element.on("mouseleave."+e.getName(),(function(e){n(e)})),e.popupView.element.off("mouseenter."+e.getName())})),BI.defer((function(){s||n(t)}),50))}));break;case"click":var a=BI.debounce((function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(t.toggle?e._toggle(i):e._popupView(i),e.isViewVisible()?(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND)):(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.COLLAPSE,"",e.combo),e.fireEvent(BI.Combo.EVENT_COLLAPSE)))}),BI.EVENT_RESPONSE_TIME,{leading:!0,trailing:!1});e.element.off(r+"."+e.getName()).on(r+"."+e.getName(),(function(e){a(e),o(e)}));break;case"click-hover":a=BI.debounce((function(t){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(e._popupView(t),e.isViewVisible()&&(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND)))}),BI.EVENT_RESPONSE_TIME,{leading:!0,trailing:!1});e.element.off("click."+e.getName()).on("click."+e.getName(),(function(e){a(e),o(e)})),e.element.on("mouseleave."+e.getName(),(function(t){e.popupView&&(e.popupView.element.on("mouseenter."+e.getName(),(function(t){s=!0,e.popupView.element.on("mouseleave."+e.getName(),(function(e){n(e)})),e.popupView.element.off("mouseenter."+e.getName())})),BI.delay((function(){s||n(t)}),50))}))}}))},_initCombo:function(){this.combo=BI.createWidget(this.options.el,{value:this.options.value})},_assertPopupView:function(){var e=this,t=this.options;null==this.popupView&&(this.popupView=BI.createWidget(this.options.popup,{type:"bi.popup_view",value:t.value},this),this.popupView.on(BI.Controller.EVENT_CHANGE,(function(t,i,o){t===BI.Events.CLICK&&(e.combo.setValue(e.getValue()),e.fireEvent(BI.Combo.EVENT_CHANGE,i,o)),e.fireEvent(BI.Controller.EVENT_CHANGE,arguments)})),this.popupView.setVisible(!1),BI.nextTick((function(){e.fireEvent(BI.Combo.EVENT_AFTER_INIT)})))},_assertPopupViewRender:function(){this._assertPopupView(),this._rendered||(BI.createWidget({type:"bi.vertical",scrolly:!1,element:this.options.container||this,items:[{el:this.popupView}]}),this._rendered=!0)},_hideIf:function(e,t){if(e&&(!0!==t&&this.element.find(e.target).length>0||this.popupView&&this.popupView.element.find(e.target).length>0||"CodeMirror-cursor"===e.target.className||BI.Widget._renderEngine.createElement(e.target).closest(".CodeMirror-hints").length>0)){var i=this.options.direction.split(",");(BI.contains(i,"innerLeft")||BI.contains(i,"innerRight"))&&(this.adjustWidth(),this.adjustHeight())}else{if(!1!==this.options.hideChecker.apply(this,[e]))return this._hideView(),!0}},_hideView:function(){this.fireEvent(BI.Combo.EVENT_BEFORE_HIDEVIEW),!0===this.options.destroyWhenHide?(this.popupView&&this.popupView.destroy(),this.popupView=null,this._rendered=!1):this.popupView&&this.popupView.invisible(),this.element.removeClass(this.options.comboClass),delete o[this.getName()],BI.Widget._renderEngine.createElement(document).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()),this.fireEvent(BI.Combo.EVENT_AFTER_HIDEVIEW)},_popupView:function(e){var t=this;this._assertPopupViewRender(),this.fireEvent(BI.Combo.EVENT_BEFORE_POPUPVIEW),this.popupView.css({left:-999999999,top:-99999999}),this.popupView.visible(),BI.each(o,(function(i,s){i!==t.getName()&&s&&!0===s._hideIf(e,!0)&&delete o[i]})),this.options.hideWhenAnotherComboOpen&&(o[this.getName()]=this),this.adjustWidth(e),this.adjustHeight(e),this.element.addClass(this.options.comboClass),BI.Widget._renderEngine.createElement(document).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()),BI.Widget._renderEngine.createElement(document).bind("mousedown."+this.getName(),BI.bind(this._hideIf,this)).bind("mousewheel."+this.getName(),BI.bind(this._hideIf,this)),this.fireEvent(BI.Combo.EVENT_AFTER_POPUPVIEW)},adjustWidth:function(e){var t=this.options;if(this.popupView&&!0===t.isNeedAdjustWidth){this.resetListWidth("");var i=this.popupView.element.outerWidth(),o=this.element.outerWidth()||t.width;i>o+80?o+=80:i>o&&(o=i),this.resetListWidth(o<100?100:o)}},adjustHeight:function(e){var t=this.options,i={top:0,adaptHeight:0,left:0};if(this.popupView){var o=this.popupView.isVisible();this.popupView.visible();var s=t.belowMouse&&BI.isNotNull(e)?{element:{offset:function(){return{left:e.pageX,top:e.pageY}},bounds:function(){return{x:e.offsetX,y:e.offsetY,width:0,height:24}},outerWidth:function(){return 0},outerHeight:function(){return 24}}}:this.combo;switch(t.direction){case"bottom":case"bottom,right":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["bottom","top","right","left"],t.offsetStyle);break;case"top":case"top,right":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["top","bottom","right","left"],t.offsetStyle);break;case"left":case"left,bottom":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["left","right","bottom","top"],t.offsetStyle);break;case"right":case"right,bottom":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","bottom","top"],t.offsetStyle);break;case"top,left":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["top","bottom","left","right"],t.offsetStyle);break;case"bottom,left":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["bottom","top","left","right"],t.offsetStyle);break;case"left,top":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["left","right","top","bottom"],t.offsetStyle);break;case"right,top":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","top","bottom"],t.offsetStyle);break;case"right,innerRight":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","innerRight","innerLeft","bottom","top"],t.offsetStyle);break;case"right,innerLeft":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","innerLeft","innerRight","bottom","top"],t.offsetStyle);break;case"innerRight":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["innerRight","innerLeft","right","left","bottom","top"],t.offsetStyle);break;case"innerLeft":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["innerLeft","innerRight","left","right","bottom","top"],t.offsetStyle);break;case"top,custom":case"custom,top":i=BI.DOM.getTopAdaptPosition(s,this.popupView,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight);break;case"custom,bottom":case"bottom,custom":i=BI.DOM.getBottomAdaptPosition(s,this.popupView,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight);break;case"left,custom":case"custom,left":delete(i=BI.DOM.getLeftAdaptPosition(s,this.popupView,t.adjustXOffset||t.adjustLength)).top,delete i.adaptHeight;break;case"custom,right":case"right,custom":delete(i=BI.DOM.getRightAdaptPosition(s,this.popupView,t.adjustXOffset||t.adjustLength)).top,delete i.adaptHeight}"adaptHeight"in i&&this.resetListHeight(i.adaptHeight),"left"in i&&this.popupView.element.css({left:i.left}),"top"in i&&this.popupView.element.css({top:i.top}),this.position=i,this.popupView.setVisible(o)}},resetListHeight:function(e){this._assertPopupView(),this.popupView.resetHeight&&this.popupView.resetHeight(e)},resetListWidth:function(e){this._assertPopupView(),this.popupView.resetWidth&&this.popupView.resetWidth(e)},populate:function(e){this._assertPopupView(),this.popupView.populate.apply(this.popupView,arguments),this.combo.populate&&this.combo.populate.apply(this.combo,arguments)},_setEnable:function(e){BI.Combo.superclass._setEnable.apply(this,arguments),!0===e?this.element.removeClass("base-disabled disabled"):!1===e&&this.element.addClass("base-disabled disabled"),!e&&this.element.removeClass(this.options.hoverClass),!e&&this.isViewVisible()&&this._hideView()},setValue:function(e){this.combo.setValue(e),BI.isNull(this.popupView)?this.options.popup.value=e:this.popupView.setValue(e)},getValue:function(){return BI.isNull(this.popupView)?this.options.popup.value:this.popupView.getValue()},isViewVisible:function(){return this.isEnabled()&&this.combo.isEnabled()&&!!this.popupView&&this.popupView.isVisible()},showView:function(e){this.isEnabled()&&this.combo.isEnabled()&&!this.isViewVisible()&&this._popupView(e)},hideView:function(){this._hideView()},getView:function(){return this.popupView},getPopupPosition:function(){return this.position},toggle:function(){this._toggle()},destroyed:function(){BI.Widget._renderEngine.createElement(document).unbind("click."+this.getName()).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()).unbind("mouseenter."+this.getName()).unbind("mousemove."+this.getName()).unbind("mouseleave."+this.getName()).unbind("blur."+this.getName()),BI.Resizers.remove(this.getName()),this.popupView&&this.popupView._destroy(),delete o[this.getName()]}}),BI.Combo.EVENT_TRIGGER_CHANGE="EVENT_TRIGGER_CHANGE",BI.Combo.EVENT_CHANGE="EVENT_CHANGE",BI.Combo.EVENT_EXPAND="EVENT_EXPAND",BI.Combo.EVENT_COLLAPSE="EVENT_COLLAPSE",BI.Combo.EVENT_AFTER_INIT="EVENT_AFTER_INIT",BI.Combo.EVENT_BEFORE_POPUPVIEW="EVENT_BEFORE_POPUPVIEW",BI.Combo.EVENT_AFTER_POPUPVIEW="EVENT_AFTER_POPUPVIEW",BI.Combo.EVENT_BEFORE_HIDEVIEW="EVENT_BEFORE_HIDEVIEW",BI.Combo.EVENT_AFTER_HIDEVIEW="EVENT_AFTER_HIDEVIEW",BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0,t.className="designer.components.phone.editor.item",t.Widget=BI.inherit(BI.BasicButton,{props:{baseCls:"designer-login-login-body",label:"",text:""},render:function(){var e=this.options;return{type:"bi.htape",items:[{el:{type:"bi.label",text:e.label,title:e.label,textAlign:"left"},lgap:10,rgap:5},{el:{type:"bi.label",text:e.text,textAlign:"right"},width:32,rgap:10}]}},doClick:function(){BI.SingleSelectItem.superclass.doClick.apply(this,arguments),this.isValid()&&this.fireEvent("EVENT_CHANGE",this.isSelected(),this)},setSelected:function(e){BI.SingleSelectItem.superclass.setSelected.apply(this,arguments)},getValue:function(){return this.options.value}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0);t.className="designer.user.account.setting.captcha",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},render:function(){var e=this;this.options;return{type:o.TextButton,text:BI.i18nText("Designer-Login_Code_Request"),cls:"designer-login-border-bottom designer-login-code-text",handler:function(){e.setButtonEnable(!1),e.fireEvent("EVENT_SEND")},ref:function(t){e.getButton=t}}},setButtonEnable:function(e){this.captchaTime&&(e=!1),this.getButton.setEnable(e)},regainCaptcha:function(){var e=this,t=0;window.clearInterval(e.captchaTime),this.captchaTime=window.setInterval((function(){if(60===t)return window.clearInterval(e.captchaTime),e.captchaTime=null,e.getButton.setText(BI.i18nText("Designer-Login_Code_Request")),void e.setButtonEnable(!0);e.getButton.setText(BI.i18nText("Designer-Login_Code_Request_Again")+"("+(60-t)+")"),t++}),1e3),this.setButtonEnable(!1)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0,t.className="designer.login.model.sms_method",t.Model=BI.inherit(Fix.Model,{context:[""],state:function(){return{errMessage:"",isRegister:!1,regToken:""}},actions:{setErrMessage:function(e){this.model.errMessage=e},setRegister:function(e){this.model.isRegister=e},setRegToken:function(e){this.model.regToken=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){}]); \ No newline at end of file +!function(e){var t={};function i(o){if(t[o])return t[o].exports;var s=t[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,i),s.l=!0,s.exports}i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)i.d(o,s,function(t){return e[t]}.bind(null,s));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=4)}([function(e,t,i){"use strict";var o=this&&this.__createBinding||(Object.create?function(e,t,i,o){o===undefined&&(o=i),Object.defineProperty(e,o,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,o){o===undefined&&(o=i),e[o]=t[i]}),s=this&&this.__exportStar||function(e,t){for(var i in e)"default"===i||t.hasOwnProperty(i)||o(t,e,i)};Object.defineProperty(t,"__esModule",{value:!0}),s(i(5),t)},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=window.DesignerLoginHelper,s=function(){function e(){}return e.prototype.getParams=function(){return{designerLoginSource:window.designerLoginSource||"0",lastLoginType:window.lastLoginType||"-1",lastLoginAccount:window.lastLoginAccount||""}},e.prototype.closeWindow=function(e){o&&o.closeWindow(e)},e.prototype.serviceHref=function(){o?o.serviceHref():window.open("https://bbs.fanruan.com/thread-102821-1-1.html")},e.prototype.forgetHref=function(){o?o.forgetHref():window.open("https://id.fanruan.com/forget/forget.php?clue=activityf")},e.prototype.normalLogin=function(e,t,i){o?o.normalLogin(e,t,i):i(-1)},e.prototype.sendCaptcha=function(e,t,i){o?o.sendCaptcha(e,t,i):i(-1)},e.prototype.smsLogin=function(e,t,i,s){o?o.smsLogin(e,t,i,s):s(null)},e.prototype.smsRegister=function(e,t,i,s,n){o?o.smsRegister(e,t,i,s,n):n(-1)},e.prototype.resize=function(e,t){o&&o.resize(e,t)},e}();t["default"]=new s},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BBS_ERROR_CODE=t.NORMAL_LOGIN_RESULT=t.REGION=t.LOGIN=void 0,t.LOGIN={NORMAL_METHOD:"normal",SMS_METHOD:"sms",TABS:{LOGIN:"login",FORGET_PASSWORD:"forget",RESET_PASSWORD:"reset",REGISTER:"register"}},t.REGION=[{value:"+86",text:"Designer-Basic_Chinese_Mainland"},{value:"+886",text:"Designer-Basic_Chinese_Taiwan"},{value:"+852",text:"Designer-Basic_Chinese_Hong_Kong"},{value:"+853",text:"Designer-Basic_Chinese_Macao"},{value:"+90",text:"Designer-Basic_Turkey"},{value:"+82",text:"Designer-Basic_South_Korea"},{value:"+81",text:"Designer-Basic_Japan"},{value:"+65",text:"Designer-Basic_Singapore"},{value:"+60",text:"Designer-Basic_Malaysia"}],t.NORMAL_LOGIN_RESULT=[{status:0,message:"Designer-Login_Internal_Error"},{status:-1,message:"Designer-Login_Store_User_Not_Exist"},{status:-2,message:"Designer-Login_Store_User_Password_Error"},{status:-3,message:"Designer-Login_Unexpected_Error"},{status:-4,message:"Designer-Login_Network_Connected_Failed"},{status:-5,message:"Designer-Login_Failed_Exceed_Limit"}],t.BBS_ERROR_CODE=[{status:0,message:"Designer-Login_Internal_Error"},{status:-1,message:"Designer-BBS_Register_Timeout"},{status:-2,message:"Designer-BBS_Phone_Is_Register"},{status:-3,message:"Designer-BBS_Captcha_Send_Exceed_Limit"},{status:-4,message:"Designer-BBS_Phone_Format_Error"},{status:-100,message:"Designer-BBS_Captcha_Out_Of_Date"},{status:-101,message:"Designer-BBS_Captcha_Try_Exceed_Limit"},{status:-102,message:"Designer-BBS_Captcha_Error"},{status:-104,message:"Designer-BBS_Username_Format_Error"},{status:-103,message:"Designer-BBS_Please_Enter_Correct_Phone"},{status:-105,message:"Designer-BBS_Username_Too_Short"},{status:-106,message:"Designer-BBS_Username_Too_Long"},{status:-107,message:"Designer-BBS_Phone_Is_Register"},{status:-108,message:"Designer-BBS_Username_Is_Register"}]},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getError=void 0,t.getError=function(e,t){var i=BI.find(e,(function(e,i){return i.status===t}));return i&&i.message?i.message:""}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=i(0),s=i(6);BI.addI18n(Store.i18n),BI.createWidget({type:o.Vertical,element:"body",items:[{type:s["default"]}]})},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ListView=t.VirtualGroup=t.LeftRightVerticalAdapt=t.Left=t.Horizontal=t.Vertical=t.Absolute=t.Layout=t.Htape=t.CenterAdapt=t.Vtape=t.HorizontalAdapt=t.VerticalAdapt=t.BubbleCombo=t.Img=t.Tab=t.SingleSelectInsertCombo=t.SingleSelectRadioItem=t.MultiTreePopupView=t.Editor=t.NicEditor=t.RichEditor=t.MultiTreeCombo=t.DynamicDateTimeCombo=t.DynamicDateCombo=t.BarPopOver=t.MultiSelectItem=t.TextAreaEditor=t.AllValueChooserCombo=t.ButtonGroup=t.MultiSelectInsertCombo=t.TextEditor=t.Button=t.SignEditor=t.MultiFileEditor=t.SmallTextEditor=t.HtmlLabel=t.Label=t.DownListCombo=t.TextButton=t.IconChangeButton=t.IconButton=t.IconTextIconItem=t.IconTextItem=void 0,t.IconTextItem="bi.icon_text_item",t.IconTextIconItem="bi.icon_text_icon_item",t.IconButton="bi.icon_button",t.IconChangeButton="bi.icon_change_button",t.TextButton="bi.text_button",t.DownListCombo="bi.down_list_combo",t.Label="bi.label",t.HtmlLabel="bi.html_label",t.SmallTextEditor="bi.small_text_editor",t.MultiFileEditor="bi.multifile_editor",t.SignEditor="bi.sign_editor",t.Button="bi.button",t.TextEditor="bi.text_editor",t.MultiSelectInsertCombo="bi.multi_select_insert_combo",t.ButtonGroup="bi.button_group",t.AllValueChooserCombo="bi.all_value_chooser_combo",t.TextAreaEditor="bi.textarea_editor",t.MultiSelectItem="bi.multi_select_item",t.BarPopOver="bi.bar_popover",t.DynamicDateCombo="bi.dynamic_date_combo",t.DynamicDateTimeCombo="bi.dynamic_date_time_combo",t.MultiTreeCombo="bi.multi_tree_combo",t.RichEditor="bi.rich_editor",t.NicEditor="bi.nic_editor",t.Editor="bi.editor",t.MultiTreePopupView="bi.multi_tree_popup_view",t.SingleSelectRadioItem="bi.single_select_radio_item",t.SingleSelectInsertCombo="bi.single_select_insert_combo",t.Tab="bi.tab",t.Img="bi.img",t.BubbleCombo="bi.bubble_combo",t.VerticalAdapt="bi.vertical_adapt",t.HorizontalAdapt="bi.horizontal_adapt",t.Vtape="bi.vtape",t.CenterAdapt="bi.center_adapt",t.Htape="bi.htape",t.Layout="bi.layout",t.Absolute="bi.absolute",t.Vertical="bi.vertical",t.Horizontal="bi.horizontal",t.Left="bi.left",t.LeftRightVerticalAdapt="bi.left_right_vertical_adapt",t.VirtualGroup="bi.virtual_group",t.ListView="bi.list_view"},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(7),n=i(8),r=i(9),a=i(11);i(25),t.className="designer.login.login",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login",width:420},_store:function(){return BI.Models.getModel(s["default"])},watch:{loading:function(e){this.loading.setVisible(e)}},render:function(){return{type:o.Vertical,cls:"designer-login",items:[{el:{type:o.HorizontalAdapt,items:[{type:n["default"],rgap:14,tgap:14}]}},{el:{type:o.Vertical,items:[{type:r["default"]},{type:a["default"]}]},lgap:15,rgap:15,bgap:15}]}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});BI.model("designer.login.login.model",BI.inherit(Fix.Model,{childContext:["loading"],state:function(){return{loading:!1}}})),t["default"]="designer.login.login.model"},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(1);t.className="designer.login.login.close.button",t.Widget=BI.inherit(BI.Widget,{render:function(){return{type:o.TextButton,text:String.fromCharCode(10005),cls:"background-login-close",width:18.38,height:18.38,handler:function(){s["default"].closeWindow(!1)}}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0);i(10),t.className="designer.login.login.title",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-title"},render:function(){return{type:o.Label,text:BI.i18nText("Designer-Login_Title"),cls:"bi-font-bold",bgap:10}}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(12);i(13);var n=i(14),r=i(16),a=i(18),l=i(2),u=i(1),d=249.64,g=331.64,c=422,p=478,h=560;t.className="designer.login.login.body",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(s["default"])},watch:{loginMethod:function(e){this.tabOption.setValue(e),this.tab.setSelect(e),this.foot.setLoginMethod(e),this.refreshLoginButton(),e===l.LOGIN.NORMAL_METHOD?(this.tab.setHeight(d),u["default"].resize(c,p)):this.model.expand&&(u["default"].resize(c,h),this.tab.setHeight(g))},approve:function(e){this.refreshLoginButton()},expand:function(e){e&&(u["default"].resize(c,h),this.tab.setHeight(g))}},render:function(){var e=this;return{type:o.Vertical,cls:"designer-login-body",items:[{type:o.ButtonGroup,value:this.model.loginMethod,ref:function(t){e.tabOption=t},layouts:[{type:o.HorizontalAdapt}],items:[{cls:"designer-login-change-mode bi-list-item-effect bi-border-bottom bi-font-bold",width:70,height:28,value:l.LOGIN.SMS_METHOD,text:BI.i18nText("Designer-Login_Sms")},{cls:"designer-login-change-mode bi-list-item-effect bi-border-bottom bi-font-bold",width:70,height:28,value:l.LOGIN.NORMAL_METHOD,text:BI.i18nText("Designer-Login_Normal")}],listeners:[{eventName:BI.ButtonGroup.EVENT_CHANGE,action:function(t){e.store.setLoginMethod(t)}}],tgap:24,lgap:75,rgap:75},{type:o.CenterAdapt,tgap:35,items:[{type:o.Tab,cardCreator:BI.bind(this.createCard,this),showIndex:this.model.loginMethod,ref:function(t){e.tab=t},height:d,width:280}]},{type:n["default"],lgap:50,rgap:50,bgap:30,ref:function(t){e.foot=t},refreshStatus:function(t){e.store.setApprove(t)}}]}},mounted:function(){var e=u["default"].getParams(),t=e.designerLoginSource,i=e.lastLoginType;if("2"===t){var o="0"===i?l.LOGIN.NORMAL_METHOD:l.LOGIN.SMS_METHOD;this.store.setLoginMethod(o)}},createCard:function(e){var t=this;switch(e){case l.LOGIN.NORMAL_METHOD:return{type:r["default"],ref:function(e){t.normalMethod=e}};case l.LOGIN.SMS_METHOD:default:return{type:a["default"],ref:function(e){t.smsMethod=e},expand:function(){t.store.setExpand(!0)}}}},refreshLoginButton:function(){this.model.loginMethod===l.LOGIN.NORMAL_METHOD?this.normalMethod.setApprove(this.model.approve):this.smsMethod.setApprove(this.model.approve)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0;var o=i(2);t.className="designer.login.model.login.body",t.Model=BI.inherit(Fix.Model,{context:["loading"],state:function(){return{loginMethod:o.LOGIN.SMS_METHOD,approve:!0,expand:!1}},actions:{setLoginMethod:function(e){this.model.loginMethod=e},setApprove:function(e){this.model.approve=e},setExpand:function(e){this.model.expand=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(1),s=i(0);i(15);var n=i(2);t.className="designer.login.login.foot",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-foot"},render:function(){var e=this,t=this.options;return{type:s.LeftRightVerticalAdapt,items:{left:[{type:s.MultiSelectItem,width:30,selected:!0,handler:function(){t.refreshStatus(this.isSelected())}},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:BI.i18nText("Designer-Login_I_Have_Read")},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:"《"},{type:s.TextButton,cls:"login-link",textAlign:"left",text:BI.i18nText("Designer-Login_Service_Terms"),handler:function(){o["default"].serviceHref()}},{type:s.Label,cls:"login-foot-text",textAlign:"left",text:"》"}],right:[{type:s.TextButton,cls:"login-link",textAlign:"right",text:BI.i18nText("Designer-Login_Forget_Password"),invisible:!0,tgap:2,ref:function(t){e.forgetPassword=t},handler:function(){o["default"].forgetHref()}}]}}},setLoginMethod:function(e){e===n.LOGIN.NORMAL_METHOD?this.forgetPassword.setVisible(!0):this.forgetPassword.setVisible(!1)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(3),n=i(1),r=i(17),a=i(2);t.className="designer.login.login.normal",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(r["default"])},watch:{errMessage:function(e){this.errMessage.setText(e)}},render:function(){var e=this;return{type:o.Vertical,items:[{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_User_Name"),bgap:3},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-username",watermark:BI.i18nText("Designer-Login_User_Name_Hint"),inputType:"text",allowBlank:!0,height:40,ref:function(t){e.userName=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Password"),bgap:3},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Password_Hint"),inputType:"password",allowBlank:!0,height:40,ref:function(t){e.password=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,cls:"designer-login-error-message",textAlign:"center",text:"",height:20,bgap:10,ref:function(t){e.errMessage=t}},{type:o.Button,cls:"login-login-button bi-font-bold",text:BI.i18nText("Designer-Login"),level:"common",height:40,ref:function(t){e.loginButton=t},handler:function(){e.login()}}]}},mounted:function(){var e=this;this.element.keyup((function(t){13===t.keyCode&&e.login()}));var t=n["default"].getParams(),i=t.designerLoginSource,o=t.lastLoginType,s=t.lastLoginAccount;"2"===i&&"0"===o&&e.userName.setValue(s)},checkUsername:function(){var e=this.userName.getValue();e&&this.userName.setValue(e.replace(/\s+/g,""))},login:function(){var e=this;e.checkUsername();var t=this.userName.getValue(),i=this.password.getValue();t?i?n["default"].normalLogin(t,i,(function(t){var i=parseInt(t,10);if(i>0)n["default"].closeWindow(!0);else{var o=s.getError(a.NORMAL_LOGIN_RESULT,i);o&&e.store.setErrMessage(BI.i18nText(o))}})):this.store.setErrMessage(BI.i18nText("Designer-Login_Password_Not_Null")):this.store.setErrMessage(BI.i18nText("Designer-Login_Username_Not_Null"))},setApprove:function(e){this.loginButton.setEnable(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0,t.className="designer.login.model.normal_method",t.Model=BI.inherit(Fix.Model,{context:[""],state:function(){return{errMessage:""}},actions:{setErrMessage:function(e){this.model.errMessage=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0),s=i(19),n=i(22),r=i(23),a=i(2),l=i(24),u=i(1),d=i(3);t.className="designer.login.login.sms",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},_store:function(){return BI.Stores.getStore(l["default"])},watch:{errMessage:function(e){this.errMessage.setText(e)},isRegister:function(e){var t=this.options;e&&(t.expand(),this.password.setVisible(!0),this.passwordLabel.setVisible(!0))}},render:function(){var e=this,t=this;return{type:o.Vertical,items:[{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Phone"),bgap:3},{type:o.HorizontalAdapt,bgap:7,items:[{type:s["default"],height:42,textFormatter:function(e){var i=t.getNumberTypeItem(e);return{value:i.value,text:BI.i18nText(i.text)}},value:a.REGION[0].value,items:BI.map(a.REGION,(function(e,t){return{type:n["default"],value:t.value,label:BI.i18nText(t.text),text:t.value}})),ref:function(t){e.regionCode=t}},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-username",watermark:BI.i18nText("Designer-Login_Phone_Hint"),inputType:"text",allowBlank:!0,height:40,ref:function(t){e.phone=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Code"),bgap:3},{type:o.Horizontal,bgap:7,items:[{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Code_Hint"),inputType:"text",allowBlank:!0,height:40,width:190,ref:function(t){e.code=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:r["default"],height:40,width:90,ref:function(t){e.accountCaptcha=t},listeners:[{eventName:"EVENT_SEND",action:function(){t.sendCaptcha()}}]}]},{type:o.Label,textAlign:"left",cls:"designer-login-text",text:BI.i18nText("Designer-Login_Password"),bgap:3,invisible:!0,ref:function(t){e.passwordLabel=t}},{type:o.Editor,cls:"bi-border-bottom designer-login-editor-password",watermark:BI.i18nText("Designer-Login_Password_Setting_Hint"),inputType:"password",allowBlank:!0,height:40,invisible:!0,ref:function(t){e.password=t},listeners:[{eventName:"EVENT_CHANGE",action:function(){e.store.setErrMessage("")}}]},{type:o.Label,cls:"designer-login-error-message",textAlign:"center",text:"",height:20,bgap:11,ref:function(t){e.errMessage=t}},{type:o.Button,cls:"login-login-button bi-font-bold",text:BI.i18nText("Designer-Login_Register_Or_Login"),level:"common",height:40,ref:function(t){e.loginButton=t},handler:function(){e.login()}}]}},mounted:function(){var e=this;this.element.keyup((function(t){13===t.keyCode&&e.login()}));var t=u["default"].getParams(),i=t.designerLoginSource,o=t.lastLoginType,s=t.lastLoginAccount;if("2"===i&&"1"===o){var n=s.split("-")[0],r=s.split("-")[1];e.regionCode.setValue(n),e.phone.setValue(r)}},getNumberTypeItem:function(e){return BI.find(a.REGION,(function(t,i){return e===i.value}))||{}},checkPhone:function(){var e=this.phone.getValue();e&&this.phone.setValue(e.replace(/\s+/g,""))},login:function(){var e=this,t=this;t.checkPhone();var i=this.phone.getValue(),o=this.code.getValue();if(i)if(o){var s=this.regionCode.getValue();if(this.model.isRegister){var n=this.password.getValue();if(!n)return void this.store.setErrMessage(BI.i18nText("Designer-Login_Password_Not_Null"));var r=this.model.regToken;if(!r)return void this.store.setErrMessage(BI.i18nText("Designer-Login_Token_Request_Failed"));u["default"].smsRegister(s,i,n,r,(function(e){var i=parseInt(e,10);if(i>0)u["default"].closeWindow(!0);else{var o=d.getError(a.BBS_ERROR_CODE,i);o&&t.store.setErrMessage(BI.i18nText(o))}}))}else u["default"].smsLogin(s,i,o,(function(i){var o=JSON.parse(i);if(o.status>0)if(!0===o.register){var s=o.regtoken;s?(t.store.setRegister(!0),t.store.setRegToken(s)):e.store.setErrMessage(BI.i18nText("Designer-Login_Token_Request_Failed"))}else u["default"].closeWindow(!0);else{var n=d.getError(a.BBS_ERROR_CODE,o.status);n&&t.store.setErrMessage(BI.i18nText(n))}}))}else this.store.setErrMessage(BI.i18nText("Designer-Login_Code_Not_Null"));else this.store.setErrMessage(BI.i18nText("Designer-Login_Phone_Not_Null"))},sendCaptcha:function(){var e=this;e.checkPhone();var t=this.phone.getValue();if(!t)return e.accountCaptcha.setButtonEnable(!0),void this.store.setErrMessage(BI.i18nText("Designer-Login_Phone_Not_Null"));var i=this.regionCode.getValue();u["default"].sendCaptcha(i,t,(function(t){var i=parseInt(t,10);if(1===i)e.accountCaptcha.regainCaptcha();else{if(e.accountCaptcha.setButtonEnable(!0),0===i)return void e.store.setErrMessage(BI.i18nText("Designer-BBS_Please_Enter_Correct_Phone"));var o=d.getError(a.BBS_ERROR_CODE,i);o&&e.store.setErrMessage(BI.i18nText(o))}}))},setApprove:function(e){this.loginButton.setEnable(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(20),s=i(21);t.className="designer.left_right_text_value_combo",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"",height:24,chooseType:BI.ButtonGroup.CHOOSE_TYPE_SINGLE,textFormatter:function(e){return e},value:""},render:function(){var e=this,t=this.options;return{type:s["default"],container:t.container,adjustLength:2,ref:function(t){e.combo=t},el:{type:o["default"],cls:"text-value-trigger",items:t.items,height:t.height-2,value:t.textFormatter(t.value),ref:function(t){e.trigger=t}},popup:{el:{type:"bi.text_value_combo_popup",chooseType:t.chooseType,value:t.value,items:t.items,ref:function(t){e.popup=t},listeners:[{eventName:BI.TextValueComboPopup.EVENT_CHANGE,action:function(){e.setValue(e.getValue()),e.combo.hideView(),e.fireEvent("EVENT_CHANGE",arguments)}},{eventName:BI.Controller.EVENT_CHANGE,action:function(){e.fireEvent(BI.Controller.EVENT_CHANGE,arguments)}}]},value:t.value,maxHeight:240,minHeight:25}}},setValue:function(e){this.combo.setValue(e),this.trigger.setValue(this.options.textFormatter(e))},getValue:function(){var e=this.combo.getValue();return BI.isNull(e)?"":BI.isArray(e)?e[0]:e},populate:function(e){this.options.items=e,this.combo.populate(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0,t.className="designer.left_right_text_value_combo_trigger",t.Widget=BI.inherit(BI.Trigger,{props:{baseCls:"",value:{}},render:function(){var e=this,t=this.options,i=t.value;return{type:"bi.htape",cls:"bi-border-bottom bi-border-radius",items:[{type:"bi.label",text:i.text,title:function(){return e.textRow.getText()},height:t.height,hgap:3,textAlign:"left",ref:function(t){e.textRow=t}},{type:"bi.label",text:i.value,height:t.height,width:32,textAlign:"right",ref:function(t){e.valueRow=t}},{type:"bi.trigger_icon_button",width:t.triggerWidth||t.height}]}},setValue:function(e){this.textRow.setText(e.text),this.valueRow.setText(e.value)},setText:function(e){this.textRow.setText(e)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o={};t.className="designer.login_combo",t.Widget=BI.inherit(BI.Widget,{_defaultConfig:function(){var e=BI.Combo.superclass._defaultConfig.apply(this,arguments);return BI.extend(e,{baseCls:(e.baseCls||"")+" bi-combo"+(BI.isIE()?" hack":""),attributes:{tabIndex:-1},trigger:"click",toggle:!0,direction:"bottom",logic:{dynamic:!0},container:null,isDefaultInit:!1,destroyWhenHide:!1,hideWhenAnotherComboOpen:!1,isNeedAdjustHeight:!0,isNeedAdjustWidth:!0,stopEvent:!1,stopPropagation:!1,adjustLength:0,adjustXOffset:0,adjustYOffset:0,hideChecker:BI.emptyFn,offsetStyle:"left",el:{},popup:{},comboClass:"bi-combo-popup",hoverClass:"bi-combo-hover",belowMouse:!1})},_init:function(){BI.Combo.superclass._init.apply(this,arguments);var e=this,t=this.options;this._initCombo(),this._initPullDownAction(),this.combo.on(BI.Controller.EVENT_CHANGE,(function(t,i,o){e.isEnabled()&&e.isValid()&&(t===BI.Events.EXPAND&&e._popupView(),t===BI.Events.COLLAPSE&&e._hideView(),t===BI.Events.EXPAND&&(e.fireEvent(BI.Controller.EVENT_CHANGE,arguments),e.fireEvent(BI.Combo.EVENT_EXPAND)),t===BI.Events.COLLAPSE&&(e.fireEvent(BI.Controller.EVENT_CHANGE,arguments),e.isViewVisible()&&e.fireEvent(BI.Combo.EVENT_COLLAPSE)),t===BI.Events.CLICK&&e.fireEvent(BI.Combo.EVENT_TRIGGER_CHANGE,o))})),e.element.on("mouseenter."+e.getName(),(function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&e.element.addClass(t.hoverClass)})),e.element.on("mouseleave."+e.getName(),(function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&e.element.removeClass(t.hoverClass)})),BI.createWidget(BI.extend({element:this},BI.LogicFactory.createLogic("vertical",BI.extend(t.logic,{items:[{el:this.combo}]})))),t.isDefaultInit&&this._assertPopupView(),BI.Resizers.add(this.getName(),BI.bind((function(e){this.isViewVisible()&&(BI.isNotNull(e)?this._hideIf(e):this._hideView())}),this))},_toggle:function(e){this._assertPopupViewRender(),this.popupView.isVisible()?this._hideView(e):this.isEnabled()&&this._popupView(e)},_initPullDownAction:function(){var e=this,t=this.options,i=(this.options.trigger||"").split(","),o=function(e){t.stopEvent&&e.stopEvent(),t.stopPropagation&&e.stopPropagation()},s=!1;function n(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&!0===t.toggle&&(e._hideView(i),e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.COLLAPSE,"",e.combo),e.fireEvent(BI.Combo.EVENT_COLLAPSE)),e.popupView&&e.popupView.element.off("mouseenter."+e.getName()).off("mouseleave."+e.getName()),s=!1}BI.each(i,(function(i,r){switch(r){case"hover":e.element.on("mouseenter."+e.getName(),(function(t){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(e._popupView(t),e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND))})),e.element.on("mouseleave."+e.getName(),(function(t){e.popupView&&(e.popupView.element.on("mouseenter."+e.getName(),(function(t){s=!0,e.popupView.element.on("mouseleave."+e.getName(),(function(e){n(e)})),e.popupView.element.off("mouseenter."+e.getName())})),BI.defer((function(){s||n(t)}),50))}));break;case"click":var a=BI.debounce((function(i){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(t.toggle?e._toggle(i):e._popupView(i),e.isViewVisible()?(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND)):(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.COLLAPSE,"",e.combo),e.fireEvent(BI.Combo.EVENT_COLLAPSE)))}),BI.EVENT_RESPONSE_TIME,{leading:!0,trailing:!1});e.element.off(r+"."+e.getName()).on(r+"."+e.getName(),(function(e){a(e),o(e)}));break;case"click-hover":a=BI.debounce((function(t){e.isEnabled()&&e.isValid()&&e.combo.isEnabled()&&e.combo.isValid()&&(e._popupView(t),e.isViewVisible()&&(e.fireEvent(BI.Controller.EVENT_CHANGE,BI.Events.EXPAND,"",e.combo),e.fireEvent(BI.Combo.EVENT_EXPAND)))}),BI.EVENT_RESPONSE_TIME,{leading:!0,trailing:!1});e.element.off("click."+e.getName()).on("click."+e.getName(),(function(e){a(e),o(e)})),e.element.on("mouseleave."+e.getName(),(function(t){e.popupView&&(e.popupView.element.on("mouseenter."+e.getName(),(function(t){s=!0,e.popupView.element.on("mouseleave."+e.getName(),(function(e){n(e)})),e.popupView.element.off("mouseenter."+e.getName())})),BI.delay((function(){s||n(t)}),50))}))}}))},_initCombo:function(){this.combo=BI.createWidget(this.options.el,{value:this.options.value})},_assertPopupView:function(){var e=this,t=this.options;null==this.popupView&&(this.popupView=BI.createWidget(this.options.popup,{type:"bi.popup_view",value:t.value},this),this.popupView.on(BI.Controller.EVENT_CHANGE,(function(t,i,o){t===BI.Events.CLICK&&(e.combo.setValue(e.getValue()),e.fireEvent(BI.Combo.EVENT_CHANGE,i,o)),e.fireEvent(BI.Controller.EVENT_CHANGE,arguments)})),this.popupView.setVisible(!1),BI.nextTick((function(){e.fireEvent(BI.Combo.EVENT_AFTER_INIT)})))},_assertPopupViewRender:function(){this._assertPopupView(),this._rendered||(BI.createWidget({type:"bi.vertical",scrolly:!1,element:this.options.container||this,items:[{el:this.popupView}]}),this._rendered=!0)},_hideIf:function(e,t){if(e&&(!0!==t&&this.element.find(e.target).length>0||this.popupView&&this.popupView.element.find(e.target).length>0||"CodeMirror-cursor"===e.target.className||BI.Widget._renderEngine.createElement(e.target).closest(".CodeMirror-hints").length>0)){var i=this.options.direction.split(",");(BI.contains(i,"innerLeft")||BI.contains(i,"innerRight"))&&(this.adjustWidth(),this.adjustHeight())}else{if(!1!==this.options.hideChecker.apply(this,[e]))return this._hideView(),!0}},_hideView:function(){this.fireEvent(BI.Combo.EVENT_BEFORE_HIDEVIEW),!0===this.options.destroyWhenHide?(this.popupView&&this.popupView.destroy(),this.popupView=null,this._rendered=!1):this.popupView&&this.popupView.invisible(),this.element.removeClass(this.options.comboClass),delete o[this.getName()],BI.Widget._renderEngine.createElement(document).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()),this.fireEvent(BI.Combo.EVENT_AFTER_HIDEVIEW)},_popupView:function(e){var t=this;this._assertPopupViewRender(),this.fireEvent(BI.Combo.EVENT_BEFORE_POPUPVIEW),this.popupView.css({left:-999999999,top:-99999999}),this.popupView.visible(),BI.each(o,(function(i,s){i!==t.getName()&&s&&!0===s._hideIf(e,!0)&&delete o[i]})),this.options.hideWhenAnotherComboOpen&&(o[this.getName()]=this),this.adjustWidth(e),this.adjustHeight(e),this.element.addClass(this.options.comboClass),BI.Widget._renderEngine.createElement(document).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()),BI.Widget._renderEngine.createElement(document).bind("mousedown."+this.getName(),BI.bind(this._hideIf,this)).bind("mousewheel."+this.getName(),BI.bind(this._hideIf,this)),this.fireEvent(BI.Combo.EVENT_AFTER_POPUPVIEW)},adjustWidth:function(e){var t=this.options;if(this.popupView&&!0===t.isNeedAdjustWidth){this.resetListWidth("");var i=this.popupView.element.outerWidth(),o=this.element.outerWidth()||t.width;i>o+80?o+=80:i>o&&(o=i),this.resetListWidth(o<100?100:o)}},adjustHeight:function(e){var t=this.options,i={top:0,adaptHeight:0,left:0};if(this.popupView){var o=this.popupView.isVisible();this.popupView.visible();var s=t.belowMouse&&BI.isNotNull(e)?{element:{offset:function(){return{left:e.pageX,top:e.pageY}},bounds:function(){return{x:e.offsetX,y:e.offsetY,width:0,height:24}},outerWidth:function(){return 0},outerHeight:function(){return 24}}}:this.combo;switch(t.direction){case"bottom":case"bottom,right":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["bottom","top","right","left"],t.offsetStyle);break;case"top":case"top,right":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["top","bottom","right","left"],t.offsetStyle);break;case"left":case"left,bottom":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["left","right","bottom","top"],t.offsetStyle);break;case"right":case"right,bottom":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","bottom","top"],t.offsetStyle);break;case"top,left":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["top","bottom","left","right"],t.offsetStyle);break;case"bottom,left":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight,["bottom","top","left","right"],t.offsetStyle);break;case"left,top":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["left","right","top","bottom"],t.offsetStyle);break;case"right,top":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","top","bottom"],t.offsetStyle);break;case"right,innerRight":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","innerRight","innerLeft","bottom","top"],t.offsetStyle);break;case"right,innerLeft":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["right","left","innerLeft","innerRight","bottom","top"],t.offsetStyle);break;case"innerRight":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["innerRight","innerLeft","right","left","bottom","top"],t.offsetStyle);break;case"innerLeft":i=BI.DOM.getComboPosition(s,this.popupView,t.adjustXOffset||t.adjustLength,t.adjustYOffset,t.isNeedAdjustHeight,["innerLeft","innerRight","left","right","bottom","top"],t.offsetStyle);break;case"top,custom":case"custom,top":i=BI.DOM.getTopAdaptPosition(s,this.popupView,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight);break;case"custom,bottom":case"bottom,custom":i=BI.DOM.getBottomAdaptPosition(s,this.popupView,t.adjustYOffset||t.adjustLength,t.isNeedAdjustHeight);break;case"left,custom":case"custom,left":delete(i=BI.DOM.getLeftAdaptPosition(s,this.popupView,t.adjustXOffset||t.adjustLength)).top,delete i.adaptHeight;break;case"custom,right":case"right,custom":delete(i=BI.DOM.getRightAdaptPosition(s,this.popupView,t.adjustXOffset||t.adjustLength)).top,delete i.adaptHeight}"adaptHeight"in i&&this.resetListHeight(i.adaptHeight),"left"in i&&this.popupView.element.css({left:i.left}),"top"in i&&this.popupView.element.css({top:i.top}),this.position=i,this.popupView.setVisible(o)}},resetListHeight:function(e){this._assertPopupView(),this.popupView.resetHeight&&this.popupView.resetHeight(e)},resetListWidth:function(e){this._assertPopupView(),this.popupView.resetWidth&&this.popupView.resetWidth(e)},populate:function(e){this._assertPopupView(),this.popupView.populate.apply(this.popupView,arguments),this.combo.populate&&this.combo.populate.apply(this.combo,arguments)},_setEnable:function(e){BI.Combo.superclass._setEnable.apply(this,arguments),!0===e?this.element.removeClass("base-disabled disabled"):!1===e&&this.element.addClass("base-disabled disabled"),!e&&this.element.removeClass(this.options.hoverClass),!e&&this.isViewVisible()&&this._hideView()},setValue:function(e){this.combo.setValue(e),BI.isNull(this.popupView)?this.options.popup.value=e:this.popupView.setValue(e)},getValue:function(){return BI.isNull(this.popupView)?this.options.popup.value:this.popupView.getValue()},isViewVisible:function(){return this.isEnabled()&&this.combo.isEnabled()&&!!this.popupView&&this.popupView.isVisible()},showView:function(e){this.isEnabled()&&this.combo.isEnabled()&&!this.isViewVisible()&&this._popupView(e)},hideView:function(){this._hideView()},getView:function(){return this.popupView},getPopupPosition:function(){return this.position},toggle:function(){this._toggle()},destroyed:function(){BI.Widget._renderEngine.createElement(document).unbind("click."+this.getName()).unbind("mousedown."+this.getName()).unbind("mousewheel."+this.getName()).unbind("mouseenter."+this.getName()).unbind("mousemove."+this.getName()).unbind("mouseleave."+this.getName()).unbind("blur."+this.getName()),BI.Resizers.remove(this.getName()),this.popupView&&this.popupView._destroy(),delete o[this.getName()]}}),BI.Combo.EVENT_TRIGGER_CHANGE="EVENT_TRIGGER_CHANGE",BI.Combo.EVENT_CHANGE="EVENT_CHANGE",BI.Combo.EVENT_EXPAND="EVENT_EXPAND",BI.Combo.EVENT_COLLAPSE="EVENT_COLLAPSE",BI.Combo.EVENT_AFTER_INIT="EVENT_AFTER_INIT",BI.Combo.EVENT_BEFORE_POPUPVIEW="EVENT_BEFORE_POPUPVIEW",BI.Combo.EVENT_AFTER_POPUPVIEW="EVENT_AFTER_POPUPVIEW",BI.Combo.EVENT_BEFORE_HIDEVIEW="EVENT_BEFORE_HIDEVIEW",BI.Combo.EVENT_AFTER_HIDEVIEW="EVENT_AFTER_HIDEVIEW",BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0,t.className="designer.components.phone.editor.item",t.Widget=BI.inherit(BI.BasicButton,{props:{baseCls:"designer-login-login-body",label:"",text:""},render:function(){var e=this.options;return{type:"bi.htape",items:[{el:{type:"bi.label",text:e.label,title:e.label,textAlign:"left"},lgap:10,rgap:5},{el:{type:"bi.label",text:e.text,textAlign:"right"},width:32,rgap:10}]}},doClick:function(){BI.SingleSelectItem.superclass.doClick.apply(this,arguments),this.isValid()&&this.fireEvent("EVENT_CHANGE",this.isSelected(),this)},setSelected:function(e){BI.SingleSelectItem.superclass.setSelected.apply(this,arguments)},getValue:function(){return this.options.value}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Widget=t.className=void 0;var o=i(0);t.className="designer.user.account.setting.captcha",t.Widget=BI.inherit(BI.Widget,{props:{baseCls:"designer-login-login-body"},render:function(){var e=this;this.options;return{type:o.TextButton,text:BI.i18nText("Designer-Login_Code_Request"),cls:"designer-login-border-bottom designer-login-code-text",handler:function(){e.setButtonEnable(!1),e.fireEvent("EVENT_SEND")},ref:function(t){e.getButton=t}}},setButtonEnable:function(e){this.captchaTime&&(e=!1),this.getButton.setEnable(e)},regainCaptcha:function(){var e=this,t=0;window.clearInterval(e.captchaTime),this.captchaTime=window.setInterval((function(){if(60===t)return window.clearInterval(e.captchaTime),e.captchaTime=null,e.getButton.setText(BI.i18nText("Designer-Login_Code_Request")),void e.setButtonEnable(!0);e.getButton.setText(BI.i18nText("Designer-Login_Code_Request_Again")+"("+(60-t)+")"),t++}),1e3),this.setButtonEnable(!1)}}),BI.shortcut(t.className,t.Widget),t["default"]=t.className},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Model=t.className=void 0,t.className="designer.login.model.sms_method",t.Model=BI.inherit(Fix.Model,{context:[""],state:function(){return{errMessage:"",isRegister:!1,regToken:""}},actions:{setErrMessage:function(e){this.model.errMessage=e},setRegister:function(e){this.model.isRegister=e},setRegToken:function(e){this.model.regToken=e}}}),BI.store(t.className,t.Model),t["default"]=t.className},function(e,t,i){}]); \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png deleted file mode 100644 index c696cba4d3..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.svg b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.svg new file mode 100644 index 0000000000..f18c158027 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_all.svg @@ -0,0 +1,13 @@ + + + 全部完成 + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png deleted file mode 100644 index 4c6c6f2bba..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.svg b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.svg new file mode 100644 index 0000000000..ec078243bf --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_none.svg @@ -0,0 +1,13 @@ + + + 未完成@2x + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png deleted file mode 100644 index b3443318bd..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.svg b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.svg new file mode 100644 index 0000000000..e6151ea038 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/mainframe/guide/complete_some.svg @@ -0,0 +1,23 @@ + + + 部分完成 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png b/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png deleted file mode 100644 index ef5a197834..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/mainframe/guide/guide.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/mainframe/predefined/previewData b/designer-base/src/main/resources/com/fr/design/mainframe/predefined/previewData deleted file mode 100644 index cfcf502f3f..0000000000 --- a/designer-base/src/main/resources/com/fr/design/mainframe/predefined/previewData +++ /dev/null @@ -1,5 +0,0 @@ -城市 当月目标 当月实际完成 月度完成率 -南通市 324,646 324,646 100% -合肥市 248,938 348,938 140% -邵阳市 248,938 348,938 140% -合计 1,071,460 1,371,460 128% diff --git a/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenter.png b/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenter.png deleted file mode 100644 index 0445f31344..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenter.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenterDot.png b/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenterDot.png deleted file mode 100644 index 599a9ba64a..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/notification/ui/notificationCenterDot.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/standard/add/add_black_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/add/add_black_normal.svg new file mode 100644 index 0000000000..2c63e640bc --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/add/add_black_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/sheet/add_polysheet_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/add_polysheet_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/sheet/add_polysheet_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/add_polysheet_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/standard/add_worksheet_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/add_worksheet_normal.svg new file mode 100644 index 0000000000..e373bd448d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/add_worksheet_normal.svg @@ -0,0 +1,17 @@ + + + icon_sheet_添加一页_normal + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/addicon/add_press.svg b/designer-base/src/main/resources/com/fr/design/standard/addicon/add_press.svg new file mode 100644 index 0000000000..c23b1b8ada --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/addicon/add_press.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/addicon/addicon_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/addicon/addicon_normal.svg new file mode 100644 index 0000000000..586122fd23 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/addicon/addicon_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_disabled.svg new file mode 100644 index 0000000000..d48e1a27bb --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_disabled.svg @@ -0,0 +1,16 @@ + + + 编组 + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_normal.svg new file mode 100644 index 0000000000..8cec802fee --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/addpopup/addPopup_normal.svg @@ -0,0 +1,14 @@ + + + 编组备份 + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/alpha_fine_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/alpha_fine_normal.svg new file mode 100644 index 0000000000..efe176ceab --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/alpha_fine_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg new file mode 100755 index 0000000000..0a20cf97a8 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg new file mode 100755 index 0000000000..9d111eff91 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg new file mode 100755 index 0000000000..4ab4c796e2 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg new file mode 100755 index 0000000000..040db18bd0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/background_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/background_normal.svg new file mode 100644 index 0000000000..577e8bd8a0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/background_normal.svg @@ -0,0 +1,7 @@ + + + icon_文本背景色_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_disabled.svg new file mode 100644 index 0000000000..ed225a99b9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_normal.svg new file mode 100644 index 0000000000..c81b5419aa --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/batchesdoff/batch_esd_off_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_disabled.svg new file mode 100644 index 0000000000..23d8c5da55 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_normal.svg new file mode 100644 index 0000000000..13f924d88b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/batchesdon/batch_esd_on_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bias/bias_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/bias/bias_disabled.svg new file mode 100644 index 0000000000..bc8c7ac44d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bias/bias_disabled.svg @@ -0,0 +1,7 @@ + + + icon_斜线_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bias/bias_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/bias/bias_normal.svg new file mode 100644 index 0000000000..92af8e076a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bias/bias_normal.svg @@ -0,0 +1,7 @@ + + + icon_斜线_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_disabled.svg new file mode 100644 index 0000000000..6c80b82afb --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_disabled.svg @@ -0,0 +1,7 @@ + + + icon_插入数据列_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_normal.svg new file mode 100644 index 0000000000..ea35ccb27f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bindcolunm/bind_column_normal.svg @@ -0,0 +1,7 @@ + + + icon_插入数据列_nomal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bold/bold_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/bold/bold_normal.svg new file mode 100644 index 0000000000..fa9d660221 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bold/bold_normal.svg @@ -0,0 +1,7 @@ + + + icon_文本工具_加粗_nomal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/bold/bold_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/bold/bold_selected.svg new file mode 100644 index 0000000000..638fadc32c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/bold/bold_selected.svg @@ -0,0 +1,7 @@ + + + icon_文本工具_加粗_selected + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cell_default_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/cell_default_normal.svg new file mode 100644 index 0000000000..d897c1793c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cell_default_normal.svg @@ -0,0 +1,13 @@ + + + icon/鼠标状态/十字光标 + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_normal.svg new file mode 100644 index 0000000000..46c7848030 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_normal.svg @@ -0,0 +1,7 @@ + + + icon_对齐 居中对齐_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_selected.svg new file mode 100644 index 0000000000..ca87172041 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_center_selected.svg @@ -0,0 +1,7 @@ + + + icon_对齐 居中对齐_selected + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_normal.svg new file mode 100644 index 0000000000..480e12e8c1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_normal.svg @@ -0,0 +1,7 @@ + + + icon_对齐 左对齐_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_selected.svg new file mode 100644 index 0000000000..b859a9ac96 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_left_selected.svg @@ -0,0 +1,7 @@ + + + icon_对齐 左对齐_selected + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_normal.svg new file mode 100644 index 0000000000..9707e270d9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_normal.svg @@ -0,0 +1,7 @@ + + + icon_对齐 右对齐_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_selected.svg new file mode 100644 index 0000000000..f2ca4708cb --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cellstyle/h_right_selected.svg @@ -0,0 +1,7 @@ + + + icon_对齐 右对齐_selected + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/chart/chart_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/chart/chart_disabled.svg new file mode 100644 index 0000000000..b2b724c64c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/chart/chart_disabled.svg @@ -0,0 +1,7 @@ + + + icon_图表_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/chart/chart_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/chart/chart_normal.svg new file mode 100644 index 0000000000..59fc97567f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/chart/chart_normal.svg @@ -0,0 +1,7 @@ + + + icon_图表_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/class_table_data_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/class_table_data_normal.svg new file mode 100644 index 0000000000..19fc851ecd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/class_table_data_normal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/clear_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/clear_normal.svg new file mode 100644 index 0000000000..11f60a5530 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/clear_normal.svg @@ -0,0 +1,10 @@ + + + icon_关闭_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/close/close_mouseover.svg b/designer-base/src/main/resources/com/fr/design/standard/close/close_mouseover.svg new file mode 100644 index 0000000000..bc0afc24d2 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/close/close_mouseover.svg @@ -0,0 +1,9 @@ + + + icon_关闭_hover + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/close/close_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/close/close_normal.svg new file mode 100644 index 0000000000..23c1cbe2c0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/close/close_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/close/close_press.svg b/designer-base/src/main/resources/com/fr/design/standard/close/close_press.svg new file mode 100644 index 0000000000..bc0afc24d2 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/close/close_press.svg @@ -0,0 +1,9 @@ + + + icon_关闭_hover + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/collapse_all_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/collapse_all_normal.svg new file mode 100644 index 0000000000..45b28a56b3 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/collapse_all_normal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/connection_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/connection_normal.svg new file mode 100644 index 0000000000..7c865b45e0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/connection_normal.svg @@ -0,0 +1,11 @@ + + + icon_定义数据连接_normal备份 + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/copy/copy_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/copy/copy_disabled.svg new file mode 100644 index 0000000000..05585d3abd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/copy/copy_disabled.svg @@ -0,0 +1,7 @@ + + + icon_复制_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/copy/copy_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/copy/copy_normal.svg new file mode 100644 index 0000000000..7e45e69356 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/copy/copy_normal.svg @@ -0,0 +1,10 @@ + + + icon_复制_normal + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cut/cut_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/cut/cut_disabled.svg new file mode 100644 index 0000000000..6f469f8e63 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cut/cut_disabled.svg @@ -0,0 +1,9 @@ + + + icon_剪切_disabled + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/cut/cut_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/cut/cut_normal.svg new file mode 100644 index 0000000000..485201206b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/cut/cut_normal.svg @@ -0,0 +1,10 @@ + + + icon_剪切_normal + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/data_table_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/data_table_normal.svg new file mode 100644 index 0000000000..220cd95269 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/data_table_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/database_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/database_normal.svg new file mode 100644 index 0000000000..8c0361dcda --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/database_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/debug/debug_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/debug/debug_disabled.svg new file mode 100644 index 0000000000..520d126a0f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/debug/debug_disabled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/debug/debug_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/debug/debug_normal.svg new file mode 100644 index 0000000000..80abccaba9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/debug/debug_normal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/dot_line_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/dot_line_normal.svg new file mode 100644 index 0000000000..989837d583 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/dot_line_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/drag/left_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/drag/left_normal.svg new file mode 100644 index 0000000000..0809e2e261 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/drag/left_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/drag/left_pressed.svg b/designer-base/src/main/resources/com/fr/design/standard/drag/left_pressed.svg new file mode 100644 index 0000000000..7f293e9a15 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/drag/left_pressed.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/drag/right_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/drag/right_normal.svg new file mode 100644 index 0000000000..a9bc6d2c6b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/drag/right_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/drag/right_pressed.svg b/designer-base/src/main/resources/com/fr/design/standard/drag/right_pressed.svg new file mode 100644 index 0000000000..7fa6c4e056 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/drag/right_pressed.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/edit/edit_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/edit/edit_disabled.svg new file mode 100644 index 0000000000..6ac7d0b932 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/edit/edit_disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/edit/edit_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/edit/edit_normal.svg new file mode 100644 index 0000000000..3ab4c0b297 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/edit/edit_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_disabled.svg new file mode 100644 index 0000000000..9b001cfc5f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_disabled.svg @@ -0,0 +1,8 @@ + + + icon_编辑_disable + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_normal.svg new file mode 100644 index 0000000000..2917194523 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/editdataset/edit_normal.svg @@ -0,0 +1,8 @@ + + + icon_编辑_normal + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/field_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/field_normal.svg new file mode 100644 index 0000000000..608d1fd589 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/field_normal.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/file_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/file_normal.svg new file mode 100644 index 0000000000..cafbff6526 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/file_normal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/cht_icon.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cht_icon.svg new file mode 100644 index 0000000000..0a764389b8 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cht_icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/cpt_icon.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cpt_icon.svg new file mode 100644 index 0000000000..d691f38b67 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cpt_icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon.svg new file mode 100644 index 0000000000..79eff58617 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon_locked.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon_locked.svg new file mode 100644 index 0000000000..1b662d0bfc --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/cptx_icon_locked.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder.svg new file mode 100644 index 0000000000..ebafeec23c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder_half_authority.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder_half_authority.svg new file mode 100644 index 0000000000..55be60bd43 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/folder_half_authority.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/frm_icon.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/frm_icon.svg new file mode 100644 index 0000000000..fa61a511fe --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/frm_icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/minus.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/minus.svg new file mode 100644 index 0000000000..067df99f84 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/fileicon/plus.svg b/designer-base/src/main/resources/com/fr/design/standard/fileicon/plus.svg new file mode 100644 index 0000000000..c2b0e9d9c4 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/fileicon/plus.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/floatpop_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/floatpop_normal.svg new file mode 100644 index 0000000000..95806104dc --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/floatpop_normal.svg @@ -0,0 +1,9 @@ + + + icon_悬浮元素&三角_normal + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/font_miss_check_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/font_miss_check_normal.svg new file mode 100644 index 0000000000..3b87159e18 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/font_miss_check_normal.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/foreground_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/foreground_normal.svg new file mode 100644 index 0000000000..0eaa40e93a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/foreground_normal.svg @@ -0,0 +1,7 @@ + + + icon_文本前景色_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/formatbrush/formatBrush_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/formatbrush/formatBrush_normal.svg new file mode 100644 index 0000000000..f02c9cb616 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/formatbrush/formatBrush_normal.svg @@ -0,0 +1,9 @@ + + + icon_格式刷_normal + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/formula/formula_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/formula/formula_disabled.svg new file mode 100644 index 0000000000..18eb078e73 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/formula/formula_disabled.svg @@ -0,0 +1,7 @@ + + + icon_公式_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/formula/formula_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/formula/formula_normal.svg new file mode 100644 index 0000000000..981ec11b45 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/formula/formula_normal.svg @@ -0,0 +1,7 @@ + + + icon_公式_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/guide_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/guide_normal.svg new file mode 100644 index 0000000000..acf81b1e49 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/guide_normal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/image/image_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/image/image_disabled.svg new file mode 100644 index 0000000000..b18058f59c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/image/image_disabled.svg @@ -0,0 +1,12 @@ + + + icon_图片__disabled + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/image/image_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/image/image_normal.svg new file mode 100644 index 0000000000..19eb761998 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/image/image_normal.svg @@ -0,0 +1,10 @@ + + + icon_图片_normal + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/italic/italic_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/italic/italic_normal.svg new file mode 100644 index 0000000000..97ed4dd1ae --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/italic/italic_normal.svg @@ -0,0 +1,9 @@ + + + icon_文本工具_斜体_normal + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/italic/italic_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/italic/italic_selected.svg new file mode 100644 index 0000000000..1a84fd6da9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/italic/italic_selected.svg @@ -0,0 +1,9 @@ + + + icon_文本工具_斜体_selected + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/list/list_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/list/list_normal.svg new file mode 100644 index 0000000000..b6fccb0337 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/list/list_normal.svg @@ -0,0 +1,7 @@ + + + icon_标签栏_工作簿列表_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/list/list_pressed.svg b/designer-base/src/main/resources/com/fr/design/standard/list/list_pressed.svg new file mode 100644 index 0000000000..a6b49b76b0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/list/list_pressed.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif new file mode 100644 index 0000000000..99f95a0fa8 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif new file mode 100644 index 0000000000..9db4c738fb Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/standard/locate/locate_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/locate/locate_disabled.svg new file mode 100644 index 0000000000..3a94510fb0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/locate/locate_disabled.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/locate/locate_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/locate/locate_normal.svg new file mode 100644 index 0000000000..6c78878c0a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/locate/locate_normal.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/merge/merge_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/merge/merge_disabled.svg new file mode 100644 index 0000000000..a54f56a5bc --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/merge/merge_disabled.svg @@ -0,0 +1,11 @@ + + + icon_合并单元格_disabled + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/merge/merge_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/merge/merge_normal.svg new file mode 100644 index 0000000000..ad75844975 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/merge/merge_normal.svg @@ -0,0 +1,11 @@ + + + icon_合并单元格_normal + + + + a + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/multi_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/multi_normal.svg new file mode 100644 index 0000000000..0c8144e634 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/multi_normal.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_disabled.svg new file mode 100644 index 0000000000..f3936e1539 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_disabled.svg @@ -0,0 +1,8 @@ + + + icon_NewFolderIcon_disable + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_normal.svg new file mode 100644 index 0000000000..85f41e26a7 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/newfolder/new_folder_normal.svg @@ -0,0 +1,8 @@ + + + icon_NewFolderIcon_normal + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/sheet/next_page_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/nextpage/next_page_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/sheet/next_page_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/nextpage/next_page_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/sheet/next_page_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/nextpage/next_page_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/sheet/next_page_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/nextpage/next_page_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/standard/noboder_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/noboder_normal.svg new file mode 100644 index 0000000000..b3ef846a91 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/noboder_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/notification/notification_dot.svg b/designer-base/src/main/resources/com/fr/design/standard/notification/notification_dot.svg new file mode 100644 index 0000000000..a78a459443 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/notification/notification_dot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/notification/notification_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/notification/notification_normal.svg new file mode 100644 index 0000000000..783aabaff6 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/notification/notification_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/paste/paste_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/paste/paste_disabled.svg new file mode 100644 index 0000000000..778257c33d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/paste/paste_disabled.svg @@ -0,0 +1,10 @@ + + + icon_粘贴_disabled + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/paste/paste_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/paste/paste_normal.svg new file mode 100644 index 0000000000..3a2f314044 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/paste/paste_normal.svg @@ -0,0 +1,11 @@ + + + icon_粘贴_normal + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/polysheet_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/polysheet_normal.svg new file mode 100644 index 0000000000..85674ff032 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/polysheet_normal.svg @@ -0,0 +1,9 @@ + + + icon_sheet_normal + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/popup_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/popup_normal.svg new file mode 100644 index 0000000000..81e81b0a17 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/popup_normal.svg @@ -0,0 +1,7 @@ + + + icon_组件分隔_箭头下_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/sheet/pre_page_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/prepage/pre_page_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/sheet/pre_page_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/prepage/pre_page_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/sheet/pre_page_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/prepage/pre_page_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/sheet/pre_page_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/prepage/pre_page_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/anab24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/anab24.svg new file mode 100644 index 0000000000..ed3352bed9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/anab24.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/anas.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/anas.svg new file mode 100644 index 0000000000..f4d02b287c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/anas.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview.svg new file mode 100644 index 0000000000..e47c0eb4f1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview24.svg new file mode 100644 index 0000000000..5da0955b1e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/developer_preview24.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/mobile.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/mobile.svg new file mode 100644 index 0000000000..788e303b20 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/mobile.svg @@ -0,0 +1,19 @@ + + + icon_预览_移动端预览_小图 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/mobileb24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/mobileb24.svg new file mode 100644 index 0000000000..ce7cb40265 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/mobileb24.svg @@ -0,0 +1,19 @@ + + + icon_预览_移动端预览_大图标 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/pageb24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/pageb24.svg new file mode 100644 index 0000000000..f9f1448755 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/pageb24.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/pages.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/pages.svg new file mode 100644 index 0000000000..b9a18a7068 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/pages.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/run24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/run24.svg new file mode 100644 index 0000000000..f9f1448755 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/run24.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/runs.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/runs.svg new file mode 100644 index 0000000000..b9a18a7068 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/runs.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/writeb24.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/writeb24.svg new file mode 100644 index 0000000000..ecf74889a5 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/writeb24.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/preview/writes.svg b/designer-base/src/main/resources/com/fr/design/standard/preview/writes.svg new file mode 100644 index 0000000000..e8f9368247 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/preview/writes.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_disabled.svg new file mode 100644 index 0000000000..6f2c4afa1f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_disabled.svg @@ -0,0 +1,7 @@ + + + icon_预览_disabled + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_normal.svg new file mode 100644 index 0000000000..0412b5e108 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/previewdateset/preview_normal.svg @@ -0,0 +1,7 @@ + + + icon_预览_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/authorityedit_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/authorityedit_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellattr_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellattr_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/cellelement_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/cellelement_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/conditionattr_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/conditionattr_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/configuredroles_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/configuredroles_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/floatelement_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/floatelement_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/hyperlink_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/hyperlink_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetlib_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetlib_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_disabled.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_disabled.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_disabled.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_normal.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_normal.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_normal.svg diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_selected.svg similarity index 100% rename from designer-base/src/main/resources/com/fr/design/images/buttonicon/propertiestab/widgetsettings_selected.svg rename to designer-base/src/main/resources/com/fr/design/standard/propertiestab/widgetsettings_selected.svg diff --git a/designer-base/src/main/resources/com/fr/design/standard/redo/redo_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/redo/redo_disabled.svg new file mode 100644 index 0000000000..ae600230cd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/redo/redo_disabled.svg @@ -0,0 +1,7 @@ + + + icon_重做_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/redo/redo_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/redo/redo_normal.svg new file mode 100644 index 0000000000..8c26e8925f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/redo/redo_normal.svg @@ -0,0 +1,7 @@ + + + icon_重做_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/refresh_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/refresh_normal.svg new file mode 100644 index 0000000000..4e3fd9c147 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/refresh_normal.svg @@ -0,0 +1,7 @@ + + + icon_刷新_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg new file mode 100755 index 0000000000..6ef70206f1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg new file mode 100755 index 0000000000..c26d221b58 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg new file mode 100755 index 0000000000..5b0eabe822 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning_window.svg b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning_window.svg new file mode 100644 index 0000000000..66dde59232 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning_window.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/remove/remove_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_disabled.svg new file mode 100644 index 0000000000..b57f9a853d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_disabled.svg @@ -0,0 +1,11 @@ + + + icon_删除_normal + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/remove/remove_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_normal.svg new file mode 100644 index 0000000000..b09268f454 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_normal.svg @@ -0,0 +1,9 @@ + + + icon_删除_normal备份 + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/remove/remove_red_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_red_normal.svg new file mode 100644 index 0000000000..74ff5ab385 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/remove/remove_red_normal.svg @@ -0,0 +1,7 @@ + + + icon_关闭_red + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/remove_red_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/remove_red_normal.svg new file mode 100644 index 0000000000..74ff5ab385 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/remove_red_normal.svg @@ -0,0 +1,7 @@ + + + icon_关闭_red + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_disabled.svg new file mode 100644 index 0000000000..1245fbd4e3 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_disabled.svg @@ -0,0 +1,7 @@ + + + icon_删除_disabled + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_normal.svg new file mode 100644 index 0000000000..69a3011faf --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/removefile/remove_normal.svg @@ -0,0 +1,7 @@ + + + icon_删除_normal copy + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/rename/rename_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/rename/rename_disabled.svg new file mode 100644 index 0000000000..953e12eaa9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/rename/rename_disabled.svg @@ -0,0 +1,7 @@ + + + icon_重命名_disable + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/rename/rename_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/rename/rename_normal.svg new file mode 100644 index 0000000000..a2c287789d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/rename/rename_normal.svg @@ -0,0 +1,7 @@ + + + icon_重命名_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_disabled.svg new file mode 100644 index 0000000000..916c433033 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_disabled.svg @@ -0,0 +1,7 @@ + + + icon_富文本_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_normal.svg new file mode 100644 index 0000000000..3665dd01e1 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/richtext/richtext_normal.svg @@ -0,0 +1,7 @@ + + + icon_富文本_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/save/save_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/save/save_disabled.svg new file mode 100644 index 0000000000..99087a805b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/save/save_disabled.svg @@ -0,0 +1,12 @@ + + + icon_保存_disabled + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/save/save_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/save/save_normal.svg new file mode 100644 index 0000000000..f1caf5d1e7 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/save/save_normal.svg @@ -0,0 +1,12 @@ + + + icon_保存_normal + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/search_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/search_normal.svg new file mode 100644 index 0000000000..673548dfaf --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/search_normal.svg @@ -0,0 +1,7 @@ + + + icon_搜索_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/server_database_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/server_database_normal.svg new file mode 100644 index 0000000000..50a509fcbf --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/server_database_normal.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/smallsearch_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/smallsearch_normal.svg new file mode 100644 index 0000000000..efe176ceab --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/smallsearch_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/store_procedure_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/store_procedure_normal.svg new file mode 100644 index 0000000000..55393d59ab --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/store_procedure_normal.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_disabled.svg new file mode 100644 index 0000000000..14ee3f16c3 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_disabled.svg @@ -0,0 +1,12 @@ + + + icon_子报表_disabled + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_normal.svg new file mode 100644 index 0000000000..d06985a528 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/subreport/sub_report_normal.svg @@ -0,0 +1,10 @@ + + + icon_子报表_normal + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg b/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg new file mode 100644 index 0000000000..777e87831e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/add_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/add_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/system/add_normal.svg new file mode 100644 index 0000000000..cccd52cb5c --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/add_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/cpt_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/system/cpt_normal.svg new file mode 100644 index 0000000000..0fcdcf70ae --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/cpt_normal.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/error_tips_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/system/error_tips_normal.svg new file mode 100644 index 0000000000..900205215b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/error_tips_normal.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg b/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg new file mode 100755 index 0000000000..eaf43b0cf8 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/home_folder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg b/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg new file mode 100755 index 0000000000..514e4c5006 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/system/remote_connect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/template_theme_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/template_theme_normal.svg new file mode 100644 index 0000000000..c9e90de473 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/template_theme_normal.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/text/text_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/text/text_disabled.svg new file mode 100644 index 0000000000..a25d12a706 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/text/text_disabled.svg @@ -0,0 +1,7 @@ + + + icon_普通文本_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/text/text_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/text/text_normal.svg new file mode 100644 index 0000000000..bf3b0c6879 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/text/text_normal.svg @@ -0,0 +1,7 @@ + + + icon_普通文本_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/tip/tips_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/tip/tips_normal.svg new file mode 100644 index 0000000000..cfc3370a66 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/tip/tips_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/tree_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/tree_normal.svg new file mode 100644 index 0000000000..cc965888e7 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/tree_normal.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_hover.svg b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_hover.svg new file mode 100644 index 0000000000..f83d881a5d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_normal.svg new file mode 100644 index 0000000000..478b58eba7 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/down_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_hover.svg b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_hover.svg new file mode 100644 index 0000000000..67045e796a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_hover.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_normal.svg new file mode 100644 index 0000000000..2297284274 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/triangle.arrow/up_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_normal.svg new file mode 100644 index 0000000000..591c5e1465 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_pressed.svg b/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_pressed.svg new file mode 100644 index 0000000000..c2b3252552 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/uimode/edit_pressed.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_normal.svg new file mode 100644 index 0000000000..aa140c6e24 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_normal.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_pressed.svg b/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_pressed.svg new file mode 100644 index 0000000000..6d71750234 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/uimode/hide_pressed.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/uimode/view_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/uimode/view_normal.svg new file mode 100644 index 0000000000..8a44f28058 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/uimode/view_normal.svg @@ -0,0 +1,7 @@ + + + icon 显示 + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/underline/underline_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/underline/underline_normal.svg new file mode 100644 index 0000000000..51a6fd7837 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/underline/underline_normal.svg @@ -0,0 +1,7 @@ + + + icon_文本工具_下划线_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/underline/underline_selected.svg b/designer-base/src/main/resources/com/fr/design/standard/underline/underline_selected.svg new file mode 100644 index 0000000000..ccaafc40a6 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/underline/underline_selected.svg @@ -0,0 +1,7 @@ + + + icon_文本工具_下划线_selected + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/undo/undo_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/undo/undo_disabled.svg new file mode 100644 index 0000000000..24c5cd7c93 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/undo/undo_disabled.svg @@ -0,0 +1,7 @@ + + + icon_撤销_disabled + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/undo/undo_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/undo/undo_normal.svg new file mode 100644 index 0000000000..d36032371a --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/undo/undo_normal.svg @@ -0,0 +1,7 @@ + + + icon_撤销_normal + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_disabled.svg new file mode 100644 index 0000000000..bb9f7a22f6 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_disabled.svg @@ -0,0 +1,10 @@ + + + icon_拆分单元格_disabled + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_normal.svg new file mode 100644 index 0000000000..3af2c0ff3d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/unmerge/unmerge_normal.svg @@ -0,0 +1,8 @@ + + + icon_拆分单元格_normal + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_disabled.svg new file mode 100644 index 0000000000..b88ee0998e --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_disabled.svg @@ -0,0 +1,7 @@ + + + icon_版本管理_disabled + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_normal.svg new file mode 100644 index 0000000000..ebfca43899 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/vcslist/vcs_list_normal.svg @@ -0,0 +1,7 @@ + + + icon_版本管理_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_disabled.svg b/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_disabled.svg new file mode 100644 index 0000000000..376d372d41 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_disabled.svg @@ -0,0 +1,7 @@ + + + icon_打开文件_disable + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_normal.svg new file mode 100644 index 0000000000..42ae6cbd3d --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/viewfolder/view_folder_normal.svg @@ -0,0 +1,7 @@ + + + icon_所在文件夹_normal + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/standard/warning.svg b/designer-base/src/main/resources/com/fr/design/standard/warning.svg new file mode 100644 index 0000000000..8b5d47014b --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/warning.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/standard/worksheet_normal.svg b/designer-base/src/main/resources/com/fr/design/standard/worksheet_normal.svg new file mode 100644 index 0000000000..dcf4e572c9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/standard/worksheet_normal.svg @@ -0,0 +1,10 @@ + + + icon_sheet_page_normal + + + + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg b/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg new file mode 100755 index 0000000000..fd61e745be --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/create_new_template.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg new file mode 100755 index 0000000000..a79e502777 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_28.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg new file mode 100644 index 0000000000..8ea966cbc4 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/local_server_background_36.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/more.svg b/designer-base/src/main/resources/com/fr/design/startup/more.svg new file mode 100755 index 0000000000..65f7b7c701 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/more.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg b/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg new file mode 100644 index 0000000000..5b4ee1d6fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/more_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg new file mode 100755 index 0000000000..da22546f98 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_28.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg new file mode 100755 index 0000000000..d10b2700a0 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/remote_server_background_36.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/show_less.svg b/designer-base/src/main/resources/com/fr/design/startup/show_less.svg new file mode 100755 index 0000000000..b929630e7f --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/show_less.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/show_more.svg b/designer-base/src/main/resources/com/fr/design/startup/show_more.svg new file mode 100755 index 0000000000..1b7c059d97 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/startup/show_more.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/design/startup/startup_page_background.jpg b/designer-base/src/main/resources/com/fr/design/startup/startup_page_background.jpg new file mode 100755 index 0000000000..ad0c5de365 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/startup/startup_page_background.jpg differ diff --git a/designer-base/src/main/resources/com/fr/env/detect/detect.svg b/designer-base/src/main/resources/com/fr/env/detect/detect.svg new file mode 100644 index 0000000000..b279a649fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/env/detect/detect.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg b/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg new file mode 100644 index 0000000000..b279a649fd --- /dev/null +++ b/designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg @@ -0,0 +1,3 @@ + + + diff --git a/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java b/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java index 090838fd0c..cab7037cd2 100644 --- a/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java +++ b/designer-base/src/test/java/com/fr/design/EnvChangeEntranceTest.java @@ -1,12 +1,12 @@ package com.fr.design; -import com.fr.decision.webservice.v10.plugin.helper.PluginErrorRemindHandler; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; +import com.fr.plugin.error.PluginErrorRemindHandler; import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.LocalDesignerWorkspaceInfo; import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.env.CheckServiceDialog; -import com.fr.env.PluginErrorRemindDialog; import com.fr.invoke.Reflect; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; @@ -108,33 +108,4 @@ public class EnvChangeEntranceTest { Assert.assertFalse(Reflect.on(entrance).call("isNotRememberPwd", info3).get()); Assert.assertFalse(Reflect.on(entrance).call("isNotRememberPwd", info4).get()); } - - @Test - public void testPluginErrorRemind() { - - try { - - Workspace workspace = EasyMock.mock(Workspace.class); - EasyMock.expect(workspace.isLocal()).andReturn(false).once(); - EasyMock.expect(workspace.isLocal()).andReturn(true).once(); - PowerMock.mockStatic(WorkContext.class); - EasyMock.expect(WorkContext.getCurrent()).andReturn(workspace).anyTimes(); - - PowerMock.mockStatic(PluginErrorRemindHandler.class); - EasyMock.expect(PluginErrorRemindHandler.pluginErrorContent()).andReturn("").once(); - - EasyMock.replay(workspace); - PowerMock.replayAll(); - - EnvChangeEntrance entrance = EnvChangeEntrance.getInstance(); - - entrance.pluginErrorRemind(); - entrance.pluginErrorRemind(); - - EasyMock.verify(workspace); - PowerMock.verifyAll(); - } catch (Exception e) { - Assert.fail(); - } - } -} \ No newline at end of file +} diff --git a/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java b/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java new file mode 100644 index 0000000000..b4ae293979 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java @@ -0,0 +1,43 @@ +package com.fr.design.components.notification; + +import com.fr.design.utils.DevUtils; +import com.fr.third.guava.collect.Lists; + +import java.awt.Frame; +import java.util.function.Consumer; + +public class NotificationDialogTest { + + public static void main(String[] args) { + + testShow(); + } + + public static void testShow() { + + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + + NotificationModel model1 = new NotificationModel(NotificationType.WARNING, null, new NotificationMessage.LinkMessage("test", "abc"), new NotificationMessage.LinkMessage("abc", "aaa")); + + NotificationModel model2 = new NotificationModel(NotificationType.INFO, new NotificationAction() { + @Override + public String name() { + return "action"; + } + + @Override + public void run(Object... args) { + System.out.println("1111"); + } + }, new NotificationMessage.LinkMessage("1111 2222 33333333 4444 555 6666 66555 888 999 333
3333
444
555
", ""),new NotificationMessage.LinkMessage("display model2 test", "abc")); + + NotificationDialogProperties properties = new NotificationDialogProperties(frame, "test"); + NotificationDialog dialog = new NotificationDialog(properties, Lists.newArrayList(model1, model2)); + dialog.setVisible(true); + } + }); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/data/MapCompareUtilsTest.java b/designer-base/src/test/java/com/fr/design/data/MapCompareUtilsTest.java new file mode 100644 index 0000000000..1f1e60e2be --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/data/MapCompareUtilsTest.java @@ -0,0 +1,57 @@ +package com.fr.design.data; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author rinoux + * @version 10.0 + * Created by rinoux on 2022/3/28 + */ +public class MapCompareUtilsTest { + + @Test + public void contrastMapEntries() { + + + Map orig = new LinkedHashMap<>(); + + orig.put("aaa", "aaa"); + orig.put("bbb", "bbb"); + orig.put("ccc", "ccc"); + orig.put("ddd", "ddd"); + + + Map other = new LinkedHashMap<>(); + + other.put("aaa", "111"); + other.put("bbb", "bbb"); + other.put("ccc", "ccc"); + other.put("eee", "eee"); + + + MapCompareUtils.contrastMapEntries(orig, other, new MapCompareUtils.EventHandler() { + @Override + public void on(MapCompareUtils.EntryEventKind entryEventKind, String s, String s2) { + switch (entryEventKind) { + case UPDATED: + Assert.assertEquals(s, "aaa"); + Assert.assertEquals(s2, "111"); + break; + case REMOVED: + Assert.assertEquals(s, "ddd"); + break; + case ADDED: + Assert.assertEquals(s, "eee"); + Assert.assertEquals(s2, "eee"); + break; + default: + Assert.fail(); + } + } + }); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java b/designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java new file mode 100644 index 0000000000..98871158d3 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java @@ -0,0 +1,43 @@ +package com.fr.design.data.datapane.management.clip; + +import com.fr.data.impl.EmbeddedTableData; +import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper; +import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; +import junit.framework.TestCase; +import org.junit.Assert; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Yvan + */ +public class TableDataTreeClipboardTest extends TestCase { + + public void testAddAndTake() { + Map testMap = new HashMap<>(); + testMap.put("ds1", new TemplateTableDataWrapper(new EmbeddedTableData())); + testMap.put("ds2", new TemplateTableDataWrapper(new EmbeddedTableData())); + + Map anotherTestMap = new HashMap<>(); + anotherTestMap.put("ds3", new TemplateTableDataWrapper(new EmbeddedTableData())); + + Map clip; + TableDataTreeClipboard.getInstance().addToClip(testMap); + clip = TableDataTreeClipboard.getInstance().takeFromClip(); + Assert.assertEquals(2, clip.size()); + Assert.assertTrue(clip.containsKey("ds1")); + Assert.assertTrue(clip.containsKey("ds2")); + + // 验证多次取出 + clip = TableDataTreeClipboard.getInstance().takeFromClip(); + Assert.assertEquals(2, clip.size()); + Assert.assertTrue(clip.containsKey("ds1")); + Assert.assertTrue(clip.containsKey("ds2")); + + TableDataTreeClipboard.getInstance().addToClip(anotherTestMap); + clip = TableDataTreeClipboard.getInstance().takeFromClip(); + Assert.assertEquals(1, clip.size()); + Assert.assertTrue(clip.containsKey("ds3")); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java b/designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java new file mode 100644 index 0000000000..2435f363fc --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java @@ -0,0 +1,201 @@ +package com.fr.design.data.tabledata.paste; + +import com.fr.base.TableData; +import com.fr.data.Dictionary; +import com.fr.data.TableDataSource; +import com.fr.data.impl.EmbeddedTableData; +import com.fr.design.data.DesignTableDataManager; +import com.fr.design.data.tabledata.wrapper.TableDataWrapper; +import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; +import com.fr.form.data.DataBinding; +import com.fr.form.data.DataTableConfig; +import com.fr.form.ui.AbstractDataControl; +import com.fr.form.ui.DictionaryContainer; +import com.fr.form.ui.Widget; +import com.fr.form.ui.WidgetValue; +import com.fr.report.cell.tabledata.ElementUsedTableDataProvider; +import com.fr.script.Calculator; +import com.fr.stable.script.CalculatorProvider; +import com.fr.stable.script.NameSpace; +import com.fr.web.core.TemplateSessionIDInfo; +import junit.framework.TestCase; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Yvan + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({DesignTableDataManager.class}) +public class TableDataFollowingPasteUtilsTest extends TestCase { + + @Before + public void beforeTest() { + Map templateDataMap = new LinkedHashMap(); + Map serverDataMap = new LinkedHashMap(); + Map storeProcedureMap = new LinkedHashMap(); + templateDataMap.put("ds1", new TemplateTableDataWrapper(new EmbeddedTableData())); + templateDataMap.put("ds2", new TemplateTableDataWrapper(new EmbeddedTableData())); + templateDataMap.put("ds3", new TemplateTableDataWrapper(new EmbeddedTableData())); + templateDataMap.put("ds4", new TemplateTableDataWrapper(new EmbeddedTableData())); + templateDataMap.put("ds5", new TemplateTableDataWrapper(new EmbeddedTableData())); + + List> list = new ArrayList>(); + list.add(templateDataMap); + list.add(serverDataMap); + list.add(storeProcedureMap); + + TableDataSource tableDataSource = EasyMock.mock(TableDataSource.class); + PowerMock.mockStatic(DesignTableDataManager.class); + EasyMock.expect(DesignTableDataManager.getEditingTableDataSource()).andReturn(tableDataSource).anyTimes(); + EasyMock.expect(DesignTableDataManager.getEditingDataSet(tableDataSource)).andReturn(list).anyTimes(); + PowerMock.replayAll(); + } + + public void testTransferProvider2TableDataMap() { + ElementUsedTableDataProvider[] providers = generateElementUsedTableDataProvider(); + Map tableDataMap = TableDataFollowingPasteUtils.transferProvider2TableDataMap(providers); + Assert.assertEquals(2, tableDataMap.size()); + Assert.assertTrue(tableDataMap.containsKey("ds1")); + Assert.assertTrue(tableDataMap.containsKey("ds2")); + } + + private ElementUsedTableDataProvider[] generateElementUsedTableDataProvider() { + ElementUsedTableDataProvider elementUsedTableDataProvider1 = new ElementUsedTableDataProvider() { + @Override + public Set getElementUsedTableDataNames() { + Set set = new HashSet<>(); + set.add("ds1"); + return set; + } + }; + ElementUsedTableDataProvider elementUsedTableDataProvider2 = new ElementUsedTableDataProvider() { + @Override + public Set getElementUsedTableDataNames() { + Set set = new HashSet<>(); + set.add("ds2"); + return set; + } + }; + return new ElementUsedTableDataProvider[]{elementUsedTableDataProvider1, elementUsedTableDataProvider2}; + } + + public void testTransferWidgetArray2TableDataMap() { + Widget[] widgets = generateWidgetArray(); + Map tableDataMap = TableDataFollowingPasteUtils.transferWidgetArray2TableDataMap(widgets); + Assert.assertEquals(3, tableDataMap.size()); + Assert.assertTrue(tableDataMap.containsKey("ds3")); + Assert.assertTrue(tableDataMap.containsKey("ds4")); + Assert.assertTrue(tableDataMap.containsKey("ds5")); + } + + private Widget[] generateWidgetArray() { + Set set = new HashSet<>(); + set.add("ds3"); + MockWidget widget1 = EasyMock.mock(MockWidget.class); + EasyMock.expect(widget1.getUsedTableDataSets()).andReturn(set).anyTimes(); + EasyMock.replay(widget1); + + DataBinding dataBinding = new DataBinding("ds4", ""); + WidgetValue widgetValue2 = new WidgetValue(); + widgetValue2.setValue(dataBinding); + AbstractDataControl widget2 = EasyMock.mock(AbstractDataControl.class); + EasyMock.expect(widget2.getWidgetValue()).andReturn(widgetValue2).anyTimes(); + EasyMock.replay(widget2); + + DataTableConfig dataTableConfig = EasyMock.mock(DataTableConfig.class); + EasyMock.expect(dataTableConfig.getTableDataName()).andReturn("ds5").anyTimes(); + WidgetValue widgetValue3 = new WidgetValue(); + widgetValue3.setValue(dataTableConfig); + AbstractDataControl widget3 = EasyMock.mock(AbstractDataControl.class); + EasyMock.expect(widget3.getWidgetValue()).andReturn(widgetValue3).anyTimes(); + EasyMock.replay(dataTableConfig, widget3); + + Widget[] widgets = new Widget[3]; + widgets[0] = widget1; + widgets[1] = widget2; + widgets[2] = widget3; + return widgets; + } + + private class MockWidget extends Widget implements DictionaryContainer { + + @Override + public String[] supportedEvents() { + return new String[0]; + } + + @Override + public void setDictionary(Dictionary model) { + + } + + @Override + public Dictionary getDictionary() { + return null; + } + + @Override + public Object getViewValue(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req) { + return null; + } + + @Override + public Object getModuleValue(Object text, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req) { + return null; + } + + @Override + public Object getViewValue(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) { + return null; + } + + @Override + public Object getModuleValue(Object text, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) { + return null; + } + + @Override + public boolean isValueAllInDictionary(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) { + return false; + } + + @Override + public String getXType() { + return null; + } + + @Override + public boolean isEditor() { + return false; + } + + @Override + public void setDependenceMap(Map dependenceMap) { + + } + + @Override + public Map getDependenceMap() { + return null; + } + + @Override + public String[] dependence(CalculatorProvider calculatorProvider) { + return new String[0]; + } + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/gui/iprogressbar/ProgressDialogTest.java b/designer-base/src/test/java/com/fr/design/gui/iprogressbar/ProgressDialogTest.java new file mode 100644 index 0000000000..336850f26b --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/gui/iprogressbar/ProgressDialogTest.java @@ -0,0 +1,55 @@ +package com.fr.design.gui.iprogressbar; + +import com.fr.design.utils.DevUtils; + +import java.awt.Dimension; +import java.awt.Frame; +import java.util.function.Consumer; + +/** + * @author Harrison + * @version 11.0 + * Created by Harrison on 2022/11/23 + */ +public class ProgressDialogTest { + + public static void main(String[] args) { + + mockInitSize(); + } + + /** + * 模拟 frame 的大小未初始化好的情况 + */ + private static void mockNotInitSize() { + + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + + Dimension origin = frame.getSize(); + frame.setSize(0, 0); + ProgressDialog progressDialog = new ProgressDialog(frame); + progressDialog.setVisible(true); + progressDialog.updateLoadingText("test"); + frame.setSize(origin); + } + }); + } + + /** + * 模拟 frame 的大小初始化好的情况 + */ + private static void mockInitSize() { + + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + + ProgressDialog progressDialog = new ProgressDialog(frame); + progressDialog.setVisible(true); + progressDialog.updateLoadingText("test"); + } + }); + } +} \ 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/java/com/fr/design/mainframe/JTemplateNameHelperTest.java b/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java index 032e715f60..0202028480 100644 --- a/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java +++ b/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java @@ -2,6 +2,8 @@ package com.fr.design.mainframe; import junit.framework.TestCase; +import com.fr.invoke.Reflect; + /** * @author shine * @version 10.0 @@ -18,6 +20,27 @@ public class JTemplateNameHelperTest extends TestCase { String name1 = JTemplateNameHelper.newTemplateNameByIndex("TEST"); assertEquals("TEST2", name1); + } + + public void testGetFileNameIndex() { + //正常情况 + assertEquals("1", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook1").toString()); + + //正常情况 + assertEquals("8888888888", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook8888888888").toString()); + + //正常情况 + assertEquals("88812214128888881231238123123", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook88812214128888881231238123123").toString()); + + //前缀不匹配 + assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "Work123", "WorkBook8888888888").get()); + + //前缀为空 + assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "", "WorkBook8888888888").get()); + + //文件长度小于前缀 + assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "").get()); + } } diff --git a/designer-base/src/test/java/com/fr/design/mainframe/loghandler/DesignerLogHandlerTest.java b/designer-base/src/test/java/com/fr/design/mainframe/loghandler/DesignerLogHandlerTest.java new file mode 100644 index 0000000000..c7dd1de70a --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/mainframe/loghandler/DesignerLogHandlerTest.java @@ -0,0 +1,50 @@ +package com.fr.design.mainframe.loghandler; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author vito + * @version 10.0 + * Created by vito on 2022/1/25 + */ +public class DesignerLogHandlerTest { + + @Test + public void findTplLink() { + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)", "(公式定位测试/单sheet2(2).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式计算错误:(公式定位测试/单sheet2(1).cpt:0:A1),出错公式(公式定位测试/单sheet2(2).cpt:0:A1),的飞机啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).frm:0:A1)", "(公式定位测试/单sheet2(2).frm:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式计算错误:(公式定位测试/单sheet2(1).frm:0:A1),出错公式(公式定位测试/单sheet2(2).frm:0:A1),的飞机啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式(计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式)计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机)啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机(啊") + ); + Assert.assertArrayEquals( + new String[]{"(公式定位测试/单sheet2(1).cpt:0:A1)"}, + DesignerLogHandler.findTplLink("错误代码:11300310 公式(0fdasf)计算错误:(公式定位测试/单sheet2(1).cpt:0:A1)的飞机啊") + ); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfoTest.java b/designer-base/src/test/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfoTest.java index c90e7a8b05..4095390016 100644 --- a/designer-base/src/test/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfoTest.java +++ b/designer-base/src/test/java/com/fr/design/mainframe/reuse/ComponentReuseNotificationInfoTest.java @@ -18,13 +18,11 @@ public class ComponentReuseNotificationInfoTest { @Test public void testReadXML() { try { - XMLableReader xmlReader = XMLableReader.createXMLableReader(new StringReader("\n")); + XMLableReader xmlReader = XMLableReader.createXMLableReader(new StringReader("\n")); ComponentReuseNotificationInfo notificationInfo = ComponentReuseNotificationInfo.getInstance(); notificationInfo.readXML(xmlReader); xmlReader.close(); - Assert.assertEquals(2, notificationInfo.getNotifiedNumber()); Assert.assertEquals(true, notificationInfo.isClickedWidgetLib()); - Assert.assertEquals(1620612153215L, notificationInfo.getLastNotifyTime()); } catch (XMLStreamException e) { Assert.fail(e.getMessage()); } @@ -35,12 +33,11 @@ public class ComponentReuseNotificationInfoTest { StringWriter sw = new StringWriter(); XMLPrintWriter writer = XMLPrintWriter.create(new PrintWriter(sw)); ComponentReuseNotificationInfo notificationInfo = ComponentReuseNotificationInfo.getInstance(); - notificationInfo.setNotifiedNumber(1); notificationInfo.writeXML(writer); writer.flush(); writer.close(); Assert.assertEquals("\n" + - "\n", sw.toString()); + "\n", sw.toString()); } } diff --git a/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java b/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java new file mode 100644 index 0000000000..b7df5af5a7 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/plugin/remind/PluginErrorDesignReminderTest.java @@ -0,0 +1,72 @@ +package com.fr.design.plugin.remind; + +import com.fr.plugin.error.PluginErrorRemindHandler; +import com.fr.workspace.WorkContext; +import com.fr.workspace.empty.EmptyWorkspace; +import junit.framework.TestCase; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Yvan + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(PluginErrorRemindHandler.class) +public class PluginErrorDesignReminderTest extends TestCase { + + @Before + public void before() { + WorkContext.switchTo(EmptyWorkspace.getInstance()); + } + + public void testRemindStartFailedPlugins() { + PowerMock.mockStatic(PluginErrorRemindHandler.class); + EasyMock.expect(PluginErrorRemindHandler.pluginErrorContent()).andReturn("").once(); + + PowerMock.replayAll(); + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); + + PowerMock.verifyAll(); + } + + public void testRemindInvalidatePlugins() { + PowerMock.mockStatic(PluginErrorRemindHandler.class); + EasyMock.expect(PluginErrorRemindHandler.getInvalidateEmbedPluginNames()).andReturn(new ArrayList<>()).once(); + + PowerMock.replayAll(); + PluginErrorDesignReminder.getInstance().remindInvalidatePlugins(); + + PowerMock.verifyAll(); + } + + public void testDealWithPluginNames() { + List pluginNames1 = Arrays.asList("1"); + String content1 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames1); + Assert.assertFalse(content1.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content1.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames2 = Arrays.asList("1", "2"); + String content2 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames2); + Assert.assertTrue(content2.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content2.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames3 = Arrays.asList("1", "2", "3", "4"); + String content3 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames3); + Assert.assertTrue(content3.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertTrue(content3.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + + List pluginNames4 = Arrays.asList("1", "2", "3"); + String content4 = PluginErrorDesignReminder.getInstance().dealWithPluginNames(pluginNames4); + Assert.assertTrue(content4.contains(PluginErrorDesignReminder.COMMA)); + Assert.assertFalse(content4.contains(PluginErrorDesignReminder.NEW_LINE_TAG)); + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java b/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java new file mode 100644 index 0000000000..837c2bd5b8 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java @@ -0,0 +1,139 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.ByteBuddy; +import com.fr.third.net.bytebuddy.agent.ByteBuddyAgent; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import com.fr.third.net.bytebuddy.matcher.ElementMatchers; +import com.fr.third.org.apache.commons.lang3.time.StopWatch; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +/** + * 测试一下,通过 redefine 去处理代码时 + * 相应的 advice 应该怎么写 + */ +public class BytebuddyRedefineTest { + + /** + * 测试一下是否可以直接抛出异常 + */ + @Test + public void testThrowException() { + + try { + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestThrowExceptionAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + testClass.testPrint(); + } catch (Throwable throwable) { + Assert.assertNotNull("expected throw exception", throwable); + } + } + + /** + * 测试是否可以直接传值 + */ + @Test + public void testTransferValue() { + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestTransferValueAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + String print = testClass.testPrint(); + + Assert.assertEquals(10, TestTransferValueAdvice.intField); + Assert.assertEquals("[test]stringField", TestTransferValueAdvice.stringField); + Assert.assertEquals("[test]objectField", TestTransferValueAdvice.objectField); + + } + + /** + * 测试是否可以改变返回值 + */ + @Test + public void testModifyReturn() { + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestModifyReturnAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + String print = testClass.testPrint(); + + Assert.assertEquals("[test]Modify Return Value", print); + + } + + @Test + public void testCallable() throws Exception { + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + TestClass testClass = new TestClass(); + String print = testClass.testPrint(); + + Assert.assertEquals("[test]Callable", print); + } + + @Test + public void testCallablePerformance() throws Exception { + + // 千 + int loop = 1000; + StopWatch stopWatch = new StopWatch(); + + stopWatch.start(); + TestClass rawClass = new TestClass(); + for (int i = 0; i < loop; i++) { + rawClass.testPrint(); + } + System.out.printf("raw class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS)); + + + ByteBuddyAgent.install(); + + new ByteBuddy() + .redefine(TestClass.class) + .visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint"))) + .make() + .load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + + stopWatch.reset(); + stopWatch.start(); + + TestClass retransformClass = new TestClass(); + for (int i = 0; i < loop; i++) { + retransformClass.testPrint(); + } + + System.out.printf("retransformClass class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS)); + + Assert.assertEquals("[test]Callable", retransformClass.testPrint()); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java new file mode 100644 index 0000000000..f98cedcde9 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java @@ -0,0 +1,50 @@ +package com.fr.design.record.analyzer; + +import com.fr.record.analyzer.advice.AdviceCallable; +import com.fr.record.analyzer.advice.AdviceContext; +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; +import com.fr.tolerance.FaultTolerance; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * created by Harrison on 2022/03/09 + **/ +public class TestCallableAdvice { + + @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) + public static boolean onMethodEnter(@Advice.Local("context")AdviceContext adviceContext) { + + adviceContext = AdviceContext + .builder() + .onAdviceCall() + .build(); + // 如果是切面调用,则忽视当前方法 + return adviceContext.isOnAdviceCall(); + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result, + @Advice.Local("context") AdviceContext adviceContext) throws Exception { + + // 如果是切面调用,则忽视不继续 exit + if (adviceContext != null && adviceContext.isOnAdviceCall()) { + return; + } + + FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class); + Callable callable = new AdviceCallable() { + @Override + public Object call() throws Exception { + return method.invoke(self, args); + } + }; + result = TestCallableHelper.test(callable); + } + +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java new file mode 100644 index 0000000000..4e99bb7031 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java @@ -0,0 +1,15 @@ +package com.fr.design.record.analyzer; + +import java.util.concurrent.Callable; + +/** + * created by Harrison on 2022/03/09 + **/ +public class TestCallableHelper { + + public static String test(Callable callable) throws Exception { + + callable.call(); + return "[test]Callable"; + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java new file mode 100644 index 0000000000..e1a2761aaa --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java @@ -0,0 +1,11 @@ +package com.fr.design.record.analyzer; + +/** + * created by Harrison on 2022/03/04 + **/ +public class TestClass { + + public String testPrint() { + return ""; + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java new file mode 100644 index 0000000000..7c2dae455a --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java @@ -0,0 +1,29 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestModifyReturnAdvice { + + @Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class) + public static int onMethodEnter() throws Exception { + + return 0; + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self, + @Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception { + + result = "[test]Modify Return Value"; + + } + +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java new file mode 100644 index 0000000000..53c54c28d8 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java @@ -0,0 +1,19 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; +import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Method; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestThrowExceptionAdvice { + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Origin Method method, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e) throws Exception { + throw new RuntimeException("[test] throw exception in advice"); + } +} diff --git a/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java b/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java new file mode 100644 index 0000000000..fa0bf6f095 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java @@ -0,0 +1,37 @@ +package com.fr.design.record.analyzer; + +import com.fr.third.net.bytebuddy.asm.Advice; + +/** + * created by Harrison on 2022/03/07 + **/ +public class TestTransferValueAdvice { + + public static int intField; + + public static String stringField; + + public static Object objectField; + + @Advice.OnMethodEnter + public static void onMethodEnter(@Advice.Local("int") int intField, + @Advice.Local("string") String stringField, + @Advice.Local("Object") Object objectField) { + + intField = 10; + stringField = "[test]stringField"; + objectField = "[test]objectField"; + } + + @Advice.OnMethodExit(onThrowable = Exception.class) + public static void onMethodExit(@Advice.Local("int") int intField, + @Advice.Local("string") String stringField, + @Advice.Local("Object") Object objectField) throws Exception { + + TestTransferValueAdvice.intField = intField; + TestTransferValueAdvice.stringField = stringField; + TestTransferValueAdvice.objectField = objectField; + + } + +} diff --git a/designer-base/src/test/java/com/fr/design/upm/UpmUtilsTest.java b/designer-base/src/test/java/com/fr/design/upm/UpmUtilsTest.java index 31119d049c..5d96a6f0b3 100644 --- a/designer-base/src/test/java/com/fr/design/upm/UpmUtilsTest.java +++ b/designer-base/src/test/java/com/fr/design/upm/UpmUtilsTest.java @@ -34,7 +34,7 @@ public class UpmUtilsTest { EasyMock.expect(ServerPreferenceConfig.getInstance()).andReturn(serverPreferenceConfig).anyTimes(); CloudCenter cloudCenter = EasyMock.mock(CloudCenter.class); - EasyMock.expect(cloudCenter.acquireUrlByKind("upm.script.version")).andReturn("2.0").anyTimes(); + EasyMock.expect(cloudCenter.acquireUrlByKind("upm.script.version.v11")).andReturn("2.0").anyTimes(); PowerMock.mockStatic(CloudCenter.class); EasyMock.expect(CloudCenter.getInstance()).andReturn(cloudCenter).anyTimes(); diff --git a/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java b/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java new file mode 100644 index 0000000000..60a294d260 --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java @@ -0,0 +1,12 @@ +package com.fr.design.utils; + +/** + * created by Harrison on 2022/05/26 + **/ +public class DevDebugUtils { + + public static void main(String[] args) { + + org.swingexplorer.Launcher.main(new String[]{"com.fr.startup.ui.StartupPageWindowTest"}); + } +} diff --git a/designer-base/src/test/java/com/fr/design/utils/DevUtils.java b/designer-base/src/test/java/com/fr/design/utils/DevUtils.java new file mode 100644 index 0000000000..dcba96f05f --- /dev/null +++ b/designer-base/src/test/java/com/fr/design/utils/DevUtils.java @@ -0,0 +1,66 @@ +package com.fr.design.utils; + +import com.fr.config.dao.DaoContext; +import com.fr.config.dao.impl.LocalClassHelperDao; +import com.fr.config.dao.impl.LocalEntityDao; +import com.fr.config.dao.impl.LocalXmlEntityDao; +import com.fr.design.ui.util.UIUtil; +import com.fr.transaction.Configurations; +import com.fr.transaction.LocalConfigurationHelper; + +import javax.swing.JFrame; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Toolkit; +import java.util.function.Consumer; + +/** + * 设计器的开发时工具 + * 帮助进行 UI 页面的调试 + *

+ * created by Harrison on 2022/05/23 + **/ +public class DevUtils { + + private static void prepare() { + + DaoContext.setEntityDao(new LocalEntityDao()); + DaoContext.setClassHelperDao(new LocalClassHelperDao()); + DaoContext.setXmlEntityDao(new LocalXmlEntityDao()); + Configurations.setHelper(new LocalConfigurationHelper()); + } + + public static void show(Consumer consumer) { + + DesignUtils.initLookAndFeel(); + + UIUtil.invokeLaterIfNeeded(() -> { + + JFrame frame = new JFrame("dev-util"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize(); + frame.setSize(dimension); + + consumer.accept(frame); + + frame.setVisible(true); + }); + + } + + public static void show(Runnable runnable) { + + DesignUtils.initLookAndFeel(); + UIUtil.invokeLaterIfNeeded(runnable); + } + + public static void main(String[] args) { + + DevUtils.prepare(); + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + } + }); + } +} diff --git a/designer-base/src/test/java/com/fr/env/RemoteWorkspaceURLTest.java b/designer-base/src/test/java/com/fr/env/RemoteWorkspaceURLTest.java index f066ae6896..b9412a93d5 100644 --- a/designer-base/src/test/java/com/fr/env/RemoteWorkspaceURLTest.java +++ b/designer-base/src/test/java/com/fr/env/RemoteWorkspaceURLTest.java @@ -242,4 +242,14 @@ public class RemoteWorkspaceURLTest { assertEquals("servlet", b.getServlet()); //others begin } + + @Test + public void testIPV6Url() { + String trueUrl = "http://[fe80::4d83:cc10:9f6f:3303]:8080/webroot/decision"; + RemoteWorkspaceURL remoteWorkspaceURL1 = new RemoteWorkspaceURL(trueUrl); + assertEquals("[fe80::4d83:cc10:9f6f:3303]", remoteWorkspaceURL1.getHost()); + assertEquals("8080", remoteWorkspaceURL1.getPort()); + assertEquals("webroot", remoteWorkspaceURL1.getWeb()); + assertEquals("decision", remoteWorkspaceURL1.getServlet()); + } } diff --git a/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java b/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java new file mode 100644 index 0000000000..20f370b7b1 --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java @@ -0,0 +1,17 @@ +package com.fr.env.detect.impl.converter; + +import org.junit.Assert; +import org.junit.Test; + +public class ClassConflictConvertorTest { + + @Test + public void testInnerFinder() { + + ClassNotFoundException ex1 = new ClassNotFoundException("Class 111.222.333 not found"); + Iterable names = ClassConflictConvertor.Converter.CLASS.converter(ex1); + + String next = names.iterator().next(); + Assert.assertEquals("111.222.333", next); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java b/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java new file mode 100644 index 0000000000..b54288ea54 --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/ui/DetectorErrorDialogTest.java @@ -0,0 +1,33 @@ +package com.fr.env.detect.ui; + +import com.fr.design.utils.DevUtils; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorType; +import com.fr.env.detect.bean.ExceptionLog; +import com.fr.env.detect.bean.ExceptionSolution; +import com.fr.env.detect.bean.ExceptionTips; +import com.fr.third.guava.collect.Lists; + +import java.awt.Frame; +import java.util.function.Consumer; + +import static org.junit.Assert.*; + +public class DetectorErrorDialogTest { + + public static void main(String[] args) { + + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + + DetectorErrorDialog dialog = new DetectorErrorDialog(frame, Lists.newArrayList(DetectorResult.exception(DetectorType.FINE_DB_PERMISSION, + ExceptionTips.create("test"), + ExceptionSolution.create("111test222", "www.baidu.com", null), + ExceptionLog.create("log")))); + dialog.setVisible(true); + } + }); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java b/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java new file mode 100644 index 0000000000..fd63b1714f --- /dev/null +++ b/designer-base/src/test/java/com/fr/env/detect/ui/EnvDetectorDialogTest.java @@ -0,0 +1,37 @@ +package com.fr.env.detect.ui; + +import com.fr.design.utils.DevUtils; +import com.fr.env.detect.bean.DetectorResult; +import com.fr.env.detect.bean.DetectorStatus; +import com.fr.env.detect.bean.DetectorType; + +import java.awt.Frame; +import java.util.function.Consumer; + +public class EnvDetectorDialogTest { + + public static void main(String[] args) { + + testShow(); + } + + private static void testShow() { + + DevUtils.show(new Consumer() { + @Override + public void accept(Frame frame) { + + EnvDetectorModel envDetectorModel = new EnvDetectorModel(); + envDetectorModel.update(DetectorType.JAR_CONFLICT, DetectorResult.builder() + .withTips("test") + .withSolution("test", "abc") + .withStatus(DetectorStatus.EXCEPTION) + .build()); + + EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(frame, envDetectorModel); + envDetectorDialog.setVisible(true); + } + }); + } + +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/startup/ui/StartupPageUtilTest.java b/designer-base/src/test/java/com/fr/startup/ui/StartupPageUtilTest.java new file mode 100644 index 0000000000..fe69541e35 --- /dev/null +++ b/designer-base/src/test/java/com/fr/startup/ui/StartupPageUtilTest.java @@ -0,0 +1,21 @@ +package com.fr.startup.ui; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class StartupPageUtilTest { + + @Test + public void testGetRemoteAddress() throws Exception { + String remoteAddress = StartupPageUtil.getRemoteAddress("https://localhost:9090/webroot"); + Assert.assertEquals("localhost:9090", remoteAddress); + + String remoteAddress1 = StartupPageUtil.getRemoteAddress("https://localhost/webroot"); + Assert.assertEquals("localhost", remoteAddress1); + + String remoteAddress2 = StartupPageUtil.getRemoteAddress(null); + Assert.assertEquals("", remoteAddress2); + } +} \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java b/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java new file mode 100644 index 0000000000..804bb7d3fb --- /dev/null +++ b/designer-base/src/test/java/com/fr/startup/ui/StartupPageWindowTest.java @@ -0,0 +1,32 @@ +package com.fr.startup.ui; + +import com.fr.design.utils.DevUtils; +import com.fr.third.guava.collect.Lists; + +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class StartupPageWindowTest { + + public static void main(String[] args) { + + DevUtils.show(new Runnable() { + @Override + public void run() { + HashMap> recentOpenFileMap = new HashMap<>(); + recentOpenFileMap.put("111", Lists.newArrayList("111.cpt", "222//3333.cpt","333.cpt", "444.cpt", "555.cpt", "666.cpt", "777.cpt")); + StartupPageModel model = new StartupPageModel(Stream.of( + StartupWorkspaceBean.create("111", "222333344455556663333444555566633334445555666"), StartupWorkspaceBean.create("113", "222"), + StartupWorkspaceBean.create("114", "222"), StartupWorkspaceBean.create("115", "222"), StartupWorkspaceBean.create("116", "222"), + //StartupWorkspaceBean.create("117", "222"), StartupWorkspaceBean.create("118", "222"), StartupWorkspaceBean.create("119", "222"), + //StartupWorkspaceBean.create("121", "222"), StartupWorkspaceBean.create("122", "222"), StartupWorkspaceBean.create("123", "222"), + StartupWorkspaceBean.create("1245678888888", "222"), StartupWorkspaceBean.create("125", "222"), StartupWorkspaceBean.create("126", "222") + ).collect(Collectors.toList()), recentOpenFileMap); + StartupPageWindow window = new StartupPageWindow(model); + window.setVisible(true); + } + }); + } +} \ No newline at end of file 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/ChartTypeInterfaceManager.java b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java index 2d54fc8189..b7c9c474e4 100644 --- a/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java +++ b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java @@ -111,6 +111,8 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr public static final String TYPE_PANE_DEFAULT_TITLE = "DEFAULT_NAME"; + public static final String GEO_LAND_CHART_ID = "UGeoLandChart"; + public synchronized static ChartTypeInterfaceManager getInstance() { return classManager; diff --git a/designer-chart/src/main/java/com/fr/design/chart/ChartDataHelper.java b/designer-chart/src/main/java/com/fr/design/chart/ChartDataHelper.java new file mode 100644 index 0000000000..e8371a3c12 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/design/chart/ChartDataHelper.java @@ -0,0 +1,69 @@ +package com.fr.design.chart; + +import com.fr.base.TableData; +import com.fr.base.chart.chartdata.TopDefinitionProvider; +import com.fr.chart.chartattr.Chart; +import com.fr.chart.chartattr.Plot; +import com.fr.chart.chartdata.MoreNameCDDefinition; +import com.fr.chart.chartdata.OneValueCDDefinition; +import com.fr.data.TableDataSource; +import com.fr.design.DesignModelAdapter; +import com.fr.design.data.DesignTableDataManager; +import com.fr.general.ComparatorUtils; +import com.fr.plugin.chart.custom.CustomDefinition; +import com.fr.plugin.chart.custom.type.CustomPlotType; +import com.fr.van.chart.designer.PlotFactory; +import java.util.Map; + +public class ChartDataHelper { + public static String[] getCommonChartFieldNames(Chart chart) { + if (chart == null) { + return null; + } + Plot plot = chart.getPlot(); + if (plot == null) { + return null; + } + + if (!PlotFactory.plotSupportAddTableField(plot)) { + return null; + } + TopDefinitionProvider definition = chart.getFilterDefinition(); + return getFieldNames(definition); + } + + public static String[] getCustomChartTableFieldNames(Chart chart, CustomPlotType plotType) { + if (chart == null || plotType == null) { + return null; + } + + TopDefinitionProvider filterDefinition = chart.getFilterDefinition(); + if (filterDefinition instanceof CustomDefinition) { + CustomDefinition customDefinition = (CustomDefinition) filterDefinition; + Map definitionProviderMap = customDefinition.getDefinitionProviderMap(); + return getFieldNames(definitionProviderMap.get(plotType)); + } + return null; + } + + private static String[] getFieldNames(TopDefinitionProvider definition) { + if (definition == null) { + return null; + } + DesignModelAdapter adapter = DesignModelAdapter.getCurrentModelAdapter(); + TableDataSource tableDataSource = adapter == null ? null : adapter.getBook(); + TableData tableData = null; + if (ComparatorUtils.equals(definition.getDataDefinitionType(), OneValueCDDefinition.DEFINITION_TYPE)) { + OneValueCDDefinition oneValueCDDefinition = (OneValueCDDefinition) definition; + tableData = oneValueCDDefinition.getTableData(); + } else if (ComparatorUtils.equals(definition.getDataDefinitionType(), MoreNameCDDefinition.DEFINITION_TYPE)) { + MoreNameCDDefinition moreNameCDDefinition = (MoreNameCDDefinition) definition; + tableData = moreNameCDDefinition.getTableData(); + } + if (tableData == null) { + return null; + } + return DesignTableDataManager.getSelectedColumnNames(tableDataSource, tableData.getName()); + } + +} diff --git a/designer-chart/src/main/java/com/fr/design/chart/ChartDialog.java b/designer-chart/src/main/java/com/fr/design/chart/ChartDialog.java index bce90aaaeb..183f14b768 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/ChartDialog.java +++ b/designer-chart/src/main/java/com/fr/design/chart/ChartDialog.java @@ -4,9 +4,11 @@ import com.fr.base.chart.BaseChartCollection; import com.fr.chart.chartattr.ChartCollection; import com.fr.design.dialog.BasicDialog; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.gui.chart.MiddleChartDialog; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.i18n.Toolkit; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.third.joda.time.DateTime; @@ -87,6 +89,10 @@ public class ChartDialog extends MiddleChartDialog { return new ActionListener() { public void actionPerformed(ActionEvent e) { chartTypePane.update((ChartCollection) cc, createTime); + DefaultValueAdjustProvider adjustProvider = DesignUtils.getValueAdjust(); + if (adjustProvider != null) { + adjustProvider.adjustChartCollectionStyle(cc); + } doOK(); } }; diff --git a/designer-chart/src/main/java/com/fr/design/chart/ChartTypePane.java b/designer-chart/src/main/java/com/fr/design/chart/ChartTypePane.java index d31cd32088..c34fcce653 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/ChartTypePane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/ChartTypePane.java @@ -8,11 +8,14 @@ import com.fr.chart.chartattr.ChartCollection; import com.fr.chart.charttypes.ChartTypeManager; import com.fr.chartx.attr.ChartProvider; import com.fr.design.ChartTypeInterfaceManager; +import com.fr.design.base.mode.DesignModeContext; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.chart.info.ChartInfoCollector; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; +import com.fr.stable.ArrayUtils; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; @@ -23,10 +26,10 @@ import javax.swing.JSplitPane; import javax.swing.ListCellRenderer; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.awt.Color; import java.awt.Component; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class ChartTypePane extends ChartCommonWizardPane implements CallbackEvent { private static final long serialVersionUID = -1175602484968520546L; @@ -44,6 +47,11 @@ public class ChartTypePane extends ChartCommonWizardPane implements CallbackEven DefaultListModel defaultListModel = new DefaultListModel(); mainTypeList = new JList(defaultListModel); + if (DesignModeContext.isDuchampMode() + && ArrayUtils.contains(chartIDs, ChartTypeInterfaceManager.GEO_LAND_CHART_ID)) { + chartIDs = ArrayUtils.removeElement(chartIDs, ChartTypeInterfaceManager.GEO_LAND_CHART_ID); + } + for (int i = 0; i < chartIDs.length; i++) { defaultListModel.insertElementAt(ChartTypeInterfaceManager.getInstance().getName(chartIDs[i]), i); } @@ -153,6 +161,8 @@ public class ChartTypePane extends ChartCommonWizardPane implements CallbackEven } } + DefaultStyleHelper4Van.checkChartDefaultStyle4Duchamp(chart4Update); + update(chart4Update); } diff --git a/designer-chart/src/main/java/com/fr/design/chart/axis/ChartAlertValuePane.java b/designer-chart/src/main/java/com/fr/design/chart/axis/ChartAlertValuePane.java index d0244cebab..59250c9725 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/axis/ChartAlertValuePane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/axis/ChartAlertValuePane.java @@ -18,6 +18,7 @@ import com.fr.design.layout.TableLayoutHelper; import com.fr.design.style.AlphaPane; import com.fr.design.style.FRFontPane; import com.fr.design.style.color.ColorSelectBox; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; @@ -114,7 +115,7 @@ public class ChartAlertValuePane extends BasicBeanPane { fontNameBox.setPreferredSize(new Dimension(80,20)); fontNameBox.addItem("SimSun"); // TODO 这边字体中没有在列表内 - String[] names = Utils.getAvailableFontFamilyNames4Report(); + String[] names = DesignUtils.getAvailableFontFamilyNames4Report(); for(int i = 0; i < names.length; i++) { fontNameBox.addItem(names[i]); } diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java b/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java index 133e2fef74..a5351c74bf 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java @@ -9,8 +9,9 @@ import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icombobox.FilterComboBox; +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.BoldFontTextLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.mainframe.DesignerContext; @@ -19,8 +20,6 @@ import com.fr.general.ComparatorUtils; import com.fr.general.GeneralUtils; import com.fr.general.data.DataModel; import com.fr.log.FineLoggerFactory; -import com.fr.stable.StringUtils; -import org.apache.batik.swing.svg.SVGFileFilter; import javax.swing.JFileChooser; import javax.swing.JPanel; @@ -110,10 +109,12 @@ public class MapCustomPane extends BasicBeanPane implements AbstrctMapAt private ActionListener selectPictureActionListener = new ActionListener() { + @Override public void actionPerformed(ActionEvent evt) { - FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder(). - filter(".svg, .svgz", "*.svg", "*.svgz"). - currentDirectory(lastSelectPath).build(); + FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser( + FileChooserArgs.newBuilder(). + setFilter(".svg, .svgz", "*.svg", "*.svgz"). + setSelectedPath(lastSelectPath).build()); int returnVal = fileChooserProvider.showDialog(DesignerContext.getDesignerFrame()); if (returnVal != JFileChooser.CANCEL_OPTION) { File selectedFile = fileChooserProvider.getSelectedFile(); diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ChartConditionPane.java b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ChartConditionPane.java index af44b6331c..4085c7f10c 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ChartConditionPane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ChartConditionPane.java @@ -7,6 +7,7 @@ import com.fr.design.beans.BasicBeanPane; import com.fr.design.condition.LiteConditionPane; import com.fr.design.editor.ValueEditorPane; import com.fr.design.editor.ValueEditorPaneFactory; +import com.fr.design.editor.editor.Editor; import com.fr.design.formula.CustomVariableResolver; import com.fr.design.formula.VariableResolver; import com.fr.design.gui.icombobox.UIComboBox; @@ -17,6 +18,7 @@ import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.general.ComparatorUtils; import com.fr.plugin.chart.type.ConditionKeyType; +import com.fr.stable.ArrayUtils; import com.fr.stable.StringUtils; import javax.swing.DefaultComboBoxModel; @@ -79,7 +81,10 @@ public class ChartConditionPane extends LiteConditionPane { return this; } }); - conditionValuePane = ValueEditorPaneFactory.createAllValueEditorPane(); + Editor[] editors = ValueEditorPaneFactory.allEditors(); + ColSelectedWithSummaryMethodEditor colSelectedWithSummaryMethodEditor = new ColSelectedWithSummaryMethodEditor(); + Editor[] allEditors = ArrayUtils.add(editors,colSelectedWithSummaryMethodEditor); + conditionValuePane = ValueEditorPaneFactory.createValueEditorPane(allEditors,StringUtils.EMPTY,StringUtils.EMPTY); conditionKeyComboBox.setPreferredSize(new Dimension(175, conditionKeyComboBox.getPreferredSize().height)); conditionOPComboBox.setPreferredSize(new Dimension(80, 20)); Component[][] components = { diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ColSelectedWithSummaryMethodEditor.java b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ColSelectedWithSummaryMethodEditor.java new file mode 100644 index 0000000000..be12d6214a --- /dev/null +++ b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/ColSelectedWithSummaryMethodEditor.java @@ -0,0 +1,118 @@ +package com.fr.design.chart.series.SeriesCondition; + +import com.fr.chart.chartattr.Chart; +import com.fr.chart.chartattr.ChartCommonCondition; +import com.fr.chart.chartattr.Plot; +import com.fr.chart.chartglyph.ConditionAttr; +import com.fr.chart.chartglyph.ConditionCollection; +import com.fr.data.DSColumnWithSummaryMethod; +import com.fr.data.util.function.AbstractDataFunction; +import com.fr.design.chart.ChartDataHelper; +import com.fr.design.data.datapane.SummaryMethodComboBox; +import com.fr.design.editor.editor.Editor; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.plugin.chart.attr.plot.VanChartPlot; +import com.fr.plugin.chart.custom.VanChartCustomPlot; +import com.fr.plugin.chart.custom.type.CustomPlotType; +import java.awt.Dimension; +import java.util.List; +import javax.swing.DefaultComboBoxModel; + +public class ColSelectedWithSummaryMethodEditor extends Editor { + private UIComboBox columnNameComboBox = new UIComboBox(); + private SummaryMethodComboBox summaryMethodComboBox; + private static DefaultComboBoxModel columnNameComboBoxModel = new DefaultComboBoxModel<>(); + private static DefaultComboBoxModel summaryMethodComboBoxModel = new DefaultComboBoxModel<>(SummaryMethodComboBox.CALCULATE_ARRAY); + + public ColSelectedWithSummaryMethodEditor() { + this.setName(Toolkit.i18nText("Fine-Design_Chart_Summary_Field_Value")); + this.setLayout(FRGUIPaneFactory.createLeftZeroLayout()); + if (columnNameComboBox == null) { + columnNameComboBox = new UIComboBox(); + } + columnNameComboBox.setPreferredSize(new Dimension(82, 20)); + summaryMethodComboBox = new SummaryMethodComboBox(); + summaryMethodComboBox.setModel(summaryMethodComboBoxModel); + summaryMethodComboBox.setPreferredSize(new Dimension(82, 20)); + this.setLayout(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); + this.add(columnNameComboBox); + this.add(summaryMethodComboBox); + columnNameComboBox.setModel(columnNameComboBoxModel); + columnNameComboBox.setSelectedItem(null); + summaryMethodComboBox.setSelectedItem(null); + } + + public static void refreshCommonChartFieldNames(Chart chart) { + refreshComboBoxModel(ChartDataHelper.getCommonChartFieldNames(chart)); + } + + public static void refreshCustomChartTableFieldNames(Chart chart, CustomPlotType plotType) { + refreshComboBoxModel(ChartDataHelper.getCustomChartTableFieldNames(chart, plotType)); + } + + private static void refreshComboBoxModel(String[] columnNames) { + columnNameComboBoxModel.removeAllElements(); + summaryMethodComboBoxModel.removeAllElements(); + if (columnNames != null) { + for (String columnName : columnNames) { + columnNameComboBoxModel.addElement(columnName); + } + for (String method : SummaryMethodComboBox.CALCULATE_ARRAY) { + summaryMethodComboBoxModel.addElement(method); + } + columnNameComboBoxModel.setSelectedItem(null); + summaryMethodComboBoxModel.setSelectedItem(null); + } + } + + public String getIconName() { + return "ds_column_summary"; + } + + @Override + public DSColumnWithSummaryMethod getValue() { + if (columnNameComboBox.getSelectedItem() == null || summaryMethodComboBox.getSelectedItem() == null) { + return null; + } + DSColumnWithSummaryMethod dsColumnWithSummaryMethod = new DSColumnWithSummaryMethod(); + dsColumnWithSummaryMethod.setFieldName(columnNameComboBox.getSelectedItem().toString()); + dsColumnWithSummaryMethod.setDataFunction(summaryMethodComboBox.updateBean()); + return dsColumnWithSummaryMethod; + } + + @Override + public void setValue(DSColumnWithSummaryMethod value) { + if (value != null) { + columnNameComboBox.setSelectedItem(value.getFieldName()); + summaryMethodComboBox.populateBean((AbstractDataFunction)value.getDataFunction()); + } + } + + @Override + public boolean accept(Object object) { + return object instanceof DSColumnWithSummaryMethod; + } + + public static void update(int index, Plot plot) { + if (plot instanceof VanChartCustomPlot) { + List list = ((VanChartCustomPlot) plot).getCustomPlotList(); + VanChartPlot vanChartPlot = list.get(index); + ConditionCollection conditionCollection = vanChartPlot.getConditionCollection(); + ConditionAttr[] conditionAttrs = conditionCollection.getAllConditionAttrList(); + for (ConditionAttr conditionAttr : conditionAttrs) { + if (conditionAttr.getCondition() instanceof ChartCommonCondition) { + ChartCommonCondition chartCommonCondition = (ChartCommonCondition) conditionAttr.getCondition(); + if (chartCommonCondition.getCompare().getValue() instanceof DSColumnWithSummaryMethod) { + DSColumnWithSummaryMethod dsColumnWithSummaryMethod = (DSColumnWithSummaryMethod) chartCommonCondition.getCompare().getValue(); + columnNameComboBoxModel.setSelectedItem(dsColumnWithSummaryMethod.getFieldName()); + summaryMethodComboBoxModel.setSelectedItem(ChartCommonCondition.FORMAT_MAP.get(String.valueOf(dsColumnWithSummaryMethod.getDataFunction().getFormula()))); + return; + } + } + } + } + } + +} diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/DataLabelStylePane.java b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/DataLabelStylePane.java index a2047b4e1c..c2036b7292 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/DataLabelStylePane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/DataLabelStylePane.java @@ -9,6 +9,7 @@ import com.fr.chart.base.TextAttr; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.dialog.BasicPane; +import com.fr.design.utils.DesignUtils; import com.fr.general.FRFont; import com.fr.design.style.FRFontPane; @@ -36,7 +37,7 @@ public class DataLabelStylePane extends BasicPane { private void initPane(boolean isSurpportFontColor) { this.setLayout(FRGUIPaneFactory.createBoxFlowLayout()); - this.add(nameBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report())); + this.add(nameBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report())); nameBox.setPreferredSize(new Dimension(80, 20)); String[] styles = { diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/impl/ChartHyperPoplinkPane.java b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/impl/ChartHyperPoplinkPane.java index 3372880dda..35b0c0d5bc 100644 --- a/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/impl/ChartHyperPoplinkPane.java +++ b/designer-chart/src/main/java/com/fr/design/chart/series/SeriesCondition/impl/ChartHyperPoplinkPane.java @@ -8,16 +8,19 @@ import com.fr.chart.web.ChartHyperPoplink; import com.fr.chartx.attr.ChartProvider; import com.fr.design.chart.gui.ChartComponent; import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.hyperlink.AbstractHyperLinkPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.chart.ChartHyperEditPane; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; +import com.fr.van.chart.config.DefaultStyleHelper4Van; -import java.util.HashMap; import java.awt.BorderLayout; import java.awt.Dimension; +import java.util.HashMap; /** * 类说明: 图表超链 -- 弹出 悬浮窗. @@ -66,11 +69,16 @@ public class ChartHyperPoplinkPane extends AbstractHyperLinkPane extends BasicBeanPane(columnNameList); } private void checkCardPane() { diff --git a/designer-chart/src/main/java/com/fr/design/chartx/component/correlation/AbstractCorrelationPane.java b/designer-chart/src/main/java/com/fr/design/chartx/component/correlation/AbstractCorrelationPane.java index 5c468c424a..2cb52f4542 100644 --- a/designer-chart/src/main/java/com/fr/design/chartx/component/correlation/AbstractCorrelationPane.java +++ b/designer-chart/src/main/java/com/fr/design/chartx/component/correlation/AbstractCorrelationPane.java @@ -127,4 +127,14 @@ public abstract class AbstractCorrelationPane extends BasicBeanPane { return StringUtils.EMPTY; } + /** + * 清空 “系列名使用字段名” 表格 + */ + public void clearAllBoxList() { + this.correlationPane.getTable().clear(); + this.correlationPane.validate(); + this.correlationPane.repaint(); + this.correlationPane.revalidate(); + } + } diff --git a/designer-chart/src/main/java/com/fr/design/chartx/single/DataSetPane.java b/designer-chart/src/main/java/com/fr/design/chartx/single/DataSetPane.java index 3df0d3d6d5..dab74e15a4 100644 --- a/designer-chart/src/main/java/com/fr/design/chartx/single/DataSetPane.java +++ b/designer-chart/src/main/java/com/fr/design/chartx/single/DataSetPane.java @@ -8,6 +8,7 @@ import com.fr.design.chartx.fields.AbstractDataSetFieldsPane; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.chart.gui.data.DatabaseTableDataPane; +import com.fr.stable.StringUtils; import javax.swing.JPanel; import java.awt.BorderLayout; @@ -75,6 +76,10 @@ public class DataSetPane extends FurtherBasicBeanPane { List columnNameList = dataWrap.calculateColumnNameList(); if (dataSetFieldsPane != null) { + // 如果属性编辑画板中选中的数据集发生改变,则清空之前的匹配项 + if (!StringUtils.equals(dataSetFieldsPane.getTableName(), dataWrap.getTableDataName())) { + dataSetFieldsPane.clearAllBoxList(); + } dataSetFieldsPane.refreshBoxListWithSelectTableData(columnNameList); dataSetFieldsPane.setTableName(dataWrap.getTableDataName()); } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java index 2d4d5fef6c..4efe977ff3 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java @@ -16,7 +16,6 @@ import com.fr.design.gui.chart.ChartEditPaneProvider; import com.fr.design.gui.frpane.UITitlePanel; import com.fr.design.mainframe.chart.ChartEditPane; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.stable.AssistUtils; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -36,9 +35,6 @@ public class ChartPropertyPane extends BaseChartPropertyPane { protected ChartEditPane chartEditPane; - //ID一样的话 不用新建chartEditPane - private String currentID; - private ChartPropertyPane() { initComponent(); } @@ -50,14 +46,9 @@ public class ChartPropertyPane extends BaseChartPropertyPane { @Override public void updateChartEditPane(String plotID) { - if (!AssistUtils.equals(currentID, plotID)) { - chartEditPane = ChartTypeInterfaceManager.getInstance().getChartEditPane(plotID); - chartEditPane.setContainer(container); - currentID = plotID; - resetChartEditPane(); - } else { - chartEditPane.resetLastChartCollection(); - } + chartEditPane = ChartTypeInterfaceManager.getInstance().getChartEditPane(plotID); + chartEditPane.setContainer(container); + resetChartEditPane(); } @Override diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java index 70b7130f12..6064ef89d0 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java @@ -22,11 +22,14 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane; import com.fr.design.mainframe.chart.gui.ChartTypePane; import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane; import com.fr.design.mainframe.chart.info.ChartInfoCollector; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.form.main.Form; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; +import com.fr.plugin.chart.custom.VanChartCustomPlot; import com.fr.plugin.chart.vanchart.VanChart; +import com.fr.van.chart.drillmap.designer.data.VanChartDrillMapDataPane; import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -146,7 +149,12 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare ChartInfoCollector.getInstance().updateChartPropertyTime(collection.getSelectedChartProvider(ChartProvider.class)); selectedPane.update(collection); - + for (int i = 0; i < paneList.size(); i++) { + if (paneList.get(i) instanceof VanChartDrillMapDataPane && i != tabsHeaderIconPane.getSelectedIndex()) { + paneList.get(i).populateBean(collection); + break; + } + } if (!ComparatorUtils.equals(collection, lastCollection)) { VanChart vanChart = collection.getSelectedChartProvider(VanChart.class); if (vanChart != null) { @@ -334,7 +342,10 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare String chartID = chart.getID(); boolean currentPane = ChartTypeInterfaceManager.getInstance().isUseDefaultPane(chartID); - return (currentPane != isDefaultPane) || (!currentPane && lastIndex != currentIndex); + boolean duchampCustomChart = ChartEditContext.duchampMode() + && VanChartCustomPlot.VAN_CHART_CUSTOM_PLOT_ID.equals(chartID); + + return (currentPane != isDefaultPane) || (!currentPane && lastIndex != currentIndex) || duchampCustomChart; } return false; } 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..a04acb83de 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,45 @@ 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.chart.chartattr.SwitchTitle; import com.fr.design.beans.BasicBeanPane; +import com.fr.design.dialog.AttrScrollPane; +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.stable.StringUtils; 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 +56,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,23 +73,44 @@ 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(){ + init(); + this.setLayout(new BorderLayout()); + this.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15)); + this.add(createScrollPane(), BorderLayout.CENTER); + } + + private JPanel createScrollPane() { + return new AttrScrollPane() { + @Override + protected JPanel createContentPane() { + return contentPane; + } + }; + } + + private void init() { initButtonGroup(); configPane = createConfigPane(); contentPane = createContentPane(); contentPane.setBorder(BorderFactory.createEmptyBorder(CONSTANT_TEN, CONSTANT_THIRTY, CONSTANT_TEN, CONSTANT_THIRTY)); - this.add(contentPane, BorderLayout.CENTER); } private JPanel createContentPane() { 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 +185,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)); + chartTypesPane.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); + switchTitlePane.setLayout(new CardLayout()); + + JPanel titleEditPane = TableLayout4VanChartHelper.createGapTableLayoutPane( + Toolkit.i18nText("Fine-Design_Chart_Switch_Title_Label"), + switchTitlePane, + EDIT_AREA_WIDTH + ); + titleEditPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + + buttonContentPane.add(chartTypesPane, BorderLayout.NORTH); + buttonContentPane.add(titleEditPane, BorderLayout.CENTER); + + UIExpandablePane expandablePane = new UIExpandablePane(Toolkit.i18nText("Fine-Design_Chart_Button_And_Rotation_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); + } + + showSwitchTitleCard(collection.getChartName(select)); + chartTypesPane.revalidate(); + switchTitlePane.revalidate(); + selectedChart = select; + } + + private void populateSwitchTitlePane(int chartIndex, ChartCollection collection) { + Chart chart = collection.getChart(chartIndex, Chart.class); + SwitchTitle switchTitle = chart.getSwitchTitle(); + Object content = switchTitle.getContent(); + String result = StringUtils.EMPTY; + if (content != null) { + if (content instanceof BaseFormula) { + result = ((BaseFormula) content).getContent(); + } else { + result = Utils.objectToString(content); + } + } + 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 +303,7 @@ public class ChangeConfigPane extends BasicBeanPane { //按钮切换界面 styleAttrPane.populate(changeConfigAttr.getStyleAttr()); colorSelectBox4button.setSelectObject(changeConfigAttr.getButtonColor()); + populateButtonContentPane(ob); //轮播切换界面 timeInterval.setValue(changeConfigAttr.getTimeInterval()); @@ -224,10 +333,68 @@ 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(new SwitchTitle(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(); + showSwitchTitleCard(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); + } + } + + private void showSwitchTitleCard(String chartName) { + CardLayout cardLayout = (CardLayout) switchTitlePane.getLayout(); + cardLayout.show(switchTitlePane, chartName); + } } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartOtherPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartOtherPane.java index 4bc363306c..36bc56d6b8 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartOtherPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartOtherPane.java @@ -5,6 +5,7 @@ import com.fr.chart.chartattr.ChartCollection; import com.fr.chart.chartattr.Plot; import com.fr.chartx.config.info.constant.ConfigType; import com.fr.design.beans.BasicBeanPane; +import com.fr.design.chart.series.SeriesCondition.ColSelectedWithSummaryMethodEditor; import com.fr.design.dialog.BasicPane; import com.fr.design.mainframe.chart.AbstractChartAttrPane; import com.fr.design.mainframe.chart.ChartEditPane; @@ -112,6 +113,7 @@ public class ChartOtherPane extends AbstractChartAttrPane { interactivePane.populateBean(chart); if (ChartOtherPane.this.isHaveCondition()) { VanChartRichEditorPane.refreshCommonChartFieldNames(chart); + ColSelectedWithSummaryMethodEditor.refreshCommonChartFieldNames(chart); conditionAttrPane.populateBean(chart); } } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java index 1fdd6e9fd8..8b1c293282 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java @@ -22,6 +22,7 @@ import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.plugin.chart.vanchart.VanChart; import com.fr.stable.StringUtils; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import javax.swing.BorderFactory; import javax.swing.BoxLayout; @@ -154,6 +155,7 @@ public class ChartTypeButtonPane extends BasicBeanPane implemen addButton.addActionListener((e) -> { String name = getNewChartName(); ChartProvider chart = getChangeStateNewChart(); + DefaultStyleHelper4Van.checkChartDefaultStyle4Duchamp(chart); checkInForm(chart); addNewChart(chart, name, editingCollection.getChartCount()); }); @@ -660,7 +662,7 @@ public class ChartTypeButtonPane extends BasicBeanPane implemen //记录改变前的plotID String lastPlotID = editingCollection == null ? StringUtils.EMPTY : editingCollection.getSelectedChartProvider(ChartProvider.class).getID(); changeCollectionSelected(getButtonName()); - setSelectedWithFireListener(true); + setSelected(true, true); fireSelectedChanged(); //需要先更新,最后重构面板 diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java index 2eea49f16d..bd94ff561a 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java @@ -19,7 +19,6 @@ import com.fr.design.mainframe.chart.gui.item.FlexibleComboBox; import com.fr.design.mainframe.chart.gui.item.ItemEventType; import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane; import com.fr.design.mainframe.chart.mode.ChartEditContext; -import com.fr.design.mainframe.chart.mode.ChartEditMode; import com.fr.design.module.DesignModuleFactory; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; @@ -27,11 +26,6 @@ import com.fr.stable.AssistUtils; import com.fr.stable.StringUtils; import javax.swing.JPanel; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.event.ActionEvent; @@ -40,6 +34,11 @@ 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.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; /** * 图表 属性表, 类型选择 界面. @@ -55,6 +54,7 @@ public class ChartTypePane extends AbstractChartAttrPane { private ActionListener autoButtonListener; private boolean inForm; + @Override protected JPanel createContentPane() { initButtonListener(); @@ -291,13 +291,20 @@ public class ChartTypePane extends AbstractChartAttrPane { String plotID = entry.getKey(); if (ignore || ChartTypeManager.enabledChart(plotID)) { if (ChartTypeManager.getInstance().isShowInDesigner(plotID)) { - cards.add(entry.getValue()); + if (notGeoLandInDuchampCPT(plotID)) { + cards.add(entry.getValue()); + } } } } } + public boolean notGeoLandInDuchampCPT(String plotID) { + return !(DesignModeContext.isDuchampMode() + && ChartTypeInterfaceManager.GEO_LAND_CHART_ID.equals(plotID)); + } + private void addOnePlotIDCards(int priority, String plotID) { cards.add(allChartTypePane.get(priority).get(plotID)); } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/CalculateComboBox.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/CalculateComboBox.java index a1ad223125..61a906a3f2 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/CalculateComboBox.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/CalculateComboBox.java @@ -1,17 +1,6 @@ package com.fr.design.mainframe.chart.gui.data; -import com.fr.data.util.function.AbstractDataFunction; -import com.fr.data.util.function.AverageFunction; -import com.fr.data.util.function.CountFunction; -import com.fr.data.util.function.MaxFunction; -import com.fr.data.util.function.MinFunction; -import com.fr.data.util.function.NoneFunction; -import com.fr.data.util.function.SumFunction; -import com.fr.design.gui.icombobox.UIComboBox; -import com.fr.design.i18n.Toolkit; -import com.fr.general.ComparatorUtils; -import com.fr.log.FineLoggerFactory; -import com.fr.plugin.chart.base.FirstFunction; +import com.fr.design.data.datapane.SummaryMethodComboBox; /** @@ -20,53 +9,11 @@ import com.fr.plugin.chart.base.FirstFunction; * @author kunsnat E-mail:kunsnat@gmail.com * @version 创建时间:2013-1-8 上午09:52:15 */ -public class CalculateComboBox extends UIComboBox { - - public static final String[] CALCULATE_ARRAY = {Toolkit.i18nText("Fine-Design_Chart_Data_Function_First"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Last"), - Toolkit.i18nText("Fine-Design_Chart_Data_Function_Sum"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Average"), - Toolkit.i18nText("Fine-Design_Chart_Data_Function_Max"), Toolkit.i18nText("Fine-Design_Chart_Data_Function_Min"), - Toolkit.i18nText("Fine-Design_Chart_Data_Function_Count")}; - public static final Class[] CLASS_ARRAY = {FirstFunction.class, NoneFunction.class, SumFunction.class, AverageFunction.class, - MaxFunction.class, MinFunction.class, CountFunction.class}; +public class CalculateComboBox extends SummaryMethodComboBox { + public static final String[] CALCULATE_ARRAY = SummaryMethodComboBox.CALCULATE_ARRAY; + public static final Class[] CLASS_ARRAY = SummaryMethodComboBox.CLASS_ARRAY; public CalculateComboBox() { - super(CALCULATE_ARRAY); - setSelectedIndex(2); - } - - public void reset() { - this.setSelectedItem(Toolkit.i18nText("Fine-Design_Chart_Data_Function_Sum")); - } - - /** - * 更新公式选择. - */ - public void populateBean(AbstractDataFunction function) { - for (int i = 0; i < CLASS_ARRAY.length; i++) { - if (function != null && ComparatorUtils.equals(function.getClass(), CLASS_ARRAY[i])) { - setSelectedIndex(i); - break; - } - } - } - - /** - * 返回当前选择的公式 - */ - public AbstractDataFunction updateBean() { - try { - int selectIndex = getSelectedIndex(); - if (selectIndex >= 0 && selectIndex < CLASS_ARRAY.length) { - return (AbstractDataFunction) CLASS_ARRAY[selectIndex].newInstance(); - } - } catch (InstantiationException e) { - FineLoggerFactory.getLogger().error("Function Error"); - return null; - } catch (IllegalAccessException e) { - FineLoggerFactory.getLogger().error("Function Error"); - return null; - } - - return null; + super(); } } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/ChartDataHelper.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/ChartDataHelper.java new file mode 100644 index 0000000000..0ff5b275f4 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/ChartDataHelper.java @@ -0,0 +1,35 @@ +package com.fr.design.mainframe.chart.gui.data; + +import com.fr.base.chart.chartdata.TopDefinitionProvider; +import com.fr.chart.chartattr.ChartCollection; +import com.fr.chart.chartattr.Plot; +import com.fr.plugin.chart.attr.axis.VanChartAxis; +import com.fr.plugin.chart.attr.axis.VanChartAxisLabelStyle; +import com.fr.plugin.chart.attr.plot.VanChartAxisPlot; +import com.fr.van.chart.config.DefaultStyleHelper4Van; + +/** + * @author shine + * @version 10.0 + * Created by shine on 2022/4/6 + */ +public class ChartDataHelper { + + /** + * 在update数据集分类的时候,需要联动update一下样式-坐标轴里面的分层样式设置,来自CHART-22873 + */ + public static void updateAxisCategoryStyles(ChartCollection chartCollection) { + TopDefinitionProvider definition = chartCollection.getSelectedChart().getFilterDefinition(); + int size = definition == null ? 1 : definition.getMoreCateSize() + 1; + + Plot plot = chartCollection.getSelectedChart().getPlot(); + if (plot instanceof VanChartAxisPlot) { + for (VanChartAxis axis : ((VanChartAxisPlot) plot).getXAxisList()) { + axis.clearCategoryStyles(); + for (int i = 0; i < size; i++) { + axis.addCategoryStyle(DefaultStyleHelper4Van.dealAxisCheckTheme(new VanChartAxisLabelStyle())); + } + } + } + } +} diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/TableDataPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/TableDataPane.java index 8863977740..82240bc6d2 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/TableDataPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/TableDataPane.java @@ -15,6 +15,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.chart.gui.ChartDataPane; import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane; import com.fr.design.utils.gui.UIComponentUtils; +import com.fr.stable.StringUtils; import javax.swing.BorderFactory; import java.awt.BorderLayout; @@ -74,6 +75,10 @@ public class TableDataPane extends FurtherBasicBeanPane{ return; } if(dataContentPane != null) { + // 如果属性编辑画板中选中的数据集发生改变,则清空之前的匹配项 + if (!StringUtils.equals(dataContentPane.getTableName(), dataWrap.getTableDataName())) { + dataContentPane.clearAllBoxList(); + } dataContentPane.onSelectTableData(dataWrap); dataContentPane.setTableName(dataWrap.getTableDataName()); } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java index d4e1f64e77..427e241e60 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java @@ -13,20 +13,21 @@ import com.fr.design.formula.TinyFormulaPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.mainframe.chart.gui.ChartDataPane; import com.fr.design.mainframe.chart.gui.data.ChartDataFilterPane; +import com.fr.design.mainframe.chart.gui.data.ChartDataHelper; import com.fr.stable.StringUtils; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JPanel; -import java.util.ArrayList; -import java.util.List; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; /** @@ -40,7 +41,7 @@ public class CategoryPlotMoreCateReportDataContentPane extends CategoryPlotRepor private JPanel boxPane; private UIButton addButton; - private ArrayList formualList = new ArrayList(); + private List formualList = new ArrayList(); private UIObserverListener uiobListener = null; public List getFormualList() { @@ -190,10 +191,9 @@ public class CategoryPlotMoreCateReportDataContentPane extends CategoryPlotRepor Plot plot = collection.getSelectedChart().getPlot(); if (definition instanceof NormalReportDataDefinition) { NormalReportDataDefinition reportDefinition = (NormalReportDataDefinition) definition; - reportDefinition.clearMoreCate(); updateMoreCate(reportDefinition, plot); - + ChartDataHelper.updateAxisCategoryStyles(collection); } } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java index 3bf0225ef2..7432dfcce1 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java @@ -13,11 +13,16 @@ import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.BoldFontTextLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.mainframe.chart.gui.ChartDataPane; +import com.fr.design.mainframe.chart.gui.data.ChartDataHelper; import com.fr.design.utils.gui.GUICoreUtils; - -import javax.swing.*; -import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +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 java.awt.event.ItemEvent; @@ -39,7 +44,7 @@ public class CategoryPlotMoreCateTableDataContentPane extends CategoryPlotTableD private JPanel boxPane; - private ArrayList boxList = new ArrayList(); + private List boxList = new ArrayList(); private UIButton addButton; private UIObserverListener uiobListener = null; @@ -242,6 +247,7 @@ public class CategoryPlotMoreCateTableDataContentPane extends CategoryPlotTableD normal.clearMoreCate(); updateMoreCate(normal, plot); } + ChartDataHelper.updateAxisCategoryStyles(collection); } protected void updateMoreCate(NormalTableDataDefinition normal, Plot plot) { @@ -252,5 +258,4 @@ public class CategoryPlotMoreCateTableDataContentPane extends CategoryPlotTableD } } } - } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/SeriesNameUseFieldNamePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/SeriesNameUseFieldNamePane.java index 9783c0577a..ec63cda9b9 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/SeriesNameUseFieldNamePane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/SeriesNameUseFieldNamePane.java @@ -24,8 +24,6 @@ import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.event.ChangeEvent; -import java.util.ArrayList; -import java.util.List; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; @@ -33,6 +31,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.List; /** * 属性表 数据集界面: 系列名 使用字段名. @@ -145,7 +145,7 @@ public class SeriesNameUseFieldNamePane extends FurtherBasicBeanPane { + // kuns: 默认修改500, 在地图修改系列颜色text时, 快速响应. + SwingUtilities.invokeLater(this::runChange); }, 500, TimeUnit.MILLISECONDS); } diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java index 736ae5b3f7..2ae7e502e1 100644 --- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java +++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java @@ -21,6 +21,7 @@ import com.fr.design.style.color.ColorSelectBox; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.stable.StringUtils; import com.fr.van.chart.designer.TableLayout4VanChartHelper; +import com.fr.van.chart.range.component.LegendGradientBar; import javax.swing.JComponent; import javax.swing.JFrame; @@ -29,8 +30,6 @@ import javax.swing.JPanel; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.util.ArrayList; -import java.util.List; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -42,6 +41,8 @@ import java.awt.LayoutManager; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; public class UIColorPickerPane extends BasicPane implements UIObserver { private static final int MARGIN_TOP = 7; @@ -102,7 +103,7 @@ public class UIColorPickerPane extends BasicPane implements UIObserver { } }); - regionNumPane = new UINumberDragPane(1, 6) { + regionNumPane = new UINumberDragPane(1, LegendGradientBar.COLOR_GRADUAL_NUM_MAX) { @Override public void userEvent(double value) { if(!UIColorPickerPane.this.moveOnColorOrTextPane){ @@ -191,7 +192,7 @@ public class UIColorPickerPane extends BasicPane implements UIObserver { } }); - regionNumPane = new UINumberDragPane(1, 6) { + regionNumPane = new UINumberDragPane(1, LegendGradientBar.COLOR_GRADUAL_NUM_MAX) { @Override public void userEvent(double value) { if(!UIColorPickerPane.this.moveOnColorOrTextPane){ @@ -696,14 +697,18 @@ public class UIColorPickerPane extends BasicPane implements UIObserver { fillStyleCombox.setSelectObject(mainColor); designTypeButtonGroup.setSelectedIndex(hotAreaColor.getUseType()); - double value = (double) hotAreaColor.getAreaNumber(); + int value = hotAreaColor.getAreaNumber(); UIColorPickerPane.this.add(textGroup); UIColorPickerPane.this.add(colorGroup); Color[] colors = hotAreaColor.initColor(); BaseFormula[] values = hotAreaColor.initValues(); + if (value != colors.length && hotAreaColor.getUseType() == MapHotAreaColor.CUSTOM) { + colors = getColorArray(mainColor, value); + values = getValueArray(value); + } refreshGroupPane(colors, values); this.initContainerLister(); - regionNumPane.populateBean(value); + regionNumPane.populateBean((double) value); refreshPane(); } diff --git a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java index 378e6a0d79..e0112f1865 100644 --- a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java +++ b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java @@ -59,7 +59,7 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup { return false; } - if (template.isJWorkBook() || DesignModeContext.isDuchampMode()) { + if (template.isJWorkBook()) { // 如果是普通报表单元格,那么没有 FormHyperlink 选项 FormHyperlinkProvider formHyperlink = StableFactory.getMarkedInstanceObjectFromClass(FormHyperlinkProvider.XML_TAG, FormHyperlinkProvider.class); //返回true表示可用,返回false表示不可用 diff --git a/designer-chart/src/main/java/com/fr/van/chart/DownloadOnlineSourcesHelper.java b/designer-chart/src/main/java/com/fr/van/chart/DownloadOnlineSourcesHelper.java index 33dba72f9b..a2e43df3eb 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/DownloadOnlineSourcesHelper.java +++ b/designer-chart/src/main/java/com/fr/van/chart/DownloadOnlineSourcesHelper.java @@ -5,9 +5,12 @@ import com.fr.design.RestartHelper; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.extra.PluginConstants; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.CloudCenter; import com.fr.general.IOUtils; +import com.fr.general.SiteBlockedException; import com.fr.general.http.HttpClient; import com.fr.plugin.chart.DownloadSourcesEvent; import com.fr.stable.CommonUtils; @@ -20,6 +23,8 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; @@ -33,6 +38,8 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; +import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL; + /** * Created by shine on 2017/8/21. */ @@ -69,7 +76,23 @@ public class DownloadOnlineSourcesHelper implements DownloadSourcesEvent { //本地有这个资源,不下载 return; } - httpClient = new HttpClient(CloudCenter.getInstance().acquireUrlByKind(siteKind)); + try { + httpClient = new HttpClient(CloudCenter.getInstance().acquireUrlByKind(siteKind)); + } catch (SiteBlockedException e) { + FineJOptionPane.showConfirmDialogWithOkListener(null, + e.getMessage(), + Toolkit.i18nText("Fine-Design_Basic_Alert"), null, null, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DesignUtils.visitEnvServerByParameters( + "#management/system/normal", + null, + null); + } + }); + return; + } if (httpClient.getResponseCode() != HttpURLConnection.HTTP_OK) { //服务器连不上,不下载 return; @@ -116,12 +139,22 @@ public class DownloadOnlineSourcesHelper implements DownloadSourcesEvent { private void downloadAndInstallPluginDependenceFile() { try { double currentBytesRead = 0; + result = false; for (int i = 0; i < list.size(); i++) { SiteInfo siteInfo = list.get(i); - - httpClient = new HttpClient(CloudCenter.getInstance().acquireUrlByKind(siteInfo.siteKind)); + try { + httpClient = new HttpClient(CloudCenter.getInstance().acquireUrlByKind(siteInfo.siteKind)); + } catch (SiteBlockedException e) { + FineJOptionPane.showConfirmDialog(null, + e.getMessage(), + Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.DEFAULT_OPTION, + FineJOptionPane.WARNING_MESSAGE, null, OPTION_OK_CANCEL, null); + result = false; + return; + } if (httpClient.getResponseCode() == HttpURLConnection.HTTP_OK) { + result = true; String temp = StableUtils.pathJoin(PluginConstants.DOWNLOAD_PATH, PluginConstants.TEMP_FILE); File file = new File(temp); StableUtils.makesureFileExist(file); diff --git a/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleConstants.java b/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleConstants.java new file mode 100644 index 0000000000..64f9838f96 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleConstants.java @@ -0,0 +1,96 @@ +package com.fr.van.chart.config; + +import com.fr.base.ChartPreStyleConfig; +import com.fr.chart.base.ChartBaseUtils; +import com.fr.chart.base.ChartConstants; +import com.fr.general.Background; +import com.fr.general.FRFont; +import com.fr.general.GeneralUtils; +import com.fr.stable.CodeUtils; +import com.fr.stable.Constants; + +import java.awt.Color; +import java.awt.Font; + +/** + * @author shine + * @version 10.0 + * Created by shine on 2021/6/25 + */ +public class DefaultStyleConstants { + static final FRFont TITLE = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.BOLD, 19, new Color(241, 246, 255)); + static final FRFont LEGEND = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 12, new Color(159, 173, 191)); + + static final FRFont AXIS_LABEL = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 12, new Color(159, 173, 191)); + static final FRFont AXIS_TITLE = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 12, new Color(200, 211, 228)); + static final Color AXIS_LINE = new Color(46, 75, 102); + static final Color GRID_LINE = new Color(30, 55, 78); + + static final FRFont ALERT_FONT = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 12, new Color(255, 0, 0)); + + static final FRFont DATA_SHEET = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 12, new Color(159, 173, 191)); + static final Color DATA_SHEET_BORDER = new Color(46, 75, 102); + + static final Color BORDER = Color.BLACK; + static final int BORDER_WIDTH = Constants.LINE_NONE; + static final int SPECIAL_BORDER_WIDTH = Constants.LINE_THIN; + + static final FRFont PIE_CATEGORY_LABEL = FRFont.getInstance(ChartBaseUtils.getLocalDefaultFont("Microsoft YaHei"), Font.PLAIN, 13, new Color(232, 232, 232)); + + static final Color GAUGE_PANE_BACK_COLOR = null; + static final Color GAUGE_HINGE = null; + static final Color GAUGE_PANE_BACK_COLOR_4_RING = new Color(72, 73, 79); + static final Color GAUGE_SLOT_BACKGROUND_COLOR = new Color(72, 73, 79); + private static final String FONT_NAME = ChartBaseUtils.getLocalDefaultFont("verdana"); + static final FRFont THERMOMETER_LABEL_FONT = FRFont.getInstance(FONT_NAME, Font.BOLD, 12, new Color(232, 232, 232));//试管仪表盘标签的默认样式 + static final FRFont THERMOMETER_AXIS_LABEL = FRFont.getInstance(FONT_NAME, Font.PLAIN, 11, new Color(159, 173, 191)); + static final FRFont RING_VALUE_LABEL_FONT = FRFont.getInstance(FONT_NAME, Font.PLAIN, ChartConstants.AUTO_FONT_SIZE, new Color(232, 232, 232));//百分比圆环仪表盘值标签的默认样式 + static final FRFont POINTER_VALUE_LABEL_FONT = FRFont.getInstance(FONT_NAME, Font.PLAIN, ChartConstants.AUTO_FONT_SIZE, new Color(232, 232, 232));//多指针仪表盘值标签的默认样式 + static final FRFont POINTER_CATE_LABEL_FONT = FRFont.getInstance(FONT_NAME, Font.PLAIN, 13, new Color(232, 232, 232));//多指针仪表盘分类标签的默认样式 + + static final Color MAP_NULL_VALUE_COLOR = new Color(168, 168, 168); + static final Color MAP_BORDER = Color.BLACK; + static final Color MAP_LEGEND_BACK = Color.BLACK; + static final Color MAP_TITLE_BACK = Color.BLACK; + + static final Color DRILL_MAP_DRILL_TOOLS_BACK = Color.BLACK; + static final float DRILL_MAP_DRILL_TOOLS_BACK_OPACITY = 0.8f; + + static final Background BACK = null; + + //新特新 + public static String COLOR_NAME_1; + //经典高亮 + private static String COLOR_NAME_2; + + static { + try { + COLOR_NAME_1 = CodeUtils.cjkDecode("\u65b0\u7279\u6027"); + COLOR_NAME_2 = CodeUtils.cjkDecode("\u7ecf\u5178\u9ad8\u4eae"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + static String COLORS = null; + + static { + ChartPreStyleConfig config = ChartPreStyleConfig.getInstance(); + + COLORS = COLOR_NAME_2; + // 没有经典高亮, 用新特性 + if (config.getPreStyle(COLORS) == null) { + COLORS = COLOR_NAME_1; + } + // 没有新特性, 用第一个配色 + if (config.getPreStyle(COLORS) == null) { + if (config.names().hasNext()) { + + String name = GeneralUtils.objectToString(config.names().next()); + if (config.getPreStyle(name) != null) { + COLORS = name; + } + } + } + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleHelper4Van.java b/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleHelper4Van.java new file mode 100644 index 0000000000..60f208f228 --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/config/DefaultStyleHelper4Van.java @@ -0,0 +1,266 @@ +package com.fr.van.chart.config; + +import com.fr.base.ChartColorMatching; +import com.fr.base.ChartPreStyleConfig; +import com.fr.chart.base.AttrBorder; +import com.fr.chart.base.AttrFillStyle; +import com.fr.chart.base.ChartConstants; +import com.fr.chart.base.ChartThemeStyleProvider; +import com.fr.chart.chartattr.Plot; +import com.fr.chart.chartglyph.ConditionAttr; +import com.fr.chart.chartglyph.DataSheet; +import com.fr.chartx.attr.ChartProvider; +import com.fr.config.predefined.ColorFillStyle; +import com.fr.design.fun.DefaultValueAdjustProvider; +import com.fr.design.mainframe.chart.mode.ChartEditContext; +import com.fr.design.utils.DesignUtils; +import com.fr.plugin.chart.PiePlot4VanChart; +import com.fr.plugin.chart.attr.axis.VanChartAlertValue; +import com.fr.plugin.chart.attr.axis.VanChartAxis; +import com.fr.plugin.chart.attr.axis.VanChartAxisLabelStyle; +import com.fr.plugin.chart.attr.plot.VanChartPlot; +import com.fr.plugin.chart.attr.plot.VanChartRectanglePlot; +import com.fr.plugin.chart.base.AttrLabel; +import com.fr.plugin.chart.base.AttrLabelDetail; +import com.fr.plugin.chart.custom.type.CustomPlotType; +import com.fr.plugin.chart.gauge.VanChartGaugePlot; +import com.fr.plugin.chart.map.VanChartMapPlot; +import com.fr.plugin.chart.type.GaugeStyle; +import com.fr.plugin.chart.vanchart.VanChart; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author shine + * @version 10.0 + * Created by shine on 2021/10/22 + * vanchart的抽出来,因为主体代码 新增y轴 组合图新增图表都要用 + */ +public class DefaultStyleHelper4Van { + + private static boolean duchampMode() { + try { + return ChartEditContext.duchampMode(); + } catch (Throwable e) { + //tomcat预览 默认数据的图表 + return true; + } + } + + public static void checkChartDefaultStyle4Duchamp(ChartProvider chartProvider) { + if (!ChartEditContext.supportTheme() && chartProvider instanceof VanChart) { + //主题中有的属性 界面上屏蔽不跟随主题 属性全部设置成自定义 + ((VanChart) chartProvider).setThemeCustom(); + dealChartColor((VanChart) chartProvider); +// //主题中没有的 根据主题深浅色自动 的属性 默认自动 +// ((VanChart) chart4Update).setAutoThemeCustom(); + DefaultValueAdjustProvider adjustProvider = DesignUtils.getValueAdjust(); + if (adjustProvider != null) { + adjustProvider.adjustChart(chartProvider); + } + } + + } + + public static void dealVanPlot4Custom(VanChartPlot plot, CustomPlotType customPlotType) { + if (!duchampMode()) { + return; + } + dealVanPlotCommonAttr(plot); + switch (customPlotType) { + case PIE: + case DIFFERENT_PIE: + case SAME_PIE: + dealPie(plot); + break; + case SLOT: + case POINTER_360: + case POINTER_180: + case CUVETTE: + case RING: + dealGauge(plot); + break; + case COLUMN: + case LINE: + case AREA: + case BUBBLE: + case RADAR: + case STACK_RADAR: + case SCATTER: + default: + break; + } + + } + + private static void dealAxisCheckTheme(VanChartAxis axis) { + if (!ChartEditContext.supportTheme()) { + List chartThemeStyleProviders = new ArrayList<>(); + VanChartRectanglePlot.getAxisChartPreStyleProvider(axis, chartThemeStyleProviders); + for (ChartThemeStyleProvider themeStyleProvider : chartThemeStyleProviders) { + themeStyleProvider.setThemeCustom(); + } + } + } + + public static VanChartAxisLabelStyle dealAxisCheckTheme(VanChartAxisLabelStyle labelStyle) { + if (!ChartEditContext.supportTheme()) { + labelStyle.getTextAttr().setThemeCustom(); + } + return labelStyle; + } + + + public static VanChartAxis dealAxisDefault(VanChartAxis axis) { + + dealAxisCheckTheme(axis); + + if (!duchampMode()) { + return axis; + } + axis.getTitle().getTextAttr().setFRFont(DefaultStyleConstants.AXIS_TITLE); + axis.getTextAttr().setFRFont(DefaultStyleConstants.AXIS_LABEL); + axis.setAxisColor(DefaultStyleConstants.AXIS_LINE); + axis.setMainGridColor(DefaultStyleConstants.GRID_LINE); + return axis; + } + + public static void dealAxisAlert(VanChartAlertValue vanChartAlertValue) { + if (!duchampMode()) { + return; + } + vanChartAlertValue.setAlertFont(DefaultStyleConstants.ALERT_FONT); + } + + static void dealVanPlotCommonAttr(Plot plot) { + if (!duchampMode()) { + return; + } + if (plot instanceof VanChartPlot) { + VanChartPlot vanChartPlot = (VanChartPlot) plot; + + dealChartColor(vanChartPlot); + + if (vanChartPlot.getLegend() != null) { + vanChartPlot.getLegend().setFRFont(DefaultStyleConstants.LEGEND); + } + + if (vanChartPlot instanceof VanChartRectanglePlot) { + VanChartRectanglePlot vanChartRectanglePlot = (VanChartRectanglePlot) vanChartPlot; + + for (VanChartAxis axis : vanChartRectanglePlot.getXAxisList()) { + dealAxisDefault(axis); + } + for (VanChartAxis axis : vanChartRectanglePlot.getYAxisList()) { + dealAxisDefault(axis); + } + } + + dealBorder(vanChartPlot); + + DataSheet dataSheet = vanChartPlot.getDataSheet(); + dataSheet.getTextAttr().setFRFont(DefaultStyleConstants.DATA_SHEET); + dataSheet.setBorderColor(DefaultStyleConstants.DATA_SHEET_BORDER); + } + + } + + private static void dealChartColor(VanChart vanChart) { + dealChartColor(vanChart.getPlot()); + } + + private static void dealChartColor(VanChartPlot vanChartPlot) { + ChartPreStyleConfig manager = ChartPreStyleConfig.getInstance(); + Object preStyle = manager.getPreStyle(DefaultStyleConstants.COLORS); + ColorFillStyle colorFillStyle = new ColorFillStyle(); + if (preStyle instanceof ChartColorMatching) { + //default是默认的意思,为服务器默认配色方案 + //acc为多个颜色组合 + //gradient为渐变颜色 + colorFillStyle.setColorStyle(ChartConstants.COLOR_ACC); + colorFillStyle.setFillStyleName(DefaultStyleConstants.COLORS); + colorFillStyle.setColorList(((ChartColorMatching) preStyle).getColorList()); + } else { + //服务器上没有图表配色 + //需要指定配色属性为自定义组合色,否则会被兼容成跟随主题 + // com.fr.plugin.chart.attr.plot.VanChartPlot.compatibleFillStyle + colorFillStyle.setColorStyle(ChartConstants.COLOR_ACC); + colorFillStyle.setColorList(Arrays.asList(ChartConstants.NEW_FEATURES)); + } + + AttrFillStyle plotFillStyle = vanChartPlot.getPlotFillStyle(); + if (plotFillStyle == null) { + plotFillStyle = new AttrFillStyle(); + vanChartPlot.setPlotFillStyle(plotFillStyle); + } + plotFillStyle.setColorFillStyle(colorFillStyle); + } + + private static void dealBorder(VanChartPlot vanChartPlot) { + ConditionAttr defaultAttr = vanChartPlot.getConditionCollection().getDefaultAttr(); + AttrBorder attrBorder = defaultAttr.getExisted(AttrBorder.class); + if (attrBorder != null) { + attrBorder.setBorderColor(DefaultStyleConstants.BORDER); + attrBorder.setBorderStyle(defaultBorderWidth(vanChartPlot)); + } + } + + private static int defaultBorderWidth(VanChartPlot vanChartPlot) { + //pie multipie treemap map drillmap heatmap + if (vanChartPlot instanceof PiePlot4VanChart + || vanChartPlot instanceof VanChartMapPlot) { + return DefaultStyleConstants.SPECIAL_BORDER_WIDTH; + } + return DefaultStyleConstants.BORDER_WIDTH; + } + + static void dealPie(Plot plot) { + if (plot instanceof PiePlot4VanChart) { + ConditionAttr defaultAttr = plot.getConditionCollection().getDefaultAttr(); + AttrLabel attrLabel = defaultAttr.getExisted(AttrLabel.class); + if (attrLabel == null) { + attrLabel = ((PiePlot4VanChart) plot).getDefaultAttrLabel(); + defaultAttr.addDataSeriesCondition(attrLabel); + } + attrLabel.getSecondLabelDetail().getTextAttr().setFRFont(DefaultStyleConstants.PIE_CATEGORY_LABEL); + } + } + + static void dealGauge(Plot param) { + if (!(param instanceof VanChartGaugePlot)) { + return; + } + VanChartGaugePlot plot = (VanChartGaugePlot) param; + plot.getGaugeDetailStyle().setPaneBackgroundColor(plot.getGaugeStyle() == GaugeStyle.RING ? DefaultStyleConstants.GAUGE_PANE_BACK_COLOR_4_RING : DefaultStyleConstants.GAUGE_PANE_BACK_COLOR); + plot.getGaugeDetailStyle().setSlotBackgroundColor(DefaultStyleConstants.GAUGE_SLOT_BACKGROUND_COLOR); + plot.getGaugeDetailStyle().setHingeColor(DefaultStyleConstants.GAUGE_HINGE); + + ConditionAttr defaultAttr = plot.getConditionCollection().getDefaultAttr(); + AttrLabel attrLabel = defaultAttr.getExisted(AttrLabel.class); + if (attrLabel != null) { + AttrLabelDetail detail = attrLabel.getAttrLabelDetail(); + AttrLabelDetail valueDetail = attrLabel.getGaugeValueLabelDetail(); + + switch (plot.getGaugeStyle()) { + case POINTER: + case POINTER_SEMI: + detail.getContent().getCategoryFormat().setEnable(false); + detail.getTextAttr().setFRFont(DefaultStyleConstants.POINTER_CATE_LABEL_FONT); + valueDetail.getTextAttr().setFRFont(DefaultStyleConstants.POINTER_VALUE_LABEL_FONT); + break; + case RING: + case SLOT: + valueDetail.getTextAttr().setFRFont(DefaultStyleConstants.RING_VALUE_LABEL_FONT); + break; + case THERMOMETER: + detail.getTextAttr().setFRFont(DefaultStyleConstants.THERMOMETER_LABEL_FONT); + valueDetail.getTextAttr().setFRFont(DefaultStyleConstants.THERMOMETER_LABEL_FONT); + plot.getGaugeAxis().getTextAttr().setFRFont(DefaultStyleConstants.THERMOMETER_AXIS_LABEL); + break; + } + + } + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartCustomPlotSelectPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartCustomPlotSelectPane.java index 8f7b9557d0..589b03cad3 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartCustomPlotSelectPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartCustomPlotSelectPane.java @@ -1,18 +1,20 @@ package com.fr.van.chart.custom.component; +import com.fr.chart.base.ChartThemeStyleProvider; import com.fr.chart.chartattr.Chart; import com.fr.design.beans.BasicBeanPane; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; - import com.fr.plugin.chart.attr.plot.VanChartPlot; import com.fr.plugin.chart.attr.plot.VanChartRectanglePlot; import com.fr.plugin.chart.custom.CustomPlotFactory; import com.fr.plugin.chart.custom.VanChartCustomPlot; import com.fr.plugin.chart.custom.type.CustomPlotType; import com.fr.plugin.chart.custom.type.CustomStyle; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import com.fr.van.chart.custom.CustomPlotDesignerPaneFactory; import javax.swing.JOptionPane; @@ -260,10 +262,18 @@ public class VanChartCustomPlotSelectPane extends BasicBeanPane { CustomPlotType customPlotType = selectedPlotTypeList.get(i); if (!CustomPlotFactory.customPlotContains(newCustomPlotList, customPlotType)){ VanChartPlot vanChartPlot = CustomPlotFactory.getCustomPlot(customPlotType); + DefaultStyleHelper4Van.dealVanPlot4Custom(vanChartPlot, customPlotType); vanChartPlot.setCustomType(CustomStyle.CUSTOM.toString()); //设置公共属性 setCommonAttr(vanChartPlot, customPlot); + if (!ChartEditContext.supportTheme()) { + //主题中有的属性 界面上屏蔽不跟随主题 属性全部设置成自定义 + setThemeCustom(vanChartPlot); +// //主题中没有的 根据主题深浅色自动 的属性 默认自动 +// ((VanChart) chart4Update).setAutoThemeCustom(); + } + newCustomPlotList.add(vanChartPlot); } } @@ -271,6 +281,14 @@ public class VanChartCustomPlotSelectPane extends BasicBeanPane { customPlot.setCustomPlotList(newCustomPlotList); } + private void setThemeCustom(VanChartPlot customPlot) { + List chartThemeStyleProviders = new ArrayList<>(); + customPlot.getChartPreStyleProvider(chartThemeStyleProviders); + for (ChartThemeStyleProvider chartThemeStyleProvider : chartThemeStyleProviders) { + chartThemeStyleProvider.setThemeCustom(); + } + } + private void setCommonAttr(VanChartPlot vanChartPlot, VanChartCustomPlot customPlot) { //坐标轴公共属性 dealAxisAttr(vanChartPlot, customPlot); diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java index b5efad3b66..75ec5d3ce2 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java @@ -6,6 +6,7 @@ import com.fr.chart.web.ChartHyperPoplink; import com.fr.chart.web.ChartHyperRelateCellLink; import com.fr.chart.web.ChartHyperRelateFloatLink; import com.fr.design.ExtraDesignClassManager; +import com.fr.design.base.mode.DesignModeContext; import com.fr.design.beans.BasicBeanPane; import com.fr.design.chart.javascript.ChartEmailPane; import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperPoplinkPane; @@ -13,6 +14,7 @@ import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperRelateCellLinkP import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperRelateFloatLinkPane; import com.fr.design.chart.series.SeriesCondition.impl.FormHyperlinkPane; import com.fr.design.designer.TargetComponent; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.fun.HyperlinkProvider; import com.fr.design.gui.controlpane.NameObjectCreator; import com.fr.design.gui.controlpane.NameableCreator; @@ -21,7 +23,10 @@ import com.fr.design.hyperlink.ReportletHyperlinkPane; import com.fr.design.hyperlink.WebHyperlinkPane; import com.fr.design.javascript.JavaScriptImplPane; import com.fr.design.javascript.ParameterJavaScriptPane; +import com.fr.design.mainframe.BaseJForm; +import com.fr.design.mainframe.JTemplate; import com.fr.design.module.DesignModuleFactory; +import com.fr.general.ComparatorUtils; import com.fr.general.NameObject; import com.fr.js.EmailJavaScript; import com.fr.js.FormHyperlinkProvider; @@ -38,6 +43,8 @@ import com.fr.stable.Nameable; import com.fr.stable.bridge.StableFactory; import com.fr.van.chart.designer.component.VanChartUIListControlPane; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -78,14 +85,11 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { constructor = creator.getUpdatePane().getConstructor(HashMap.class, boolean.class); return constructor.newInstance(getHyperLinkEditorMap(), false); - } catch (InstantiationException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } catch (NoSuchMethodException e) { + FineLoggerFactory.getLogger().warn(e.getMessage(), e); return super.createPaneByCreators(creator); - } catch (InvocationTargetException e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); } return null; } @@ -144,26 +148,36 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { return new NameJavaScriptGroup(res_array); } - public void populate(Plot plot) { - setPlot(plot); - HashMap paneMap = getHyperlinkMap(plot); + private void refreshNameableCreator() { + if (DesignModeContext.isDuchampMode()) { + return; + } + HashMap paneMap = getHyperlinkMap(); //安装平台内打开插件时,添加相应按钮 Set providers = ExtraDesignClassManager.getInstance().getArray(HyperlinkProvider.XML_TAG); - for (HyperlinkProvider provider : providers) { - NameableCreator nc = provider.createHyperlinkCreator(); - paneMap.put(nc.getHyperlink(), nc.getUpdatePane()); - } - java.util.List list = refreshList(paneMap); - NameObjectCreator[] creators = new NameObjectCreator[list.size()]; - for (int i = 0; list != null && i < list.size(); i++) { + int size = list.size(); + NameObjectCreator[] creators = new NameObjectCreator[size + providers.size()]; + for (int i = 0; i < size; i++) { UIMenuNameableCreator uiMenuNameableCreator = list.get(i); creators[i] = new NameObjectCreator(uiMenuNameableCreator.getName(), uiMenuNameableCreator.getObj().getClass(), uiMenuNameableCreator.getPaneClazz()); - + } + for (HyperlinkProvider provider : providers) { + NameableCreator creator = provider.createHyperlinkCreator(); + if (creator != null) { + creators[size] = new NameObjectCreator(creator.menuName(), creator.getHyperlink(), creator.getUpdatePane()); + size++; + } } refreshNameableCreator(creators); + } + + public void populate(Plot plot) { + setPlot(plot); + + refreshNameableCreator(); java.util.List nameObjects = new ArrayList(); @@ -172,13 +186,22 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { NameJavaScript javaScript = nameGroup.getNameHyperlink(i); if (javaScript != null && javaScript.getJavaScript() != null) { JavaScript script = javaScript.getJavaScript(); - UIMenuNameableCreator uiMenuNameableCreator = new UIMenuNameableCreator(javaScript.getName(), script, getUseMap(paneMap, script.getClass())); - nameObjects.add(new NameObject(uiMenuNameableCreator.getName(), uiMenuNameableCreator.getObj())); + nameObjects.add(new NameObject(javaScript.getName(), script)); } } this.populate(nameObjects.toArray(new NameObject[nameObjects.size()])); + if (popupEditDialog instanceof HyperDialog) { + popupEditDialog.addWindowFocusListener(new WindowAdapter() { + @Override + public void windowLostFocus(WindowEvent e) { + if (needToHidePopupEditDialog()) { + popupEditDialog.setVisible(false); + } + } + }); + } doLayout(); } @@ -186,7 +209,7 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { return plot.getHotHyperLink(); } - protected HashMap getHyperlinkMap(Plot plot) { + protected HashMap getHyperlinkMap() { HashMap map = new HashMap(); map.put(ReportletHyperlink.class, ReportletHyperlinkPane.class); @@ -278,5 +301,24 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane { } } - + @Override + protected void initCreatorsFilter() { + this.creatorsFilter = nameableCreator -> { + Class clazz = nameableCreator.getHyperlink(); + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (!JTemplate.isValid(template)) { + return false; + } + Class[] classes = new Class[]{ChartHyperRelateCellLink.class, ChartHyperRelateFloatLink.class}; + for (Class aClass : classes) { + if (template.getEditingReportIndex() == BaseJForm.FORM_TAB) { + // 编辑的是决策报表中的图表,那么没有ChartHyperRelateFloatLink 和 ChartHyperRelateCellLink 选项,有FormHyperlink 选项 + if (ComparatorUtils.equals(aClass, clazz)) { + return false; + } + } + } + return true; + }; + } } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomPlotConditionAttrTabPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomPlotConditionAttrTabPane.java index 4cb5c652f6..0f23c5050e 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomPlotConditionAttrTabPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomPlotConditionAttrTabPane.java @@ -1,6 +1,7 @@ package com.fr.van.chart.custom.other; import com.fr.chart.chartattr.Chart; +import com.fr.design.chart.series.SeriesCondition.ColSelectedWithSummaryMethodEditor; import com.fr.design.dialog.BasicPane; import com.fr.plugin.chart.attr.plot.VanChartPlot; import com.fr.plugin.chart.custom.CustomPlotFactory; @@ -91,6 +92,10 @@ public class VanChartCustomPlotConditionAttrTabPane extends VanChartCustomPlotTa CustomPlotType plotType = CustomPlotFactory.getCustomType(chartPlot); VanChartRichEditorPane.refreshCustomChartTableFieldNames(chart, plotType); + ColSelectedWithSummaryMethodEditor.refreshCustomChartTableFieldNames(chart, plotType); + if (chart != null) { + ColSelectedWithSummaryMethodEditor.update(index, chart.getPlot()); + } } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisPane.java index 35b6d63e70..75a3c0f2ca 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisPane.java @@ -54,7 +54,7 @@ public class VanChartCustomAxisPane extends BasicScrollPane { } if(axisPane != null) { - axisPane.populateBean((VanChartCustomPlot) chart.getPlot()); + axisPane.populateBean((VanChart) chart); } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisTabPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisTabPane.java index 93ac30c52e..5f9927c6b1 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisTabPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/custom/style/VanChartCustomAxisTabPane.java @@ -87,11 +87,16 @@ public class VanChartCustomAxisTabPane extends VanChartCustomPlotTabPane customPlotList = plot.getCustomPlotList(); ArrayList plotOrder = plot.getDiffAxisOrder(); @@ -100,12 +105,13 @@ public class VanChartCustomAxisTabPane extends VanChartCustomPlotTabPane 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/component/VanChartHtmlLabelPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartHtmlLabelPane.java index 0e9cc416f9..ebff936c1c 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartHtmlLabelPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartHtmlLabelPane.java @@ -5,6 +5,7 @@ import com.fr.design.constants.KeyWords; import com.fr.design.gui.autocomplete.AutoCompletion; import com.fr.design.gui.autocomplete.BasicCompletion; import com.fr.design.gui.autocomplete.DefaultCompletionProvider; +import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.icontainer.UIScrollPane; @@ -45,7 +46,7 @@ public class VanChartHtmlLabelPane extends JPanel { private UICheckBox isCustomHeight; private UITextField customHeight; - private VanChartStylePane parent; + private AbstractAttrNoScrollPane parent; private JPanel widthAndHeightPane; @@ -53,7 +54,7 @@ public class VanChartHtmlLabelPane extends JPanel { contentTextArea.setText(text); } - public void setParent(VanChartStylePane parent) { + public void setParent(AbstractAttrNoScrollPane parent) { this.parent = parent; } @@ -126,7 +127,7 @@ public class VanChartHtmlLabelPane extends JPanel { }; } - private void fireJSChange() { + protected void fireJSChange() { if (parent != null) { parent.attributeChanged(); } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartLabelContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartLabelContentPane.java index 8133771f94..54200fcdee 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartLabelContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartLabelContentPane.java @@ -1,12 +1,18 @@ package com.fr.van.chart.designer.component; +import com.fr.design.gui.ibutton.UIColorButtonWithAuto; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithAuto; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.plugin.chart.base.AttrTooltipContent; +import com.fr.plugin.chart.type.FontAutoType; import com.fr.plugin.chart.type.TextAlign; import com.fr.van.chart.designer.style.VanChartStylePane; import javax.swing.JPanel; import java.awt.BorderLayout; +import java.awt.Component; public class VanChartLabelContentPane extends VanChartTooltipContentPane { @@ -25,10 +31,10 @@ public class VanChartLabelContentPane extends VanChartTooltipContentPane { } public JPanel createCommonStylePane() { - if (isInCondition()) { + if (isInCondition() || !ChartEditContext.supportTheme()) { return super.createCommonStylePane(); } - setTextAttrPane(new ChartTextAttrPaneWithThemeStyle()); + setTextAttrPane(new LabelAttrPaneWithThemeStyle()); JPanel stylePanel = new JPanel(new BorderLayout()); stylePanel.add(getTextAttrPane(), BorderLayout.CENTER); @@ -36,8 +42,21 @@ public class VanChartLabelContentPane extends VanChartTooltipContentPane { return stylePanel; } + @Override + protected ChartTextAttrPane createChartTextAttrPane() { + return new ChartTextAttrPaneWithAuto(FontAutoType.COLOR) { + protected Component[][] getComponents(JPanel buttonPane) { + return new Component[][]{ + new Component[]{null, null}, + new Component[]{null, getFontNameComboBox()}, + new Component[]{null, buttonPane} + }; + } + }; + } + public void updateTextAttr(AttrTooltipContent attrTooltipContent) { - if (isInCondition()) { + if (isInCondition() || !ChartEditContext.supportTheme()) { super.updateTextAttr(attrTooltipContent); return; } @@ -48,4 +67,11 @@ public class VanChartLabelContentPane extends VanChartTooltipContentPane { } } } + + class LabelAttrPaneWithThemeStyle extends ChartTextAttrPaneWithThemeStyle { + @Override + protected void initFontColorState() { + setFontColor(new UIColorButtonWithAuto()); + } + } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartTooltipContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartTooltipContentPane.java index 12e242b731..ab84b88b89 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartTooltipContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/component/VanChartTooltipContentPane.java @@ -39,10 +39,6 @@ import com.fr.van.chart.designer.style.VanChartStylePane; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.SwingUtilities; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; @@ -51,6 +47,10 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; /** * 数据点提示内容界面,含有通用设置、富文本编辑器、自定义JS界面 @@ -315,15 +315,7 @@ public class VanChartTooltipContentPane extends BasicBeanPane { public VanChartImageMarkerPane() { imageBackgroundPane = new ImageBackgroundQuickPane(false); imageBackgroundPane.setPreferredSize(getImageBackgroundPreferredSize(imageBackgroundPane.getPreferredSize())); - width = new UISpinnerWithPx(0, 100, 0.5, 30); - height = new UISpinnerWithPx(0, 100, 0.5, 30); + width = new UISpinnerWithPx(0, Integer.MAX_VALUE, 0.5, 30); + height = new UISpinnerWithPx(0, Integer.MAX_VALUE, 0.5, 30); double p = TableLayout.PREFERRED; double f = TableLayout.FILL; diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java index dcf160aec1..4d9f0aa61f 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java @@ -22,13 +22,14 @@ public class VanChartMoreCateTableDataContentPane extends CategoryPlotMoreCateTa @Override public void populateBean(ChartCollection collection) { super.populateBean(collection); - VanChartRectanglePlot plot = (VanChartRectanglePlot) collection.getSelectedChart().getPlot(); + VanChartRectanglePlot plot = collection.getSelectedChart().getPlot(); isSupportMultiCategory = plot.isSupportMultiCategory(); checkBoxList(isSupportMultiCategory); } protected void updateMoreCate(NormalTableDataDefinition normal, Plot plot) { super.updateMoreCate(normal, plot); + isSupportMultiCategory = ((VanChartRectanglePlot) plot).isSupportMultiCategory(); ((VanChartPlot) plot).setCategoryNum(getBoxList().size() + 1); if (!getBoxList().isEmpty()) { plot.getDataSheet().setVisible(false); diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartPlotLegendPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartPlotLegendPane.java index f51d1d689a..3543edb5c9 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartPlotLegendPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartPlotLegendPane.java @@ -16,6 +16,7 @@ import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.PaneTitleConstants; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.plugin.chart.attr.VanChartLegend; import com.fr.plugin.chart.type.LayoutType; @@ -288,7 +289,7 @@ public class VanChartPlotLegendPane extends BasicPane { } private JPanel createTitleStylePane() { - textAttrPane = new ChartTextAttrPaneWithThemeStyle(); + textAttrPane = ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() : new ChartTextAttrPane(); return TableLayout4VanChartHelper.createExpandablePaneWithTitle(Toolkit.i18nText("Fine-Design_Chart_Widget_Style"), textAttrPane); } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartStylePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartStylePane.java index 7ca77a9fc2..603b5af0a2 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartStylePane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartStylePane.java @@ -1,6 +1,7 @@ package com.fr.van.chart.designer.style; import com.fr.chart.chartattr.Plot; +import com.fr.design.chart.series.SeriesCondition.ColSelectedWithSummaryMethodEditor; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.frpane.AttributeChangeListener; import com.fr.design.mainframe.chart.ChartEditPane; @@ -88,6 +89,7 @@ public class VanChartStylePane extends ChartStylePane { public void refreshTableFieldNames() { VanChartRichEditorPane.refreshCommonChartFieldNames(getChart()); + ColSelectedWithSummaryMethodEditor.refreshCommonChartFieldNames(getChart()); } public void registerChartEditPane(ChartEditPane currentEditPane) { diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartTitlePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartTitlePane.java index fd5e37890b..87d6fbfda7 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartTitlePane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/VanChartTitlePane.java @@ -17,8 +17,10 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.PaneTitleConstants; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; import com.fr.design.mainframe.chart.info.ChartInfoCollector; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.plugin.chart.attr.VanChartTitle; import com.fr.plugin.chart.vanchart.VanChart; @@ -57,7 +59,7 @@ public class VanChartTitlePane extends AbstractVanChartScrollPane { private JPanel titlePane; private TinyFormulaPane titleContent; - private ChartTextAttrPaneWithThemeStyle textAttrPane; + private ChartTextAttrPane textAttrPane; private UIButtonGroup alignmentPane; private VanChartBackgroundWithOutShadowWithRadiusPane backgroundPane; private UIToggleButton useHtml; @@ -188,7 +190,7 @@ public class VanChartTitlePane extends AbstractVanChartScrollPane { } private JPanel createTitleStylePane() { - textAttrPane = new ChartTextAttrPaneWithThemeStyle(); + textAttrPane = ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() : new ChartTextAttrPane(); return TableLayout4VanChartHelper.createExpandablePaneWithTitle(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Widget_Style"), textAttrPane); } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPane.java index 5c71317f20..ef532d12ba 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPane.java @@ -1,5 +1,6 @@ package com.fr.van.chart.designer.style.axis; +import com.fr.chart.chartattr.Chart; import com.fr.chart.chartattr.Plot; import com.fr.chart.chartglyph.ConditionAttr; import com.fr.chart.chartglyph.ConditionCollection; @@ -14,16 +15,17 @@ import com.fr.plugin.chart.attr.plot.VanChartRectanglePlot; import com.fr.plugin.chart.base.AttrSeriesStackAndAxis; import com.fr.plugin.chart.base.VanChartConstants; import com.fr.plugin.chart.vanchart.VanChart; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import com.fr.van.chart.designer.style.VanChartStylePane; import com.fr.van.chart.designer.style.axis.component.VanChartAxisButtonPane; import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.CardLayout; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.awt.BorderLayout; -import java.awt.CardLayout; /** * 样式-坐标轴界面 @@ -40,6 +42,7 @@ public class VanChartAxisPane extends BasicBeanPane { protected VanChartAxisPlot editingPlot; protected VanChartStylePane parent; + private Chart chart; public VanChartAxisPane(VanChartAxisPlot plot, VanChartStylePane parent){ this.editingPlot = plot; @@ -104,6 +107,7 @@ public class VanChartAxisPane extends BasicBeanPane { List xAxisList = editingPlot.getXAxisList(); VanChartAxis axis = editingPlot.createXAxis(name, VanChartConstants.AXIS_BOTTOM); xAxisList.add(axis); + DefaultStyleHelper4Van.dealAxisDefault(axis); VanChartXYAxisPaneInterface axisPane = initXAxisPane(axis); axisPane.populate(axis); @@ -119,6 +123,7 @@ public class VanChartAxisPane extends BasicBeanPane { List yAxisList = editingPlot.getYAxisList(); VanChartAxis axis = editingPlot.createYAxis(name, VanChartConstants.AXIS_LEFT); yAxisList.add(axis); + DefaultStyleHelper4Van.dealAxisDefault(axis); VanChartXYAxisPaneInterface axisPane = initYAxisPane(axis); axisPane.populate(axis); @@ -185,6 +190,7 @@ public class VanChartAxisPane extends BasicBeanPane { if(chart == null){ return; } + this.chart = chart; Plot plot = chart.getPlot(); populateBean(plot); @@ -205,10 +211,12 @@ public class VanChartAxisPane extends BasicBeanPane { } for(VanChartAxis axis : editingPlot.getXAxisList()){ + axis.setChart(chart); VanChartXYAxisPaneInterface axisPane = xAxisPaneMap.get(axis.getAxisName()); axisPane.populate(axis); } for(VanChartAxis axis : editingPlot.getYAxisList()){ + axis.setChart(chart); VanChartXYAxisPaneInterface axisPane = yAxisPaneMap.get(axis.getAxisName()); axisPane.populate(axis); } @@ -234,6 +242,7 @@ public class VanChartAxisPane extends BasicBeanPane { if(chart == null){ return; } + this.chart = chart; Plot plot = chart.getPlot(); @@ -278,4 +287,8 @@ public class VanChartAxisPane extends BasicBeanPane { public VanChart updateBean() { return null; } + + public void setChart(Chart chart) { + this.chart = chart; + } } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPaneHelper.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPaneHelper.java new file mode 100644 index 0000000000..770043af9c --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisPaneHelper.java @@ -0,0 +1,30 @@ +package com.fr.van.chart.designer.style.axis; + +import com.fr.design.layout.TableLayout; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; +import com.fr.design.mainframe.chart.mode.ChartEditContext; +import com.fr.van.chart.designer.TableLayout4VanChartHelper; + +import javax.swing.JPanel; + +public class VanChartAxisPaneHelper { + public static ChartTextAttrPane createAxisTextAttrPane() { + return ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() { + protected double getEdithAreaWidth() { + return TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH; + } + } : new ChartTextAttrPane() { + @Override + protected JPanel getContentPane(JPanel buttonPane) { + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double e = TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH; + double[] columnSize = {f, e}; + double[] rowSize = {p, p, p}; + + return TableLayout4VanChartHelper.createGapTableLayoutPane(getComponents(buttonPane), rowSize, columnSize); + } + }; + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisScrollPaneWithTypeSelect.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisScrollPaneWithTypeSelect.java index 15154de28b..46b210c7ec 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisScrollPaneWithTypeSelect.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisScrollPaneWithTypeSelect.java @@ -11,6 +11,7 @@ import com.fr.plugin.chart.attr.axis.VanChartAxis; import com.fr.plugin.chart.attr.axis.VanChartTimeAxis; import com.fr.plugin.chart.attr.axis.VanChartValueAxis; import com.fr.plugin.chart.type.AxisType; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import com.fr.van.chart.designer.AbstractVanChartScrollPane; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import com.fr.van.chart.designer.style.VanChartStylePane; @@ -84,9 +85,9 @@ public class VanChartAxisScrollPaneWithTypeSelect extends AbstractVanChartScroll public void populate(VanChartAxis axis){ AxisType axisType = axis.getAxisType(); - textAxisPane.populateBean(new VanChartAxis(axis.getAxisName(), axis.getPosition())); - timeAxisPane.populateBean(new VanChartTimeAxis(axis.getAxisName(), axis.getPosition())); - valueAxisPane.populateBean(new VanChartValueAxis(axis.getAxisName(), axis.getPosition())); + textAxisPane.populateBean(DefaultStyleHelper4Van.dealAxisDefault(new VanChartAxis(axis.getAxisName(), axis.getPosition()))); + timeAxisPane.populateBean(DefaultStyleHelper4Van.dealAxisDefault(new VanChartTimeAxis(axis.getAxisName(), axis.getPosition()))); + valueAxisPane.populateBean(DefaultStyleHelper4Van.dealAxisDefault(new VanChartValueAxis(axis.getAxisName(), axis.getPosition()))); if(ComparatorUtils.equals(axisType, AxisType.AXIS_CATEGORY)){ textAxisPane.populateBean(axis); } else if(ComparatorUtils.equals(axisType, AxisType.AXIS_TIME)){ diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisStyleSettingPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisStyleSettingPane.java new file mode 100644 index 0000000000..dde467226c --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartAxisStyleSettingPane.java @@ -0,0 +1,168 @@ +package com.fr.van.chart.designer.style.axis; + +import com.fr.base.BaseFormula; +import com.fr.chart.base.TextAttr; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.gui.frpane.UINumberDragPane; +import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayout; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; +import com.fr.design.utils.gui.UIComponentUtils; +import com.fr.design.widget.FRWidgetFactory; +import com.fr.plugin.chart.attr.axis.VanChartAxisLabelStyle; +import com.fr.van.chart.config.DefaultStyleHelper4Van; +import com.fr.van.chart.designer.TableLayout4VanChartHelper; +import com.fr.van.chart.designer.style.axis.component.AxisLabelDisplayComboBox; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class VanChartAxisStyleSettingPane extends BasicBeanPane { + private static final double ROTATION_MAX = 90.0; + + private AxisLabelDisplayComboBox labelDisplayComboBox; + private JPanel labelDisplayPane; + private ChartTextAttrPane labelTextAttrPane; + private UINumberDragPane labelTextRotation; + private UIButtonGroup labelGapStyle; + private UITextField labelGapValue; + private JPanel labelGapPane; + private JPanel labelGapValuePane; + private JPanel contentPane; + + private boolean showLabelDisplayPane = true; + + public VanChartAxisStyleSettingPane(boolean showLabelDisplayPane, ChartTextAttrPane textAttrPane) { + this.showLabelDisplayPane = showLabelDisplayPane; + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double s = TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH; + double[] column = {f, s}; + double[] row = {p, p, p}; + + labelDisplayComboBox = new AxisLabelDisplayComboBox(); + labelDisplayPane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label_Show"), labelDisplayComboBox, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); + labelDisplayPane.setVisible(showLabelDisplayPane); + + labelTextAttrPane = textAttrPane; + labelTextRotation = new UINumberDragPane(-ROTATION_MAX, ROTATION_MAX); + + labelGapStyle = new UIButtonGroup<>(new String[]{Toolkit.i18nText("Fine-Design_Chart_Automatic"), Toolkit.i18nText("Fine-Design_Chart_Fixed")}); + labelGapValue = new UITextField(); + labelGapPane = createLabelGapPane(row, column); + + this.setLayout(new BorderLayout()); + contentPane = new JPanel(new BorderLayout()); + contentPane.add(labelDisplayPane, BorderLayout.NORTH); + contentPane.add(labelTextAttrPane, BorderLayout.CENTER); + contentPane.add(labelGapPane, BorderLayout.SOUTH); + this.add(contentPane, BorderLayout.NORTH); + initListner(); + } + + public VanChartAxisStyleSettingPane(ChartTextAttrPane textAttrPane) { + this(true, textAttrPane); + } + + @Override + public Dimension getPreferredSize() { + Dimension defaultSize = super.getPreferredSize(); + return new Dimension(defaultSize.width, contentPane.getPreferredSize().height); + } + + private void initListner() { + labelDisplayComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + checkLabelGapPane(); + } + }); + + labelGapStyle.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + checkLabelGapValuePane(); + } + }); + } + + private void checkLabelGapPane() { + if (labelGapPane != null) { + boolean visible = true; + + if (showLabelDisplayPane && labelDisplayPane != null && labelDisplayComboBox != null) { + visible = labelDisplayComboBox.getSelectedIndex() == 0; + } + + labelGapPane.setVisible(visible); + } + } + + private void checkLabelGapValuePane() { + if (labelGapValuePane != null && labelGapStyle != null) { + labelGapValuePane.setVisible(labelGapStyle.getSelectedIndex() == 1); + } + } + + @Override + public void populateBean(VanChartAxisLabelStyle style) { + labelDisplayComboBox.populateBean(style.getLabelDisplay()); + labelTextAttrPane.populate(style.getTextAttr()); + labelTextRotation.populateBean((double) style.getTextAttr().getRotation()); + labelGapStyle.setSelectedIndex(style.isAutoLabelGap() ? 0 : 1); + labelGapValue.setText(style.getLabelIntervalNumber().getContent()); + + checkLabelGapPane(); + checkLabelGapValuePane(); + } + + @Override + public VanChartAxisLabelStyle updateBean() { + VanChartAxisLabelStyle style = new VanChartAxisLabelStyle(); + DefaultStyleHelper4Van.dealAxisCheckTheme(style); + style.setLabelDisplay(labelDisplayComboBox.updateBean()); + TextAttr textAttr = style.getTextAttr(); + labelTextAttrPane.update(textAttr); + textAttr.setRotation(labelTextRotation.updateBean().intValue()); + style.setTextAttr(textAttr); + style.setAutoLabelGap(labelGapStyle.getSelectedIndex() == 0); + if (style.isAutoLabelGap()) { + style.setLabelIntervalNumber(BaseFormula.createFormulaBuilder().build("0")); + } else { + style.setLabelIntervalNumber(BaseFormula.createFormulaBuilder().build(labelGapValue.getText())); + } + return style; + } + + @Override + protected String title4PopupWindow() { + return null; + } + + private JPanel createLabelGapPane(double[] row, double[] col) { + Component[][] gapComponents = new Component[][]{ + new Component[]{null, null}, + new Component[]{ + FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Chart_TextRotation")), + UIComponentUtils.wrapWithBorderLayoutPane(labelTextRotation) + }, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Label_Interval")), labelGapStyle} + }; + + JPanel gapDetailPane = TableLayout4VanChartHelper.createGapTableLayoutPane(gapComponents, row, col); + labelGapValuePane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText(""), labelGapValue, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(gapDetailPane, BorderLayout.CENTER); + panel.add(labelGapValuePane, BorderLayout.SOUTH); + + return panel; + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartBaseAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartBaseAxisPane.java index f945a19699..1197d16b7c 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartBaseAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartBaseAxisPane.java @@ -3,7 +3,9 @@ package com.fr.van.chart.designer.style.axis; import com.fr.base.BaseFormula; import com.fr.base.BaseUtils; import com.fr.base.Utils; +import com.fr.base.chart.chartdata.TopDefinitionProvider; import com.fr.chart.base.TextAttr; +import com.fr.chart.chartattr.Chart; import com.fr.chart.chartattr.Title; import com.fr.design.beans.FurtherBasicBeanPane; import com.fr.design.formula.TinyFormulaPane; @@ -13,29 +15,28 @@ import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.ilable.UILabel; -import com.fr.design.gui.itextfield.UITextField; import com.fr.design.gui.style.FormatPane; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.PaneTitleConstants; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; -import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; import com.fr.design.mainframe.chart.gui.style.ColorSelectBoxWithThemeStyle; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.design.widget.FRWidgetFactory; import com.fr.plugin.chart.attr.axis.VanChartAxis; +import com.fr.plugin.chart.attr.axis.VanChartAxisLabelStyle; import com.fr.plugin.chart.base.OverlapHandleType; import com.fr.plugin.chart.base.VanChartConstants; import com.fr.plugin.chart.type.AxisTickLineType; import com.fr.stable.Constants; import com.fr.stable.CoreConstants; import com.fr.stable.StableUtils; -import com.fr.stable.StringUtils; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import com.fr.van.chart.designer.component.VanChartHtmlLabelPane; import com.fr.van.chart.designer.style.VanChartStylePane; -import com.fr.van.chart.designer.style.axis.component.AxisLabelDisplayComboBox; +import com.fr.van.chart.designer.style.axis.component.VanChartCategoryStylePaneWithCheckBox; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -46,16 +47,21 @@ import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; /** * 坐标轴的基础配置项。分类,时间,值等公共的部分。 */ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { - private static final long serialVersionUID = -5717246802333308973L; private static final double ROTATION_MAX = 90.0; + private static final String WHOLE_DISPLAY = "wholeDisplay"; // 整体显示 + private static final String LAYER_DISPLAY = "layerDisplay"; // 分层显示 + protected UIButtonGroup showTitle; protected TinyFormulaPane titleContent; protected UIButtonGroup titleAlignPane; @@ -65,24 +71,19 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { protected JPanel titlePane; protected UIButtonGroup showLabel; - protected ChartTextAttrPane labelTextAttrPane; - protected UINumberDragPane labelTextRotation; - - private AxisLabelDisplayComboBox labelDisplayComboBox; - - //轴标签缩略间隔显示 恢复用注释。下面6行删除。 - protected UITextField labelGapValue; + protected UIButtonGroup showLogic; private UIButtonGroup overlapHandleTypeGroup; - protected UIButtonGroup labelGapStyle; //轴标签缩略间隔显示 恢复用注释。取消注释。 //protected UISpinner labelGapValue; - protected JPanel labelPanel; - private JPanel labelGapPane; - private JPanel labelGapStylePane; - private JPanel labelGapValuePane; - private JPanel labelDisplayPane; + protected JPanel labelContentPane; + private VanChartAxisStyleSettingPane labelPane; + private JPanel showLogicPane; + private JPanel labelStylePane; + private JPanel categoryStylePane; + private VanChartAxisStyleSettingPane wholeDisplayLabelPanel; + private List categoryStyles = new ArrayList<>(); protected LineComboBox axisLineStyle; @@ -106,6 +107,8 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { protected JPanel centerPane; private VanChartHtmlLabelPane htmlLabelPane; + private VanChartStylePane parent; + public VanChartBaseAxisPane() { this(true); } @@ -116,6 +119,7 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { } public void setParentPane(VanChartStylePane parent) { + this.parent = parent; htmlLabelPane.setParent(parent); } @@ -213,178 +217,102 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { protected JPanel createLabelPane(double[] row, double[] col) { initLabelComponents(); - labelGapPane = createLabelGapPane(row, col); - labelPanel = createLabelDetailPanel(); + labelPane = new VanChartAxisStyleSettingPane(showLabelDisplay(), getChartTextAttrPane()); + wholeDisplayLabelPanel = new VanChartAxisStyleSettingPane(showLabelDisplay(), getChartTextAttrPane()); + wholeDisplayLabelPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); addComponentsListener(); JPanel showLabelPane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label"), showLabel); + JPanel labelContentPane = createLabelContentPane(); JPanel labelPane = new JPanel(new BorderLayout()); labelPane.add(showLabelPane, BorderLayout.NORTH); - labelPane.add(labelPanel, BorderLayout.CENTER); + labelPane.add(labelContentPane, BorderLayout.CENTER); return TableLayout4VanChartHelper.createExpandablePaneWithTitle(PaneTitleConstants.CHART_STYLE_LABEL_TITLE, labelPane); } private void initLabelComponents() { showLabel = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Use_Show"), Toolkit.i18nText("Fine-Design_Chart_Hidden")}); - - labelDisplayComboBox = new AxisLabelDisplayComboBox(); - labelDisplayPane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label_Show"), labelDisplayComboBox, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); - labelDisplayPane.setVisible(showLabelDisplay()); - - labelTextAttrPane = getChartTextAttrPane(); - labelTextRotation = new UINumberDragPane(-ROTATION_MAX, ROTATION_MAX); - labelGapStyle = new UIButtonGroup<>(new String[]{Toolkit.i18nText("Fine-Design_Chart_Automatic"), Toolkit.i18nText("Fine-Design_Chart_Fixed")}); - labelGapValue = new UITextField(); - } - - private JPanel createLabelGapPane(double[] row, double[] col) { - Component[][] gapComponents = new Component[][]{ - new Component[]{null, null}, - new Component[]{ - FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Chart_TextRotation")), - UIComponentUtils.wrapWithBorderLayoutPane(labelTextRotation) - }, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Label_Interval")), labelGapStyle} - }; - - JPanel gapDetailPane = TableLayout4VanChartHelper.createGapTableLayoutPane(gapComponents, row, col); - labelGapValuePane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText(""), labelGapValue, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); - - JPanel panel = new JPanel(new BorderLayout()); - panel.add(gapDetailPane, BorderLayout.CENTER); - panel.add(labelGapValuePane, BorderLayout.SOUTH); - - return panel; + showLogic = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Axis_Style_Whole_Display"), Toolkit.i18nText("Fine-Design_Chart_Axis_Style_Layer_Display")}); + initButtonGroupListener(); } - private JPanel createLabelDetailPanel() { - JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); - - panel.add(labelDisplayPane, BorderLayout.NORTH); - panel.add(labelTextAttrPane, BorderLayout.CENTER); - panel.add(labelGapPane, BorderLayout.SOUTH); - - return panel; - } - - private void addComponentsListener() { - // 显示/隐藏 - showLabel.addActionListener(new ActionListener() { + private void initButtonGroupListener() { + showLogic.addChangeListener(new ChangeListener() { @Override - public void actionPerformed(ActionEvent e) { - checkLabelPane(); - } - }); - - // 间隔/缩略/换行 - labelDisplayComboBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkLabelGapPane(); - } - }); - - // 自动/固定 - labelGapStyle.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - checkLabelGapValuePane(); + public void stateChanged(ChangeEvent e) { + showLabelStyleCard(); } }); } -// protected JPanel createLabelPane(double[] row, double[] col){ -// double p = TableLayout.PREFERRED; -// showLabel = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Use_Show"), Toolkit.i18nText("Fine-Design_Chart_Hidden")}); -// labelTextAttrPane = getChartTextAttrPane(); -// -// JPanel rotationPane = createLabelRotationPane(col); -// JPanel overlapPane = createLabelOverlapPane(); -// -// -// Component[][] components = new Component[][]{ -// new Component[]{labelTextAttrPane, null}, -// new Component[]{rotationPane, null}, -// new Component[]{overlapPane, null}, -// }; -// -// JPanel showLabelPane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label"),showLabel); -// labelPanel = TableLayout4VanChartHelper.createGapTableLayoutPane(components, new double[]{p, p, p}, col); -// labelPanel.setBorder(BorderFactory.createEmptyBorder(0,10,0,0)); -// showLabel.addActionListener(new ActionListener() { -// @Override -// public void actionPerformed(ActionEvent e) { -// checkLabelPane(); -// } -// }); -// JPanel jPanel = new JPanel(new BorderLayout()); -// jPanel.add(showLabelPane, BorderLayout.NORTH); -// jPanel.add(labelPanel, BorderLayout.CENTER); -// return TableLayout4VanChartHelper.createExpandablePaneWithTitle(PaneTitleConstants.CHART_STYLE_LABEL_TITLE, jPanel); -// } - - private JPanel createLabelRotationPane(double[] col) { - labelTextRotation = new UINumberDragPane(-ROTATION_MAX, ROTATION_MAX); - - Component[][] gapComponents = new Component[][]{ - new Component[]{ - FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Chart_TextRotation")), - UIComponentUtils.wrapWithBorderLayoutPane(labelTextRotation) - } - }; - return TableLayout4VanChartHelper.createGapTableLayoutPane(gapComponents, new double[]{TableLayout.PREFERRED}, col); + private void showLabelStyleCard() { + CardLayout layout = (CardLayout) labelStylePane.getLayout(); + if (showLogic.getSelectedIndex() == 0) { + layout.show(labelStylePane, WHOLE_DISPLAY); + } else { + layout.show(labelStylePane, LAYER_DISPLAY); + } + labelStylePane.revalidate(); } - private JPanel createLabelOverlapPane() { - - labelGapStyle = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Automatic"), Toolkit.i18nText("Fine-Design_Chart_Fixed")}); - labelGapStylePane = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Label_Interval"), labelGapStyle, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); - - //轴标签缩略间隔显示 恢复用注释。取消注释。 - //labelGapValue = new UISpinner(0, Integer.MAX_VALUE, 1, 1); - labelGapValuePane = TableLayout4VanChartHelper.createGapTableLayoutPane(StringUtils.EMPTY, labelGapValue, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); - - JPanel panel = new JPanel(new BorderLayout(0, 0)); - addOverlapGroupButton(panel); - panel.add(labelGapStylePane, BorderLayout.CENTER); - panel.add(labelGapValuePane, BorderLayout.SOUTH); - - labelGapStyle.addActionListener(new ActionListener() { + /** + * 创建显示逻辑以及其下面面板 + * + * @return + */ + private JPanel createLabelContentPane() { + labelContentPane = new JPanel(new BorderLayout()); + showLogicPane = new JPanel(new BorderLayout()); + labelStylePane = new JPanel(new CardLayout()) { @Override - public void actionPerformed(ActionEvent e) { - checkLabelGapValuePane(); + public Dimension getPreferredSize() { + switch (showLogic.getSelectedIndex()) { + case 0: + return wholeDisplayLabelPanel.getPreferredSize(); + case 1: + return categoryStylePane.getPreferredSize(); + case -1: + default: + return super.getPreferredSize(); + } } - }); - - return panel; + }; + labelStylePane.add(wholeDisplayLabelPanel, WHOLE_DISPLAY); + labelStylePane.add(createCategoryStylePane(), LAYER_DISPLAY); + showLogicPane.add(TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label_Show_Logic"), showLogic), BorderLayout.NORTH); + showLogicPane.add(labelStylePane, BorderLayout.CENTER); + showLogicPane.setVisible(false); + labelContentPane.add(labelPane, BorderLayout.NORTH); + labelContentPane.add(showLogicPane, BorderLayout.CENTER); + return labelContentPane; } - protected void addOverlapGroupButton(JPanel panel) { - overlapHandleTypeGroup = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Label_OverlapAbbreviate"), Toolkit.i18nText("Fine-Design_Chart_Label_OverlapInterval")}, - new OverlapHandleType[]{OverlapHandleType.ABBREVIATE, OverlapHandleType.INTERVAL}); - JPanel north = TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Label_WhenOverlap"), overlapHandleTypeGroup, TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH); - - panel.add(north, BorderLayout.NORTH); + /** + * 创建多分类轴标签设置面板 + * + * @return + */ + private JPanel createCategoryStylePane() { + categoryStylePane = new JPanel(new BorderLayout()); + categoryStylePane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + return categoryStylePane; + } - overlapHandleTypeGroup.addChangeListener(new ChangeListener() { + private void addComponentsListener() { + // 显示/隐藏 + showLabel.addActionListener(new ActionListener() { @Override - public void stateChanged(ChangeEvent e) { - checkLabelGapAndStylePane(); + public void actionPerformed(ActionEvent e) { + checkLabelPane(); } }); - } protected ChartTextAttrPane getChartTextAttrPane() { - return new ChartTextAttrPaneWithThemeStyle() { - protected double getEdithAreaWidth() { - return TableLayout4VanChartHelper.SECOND_EDIT_AREA_WIDTH; - } - }; + return VanChartAxisPaneHelper.createAxisTextAttrPane(); } protected JPanel createLineStylePane(double[] row, double[] col) { @@ -525,7 +453,6 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { protected void checkAllUse() { checkCardPane(); checkLabelPane(); - checkLabelGapPane(); checkTitlePane(); //区域显示策略 恢复用注释。删除下面一行。 checkMaxProPortionUse(); @@ -558,14 +485,8 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { protected void checkLabelPane() { if (showLabel != null) { boolean enabled = showLabel.getSelectedIndex() == 0; - if (labelPanel != null) { - labelPanel.setVisible(enabled); - } - if (enabled) { - //轴标签缩略间隔显示 恢复用注释。下面1行删除。 - checkLabelGapValuePane(); - //轴标签缩略间隔显示 恢复用注释。取消注释。 - //checkLabelGapAndStylePane(); + if (labelContentPane != null) { + labelContentPane.setVisible(enabled); } } } @@ -576,39 +497,6 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { } } - private void checkLabelGapAndStylePane() { - if (overlapHandleTypeGroup != null && labelGapStylePane != null) { - boolean visible = overlapHandleTypeGroup.getSelectedItem() == OverlapHandleType.INTERVAL; - - labelGapStylePane.setVisible(visible); - } - checkLabelGapValuePane(); - } - - protected void checkLabelGapPane() { - if (labelGapPane != null) { - boolean visible = true; - - if (showLabelDisplay() && labelDisplayPane != null && labelDisplayComboBox != null) { - visible = labelDisplayComboBox.getSelectedIndex() == 0; - } - - labelGapPane.setVisible(visible); - } - } - - protected void checkLabelGapValuePane() { - if (labelGapValuePane != null && labelGapStyle != null) { - boolean visible = labelGapStyle.getSelectedIndex() == 1; - //轴标签缩略间隔显示 恢复用注释。取消注释。 -// if (overlapHandleTypeGroup != null) { -// visible = visible && overlapHandleTypeGroup.getSelectedItem() == OverlapHandleType.INTERVAL; -// } - labelGapValuePane.setVisible(visible); - } - } - - /** * 是否是指定类型 * @@ -682,33 +570,140 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { } //标签 - private void populateLabel(VanChartAxis axis) { + protected void populateLabel(VanChartAxis axis) { if (showLabel != null) { showLabel.setSelectedIndex(axis.isShowAxisLabel() ? 0 : 1); } - TextAttr labelTextAttr = axis.getTextAttr(); - if (labelTextAttrPane != null) { - labelTextAttrPane.populate(labelTextAttr); + + labelPane.populateBean(getAxisLabelStyle(axis)); + populateShowLogicPane(axis); + switchLabelPane(axis); + labelContentPane.validate(); + } + + /** + * 切换显示是单分类样式设置面板还是多分类样式设置面板 + */ + private void switchLabelPane(VanChartAxis axis) { + labelPane.setVisible(!axis.isMultiCategory()); + showLogicPane.setVisible(axis.isMultiCategory()); + } + + private void populateShowLogicPane(VanChartAxis axis) { + if (showLogic != null) { + showLogic.setSelectedIndex(axis.getLabelDisplayMode()); } - if (labelTextRotation != null) { - labelTextRotation.populateBean((double) labelTextAttr.getRotation()); + populateWholeDisplayPane(axis); + populateLayerDisplayPane(axis); + showLabelStyleCard(); + labelStylePane.revalidate(); + } + + /** + * populate整体显示那个card面板 + */ + private void populateWholeDisplayPane(VanChartAxis axis) { + wholeDisplayLabelPanel.populateBean(getAxisLabelStyle(axis)); + } + + private VanChartAxisLabelStyle getAxisLabelStyle(VanChartAxis axis) { + VanChartAxisLabelStyle style = new VanChartAxisLabelStyle(); + DefaultStyleHelper4Van.dealAxisCheckTheme(style); + style.setLabelDisplay(axis.getLabelDisplay()); + style.setTextAttr(axis.getTextAttr()); + style.setAutoLabelGap(axis.isAutoLabelGap()); + style.setLabelIntervalNumber(axis.getLabelNumber()); + return style; + } + + /** + * populate分层显示那个card面板 + * + * @param axis + */ + private void populateLayerDisplayPane(VanChartAxis axis) { + Chart chart = axis.getChart(); + if (chart == null) { + return; } - //轴标签缩略间隔显示 恢复用注释。取消注释。 -// if (overlapHandleTypeGroup != null) { -// overlapHandleTypeGroup.setSelectedItem(axis.getOverlapHandleType()); -// } - if (labelDisplayComboBox != null) { - labelDisplayComboBox.populateBean(axis.getLabelDisplay()); + categoryStylePane.removeAll(); + categoryStyles.clear(); + populateCateLabelStyle(axis); + + categoryStylePane.revalidate(); + } + + + /** + * populate分类标签 + * + * @param axis + */ + private void populateCateLabelStyle(VanChartAxis axis) { + Chart chart = axis.getChart(); + int size; + TopDefinitionProvider definition = chart.getFilterDefinition(); + size = definition == null ? 1 : definition.getMoreCateSize() + 1; + + for (int i = 0; i < size; i++) { + populateCategoryStyles(axis, i); } - if (labelGapStyle != null) { - labelGapStyle.setSelectedIndex(axis.isAutoLabelGap() ? 0 : 1); + } + + private void populateCategoryStyles(VanChartAxis axis, int index) { + VanChartCategoryStylePaneWithCheckBox pane = new VanChartCategoryStylePaneWithCheckBox(parent, this, Toolkit.i18nText("Fine-Design_Chart_Style_Category") + (index + 1)); + VanChartAxisLabelStyle style = populateAxisCategoryStyles(axis, index); + pane.populate(style); + categoryStyles.add(pane); + categoryStylePane.add(createCateLableStylePanel(), BorderLayout.NORTH); + + } + + private VanChartAxisLabelStyle populateAxisCategoryStyles(VanChartAxis axis, int index) { + VanChartAxisLabelStyle style; + if (axis.getCategoryStylesSize() > index && axis.getCategoryStyle(index) != null) { + style = axis.getCategoryStyle(index); + } else { + style = new VanChartAxisLabelStyle(); + DefaultStyleHelper4Van.dealAxisCheckTheme(style); + axis.addCategoryStyle(style); } - if (labelGapValue != null) { - //轴标签缩略间隔显示 恢复用注释。下面1行删除。 - labelGapValue.setText(axis.getLabelNumber().getContent()); - //轴标签缩略间隔显示 恢复用注释。取消注释。 - //labelGapValue.setValue(axis.getIntervalNumber()); + return style; + } + + private JPanel createCateLableStylePanel() { + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + double e = TableLayout4VanChartHelper.EDIT_AREA_WIDTH; + double[] row = getCateLableStylePaneRow(); + double[] column = {f, p}; + + JPanel content = TableLayoutHelper.createTableLayoutPane(getCateLabelStyleComponents(), row, column); + + Component[][] components = new Component[][]{ + new Component[]{null, null}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Style_Category")), content} + }; + + return TableLayoutHelper.createTableLayoutPane(components, new double[]{p, p}, new double[]{f, e}); + } + + private Component[][] getCateLabelStyleComponents() { + Component[][] components = new Component[categoryStyles.size()][]; + for (int i = 0; i < categoryStyles.size(); i++) { + components[i] = new Component[2]; + components[i][0] = categoryStyles.get(i); + components[i][1] = null; } + return components; + } + + private double[] getCateLableStylePaneRow() { + double[] row = new double[categoryStyles.size()]; + for (int i = 0; i < categoryStyles.size(); i++) { + row[i] = TableLayout.PREFERRED; + } + return row; } //轴线样式 @@ -821,37 +816,54 @@ public class VanChartBaseAxisPane extends FurtherBasicBeanPane { } //标签 - private void updateLabel(VanChartAxis axis) { + protected void updateLabel(VanChartAxis axis) { if (showLabel != null) { axis.setShowAxisLabel(showLabel.getSelectedIndex() == 0); } - TextAttr labelTextAttr = axis.getTextAttr(); - if (labelTextAttrPane != null) { - labelTextAttrPane.update(labelTextAttr); - } - if (labelTextRotation != null) { - labelTextAttr.setRotation(labelTextRotation.updateBean().intValue()); - } - //轴标签缩略间隔显示 恢复用注释。取消注释。 -// if (overlapHandleTypeGroup != null) { -// axis.setOverlapHandleType(overlapHandleTypeGroup.getSelectedItem()); -// } - if (labelDisplayComboBox != null) { - axis.setLabelDisplay(labelDisplayComboBox.updateBean()); + if (!axis.isMultiCategory()) { + axis.setLabelDisplayMode(VanChartAxis.WHOLE_DISPLAY); + updateLabelPaneStyle(axis, labelPane); + } else { + updateShowLogicPane(axis); } - if (labelGapStyle != null) { - axis.setAutoLabelGap(labelGapStyle.getSelectedIndex() == 0); + switchLabelPane(axis); + } + + private void updateShowLogicPane(VanChartAxis axis) { + if (showLogic != null) { + axis.setLabelDisplayMode(showLogic.getSelectedIndex()); } - if (labelGapValue != null) { - //轴标签缩略间隔显示 恢复用注释。下面5行删除。 - if (axis.isAutoLabelGap()) { - axis.setLabelIntervalNumber(BaseFormula.createFormulaBuilder().build("1")); - } else { - axis.setLabelIntervalNumber(BaseFormula.createFormulaBuilder().build(labelGapValue.getText())); - } - //轴标签缩略间隔显示 恢复用注释。取消注释。 - //axis.setIntervalNumber((int) labelGapValue.getValue()); + + updateWholeDisplayPane(axis); + updateLayerDisplayPane(axis); + } + + /** + * update整体显示那个card面板 + */ + private void updateWholeDisplayPane(VanChartAxis axis) { + updateLabelPaneStyle(axis, wholeDisplayLabelPanel); + } + + private void updateLabelPaneStyle(VanChartAxis axis, VanChartAxisStyleSettingPane pane) { + VanChartAxisLabelStyle style = pane.updateBean(); + axis.setLabelDisplay(style.getLabelDisplay()); + axis.setTextAttr(style.getTextAttr()); + axis.setAutoLabelGap(style.isAutoLabelGap()); + axis.setLabelIntervalNumber(style.getLabelIntervalNumber()); + } + + /** + * update分层显示那个card面板 + * + * @param axis + */ + private void updateLayerDisplayPane(VanChartAxis axis) { + List styles = new ArrayList<>(); + for (VanChartCategoryStylePaneWithCheckBox categoryStyle : categoryStyles) { + styles.add(categoryStyle.update()); } + axis.setCategoryStyles(styles); } //轴线样式 diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartTimeAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartTimeAxisPane.java index 1a0b78982f..500667963b 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartTimeAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartTimeAxisPane.java @@ -85,11 +85,6 @@ public class VanChartTimeAxisPane extends VanChartBaseAxisPane { return false; } - @Override - protected void addOverlapGroupButton(JPanel panel) { - //do nothing - } - private JPanel createValueDefinition(){ timeMinMaxValuePane = new TimeMinMaxValuePane(); return TableLayout4VanChartHelper.createExpandablePaneWithTitle(Toolkit.i18nText("Fine-Design_Chart_Value_Definition"), timeMinMaxValuePane); diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartValueAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartValueAxisPane.java index 7633d0c1e4..032642c93a 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartValueAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/VanChartValueAxisPane.java @@ -66,11 +66,6 @@ public class VanChartValueAxisPane extends VanChartBaseAxisPane { return false; } - @Override - protected void addOverlapGroupButton(JPanel panel) { - //do nothing - } - protected JPanel createMinMaxValuePane(double[] row, double[] col){ JPanel panel = createCommenValuePane(row,col); return TableLayout4VanChartHelper.createExpandablePaneWithTitle(Toolkit.i18nText("Fine-Design_Chart_Value_Definition"), panel); diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartAxisButtonPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartAxisButtonPane.java index d5f866c818..3020093278 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartAxisButtonPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartAxisButtonPane.java @@ -356,7 +356,7 @@ public class VanChartAxisButtonPane extends BasicBeanPane { if (isEnabled()) { noSelected(); changeAxisSelected(getButtonName()); - setSelectedWithFireListener(true); + setSelected(true, true); fireSelectedChanged(); } } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartCategoryStylePaneWithCheckBox.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartCategoryStylePaneWithCheckBox.java new file mode 100644 index 0000000000..79e4aad9bd --- /dev/null +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/component/VanChartCategoryStylePaneWithCheckBox.java @@ -0,0 +1,97 @@ +package com.fr.van.chart.designer.style.axis.component; + +import com.fr.design.gui.frpane.AbstractAttrNoScrollPane; +import com.fr.design.gui.frpane.ClosableBubbleFloatPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.i18n.Toolkit; +import com.fr.plugin.chart.attr.axis.VanChartAxisLabelStyle; +import com.fr.stable.Constants; +import com.fr.van.chart.designer.style.axis.VanChartAxisPaneHelper; +import com.fr.van.chart.designer.style.axis.VanChartAxisStyleSettingPane; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class VanChartCategoryStylePaneWithCheckBox extends JPanel { + private UICheckBox checkBox; // 复选框 + private UIButton settingButton; // 设置按钮 + private VanChartAxisStyleSettingPane settingPane; // 设置弹窗面板 + + private JPanel showOnPane; + private AbstractAttrNoScrollPane parent; + + private VanChartAxisLabelStyle axis; + + public VanChartCategoryStylePaneWithCheckBox(AbstractAttrNoScrollPane parent, JPanel showOnPane, String checkBoxName) { + this.parent = parent; + this.showOnPane = showOnPane; + + this.setLayout(new BorderLayout()); + checkBox = new UICheckBox(checkBoxName); + checkBox.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); + checkBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + /* 为什么需要这句话呢?因为这个checkBox是动态加上去的,没有走最上层父组件ChartStylePane的initAllListener方法, + * 所以不会触发update监听,下面的bubble弹窗则是不属于ChartStylePane的单独悬浮组件,也只能这样触发update监听 + */ + if(parent != null){ + parent.attributeChanged(); + } + } + }); + settingButton = new UIButton(Toolkit.i18nText("Fine-Design_Chart_Axis_Style_Setting")); + + this.add(checkBox, BorderLayout.CENTER); + this.add(settingButton, BorderLayout.EAST); + + initListener(); + } + + private void initListener() { + if(settingButton != null) { + settingButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + if (settingPane == null) { + settingPane = new VanChartAxisStyleSettingPane(VanChartAxisPaneHelper.createAxisTextAttrPane()); + } + + Point comPoint = settingButton.getLocationOnScreen(); + Point arrowPoint = new Point(comPoint.x +settingButton.getWidth() - 25, comPoint.y + settingButton.getHeight()); + Dimension size = settingPane.getPreferredSize(); + ClosableBubbleFloatPane pane = new ClosableBubbleFloatPane(Constants.LEFT, arrowPoint, settingPane, size.width, 240) { + + @Override + public void updateContentPane() { + axis = settingPane.updateBean(); + if(parent != null){//条件属性没有parent + parent.attributeChanged(); + } + } + }; + pane.show(showOnPane, axis); + super.mouseReleased(e); + } + }); + } + } + + public void populate(VanChartAxisLabelStyle style) { + this.axis = style; + checkBox.setSelected(axis.isShowLabel()); + } + + public VanChartAxisLabelStyle update() { + axis.setShowLabel(checkBox.isSelected()); + return axis; + } +} diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/gauge/VanChartGaugeDetailAxisPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/gauge/VanChartGaugeDetailAxisPane.java index 18fadeb985..7817b75f58 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/gauge/VanChartGaugeDetailAxisPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/axis/gauge/VanChartGaugeDetailAxisPane.java @@ -1,5 +1,6 @@ package com.fr.van.chart.designer.style.axis.gauge; +import com.fr.chart.base.TextAttr; import com.fr.design.gui.ibutton.UIButtonGroup; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; @@ -9,6 +10,7 @@ import com.fr.design.mainframe.chart.PaneTitleConstants; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithAuto; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.design.style.color.ColorSelectBox; import com.fr.plugin.chart.attr.axis.VanChartAxis; import com.fr.plugin.chart.attr.axis.VanChartGaugeAxis; @@ -34,6 +36,7 @@ public class VanChartGaugeDetailAxisPane extends VanChartValueAxisPane { private static final long serialVersionUID = -9213466625457882224L; + private ChartTextAttrPane labelTextAttrPane; private ColorSelectBox mainTickColor; private ColorSelectBox secTickColor; @@ -82,12 +85,12 @@ public class VanChartGaugeDetailAxisPane extends VanChartValueAxisPane { protected JPanel createLabelPane(double[] row, double[] col) { showLabel = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Use_Show"), Toolkit.i18nText("Fine-Design_Chart_Hidden")}); labelTextAttrPane = getChartTextAttrPane(); - labelPanel = new JPanel(new BorderLayout()); - labelPanel.add(labelTextAttrPane); - labelPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0)); + labelContentPane = new JPanel(new BorderLayout()); + labelContentPane.add(labelTextAttrPane); + labelContentPane.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0)); JPanel panel = new JPanel(new BorderLayout(0, 6)); panel.add(TableLayout4VanChartHelper.createGapTableLayoutPane(Toolkit.i18nText("Fine-Design_Chart_Axis_Label"), showLabel), BorderLayout.NORTH); - panel.add(labelPanel, BorderLayout.CENTER); + panel.add(labelContentPane, BorderLayout.CENTER); showLabel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -103,7 +106,7 @@ public class VanChartGaugeDetailAxisPane extends VanChartValueAxisPane { if (isMulti(gaugeStyle)) { return new ChartTextAttrPaneWithAuto(FontAutoType.SIZE_AND_COLOR); } else { - return new ChartTextAttrPaneWithThemeStyle(); + return ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() : new ChartTextAttrPane(); } } @@ -182,23 +185,44 @@ public class VanChartGaugeDetailAxisPane extends VanChartValueAxisPane { public void populateBean(VanChartAxis axis) { VanChartGaugeAxis gaugeAxis = (VanChartGaugeAxis) axis; + labelTextAttrPane.populate(axis.getTextAttr()); + super.populateBean(gaugeAxis); + } + + @Override + protected void populateLabel(VanChartAxis axis) { + VanChartGaugeAxis gaugeAxis = (VanChartGaugeAxis) axis; + + if (showLabel != null) { + showLabel.setSelectedIndex(axis.isShowAxisLabel() ? 0 : 1); + } if (mainTickColor != null) { mainTickColor.setSelectObject(gaugeAxis.getMainTickColor()); } if (secTickColor != null) { secTickColor.setSelectObject(gaugeAxis.getSecTickColor()); } - super.populateBean(gaugeAxis); } public void updateBean(VanChartAxis axis) { VanChartGaugeAxis gaugeAxis = (VanChartGaugeAxis) axis; + TextAttr textAttr = axis.getTextAttr(); + labelTextAttrPane.update(textAttr); + super.updateBean(gaugeAxis); + } + + @Override + protected void updateLabel(VanChartAxis axis) { + VanChartGaugeAxis gaugeAxis = (VanChartGaugeAxis) axis; + + if (showLabel != null) { + axis.setShowAxisLabel(showLabel.getSelectedIndex() == 0); + } if (mainTickColor != null) { gaugeAxis.setMainTickColor(mainTickColor.getSelectObject()); } if (secTickColor != null) { gaugeAxis.setSecTickColor(secTickColor.getSelectObject()); } - super.updateBean(gaugeAxis); } } \ No newline at end of file diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/ChartNameObjectCreator.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/ChartNameObjectCreator.java index 8a5a33ca85..4d8bbe990b 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/ChartNameObjectCreator.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/ChartNameObjectCreator.java @@ -3,10 +3,11 @@ package com.fr.van.chart.designer.style.background; import com.fr.design.beans.BasicBeanPane; import com.fr.design.gui.controlpane.NameObjectCreator; import com.fr.design.gui.controlpane.UnrepeatedNameHelper; -import com.fr.log.FineLoggerFactory; import com.fr.general.NameObject; +import com.fr.log.FineLoggerFactory; import com.fr.plugin.chart.attr.axis.VanChartAlertValue; import com.fr.stable.Nameable; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -37,6 +38,7 @@ public class ChartNameObjectCreator extends NameObjectCreator { VanChartAlertValue vanChartAlertValue = constructor.newInstance(); vanChartAlertValue.setAxisNamesArray((String[]) object); vanChartAlertValue.setAxisName(((String[]) object)[0]); + DefaultStyleHelper4Van.dealAxisAlert(vanChartAlertValue); return new NameObject(helper.createUnrepeatedName(this.menuName()), vanChartAlertValue); } catch (NoSuchMethodException e) { diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAlertValuePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAlertValuePane.java index 387d974d28..49e7f3fa99 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAlertValuePane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAlertValuePane.java @@ -17,6 +17,7 @@ import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.style.color.ColorSelectBox; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; import com.fr.general.GeneralUtils; @@ -99,7 +100,7 @@ public class VanChartAlertValuePane extends BasicBeanPane { alertText.setPreferredSize(new Dimension(TEXT_WD, HT)); fontSize = new UIComboBox(FRFontPane.FONT_SIZES); - fontName = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontName = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); fontColor = new ColorSelectBox(100); } diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAreaBackgroundPane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAreaBackgroundPane.java index 6f65af6e15..e6eb8c6131 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAreaBackgroundPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/style/background/VanChartAreaBackgroundPane.java @@ -8,6 +8,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.chart.PaneTitleConstants; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.van.chart.designer.AbstractVanChartScrollPane; import com.fr.van.chart.designer.TableLayout4VanChartHelper; import com.fr.van.chart.designer.component.background.VanChartBackgroundPane; @@ -49,7 +50,7 @@ public class VanChartAreaBackgroundPane extends AbstractVanChartScrollPane { } protected VanChartBorderPane createBorderPanePane() { - return new VanChartBorderPaneWithPreStyle(); + return ChartEditContext.supportTheme() ? new VanChartBorderPaneWithPreStyle() : new VanChartBorderPane(); } protected ChartTextAttrPane createChartTextAttrPane() { - return new ChartTextAttrPaneWithThemeStyle(); + return ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() : new ChartTextAttrPane(); } @Override diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/type/AbstractVanChartTypePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/type/AbstractVanChartTypePane.java index 9cf9165547..ef58809795 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/designer/type/AbstractVanChartTypePane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/designer/type/AbstractVanChartTypePane.java @@ -24,6 +24,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane; import com.fr.design.mainframe.chart.gui.type.ChartImagePane; import com.fr.design.mainframe.chart.info.ChartInfoCollector; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.general.Background; import com.fr.js.NameJavaScriptGroup; import com.fr.log.FineLoggerFactory; @@ -31,6 +32,7 @@ import com.fr.plugin.chart.attr.plot.VanChartPlot; import com.fr.plugin.chart.base.VanChartTools; import com.fr.plugin.chart.base.VanChartZoom; import com.fr.plugin.chart.vanchart.VanChart; +import com.fr.van.chart.config.DefaultStyleHelper4Van; import javax.swing.BorderFactory; import javax.swing.JPanel; @@ -144,6 +146,7 @@ public abstract class AbstractVanChartTypePane extends AbstractChartTypePane 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-chart/src/main/java/com/fr/van/chart/gantt/designer/style/tooltip/VanChartFormatComBoxWithCheckBox.java b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/tooltip/VanChartFormatComBoxWithCheckBox.java index 95da8ea986..f17d07a249 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/tooltip/VanChartFormatComBoxWithCheckBox.java +++ b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/style/tooltip/VanChartFormatComBoxWithCheckBox.java @@ -53,7 +53,7 @@ public class VanChartFormatComBoxWithCheckBox extends JPanel { } }); - formatComBox.setPreferredSize(new Dimension(40, 20)); + formatComBox.setPreferredSize(new Dimension(55, 20)); if (showSelectBox()) { this.add(isSelectedBox, BorderLayout.CENTER); diff --git a/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/GisLayerPane.java b/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/GisLayerPane.java index 580144ce54..43a770beae 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/GisLayerPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/GisLayerPane.java @@ -9,6 +9,7 @@ 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.mode.ChartEditContext; import com.fr.general.ComparatorUtils; import com.fr.plugin.chart.base.GisLayer; import com.fr.plugin.chart.map.VanChartMapPlot; @@ -84,7 +85,7 @@ public class GisLayerPane extends JPanel implements UIObserver { private JPanel createGISLayerPane() { gisButton = new UIButtonGroup(new String[]{Toolkit.i18nText("Fine-Design_Chart_Mode_Auto"), Toolkit.i18nText("Fine-Design_Form_Widget_Style_Standard"), Toolkit.i18nText("Fine-Design_Chart_Custom")}); - gisButton.setSelectedIndex(0); + gisButton.setSelectedIndex(ChartEditContext.supportTheme() ? 0 : 1); gisGaoDeLayer = new UIComboBox(MapLayerConfigManager.getGaoDeLayerItems()); gisButton.addActionListener(event -> { refreshZoomLevel(); @@ -236,9 +237,19 @@ public class GisLayerPane extends JPanel implements UIObserver { } public void resetGisLayer(VanChartMapPlot mapPlot) { - GisLayer defaultGisLayer = mapPlot.getDefaultGisLayer(); - mapPlot.setGisLayer(defaultGisLayer); - populate(defaultGisLayer); + +// if (ChartEditContext.supportTheme()) { + GisLayer defaultGisLayer = mapPlot.getDefaultGisLayer(); + mapPlot.setGisLayer(defaultGisLayer); + populate(defaultGisLayer); +// } else { +// GaoDeGisType gaoDeGisType = mapPlot.getDefaultGisLayerType(); +// +// mapPlot.getGisLayer().setGisLayerType(GISLayerType.GAO_DE_API); +// mapPlot.getGisLayer().setLayerName(gaoDeGisType.getTypeName()); +// mapPlot.getGisLayer().setGaoDeGisType(gaoDeGisType); +// populate(mapPlot.getGisLayer()); +// } } public void populate(GisLayer layer) { diff --git a/designer-chart/src/main/java/com/fr/van/chart/multilayer/data/MultiPiePlotTableDataContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/multilayer/data/MultiPiePlotTableDataContentPane.java index bfea7e1dc7..b32ea4b67c 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/multilayer/data/MultiPiePlotTableDataContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/multilayer/data/MultiPiePlotTableDataContentPane.java @@ -10,6 +10,7 @@ import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ispinner.UISpinner; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayout; import com.fr.design.mainframe.chart.gui.ChartDataPane; import com.fr.design.mainframe.chart.gui.data.CalculateComboBox; @@ -17,7 +18,6 @@ import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane import com.fr.design.mainframe.chart.gui.data.table.DataPaneHelper; import com.fr.general.ComparatorUtils; import com.fr.plugin.chart.multilayer.data.MultiPieValueDefinition; -import com.fr.design.i18n.Toolkit; import com.fr.stable.ArrayUtils; import com.fr.stable.AssistUtils; import com.fr.stable.StringUtils; @@ -235,7 +235,14 @@ public class MultiPiePlotTableDataContentPane extends AbstractTableDataContentPa @Override public void clearAllBoxList() { - + levelNumEdit.setValue(3); + nameField.setText(StringUtils.EMPTY); + clearBoxItems(value); + for (UIComboBox uiComboBox : levelNameList) { + clearBoxItems(uiComboBox); + } + clearBoxItems(calculateCombox); + refreshCenterPane(); } @Override diff --git a/designer-chart/src/main/java/com/fr/van/chart/pie/style/VanChartPieCategoryLabelContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/pie/style/VanChartPieCategoryLabelContentPane.java index 73c63bbeec..5039f53881 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/pie/style/VanChartPieCategoryLabelContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/pie/style/VanChartPieCategoryLabelContentPane.java @@ -1,13 +1,14 @@ package com.fr.van.chart.pie.style; import com.fr.design.i18n.Toolkit; -import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithAuto; import com.fr.design.ui.ModernUIPane; import com.fr.plugin.chart.base.AttrTooltipContent; import com.fr.plugin.chart.base.format.AttrTooltipCategoryFormat; import com.fr.plugin.chart.base.format.AttrTooltipFormat; import com.fr.plugin.chart.base.format.AttrTooltipSummaryValueFormat; import com.fr.plugin.chart.pie.attr.PieCategoryLabelContent; +import com.fr.plugin.chart.type.FontAutoType; import com.fr.van.chart.designer.component.VanChartLabelContentPane; import com.fr.van.chart.designer.component.format.CategoryNameFormatPaneWithCheckBox; import com.fr.van.chart.designer.component.format.SummaryValueFormatPaneWithCheckBox; @@ -86,7 +87,7 @@ public class VanChartPieCategoryLabelContentPane extends VanChartLabelContentPan } public JPanel createCommonStylePane() { - setTextAttrPane(new ChartTextAttrPane()); + setTextAttrPane(new ChartTextAttrPaneWithAuto(FontAutoType.COLOR)); return getTextAttrPane(); } diff --git a/designer-chart/src/main/java/com/fr/van/chart/range/component/GradualIntervalConfigPane.java b/designer-chart/src/main/java/com/fr/van/chart/range/component/GradualIntervalConfigPane.java index 1a0413ffaa..f1cdc5b62e 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/range/component/GradualIntervalConfigPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/range/component/GradualIntervalConfigPane.java @@ -14,7 +14,7 @@ import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.Component; -public class GradualIntervalConfigPane extends JPanel{ +public class GradualIntervalConfigPane extends JPanel { private static final long serialVersionUID = 1614283200308877353L; //最大最小值面板 @@ -26,7 +26,7 @@ public class GradualIntervalConfigPane extends JPanel{ //渐变色编辑器 private LegendGradientBar legendGradientBar; - public GradualIntervalConfigPane(){ + public GradualIntervalConfigPane() { initComponents(); } @@ -42,10 +42,10 @@ public class GradualIntervalConfigPane extends JPanel{ } }); - numberDragPane = new UINumberDragPane(1,6) { + numberDragPane = new UINumberDragPane(1, LegendGradientBar.COLOR_GRADUAL_NUM_MAX) { @Override public void userEvent(double value) { - legendGradientBar.refreshColorSelectionBtnNum((int)value); + legendGradientBar.refreshColorSelectionBtnNum((int) value); } }; @@ -60,9 +60,9 @@ public class GradualIntervalConfigPane extends JPanel{ Component[][] components = getPaneComponents(minMaxValuePane, colorSelectBox, numberDragPane, legendGradientBar); //控件承载面板 - JPanel contentPane = TableLayout4VanChartHelper.createGapTableLayoutPane(components,row,col); + JPanel contentPane = TableLayout4VanChartHelper.createGapTableLayoutPane(components, row, col); this.setLayout(new BorderLayout()); - this.add(contentPane,BorderLayout.CENTER); + this.add(contentPane, BorderLayout.CENTER); } protected LegendGradientBar createLegendGradientBar() { @@ -81,7 +81,7 @@ public class GradualIntervalConfigPane extends JPanel{ }; } - public void populate(GradualIntervalConfig intervalConfig){ + public void populate(GradualIntervalConfig intervalConfig) { minMaxValuePane.populate(intervalConfig.getMinAndMaxValue()); colorSelectBox.setSelectObject(intervalConfig.getSubColor()); @@ -92,7 +92,7 @@ public class GradualIntervalConfigPane extends JPanel{ legendGradientBar.populate(intervalConfig); } - public void update(GradualIntervalConfig intervalConfig){ + public void update(GradualIntervalConfig intervalConfig) { minMaxValuePane.update(intervalConfig.getMinAndMaxValue()); intervalConfig.setSubColor(colorSelectBox.getSelectObject()); diff --git a/designer-chart/src/main/java/com/fr/van/chart/range/component/LegendGradientBar.java b/designer-chart/src/main/java/com/fr/van/chart/range/component/LegendGradientBar.java index 6096056a4b..c55e2a4923 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/range/component/LegendGradientBar.java +++ b/designer-chart/src/main/java/com/fr/van/chart/range/component/LegendGradientBar.java @@ -44,14 +44,16 @@ public class LegendGradientBar extends JComponent implements ColorSelectable, UI private static final int REC_HEIGHT = 30; private static final int MAX_VERTICAL = 45; + //颜色选择器个数 private int colorSelectionBtnNum; //主题色 private Color subColor; - private int max = 150; + private static int max = 150; private int min = 4; + public static final int COLOR_GRADUAL_NUM_MAX = max / 5; //选中的颜色 private Color color; diff --git a/designer-chart/src/main/java/com/fr/van/chart/scatter/VanChartScatterLabelContentPane.java b/designer-chart/src/main/java/com/fr/van/chart/scatter/VanChartScatterLabelContentPane.java index 364b3d1feb..85bbc3c5a2 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/scatter/VanChartScatterLabelContentPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/scatter/VanChartScatterLabelContentPane.java @@ -1,6 +1,8 @@ package com.fr.van.chart.scatter; +import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane; import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPaneWithThemeStyle; +import com.fr.design.mainframe.chart.mode.ChartEditContext; import com.fr.plugin.chart.base.AttrTooltipContent; import com.fr.van.chart.designer.component.VanChartHtmlLabelPane; import com.fr.van.chart.designer.component.VanChartHtmlLabelPaneWithBackGroundLabel; @@ -28,7 +30,7 @@ public class VanChartScatterLabelContentPane extends VanChartScatterTooltipCont if (isInCondition()) { return super.createCommonStylePane(); } - setTextAttrPane(new ChartTextAttrPaneWithThemeStyle()); + setTextAttrPane(ChartEditContext.supportTheme() ? new ChartTextAttrPaneWithThemeStyle() : new ChartTextAttrPane()); JPanel stylePanel = new JPanel(new BorderLayout()); stylePanel.add(getTextAttrPane(), BorderLayout.CENTER); diff --git a/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/style/VanChartWordCloudSeriesPane.java b/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/style/VanChartWordCloudSeriesPane.java index 543b8139f6..29624a5867 100644 --- a/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/style/VanChartWordCloudSeriesPane.java +++ b/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/style/VanChartWordCloudSeriesPane.java @@ -14,6 +14,7 @@ import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.backgroundpane.ImageBackgroundQuickPane; import com.fr.design.mainframe.chart.gui.ChartStylePane; +import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.FRFont; import com.fr.general.IOUtils; @@ -94,7 +95,7 @@ public class VanChartWordCloudSeriesPane extends VanChartColorValueSeriesPane { double[] northC = {f, e}; double[] northR = {p, p}; - fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report()); + fontNameComboBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); defineFontSize = new UIButtonGroup(new String[]{AUTO_FONT_SIZE, CUSTOM_FONT_SIZE}); Component[][] northComps = new Component[][]{ new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Font")), fontNameComboBox}, diff --git a/designer-chart/src/main/resources/com/fr/design/editor/rich_editor.html b/designer-chart/src/main/resources/com/fr/design/editor/rich_editor.html index 6df5a29a14..da8dd5bed1 100644 --- a/designer-chart/src/main/resources/com/fr/design/editor/rich_editor.html +++ b/designer-chart/src/main/resources/com/fr/design/editor/rich_editor.html @@ -20,6 +20,33 @@