diff --git a/designer_base/src/com/fr/design/beans/location/MoveUtils.java b/designer_base/src/com/fr/design/beans/location/MoveUtils.java index f96782ba8e..da5b0fa970 100644 --- a/designer_base/src/com/fr/design/beans/location/MoveUtils.java +++ b/designer_base/src/com/fr/design/beans/location/MoveUtils.java @@ -1,544 +1,544 @@ -/* - * Copyright(c) 2001-2011, FineReport Inc, All Rights Reserved. - */ -package com.fr.design.beans.location; - -import javax.swing.*; -import java.awt.*; -import java.util.ArrayList; - -/** - * Created by IntelliJ IDEA. - * - * @author: Richer - * @since : 6.5.5 Date: 11-7-1 Time: 下午2:22 - */ -public class MoveUtils { - - public static final int SORPTION_UNIT = 5; - private static final int EQUIDISTANTLINE_UNIT = 4; - - public static ArrayList equidistantLines = new ArrayList<>(); - - private MoveUtils() { - - } - - public interface RectangleDesigner { - - /** - * 获取块边界的迭代器 - * - * @return 块边界的迭代器 - * @date 2015-2-12-下午2:43:47 - */ - RectangleIterator createRectangleIterator(); - - /** - * 设置X轴的线 - * - * @param line 连接线 - * @date 2015-2-12-下午2:44:04 - */ - void setXAbsorptionline(Absorptionline line); - - /** - * 设置Y轴的线 - * - * @param line 连接线 - * @date 2015-2-12-下午2:44:04 - */ - void setYAbsorptionline(Absorptionline line); - - /** - * 获取当前选中块的垂直线数组 - * - * @return 块的垂直线数组 - */ - int[] getVerticalLine(); - - /** - * 获取当前选中块的水平线数组 - * - * @return 块的水平线数组 - */ - int[] getHorizontalLine(); - - /** - * 设置designer内部组件是否重叠的标志位 - * - * @param isIntersects 是否重叠 - */ - void setWidgetsIntersected(boolean isIntersects); - - /** - * 获取designer内部组件是否重叠的标志位 - * - * @return 重叠 - */ - boolean isWidgetsIntersected(); - - /** - * 获取designer相对屏幕的位置 - * - * @return 位置 - */ - Point getDesignerLocationOnScreen(); - - /** - * 设置等距线 - * - * @param line 吸附线 - */ - void setEquidistantLine(Absorptionline line); - - /** - * 获取设计器垂直滚动条的值 - * - * @return 滚动条的值 - */ - int getDesignerScrollVerticalValue(); - - /** - * 获取设计器水平滚动条的值 - * - * @return 滚动条的值 - */ - int getDesignerScrollHorizontalValue(); - } - - public interface RectangleIterator { - - /** - * 是否存在下一个块 - * - * @return 是否存在下一个块 - * @date 2015-2-12-下午2:41:32 - */ - boolean hasNext(); - - /** - * 获取下一个块的bounds - * - * @return 下一个块的bounds - * @date 2015-2-12-下午2:41:55 - */ - Rectangle nextRectangle(); - - /** - * 获取块的垂直线数组 - * - * @return 块的垂直线数组 - * @date 2015-2-12-下午2:42:27 - */ - int[] getVerticalLine(); - - /** - * 获取块的水平线数组 - * - * @return 块的水平线数组 - * @date 2015-2-12-下午2:42:27 - */ - int[] getHorizontalLine(); - } - - private static class PlacePointing { - public PlacePointing(int x) { - this.palce = x; - } - - private boolean isFind() { - return direction != -1; - } - - private int palce; - private int direction = -1; - } - - private static void findX(PlacePointing px, Rectangle bounds, int left, int right, int width) { - if (px.isFind()) { - return; - } - if (Math.abs(bounds.x + bounds.width / 2 - (left + right) / 2) <= SORPTION_UNIT) { - px.palce = bounds.x + bounds.width / 2 - width / 2; - px.direction = SwingConstants.CENTER; - } - int x1 = bounds.x; - if (Math.abs(x1 - left) <= SORPTION_UNIT) { - px.palce = x1; - px.direction = SwingConstants.LEFT; - } - if (Math.abs(x1 - right) <= SORPTION_UNIT) { - px.palce = x1 - width; - px.direction = SwingConstants.RIGHT; - } - int x2 = bounds.x + bounds.width; - if (Math.abs(x2 - left) <= SORPTION_UNIT) { - px.palce = x2; - px.direction = SwingConstants.LEFT; - } - if (Math.abs(x2 - right) <= SORPTION_UNIT) { - px.palce = x2 - width; - px.direction = SwingConstants.RIGHT; - } - if (Math.abs(bounds.x + bounds.width / 2 - left) <= SORPTION_UNIT) { - px.palce = bounds.x + bounds.width / 2; - px.direction = SwingConstants.LEFT; - } - if (Math.abs(bounds.x + bounds.width / 2 - right) <= SORPTION_UNIT) { - px.palce = bounds.x + bounds.width / 2 - width; - px.direction = SwingConstants.RIGHT; - } - } - - private static void findY(PlacePointing py, Rectangle bounds, int top, int bottom, int height) { - if (py.isFind()) { - return; - } - - if (Math.abs(bounds.y + bounds.height / 2 - (top + bottom) / 2) <= SORPTION_UNIT) { - py.palce = bounds.y + bounds.height / 2 - height / 2; - py.direction = SwingConstants.CENTER; - } - int y1 = bounds.y; - if (Math.abs(y1 - top) <= SORPTION_UNIT) { - py.palce = y1; - py.direction = SwingConstants.TOP; - } - if (Math.abs(y1 - bottom) <= SORPTION_UNIT) { - py.palce = y1 - height; - py.direction = SwingConstants.BOTTOM; - } - int y2 = bounds.y + bounds.height; - if (Math.abs(y2 - top) <= SORPTION_UNIT) { - py.palce = y2; - py.direction = SwingConstants.TOP; - } - if (Math.abs(y2 - bottom) <= SORPTION_UNIT) { - py.palce = y2 - height; - py.direction = SwingConstants.BOTTOM; - } - if (Math.abs(bounds.y + bounds.height / 2 - top) <= SORPTION_UNIT) { - py.palce = bounds.y + bounds.height / 2; - py.direction = SwingConstants.TOP; - } - if (Math.abs(bounds.y + bounds.height / 2 - bottom) <= SORPTION_UNIT) { - py.palce = bounds.y + bounds.height / 2 - height; - py.direction = SwingConstants.BOTTOM; - } - } - - private static void findEquidistantLine(Rectangle bounds, int left, int top, int height, int width) { - //最近的距离与坐标 - EquidistantLine equidistantLineInfo = new EquidistantLine(0, 0, 0); - //等距线从各边中点画出,先要判断是不是在范围内 - int topMiddleX = left + width / 2; - int leftMiddleY = top + height / 2; - if ((topMiddleX > bounds.getX()) && (topMiddleX < (bounds.getX() + bounds.getWidth()))) { - //当前操作rec在bounds的下方 - if (top > (bounds.getY() + bounds.getHeight())) { - equidistantLineInfo.setDistance(top - (bounds.y + bounds.height)); - equidistantLineInfo.setReference(bounds.y + bounds.height); - equidistantLineInfo.setDirection(SwingConstants.TOP); - } - //当前操作rec在bounds上方 - if ((top + height) < bounds.getY()) { - equidistantLineInfo.setDistance(bounds.y - (top + height)); - equidistantLineInfo.setReference(bounds.y); - equidistantLineInfo.setDirection(SwingConstants.BOTTOM); - } - } else if ((leftMiddleY > bounds.getY()) && (leftMiddleY < (bounds.getY() + bounds.getHeight()))) { - //当前操作rec在bounds的右侧 - if (left > (bounds.getX() + bounds.getWidth())) { - equidistantLineInfo.setDistance(left - (bounds.x + bounds.width)); - equidistantLineInfo.setReference(bounds.x + bounds.width); - equidistantLineInfo.setDirection(SwingConstants.LEFT); - } - //当前操作rec在bounds的左侧 - if ((left + width) < bounds.getX()) { - equidistantLineInfo.setDistance(bounds.x - (left + width)); - equidistantLineInfo.setReference(bounds.x); - equidistantLineInfo.setDirection(SwingConstants.RIGHT); - } - } - if (equidistantLineInfo.getDistance() > 0) { - equidistantLines.add(equidistantLineInfo); - } - } - - - /** - * 吸附 - * - * @param x x坐标 - * @param y y坐标 - * @param width 宽度 - * @param height 高度 - * @param designer 块设计器 - * @return 吸附后坐标 - * @date 2015-2-12-下午2:39:16 - */ - public static Point sorption(int x, int y, int width, int height, RectangleDesigner designer, boolean isParameterLayout) { - - int left = x, top = y, bottom = top + height, right = left + width; - - Rectangle operatingRectangle = new Rectangle(x, y, width, height); - - equidistantLines.clear(); - - PlacePointing px = new PlacePointing(x); - PlacePointing py = new PlacePointing(y); - - PlacePointing pEquidistantX = new PlacePointing(x); - PlacePointing pEquidistantY = new PlacePointing(y); - - RectangleIterator iterator = designer.createRectangleIterator(); - - java.util.List cacheRecs = new ArrayList(); - while (iterator.hasNext()) { - Rectangle bounds = iterator.nextRectangle(); - cacheRecs.add(bounds); - findX(px, bounds, left, right, width); - findY(py, bounds, top, bottom, height); - - if (!isParameterLayout) { - findEquidistantLine(bounds, left, top, height, width); - } - } - - createXAbsorptionline(px, designer, width, cacheRecs); - createYAbsorptionline(py, designer, height, cacheRecs); - operatingRectangle.x = px.palce; - operatingRectangle.y = py.palce; - createEquidistantLine(pEquidistantX, pEquidistantY, operatingRectangle, designer); - Point sorptionPoint = new Point(px.palce, py.palce); - if (!px.isFind()) { - sorptionPoint.x = pEquidistantX.palce; - } - if (!py.isFind()) { - sorptionPoint.y = pEquidistantY.palce; - } - return sorptionPoint; - } - - - private static void createXAbsorptionline(PlacePointing px, RectangleDesigner designer, int width, java.util.List cacheRecs) { - Absorptionline line = null; - RectangleIterator iterator = designer.createRectangleIterator(); - int[] selfVertical = designer.getVerticalLine(); - if (px.direction == SwingConstants.CENTER) { - line = Absorptionline.createXMidAbsorptionline(px.palce + width / 2); - int left = px.palce; - int right = px.palce + width; - for (Rectangle bounds : cacheRecs) { - if (bounds.x == left || bounds.x + bounds.width == left) { - line.setFirstLine(left); - } - if (bounds.x == right || bounds.x + bounds.width == right) { - line.setSecondLine(right); - } - updateVerticalLine(selfVertical, iterator, line); - if (line.isFull()) { - break; - } - } - } else if (px.direction == SwingConstants.LEFT || px.direction == SwingConstants.RIGHT) { - int left = px.direction == SwingConstants.LEFT ? px.palce + width : px.palce; - line = Absorptionline.createXAbsorptionline(px.direction == SwingConstants.LEFT ? px.palce : px.palce + width); - int middle = px.palce + width / 2; - for (Rectangle bounds : cacheRecs) { - if (bounds.x == left || bounds.x + bounds.width == left) { - line.setSecondLine(left); - } - if (bounds.x + bounds.width / 2 == middle) { - line.setMidLine(middle); - } - updateVerticalLine(selfVertical, iterator, line); - if (line.isFull()) { - break; - } - } - } - designer.setXAbsorptionline(line); - } - - private static void createYAbsorptionline(PlacePointing py, RectangleDesigner designer, int height, java.util.List cacheRecs) { - Absorptionline line = null; - RectangleIterator iterator = designer.createRectangleIterator(); - int[] selfHorizontal = designer.getHorizontalLine(); - if (py.direction == SwingConstants.CENTER) { - line = Absorptionline.createYMidAbsorptionline(py.palce + height / 2); - int top = py.palce; - int bottom = py.palce + height; - for (Rectangle bounds : cacheRecs) { - if (bounds.y == top || bounds.y + bounds.height == top) { - line.setFirstLine(top); - } - if (bounds.y == bottom || bounds.y + bounds.height == bottom) { - line.setSecondLine(bottom); - } - updateHorizontalLine(selfHorizontal, iterator, line); - if (line.isFull()) { - break; - } - } - } else if (py.direction == SwingConstants.TOP || py.direction == SwingConstants.BOTTOM) { - int top = py.direction == SwingConstants.TOP ? py.palce + height : py.palce; - line = Absorptionline.createYAbsorptionline(py.direction == SwingConstants.TOP ? py.palce : py.palce + height); - int middle = py.palce + height / 2; - for (Rectangle bounds : cacheRecs) { - if (bounds.y == top || bounds.y + bounds.height == top) { - line.setSecondLine(top); - } - if (bounds.y + bounds.height / 2 == middle) { - line.setMidLine(middle); - } - updateHorizontalLine(selfHorizontal, iterator, line); - if (line.isFull()) { - break; - } - } - } - designer.setYAbsorptionline(line); - } - - private static void createEquidistantLine(PlacePointing px, PlacePointing py, Rectangle operatingRectangle, RectangleDesigner designer) { - processEquidistantLinesList(px, py, operatingRectangle); - Absorptionline line = null; - if (equidistantLines.size() > 0) { - int top = -1; - int left = -1; - int bottom = -1; - int right = -1; - for (int i = 0; i < equidistantLines.size(); i++) { - if (equidistantLines.get(i).getDirection() == SwingConstants.TOP) { - top = equidistantLines.get(i).getReference(); - } - if (equidistantLines.get(i).getDirection() == SwingConstants.LEFT) { - left = equidistantLines.get(i).getReference(); - } - if (equidistantLines.get(i).getDirection() == SwingConstants.BOTTOM) { - bottom = equidistantLines.get(i).getReference(); - } - if (equidistantLines.get(i).getDirection() == SwingConstants.RIGHT) { - right = equidistantLines.get(i).getReference(); - } - } - operatingRectangle.x -= designer.getDesignerScrollHorizontalValue(); - operatingRectangle.y -= designer.getDesignerScrollVerticalValue(); - line = Absorptionline.createEquidistantAbsorptionline(operatingRectangle, - top - designer.getDesignerScrollVerticalValue(), - left - designer.getDesignerScrollHorizontalValue(), - bottom - designer.getDesignerScrollVerticalValue(), - right - designer.getDesignerScrollHorizontalValue()); - } - designer.setEquidistantLine(line); - } - - private static void processEquidistantLinesList(PlacePointing pEquidistantX, PlacePointing pEquidistantY, Rectangle operatingRectangle) { - EquidistantLine[] equidistantLines1 = new EquidistantLine[EQUIDISTANTLINE_UNIT]; - //先按方向处理,只保留四个方向上距离最近 - for (int count = 0; count < equidistantLines.size(); count++) { - for (int direction = 0; direction < EQUIDISTANTLINE_UNIT; direction++) { - if (equidistantLines.get(count).getDirection() == (direction + 1)) {//direction 1,2,3,4 分别对应top,left,bottom,right - if (equidistantLines1[direction] != null - && equidistantLines1[direction].getDistance() > equidistantLines.get(count).getDistance() - || equidistantLines1[direction] == null) { - equidistantLines1[direction] = equidistantLines.get(count); - } - } - } - } - - equidistantLines.clear(); - //找list中横纵分别等距的组合 - if (equidistantLines1[0] != null && equidistantLines1[2] != null) {//top, bottom - int offset = equidistantLines1[0].getDistance() - equidistantLines1[2].getDistance(); - if (Math.abs(offset) <= SORPTION_UNIT * 2) { - pEquidistantY.direction = SwingConstants.TOP; - equidistantLines.add(equidistantLines1[0]); - equidistantLines.add(equidistantLines1[2]); - pEquidistantY.palce = operatingRectangle.y - offset / 2; - operatingRectangle.y = pEquidistantY.palce; - } - } - if (equidistantLines1[1] != null && equidistantLines1[3] != null) {//left, right - int offset = equidistantLines1[1].getDistance() - equidistantLines1[3].getDistance(); - if (Math.abs(offset) <= SORPTION_UNIT * 2) { - pEquidistantX.direction = SwingConstants.LEFT; - equidistantLines.add(equidistantLines1[1]); - equidistantLines.add(equidistantLines1[3]); - pEquidistantX.palce = operatingRectangle.x - offset / 2; - operatingRectangle.x = pEquidistantX.palce; - } - } - } - - //更新纵向行列线 - private static void updateVerticalLine(int[] selfVertical, RectangleIterator iterator, Absorptionline line) { - int[] targetArray = iterator.getVerticalLine(); - if (intersectArrays(targetArray, selfVertical)) { - line.setVerticalLines(targetArray); - } - } - - //更新横向行列线 - private static void updateHorizontalLine(int[] selfHorizontal, RectangleIterator iterator, Absorptionline line) { - int[] targetArray = iterator.getHorizontalLine(); - if (intersectArrays(targetArray, selfHorizontal)) { - line.setHorizontalLines(targetArray); - } - } - - //检测两个数组是否有相交的部分 - private static boolean intersectArrays(int[] targetArray, int[] selfArray) { - for (int i : targetArray) { - for (int j : selfArray) { - if (i == j) { - return true; - } - } - } - - return false; - } - - private static class EquidistantLine { - //与操作rectangle的距离 - private int distance; - //参考rectangle的位置 - private int reference; - //等距线的方向 - private int direction; - - EquidistantLine(int distance, int reference, int direction) { - this.distance = distance; - this.reference = reference; - this.direction = direction; - } - - public void setDistance(int distance) { - this.distance = distance; - } - - public int getDistance() { - return this.distance; - } - - public void setReference(int reference) { - this.reference = reference; - } - - public int getReference() { - return this.reference; - } - - public void setDirection(int direction) { - this.direction = direction; - } - - public int getDirection() { - return this.direction; - } - } +/* + * Copyright(c) 2001-2011, FineReport Inc, All Rights Reserved. + */ +package com.fr.design.beans.location; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; + +/** + * Created by IntelliJ IDEA. + * + * @author: Richer + * @since : 6.5.5 Date: 11-7-1 Time: 下午2:22 + */ +public class MoveUtils { + + public static final int SORPTION_UNIT = 5; + private static final int EQUIDISTANTLINE_UNIT = 4; + + public static ArrayList equidistantLines = new ArrayList<>(); + + private MoveUtils() { + + } + + public interface RectangleDesigner { + + /** + * 获取块边界的迭代器 + * + * @return 块边界的迭代器 + * @date 2015-2-12-下午2:43:47 + */ + RectangleIterator createRectangleIterator(); + + /** + * 设置X轴的线 + * + * @param line 连接线 + * @date 2015-2-12-下午2:44:04 + */ + void setXAbsorptionline(Absorptionline line); + + /** + * 设置Y轴的线 + * + * @param line 连接线 + * @date 2015-2-12-下午2:44:04 + */ + void setYAbsorptionline(Absorptionline line); + + /** + * 获取当前选中块的垂直线数组 + * + * @return 块的垂直线数组 + */ + int[] getVerticalLine(); + + /** + * 获取当前选中块的水平线数组 + * + * @return 块的水平线数组 + */ + int[] getHorizontalLine(); + + /** + * 设置designer内部组件是否重叠的标志位 + * + * @param isIntersects 是否重叠 + */ + void setWidgetsIntersected(boolean isIntersects); + + /** + * 获取designer内部组件是否重叠的标志位 + * + * @return 重叠 + */ + boolean isWidgetsIntersected(); + + /** + * 获取designer相对屏幕的位置 + * + * @return 位置 + */ + Point getDesignerLocationOnScreen(); + + /** + * 设置等距线 + * + * @param line 吸附线 + */ + void setEquidistantLine(Absorptionline line); + + /** + * 获取设计器垂直滚动条的值 + * + * @return 滚动条的值 + */ + int getDesignerScrollVerticalValue(); + + /** + * 获取设计器水平滚动条的值 + * + * @return 滚动条的值 + */ + int getDesignerScrollHorizontalValue(); + } + + public interface RectangleIterator { + + /** + * 是否存在下一个块 + * + * @return 是否存在下一个块 + * @date 2015-2-12-下午2:41:32 + */ + boolean hasNext(); + + /** + * 获取下一个块的bounds + * + * @return 下一个块的bounds + * @date 2015-2-12-下午2:41:55 + */ + Rectangle nextRectangle(); + + /** + * 获取块的垂直线数组 + * + * @return 块的垂直线数组 + * @date 2015-2-12-下午2:42:27 + */ + int[] getVerticalLine(); + + /** + * 获取块的水平线数组 + * + * @return 块的水平线数组 + * @date 2015-2-12-下午2:42:27 + */ + int[] getHorizontalLine(); + } + + private static class PlacePointing { + public PlacePointing(int x) { + this.palce = x; + } + + private boolean isFind() { + return direction != -1; + } + + private int palce; + private int direction = -1; + } + + private static void findX(PlacePointing px, Rectangle bounds, int left, int right, int width) { + if (px.isFind()) { + return; + } + if (Math.abs(bounds.x + bounds.width / 2 - (left + right) / 2) <= SORPTION_UNIT) { + px.palce = bounds.x + bounds.width / 2 - width / 2; + px.direction = SwingConstants.CENTER; + } + int x1 = bounds.x; + if (Math.abs(x1 - left) <= SORPTION_UNIT) { + px.palce = x1; + px.direction = SwingConstants.LEFT; + } + if (Math.abs(x1 - right) <= SORPTION_UNIT) { + px.palce = x1 - width; + px.direction = SwingConstants.RIGHT; + } + int x2 = bounds.x + bounds.width; + if (Math.abs(x2 - left) <= SORPTION_UNIT) { + px.palce = x2; + px.direction = SwingConstants.LEFT; + } + if (Math.abs(x2 - right) <= SORPTION_UNIT) { + px.palce = x2 - width; + px.direction = SwingConstants.RIGHT; + } + if (Math.abs(bounds.x + bounds.width / 2 - left) <= SORPTION_UNIT) { + px.palce = bounds.x + bounds.width / 2; + px.direction = SwingConstants.LEFT; + } + if (Math.abs(bounds.x + bounds.width / 2 - right) <= SORPTION_UNIT) { + px.palce = bounds.x + bounds.width / 2 - width; + px.direction = SwingConstants.RIGHT; + } + } + + private static void findY(PlacePointing py, Rectangle bounds, int top, int bottom, int height) { + if (py.isFind()) { + return; + } + + if (Math.abs(bounds.y + bounds.height / 2 - (top + bottom) / 2) <= SORPTION_UNIT) { + py.palce = bounds.y + bounds.height / 2 - height / 2; + py.direction = SwingConstants.CENTER; + } + int y1 = bounds.y; + if (Math.abs(y1 - top) <= SORPTION_UNIT) { + py.palce = y1; + py.direction = SwingConstants.TOP; + } + if (Math.abs(y1 - bottom) <= SORPTION_UNIT) { + py.palce = y1 - height; + py.direction = SwingConstants.BOTTOM; + } + int y2 = bounds.y + bounds.height; + if (Math.abs(y2 - top) <= SORPTION_UNIT) { + py.palce = y2; + py.direction = SwingConstants.TOP; + } + if (Math.abs(y2 - bottom) <= SORPTION_UNIT) { + py.palce = y2 - height; + py.direction = SwingConstants.BOTTOM; + } + if (Math.abs(bounds.y + bounds.height / 2 - top) <= SORPTION_UNIT) { + py.palce = bounds.y + bounds.height / 2; + py.direction = SwingConstants.TOP; + } + if (Math.abs(bounds.y + bounds.height / 2 - bottom) <= SORPTION_UNIT) { + py.palce = bounds.y + bounds.height / 2 - height; + py.direction = SwingConstants.BOTTOM; + } + } + + private static void findEquidistantLine(Rectangle bounds, int left, int top, int height, int width) { + //最近的距离与坐标 + EquidistantLine equidistantLineInfo = new EquidistantLine(0, 0, 0); + //等距线从各边中点画出,先要判断是不是在范围内 + int topMiddleX = left + width / 2; + int leftMiddleY = top + height / 2; + if ((topMiddleX > bounds.getX()) && (topMiddleX < (bounds.getX() + bounds.getWidth()))) { + //当前操作rec在bounds的下方 + if (top > (bounds.getY() + bounds.getHeight())) { + equidistantLineInfo.setDistance(top - (bounds.y + bounds.height)); + equidistantLineInfo.setReference(bounds.y + bounds.height); + equidistantLineInfo.setDirection(SwingConstants.TOP); + } + //当前操作rec在bounds上方 + if ((top + height) < bounds.getY()) { + equidistantLineInfo.setDistance(bounds.y - (top + height)); + equidistantLineInfo.setReference(bounds.y); + equidistantLineInfo.setDirection(SwingConstants.BOTTOM); + } + } else if ((leftMiddleY > bounds.getY()) && (leftMiddleY < (bounds.getY() + bounds.getHeight()))) { + //当前操作rec在bounds的右侧 + if (left > (bounds.getX() + bounds.getWidth())) { + equidistantLineInfo.setDistance(left - (bounds.x + bounds.width)); + equidistantLineInfo.setReference(bounds.x + bounds.width); + equidistantLineInfo.setDirection(SwingConstants.LEFT); + } + //当前操作rec在bounds的左侧 + if ((left + width) < bounds.getX()) { + equidistantLineInfo.setDistance(bounds.x - (left + width)); + equidistantLineInfo.setReference(bounds.x); + equidistantLineInfo.setDirection(SwingConstants.RIGHT); + } + } + if (equidistantLineInfo.getDistance() > 0) { + equidistantLines.add(equidistantLineInfo); + } + } + + + /** + * 吸附 + * + * @param x x坐标 + * @param y y坐标 + * @param width 宽度 + * @param height 高度 + * @param designer 块设计器 + * @return 吸附后坐标 + * @date 2015-2-12-下午2:39:16 + */ + public static Point sorption(int x, int y, int width, int height, RectangleDesigner designer, boolean isParameterLayout) { + + int left = x, top = y, bottom = top + height, right = left + width; + + Rectangle operatingRectangle = new Rectangle(x, y, width, height); + + equidistantLines.clear(); + + PlacePointing px = new PlacePointing(x); + PlacePointing py = new PlacePointing(y); + + PlacePointing pEquidistantX = new PlacePointing(x); + PlacePointing pEquidistantY = new PlacePointing(y); + + RectangleIterator iterator = designer.createRectangleIterator(); + + java.util.List cacheRecs = new ArrayList(); + while (iterator.hasNext()) { + Rectangle bounds = iterator.nextRectangle(); + cacheRecs.add(bounds); + findX(px, bounds, left, right, width); + findY(py, bounds, top, bottom, height); + + if (!isParameterLayout) { + findEquidistantLine(bounds, left, top, height, width); + } + } + + createXAbsorptionline(px, designer, width, cacheRecs); + createYAbsorptionline(py, designer, height, cacheRecs); + operatingRectangle.x = px.palce; + operatingRectangle.y = py.palce; + createEquidistantLine(pEquidistantX, pEquidistantY, operatingRectangle, designer); + Point sorptionPoint = new Point(px.palce, py.palce); + if (!px.isFind()) { + sorptionPoint.x = pEquidistantX.palce; + } + if (!py.isFind()) { + sorptionPoint.y = pEquidistantY.palce; + } + return sorptionPoint; + } + + + private static void createXAbsorptionline(PlacePointing px, RectangleDesigner designer, int width, java.util.List cacheRecs) { + Absorptionline line = null; + RectangleIterator iterator = designer.createRectangleIterator(); + int[] selfVertical = designer.getVerticalLine(); + if (px.direction == SwingConstants.CENTER) { + line = Absorptionline.createXMidAbsorptionline(px.palce + width / 2); + int left = px.palce; + int right = px.palce + width; + for (Rectangle bounds : cacheRecs) { + if (bounds.x == left || bounds.x + bounds.width == left) { + line.setFirstLine(left); + } + if (bounds.x == right || bounds.x + bounds.width == right) { + line.setSecondLine(right); + } + updateVerticalLine(selfVertical, iterator, line); + if (line.isFull()) { + break; + } + } + } else if (px.direction == SwingConstants.LEFT || px.direction == SwingConstants.RIGHT) { + int left = px.direction == SwingConstants.LEFT ? px.palce + width : px.palce; + line = Absorptionline.createXAbsorptionline(px.direction == SwingConstants.LEFT ? px.palce : px.palce + width); + int middle = px.palce + width / 2; + for (Rectangle bounds : cacheRecs) { + if (bounds.x == left || bounds.x + bounds.width == left) { + line.setSecondLine(left); + } + if (bounds.x + bounds.width / 2 == middle) { + line.setMidLine(middle); + } + updateVerticalLine(selfVertical, iterator, line); + if (line.isFull()) { + break; + } + } + } + designer.setXAbsorptionline(line); + } + + private static void createYAbsorptionline(PlacePointing py, RectangleDesigner designer, int height, java.util.List cacheRecs) { + Absorptionline line = null; + RectangleIterator iterator = designer.createRectangleIterator(); + int[] selfHorizontal = designer.getHorizontalLine(); + if (py.direction == SwingConstants.CENTER) { + line = Absorptionline.createYMidAbsorptionline(py.palce + height / 2); + int top = py.palce; + int bottom = py.palce + height; + for (Rectangle bounds : cacheRecs) { + if (bounds.y == top || bounds.y + bounds.height == top) { + line.setFirstLine(top); + } + if (bounds.y == bottom || bounds.y + bounds.height == bottom) { + line.setSecondLine(bottom); + } + updateHorizontalLine(selfHorizontal, iterator, line); + if (line.isFull()) { + break; + } + } + } else if (py.direction == SwingConstants.TOP || py.direction == SwingConstants.BOTTOM) { + int top = py.direction == SwingConstants.TOP ? py.palce + height : py.palce; + line = Absorptionline.createYAbsorptionline(py.direction == SwingConstants.TOP ? py.palce : py.palce + height); + int middle = py.palce + height / 2; + for (Rectangle bounds : cacheRecs) { + if (bounds.y == top || bounds.y + bounds.height == top) { + line.setSecondLine(top); + } + if (bounds.y + bounds.height / 2 == middle) { + line.setMidLine(middle); + } + updateHorizontalLine(selfHorizontal, iterator, line); + if (line.isFull()) { + break; + } + } + } + designer.setYAbsorptionline(line); + } + + private static void createEquidistantLine(PlacePointing px, PlacePointing py, Rectangle operatingRectangle, RectangleDesigner designer) { + processEquidistantLinesList(px, py, operatingRectangle); + Absorptionline line = null; + if (equidistantLines.size() > 0) { + int top = -1; + int left = -1; + int bottom = -1; + int right = -1; + for (int i = 0; i < equidistantLines.size(); i++) { + if (equidistantLines.get(i).getDirection() == SwingConstants.TOP) { + top = equidistantLines.get(i).getReference(); + } + if (equidistantLines.get(i).getDirection() == SwingConstants.LEFT) { + left = equidistantLines.get(i).getReference(); + } + if (equidistantLines.get(i).getDirection() == SwingConstants.BOTTOM) { + bottom = equidistantLines.get(i).getReference(); + } + if (equidistantLines.get(i).getDirection() == SwingConstants.RIGHT) { + right = equidistantLines.get(i).getReference(); + } + } + operatingRectangle.x -= designer.getDesignerScrollHorizontalValue(); + operatingRectangle.y -= designer.getDesignerScrollVerticalValue(); + line = Absorptionline.createEquidistantAbsorptionline(operatingRectangle, + top - designer.getDesignerScrollVerticalValue(), + left - designer.getDesignerScrollHorizontalValue(), + bottom - designer.getDesignerScrollVerticalValue(), + right - designer.getDesignerScrollHorizontalValue()); + } + designer.setEquidistantLine(line); + } + + private static void processEquidistantLinesList(PlacePointing pEquidistantX, PlacePointing pEquidistantY, Rectangle operatingRectangle) { + EquidistantLine[] equidistantLines1 = new EquidistantLine[EQUIDISTANTLINE_UNIT]; + //先按方向处理,只保留四个方向上距离最近 + for (int count = 0; count < equidistantLines.size(); count++) { + for (int direction = 0; direction < EQUIDISTANTLINE_UNIT; direction++) { + if (equidistantLines.get(count).getDirection() == (direction + 1)) {//direction 1,2,3,4 分别对应top,left,bottom,right + if (equidistantLines1[direction] != null + && equidistantLines1[direction].getDistance() > equidistantLines.get(count).getDistance() + || equidistantLines1[direction] == null) { + equidistantLines1[direction] = equidistantLines.get(count); + } + } + } + } + + equidistantLines.clear(); + //找list中横纵分别等距的组合 + if (equidistantLines1[0] != null && equidistantLines1[2] != null) {//top, bottom + int offset = equidistantLines1[0].getDistance() - equidistantLines1[2].getDistance(); + if (Math.abs(offset) <= SORPTION_UNIT * 2) { + pEquidistantY.direction = SwingConstants.TOP; + equidistantLines.add(equidistantLines1[0]); + equidistantLines.add(equidistantLines1[2]); + pEquidistantY.palce = operatingRectangle.y - offset / 2; + operatingRectangle.y = pEquidistantY.palce; + } + } + if (equidistantLines1[1] != null && equidistantLines1[3] != null) {//left, right + int offset = equidistantLines1[1].getDistance() - equidistantLines1[3].getDistance(); + if (Math.abs(offset) <= SORPTION_UNIT * 2) { + pEquidistantX.direction = SwingConstants.LEFT; + equidistantLines.add(equidistantLines1[1]); + equidistantLines.add(equidistantLines1[3]); + pEquidistantX.palce = operatingRectangle.x - offset / 2; + operatingRectangle.x = pEquidistantX.palce; + } + } + } + + //更新纵向行列线 + private static void updateVerticalLine(int[] selfVertical, RectangleIterator iterator, Absorptionline line) { + int[] targetArray = iterator.getVerticalLine(); + if (intersectArrays(targetArray, selfVertical)) { + line.setVerticalLines(targetArray); + } + } + + //更新横向行列线 + private static void updateHorizontalLine(int[] selfHorizontal, RectangleIterator iterator, Absorptionline line) { + int[] targetArray = iterator.getHorizontalLine(); + if (intersectArrays(targetArray, selfHorizontal)) { + line.setHorizontalLines(targetArray); + } + } + + //检测两个数组是否有相交的部分 + private static boolean intersectArrays(int[] targetArray, int[] selfArray) { + for (int i : targetArray) { + for (int j : selfArray) { + if (i == j) { + return true; + } + } + } + + return false; + } + + private static class EquidistantLine { + //与操作rectangle的距离 + private int distance; + //参考rectangle的位置 + private int reference; + //等距线的方向 + private int direction; + + EquidistantLine(int distance, int reference, int direction) { + this.distance = distance; + this.reference = reference; + this.direction = direction; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public int getDistance() { + return this.distance; + } + + public void setReference(int reference) { + this.reference = reference; + } + + public int getReference() { + return this.reference; + } + + public void setDirection(int direction) { + this.direction = direction; + } + + public int getDirection() { + return this.direction; + } + } } \ No newline at end of file diff --git a/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java b/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java index 5f3c3ac821..6105813576 100644 --- a/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java +++ b/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java @@ -1,410 +1,410 @@ -package com.fr.design.designer.beans.models; - -import java.awt.LayoutManager; -import java.awt.Rectangle; -import java.awt.Toolkit; -import java.awt.event.MouseEvent; -import java.util.ArrayList; - -import com.fr.design.designer.beans.AdapterBus; -import com.fr.design.designer.beans.LayoutAdapter; -import com.fr.design.designer.beans.events.DesignerEvent; -import com.fr.design.designer.beans.location.Direction; -import com.fr.design.designer.beans.location.Location; -import com.fr.design.designer.creator.*; -import com.fr.design.designer.creator.cardlayout.XWCardLayout; -import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout; -import com.fr.design.designer.creator.cardlayout.XWTabFitLayout; -import com.fr.design.form.util.XCreatorConstants; -import com.fr.design.mainframe.FormDesigner; -import com.fr.design.mainframe.FormSelection; -import com.fr.design.mainframe.FormSelectionUtils; -import com.fr.design.utils.gui.LayoutUtils; -import com.fr.form.ui.container.cardlayout.WCardMainBorderLayout; -import com.fr.stable.ArrayUtils; - -/** - * 该model保存当前选择的组件和剪切版信息 - */ -public class SelectionModel { - //被粘贴组件在所选组件位置处往下、往右各错开20像素。执行多次粘贴时,在上一次粘贴的位置处错开20像素。 - private static final int DELTA_X_Y = 20; //粘贴时候的偏移距离 - private static final int BORDER_PROPORTION = 20; - private static FormSelection CLIP_BOARD = new FormSelection(); - private FormDesigner designer; - private FormSelection selection; - private Rectangle hotspot_bounds; - - public SelectionModel(FormDesigner designer) { - this.designer = designer; - selection = new FormSelection(); - } - - /** - * 重置。清空formSelction以及选择区域 - */ - public void reset() { - selection.reset(); - hotspot_bounds = null; - } - - /** - * formSelction是否为空 - * - * @return 是否为空 - */ - public static boolean isEmpty() { - return CLIP_BOARD.isEmpty(); - } - - /** - * 鼠标点击一下,所选中的单个组件。按下Ctrl或者shift键时鼠标可以进行多选 - * - * @param e 鼠标事件 - */ - public void selectACreatorAtMouseEvent(MouseEvent e) { - if (!e.isControlDown() && !e.isShiftDown()) { - // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件 - selection.reset(); - } - - // 获取e所在的组件 - XCreator comp = designer.getComponentAt(e); - - //布局组件的顶层布局如不可编辑,要获取其顶层布局 - XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout(); - if (topLayout != null && !topLayout.isEditable()) { - comp = topLayout; - } - - // 如果父层是scale和title两个专属容器,返回其父层,组件本身是不让被选中的 - if (comp != designer.getRootComponent() && comp != designer.getParaComponent()) { - XCreator parentContainer = (XCreator) comp.getParent(); - comp = parentContainer.isDedicateContainer() ? parentContainer : comp; - } - if (selection.removeSelectedCreator(comp) || selection.addSelectedCreator(comp)) { - designer.getEditListenerTable().fireCreatorModified(comp, DesignerEvent.CREATOR_SELECTED); - designer.repaint(); - } - } - - /** - * 将所选组件剪切到剪切板上 - */ - public void cutSelectedCreator2ClipBoard() { - if (hasSelectionComponent()) { - selection.cut2ClipBoard(CLIP_BOARD); - designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_CUTED); - designer.repaint(); - } - } - - /** - * 复制当前选中的组件到剪切板 - */ - public void copySelectedCreator2ClipBoard() { - if (!selection.isEmpty()) { - selection.copy2ClipBoard(CLIP_BOARD); - } - } - - /** - * 从剪切板粘帖组件 - * - * @return 否 - */ - public boolean pasteFromClipBoard() { - if (!CLIP_BOARD.isEmpty()) { - XLayoutContainer parent = null; - //未选 - if (!hasSelectionComponent()) { - if (designer.getClass().equals(FormDesigner.class)) { - if (selection.getSelectedCreator() instanceof XWFitLayout) { - if (selection.getSelectedCreator().getClass().equals(XWTabFitLayout.class)) { - Rectangle rec = selection.getRelativeBounds(); - //Tab布局 - FormSelectionUtils.paste2Container(designer, (XLayoutContainer) selection.getSelectedCreator(), - CLIP_BOARD, - rec.x + rec.width / 2, - rec.y + BORDER_PROPORTION); - } else { - Rectangle rec = selection.getRelativeBounds(); - //自适应布局 - FormSelectionUtils.paste2Container(designer, designer.getRootComponent(), - CLIP_BOARD, - rec.x + rec.width / 2, - rec.y + BORDER_PROPORTION); - } - } else { - //绝对布局 - //编辑器外面还有两层容器,使用designer.getRootComponent()获取到的是编辑器中层的容器,不是编辑器表层 - //当前选择的就是编辑器表层 - FormSelectionUtils.paste2Container(designer, (XLayoutContainer) selection.getSelectedCreator(), - CLIP_BOARD, - DELTA_X_Y, - DELTA_X_Y); - } - } else { - //cpt本地组件复用,编辑器就一层,是最底层,使用designer.getRootComponent()就可以获取到 - //使用selection.getSelectedCreator()也应该是可以获取到的。 - FormSelectionUtils.paste2Container(designer, designer.getRootComponent(), - CLIP_BOARD, - DELTA_X_Y, - DELTA_X_Y); - } - } - //已选 - else { - //获取到编辑器的表层容器(已选的组件的父容器就是表层容器) - parent = XCreatorUtils.getParentXLayoutContainer(selection.getSelectedCreator()); - if (selection.getSelectedCreator().getParent() instanceof XWFitLayout) { - //自适应布局 - if (parent != null) { - Rectangle rec = selection.getRelativeBounds(); - FormSelectionUtils.paste2Container(designer, parent, CLIP_BOARD, rec.x + rec.width / 2, rec.y + - rec.height - BORDER_PROPORTION); - } - } else if (selection.getSelectedCreator().getParent() instanceof XWAbsoluteLayout) { - //绝对布局 - if (parent != null) { - Rectangle rec = selection.getSelctionBounds(); - FormSelectionUtils.paste2Container(designer, parent, CLIP_BOARD, rec.x + DELTA_X_Y, rec.y + DELTA_X_Y); - } - } - } - } else { - Toolkit.getDefaultToolkit().beep(); - } - return false; - } - - public FormSelection getSelection() { - return selection; - } - - /** - * 删除当前所有选择的组件 - */ - public void deleteSelection() { - XCreator[] roots = selection.getSelectedCreators(); - - if (roots.length > 0) { - for (XCreator creator : roots) { - if (creator.acceptType(XWParameterLayout.class)) { - designer.removeParaComponent(); - } - - removeCreatorFromContainer(creator, creator.getWidth(), creator.getHeight()); - creator.removeAll(); - // 清除被选中的组件 - selection.reset(); - } - setSelectedCreator(designer.getRootComponent()); - // 触发事件 - designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_DELETED); - designer.repaint(); - } - } - - /** - * 从选择组件中删除某组件 - * - * @param creator 组件 - * @param creatorWidth 组件之前宽度 - * @param creatorHeight 组件之前高度 - */ - public void removeCreator(XCreator creator, int creatorWidth, int creatorHeight) { - selection.removeCreator(creator); - removeCreatorFromContainer(creator, creatorWidth, creatorHeight); - designer.repaint(); - } - - /** - * 设置选择区域 - */ - public void setHotspotBounds(Rectangle rect) { - hotspot_bounds = rect; - } - - /** - * 获得当前选择区域 - */ - public Rectangle getHotspotBounds() { - return hotspot_bounds; - } - - private void removeCreatorFromContainer(XCreator creator, int creatorWidth, int creatorHeight) { - XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(creator); - if (parent == null) { - return; - } - boolean changeCreator = creator.shouldScaleCreator() || creator.hasTitleStyle(); - if (parent.acceptType(XWFitLayout.class) && changeCreator) { - creator = (XCreator) creator.getParent(); - } - parent.getLayoutAdapter().removeBean(creator, creatorWidth, creatorHeight); - // 删除其根组件,同时就删除了同时被选择的叶子组件 - parent.remove(creator); - LayoutManager layout = parent.getLayout(); - - if (layout != null) { - // 刷新组件容器的布局 - LayoutUtils.layoutContainer(parent); - } - } - - /** - * 是否有组件被选择。如果所选组件是最底层容器,也视为无选择 - * - * @return 是则返回true - * yaoh.wu 不应该通过判断是否是最底层容器来判断是否选择了组件 - * 而是应该判断选择的容器是否是编辑器的最表层容器,也就是点击空白地方选择的容器 - * 但是直接判断选择的容器是否是编辑器最表层类型又会引发拖动时选不上的情况, - * 因此通过判断父容器来实现 - *

- * 举例:frm组件复用 绝对布局情况下,不选择时有三层容器: - * 底层@see {@link com.fr.design.designer.creator.XWBorderLayout} - * 中层@see {@link XWFitLayout} - * 表层@see {@link com.fr.design.designer.creator.XWAbsoluteBodyLayout} - *

- * 但是编辑窗口的最外层其实是表层@see {@link com.fr.design.designer.creator.XWAbsoluteBodyLayout}, - * 其他两层不是靠添加组件就可以编辑的。 - */ - public boolean hasSelectionComponent() { - if (designer.getClass().equals(FormDesigner.class)) { - //frm本地组件复用 - return selection.getSelectedCreator() != null - && !( - //frm绝对布局编辑器 - selection.getSelectedCreator().getClass().equals(XWAbsoluteBodyLayout.class) - //Tab布局编辑器 - || selection.getSelectedCreator().getClass().equals(XWCardMainBorderLayout.class) - || selection.getSelectedCreator().getClass().equals(XWCardLayout.class) - || selection.getSelectedCreator().getClass().equals(XWTabFitLayout.class) - //自适应布局编辑器 - || selection.getSelectedCreator().getClass().equals(XWFitLayout.class) - ); - } else { - //cpt本地组件复用,selection.getSelectedCreator().getParent()=@XWParameterLayout instanceof @XWAbsoluteLayout - return selection.getSelectedCreator() != null && selection.getSelectedCreator().getParent() != null; - } - } - - /** - * 移动组件至指定位置 - * - * @param x 坐标x - * @param y 坐标y - */ - public void move(int x, int y) { - for (XCreator creator : selection.getSelectedCreators()) { - creator.setLocation(creator.getX() + x, creator.getY() + y); - LayoutAdapter layoutAdapter = AdapterBus.searchLayoutAdapter(designer, creator); - if (layoutAdapter != null) { - layoutAdapter.fix(creator); - } - } - designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), - DesignerEvent.CREATOR_SELECTED); - } - - /** - * 释放捕获 - */ - public void releaseDragging() { - designer.setPainter(null); - selection.fixCreator(designer); - designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), - DesignerEvent.CREATOR_RESIZED); - } - - public Direction getDirectionAt(MouseEvent e) { - Direction dir; - if (e.isControlDown() || e.isShiftDown()) { - XCreator creator = designer.getComponentAt(e.getX(), e.getY(), selection.getSelectedCreators()); - if (creator != designer.getRootComponent() && selection.addedable(creator)) { - return Location.add; - } - } - if (hasSelectionComponent()) { - int x = e.getX() + designer.getArea().getHorizontalValue(); - int y = e.getY() + designer.getArea().getVerticalValue(); - dir = getDirection(selection.getRelativeBounds(), x, y); - if (selection.size() == 1) { - if (!ArrayUtils.contains(selection.getSelectedCreator().getDirections(), dir.getActual())) { - dir = Location.outer; - } - } - } else { - dir = Location.outer; - } - - if (designer.getDesignerMode().isFormParameterEditor() && dir == Location.outer) { - dir = designer.getLoc2Root(e); - } - return dir; - } - - private Direction getDirection(Rectangle bounds, int x, int y) { - if (x < (bounds.x - XCreatorConstants.RESIZE_BOX_SIZ)) { - return Location.outer; - } else if ((x >= (bounds.x - XCreatorConstants.RESIZE_BOX_SIZ)) && (x <= bounds.x)) { - if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { - return Location.outer; - } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { - return Location.left_top; - } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { - return Location.left; - } else if ((y >= (bounds.y + bounds.height)) - && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { - return Location.left_bottom; - } else { - return Location.outer; - } - } else if ((x > bounds.x) && (x < (bounds.x + bounds.width))) { - if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { - return Location.outer; - } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { - return Location.top; - } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { - return Location.inner; - } else if ((y >= (bounds.y + bounds.height)) - && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { - return Location.bottom; - } else { - return Location.outer; - } - } else if ((x >= (bounds.x + bounds.width)) - && (x <= (bounds.x + bounds.width + XCreatorConstants.RESIZE_BOX_SIZ))) { - if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { - return Location.outer; - } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { - return Location.right_top; - } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { - return Location.right; - } else if ((y >= (bounds.y + bounds.height)) - && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { - return Location.right_bottom; - } else { - return Location.outer; - } - } else { - return Location.outer; - } - } - - private void fireCreatorSelected() { - designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), - DesignerEvent.CREATOR_SELECTED); - } - - public void setSelectedCreator(XCreator rootComponent) { - selection.setSelectedCreator(rootComponent); - fireCreatorSelected(); - } - - public void setSelectedCreators(ArrayList rebuildSelection) { - selection.setSelectedCreators(rebuildSelection); - fireCreatorSelected(); - } +package com.fr.design.designer.beans.models; + +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import com.fr.design.designer.beans.AdapterBus; +import com.fr.design.designer.beans.LayoutAdapter; +import com.fr.design.designer.beans.events.DesignerEvent; +import com.fr.design.designer.beans.location.Direction; +import com.fr.design.designer.beans.location.Location; +import com.fr.design.designer.creator.*; +import com.fr.design.designer.creator.cardlayout.XWCardLayout; +import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout; +import com.fr.design.designer.creator.cardlayout.XWTabFitLayout; +import com.fr.design.form.util.XCreatorConstants; +import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormSelection; +import com.fr.design.mainframe.FormSelectionUtils; +import com.fr.design.utils.gui.LayoutUtils; +import com.fr.form.ui.container.cardlayout.WCardMainBorderLayout; +import com.fr.stable.ArrayUtils; + +/** + * 该model保存当前选择的组件和剪切版信息 + */ +public class SelectionModel { + //被粘贴组件在所选组件位置处往下、往右各错开20像素。执行多次粘贴时,在上一次粘贴的位置处错开20像素。 + private static final int DELTA_X_Y = 20; //粘贴时候的偏移距离 + private static final int BORDER_PROPORTION = 20; + private static FormSelection CLIP_BOARD = new FormSelection(); + private FormDesigner designer; + private FormSelection selection; + private Rectangle hotspot_bounds; + + public SelectionModel(FormDesigner designer) { + this.designer = designer; + selection = new FormSelection(); + } + + /** + * 重置。清空formSelction以及选择区域 + */ + public void reset() { + selection.reset(); + hotspot_bounds = null; + } + + /** + * formSelction是否为空 + * + * @return 是否为空 + */ + public static boolean isEmpty() { + return CLIP_BOARD.isEmpty(); + } + + /** + * 鼠标点击一下,所选中的单个组件。按下Ctrl或者shift键时鼠标可以进行多选 + * + * @param e 鼠标事件 + */ + public void selectACreatorAtMouseEvent(MouseEvent e) { + if (!e.isControlDown() && !e.isShiftDown()) { + // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件 + selection.reset(); + } + + // 获取e所在的组件 + XCreator comp = designer.getComponentAt(e); + + //布局组件的顶层布局如不可编辑,要获取其顶层布局 + XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout(); + if (topLayout != null && !topLayout.isEditable()) { + comp = topLayout; + } + + // 如果父层是scale和title两个专属容器,返回其父层,组件本身是不让被选中的 + if (comp != designer.getRootComponent() && comp != designer.getParaComponent()) { + XCreator parentContainer = (XCreator) comp.getParent(); + comp = parentContainer.isDedicateContainer() ? parentContainer : comp; + } + if (selection.removeSelectedCreator(comp) || selection.addSelectedCreator(comp)) { + designer.getEditListenerTable().fireCreatorModified(comp, DesignerEvent.CREATOR_SELECTED); + designer.repaint(); + } + } + + /** + * 将所选组件剪切到剪切板上 + */ + public void cutSelectedCreator2ClipBoard() { + if (hasSelectionComponent()) { + selection.cut2ClipBoard(CLIP_BOARD); + designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_CUTED); + designer.repaint(); + } + } + + /** + * 复制当前选中的组件到剪切板 + */ + public void copySelectedCreator2ClipBoard() { + if (!selection.isEmpty()) { + selection.copy2ClipBoard(CLIP_BOARD); + } + } + + /** + * 从剪切板粘帖组件 + * + * @return 否 + */ + public boolean pasteFromClipBoard() { + if (!CLIP_BOARD.isEmpty()) { + XLayoutContainer parent = null; + //未选 + if (!hasSelectionComponent()) { + if (designer.getClass().equals(FormDesigner.class)) { + if (selection.getSelectedCreator() instanceof XWFitLayout) { + if (selection.getSelectedCreator().getClass().equals(XWTabFitLayout.class)) { + Rectangle rec = selection.getRelativeBounds(); + //Tab布局 + FormSelectionUtils.paste2Container(designer, (XLayoutContainer) selection.getSelectedCreator(), + CLIP_BOARD, + rec.x + rec.width / 2, + rec.y + BORDER_PROPORTION); + } else { + Rectangle rec = selection.getRelativeBounds(); + //自适应布局 + FormSelectionUtils.paste2Container(designer, designer.getRootComponent(), + CLIP_BOARD, + rec.x + rec.width / 2, + rec.y + BORDER_PROPORTION); + } + } else { + //绝对布局 + //编辑器外面还有两层容器,使用designer.getRootComponent()获取到的是编辑器中层的容器,不是编辑器表层 + //当前选择的就是编辑器表层 + FormSelectionUtils.paste2Container(designer, (XLayoutContainer) selection.getSelectedCreator(), + CLIP_BOARD, + DELTA_X_Y, + DELTA_X_Y); + } + } else { + //cpt本地组件复用,编辑器就一层,是最底层,使用designer.getRootComponent()就可以获取到 + //使用selection.getSelectedCreator()也应该是可以获取到的。 + FormSelectionUtils.paste2Container(designer, designer.getRootComponent(), + CLIP_BOARD, + DELTA_X_Y, + DELTA_X_Y); + } + } + //已选 + else { + //获取到编辑器的表层容器(已选的组件的父容器就是表层容器) + parent = XCreatorUtils.getParentXLayoutContainer(selection.getSelectedCreator()); + if (selection.getSelectedCreator().getParent() instanceof XWFitLayout) { + //自适应布局 + if (parent != null) { + Rectangle rec = selection.getRelativeBounds(); + FormSelectionUtils.paste2Container(designer, parent, CLIP_BOARD, rec.x + rec.width / 2, rec.y + + rec.height - BORDER_PROPORTION); + } + } else if (selection.getSelectedCreator().getParent() instanceof XWAbsoluteLayout) { + //绝对布局 + if (parent != null) { + Rectangle rec = selection.getSelctionBounds(); + FormSelectionUtils.paste2Container(designer, parent, CLIP_BOARD, rec.x + DELTA_X_Y, rec.y + DELTA_X_Y); + } + } + } + } else { + Toolkit.getDefaultToolkit().beep(); + } + return false; + } + + public FormSelection getSelection() { + return selection; + } + + /** + * 删除当前所有选择的组件 + */ + public void deleteSelection() { + XCreator[] roots = selection.getSelectedCreators(); + + if (roots.length > 0) { + for (XCreator creator : roots) { + if (creator.acceptType(XWParameterLayout.class)) { + designer.removeParaComponent(); + } + + removeCreatorFromContainer(creator, creator.getWidth(), creator.getHeight()); + creator.removeAll(); + // 清除被选中的组件 + selection.reset(); + } + setSelectedCreator(designer.getRootComponent()); + // 触发事件 + designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_DELETED); + designer.repaint(); + } + } + + /** + * 从选择组件中删除某组件 + * + * @param creator 组件 + * @param creatorWidth 组件之前宽度 + * @param creatorHeight 组件之前高度 + */ + public void removeCreator(XCreator creator, int creatorWidth, int creatorHeight) { + selection.removeCreator(creator); + removeCreatorFromContainer(creator, creatorWidth, creatorHeight); + designer.repaint(); + } + + /** + * 设置选择区域 + */ + public void setHotspotBounds(Rectangle rect) { + hotspot_bounds = rect; + } + + /** + * 获得当前选择区域 + */ + public Rectangle getHotspotBounds() { + return hotspot_bounds; + } + + private void removeCreatorFromContainer(XCreator creator, int creatorWidth, int creatorHeight) { + XLayoutContainer parent = XCreatorUtils.getParentXLayoutContainer(creator); + if (parent == null) { + return; + } + boolean changeCreator = creator.shouldScaleCreator() || creator.hasTitleStyle(); + if (parent.acceptType(XWFitLayout.class) && changeCreator) { + creator = (XCreator) creator.getParent(); + } + parent.getLayoutAdapter().removeBean(creator, creatorWidth, creatorHeight); + // 删除其根组件,同时就删除了同时被选择的叶子组件 + parent.remove(creator); + LayoutManager layout = parent.getLayout(); + + if (layout != null) { + // 刷新组件容器的布局 + LayoutUtils.layoutContainer(parent); + } + } + + /** + * 是否有组件被选择。如果所选组件是最底层容器,也视为无选择 + * + * @return 是则返回true + * yaoh.wu 不应该通过判断是否是最底层容器来判断是否选择了组件 + * 而是应该判断选择的容器是否是编辑器的最表层容器,也就是点击空白地方选择的容器 + * 但是直接判断选择的容器是否是编辑器最表层类型又会引发拖动时选不上的情况, + * 因此通过判断父容器来实现 + *

+ * 举例:frm组件复用 绝对布局情况下,不选择时有三层容器: + * 底层@see {@link com.fr.design.designer.creator.XWBorderLayout} + * 中层@see {@link XWFitLayout} + * 表层@see {@link com.fr.design.designer.creator.XWAbsoluteBodyLayout} + *

+ * 但是编辑窗口的最外层其实是表层@see {@link com.fr.design.designer.creator.XWAbsoluteBodyLayout}, + * 其他两层不是靠添加组件就可以编辑的。 + */ + public boolean hasSelectionComponent() { + if (designer.getClass().equals(FormDesigner.class)) { + //frm本地组件复用 + return selection.getSelectedCreator() != null + && !( + //frm绝对布局编辑器 + selection.getSelectedCreator().getClass().equals(XWAbsoluteBodyLayout.class) + //Tab布局编辑器 + || selection.getSelectedCreator().getClass().equals(XWCardMainBorderLayout.class) + || selection.getSelectedCreator().getClass().equals(XWCardLayout.class) + || selection.getSelectedCreator().getClass().equals(XWTabFitLayout.class) + //自适应布局编辑器 + || selection.getSelectedCreator().getClass().equals(XWFitLayout.class) + ); + } else { + //cpt本地组件复用,selection.getSelectedCreator().getParent()=@XWParameterLayout instanceof @XWAbsoluteLayout + return selection.getSelectedCreator() != null && selection.getSelectedCreator().getParent() != null; + } + } + + /** + * 移动组件至指定位置 + * + * @param x 坐标x + * @param y 坐标y + */ + public void move(int x, int y) { + for (XCreator creator : selection.getSelectedCreators()) { + creator.setLocation(creator.getX() + x, creator.getY() + y); + LayoutAdapter layoutAdapter = AdapterBus.searchLayoutAdapter(designer, creator); + if (layoutAdapter != null) { + layoutAdapter.fix(creator); + } + } + designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), + DesignerEvent.CREATOR_SELECTED); + } + + /** + * 释放捕获 + */ + public void releaseDragging() { + designer.setPainter(null); + selection.fixCreator(designer); + designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), + DesignerEvent.CREATOR_RESIZED); + } + + public Direction getDirectionAt(MouseEvent e) { + Direction dir; + if (e.isControlDown() || e.isShiftDown()) { + XCreator creator = designer.getComponentAt(e.getX(), e.getY(), selection.getSelectedCreators()); + if (creator != designer.getRootComponent() && selection.addedable(creator)) { + return Location.add; + } + } + if (hasSelectionComponent()) { + int x = e.getX() + designer.getArea().getHorizontalValue(); + int y = e.getY() + designer.getArea().getVerticalValue(); + dir = getDirection(selection.getRelativeBounds(), x, y); + if (selection.size() == 1) { + if (!ArrayUtils.contains(selection.getSelectedCreator().getDirections(), dir.getActual())) { + dir = Location.outer; + } + } + } else { + dir = Location.outer; + } + + if (designer.getDesignerMode().isFormParameterEditor() && dir == Location.outer) { + dir = designer.getLoc2Root(e); + } + return dir; + } + + private Direction getDirection(Rectangle bounds, int x, int y) { + if (x < (bounds.x - XCreatorConstants.RESIZE_BOX_SIZ)) { + return Location.outer; + } else if ((x >= (bounds.x - XCreatorConstants.RESIZE_BOX_SIZ)) && (x <= bounds.x)) { + if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { + return Location.outer; + } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { + return Location.left_top; + } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { + return Location.left; + } else if ((y >= (bounds.y + bounds.height)) + && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { + return Location.left_bottom; + } else { + return Location.outer; + } + } else if ((x > bounds.x) && (x < (bounds.x + bounds.width))) { + if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { + return Location.outer; + } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { + return Location.top; + } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { + return Location.inner; + } else if ((y >= (bounds.y + bounds.height)) + && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { + return Location.bottom; + } else { + return Location.outer; + } + } else if ((x >= (bounds.x + bounds.width)) + && (x <= (bounds.x + bounds.width + XCreatorConstants.RESIZE_BOX_SIZ))) { + if (y < (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) { + return Location.outer; + } else if ((y >= (bounds.y - XCreatorConstants.RESIZE_BOX_SIZ)) && (y <= bounds.y)) { + return Location.right_top; + } else if ((y > bounds.y) && (y < (bounds.y + bounds.height))) { + return Location.right; + } else if ((y >= (bounds.y + bounds.height)) + && (y <= (bounds.y + bounds.height + XCreatorConstants.RESIZE_BOX_SIZ))) { + return Location.right_bottom; + } else { + return Location.outer; + } + } else { + return Location.outer; + } + } + + private void fireCreatorSelected() { + designer.getEditListenerTable().fireCreatorModified(selection.getSelectedCreator(), + DesignerEvent.CREATOR_SELECTED); + } + + public void setSelectedCreator(XCreator rootComponent) { + selection.setSelectedCreator(rootComponent); + fireCreatorSelected(); + } + + public void setSelectedCreators(ArrayList rebuildSelection) { + selection.setSelectedCreators(rebuildSelection); + fireCreatorSelected(); + } } \ No newline at end of file diff --git a/designer_form/src/com/fr/design/mainframe/FormSelectionUtils.java b/designer_form/src/com/fr/design/mainframe/FormSelectionUtils.java index f52af750f8..dc40b0e181 100644 --- a/designer_form/src/com/fr/design/mainframe/FormSelectionUtils.java +++ b/designer_form/src/com/fr/design/mainframe/FormSelectionUtils.java @@ -1,246 +1,246 @@ -package com.fr.design.mainframe; - -import com.fr.base.FRContext; -import com.fr.design.designer.beans.LayoutAdapter; -import com.fr.design.designer.beans.adapters.layout.AbstractLayoutAdapter; -import com.fr.design.designer.beans.events.DesignerEvent; -import com.fr.design.designer.creator.*; -import com.fr.form.ui.Widget; -import com.fr.form.ui.container.WTitleLayout; -import com.fr.general.ComparatorUtils; - -import java.awt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class FormSelectionUtils { - - //组件复制时坐标偏移 - private static final int DELAY_X = 20; - private static final int DELAY_Y = 20; - - //组件复制时是否已经向左上偏移 - private static boolean backoffset = false; - - //组件重命名后缀 - private static final String POSTFIX = "_c"; - - private FormSelectionUtils() { - - } - - /** - * @param designer 编辑器 - * @param parent 粘贴依据的组件 - * @param clipBoard 剪贴板内容 - * @param x x - * @param y y - */ - public static void paste2Container(FormDesigner designer, XLayoutContainer parent, - FormSelection clipBoard, int x, int y) { - LayoutAdapter adapter = parent.getLayoutAdapter(); - if (parent instanceof XWAbsoluteLayout) { - //绝对布局 - designer.getSelectionModel().getSelection().reset(); - Rectangle rec = clipBoard.getSelctionBounds(); - for (XCreator creator : clipBoard.getSelectedCreators()) { - try { - Widget copied = copyWidget(designer, creator); - XCreator copiedCreator = XCreatorUtils.createXCreator(copied, creator.getSize()); - // 获取位置 - Point point = getPasteLocation((AbstractLayoutAdapter) adapter, - copiedCreator, - x + creator.getX() - rec.x + copiedCreator.getWidth() / 2, - y + creator.getY() - rec.y + copiedCreator.getHeight() / 2); - boolean addSuccess = adapter.addBean(copiedCreator, point.x, point.y); - - if (addSuccess) { - designer.getSelectionModel().getSelection().addSelectedCreator(copiedCreator); - } - - } catch (CloneNotSupportedException e) { - FRContext.getLogger().error(e.getMessage(), e); - } - } - rebuildSelection(designer); - designer.getEditListenerTable().fireCreatorModified( - designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); - return; - } else if (parent instanceof XWFitLayout) { - //相对布局 - designer.getSelectionModel().getSelection().reset(); - for (XCreator creator : clipBoard.getSelectedCreators()) { - try { - Widget copied = copyWidget(designer, creator); - XCreator copiedCreator = XCreatorUtils.createXCreator(copied, creator.getSize()); - boolean addSuccess = adapter.addBean(copiedCreator, x, y); - - if (addSuccess) { - designer.getSelectionModel().getSelection().addSelectedCreator(copiedCreator); - } - - } catch (CloneNotSupportedException e) { - FRContext.getLogger().error(e.getMessage(), e); - } - } - rebuildSelection(designer); - designer.getEditListenerTable().fireCreatorModified( - designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); - return; - } - Toolkit.getDefaultToolkit().beep(); - } - - /** - * 组件复用绝对布局获取粘贴组件位置 - * - * @param layoutAdapter 绝对布局容器AbstractLayoutAdapter - * @param copiedCreator 复制的组件 - * @param x x=组件x + clonedCreator.getWidth() / 2 - * @param y y=组件y + clonedCreator.getHeight() / 2 - * 除2的步骤会导致当宽度或者高度为奇数是,中心点向左上各偏移一个像素 - * 由于中心点向左上各偏移一个像素,依赖中心点计算的右下点就会相应的想做上偏移一个像素,导致结果不准确 - * @return 新位置坐标 - */ - private static Point getPasteLocation(AbstractLayoutAdapter layoutAdapter, XCreator copiedCreator, int x, int y) { - //当宽度为奇数时 设置偏移 - int xoffset = (copiedCreator.getWidth() & 1) == 1 ? 1 : 0; - //当高度为奇数时 设置偏移 - int yoffset = (copiedCreator.getHeight() & 1) == 1 ? 1 : 0; - - 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(); - /* - * 组件原始位置位于布局的右下角, - * 和布局右下边界线紧挨, - * 粘贴时组件在原始位置向左错开20像素。 - * x,y同时越界 - */ - if (xOut && yOut) { - x = backoffset ? container.getWidth() - copiedCreator.getWidth() / 2 - xoffset - : container.getWidth() - copiedCreator.getWidth() / 2 - DELAY_X - xoffset; - y = backoffset ? - container.getHeight() - copiedCreator.getHeight() / 2 - yoffset - : container.getHeight() - copiedCreator.getHeight() / 2 - DELAY_Y - yoffset; - backoffset = !backoffset; - return new Point(x, y); - } - /* - * 组件原始位置与布局边界距离小于20像素(下边界&右边界同时小于或者任意一个边界小于), - * 则粘贴时距离小于20像素一侧直接贴近布局边界, - * 距离大于20像素的一侧正常错开。 - * x,y中只有一个越界 - */ - else if ((xOut || yOut)) { - x = xOut ? container.getWidth() - copiedCreator.getWidth() / 2 - xoffset : x; - y = yOut ? container.getHeight() - copiedCreator.getHeight() / 2 - yoffset : y; - return new Point(x, y); - } - } - return new Point(x, y); - } - - - /** - * 拷贝组件 - * - * @param formDesigner - * @param xCreator - * @return - * @throws CloneNotSupportedException - */ - private static Widget copyWidget(FormDesigner formDesigner, XCreator xCreator) throws - CloneNotSupportedException { - ArrayList nameSpace = new ArrayList(); - Widget copied = (Widget) xCreator.toData().clone(); - //重命名拷贝的组件 - String name = getCopiedName(formDesigner, copied, nameSpace); - if (copied instanceof WTitleLayout) { - XWTitleLayout xwTitleLayout = new XWTitleLayout((WTitleLayout) copied, xCreator.getSize()); - xwTitleLayout.resetCreatorName(name); - } else { - copied.setWidgetName(name); - } - return copied; - } - - /** - * 组件拷贝命名规则 - * - * @param formDesigner - * @param copied - * @param nameSpace - * @return name - */ - private static String getCopiedName(FormDesigner formDesigner, Widget copied, ArrayList nameSpace) { - StringBuffer name = new StringBuffer(copied.getWidgetName()); - do { - name.append(POSTFIX); - } while (formDesigner.getTarget().isNameExist(name.toString()) || nameSpace.contains(name.toString())); - nameSpace.add(name.toString()); - return name.toString(); - } - - public static void rebuildSelection(FormDesigner designer) { - ArrayList newSelection = new ArrayList(); - List 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 rebuildSelection(XCreator rootComponent, Widget[] selectWidgets) { - List selectionWidget = new ArrayList(); - if (selectWidgets != null) { - selectionWidget.addAll(Arrays.asList(selectWidgets)); - } - return FormSelectionUtils.rebuildSelection(rootComponent, selectionWidget, new ArrayList()); - } - - private static ArrayList rebuildSelection(XCreator rootComponent, List selectionWidget, - ArrayList newSelection) { - FormSelectionUtils._rebuild(rootComponent, selectionWidget, newSelection); - if (newSelection.isEmpty()) { - newSelection.add(rootComponent); - } - return newSelection; - } - - private static void _rebuild(XCreator root, List selectionWidget, List 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); - } - } - } - } +package com.fr.design.mainframe; + +import com.fr.base.FRContext; +import com.fr.design.designer.beans.LayoutAdapter; +import com.fr.design.designer.beans.adapters.layout.AbstractLayoutAdapter; +import com.fr.design.designer.beans.events.DesignerEvent; +import com.fr.design.designer.creator.*; +import com.fr.form.ui.Widget; +import com.fr.form.ui.container.WTitleLayout; +import com.fr.general.ComparatorUtils; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FormSelectionUtils { + + //组件复制时坐标偏移 + private static final int DELAY_X = 20; + private static final int DELAY_Y = 20; + + //组件复制时是否已经向左上偏移 + private static boolean backoffset = false; + + //组件重命名后缀 + private static final String POSTFIX = "_c"; + + private FormSelectionUtils() { + + } + + /** + * @param designer 编辑器 + * @param parent 粘贴依据的组件 + * @param clipBoard 剪贴板内容 + * @param x x + * @param y y + */ + public static void paste2Container(FormDesigner designer, XLayoutContainer parent, + FormSelection clipBoard, int x, int y) { + LayoutAdapter adapter = parent.getLayoutAdapter(); + if (parent instanceof XWAbsoluteLayout) { + //绝对布局 + designer.getSelectionModel().getSelection().reset(); + Rectangle rec = clipBoard.getSelctionBounds(); + for (XCreator creator : clipBoard.getSelectedCreators()) { + try { + Widget copied = copyWidget(designer, creator); + XCreator copiedCreator = XCreatorUtils.createXCreator(copied, creator.getSize()); + // 获取位置 + Point point = getPasteLocation((AbstractLayoutAdapter) adapter, + copiedCreator, + x + creator.getX() - rec.x + copiedCreator.getWidth() / 2, + y + creator.getY() - rec.y + copiedCreator.getHeight() / 2); + boolean addSuccess = adapter.addBean(copiedCreator, point.x, point.y); + + if (addSuccess) { + designer.getSelectionModel().getSelection().addSelectedCreator(copiedCreator); + } + + } catch (CloneNotSupportedException e) { + FRContext.getLogger().error(e.getMessage(), e); + } + } + rebuildSelection(designer); + designer.getEditListenerTable().fireCreatorModified( + designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); + return; + } else if (parent instanceof XWFitLayout) { + //相对布局 + designer.getSelectionModel().getSelection().reset(); + for (XCreator creator : clipBoard.getSelectedCreators()) { + try { + Widget copied = copyWidget(designer, creator); + XCreator copiedCreator = XCreatorUtils.createXCreator(copied, creator.getSize()); + boolean addSuccess = adapter.addBean(copiedCreator, x, y); + + if (addSuccess) { + designer.getSelectionModel().getSelection().addSelectedCreator(copiedCreator); + } + + } catch (CloneNotSupportedException e) { + FRContext.getLogger().error(e.getMessage(), e); + } + } + rebuildSelection(designer); + designer.getEditListenerTable().fireCreatorModified( + designer.getSelectionModel().getSelection().getSelectedCreator(), DesignerEvent.CREATOR_PASTED); + return; + } + Toolkit.getDefaultToolkit().beep(); + } + + /** + * 组件复用绝对布局获取粘贴组件位置 + * + * @param layoutAdapter 绝对布局容器AbstractLayoutAdapter + * @param copiedCreator 复制的组件 + * @param x x=组件x + clonedCreator.getWidth() / 2 + * @param y y=组件y + clonedCreator.getHeight() / 2 + * 除2的步骤会导致当宽度或者高度为奇数是,中心点向左上各偏移一个像素 + * 由于中心点向左上各偏移一个像素,依赖中心点计算的右下点就会相应的想做上偏移一个像素,导致结果不准确 + * @return 新位置坐标 + */ + private static Point getPasteLocation(AbstractLayoutAdapter layoutAdapter, XCreator copiedCreator, int x, int y) { + //当宽度为奇数时 设置偏移 + int xoffset = (copiedCreator.getWidth() & 1) == 1 ? 1 : 0; + //当高度为奇数时 设置偏移 + int yoffset = (copiedCreator.getHeight() & 1) == 1 ? 1 : 0; + + 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(); + /* + * 组件原始位置位于布局的右下角, + * 和布局右下边界线紧挨, + * 粘贴时组件在原始位置向左错开20像素。 + * x,y同时越界 + */ + if (xOut && yOut) { + x = backoffset ? container.getWidth() - copiedCreator.getWidth() / 2 - xoffset + : container.getWidth() - copiedCreator.getWidth() / 2 - DELAY_X - xoffset; + y = backoffset ? + container.getHeight() - copiedCreator.getHeight() / 2 - yoffset + : container.getHeight() - copiedCreator.getHeight() / 2 - DELAY_Y - yoffset; + backoffset = !backoffset; + return new Point(x, y); + } + /* + * 组件原始位置与布局边界距离小于20像素(下边界&右边界同时小于或者任意一个边界小于), + * 则粘贴时距离小于20像素一侧直接贴近布局边界, + * 距离大于20像素的一侧正常错开。 + * x,y中只有一个越界 + */ + else if ((xOut || yOut)) { + x = xOut ? container.getWidth() - copiedCreator.getWidth() / 2 - xoffset : x; + y = yOut ? container.getHeight() - copiedCreator.getHeight() / 2 - yoffset : y; + return new Point(x, y); + } + } + return new Point(x, y); + } + + + /** + * 拷贝组件 + * + * @param formDesigner + * @param xCreator + * @return + * @throws CloneNotSupportedException + */ + private static Widget copyWidget(FormDesigner formDesigner, XCreator xCreator) throws + CloneNotSupportedException { + ArrayList nameSpace = new ArrayList(); + Widget copied = (Widget) xCreator.toData().clone(); + //重命名拷贝的组件 + String name = getCopiedName(formDesigner, copied, nameSpace); + if (copied instanceof WTitleLayout) { + XWTitleLayout xwTitleLayout = new XWTitleLayout((WTitleLayout) copied, xCreator.getSize()); + xwTitleLayout.resetCreatorName(name); + } else { + copied.setWidgetName(name); + } + return copied; + } + + /** + * 组件拷贝命名规则 + * + * @param formDesigner + * @param copied + * @param nameSpace + * @return name + */ + private static String getCopiedName(FormDesigner formDesigner, Widget copied, ArrayList nameSpace) { + StringBuffer name = new StringBuffer(copied.getWidgetName()); + do { + name.append(POSTFIX); + } while (formDesigner.getTarget().isNameExist(name.toString()) || nameSpace.contains(name.toString())); + nameSpace.add(name.toString()); + return name.toString(); + } + + public static void rebuildSelection(FormDesigner designer) { + ArrayList newSelection = new ArrayList(); + List 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 rebuildSelection(XCreator rootComponent, Widget[] selectWidgets) { + List selectionWidget = new ArrayList(); + if (selectWidgets != null) { + selectionWidget.addAll(Arrays.asList(selectWidgets)); + } + return FormSelectionUtils.rebuildSelection(rootComponent, selectionWidget, new ArrayList()); + } + + private static ArrayList rebuildSelection(XCreator rootComponent, List selectionWidget, + ArrayList newSelection) { + FormSelectionUtils._rebuild(rootComponent, selectionWidget, newSelection); + if (newSelection.isEmpty()) { + newSelection.add(rootComponent); + } + return newSelection; + } + + private static void _rebuild(XCreator root, List selectionWidget, List 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); + } + } + } + } } \ No newline at end of file