Browse Source
* commit 'aabaec7fab829314576eeba937a91c262193b23b': (111 commits) CHART-17983 仪表盘目标值默认 && CHART-18024 数据集改变,监听重复导致结果错误 CHART-18050 使用双列网格布局代替流式布局,补充国际化 CHART-18050 富文本弹窗界面设置为可拖拽大小 CHART-17775 删除无用方法 CHART-17775 像素 & 百分比控件优化 新增字段支持部分图表类型 调整富文本参数顺序 适配仪表盘,清理代码 适配饼图 适配箱型图 REPORT-44666 fix 无用import REPORT-44666 多屏情况下 部分弹窗显示在另一块屏幕 适配甘特图 REPORT-44666 fix 无用import REPORT-44666 多屏情况下 部分弹窗显示在另一块屏幕 REPORT-43833 【10.0.14】远程设计数据连接/服务器数据集增加锁定 1. 将本地实现作为默认实现,注册起来,以兼容远程连接老版服务器的情况 2. 之前清理脏数据的逻辑有点问题,修改方式为:为LockItem对象添加一个成员变量birth,代表其创建时间,并且会为每个ClientID在对应的服务中存上一个key=clientID,value=LockItem的键值对,在用户登入时初始化,每隔30s更新创建时间,用户登出时清除,并且在轮询任务中加入检查当前各个LockItem对应的服务下这个键值对里value的birth是否超时了,如果超时,清理脏数据 3. 将之前使用的applyForService修改为applyForCleanableService,便于集群重启时清理服务数据 适配框架图 REPORT-43833 【10.0.14】远程设计数据连接/服务器数据集增加锁定 将通知组件的操作放到EDT中 REPORT-43833 【10.0.14】远程设计数据连接/服务器数据集增加锁定 将弹窗关闭后解锁的操作,放到afterCommit中 适配漏斗图 ...feature/big-screen
zheng
4 years ago
505 changed files with 8351 additions and 2596 deletions
@ -0,0 +1,110 @@
|
||||
package com.fr.base.svg; |
||||
|
||||
import com.fr.general.IOUtils; |
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import javax.swing.Icon; |
||||
import javax.swing.ImageIcon; |
||||
|
||||
/** |
||||
* 主要是用来读取svgIcon的工具类 |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2020/12/23 |
||||
*/ |
||||
public class IconUtils { |
||||
|
||||
private static final String ICON_SUFFIX_SVG = ".svg"; |
||||
private static final String ICON_SUFFIX_PNG = ".png"; |
||||
private static final String ICON_SUFFIX_GIF = ".gif"; |
||||
private static final String SUFFIX_SEPARATOR = "."; |
||||
|
||||
public static final String ICON_TYPE_NORMAL= "_normal.svg"; |
||||
public static final String ICON_TYPE_DISABLED= "_disabled.svg"; |
||||
public static final String ICON_TYPE_PRESSED= "_pressed.svg"; |
||||
|
||||
|
||||
/** |
||||
* 可以读取SVG图标或者普通图标,并且可以读取不带扩展名的文件 |
||||
* 不带扩展名时以svg优先、其次png,最后gif |
||||
* @param resource 图片路径 |
||||
* @return 图标 |
||||
*/ |
||||
public static Icon readIcon(String resource) { |
||||
// 判断是否有.XXX文件后缀
|
||||
if (resource.contains(SUFFIX_SEPARATOR)) { |
||||
// 判断是否以.svg结尾
|
||||
if (resource.endsWith(ICON_SUFFIX_SVG)) { |
||||
if (IOUtils.readResource(resource) != null) { |
||||
return SVGIcon.readSVGIcon(resource); |
||||
} |
||||
// 适配某些插件里是_normal.png、_selected.png的情况
|
||||
String pngResource = resource.replace(ICON_SUFFIX_SVG, ICON_SUFFIX_PNG); |
||||
return IOUtils.readIcon(pngResource); |
||||
} |
||||
return IOUtils.readIcon(resource); |
||||
} |
||||
// 文件无后缀时
|
||||
return readNoSuffixResource(resource, ICON_TYPE_NORMAL); |
||||
} |
||||
|
||||
/** |
||||
* 尝试读取不带扩展名的图标,svg优先,其次png,最后gif,都没读到就打印错误日志,返回空白Icon |
||||
* @param resource 图片路径 |
||||
* @param svgIconType 针对svg来说的图标类型 |
||||
* 取值为:ICON_TYPE_NORMAL、ICON_TYPE_DISABLED、ICON_TYPE_PRESSED |
||||
* @return 图标 |
||||
*/ |
||||
private static Icon readNoSuffixResource(String resource, String svgIconType) { |
||||
String svgPath = resource + svgIconType; |
||||
if (IOUtils.readResource(svgPath) != null) { |
||||
return SVGIcon.readSVGIcon(svgPath); |
||||
} |
||||
String pngPath = resource + ICON_SUFFIX_PNG; |
||||
if (IOUtils.readResource(pngPath) != null) { |
||||
return IOUtils.readIcon(pngPath); |
||||
} |
||||
String gifPath = resource + ICON_SUFFIX_GIF; |
||||
if (IOUtils.readResource(gifPath) != null) { |
||||
return IOUtils.readIcon(gifPath); |
||||
} |
||||
FineLoggerFactory.getLogger().error("File not exists:{}", resource); |
||||
return new ImageIcon(); |
||||
} |
||||
|
||||
/** |
||||
* 读取指定类型的svgIcon |
||||
* @param resource |
||||
* @param svgIconType |
||||
* @return |
||||
*/ |
||||
public static Icon readSVGIcon(String resource, String svgIconType) { |
||||
// 判断下是否有后缀
|
||||
if (!resource.contains(SUFFIX_SEPARATOR)) { |
||||
return readNoSuffixResource(resource, svgIconType); |
||||
} |
||||
// 如果是".png"后缀,就替换为传入的svgIconType,然后读取图标
|
||||
if (resource.endsWith(ICON_SUFFIX_PNG)) { |
||||
return readSpecifiedTypeIcon(resource, ICON_SUFFIX_PNG, svgIconType); |
||||
} |
||||
// 如果是"_XXXXXX.svg"后缀
|
||||
if (resource.endsWith(ICON_TYPE_NORMAL)) { |
||||
return readSpecifiedTypeIcon(resource, ICON_TYPE_NORMAL, svgIconType); |
||||
} |
||||
if (resource.endsWith(ICON_TYPE_DISABLED)) { |
||||
return readSpecifiedTypeIcon(resource, ICON_TYPE_DISABLED, svgIconType); |
||||
} |
||||
if (resource.endsWith(ICON_TYPE_PRESSED)) { |
||||
return readSpecifiedTypeIcon(resource, ICON_TYPE_PRESSED, svgIconType); |
||||
} |
||||
return readIcon(resource); |
||||
} |
||||
|
||||
private static Icon readSpecifiedTypeIcon(String resource, String oldSuffix, String newSuffix) { |
||||
String iconPath = resource.replace(oldSuffix, newSuffix); |
||||
if (IOUtils.readResource(iconPath) != null) { |
||||
return SVGIcon.readSVGIcon(iconPath); |
||||
} |
||||
return readIcon(resource); |
||||
} |
||||
} |
@ -0,0 +1,82 @@
|
||||
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 java.awt.image.BufferedImage; |
||||
|
||||
/** |
||||
* SVG转化而来的Icon |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2020/12/17 |
||||
*/ |
||||
public class SVGIcon implements Icon { |
||||
|
||||
private BufferedImage image; |
||||
|
||||
private static final boolean HI_DPI_SURPORT = SystemScaleUtils.isJreHiDPIEnabled(); |
||||
|
||||
public static final float SYSTEM_SCALE = SystemScaleUtils.sysScale(); |
||||
|
||||
private static final String ICON_PREFIX = "/"; |
||||
|
||||
public SVGIcon(BufferedImage image) { |
||||
this.image = image; |
||||
} |
||||
|
||||
@Override |
||||
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||
if (HI_DPI_SURPORT) { |
||||
Graphics2D graphics = (Graphics2D) g.create(x, y, image.getWidth(null), image.getHeight(null)); |
||||
float scale = SYSTEM_SCALE; |
||||
graphics.scale(1 / scale, 1 / scale); |
||||
graphics.drawImage(image, 0, 0, null); |
||||
graphics.scale(1.0D, 1.0D); |
||||
graphics.dispose(); |
||||
} else { |
||||
g.drawImage(image, x, y, null); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getIconWidth() { |
||||
return HI_DPI_SURPORT ? (int) (image.getWidth() / SYSTEM_SCALE) : image.getWidth(); |
||||
} |
||||
|
||||
@Override |
||||
public int getIconHeight() { |
||||
return HI_DPI_SURPORT ? (int) (image.getHeight() / SYSTEM_SCALE) : image.getHeight(); |
||||
} |
||||
|
||||
/** |
||||
* 读取高清图标 |
||||
* @param url |
||||
* @return |
||||
*/ |
||||
public static Icon readSVGIcon(String url) { |
||||
if (!url.startsWith(ICON_PREFIX)) { |
||||
url = ICON_PREFIX + url; |
||||
} |
||||
BufferedImage image = (BufferedImage) SVGLoader.load(url); |
||||
return image == null ? IOUtils.readIcon(url) : new SVGIcon(image); |
||||
} |
||||
|
||||
/** |
||||
* 读取指定尺寸的图标 |
||||
* @param url 资源路径 |
||||
* @param width 宽度 |
||||
* @param height 高度 |
||||
* @return |
||||
*/ |
||||
public static Icon readSVGIcon(String url, float width, float height) { |
||||
if (!url.startsWith(ICON_PREFIX)) { |
||||
url = ICON_PREFIX + url; |
||||
} |
||||
BufferedImage image = (BufferedImage) SVGLoader.load(url, width, height); |
||||
return image == null ? IOUtils.readIcon(url) : new SVGIcon(image); |
||||
} |
||||
} |
@ -0,0 +1,92 @@
|
||||
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; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,181 @@
|
||||
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<Double> iconMaxSize = new AtomicNotNullLazyValue<Double>() { |
||||
@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 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\">\n" + |
||||
" <rect x=\"1\" y=\"1\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"red\" stroke-width=\"2\"/>\n" + |
||||
" <line x1=\"1\" y1=\"1\" x2=\"15\" y2=\"15\" stroke=\"red\" stroke-width=\"2\"/>\n" + |
||||
" <line x1=\"1\" y1=\"15\" x2=\"15\" y2=\"1\" stroke=\"red\" stroke-width=\"2\"/>\n" + |
||||
"</svg>\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); |
||||
} |
||||
} |
@ -0,0 +1,101 @@
|
||||
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<Boolean> 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; |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,25 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
|
||||
import com.fr.report.LockItem; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
* 定义数据连接的checker |
||||
*/ |
||||
public class ConnectionLockChangeChecker extends EditLockChangeChecker{ |
||||
|
||||
private static class Holder { |
||||
private static final ConnectionLockChangeChecker INSTANCE = new ConnectionLockChangeChecker(); |
||||
} |
||||
|
||||
public static ConnectionLockChangeChecker getInstance() { |
||||
return ConnectionLockChangeChecker.Holder.INSTANCE; |
||||
} |
||||
|
||||
public ConnectionLockChangeChecker() { |
||||
this.lockItem = LockItem.CONNECTION; |
||||
} |
||||
} |
@ -0,0 +1,73 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
import com.fr.concurrent.NamedThreadFactory; |
||||
import com.fr.design.ui.util.UIUtil; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.lock.editlock.EditLockOperator; |
||||
import com.fr.report.LockItem; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/19 |
||||
* 判断当前设计器在远程设计服务器中的锁状态是否发生了改变 |
||||
*/ |
||||
public abstract class EditLockChangeChecker { |
||||
|
||||
private static final int INTERVAL = 30000; |
||||
private ScheduledExecutorService scheduler; |
||||
protected LockItem lockItem; |
||||
private boolean isLocked = false; |
||||
private List<EditLockChangeListener> listeners = new ArrayList<>(); |
||||
|
||||
/** |
||||
* 轮询任务,如果是远程设计状态,每隔30s查询一次相应lockItem的锁状态是否改变 |
||||
*/ |
||||
public void start() { |
||||
this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("EditLockChangeChecker")); |
||||
this.scheduler.scheduleAtFixedRate(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
// 判断是否为远程设计环境
|
||||
if (!WorkContext.getCurrent().isLocal()) { |
||||
try { |
||||
EditLockOperator operator = WorkContext.getCurrent().get(EditLockOperator.class); |
||||
boolean locked = operator.isLocked(lockItem); |
||||
if (isLocked != locked) { |
||||
isLocked = locked; |
||||
fireChange(); |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
||||
}, 0, INTERVAL, TimeUnit.MILLISECONDS); |
||||
} |
||||
|
||||
public void stop() { |
||||
this.scheduler.shutdown(); |
||||
} |
||||
|
||||
public void addEditLockChangeListener(EditLockChangeListener listener) { |
||||
this.listeners.add(listener); |
||||
} |
||||
|
||||
private void fireChange() { |
||||
UIUtil.invokeLaterIfNeeded(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
for (EditLockChangeListener listener : EditLockChangeChecker.this.listeners) { |
||||
listener.updateLockedState(new EditLockChangeEvent(isLocked)); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
import java.util.EventObject; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
*/ |
||||
public class EditLockChangeEvent extends EventObject { |
||||
|
||||
private boolean isLocked; |
||||
|
||||
/** |
||||
* @param source 锁状态发生了改变,且当前锁状态就是source |
||||
*/ |
||||
public EditLockChangeEvent(boolean source) { |
||||
super(source); |
||||
this.isLocked = source; |
||||
} |
||||
|
||||
public boolean isLocked() { |
||||
return isLocked; |
||||
} |
||||
} |
@ -0,0 +1,16 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
import java.util.EventListener; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
*/ |
||||
public interface EditLockChangeListener extends EventListener { |
||||
/** |
||||
* 锁定状态改变后执行的动作 |
||||
* @param event 事件 |
||||
*/ |
||||
void updateLockedState(EditLockChangeEvent event); |
||||
} |
@ -0,0 +1,79 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.base.svg.SVGLoader; |
||||
import com.fr.design.dialog.FineJOptionPane; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.server.lock.editlock.EditLockOperator; |
||||
import com.fr.report.LockItem; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import javax.swing.Icon; |
||||
import javax.swing.JOptionPane; |
||||
import java.awt.Image; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
* 关于编辑锁定的一些常量和静态方法 |
||||
*/ |
||||
public class EditLockUtils { |
||||
|
||||
/** |
||||
* 数据连接锁定标志 |
||||
*/ |
||||
public static final Icon CONNECTION_LOCKED_ICON = IconUtils.readIcon("/com/fr/design/images/m_web/connection_locked"); |
||||
|
||||
/** |
||||
* 小锁图片 |
||||
*/ |
||||
public static final @Nullable Image LOCKED_IMAGE = SVGLoader.load("/com/fr/design/images/m_web/locked_normal.svg"); |
||||
|
||||
/** |
||||
* 提示弹窗中的提示标志 |
||||
*/ |
||||
public static final Icon TOOLTIPS_ICON = IOUtils.readIcon("/com/fr/design/images/m_web/warningIcon.png"); |
||||
|
||||
/** |
||||
* 数据连接锁定中 |
||||
*/ |
||||
public static final String CONNECTION_LOCKED_TOOLTIPS = Toolkit.i18nText("Fine_Designer_Remote_Design_Data_Connection_Locked"); |
||||
|
||||
/** |
||||
* 服务器数据集锁定中 |
||||
*/ |
||||
public static final String SERVER_TABLEDATA_LOCKED_TOOLTIPS = Toolkit.i18nText("Fine_Designer_Remote_Design_Server_TableData_Locked"); |
||||
|
||||
/** |
||||
* 提示弹窗中的提示信息 |
||||
*/ |
||||
public static final String LOCKED_MESSAGE = Toolkit.i18nText("Fine_Designer_Remote_Design_Locked_Message"); |
||||
|
||||
/** |
||||
* 提示弹窗中的标题 |
||||
*/ |
||||
public static final String TOOLTIPS = Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Title_Hint"); |
||||
|
||||
/** |
||||
* 已经被锁,跳出弹窗提示 |
||||
*/ |
||||
public static void showLockMessage() { |
||||
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), EditLockUtils.LOCKED_MESSAGE, EditLockUtils.TOOLTIPS, JOptionPane.INFORMATION_MESSAGE, EditLockUtils.TOOLTIPS_ICON); |
||||
} |
||||
|
||||
public static boolean lock(LockItem lockItem) { |
||||
return WorkContext.getCurrent().get(EditLockOperator.class).lock(lockItem); |
||||
} |
||||
|
||||
public static boolean unlock(LockItem lockItem) { |
||||
return WorkContext.getCurrent().get(EditLockOperator.class).unlock(lockItem); |
||||
} |
||||
|
||||
public static boolean isLocked(LockItem lockItem) { |
||||
return WorkContext.getCurrent().get(EditLockOperator.class).isLocked(lockItem); |
||||
} |
||||
} |
@ -0,0 +1,23 @@
|
||||
package com.fr.design.editlock; |
||||
|
||||
import com.fr.report.LockItem; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
* 服务器数据集的checker |
||||
*/ |
||||
public class ServerTableDataLockChangeChecker extends EditLockChangeChecker{ |
||||
private static class Holder { |
||||
private static final ServerTableDataLockChangeChecker INSTANCE = new ServerTableDataLockChangeChecker(); |
||||
} |
||||
|
||||
public static ServerTableDataLockChangeChecker getInstance() { |
||||
return ServerTableDataLockChangeChecker.Holder.INSTANCE; |
||||
} |
||||
|
||||
public ServerTableDataLockChangeChecker() { |
||||
this.lockItem = LockItem.SERVER_TABLE_DATA; |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.design.file.filter; |
||||
|
||||
import com.fr.stable.Filter; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* 过滤无需遍历的jdk class
|
||||
* |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/7 |
||||
*/ |
||||
public class ClassFilter implements Filter<String> { |
||||
|
||||
|
||||
private static final Set<String> FILTER_SET = new HashSet<>(); |
||||
|
||||
private static final Filter<String> INSTANCE = new ClassFilter(); |
||||
|
||||
public static Filter<String> getInstance() { |
||||
return INSTANCE; |
||||
} |
||||
|
||||
static { |
||||
FILTER_SET.add("java.awt.image.BufferedImage"); |
||||
FILTER_SET.add("sun.awt.AppContext"); |
||||
} |
||||
|
||||
@Override |
||||
public boolean accept(String s) { |
||||
return FILTER_SET.contains(s); |
||||
} |
||||
} |
@ -0,0 +1,37 @@
|
||||
package com.fr.design.fun; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.stable.fun.mark.Mutable; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2020/12/30 |
||||
*/ |
||||
|
||||
public interface MobileParamUIProvider extends Mutable { |
||||
String XML_TAG = "MobileParamUIProvider"; |
||||
|
||||
int CURRENT_LEVEL = 1; |
||||
|
||||
|
||||
/** |
||||
* 扩展项的参数面板样式 |
||||
* @return |
||||
*/ |
||||
Class<? extends MobileParamStyle> classForMobileParamStyle(); |
||||
|
||||
/** |
||||
* 移动端参数面板中扩展项的面板 |
||||
* @return |
||||
*/ |
||||
Class<? extends BasicBeanPane<? extends MobileParamStyle>> classForMobileParamAppearance(); |
||||
|
||||
/** |
||||
* 扩展项的名称描述 |
||||
* @return |
||||
*/ |
||||
String displayName(); |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.design.fun.impl; |
||||
|
||||
import com.fr.design.fun.MobileParamUIProvider; |
||||
import com.fr.stable.fun.impl.AbstractProvider; |
||||
import com.fr.stable.fun.mark.API; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2020/12/30 |
||||
*/ |
||||
@API(level = MobileParamUIProvider.CURRENT_LEVEL) |
||||
public abstract class AbstractMobileParamUIProvider extends AbstractProvider implements MobileParamUIProvider { |
||||
|
||||
@Override |
||||
public int currentAPILevel() { |
||||
return CURRENT_LEVEL; |
||||
} |
||||
|
||||
@Override |
||||
public String mark4Provider() { |
||||
return getClass().getName(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.fr.design.gui.frpane; |
||||
|
||||
import com.fr.design.gui.ispinner.UISpinner; |
||||
import com.fr.design.gui.ispinner.chart.UISpinnerWithPercent; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2021-01-21 |
||||
*/ |
||||
public class UINumberDragPaneWithPercent extends UINumberDragPane { |
||||
|
||||
public UINumberDragPaneWithPercent(double minValue, double maxValue) { |
||||
super(minValue, maxValue); |
||||
} |
||||
|
||||
public UINumberDragPaneWithPercent(double minValue, double maxValue, double dierta) { |
||||
super(minValue, maxValue, dierta); |
||||
} |
||||
|
||||
protected UISpinner createUISpinner(double minValue, double maxValue, double dierta) { |
||||
return new UISpinnerWithPercent(minValue, maxValue, dierta, minValue); |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
package com.fr.design.gui.ibutton; |
||||
|
||||
import com.fr.design.editlock.EditLockChangeEvent; |
||||
import com.fr.design.editlock.EditLockChangeListener; |
||||
import com.fr.design.editlock.EditLockUtils; |
||||
import com.fr.report.LockItem; |
||||
|
||||
import javax.swing.Icon; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
*/ |
||||
public class UILockButton extends UIButton implements EditLockChangeListener { |
||||
|
||||
/** |
||||
* 锁定状态图标 |
||||
*/ |
||||
private Icon lockedIcon; |
||||
/** |
||||
* 正常状态图标 |
||||
*/ |
||||
private Icon normalIcon; |
||||
/** |
||||
* 锁定状态的提示信息 |
||||
*/ |
||||
private String lockedTooltips; |
||||
/** |
||||
* 正常状态的提示信息 |
||||
*/ |
||||
private String normalTooltips; |
||||
|
||||
public UILockButton(Icon lockedIcon, Icon normalIcon, String lockedTooltips, String normalTooltips) { |
||||
super(); |
||||
this.lockedIcon = lockedIcon; |
||||
this.normalIcon = normalIcon; |
||||
this.lockedTooltips = lockedTooltips; |
||||
this.normalTooltips = normalTooltips; |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
boolean locked = EditLockUtils.isLocked(LockItem.CONNECTION); |
||||
this.setIcon(locked ? lockedIcon : normalIcon); |
||||
this.setToolTipText(locked ? lockedTooltips : normalTooltips); |
||||
} |
||||
|
||||
@Override |
||||
public void updateLockedState(EditLockChangeEvent event) { |
||||
this.setIcon(event.isLocked() ? lockedIcon : normalIcon); |
||||
this.setToolTipText(event.isLocked() ? lockedTooltips : normalTooltips); |
||||
this.repaint(); |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
package com.fr.design.gui.imenu; |
||||
|
||||
import com.fr.design.editlock.EditLockChangeEvent; |
||||
import com.fr.design.editlock.EditLockChangeListener; |
||||
import com.fr.report.LockItem; |
||||
|
||||
import javax.swing.Action; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
*/ |
||||
public class UILockMenuItem extends UIMenuItem implements EditLockChangeListener { |
||||
|
||||
/** |
||||
* 锁定状态的提示信息 |
||||
*/ |
||||
private String lockedTooltips; |
||||
/** |
||||
* 正常状态的提示信息 |
||||
*/ |
||||
private String normalTooltips; |
||||
|
||||
/** |
||||
* 当前锁定项 |
||||
*/ |
||||
private LockItem lockItem; |
||||
|
||||
public UILockMenuItem(Action action, String lockedTooltips, String normalTooltips, LockItem lockItem) { |
||||
super(action); |
||||
this.lockedTooltips = lockedTooltips; |
||||
this.normalTooltips = normalTooltips; |
||||
this.lockItem = lockItem; |
||||
setUI(new UILockMenuItemUI()); |
||||
} |
||||
|
||||
public LockItem getLockItem() { |
||||
return lockItem; |
||||
} |
||||
|
||||
@Override |
||||
public void updateLockedState(EditLockChangeEvent event) { |
||||
this.setToolTipText(event.isLocked() ? lockedTooltips : normalTooltips); |
||||
this.repaint(); |
||||
} |
||||
} |
@ -0,0 +1,28 @@
|
||||
package com.fr.design.gui.imenu; |
||||
|
||||
import com.fr.design.editlock.EditLockUtils; |
||||
|
||||
import javax.swing.JMenuItem; |
||||
import java.awt.Graphics; |
||||
import java.awt.Rectangle; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2021/1/20 |
||||
*/ |
||||
public class UILockMenuItemUI extends UIMenuItemUI{ |
||||
|
||||
@Override |
||||
protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { |
||||
super.paintText(g, menuItem, textRect, text); |
||||
// 除了绘制text之外,还需要画一下锁定图标
|
||||
UILockMenuItem lockMenuItem = (UILockMenuItem) menuItem; |
||||
if (EditLockUtils.isLocked(lockMenuItem.getLockItem())) { |
||||
int width = menuItem.getWidth(); |
||||
int height = menuItem.getHeight(); |
||||
g.drawImage(EditLockUtils.LOCKED_IMAGE, (int) Math.round(width * 0.9), (int) Math.round(height * 0.1), 16, 16, null); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,15 @@
|
||||
package com.fr.design.gui.ispinner.chart; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2021-01-21 |
||||
*/ |
||||
public class UISpinnerWithPercent extends UISpinnerWithUnit { |
||||
|
||||
private static final String UNIT = "%"; |
||||
|
||||
public UISpinnerWithPercent(double minValue, double maxValue, double dierta, double defaultValue) { |
||||
super(minValue, maxValue, dierta, defaultValue, UNIT); |
||||
} |
||||
} |
@ -0,0 +1,20 @@
|
||||
package com.fr.design.gui.ispinner.chart; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2021-01-21 |
||||
*/ |
||||
public class UISpinnerWithPx extends UISpinnerWithUnit { |
||||
|
||||
private static final String UNIT = "px"; |
||||
|
||||
public UISpinnerWithPx(double defaultValue) { |
||||
this(0, Double.MAX_VALUE, 1, defaultValue); |
||||
} |
||||
|
||||
public UISpinnerWithPx(double minValue, double maxValue, double dierta, double defaultValue) { |
||||
super(minValue, maxValue, dierta, defaultValue, UNIT); |
||||
this.getTextField().canFillNegativeNumber(false); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package com.fr.design.gui.ispinner.chart; |
||||
|
||||
import com.fr.design.gui.ispinner.UISpinner; |
||||
import com.fr.design.gui.itextfield.UINumberField; |
||||
import com.fr.design.gui.itextfield.UINumberFieldWithUnit; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2021-01-20 |
||||
*/ |
||||
public class UISpinnerWithUnit extends UISpinner { |
||||
|
||||
private String unit; |
||||
|
||||
public UISpinnerWithUnit(double minValue, double maxValue, double dierta, double defaultValue, String unit) { |
||||
this.unit = unit; |
||||
init(minValue, maxValue, dierta); |
||||
getTextField().setValue(defaultValue); |
||||
} |
||||
|
||||
@Override |
||||
protected UINumberField initNumberField() { |
||||
return new UINumberFieldWithUnit(3, unit); |
||||
} |
||||
} |
@ -0,0 +1,114 @@
|
||||
package com.fr.design.gui.itextfield; |
||||
|
||||
import com.fr.base.Utils; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Comparator; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
import java.awt.Toolkit; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2021-01-20 |
||||
* 这个控件不会限制输入的数字大小,但是同样不允许输入数字之外的字符 |
||||
*/ |
||||
public class UINumberFieldWithUnit extends UINumberField { |
||||
|
||||
private String unit; |
||||
|
||||
private List<String> unitList = new ArrayList<>(); |
||||
|
||||
public UINumberFieldWithUnit(int columns, String unit) { |
||||
super(columns); |
||||
this.unit = unit; |
||||
initUnitList(); |
||||
} |
||||
|
||||
//对单位的字符进行组合
|
||||
private void initUnitList() { |
||||
char[] chars = unit.toCharArray(); |
||||
Set<String> set = new LinkedHashSet<>(); |
||||
initUnitList(chars, 0, StringUtils.EMPTY, set); |
||||
unitList.addAll(set); |
||||
Collections.sort(unitList, Comparator.comparing(String::length)); |
||||
} |
||||
|
||||
private void initUnitList(char[] chars, int index, String str, Set<String> set) { |
||||
if (index == chars.length) { |
||||
return; |
||||
} |
||||
for (int i = index; i < chars.length; i++) { |
||||
String newStr = str + chars[i]; |
||||
set.add(newStr); |
||||
initUnitList(chars, i + 1, newStr, set); |
||||
} |
||||
} |
||||
|
||||
public void setFieldDocument() { |
||||
setDocument(new NumberDocumentNoLimit()); |
||||
} |
||||
|
||||
public void setValue(double value) { |
||||
this.setText(Utils.doubleToString(value) + unit); |
||||
} |
||||
|
||||
public double getValue() throws NumberFormatException { |
||||
try { |
||||
String text = this.getText(); |
||||
if (StringUtils.isEmpty(text)) { |
||||
return 0; |
||||
} |
||||
|
||||
return Double.parseDouble(text.replace(getEndString(text), StringUtils.EMPTY)); |
||||
} catch (NumberFormatException numberFormatException) { |
||||
return UINumberField.ERROR_VALUE; |
||||
} |
||||
} |
||||
|
||||
private String getEndString(String text) { |
||||
int size = unitList.size(); |
||||
for (int i = size - 1; i >= 0; i--) { |
||||
String unit = unitList.get(i); |
||||
if (text.endsWith(unit)) { |
||||
return unit; |
||||
|
||||
} |
||||
} |
||||
return StringUtils.EMPTY; |
||||
} |
||||
|
||||
class NumberDocumentNoLimit extends NumberDocument { |
||||
|
||||
public boolean checkString(int offset, String s, String str) { |
||||
return (ComparatorUtils.equals(s, "F") |
||||
|| ComparatorUtils.equals(s, "f") |
||||
|| ComparatorUtils.equals(s, "D") |
||||
|| ComparatorUtils.equals(s, "d") |
||||
|| (ComparatorUtils.equals(s, ".") && getMaxDecimalLength() == 0)); |
||||
|
||||
} |
||||
|
||||
protected boolean isOverMaxOrMinValue(String strIntPart, String strDecPart, String strNew) { |
||||
return super.isOverMaxOrMinValue(strIntPart, strDecPart, strNew.replaceFirst(getEndString(strNew), StringUtils.EMPTY)); |
||||
} |
||||
|
||||
protected boolean checkNumber(String strValue, boolean isMinus) { |
||||
try { |
||||
if (ComparatorUtils.equals(strValue, StringUtils.EMPTY) || ComparatorUtils.equals(strValue, "-")) { |
||||
return false; |
||||
} |
||||
Double.parseDouble(strValue.replaceFirst(getEndString(strValue), StringUtils.EMPTY)); |
||||
} catch (Exception e) { |
||||
Toolkit.getDefaultToolkit().beep(); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
package com.fr.design.mainframe.mobile.provider; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.fun.impl.AbstractMobileParamUIProvider; |
||||
import com.fr.design.mainframe.mobile.ui.DefaultMobileParamDefinePane; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.form.ui.mobile.impl.DefaultMobileParameterStyle; |
||||
import com.fr.locale.InterProviderFactory; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class DefaultMobileParamUIProvider extends AbstractMobileParamUIProvider { |
||||
|
||||
@Override |
||||
public Class<? extends MobileParamStyle> classForMobileParamStyle() { |
||||
return DefaultMobileParameterStyle.class; |
||||
} |
||||
|
||||
@Override |
||||
public Class<? extends BasicBeanPane<MobileParamStyle>> classForMobileParamAppearance() { |
||||
return DefaultMobileParamDefinePane.class; |
||||
} |
||||
|
||||
@Override |
||||
public String displayName() { |
||||
return InterProviderFactory.getProvider().getLocText("Fine-Engine_Report_DEFAULT"); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,43 @@
|
||||
package com.fr.design.mainframe.mobile.provider; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.fun.impl.AbstractMobileParamUIProvider; |
||||
import com.fr.design.mainframe.mobile.ui.EmptyMobileParamDefinePane; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.report.fun.MobileParamStyleProvider; |
||||
import com.fr.report.mobile.EmptyMobileParamStyle; |
||||
|
||||
/** |
||||
* 作为MobileParamStyleProvider接口实现兼容转换层 |
||||
* |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class EmptyMobileParamUIProvider extends AbstractMobileParamUIProvider { |
||||
|
||||
private MobileParamStyleProvider styleProvider; |
||||
|
||||
public EmptyMobileParamUIProvider(MobileParamStyleProvider styleProvider) { |
||||
this.styleProvider = styleProvider; |
||||
} |
||||
|
||||
@Override |
||||
public Class<? extends MobileParamStyle> classForMobileParamStyle() { |
||||
return EmptyMobileParamStyle.class; |
||||
} |
||||
|
||||
@Override |
||||
public Class<? extends BasicBeanPane<MobileParamStyle>> classForMobileParamAppearance() { |
||||
return EmptyMobileParamDefinePane.class; |
||||
} |
||||
|
||||
@Override |
||||
public String displayName() { |
||||
return styleProvider.descriptor(); |
||||
} |
||||
|
||||
public MobileParamStyleProvider getStyleProvider() { |
||||
return styleProvider; |
||||
} |
||||
} |
@ -0,0 +1,42 @@
|
||||
package com.fr.design.mainframe.mobile.ui; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.form.ui.mobile.impl.DefaultMobileParameterStyle; |
||||
import java.awt.BorderLayout; |
||||
import javax.swing.JPanel; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class DefaultMobileParamDefinePane extends BasicBeanPane<MobileParamStyle> { |
||||
|
||||
public DefaultMobileParamDefinePane() { |
||||
initComponents(); |
||||
} |
||||
|
||||
private void initComponents() { |
||||
this.setLayout(new BorderLayout()); |
||||
JPanel centerPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Set")); |
||||
this.add(centerPane); |
||||
} |
||||
|
||||
@Override |
||||
public void populateBean(MobileParamStyle ob) { |
||||
// do nothing
|
||||
} |
||||
|
||||
@Override |
||||
public MobileParamStyle updateBean() { |
||||
return new DefaultMobileParameterStyle(); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
package com.fr.design.mainframe.mobile.ui; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.report.fun.MobileParamStyleProvider; |
||||
import com.fr.report.mobile.EmptyMobileParamStyle; |
||||
import java.awt.BorderLayout; |
||||
import javax.swing.JPanel; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class EmptyMobileParamDefinePane extends BasicBeanPane<MobileParamStyle> { |
||||
|
||||
private final MobileParamStyleProvider styleProvider; |
||||
|
||||
public EmptyMobileParamDefinePane(MobileParamStyleProvider styleProvider) { |
||||
this.styleProvider = styleProvider; |
||||
initComponents(); |
||||
} |
||||
|
||||
private void initComponents() { |
||||
this.setLayout(new BorderLayout()); |
||||
JPanel centerPane = FRGUIPaneFactory.createTitledBorderPane(Toolkit.i18nText("Fine-Design_Report_Set")); |
||||
this.add(centerPane); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void populateBean(MobileParamStyle ob) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public MobileParamStyle updateBean() { |
||||
return new EmptyMobileParamStyle(styleProvider); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
package com.fr.design.mainframe.mobile.ui; |
||||
|
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.fun.MobileParamUIProvider; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.mobile.provider.EmptyMobileParamUIProvider; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.invoke.Reflect; |
||||
import com.fr.report.mobile.EmptyMobileParamStyle; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class MobileParamDefinePane extends BasicBeanPane<MobileParamStyle> { |
||||
|
||||
private BasicBeanPane<MobileParamStyle> customBeanPane; |
||||
|
||||
public MobileParamDefinePane(MobileParamUIProvider provider) { |
||||
if (provider == null || provider.classForMobileParamAppearance() == null || provider.classForMobileParamAppearance() == null) { |
||||
return; |
||||
} |
||||
if (ComparatorUtils.equals(provider.classForMobileParamStyle(), EmptyMobileParamStyle.class)) { |
||||
EmptyMobileParamUIProvider emptyMobileParamUIProvider = (EmptyMobileParamUIProvider) provider; |
||||
this.customBeanPane = Reflect.on(provider.classForMobileParamAppearance()).create(emptyMobileParamUIProvider.getStyleProvider()).get(); |
||||
} else { |
||||
this.customBeanPane = Reflect.on(provider.classForMobileParamAppearance()).create().get(); |
||||
} |
||||
initComponents(); |
||||
} |
||||
|
||||
private void initComponents() { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
this.add(customBeanPane); |
||||
} |
||||
|
||||
@Override |
||||
public void populateBean(MobileParamStyle ob) { |
||||
this.customBeanPane.populateBean(ob); |
||||
} |
||||
|
||||
@Override |
||||
public MobileParamStyle updateBean() { |
||||
|
||||
return this.customBeanPane.updateBean(); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return "MobileParamDefinePane"; |
||||
} |
||||
} |
@ -0,0 +1,154 @@
|
||||
package com.fr.design.mainframe.mobile.ui; |
||||
|
||||
import com.fr.design.ExtraDesignClassManager; |
||||
import com.fr.design.beans.BasicBeanPane; |
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.fun.MobileParamUIProvider; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.mobile.provider.DefaultMobileParamUIProvider; |
||||
import com.fr.design.mainframe.mobile.provider.EmptyMobileParamUIProvider; |
||||
import com.fr.form.ui.container.WParameterLayout; |
||||
import com.fr.form.ui.mobile.MobileParamStyle; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.report.ExtraReportClassManager; |
||||
import com.fr.report.fun.MobileParamStyleProvider; |
||||
import com.fr.report.mobile.EmptyMobileParamStyle; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.CardLayout; |
||||
import java.awt.Component; |
||||
import java.awt.Dimension; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.stream.Collectors; |
||||
import javax.swing.DefaultListCellRenderer; |
||||
import javax.swing.DefaultListModel; |
||||
import javax.swing.JList; |
||||
import javax.swing.JPanel; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class MobileParamSettingPane extends BasicPane { |
||||
|
||||
private DefaultListModel<String> listModel; |
||||
private JPanel right; |
||||
private CardLayout card; |
||||
private JList paramStyleList; |
||||
|
||||
|
||||
private Map<String, BasicBeanPane<MobileParamStyle>> map = new HashMap<>(); |
||||
|
||||
|
||||
public MobileParamSettingPane() { |
||||
initComponents(); |
||||
} |
||||
|
||||
|
||||
private void initComponents() { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
listModel = new DefaultListModel<>(); |
||||
card = new CardLayout(); |
||||
right = FRGUIPaneFactory.createCardLayout_S_Pane(); |
||||
right.setLayout(card); |
||||
MobileParamUIProvider[] mobileParamUIProviders = getMobileParamUIProviders(); |
||||
for (MobileParamUIProvider provider : mobileParamUIProviders) { |
||||
addShowPane(provider); |
||||
} |
||||
initLeftPane(); |
||||
initRightPane(); |
||||
} |
||||
|
||||
private void initLeftPane() { |
||||
paramStyleList = new JList<>(listModel); |
||||
paramStyleList.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 MobileParamStyle) { |
||||
MobileParamStyle style = (MobileParamStyle) value; |
||||
this.setText(style.toString()); |
||||
} |
||||
return this; |
||||
} |
||||
}); |
||||
paramStyleList.addListSelectionListener(e -> { |
||||
String selectedValue = (String) paramStyleList.getSelectedValue(); |
||||
card.show(right, selectedValue); |
||||
}); |
||||
JPanel leftPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); |
||||
leftPane.add(paramStyleList); |
||||
leftPane.setPreferredSize(new Dimension(100, 500)); |
||||
this.add(leftPane, BorderLayout.WEST); |
||||
} |
||||
|
||||
private void initRightPane() { |
||||
JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); |
||||
JPanel attrConfPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
centerPane.setPreferredSize(new Dimension(500, 500)); |
||||
attrConfPane.add(right, BorderLayout.CENTER); |
||||
centerPane.add(attrConfPane, BorderLayout.CENTER); |
||||
this.add(centerPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
|
||||
public void populate(MobileParamStyle mobileParamStyle) { |
||||
if (mobileParamStyle != null) { |
||||
MobileParamUIProvider[] mobileParamUIProviders = getMobileParamUIProviders(); |
||||
for (int i = 0; i < mobileParamUIProviders.length; i++) { |
||||
MobileParamUIProvider provider = mobileParamUIProviders[i]; |
||||
if (ComparatorUtils.equals(mobileParamStyle.disPlayName(), provider.displayName())) { |
||||
String displayName = provider.displayName(); |
||||
paramStyleList.setSelectedIndex(i); |
||||
// 如果是兼容空类型 无须填充面板
|
||||
if (!(mobileParamStyle instanceof EmptyMobileParamStyle)) { |
||||
map.get(displayName).populateBean(mobileParamStyle); |
||||
} |
||||
card.show(right, displayName); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
paramStyleList.setSelectedIndex(0); |
||||
} |
||||
|
||||
private void addShowPane(MobileParamUIProvider provider) { |
||||
String displayName = provider.displayName(); |
||||
listModel.addElement(provider.displayName()); |
||||
BasicBeanPane<MobileParamStyle> paramStyleBasicBeanPane = new MobileParamDefinePane(provider); |
||||
right.add(displayName, paramStyleBasicBeanPane); |
||||
map.put(displayName, paramStyleBasicBeanPane); |
||||
} |
||||
|
||||
public MobileParamStyle update() { |
||||
return map.get(paramStyleList.getSelectedValue()).updateBean(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return null; |
||||
} |
||||
|
||||
private MobileParamUIProvider[] getMobileParamUIProviders() { |
||||
Set<MobileParamUIProvider> paramUIProviders = ExtraDesignClassManager.getInstance().getArray(MobileParamUIProvider.XML_TAG); |
||||
List<MobileParamUIProvider> result = new ArrayList<>(); |
||||
result.add(new DefaultMobileParamUIProvider()); |
||||
result.addAll(paramUIProviders); |
||||
Set<String> nameSets = paramUIProviders.stream().map(MobileParamUIProvider::displayName).collect(Collectors.toSet()); |
||||
// 兼容老接口
|
||||
Set<MobileParamStyleProvider> paramStyleProviders = ExtraReportClassManager.getInstance().getArray(MobileParamStyleProvider.MARK_STRING); |
||||
|
||||
paramStyleProviders = paramStyleProviders.stream().filter(provider -> !nameSets.contains(provider.descriptor())).collect(Collectors.toSet()); |
||||
|
||||
for (MobileParamStyleProvider provider : paramStyleProviders) { |
||||
result.add(new EmptyMobileParamUIProvider(provider)); |
||||
} |
||||
|
||||
return result.toArray(new MobileParamUIProvider[0]); |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.design.mainframe.widget.wrappers; |
||||
|
||||
import com.fr.design.Exception.ValidationException; |
||||
import com.fr.design.designer.properties.Decoder; |
||||
import com.fr.design.designer.properties.Encoder; |
||||
import com.fr.locale.InterProviderFactory; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
/** |
||||
* @author hades |
||||
* @version 10.0 |
||||
* Created by hades on 2021/1/4 |
||||
*/ |
||||
public class MobileParamWrapper implements Encoder, Decoder { |
||||
|
||||
@Nullable |
||||
@Override |
||||
public Object decode(String txt) { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public void validate(String txt) throws ValidationException { |
||||
// do nothing
|
||||
} |
||||
|
||||
@Override |
||||
public String encode(Object v) { |
||||
if (v == null) { |
||||
return InterProviderFactory.getProvider().getLocText("Fine-Engine_Report_DEFAULT"); |
||||
} |
||||
return v.toString(); |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue