* commit 'c6a4b0d75d211b5ddaa2d11015879c1d9e54b30b': (58 commits) REPORT-38529 && REPORT-38527 REPORT-38534 设计器界面中的剪切和复制按钮灰化不可用 1. bug原因:对于工具栏上的工具条combineUp,当处于编辑sheet的时候,是剪切+复制+粘贴+格式刷,其它情况都是剪切+复制+粘贴+删除,而带删除的这种,是会有两种状态,选中了某个组件时,剪切、复制、删除就都是可用的,未选中时,这几个都不可用,所以这里需要有个逻辑来切换这几个按钮的状态,而对于带格式刷的,不论有没有选中都会走到这个逻辑,然后被无脑置为不可用 2. 修改方案:添加一个判断,如果当前的状态是WORK_SHEET的时候,即编辑sheet时,直接返回,其它情况正常走逻辑 REPORT-38821 修改获得扩展路径的逻辑 REPORT-38645 【JDK11】设计器右上角,fs插件管理点击登录无反应 REPORT-38889 tomcat 8.5.x 请求参数带特殊字符问题 CHART-15362 属性切换保留功能开发 REPORT-38647 && REPORT-38357 REPORT-36985 改了一点代码 REPORT-38632【无用代码删除】设计器启动页 动态画面相关代码 REPORT-36985 删除无用依赖,格式化 REPORT-36985 删除无用依赖,格式化 KERNEL-4069 jdk11 macos的jdk里面移除了windows相关的LAF REPORT-36985 删除无用依赖 REPORT-36985 代码提交 组件树删除优化和选择组件时让其浮于顶层 REPORT-36985 代码提交 组件树删除优化和选择组件时让其浮于顶层 REPORT-37821 frm绝对布局框选多个组件有问题 合丢了 REPORT-36619 fix REPORT-36619 报表设计界面拖选无法选中拖选区域 REPORT-37915 报表分栏弹窗显示未适配国际化 1. 为每种语言都适配了报表分栏弹窗中的示例图片 2. 修改对应国际化文件中代表此示例图片的文件名 CHART-15451 国际化 ...research/10.0
@ -0,0 +1,106 @@
|
||||
package com.fr.design.gui.ipasswordfield; |
||||
|
||||
import com.fr.stable.StringUtils; |
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import javax.swing.text.Document; |
||||
import java.awt.event.KeyAdapter; |
||||
import java.awt.event.KeyEvent; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
* @version 10.0 |
||||
* Created by Yvan on 2020-08-11 |
||||
* 有固定长度的"*"回显的密码框,避免泄露密码长度 |
||||
*/ |
||||
public class UIPasswordFieldWithFixedLength extends UIPassWordField { |
||||
/** |
||||
* 展示密码,为固定8位长度的特殊字符"*"组成 |
||||
*/ |
||||
private static final String DISPLAY_PASSWORD = "********"; |
||||
|
||||
/** |
||||
* 实际密码 |
||||
*/ |
||||
private String realPassword; |
||||
|
||||
/** |
||||
* 用于判断是否清空密码 |
||||
*/ |
||||
private boolean clearPassword; |
||||
|
||||
public UIPasswordFieldWithFixedLength() { |
||||
this(null, null, 0); |
||||
} |
||||
|
||||
public UIPasswordFieldWithFixedLength(String text) { |
||||
this(null, text, 0); |
||||
} |
||||
|
||||
public UIPasswordFieldWithFixedLength(int columns) { |
||||
this(null, null, columns); |
||||
} |
||||
|
||||
public UIPasswordFieldWithFixedLength(String text, int columns) { |
||||
this(null, text, columns); |
||||
} |
||||
|
||||
public UIPasswordFieldWithFixedLength(Document doc, String txt, int columns) { |
||||
super(doc, txt, columns); |
||||
initRealPassword(txt); |
||||
} |
||||
|
||||
/** |
||||
* 为realPassword赋初值并添加一个鼠标单击事件 |
||||
*/ |
||||
public void initRealPassword(String text) { |
||||
this.realPassword = text == null ? StringUtils.EMPTY : text; |
||||
this.clearPassword = true; |
||||
addShowFixedLengthPasswordListener(); |
||||
} |
||||
|
||||
/** |
||||
* 当鼠标点击密码框,第一次做出键入动作时,清空显示密码与实际密码,用户需要重新输入密码 |
||||
*/ |
||||
private void addShowFixedLengthPasswordListener() { |
||||
this.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
UIPasswordFieldWithFixedLength.this.clearPassword = true; |
||||
} |
||||
}); |
||||
this.addKeyListener(new KeyAdapter() { |
||||
@Override |
||||
public void keyPressed(KeyEvent e) { |
||||
if (clearPassword) { |
||||
UIPasswordFieldWithFixedLength.this.setText(StringUtils.EMPTY); |
||||
UIPasswordFieldWithFixedLength.this.clearPassword = false; |
||||
UIPasswordFieldWithFixedLength.this.updateUI(); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void setText(@NotNull String t) { |
||||
this.realPassword = t; |
||||
// 看到代码中有些场景是将密码置为空字符串的,所以在这里加个判断
|
||||
if (StringUtils.isEmpty(t)) { |
||||
super.setText(t); |
||||
} else { |
||||
super.setText(DISPLAY_PASSWORD); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public char[] getPassword() { |
||||
//如果用户刚清空密码框,并输入了新密码,则返回输入内容,否则返回realPassword
|
||||
String text = new String(super.getPassword()); |
||||
if (!StringUtils.isEmpty(text) && StringUtils.isEmpty(realPassword)) { |
||||
return text.toCharArray(); |
||||
} |
||||
return realPassword.toCharArray(); |
||||
} |
||||
} |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 2.7 KiB |
@ -0,0 +1,69 @@
|
||||
package com.fr.design.chartx.data; |
||||
|
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.layout.TableLayout; |
||||
import com.fr.design.layout.TableLayoutHelper; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JComponent; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.SwingConstants; |
||||
import java.awt.Component; |
||||
import java.util.Arrays; |
||||
|
||||
/** |
||||
* @author shine |
||||
* @version 10.0 |
||||
* Created by shine on 2020/7/22 |
||||
*/ |
||||
public class DataLayoutHelper { |
||||
|
||||
public static int WIDTH = 150; |
||||
public static int LABEL_HEIGHT = 20; |
||||
public static int LABEL_WIDTH = 65; |
||||
|
||||
public static int LEFT_GAP = 15; |
||||
public static int RIGHT_GAP = 10; |
||||
|
||||
public static void setWIDTH(int WIDTH) { |
||||
DataLayoutHelper.WIDTH = WIDTH; |
||||
} |
||||
|
||||
public static void setLabelHeight(int labelHeight) { |
||||
LABEL_HEIGHT = labelHeight; |
||||
} |
||||
|
||||
public static void setLabelWidth(int labelWidth) { |
||||
LABEL_WIDTH = labelWidth; |
||||
} |
||||
|
||||
public static void setLeftGap(int leftGap) { |
||||
LEFT_GAP = leftGap; |
||||
} |
||||
|
||||
public static void setRightGap(int rightGap) { |
||||
RIGHT_GAP = rightGap; |
||||
} |
||||
|
||||
public static JPanel createDataLayoutPane(Component[][] components) { |
||||
int len = components.length; |
||||
double p = TableLayout.PREFERRED; |
||||
double[] columnSize = {DataLayoutHelper.LABEL_WIDTH, DataLayoutHelper.WIDTH}; |
||||
double[] rowSize = new double[len]; |
||||
Arrays.fill(rowSize, p); |
||||
|
||||
return TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize); |
||||
} |
||||
|
||||
public static JPanel createDataLayoutPane(String label, Component component) { |
||||
Component[][] components = new Component[][]{ |
||||
new Component[]{new UILabel(label, SwingConstants.LEFT), component} |
||||
}; |
||||
|
||||
return createDataLayoutPane(components); |
||||
} |
||||
|
||||
public static void addNormalBorder(JComponent component) { |
||||
component.setBorder(BorderFactory.createEmptyBorder(0, DataLayoutHelper.LEFT_GAP, 0, DataLayoutHelper.RIGHT_GAP)); |
||||
} |
||||
} |
@ -0,0 +1,88 @@
|
||||
package com.fr.van.chart.designer.type; |
||||
|
||||
import com.fr.chart.chartglyph.ConditionCollection; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.chart.PiePlot4VanChart; |
||||
import com.fr.plugin.chart.area.VanChartAreaPlot; |
||||
import com.fr.plugin.chart.attr.axis.VanChartAxis; |
||||
import com.fr.plugin.chart.attr.plot.VanChartPlot; |
||||
import com.fr.plugin.chart.attr.plot.VanChartRectanglePlot; |
||||
import com.fr.plugin.chart.bubble.VanChartBubblePlot; |
||||
import com.fr.plugin.chart.column.VanChartColumnPlot; |
||||
import com.fr.plugin.chart.line.VanChartLinePlot; |
||||
import com.fr.plugin.chart.scatter.VanChartScatterPlot; |
||||
import com.fr.plugin.chart.type.VanChartPlotType; |
||||
import com.fr.plugin.chart.vanchart.VanChart; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2020-08-24 |
||||
*/ |
||||
public abstract class AbstractRectanglePlotPane extends AbstractVanChartTypePane { |
||||
|
||||
private static Set<String> extendPlotIds = new HashSet<>(); |
||||
|
||||
static { |
||||
extendPlotIds.add(VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID); |
||||
extendPlotIds.add(VanChartColumnPlot.VAN_CHART_BAR_PLOT_ID); |
||||
extendPlotIds.add(VanChartLinePlot.VAN_CHART_LINE_PLOT); |
||||
extendPlotIds.add(VanChartAreaPlot.VAN_CHART_AREA_PLOT_ID); |
||||
extendPlotIds.add(VanChartScatterPlot.VAN_CHART_SCATTER_PLOT_ID); |
||||
extendPlotIds.add(PiePlot4VanChart.VAN_CHART_PIE_PLOT); |
||||
} |
||||
|
||||
@Override |
||||
protected VanChartPlot cloneOldPlot2New(VanChartPlot oldPlot, VanChartPlot newPlot) { |
||||
try { |
||||
VanChartRectanglePlot vanChartRectanglePlot = (VanChartRectanglePlot) newPlot; |
||||
VanChartRectanglePlot clonePlot = (VanChartRectanglePlot) oldPlot.clone(); |
||||
clonePlot.setVanChartPlotType(vanChartRectanglePlot.getVanChartPlotType()); |
||||
//自定义类型的图形要增加一个y2轴,并且增加系列中的堆积条件,反之则要去掉y2轴和条件
|
||||
if (clonePlot.isCustomChart()) { |
||||
List<VanChartAxis> valueAxisList = clonePlot.getValueAxisList(); |
||||
valueAxisList.add(vanChartRectanglePlot.getValueAxisList().get(1)); |
||||
clonePlot.setStackAndAxisCondition(vanChartRectanglePlot.getStackAndAxisCondition()); |
||||
} else { |
||||
List<VanChartAxis> xAxisList = clonePlot.getXAxisList(); |
||||
List<VanChartAxis> yAxisList = clonePlot.getYAxisList(); |
||||
List<VanChartAxis> newXAxisList = new ArrayList<>(); |
||||
List<VanChartAxis> newYAxisList = new ArrayList<>(); |
||||
newXAxisList.add(xAxisList.get(0)); |
||||
newYAxisList.add(yAxisList.get(0)); |
||||
clonePlot.setXAxisList(newXAxisList); |
||||
clonePlot.setYAxisList(newYAxisList); |
||||
clonePlot.setStackAndAxisCondition(new ConditionCollection()); |
||||
} |
||||
|
||||
//百分比堆积图值轴的格式不保留
|
||||
if (clonePlot.getVanChartPlotType() == VanChartPlotType.STACK_BY_PERCENT || |
||||
((VanChartRectanglePlot) oldPlot).getVanChartPlotType() == VanChartPlotType.STACK_BY_PERCENT) { |
||||
VanChartAxis cloneAxis = clonePlot.getValueAxisList().get(0); |
||||
VanChartAxis vanChartAxis = vanChartRectanglePlot.getValueAxisList().get(0); |
||||
cloneAxis.setFormat(vanChartAxis.getFormat()); |
||||
cloneAxis.setPercentage(vanChartAxis.isPercentage()); |
||||
} |
||||
return clonePlot; |
||||
} catch (CloneNotSupportedException ex) { |
||||
FineLoggerFactory.getLogger().error("Error in change plot"); |
||||
return newPlot; |
||||
} |
||||
} |
||||
|
||||
//是否支持属性的继承
|
||||
@Override |
||||
protected boolean supportExtendAttr(VanChart chart) { |
||||
if (StringUtils.equals(VanChartBubblePlot.VAN_CHART_BUBBLE_PLOT_ID, chart.getID())) { |
||||
VanChartBubblePlot vanChartBubblePlot = chart.getPlot(); |
||||
return !vanChartBubblePlot.isForceBubble(); |
||||
} |
||||
return extendPlotIds.contains(chart.getID()); |
||||
} |
||||
} |
@ -0,0 +1,36 @@
|
||||
package com.fr.van.chart.map.line; |
||||
|
||||
import com.fr.chart.chartattr.Plot; |
||||
import com.fr.design.gui.icheckbox.UICheckBox; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.plugin.chart.base.AttrTooltip; |
||||
import com.fr.van.chart.designer.style.VanChartStylePane; |
||||
|
||||
import java.awt.BorderLayout; |
||||
|
||||
/** |
||||
* @author Bjorn |
||||
* @version 10.0 |
||||
* Created by Bjorn on 2020-08-20 |
||||
*/ |
||||
public class VanChartLineMapPlotTooltipNoCheckPane extends VanChartLineMapPlotTooltipPane { |
||||
|
||||
public VanChartLineMapPlotTooltipNoCheckPane(Plot plot, VanChartStylePane parent) { |
||||
super(plot, parent); |
||||
} |
||||
|
||||
protected void addComponents(Plot plot) { |
||||
isTooltipShow = new UICheckBox(Toolkit.i18nText("Fine-Design_Chart_Use_Tooltip")); |
||||
tooltipPane = createTooltipPane(plot); |
||||
|
||||
this.setLayout(new BorderLayout()); |
||||
this.add(tooltipPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
@Override |
||||
public void populate(AttrTooltip attr) { |
||||
super.populate(attr); |
||||
isTooltipShow.setSelected(true); |
||||
tooltipPane.setEnabled(isTooltipShow.isSelected()); |
||||
} |
||||
} |
@ -0,0 +1,70 @@
|
||||
package com.fr.design.mainframe.widget.topxcreator; |
||||
|
||||
import com.fr.design.designer.creator.XCreator; |
||||
import com.fr.design.mainframe.FormDesigner; |
||||
import com.fr.design.mainframe.WidgetPropertyPane; |
||||
import com.fr.design.utils.ComponentUtils; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* @Author: Yuan.Wang |
||||
* @Date: 2020/8/31 |
||||
*/ |
||||
public class BasicTopXCreator extends JComponent { |
||||
private FormDesigner designer; |
||||
private XCreator creator; |
||||
|
||||
public BasicTopXCreator(XCreator creator) { |
||||
this.designer = WidgetPropertyPane.getInstance().getEditingFormDesigner(); |
||||
this.creator = creator; |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
setOpaque(false); |
||||
setBackground(null); |
||||
setLayout(null); |
||||
setBounds(calculateBounds()); |
||||
addComponent(); |
||||
} |
||||
|
||||
|
||||
//子类可能会重写该方法
|
||||
protected void resetSize(Rectangle bounds) { |
||||
//do nothing
|
||||
} |
||||
|
||||
protected void addComponent() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 重新设置组件大小 |
||||
* */ |
||||
public void resizeTopXCreator() { |
||||
Rectangle bounds=calculateBounds(); |
||||
setBounds(bounds); |
||||
resetSize(bounds); |
||||
} |
||||
|
||||
public void displayCoverPane(MouseEvent e, boolean visible) {} |
||||
|
||||
/** |
||||
* 计算显示大小 |
||||
* */ |
||||
private Rectangle calculateBounds() { |
||||
Rectangle rect = ComponentUtils.getRelativeBounds(creator); |
||||
Rectangle bounds = new Rectangle(0, 0, creator.getWidth(), creator.getHeight()); |
||||
bounds.x += (rect.x - designer.getHorizontalScaleValue()); |
||||
bounds.y += (rect.y - designer.getVerticalScaleValue()); |
||||
return bounds; |
||||
} |
||||
|
||||
@Override |
||||
public void paint(Graphics g) { |
||||
super.paint(g); |
||||
} |
||||
} |
@ -0,0 +1,49 @@
|
||||
package com.fr.design.mainframe.widget.topxcreator; |
||||
|
||||
import com.fr.design.designer.creator.XCreator; |
||||
import com.fr.design.mainframe.CoverReportPane; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* @Author: Yuan.Wang |
||||
* @Date: 2020/8/26 |
||||
*/ |
||||
public class TopXCreator extends BasicTopXCreator { |
||||
|
||||
private final CoverReportPane coverPanel; |
||||
|
||||
public TopXCreator(XCreator creator) { |
||||
super(creator); |
||||
coverPanel = new CoverReportPane(); |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
coverPanel.setSize(getSize()); |
||||
coverPanel.setVisible(false); |
||||
add(coverPanel); |
||||
} |
||||
|
||||
|
||||
protected void resetSize(Rectangle bounds) { |
||||
coverPanel.setSize(getSize()); |
||||
} |
||||
|
||||
/** |
||||
* 设置是否显示蒙层 |
||||
* */ |
||||
public void displayCoverPane(boolean visible) { |
||||
coverPanel.setVisible(visible); |
||||
} |
||||
|
||||
/** |
||||
* 依据鼠标事件和visible设置是否显示蒙层 |
||||
* */ |
||||
public void displayCoverPane(MouseEvent event, boolean visible) { |
||||
boolean isVisible = visible && getBounds().contains(event.getX(), event.getY()); |
||||
coverPanel.setVisible(isVisible); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,101 @@
|
||||
package com.fr.design.mainframe.widget.topxcreator; |
||||
|
||||
import com.fr.design.designer.beans.events.DesignerEvent; |
||||
import com.fr.design.designer.beans.models.SelectionModel; |
||||
import com.fr.design.designer.creator.XCreator; |
||||
import com.fr.design.mainframe.FormDesigner; |
||||
|
||||
import java.awt.event.MouseEvent; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
|
||||
|
||||
/** |
||||
* 需要显示顶层的组件层 |
||||
* |
||||
* @Author: Yuan.Wang |
||||
* @Date: 2020/8/25 |
||||
*/ |
||||
public class TopXCreators extends JComponent { |
||||
final private FormDesigner designer; |
||||
|
||||
public TopXCreators(FormDesigner designer) { |
||||
this.designer = designer; |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
setLayout(null); |
||||
setVisible(false); |
||||
setBackground(null); |
||||
setOpaque(false); |
||||
designer.addDesignerEditListener(e -> { |
||||
if (e.getCreatorEventID() == DesignerEvent.CREATOR_EDITED) { |
||||
refresh(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 选中的组件有变化时刷新 |
||||
*/ |
||||
public void refresh() { |
||||
removeAll(); |
||||
addXCreators(); |
||||
} |
||||
|
||||
@Override |
||||
public void paint(Graphics g) { |
||||
setSize(designer.getSize()); |
||||
resizeTopXCreators(); |
||||
super.paint(g); |
||||
} |
||||
|
||||
@Override |
||||
public void setVisible(boolean aFlag) { |
||||
super.setVisible(aFlag); |
||||
for (int i = 0, count = getComponentCount(); i < count; i++) { |
||||
if (getComponent(i) instanceof TopXCreator) { |
||||
TopXCreator xCreator = (TopXCreator) getComponent(i); |
||||
xCreator.displayCoverPane(aFlag); |
||||
} |
||||
} |
||||
repaint(); |
||||
} |
||||
|
||||
/** |
||||
* 依据MouseEvent坐标来设置是否显示蒙层 |
||||
*/ |
||||
public void displayCoverPane(MouseEvent e) { |
||||
for (int i = 0, count = getComponentCount(); i < count; i++) { |
||||
BasicTopXCreator xCreator = (BasicTopXCreator) getComponent(i); |
||||
xCreator.displayCoverPane(e, isVisible()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 加入被选择的组件 |
||||
*/ |
||||
private void addXCreators() { |
||||
SelectionModel selectionModel = designer.getSelectionModel(); |
||||
XCreator[] xCreators = selectionModel.getSelection().getSelectedCreators(); |
||||
for (XCreator creator : xCreators) { |
||||
BasicTopXCreator topXCreator = creator.getTopXCreator(); |
||||
if (topXCreator != null) { |
||||
add(topXCreator); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 更新顶层组件的位置和大小 |
||||
*/ |
||||
private void resizeTopXCreators() { |
||||
for (int i = 0, count = getComponentCount(); i < count; i++) { |
||||
BasicTopXCreator topXCreator = (BasicTopXCreator) getComponent(i); |
||||
topXCreator.resizeTopXCreator(); |
||||
} |
||||
repaint(); |
||||
} |
||||
} |
@ -0,0 +1,203 @@
|
||||
package com.fr.design.widget.ui.designer.mobile.component; |
||||
|
||||
import com.fr.design.constants.LayoutConstants; |
||||
import com.fr.design.designer.IntervalConstants; |
||||
import com.fr.design.designer.beans.events.DesignerEvent; |
||||
import com.fr.design.dialog.BasicPane; |
||||
import com.fr.design.gui.ibutton.ModeButtonGroup; |
||||
import com.fr.design.gui.ibutton.UIRadioButton; |
||||
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.TableLayout; |
||||
import com.fr.design.layout.TableLayoutHelper; |
||||
import com.fr.design.mainframe.WidgetPropertyPane; |
||||
import com.fr.design.style.color.NewColorSelectBox; |
||||
import com.fr.general.cardtag.mobile.MobileTemplateStyle; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.JComponent; |
||||
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.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
public class MobileTabCommonSettingPane extends BasicPane { |
||||
|
||||
private UICheckBox showTabTitleCheck; |
||||
private UICheckBox tabSlideCheck; |
||||
private UICheckBox showTabDotIndicatorCheck; |
||||
private ModeButtonGroup<Integer> buttonGroup; |
||||
private NewColorSelectBox initDotColorBox; |
||||
private NewColorSelectBox selectDotColorBox; |
||||
|
||||
public MobileTabCommonSettingPane() { |
||||
initComponent(); |
||||
} |
||||
|
||||
private void initComponent() { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
|
||||
this.showTabTitleCheck = new UICheckBox( |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Tab_Show_Title"), true) { |
||||
@Override |
||||
protected void initListener() { |
||||
this.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
attributeChange(); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
this.tabSlideCheck = new UICheckBox( |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Tab_Slide"), true) { |
||||
@Override |
||||
protected void initListener() { |
||||
this.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
attributeChange(); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
this.showTabDotIndicatorCheck = new UICheckBox( |
||||
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Tab_Show_Indicator"), true) { |
||||
@Override |
||||
protected void initListener() { |
||||
this.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
attributeChange(); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Tab_Show_Indicator_type")); |
||||
JPanel dotIndicatorShowTypePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); |
||||
addIndicatorShowTypeButton(dotIndicatorShowTypePane); |
||||
|
||||
UILabel initColorLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Init_Fill")); |
||||
UILabel selectColor = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Select_Fill")); |
||||
initDotColorBox = new NewColorSelectBox(0){ |
||||
@Override |
||||
protected void iniListener() { |
||||
} |
||||
|
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
super.mouseClicked(e); |
||||
this.attributeChange(); |
||||
} |
||||
}; |
||||
selectDotColorBox = new NewColorSelectBox(0){ |
||||
@Override |
||||
protected void iniListener() { |
||||
} |
||||
|
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
super.mouseClicked(e); |
||||
this.attributeChange(); |
||||
} |
||||
}; |
||||
JPanel initDotColorPane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{initColorLabel, initDotColorBox}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_MEDIUM); |
||||
JPanel selectDotColorPane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{selectColor, selectDotColorBox}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_MEDIUM); |
||||
|
||||
double[] rowSize = {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}; |
||||
double[] columnSize = {TableLayout.FILL}; |
||||
int[][] rowCount = {{1}, {1}, {1}}; |
||||
double[] verticalGaps = {10, 10, 10}; |
||||
double[] dotSettingColumnSize = {TableLayout.PREFERRED, TableLayout.FILL}; |
||||
|
||||
Component[][] components = new Component[][]{ |
||||
new Component[]{this.showTabTitleCheck}, |
||||
new Component[]{this.tabSlideCheck}, |
||||
new Component[]{this.showTabDotIndicatorCheck} |
||||
}; |
||||
|
||||
JPanel tabBaseConfigPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, |
||||
IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_L1); |
||||
tabBaseConfigPane.setBorder(BorderFactory.createEmptyBorder(0, 0, IntervalConstants.INTERVAL_L1, 0)); |
||||
|
||||
JPanel dotIndicatorSettingPanel = TableLayoutHelper.createDiffVGapTableLayoutPane(new JComponent[][]{ |
||||
{label, dotIndicatorShowTypePane}, |
||||
{initColorLabel, initDotColorPane}, |
||||
{selectColor, selectDotColorPane}}, rowSize, dotSettingColumnSize, 0, verticalGaps); |
||||
dotIndicatorSettingPanel.setBorder( |
||||
BorderFactory.createEmptyBorder(0, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1, 0) |
||||
); |
||||
|
||||
final JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
||||
jPanel.add(tabBaseConfigPane, BorderLayout.NORTH); |
||||
jPanel.add(dotIndicatorSettingPanel, BorderLayout.CENTER); |
||||
|
||||
this.add(jPanel, BorderLayout.CENTER); |
||||
|
||||
showTabDotIndicatorCheck.addChangeListener(new ChangeListener() { |
||||
@Override |
||||
public void stateChanged(ChangeEvent e) { |
||||
dotIndicatorSettingPanel.setVisible(showTabDotIndicatorCheck.isSelected()); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public void populate(MobileTemplateStyle mobileTemplateStyle) { |
||||
this.showTabTitleCheck.setSelected(mobileTemplateStyle.isShowTabTitle()); |
||||
this.showTabDotIndicatorCheck.setSelected(mobileTemplateStyle.isShowDotIndicator()); |
||||
this.tabSlideCheck.setSelected(mobileTemplateStyle.canSlide()); |
||||
Color initDotColor = mobileTemplateStyle.getIndicatorInitialColor(); |
||||
Color selectDotColor = mobileTemplateStyle.getIndicatorSelectColor(); |
||||
int dotIndicatorShowType = mobileTemplateStyle.getDotIndicatorShowType(); |
||||
this.populateColorBox(initDotColorBox, initDotColor, MobileTemplateStyle.DEFAULT_INITIAL_DOT_COLOR); |
||||
this.populateColorBox(selectDotColorBox, selectDotColor, MobileTemplateStyle.DEFAULT_SELECT_DOT_COLOR); |
||||
if (dotIndicatorShowType != buttonGroup.getCurrentSelected()) { |
||||
this.buttonGroup.setSelectButton(dotIndicatorShowType); |
||||
} |
||||
} |
||||
|
||||
public void update(MobileTemplateStyle mobileTemplateStyle) { |
||||
mobileTemplateStyle.setShowTabTitle(showTabTitleCheck.isSelected()); |
||||
mobileTemplateStyle.setShowDotIndicator(showTabDotIndicatorCheck.isSelected()); |
||||
mobileTemplateStyle.setCanSlide(tabSlideCheck.isSelected()); |
||||
mobileTemplateStyle.setIndicatorInitialColor(initDotColorBox.getSelectObject()); |
||||
mobileTemplateStyle.setIndicatorSelectColor(selectDotColorBox.getSelectObject()); |
||||
mobileTemplateStyle.setDotIndicatorShowType(buttonGroup.getCurrentSelected()); |
||||
WidgetPropertyPane.getInstance().getEditingFormDesigner().getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_EDITED); |
||||
} |
||||
|
||||
@Override |
||||
protected String title4PopupWindow() { |
||||
return "MobileTabCommonSettingPane"; |
||||
} |
||||
|
||||
private void addIndicatorShowTypeButton(JPanel dotIndicatorShowTypePane) { |
||||
UIRadioButton holderPlaceButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Mobile_Tab_Holder_Place")); |
||||
holderPlaceButton.setSelected(true); |
||||
UIRadioButton floatButton = new UIRadioButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Mobile_Tab_Float")); |
||||
dotIndicatorShowTypePane.add(holderPlaceButton); |
||||
dotIndicatorShowTypePane.add(floatButton); |
||||
dotIndicatorShowTypePane.setBorder( |
||||
BorderFactory.createEmptyBorder(0, IntervalConstants.INTERVAL_L1, 0, 0) |
||||
); |
||||
buttonGroup = new ModeButtonGroup<>(); |
||||
buttonGroup.put(MobileTemplateStyle.TYPE_PLACEHOLDER_DOT_INDICATOR, holderPlaceButton); |
||||
buttonGroup.put(MobileTemplateStyle.TYPE_FLOAT_DOT_INDICATOR, floatButton); |
||||
} |
||||
|
||||
private void populateColorBox(NewColorSelectBox colorBox, Color color, Color defaultColor) { |
||||
if (color == null) { |
||||
color = defaultColor; |
||||
} |
||||
if (color != colorBox.getSelectObject()) { |
||||
colorBox.setSelectObject(color); |
||||
} |
||||
} |
||||
} |
@ -1,208 +0,0 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.sun.imageio.plugins.gif.GIFImageReader; |
||||
import com.sun.imageio.plugins.gif.GIFImageReaderSpi; |
||||
import com.sun.javafx.tk.ImageLoader; |
||||
import com.sun.javafx.tk.PlatformImage; |
||||
import javafx.animation.KeyFrame; |
||||
import javafx.animation.Timeline; |
||||
import javafx.event.Event; |
||||
import javafx.event.EventHandler; |
||||
import javafx.scene.image.WritableImage; |
||||
import javafx.util.Duration; |
||||
|
||||
import javax.imageio.stream.FileImageInputStream; |
||||
import java.io.File; |
||||
import java.lang.ref.WeakReference; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
import java.lang.reflect.Method; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URI; |
||||
import java.net.URL; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* 边加载边播放的gif加载器 |
||||
* |
||||
* @author daniel |
||||
*/ |
||||
public class FastGifImage extends WritableImage { |
||||
private String url; |
||||
private int gifCount; |
||||
|
||||
public FastGifImage(String url, int w, int h) { |
||||
super(w, h); |
||||
this.url = validateUrl(url); |
||||
seekCount(); |
||||
initialize(); |
||||
} |
||||
|
||||
/** |
||||
* 给出gif帧数,加快加载速度 |
||||
* |
||||
* @param url gif url |
||||
* @param gifCount gif帧数 |
||||
* @param w 宽 |
||||
* @param h 高 |
||||
*/ |
||||
public FastGifImage(String url, int gifCount, int w, int h) { |
||||
super(w, h); |
||||
this.url = validateUrl(url); |
||||
this.gifCount = gifCount; |
||||
initialize(); |
||||
} |
||||
|
||||
private void seekCount() { |
||||
try { |
||||
GIFImageReaderSpi spi = new GIFImageReaderSpi(); |
||||
GIFImageReader gifReader = (GIFImageReader) spi.createReaderInstance(); |
||||
gifReader.setInput(new FileImageInputStream(new File(new URI(url)))); |
||||
gifCount = gifReader.getNumImages(true); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
private static final Pattern URL_QUICKMATCH = Pattern.compile("^\\p{Alpha}[\\p{Alnum}+.-]*:.*$"); |
||||
|
||||
private static String validateUrl(final String url) { |
||||
if (url == null) { |
||||
throw new NullPointerException("URL must not be null"); |
||||
} |
||||
|
||||
if (url.trim().isEmpty()) { |
||||
throw new IllegalArgumentException("URL must not be empty"); |
||||
} |
||||
|
||||
try { |
||||
if (!URL_QUICKMATCH.matcher(url).matches()) { |
||||
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); |
||||
URL resource; |
||||
if (url.charAt(0) == '/') { |
||||
resource = contextClassLoader.getResource(url.substring(1)); |
||||
} else { |
||||
resource = contextClassLoader.getResource(url); |
||||
} |
||||
if (resource == null) { |
||||
throw new IllegalArgumentException("Invalid URL or resource not found"); |
||||
} |
||||
return resource.toString(); |
||||
} |
||||
// Use URL constructor for validation
|
||||
return new URL(url).toString(); |
||||
} catch (final IllegalArgumentException e) { |
||||
throw new IllegalArgumentException("Invalid URL" + e.getMessage()); |
||||
} catch (final MalformedURLException e) { |
||||
throw new IllegalArgumentException("Invalid URL" + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
private void finishImage(ImageLoader loader) { |
||||
initializeAnimatedImage(loader); |
||||
} |
||||
|
||||
// Generates the animation Timeline for multiframe images.
|
||||
private void initializeAnimatedImage(ImageLoader loader) { |
||||
|
||||
animation = new Animation(this, loader); |
||||
animation.start(); |
||||
} |
||||
|
||||
// Support for animated images.
|
||||
private Animation animation; |
||||
|
||||
private static final class Animation { |
||||
final WeakReference<FastGifImage> imageRef; |
||||
final Timeline timeline; |
||||
private ImageLoader loader; |
||||
|
||||
public Animation(final FastGifImage image, final ImageLoader loader) { |
||||
this.loader = loader; |
||||
imageRef = new WeakReference<FastGifImage>(image); |
||||
timeline = new Timeline(); |
||||
timeline.setCycleCount(Timeline.INDEFINITE); |
||||
|
||||
final int frameCount = loader.getFrameCount(); |
||||
int duration = 0; |
||||
|
||||
for (int i = 0; i < frameCount; ++i) { |
||||
addKeyFrame(i, duration); |
||||
duration = duration + loader.getFrameDelay(i); |
||||
} |
||||
|
||||
// Note: we need one extra frame in the timeline to define how long
|
||||
// the last frame is shown, the wrap around is "instantaneous"
|
||||
addKeyFrame(0, duration); |
||||
} |
||||
|
||||
public void start() { |
||||
timeline.play(); |
||||
} |
||||
|
||||
public void stop() { |
||||
timeline.stop(); |
||||
loader = null; |
||||
} |
||||
|
||||
private void updateImage(final int frameIndex) { |
||||
final FastGifImage image = imageRef.get(); |
||||
if (image != null) { |
||||
image.setPlatformImagePropertyImpl( |
||||
loader.getFrame(frameIndex)); |
||||
} else { |
||||
timeline.stop(); |
||||
} |
||||
} |
||||
|
||||
private void addKeyFrame(final int index, final double duration) { |
||||
timeline.getKeyFrames().add( |
||||
new KeyFrame(Duration.millis(duration), |
||||
new EventHandler() { |
||||
@Override |
||||
public void handle(Event event) { |
||||
updateImage(index); |
||||
} |
||||
} |
||||
)); |
||||
} |
||||
} |
||||
|
||||
private static Method method; |
||||
|
||||
static { |
||||
try { |
||||
method = FastGifImage.class.getSuperclass().getSuperclass().getDeclaredMethod("platformImagePropertyImpl"); |
||||
method.setAccessible(true); |
||||
} catch (Exception e) { |
||||
|
||||
} |
||||
} |
||||
|
||||
private void setPlatformImagePropertyImpl(PlatformImage image) { |
||||
try { |
||||
Object o = method.invoke(this); |
||||
Method method = o.getClass().getDeclaredMethod("set", Object.class); |
||||
method.setAccessible(true); |
||||
method.invoke(o, image); |
||||
} catch (IllegalAccessException e) { |
||||
e.printStackTrace(); |
||||
} catch (InvocationTargetException e) { |
||||
e.printStackTrace(); |
||||
} catch (NoSuchMethodException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void initialize() { |
||||
finishImage(new PrismImageLoader2(url, gifCount, (int) getRequestedWidth(), (int) getRequestedHeight(), isPreserveRatio(), isSmooth())); |
||||
} |
||||
|
||||
/** |
||||
* 销毁gif动画 |
||||
*/ |
||||
public void destroy() { |
||||
animation.stop(); |
||||
} |
||||
|
||||
} |
@ -1,208 +0,0 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.fr.concurrent.NamedThreadFactory; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.sun.javafx.iio.ImageFrame; |
||||
import com.sun.javafx.iio.ImageLoadListener; |
||||
import com.sun.javafx.iio.ImageLoader; |
||||
import com.sun.javafx.iio.ImageMetadata; |
||||
import com.sun.javafx.iio.ImageStorageException; |
||||
import com.sun.javafx.iio.common.ImageTools; |
||||
import com.sun.javafx.iio.gif.GIFImageLoaderFactory; |
||||
import com.sun.javafx.tk.PlatformImage; |
||||
import com.sun.prism.Image; |
||||
import com.sun.prism.impl.PrismSettings; |
||||
|
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
|
||||
/** |
||||
* 边加载边播放的gif加载器 |
||||
* |
||||
* @author daniel |
||||
*/ |
||||
class PrismImageLoader2 implements com.sun.javafx.tk.ImageLoader { |
||||
|
||||
private Image[] images; |
||||
private int[] delayTimes; |
||||
private int width; |
||||
private int height; |
||||
private int gifCount = 1; |
||||
private Exception exception; |
||||
|
||||
public PrismImageLoader2(final String url, int gifCount, final int width, final int height, |
||||
final boolean preserveRatio, final boolean smooth) { |
||||
this.gifCount = gifCount; |
||||
images = new Image[gifCount]; |
||||
delayTimes = new int[gifCount]; |
||||
this.width = width; |
||||
this.height = height; |
||||
ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("PrismImageLoader2")); |
||||
es.execute(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
InputStream inputStream = null; |
||||
try { |
||||
inputStream = ImageTools.createInputStream(url); |
||||
loadAll(inputStream, width, height, preserveRatio, smooth); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} finally { |
||||
try { |
||||
if (inputStream != null) { |
||||
inputStream.close(); |
||||
} |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
es.shutdown(); |
||||
} |
||||
|
||||
@Override |
||||
public int getWidth() { |
||||
return width; |
||||
} |
||||
|
||||
@Override |
||||
public int getHeight() { |
||||
return height; |
||||
} |
||||
|
||||
@Override |
||||
public int getFrameCount() { |
||||
return gifCount; |
||||
} |
||||
|
||||
@Override |
||||
@SuppressWarnings("squid:S2142") |
||||
public PlatformImage getFrame(int index) { |
||||
while (images[index] == null) { |
||||
synchronized (this) { |
||||
if (images[index] == null) { |
||||
try { |
||||
this.wait(); |
||||
} catch (InterruptedException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return images[index]; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getFrameDelay(int index) { |
||||
// while (images[0] == null) {
|
||||
// synchronized (this) {
|
||||
// if(images[0] == null) {
|
||||
// try {
|
||||
// this.wait();
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
// return delayTimes[0];
|
||||
// 直接使用第一帧的时间
|
||||
return 40; |
||||
} |
||||
|
||||
@Override |
||||
public int getLoopCount() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public Exception getException() { |
||||
return exception; |
||||
} |
||||
|
||||
|
||||
@SuppressWarnings("squid:S244") |
||||
private void loadAll(InputStream stream, int w, int h, |
||||
boolean preserveRatio, boolean smooth) { |
||||
ImageLoadListener listener = new PrismLoadListener(); |
||||
|
||||
try { |
||||
ImageLoader loader = null; |
||||
loader = GIFImageLoaderFactory.getInstance().createImageLoader(stream); |
||||
loader.addListener(listener); |
||||
|
||||
for (int i = 0; i < gifCount; i++) { |
||||
ImageFrame imageFrame = loader.load(i, w, h, preserveRatio, smooth); |
||||
images[i] = convert(imageFrame); |
||||
synchronized (this) { |
||||
notifyAll(); |
||||
} |
||||
} |
||||
} catch (ImageStorageException e) { |
||||
handleException(e); |
||||
} catch (Exception e) { |
||||
handleException(e); |
||||
} |
||||
} |
||||
|
||||
private void handleException(final ImageStorageException isException) { |
||||
// unwrap ImageStorageException if possible
|
||||
final Throwable exceptionCause = isException.getCause(); |
||||
if (exceptionCause instanceof Exception) { |
||||
handleException((Exception) exceptionCause); |
||||
} else { |
||||
handleException((Exception) isException); |
||||
} |
||||
} |
||||
|
||||
private void handleException(final Exception exception) { |
||||
if (PrismSettings.verbose) { |
||||
exception.printStackTrace(System.err); |
||||
} |
||||
this.exception = exception; |
||||
} |
||||
|
||||
private Image convert(ImageFrame imgFrames) { |
||||
ImageFrame frame = imgFrames; |
||||
Image image = Image.convertImageFrame(frame); |
||||
ImageMetadata metadata = frame.getMetadata(); |
||||
if (metadata != null) { |
||||
Integer delay = metadata.delayTime; |
||||
if (delay != null) { |
||||
delayTimes[0] = delay.intValue(); |
||||
} |
||||
} |
||||
return image; |
||||
} |
||||
|
||||
|
||||
private class PrismLoadListener implements ImageLoadListener { |
||||
@Override |
||||
public void imageLoadWarning(ImageLoader loader, String message) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void imageLoadProgress(ImageLoader loader, |
||||
float percentageComplete) { |
||||
// progress only matters when backgroundLoading=true, but
|
||||
// currently we are relying on AbstractRemoteResource for tracking
|
||||
// progress of the InputStream, so there's no need to implement
|
||||
// this for now; eventually though we might want to consider
|
||||
// moving away from AbstractRemoteResource and instead use
|
||||
// the built-in support for progress in the javafx-iio library...
|
||||
} |
||||
|
||||
@Override |
||||
public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) { |
||||
// We currently have no need to listen for ImageMetadata ready.
|
||||
} |
||||
} |
||||
|
||||
} |