帆软报表设计器源代码。
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.
 
 
 
 

763 lines
23 KiB

package com.fr.design.chart.series.PlotSeries;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.GeneralPath;
import java.util.*;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.fr.base.*;
import com.fr.chart.base.MapSvgAttr;
import com.fr.chart.base.MapSvgXMLHelper;
import com.fr.chart.chartglyph.MapShapeValue;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.event.ChangeEvent;
import com.fr.design.event.ChangeListener;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.BoldFontTextLabel;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itable.UISelectTable;
import com.fr.design.gui.itable.UITableNoOptionUI;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.UIDialog;
import com.fr.general.ComparatorUtils;
import com.fr.general.Inter;
import com.fr.stable.CoreGraphHelper;
import com.fr.stable.StringUtils;
import com.fr.design.utils.gui.GUICoreUtils;
/**
* 地图 图片编辑界面 选中图片 编辑. 支持鼠标选中等事件
*
* @author kunsnat E-mail:kunsnat@gmail.com
* @version 创建时间:2012-10-15 下午04:17:28
*/
public class MapImageEditPane extends BasicBeanPane<String> {
private static final long serialVersionUID = -5925535686784344616L;
private static final double ARCSIZE = 7;
private static final int LOCATIONOFFSET = 10;
private static final int NAME_EDIT_PANE_WIDTH = 130;
private static final int NAME_EDIT_PANE_HEIGHT = 225;
private ImageEditPane imageEditPane;
private UISelectTable recordTable;
private int editType = 0;// 只标记mark或者标记出路径
private List<String> fromDataList = new ArrayList<String>();// 编辑时从数据集中取出的使用字段.
private HashMap<String, ArrayList<String>> resultAreaShape = new HashMap<String, ArrayList<String>>();// 名字 对应图形 // 已编辑区全都用指定颜色
private String currentNodeName ; //当前选中的节点的名字
private String typeName = "";
private String mapName = "";
private String mouseSelectListName = "";
private String editMapName = "";
public MapImageEditPane() {
initCom();
}
private void initCom() {
this.setLayout(new BorderLayout(0, 0));
imageEditPane = new ImageEditPane();
this.add(imageEditPane, BorderLayout.CENTER);
recordTable = new UISelectTable(1){
public int columnAtPoint(Point point) {
//只有一列
return 0;
}
};
recordTable.addSelectionChangeListener(new ChangeListener() {
@Override
public void fireChanged(ChangeEvent event) {
mouseSelectListName = Utils.objectToString(event.getSource());
imageEditPane.repaint();
MapImageEditPane.this.repaint();
}
});
recordTable.setUI(new UITableNoOptionUI());
recordTable.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
List<Object[]> names = recordTable.updateBean();// 得到所有的List
List<String> test = new ArrayList<String>();
for (int i = 0; i < names.size(); i++) {
test.add(Utils.objectToString(recordTable.getValueAt(i, 0)));
}
Iterator<String> keys = resultAreaShape.keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
if (!test.contains(key)) {
keys.remove();
}
}
recordTable.revalidate();
repaint();
}
});
UIScrollPane pane = new UIScrollPane(recordTable);
pane.setPreferredSize(new Dimension(150, 320));
pane.setBorder(GUICoreUtils.createTitledBorder(Inter.getLocText(new String[]{"Filed", "WF-Name"})));
this.add(pane, BorderLayout.EAST);
}
/**
* 设置编辑的类型: 区域 或者 点
*/
public void setEditType(int editType) {
this.editType = editType;
}
/**
* 返回编辑的类型: 区域 或者 点
*/
public int getEditType() {
return editType;
}
/**
* 设置正在编辑的svg文件
*/
public void setSvgMap(String filePath){
resultAreaShape.clear();
mouseSelectListName = StringUtils.EMPTY;
recordTable.populateBean(new ArrayList<Object[]>());
recordTable.revalidate();
imageEditPane.setSvgMap(filePath);
repaint();
}
/**
* 清空图片内容
*/
public void clearSvgMap(){
resultAreaShape.clear();
mouseSelectListName = StringUtils.EMPTY;
recordTable.populateBean(new ArrayList<Object[]>());
recordTable.revalidate();
imageEditPane.clearSvgMap();
repaint();
}
/**
* 设置正在编辑的svg文件
* @param attr 已经读取过的文件
*/
public void setSvgMap(MapSvgAttr attr){
resultAreaShape.clear();
mouseSelectListName = StringUtils.EMPTY;
recordTable.populateBean(new ArrayList<Object[]>());
recordTable.revalidate();
imageEditPane.setSvgMap(attr);
repaint();
}
/**
* 刷新数据列表中的数据
* @param list 列表
*/
public void refreshFromDataList(List list) {
fromDataList.clear();
for (Object aList : list) {
fromDataList.add(Utils.objectToString(aList));
}
}
/**
* 当前正在编辑的条目的类别(国家,省市)名和地图名
* @param typeName 类别名
* @param mapName 地图名
*/
public void setTypeNameAndMapName(String typeName, String mapName){
this.typeName = typeName;
this.mapName = mapName;
}
private class ImageEditPane extends JComponent implements MouseListener, MouseMotionListener {
private MapSvgAttr currentSvgMap;//当前选中的svg地图
private GeneralPath selectedShape; // 当前选中的Shape
private Image image = BaseUtils.readImage("");// 所选择的图片
//平移的位置
private double moveLeft = 0;
private double moveTop = 0;
//鼠标落点的位置
private double mouseStartX;
private double mouseStartY;
private boolean dragged = false;
public ImageEditPane() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g) {// 选中图片之后, 记录选中的区域, 点中的 标记点
Rectangle bounds = this.getBounds();
if (bounds == null || this.image == null) {
return;
}
dealReady4Paint(g, bounds);
int imageWidth = this.image.getWidth(new JPanel());
int imageHeight = this.image.getHeight(new JPanel());
Graphics2D g2d = (Graphics2D) g;
if (this.image != null) {// 太小会放大, 太大, 则默认拖动
g2d.drawImage(this.image, (int) moveLeft, (int) moveTop, imageWidth, imageHeight, new JPanel()); // 只是移动起始位置
}
g2d.translate(moveLeft, moveTop);
g2d.setStroke(new BasicStroke(1));
if (resultAreaShape != null && !resultAreaShape.isEmpty()) {
for (String key : resultAreaShape.keySet()) {
GeneralPath selectShape = getSelectedNodePath(key);
g2d.setColor(Color.green);
g2d.draw(selectShape);
}
}
g2d.setColor(Color.blue);
if (StringUtils.isNotEmpty(mouseSelectListName) && resultAreaShape.containsKey(mouseSelectListName)) {// 当前悬浮选中的 list, 自己画的悬浮提示, 背景 边框, 文字
GeneralPath highSelect = getSelectedNodePath(mouseSelectListName);
if (highSelect != null) {
g2d.fill(highSelect);
}
} else if (selectedShape != null) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2d.fill(selectedShape);
}
g2d.translate(-moveLeft, -moveTop);
}
private void dealReady4Paint(Graphics g, Rectangle bounds) {
super.paintComponent(g);
int x = (int) bounds.getX();
int y = (int) bounds.getY();
int width = (int) bounds.getWidth();
int height = (int) bounds.getHeight();
g.clipRect(x, y, width, height);
}
//初始化下图片的状态
private void initImage() {
this.image = currentSvgMap.getMapImage();
CoreGraphHelper.waitForImage(this.image);
this.selectedShape = null;
this.moveLeft = 0;
this.moveTop = 0;
}
/**
* 设置当前正在编辑的文件
* @param filePath 文件路径
*/
public void setSvgMap(String filePath){
currentSvgMap = new MapSvgAttr(filePath);
currentSvgMap.setMapTypeAndName(typeName, mapName);
initImage();
}
/**
* 设置当前正在编辑的文件
* @param attr 读取过的文件
*/
public void setSvgMap(MapSvgAttr attr){
currentSvgMap = attr;
initImage();
}
public void clearSvgMap(){
currentSvgMap = null;
this.image = BaseUtils.readImage("");;
this.selectedShape = null;
this.moveLeft = 0;
this.moveTop = 0;
this.dragged = false;
this.mouseStartX = 0;
this.mouseStartY = 0;
}
public Image getImage() {
return this.image;
}
@Override
public void mouseClicked(MouseEvent e) {
drawSelectShape(e);
if (e.getClickCount() == 2) {// 2次编辑, 不然很容易错乱 和 update 错误
showEditNamePane(e);
}
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
this.mouseStartX = e.getPoint().getX();
this.mouseStartY = e.getPoint().getY();
}
@Override
public void mouseReleased(MouseEvent e) {
drawWhenDragEnd(e);
}
public void mouseDragged(MouseEvent e) {
this.dragged = true;
}
public void mouseMoved(MouseEvent e) {
}
private void drawWhenDragEnd(MouseEvent e) {
if (this.image == null || this.getBounds() == null) {
return;
}
if (dragged) {
double endX = e.getPoint().getX();
double endY = e.getPoint().getY();
int imageWidth = image.getWidth(new JPanel());
int imageHeight = image.getHeight(new JPanel());
int paneWidth = (int) this.getBounds().getWidth();
int paneHeight = (int) this.getBounds().getHeight();
if (imageWidth > paneWidth) {
double offX = endX - this.mouseStartX;
this.moveLeft += offX;
this.moveLeft = Math.max(this.moveLeft, paneWidth - imageWidth);
this.moveLeft = Math.min(0, this.moveLeft);
} else {
this.moveLeft = 0;
}
if (imageHeight > paneHeight) {
double offY = endY - this.mouseStartY;
this.moveTop += offY;
this.moveTop = Math.max(this.moveTop, paneHeight - imageHeight);
this.moveTop = Math.min(0, this.moveTop);
} else {
this.moveTop = 0;
}
this.repaint();
}
this.dragged = false;
}
//画鼠标点击的区域
private void drawSelectShape(MouseEvent e) {
selectedShape = null;
mouseSelectListName = StringUtils.EMPTY;
if (this.image == null) {
return;
}
Point ePoint = e.getPoint();
Point select = new Point((int) (ePoint.getX() - moveLeft), (int) (ePoint.getY() - moveTop));// 支持ctrl 选定时的多选.. 只是记录多个鼠标位置 然后shape合并
boolean gotSelectedShape = false;
for (String key : resultAreaShape.keySet()) {
GeneralPath mapSelect = getSelectedNodePath(key);
if (mapSelect.contains(select)) {
selectedShape = mapSelect;
currentNodeName = currentSvgMap.getSelectedPathName(select);
gotSelectedShape = true;
break;
}
}
if (!gotSelectedShape) {// 根据坐标重新在图片中选取Shape
if (getEditType() == MapShapeValue.AREA) {
selectedShape = currentSvgMap.getSelectPath(select);
currentNodeName = currentSvgMap.getSelectedPathName(select);
} else {
//标记点类型的要不要待定
}
}
this.repaint();
}
private void showEditNamePane(MouseEvent e) {
if (this.image == null || selectedShape == null) {
return;
}
final EditNamePane namePane = new EditNamePane();
Point ePoint = e.getPoint();
final Point select = new Point((int) (ePoint.getX() - moveLeft), (int) (ePoint.getY() - moveTop));
namePane.setEditViewRow(getEditViewRow(select));
String isSelectName = StringUtils.EMPTY;
for (String name : resultAreaShape.keySet()) {
GeneralPath shape = getSelectedNodePath(name);
if (shape.contains(select)) {
isSelectName = name;
break;
}
}
namePane.populateBean(isSelectName);
namePane.resetPaneWithNewNameList(fromDataList);
UIDialog bg = namePane.showUnsizedWindow(SwingUtilities.getWindowAncestor(ImageEditPane.this), new DialogActionAdapter() {
public void doOk() {
namePane.changeList();
String endName = namePane.updateBean();
if (resultAreaShape.containsKey(endName)) {
if(ComparatorUtils.equals(endName,namePane.startName)) {
return;
}
ArrayList<String> pathID = resultAreaShape.get(endName);
if(!pathID.contains(currentNodeName)){
pathID.add(currentNodeName);
}
}else{
ArrayList<String> paths = new ArrayList<String>();
resultAreaShape.put(endName,paths);
paths.add(currentNodeName);
ArrayList<String> exists = resultAreaShape.get(namePane.startName);
if(exists!= null){
for(String id:exists){
paths.add(id);
}
resultAreaShape.remove(namePane.startName);
}
}
}
});
bg.setSize(NAME_EDIT_PANE_WIDTH, NAME_EDIT_PANE_HEIGHT);
bg.setLocation((int) (e.getLocationOnScreen().getX()) + LOCATIONOFFSET, (int) e.getLocationOnScreen().getY());
bg.setTitle(Inter.getLocText(new String[]{"Edit", "Filed", "WF-Name"}));
bg.setVisible(true);
}
// viewList 根据内容名称 得到是哪一行.
public int getEditViewRow(Point point) {
int rowIndex = recordTable.getRowCount();// 最差 没有找到应该也是返回 row + 1
// 根据编辑的位置, 是否有shape对应, 有则找出, 没有则是新的行
String isSelectName = StringUtils.EMPTY;
for (String name : resultAreaShape.keySet()) {
GeneralPath shape = getSelectedNodePath(name);
if (shape.contains(point)) {
isSelectName = name;
break;
}
}
if (resultAreaShape.containsKey(isSelectName)) {
for (int i = 0; i < recordTable.getRowCount(); i++) {
String tmp = (String) recordTable.getValueAt(i, 0);
if (ComparatorUtils.equals(isSelectName, tmp)) {
rowIndex = i;
break;
}
}
}// 没有则添加一行
return rowIndex;
}
}
// 图片界面 悬浮点击弹出的名称列表
private class EditNamePane extends BasicBeanPane<String> {// 点击编辑名称
private UITextField nameText; // 文本框
private JList dataList;
private String startName;
private JList hasNamedList;
private int editViewRow = -1;// 所对应的view的index行 , 确定当前正在编辑的viewList的行, 然后改变值
private UILabel namedLabel = new BoldFontTextLabel(Inter.getLocText("FR-Chart-Pre_Defined") + "------");
private JPanel listPane = new JPanel();
public EditNamePane() {
initCom();
}
public void setEditViewRow(int index) {
this.editViewRow = index;
}
private void initCom() {
this.setLayout(new BorderLayout(0, 0));
nameText = new UITextField();
nameText.setPreferredSize(new Dimension(100, 20));
this.add(nameText, BorderLayout.NORTH);
listPane.setLayout(new BoxLayout(listPane, BoxLayout.Y_AXIS));
this.add(listPane, BorderLayout.CENTER);
listPane.add(new UIScrollPane(dataList = new JList(new DefaultListModel())));
dataList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() >= 2 && dataList.getSelectedValue() != null) {
String value = Utils.objectToString(dataList.getSelectedValue());
nameText.setText(value);// 直接对文本值改变, 让文本去触发事件
}
}
});
listPane.add(namedLabel);
listPane.add(new UIScrollPane(hasNamedList = new JList(new DefaultListModel())));
hasNamedList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() >= 2 && hasNamedList.getSelectedValue() != null) {
nameText.setText(Utils.objectToString(hasNamedList.getSelectedValue()));
}
}
});
}
private void relayoutList() {
listPane.removeAll();
listPane.setLayout(new BoxLayout(listPane, BoxLayout.Y_AXIS));
listPane.add(new UIScrollPane(dataList));
if (hasNamedList.getModel().getSize() > 0) {
listPane.add(namedLabel);
listPane.add(new UIScrollPane(hasNamedList));
}
}
//列表改变,选中的时候添加shape信息
private void changeList() {
String textValue = nameText.getText();
if (editViewRow >= recordTable.getRowCount()) {// 添加一行 确定的行数 即时大于viewCount
recordTable.addLine(new String[]{textValue});
} else if (editViewRow > -1) {
recordTable.setValueAt(textValue, editViewRow, 0);
}
recordTable.revalidate();
recordTable.repaint();
resetPaneWithNewNameList(fromDataList);
}
public void resetPaneWithNewNameList(List<String> list) {// 界面不变, 只是刷新重置list
DefaultListModel model = (DefaultListModel) dataList.getModel();
model.removeAllElements();
DefaultListModel hasNameModel = (DefaultListModel) hasNamedList.getModel();
hasNameModel.removeAllElements();
for (int i = 0; list != null && i < list.size(); i++) {
String value = list.get(i);
if (!resultAreaShape.containsKey(value)) {
model.addElement(value);
}
}
for (String name : resultAreaShape.keySet()) {
if (!hasNameModel.contains(name)) {
hasNameModel.addElement(name);
}
}
relayoutList();
}
public void populateBean(String list) {
nameText.setText(list);
startName = list;
nameText.setCaretPosition(list == null ? 0 : list.length());
}
@Override
public String updateBean() {
return nameText.getText();
}
@Override
protected String title4PopupWindow() {
return Inter.getLocText(new String[]{"Edit", "Image"});
}
}
@Override
protected String title4PopupWindow() {
return Inter.getLocText(new String[]{"Edit", "Image"});
}
/**
* 更新地图 名称列表以及正在编辑的图片
*/
public void populateBean(String ob) {// 确定要编辑的地图名称
this.editMapName = ob;// 当前编辑的地图名称
MapSvgXMLHelper mapHelper = MapSvgXMLHelper.getInstance();
if (mapHelper.containsMapName(editMapName)) {
MapSvgAttr svgAttr = mapHelper.getMapAttr(editMapName);
populateMapSvgAttr(svgAttr);
}else if(mapHelper.getNewMapAttr(editMapName) != null ){
clearSvgMap();
imageEditPane.currentSvgMap = mapHelper.getMapAttr(editMapName);
}else {
clearSvgMap();
}
}
/**
* 保存编辑的地图 形状等信息.
*/
public String updateBean() {
if(imageEditPane.currentSvgMap !=null){
this.editMapName = imageEditPane.currentSvgMap.getName();
}
// 将地图加入helper 固定存储 记录固定的hShape 原图片的坐标位置, 然后在根据现在现实的 实际坐标 展示
if (StringUtils.isNotEmpty(editMapName) && this.imageEditPane.getImage() != null) {
MapSvgXMLHelper mapHelper = MapSvgXMLHelper.getInstance();
MapSvgAttr mapAttr = imageEditPane.currentSvgMap;
if(mapHelper.getNewMapAttr(editMapName)!=null){
mapHelper.removeNewMapAttr(editMapName);
mapHelper.pushMapAttr(editMapName,mapAttr);
}
if(mapHelper.containsMapName(editMapName)){
//处理下mapAttr存节点name属性
updateMapShapePath(mapAttr);
mapHelper.addCustomSvgMap(editMapName, mapAttr);
//设置以后要写回
mapAttr.writeBack(editMapName);
}
}
return editMapName;
}
/**
* 更新界面
* @param svgAttr 地图属性
* */
public void populateMapSvgAttr(MapSvgAttr svgAttr){
if(svgAttr == null || svgAttr.getMapImage() == null){
clearSvgMap();
return;
}
setSvgMap(svgAttr);
Iterator names = svgAttr.shapeValuesIterator();
while (names.hasNext()) {
String name = Utils.objectToString(names.next());
ArrayList<String> pathIDs= svgAttr.getExistedShapePathID(name);
if (name != null) {
resultAreaShape.put(name,pathIDs);
recordTable.addLine(new String[]{name});
}
}
recordTable.revalidate();
}
/**
* 更新MapSvgAttr
* @return 返回属性
* */
public MapSvgAttr updateWithOutSave(){
if(imageEditPane.currentSvgMap !=null){
this.editMapName = imageEditPane.currentSvgMap.getName();
}
// 将地图加入helper 固定存储 记录固定的hShape 原图片的坐标位置, 然后在根据现在现实的 实际坐标 展示
if (StringUtils.isNotEmpty(editMapName) && this.imageEditPane.getImage() != null) {
MapSvgXMLHelper mapHelper = MapSvgXMLHelper.getInstance();
MapSvgAttr mapAttr = imageEditPane.currentSvgMap;
if(mapHelper.getNewMapAttr(editMapName)!=null){
mapHelper.removeNewMapAttr(editMapName);
mapHelper.pushMapAttr(editMapName,mapAttr);
}
if(mapHelper.containsMapName(editMapName)){
//处理下mapAttr存节点name属性
updateMapShapePath(mapAttr);
mapHelper.addCustomSvgMap(editMapName, mapAttr);
}
return mapAttr;
}
return null;
}
private void updateMapShapePath(MapSvgAttr mapSvgAttr){
mapSvgAttr.clearExistShape();
for(String key : resultAreaShape.keySet()){
ArrayList<String> nodeName = resultAreaShape.get(key);
if(nodeName == null){
continue;
}
for(String node :nodeName){
mapSvgAttr.setNodeName(node, key);
}
}
}
private GeneralPath getSelectedNodePath(String nodeName){
if(imageEditPane.currentSvgMap == null){
return new GeneralPath();
}
MapSvgAttr attr = imageEditPane.currentSvgMap;
ArrayList<String> pathsID = resultAreaShape.get(nodeName);
GeneralPath unionPath =new GeneralPath();
//这边必须在新建的一个path上append,不然直接在存的path上append,不然后面删除组合了,也不能正常的选单个
for(String id :pathsID){
unionPath.append(attr.getPath4PathID(id),false);
}
return unionPath;
}
}