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.
381 lines
16 KiB
381 lines
16 KiB
package com.fr.design.mainframe; |
|
|
|
import com.fr.design.ExtraDesignClassManager; |
|
import com.fr.design.designer.beans.LayoutAdapter; |
|
import com.fr.design.designer.beans.adapters.layout.AbstractLayoutAdapter; |
|
import com.fr.design.designer.beans.adapters.layout.FRTabFitLayoutAdapter; |
|
import com.fr.design.designer.beans.events.DesignerEvent; |
|
import com.fr.design.designer.creator.XCreator; |
|
import com.fr.design.designer.creator.XCreatorUtils; |
|
import com.fr.design.designer.creator.XLayoutContainer; |
|
import com.fr.design.designer.creator.XWAbsoluteLayout; |
|
import com.fr.design.designer.creator.XWFitLayout; |
|
import com.fr.design.designer.creator.XWParameterLayout; |
|
import com.fr.design.designer.creator.XWScaleLayout; |
|
import com.fr.design.designer.creator.XWTitleLayout; |
|
import com.fr.design.designer.creator.cardlayout.XWTabFitLayout; |
|
import com.fr.design.fun.FormWidgetOptionProvider; |
|
import com.fr.design.utils.ComponentUtils; |
|
import com.fr.design.utils.gui.LayoutUtils; |
|
import com.fr.form.main.Form; |
|
import com.fr.form.ui.Widget; |
|
import com.fr.form.ui.container.WTitleLayout; |
|
import com.fr.general.ComparatorUtils; |
|
import com.fr.log.FineLoggerFactory; |
|
|
|
import java.awt.Component; |
|
import java.awt.Point; |
|
import java.awt.Rectangle; |
|
import java.awt.Toolkit; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.List; |
|
import java.util.Set; |
|
|
|
/** |
|
* 表单选中工具类 |
|
* |
|
* @author yaoh.wu |
|
* @version 2017年11月15日13点51分 |
|
* @since 8.0 |
|
*/ |
|
public class FormSelectionUtils { |
|
|
|
/** |
|
* 组件复制时坐标偏移 |
|
*/ |
|
private static final int DELAY_X_Y = 20; |
|
|
|
/** |
|
* 组件重命名后缀 |
|
*/ |
|
private static final String POSTFIX = "_c"; |
|
|
|
private static FormWidgetOptionProvider optionProvider; |
|
|
|
private FormSelectionUtils() { |
|
|
|
} |
|
|
|
/** |
|
* 粘贴到容器 |
|
*/ |
|
public static void paste2Container(FormDesigner designer, XLayoutContainer parent, |
|
FormSelection clipboard, int x, int y) { |
|
clipboard = filterFormSelection(clipboard, parent); |
|
if (clipboard.isEmpty()) { |
|
Toolkit.getDefaultToolkit().beep(); |
|
return; |
|
} |
|
LayoutAdapter adapter = parent.getLayoutAdapter(); |
|
if (parent instanceof XWAbsoluteLayout) { |
|
//绝对布局 |
|
absolutePaste(designer, clipboard, adapter, x, y); |
|
return; |
|
} else if (parent instanceof XWFitLayout) { |
|
//相对布局 |
|
relativePaste(designer, clipboard, adapter, x, y); |
|
return; |
|
} else if (isExtraContainer(parent)) { |
|
// 扩展布局 |
|
optionProvider.formWidgetPaste(clipboard, adapter, x, y); |
|
return; |
|
} |
|
Toolkit.getDefaultToolkit().beep(); |
|
} |
|
|
|
private static FormSelection filterFormSelection(FormSelection clipboard, XLayoutContainer parent) { |
|
for (XCreator xCreator : clipboard.getSelectedCreators()) { |
|
if (parent.acceptType(XWParameterLayout.class)) { |
|
if (!xCreator.canEnterIntoParaPane()) { |
|
clipboard.removeCreator(xCreator); |
|
} |
|
} else if (parent.acceptType(XWAbsoluteLayout.class)) { |
|
if (!xCreator.canEnterIntoAbsolutePane()) { |
|
clipboard.removeCreator(xCreator); |
|
} |
|
} else if (parent.acceptType(XWFitLayout.class)) { |
|
if (!xCreator.canEnterIntoAdaptPane()) { |
|
clipboard.removeCreator(xCreator); |
|
} |
|
} |
|
} |
|
return clipboard; |
|
} |
|
|
|
private static boolean isExtraContainer(XLayoutContainer parent) { |
|
if (parent != null) { |
|
Set<FormWidgetOptionProvider> set = ExtraDesignClassManager.getInstance().getArray(FormWidgetOptionProvider.XML_TAG); |
|
for (FormWidgetOptionProvider provider : set) { |
|
if (provider.isContainer() && ComparatorUtils.equals(provider.appearanceForWidget(), parent.getClass())) { |
|
optionProvider = provider; |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
public static void rebuildSelection(FormDesigner designer) { |
|
ArrayList<XCreator> newSelection = new ArrayList<>(); |
|
List<Widget> widgetList = new ArrayList<>(); |
|
for (XCreator comp : designer.getSelectionModel().getSelection().getSelectedCreators()) { |
|
widgetList.add(comp.toData()); |
|
} |
|
designer.getSelectionModel().setSelectedCreators( |
|
rebuildSelection(designer.getRootComponent(), widgetList, newSelection)); |
|
} |
|
|
|
public static ArrayList<XCreator> rebuildSelection(XCreator rootComponent, Widget[] selectWidgets) { |
|
List<Widget> selectionWidget = new ArrayList<>(); |
|
if (selectWidgets != null) { |
|
selectionWidget.addAll(Arrays.asList(selectWidgets)); |
|
} |
|
return FormSelectionUtils.rebuildSelection(rootComponent, selectionWidget, new ArrayList<XCreator>()); |
|
} |
|
|
|
/** |
|
* 绝对布局粘贴 |
|
*/ |
|
private static void absolutePaste(FormDesigner designer, FormSelection clipboard, LayoutAdapter adapter, int x, int y) { |
|
|
|
designer.getSelectionModel().getSelection().reset(); |
|
Rectangle rec = clipboard.getSelctionBounds(); |
|
boolean addSuccess = false; |
|
for (XCreator creator : clipboard.getSelectedCreators()) { |
|
try { |
|
XCreator copiedCreator = copyXcreator(designer.getTarget(), creator); |
|
// 获取位置 |
|
Point point = getPasteLocation((AbstractLayoutAdapter) adapter, |
|
copiedCreator, |
|
x + creator.getX() - rec.x + copiedCreator.getWidth() / 2, |
|
y + creator.getY() - rec.y + copiedCreator.getHeight() / 2); |
|
if (!adapter.accept(copiedCreator, point.x, point.y)) { |
|
designer.showMessageDialog(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Too_Large_To_Paste")); |
|
return; |
|
} |
|
resetTabSub2RealSize(copiedCreator); |
|
addSuccess = adapter.addBean(copiedCreator, point.x, point.y); |
|
if (addSuccess) { |
|
designer.getSelectionModel().getSelection().addSelectedCreator(copiedCreator); |
|
} |
|
} catch (CloneNotSupportedException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
if (!addSuccess) { |
|
rebuildSelection(designer); |
|
} |
|
designer.getEditListenerTable().fireCreatorModified( |
|
designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); |
|
|
|
} |
|
|
|
/** |
|
* REPORT-6096 复制得到的是显示的大小,如果因屏幕分辨率问题存在缩放的话,显示大小和实际大小会有区别,粘贴后tab内部调整大小时会再次缩放导致问题。 |
|
* 因此在粘贴之前将tab内部的组件调整成实际的大小。 |
|
* |
|
* @param copiedCreator 复制的组件 |
|
*/ |
|
private static void resetTabSub2RealSize(XCreator copiedCreator) { |
|
ArrayList<?> childrenList = copiedCreator.getTargetChildrenList(); |
|
if (!childrenList.isEmpty()) { |
|
for (Object aChildrenList : childrenList) { |
|
XWTabFitLayout tabLayout = (XWTabFitLayout) aChildrenList; |
|
Component[] components = tabLayout.getComponents(); |
|
for (Component component : components) { |
|
Rectangle show = component.getBounds(); |
|
component.setBounds(new Rectangle(show.x, show.y, show.width, show.height)); |
|
} |
|
} |
|
} |
|
Component[] components = copiedCreator.getComponents(); |
|
for (Component component : components) { |
|
try { |
|
resetTabSub2RealSize((XCreator) component); |
|
} catch (ClassCastException ignored) { |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* 相对布局粘贴 |
|
*/ |
|
private static void relativePaste(FormDesigner designer, FormSelection clipboard, LayoutAdapter adapter, int x, int y) { |
|
|
|
//@see FRTabFitLayoutAdapter |
|
Rectangle tabContainerRect = ComponentUtils.getRelativeBounds(designer.getSelectionModel().getSelection() |
|
.getSelectedCreator().getParent()); |
|
|
|
designer.getSelectionModel().getSelection().reset(); |
|
for (XCreator creator : clipboard.getSelectedCreators()) { |
|
if (creator instanceof XWScaleLayout) { |
|
//XWScaleLayout封装了在自适应布局中需要保持默认高度的控件,由于自适应粘贴时会再次包装,因此复制时要进行解包 |
|
Component[] innerComponents = creator.getComponents(); |
|
for (Component innerComponent : innerComponents) { |
|
XCreator innerXCreator = (XCreator) innerComponent; |
|
relativePasteXCreator(designer, innerXCreator, adapter, tabContainerRect, x, y); |
|
} |
|
} else { |
|
relativePasteXCreator(designer, creator, adapter, tabContainerRect, x, y); |
|
} |
|
} |
|
rebuildSelection(designer); |
|
designer.getEditListenerTable().fireCreatorModified( |
|
designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); |
|
} |
|
|
|
|
|
private static void relativePasteXCreator(FormDesigner designer, XCreator creator, LayoutAdapter adapter, Rectangle tabContainerRect, int x, int y) { |
|
try { |
|
XCreator copiedXCreator = copyXcreator(designer.getTarget(), creator); |
|
if (adapter.getClass().equals(FRTabFitLayoutAdapter.class)) { |
|
if (!adapter.accept(copiedXCreator, x - tabContainerRect.x, y - tabContainerRect.y)) { |
|
designer.showMessageDialog(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Too_Small_To_Paste")); |
|
return; |
|
} |
|
} else { |
|
if (!adapter.accept(copiedXCreator, x, y)) { |
|
designer.showMessageDialog(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Too_Small_To_Paste")); |
|
return; |
|
} |
|
} |
|
boolean addSuccess = adapter.addBean(copiedXCreator, x, y); |
|
if (addSuccess) { |
|
designer.getSelectionModel().getSelection().addSelectedCreator(copiedXCreator); |
|
} |
|
} catch (CloneNotSupportedException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
/** |
|
* 组件复用绝对布局获取粘贴组件位置 |
|
*/ |
|
private static Point getPasteLocation(AbstractLayoutAdapter layoutAdapter, XCreator copiedCreator, int x, int y) { |
|
//当宽度为奇数时 设置偏移 |
|
int xoffset = copiedCreator.getWidth() & 1; |
|
//当高度为奇数时 设置偏移 |
|
int yoffset = copiedCreator.getHeight() & 1; |
|
|
|
if (!layoutAdapter.accept(copiedCreator, x, y)) { |
|
XLayoutContainer container = layoutAdapter.getContainer(); |
|
boolean xOut = x < 0 || x + copiedCreator.getWidth() / 2 + xoffset > container.getWidth(); |
|
boolean yOut = y < 0 || y + copiedCreator.getHeight() / 2 + yoffset > container.getHeight(); |
|
|
|
boolean isEdge = (x - DELAY_X_Y == container.getWidth() - copiedCreator.getWidth() / 2 - xoffset) |
|
&& (y - DELAY_X_Y == container.getHeight() - copiedCreator.getHeight() / 2 - yoffset); |
|
|
|
y = yOut ? container.getHeight() - copiedCreator.getHeight() / 2 - yoffset : y; |
|
if (xOut) { |
|
if (isEdge) { |
|
//向左偏移 |
|
x = container.getWidth() - copiedCreator.getWidth() / 2 - DELAY_X_Y - xoffset; |
|
} |
|
//紧贴下边界 |
|
else { |
|
x = container.getWidth() - copiedCreator.getWidth() / 2 - xoffset; |
|
} |
|
} |
|
} |
|
return new Point(x, y); |
|
} |
|
|
|
/** |
|
* 拷贝组件 |
|
* @param form 当前表单 |
|
* @param xCreator 待拷贝的组件 |
|
* @return XCreator 拷贝的组件 |
|
*/ |
|
public static XCreator copyXcreator(Form form, XCreator xCreator) throws CloneNotSupportedException{ |
|
Widget copied = (Widget) xCreator.toData().clone(); |
|
XCreator copiedCreator = XCreatorUtils.createXCreator(copied, xCreator.getSize()); |
|
//主要用来处理组件间隔和padding,保证界面上展示的组件尺寸是计算过padding和组件间隔的 |
|
LayoutUtils.layoutContainer(copiedCreator); |
|
XCreatorUtils.traverAndAdjust(copiedCreator); |
|
ArrayList<String> nameSpace = new ArrayList<>(); |
|
copyWidgetName(form, nameSpace, copiedCreator); |
|
return copiedCreator; |
|
} |
|
|
|
|
|
/** |
|
* 拷贝组件 |
|
* @param form 当前表单 |
|
* @param nameSpace 命名空间 |
|
* @param xCreator 拷贝的组件 |
|
*/ |
|
private static void copyWidgetName(Form form, ArrayList<String> nameSpace, XCreator xCreator){ |
|
String copyName = FormSelectionUtils.getCopiedName(form, xCreator.toData(), nameSpace); |
|
if (xCreator.toData() instanceof WTitleLayout) { |
|
XWTitleLayout xwTitleLayout = new XWTitleLayout((WTitleLayout) xCreator.toData(), xCreator.getSize()); |
|
xwTitleLayout.resetCreatorName(copyName); |
|
return; |
|
} |
|
xCreator.resetCreatorName(copyName); |
|
int count = xCreator.getComponentCount(); |
|
for(int a = 0; a <count; a++){ |
|
if(xCreator.getComponent(a) instanceof XCreator){ |
|
XCreator child = (XCreator)xCreator.getComponent(a); |
|
copyWidgetName(form, nameSpace, child); |
|
} |
|
|
|
} |
|
} |
|
|
|
/** |
|
* 组件拷贝命名规则 |
|
*/ |
|
private static String getCopiedName(Form form, Widget copied, ArrayList<String> nameSpace) { |
|
StringBuilder name = new StringBuilder(copied.getWidgetName()); |
|
do { |
|
name.append(POSTFIX); |
|
} while (form.isNameExist(name.toString()) || nameSpace.contains(name.toString())); |
|
nameSpace.add(name.toString()); |
|
return name.toString(); |
|
} |
|
|
|
|
|
private static ArrayList<XCreator> rebuildSelection(XCreator rootComponent, List<Widget> selectionWidget, |
|
ArrayList<XCreator> newSelection) { |
|
FormSelectionUtils.rebuild(rootComponent, selectionWidget, newSelection); |
|
if (newSelection.isEmpty()) { |
|
newSelection.add(rootComponent); |
|
} |
|
return newSelection; |
|
} |
|
|
|
private static void rebuild(XCreator root, List<Widget> selectionWidget, List<XCreator> newSelection) { |
|
if (selectionWidget.isEmpty()) { |
|
return; |
|
} |
|
for (Widget x : selectionWidget) { |
|
if (ComparatorUtils.equals(x, root.toData())) { |
|
if (!newSelection.contains(root)) { |
|
newSelection.add(root); |
|
selectionWidget.remove(x); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
int count = root.getComponentCount(); |
|
for (int i = 0; i < count && !selectionWidget.isEmpty(); i++) { |
|
Component c = root.getComponent(i); |
|
if (c instanceof XCreator) { |
|
XCreator creator = (XCreator) c; |
|
for (Widget x : selectionWidget) { |
|
if (ComparatorUtils.equals(x, creator.toData())) { |
|
newSelection.add(creator); |
|
selectionWidget.remove(x); |
|
break; |
|
} |
|
} |
|
if (c instanceof XLayoutContainer) { |
|
rebuild((XLayoutContainer) c, selectionWidget, newSelection); |
|
} |
|
} |
|
} |
|
} |
|
} |