帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

900 lines
21 KiB

/*
* Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved.
*/
package com.fr.design.designer.creator;
import com.fr.base.GraphHelper;
import com.fr.base.vcs.DesignerMode;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.actions.UpdateAction;
import com.fr.design.designer.beans.AdapterBus;
import com.fr.design.designer.beans.ComponentAdapter;
import com.fr.design.designer.beans.events.DesignerEditor;
import com.fr.design.designer.beans.models.SelectionModel;
import com.fr.design.designer.ui.PopupDialogContext;
import com.fr.design.designer.ui.SelectedPopupDialog;
import com.fr.design.fun.ShareWidgetUIProcessor;
import com.fr.design.fun.WidgetPropertyUIProvider;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.AuthorityPropertyPane;
import com.fr.design.mainframe.BaseJForm;
import com.fr.design.mainframe.CoverReportPane;
import com.fr.design.mainframe.EditingMouseListener;
import com.fr.design.mainframe.FormDesigner;
import com.fr.design.mainframe.NoSupportAuthorityEdit;
import com.fr.design.mainframe.WidgetPropertyPane;
import com.fr.design.mainframe.loghandler.LogMessageBar;
import com.fr.design.plugin.DesignerPluginContext;
import com.fr.design.utils.gui.LayoutUtils;
import com.fr.form.ui.Widget;
import com.fr.form.ui.container.WTitleLayout;
import com.fr.stable.Constants;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author richer
* @since 6.5.3 com.fr.base.listener.OB的设计组件
*
*/
public abstract class XCreator extends JPanel implements XComponent, XCreatorTools {
protected static final Border DEFALUTBORDER = BorderFactory.createLineBorder(new Color(210, 210, 210), 1);
public static final Dimension SMALL_PREFERRED_SIZE = new Dimension(80, 21);
protected static final Dimension MIDDLE_PREFERRED_SIZE = new Dimension(80, 50);
protected static final Dimension BIG_PREFERRED_SIZE = new Dimension(80, 80);
// barry: 拖拽控件时,控件要恢复原始大小,就先把控件当前大小备份到这里。
protected Dimension backupSize;
protected XLayoutContainer backupParent;
protected Widget data;
protected JComponent editor;
protected CoverReportPane coverPanel;
// XCreator加入到某些XLayoutContainer中时,能调整宽度或者高度
private int[] directions;
private Rectangle backupBound;
private String shareId = StringUtils.EMPTY;//如果组件是共享的会有这个属性
private boolean isHelpBtnOnFocus = false;//焦点是否在帮助按钮上
// 当前组件是否处在选中状态
private boolean selected;
private SelectedPopupDialog popup;
private static final int SHORTS_SEPARATOR_POS = 4; // 弹出菜单分割的位置
public XCreator(Widget ob, Dimension initSize) {
this.data = ob;
this.initEditor();
if (editor != null && editor != this) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
add(editor, BorderLayout.CENTER);
}
setInitSize(initSize);
this.setPreferredSize(initSize);
this.setSize(initSize);
this.setMaximumSize(initSize);
this.initXCreatorProperties();
}
public int[] getDirections() {
return directions;
}
public void setDirections(int[] directions) {
this.directions = directions;
}
/**
* 应用备份的大小
*/
public void useBackupSize() {
if (this.backupSize != null) {
setSize(this.backupSize);
}
}
/**
* 初始化组件大小
*/
public void setInitSize(Dimension initSize) {
if (initSize.width == 0) {
initSize.width = this.initEditorSize().width;
}
if (initSize.height == 0) {
initSize.height = this.initEditorSize().height;
}
}
/**
* 备份当前大小
*/
public void backupCurrentSize() {
this.backupSize = getSize();
}
public XLayoutContainer getBackupParent() {
return backupParent;
}
public void setBackupParent(XLayoutContainer backupContainer) {
this.backupParent = backupContainer;
}
/**
* 备份当前parent容器
*/
public void backupParent() {
setBackupParent(XCreatorUtils.getParentXLayoutContainer(this));
}
/**
* 获取当前布局控件的顶层布局框架,如tab布局、绝对布局
* @return 封装的顶层布局
*/
public XLayoutContainer getTopLayout(){
return null;
}
/**
* 获取当前XCreator的一个封装父容器
*
* @param widgetName 当前组件名
*
* @return 封装的父容器
*
*
* @date 2014-11-25-下午4:47:23
*
*/
protected XLayoutContainer getCreatorWrapper(String widgetName){
return new XWTitleLayout();
}
/**
* 将当前对象添加到父容器中
*
* @param parentPanel 父容器组件
*
*
* @date 2014-11-25-下午4:57:55
*
*/
protected void addToWrapper(XLayoutContainer parentPanel, int width, int minHeight){
parentPanel.add(this, WTitleLayout.BODY);
}
/**
* 设置父容器的名字
*
* @param parentPanel 当前父容器
* @param widgetName 当前控件名
*
*
* @date 2014-11-27-上午9:47:00
*
*/
protected void setWrapperName(XLayoutContainer parentPanel, String widgetName){
parentPanel.toData().setWidgetName(widgetName);
}
/**
* 初始化当前组件的父容器
* 大体分为三种: Scale缩放型, Title标题型, Border自定义标题栏
*
* @param minHeight 最小高度
*
* @return 父容器
*
*
* @date 2014-11-25-下午5:15:23
*
*/
public XLayoutContainer initCreatorWrapper(int minHeight){
XLayoutContainer parentPanel;
String widgetName = this.toData().getWidgetName();
parentPanel = this.getCreatorWrapper(widgetName);
int width = this.getWidth();
int height = this.getHeight();
parentPanel.setLocation(this.getX(), this.getY());
parentPanel.setSize(width, height);
setWrapperName(parentPanel, widgetName);
this.setLocation(0, 0);
this.addToWrapper(parentPanel, width, minHeight);
LayoutUtils.layoutRootContainer(parentPanel);
return parentPanel;
}
/**
* 初始化creator的属性值
*/
public void rebuid() {
initXCreatorProperties();
}
/**
* 返回组件属性值
* @return 返回组件属性值
* @throws IntrospectionException 异常
*/
public abstract CRPropertyDescriptor[] supportedDescriptor() throws IntrospectionException;
/**
* 生成creator对应的控件widget
* @return 控件widget
*/
public Widget toData() {
return this.data;
}
protected abstract JComponent initEditor();
/**
* 根据Widget的属性值初始化XCreator的属性值
*/
protected abstract void initXCreatorProperties();
/**
* 返回XCreator的默认大小80x21
* @return 默认的最小大小
*/
public Dimension initEditorSize() {
return SMALL_PREFERRED_SIZE;
}
protected String getIconName() {
return StringUtils.EMPTY;
}
public String getIconPath() {
return "/com/fr/web/images/form/resources/" + getIconName();
}
/**
* 返回组件默认名
* @return 组件类名(小写)
*/
public String createDefaultName() {
String name = this.getClass().getSimpleName();
return Character.toLowerCase(name.charAt(1)) + name.substring(2);
}
@Override
public void setBounds(Rectangle bounds) {
Dimension size = this.getMinimumSize();
if (bounds.getWidth() < size.width) {
bounds.width = size.width;
//针对拖动,不大好。
bounds.x = this.getX();
}
if (bounds.getHeight() < size.height) {
bounds.height = size.height;
bounds.y = this.getY();
}
super.setBounds(bounds);
}
public DesignerEditor<? extends JComponent> getDesignerEditor() {
return null;
}
/**
* 根据权限编辑工具界面
* @param jform 表单容器
*@param formEditor 设计界面组件
*@return 工具界面
*/
@Override
public JComponent createToolPane(BaseJForm jform, FormDesigner formEditor) {
if (!DesignerMode.isAuthorityEditing()) {
ShareWidgetUIProcessor exportProcessor = ExtraDesignClassManager.getInstance().getSingle(ShareWidgetUIProcessor.MARK_STRING);
if (exportProcessor != null) {
return exportProcessor.createToolPane(this, jform, formEditor);
}
if (isDedicateContainer() && this.getComponentCount() > 0) {
// 图表块和报表块由于控件树处不显示,但对应的属性表要显示,此处处理下
XCreator child = ((XLayoutContainer) this).getXCreator(0);
return child.createToolPane(jform, formEditor);
}
return WidgetPropertyPane.getInstance(formEditor);
} else {
//判断是不是布局,布局不支持权限编辑
if (formEditor.isSupportAuthority()) {
AuthorityPropertyPane authorityPropertyPane = new AuthorityPropertyPane(formEditor);
authorityPropertyPane.populate();
return authorityPropertyPane;
}
return new NoSupportAuthorityEdit();
}
}
@Override
public Dimension getMinimumSize() {
return new Dimension(0, 0);
}
/**
* 是否支持切换到报表界面编辑
* @return 是则返回true
*/
public boolean isReport(){
return false;
}
/**
* 该组件是否可以拖入参数面板
* @return 是则返回true
*/
public boolean canEnterIntoParaPane(){
return true;
}
/**
* 该组件是否可以拖入表单主体
* @return 是则返回true
*/
public boolean canEnterIntoAdaptPane(){
return true;
}
/**
* 该组件是否可以拖入绝对布局
* @return 是则返回true
*/
public boolean canEnterIntoAbsolutePane() {
return true;
}
/**
* 该组件是否可以拖拽(表单中参数面板和自适应布局不可以拖拽)
* @return 是则返回true
*/
public boolean isSupportDrag(){
return true;
}
public List<String> getAllXCreatorNameList(XCreator xCreator, List<String> namelist){
namelist.add(xCreator.toData().getWidgetName());
return namelist;
}
/**
* 是否有查询按钮
* @param xCreator 控件或容器
* @return 有无查询按钮
*/
public boolean SearchQueryCreators(XCreator xCreator) {
return false;
}
/**
* @return the backupBound
*/
public Rectangle getBackupBound() {
return backupBound;
}
/**
* @param rec the backupBound to set
*/
public void setBackupBound(Rectangle rec) {
this.backupBound = rec;
}
/**
* 控件树不显示此组件
* @param path 控件树list
*/
@Override
public void notShowInComponentTree(List<Component> path) {
return;
}
/**
* 获取其在控件树上可见父层
* @return 组件
*/
@Override
public Component getParentShow(){
return this.getParent();
}
/**
* 重置组件的名称
*
* @param name 名称
*/
@Override
public void resetCreatorName(String name) {
toData().setWidgetName(name);
}
/**
* 遍历所有命名相关的组件到集合中
*
* @param xCreators 集合
*/
public void traversalNameRelatedXCreators(Set<XCreator> xCreators) {
xCreators.add(this);
int componentCount = getComponentCount();
for (int i = 0; i < componentCount; i++) {
Component component = getComponent(i);
if (component instanceof XCreator) {
XCreator xCreator = (XCreator) component;
//获取真实的 creator
XCreator realCreator = xCreator.getXCreator();
realCreator.traversalNameRelatedXCreators(xCreators);
}
}
}
/**
* 重置组件的可见性
*
* @param visible 可见性
*/
public void resetVisible(boolean visible) {
toData().setVisible(visible);
}
/**
* 返回编辑的子组件,scale为其内部组件
* @return 组件
*/
@Override
public XCreator getEditingChildCreator() {
return this;
}
/**
* 返回对应属性表的组件,scale和title返回其子组件
* @return 组件
*/
@Override
public XCreator getPropertyDescriptorCreator() {
return this;
}
/**
* 更新子组件的Bound; 没有不处理
* @param minHeight 最小高度
*/
@Override
public void updateChildBound(int minHeight) {
return;
}
/**
* 是否作为控件树的叶子节点
* @return 是则返回true
*/
@Override
public boolean isComponentTreeLeaf() {
return true;
}
/**
* 是否为sclae和title专属容器
* @return 是则返回true
*/
@Override
public boolean isDedicateContainer() {
return false;
}
/**
* 是否接收这种类型
* @param acceptTypes 接收的类型
* @return 接收指定的类型则返回true,否则返回false
*/
public boolean acceptType(Class<?>... acceptTypes) {
for (Class<?> type : acceptTypes) {
if (StableUtils.objectInstanceOf(this, type)) {
return true;
}
}
return false;
}
/**
* 是否组件要缩放(自适应里部分组件需要, 如数字、文本、下拉框、下拉复选框、密码、下拉树、下拉复选树、日期)
*
* @return 是则返回true
*/
public boolean shouldScaleCreator() {
return false;
}
/**
* 是否支持标题样式
* @return 默认false
*/
public boolean hasTitleStyle() {
return false;
}
/**
* 响应点击事件
*
* @param editingMouseListener 鼠标点击,位置处理器
* @param e 鼠标点击事件
*/
public void respondClick(EditingMouseListener editingMouseListener,MouseEvent e){
FormDesigner designer = editingMouseListener.getDesigner();
SelectionModel selectionModel = editingMouseListener.getSelectionModel();
if (e.getClickCount() <= 1) {
selectionModel.selectACreatorAtMouseEvent(e);
}
editingMouseListener.refreshTopXCreator();
if (editingMouseListener.stopEditing() && this != designer.getRootComponent()) {
ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, this);
editingMouseListener.startEditing(this, adapter.getDesignerEditor(), adapter);
}
}
/**
* 删除相关组件
*
* @param creator 当前组件
* @param designer 表单设计器
*
*/
public void deleteRelatedComponent(XCreator creator,FormDesigner designer){
return;
}
/**
* 选择相关组件
*
* @param creator 当前组件
*
*/
public void seleteRelatedComponent(XCreator creator){
return;
}
/**
* 返回组件
* @return
* String
*/
public XCreator getXCreator(){
return this;
}
/**
* 按百分比调整组件
* @param percent 百分比
* void
*/
public void adjustCompSize(double percent){
return;
}
/**
* 返回一些需要的子组件
* @return 返回一些需要的子组件
* ArrayList<?>
*/
public ArrayList<?> getTargetChildrenList(){
return new ArrayList();
}
public XLayoutContainer getOuterLayout(){
return this.getBackupParent();
}
/**
* 重新调整子组件宽度
* @param width 宽度
* @param actualSize 是否按照实际大小计算
*/
public void recalculateChildWidth(int width, boolean actualSize){
return;
}
/**
* 重新调整子组件高度
* @param height 高度
* @param actualSize 是否按照实际大小计算
*/
public void recalculateChildHeight(int height, boolean actualSize){
return;
}
/**
* 是否支持定义移动端样式,默认true
* @return 是否支持定义移动端样式
*/
public boolean supportMobileStyle() {
return true;
}
/**
* 获取当前组件自定义的属性表tab
*
* @return 属性表tab数组
*/
public WidgetPropertyUIProvider[] getWidgetPropertyUIProviders() {
return new WidgetPropertyUIProvider[0];
}
/**
* 控件树面板中是否支持重命名选项
*
* @return 控件树面板中是否支持重命名选项
*/
public boolean supportRenameInWidgetTree() {
return true;
}
/**
* 组件是否是共享组件
* @return 是否是共享组件
*/
public boolean isShared() {
return StringUtils.isNotEmpty(shareId);
}
public void setShareId(String shareId) {
this.shareId = shareId;
if (coverPanel != null) {
coverPanel.setShared(isShared());
}
}
public String getShareId() {
return shareId;
}
/**
* 焦点是否在帮助按钮上
* @return 焦点是否在帮助按钮上
*/
public boolean isHelpBtnOnFocus() {
return isHelpBtnOnFocus;
}
public void setHelpBtnOnFocus(boolean isHelpBtnOnFocus) {
this.isHelpBtnOnFocus = isHelpBtnOnFocus;
}
public CoverReportPane getCoverPane(){
return coverPanel;
}
/**
* 是否展现覆盖的pane
* @param display 是否
*/
public void displayCoverPane(boolean display){
if (coverPanel != null) {
coverPanel.setVisible(display);
coverPanel.setPreferredSize(editor.getPreferredSize());
coverPanel.setBounds(new Rectangle(0, 0 , editor.getWidth(), editor.getHeight()));
editor.repaint();
}
}
/**
* 按照比例调整组件的宽度
* @param percent 比例
*/
public void adjustCompWidth(double percent){
return;
}
/**
* 按照比例调整组件的高度
* @param percent 比例
*/
public void adjustCompHeight(double percent) {
return;
}
/**
* 是否支持设置可见
* return boolean
*/
public boolean supportSetVisible(){
return true;
}
/**
* 是否支持设置可用
* return boolean
*/
public boolean supportSetEnable(){
return true;
}
/**
* 重新设置data
*
*/
public void resetData(Widget data){
this.data = data;
}
/**
* data属性改变触发其他操作
*
*/
public void firePropertyChange(){
// do nothing
}
/**
* 有的控件是有编辑状态的,给一个退出编辑的接口
*
*/
public void stopEditing() {
// do nothing
}
/**
* 编辑状态的时候需要重新绘制下边框
*
*/
public void paintBorder(Graphics g, Rectangle bounds){
GraphHelper.draw(g, bounds, Constants.LINE_MEDIUM);
}
/**
* 选中时右侧展示小弹窗
*
* @param designer
* @param bounds
*/
public void showSelectedPopup(FormDesigner designer, Rectangle bounds, boolean accept) {
if (popup == null) {
popup = new SelectedPopupDialog(this, designer);
}
PopupDialogContext.checkSelectedPop(this);
JFrame frame = LogMessageBar.getInstance().getLogFrame();
if (frame!= null && frame.isActive()) {
return;
}
int creatorRightX = (int) ((bounds.x + bounds.width + SelectedPopupDialog.OFFSET_X) * designer.getScale());
int creatorRightY = (int) (bounds.y * designer.getScale());
int formDesignerWidth = designer.getWidth();
int formDesignerHeight = designer.getHeight();
// 不超过可绘制区域
int extraX = creatorRightX < 0 ? 0 : Math.min(creatorRightX, formDesignerWidth);
int extraY = creatorRightY < 0 ? 0 : Math.min(creatorRightY, formDesignerHeight);
if (designer.isFormParaDesigner() && extraY + this.getHeight() >= formDesignerHeight) {
popup.setVisible(false);
return;
}
// 放到事件尾部执行
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
popup.setLocation(designer.getLocationOnScreen().x + designer.getPaintX() + extraX, designer.getLocationOnScreen().y + designer.getPaintY() + extraY);
popup.updatePane(designer);
boolean needShowing = selected && accept && popup.hasVisibleButtons() && popup.isCanVisible() && !isShowPluginDialog();
// 当不可见时,且可以设置为可见状态,才去设置为可见
// 避免已经是可见状态时,重复设置可见,造成闪屏
if (!popup.isVisible() && needShowing) {
popup.setVisible(true);
} else if (!needShowing) {
popup.setVisible(false);
}
popup.setRelativeBounds(bounds);
} catch (Exception ignored) {
}
}
});
}
private boolean isShowPluginDialog() {
if (DesignerPluginContext.getPluginDialog() == null) {
return false;
}
return DesignerPluginContext.getPluginDialog().isVisible();
}
/**
* 创建右击弹出菜单
*
*/
public UIPopupMenu createPopupMenu(FormDesigner formDesigner) {
UpdateAction[] actions = formDesigner.getActions();
UIPopupMenu popup = new UIPopupMenu();
for (int i = 0; i < actions.length; i++) {
if (i == SHORTS_SEPARATOR_POS) {
popup.addSeparator();
}
popup.add(actions[i].createMenuItem());
}
return popup;
}
/**
* 是否支持上移一层、下移一层等操作
*
*/
public boolean isMovable() {
return true;
}
/**
* 是否支持共享-现只支持报表块、图表、tab块、绝对布局
*/
public boolean isSupportShared() {
return false;
}
public boolean isTopable() {
return true;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
if (popup != null && !selected) {
popup.setVisible(false);
}
}
public void hidePopup() {
if (popup != null) {
popup.setVisible(false);
}
PopupDialogContext.checkSelectedPop(this);
}
public void processPopup(boolean canVisible) {
if (popup != null) {
popup.setCanVisible(canVisible);
}
}
public boolean isParentAbsolute() {
return ((XCreator) this.getParent()).acceptType(XWAbsoluteLayout.class);
}
public int getLevel() {
if (this.getParent() == null) {
return 1;
}
return ((XCreator) this.getParent()).getLevel() + 1;
}
}