📄 selectionmodel.java
字号:
/*
* SelectionModel.java
*
* Created on 2007年5月7日, 下午9:58
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package dyno.swing.designer.beans.models;
import dyno.swing.beans.layouts.AbsoluteLayout;
import dyno.swing.designer.beans.AdapterBus;
import dyno.swing.designer.beans.ComponentAdapter;
import dyno.swing.designer.beans.Constants;
import dyno.swing.designer.beans.ContainerAdapter;
import dyno.swing.designer.beans.SwingDesigner;
import dyno.swing.designer.beans.Util;
import dyno.swing.designer.beans.events.DesignerEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
/**
* 该model保存当前选择的组件和剪切版信息
* @author William Chen
*/
public class SelectionModel implements Constants {
private SwingDesigner designer;
//当前选中的组件,可以是多选,被选中的组件之间可以存在父子树状关系
private transient ArrayList<Component> selection;
//当前被拷贝或粘帖的剪切板
private transient ArrayList<Component> clip_board;
//当前拖拽和选择的热点区域
private transient Rectangle hotspot_bounds;
public SelectionModel(SwingDesigner designer) {
this.designer = designer;
selection = new ArrayList<Component>();
clip_board = new ArrayList<Component>();
}
public void reset(){
selection.clear();
clip_board.clear();
hotspot_bounds=null;
}
/**
* 当前选择的组件是否是可以拖拽的。可以拖拽的条件为:
* 1.选中的组件不为空(很明显)
* 2.选中的组件不是根组件
* 3.选中的组件的父亲容器必须是同一个容器(不同容器内的组件不可以被同时拖拽)
* 4.选中的组件的父亲容器的布局管理器为空,或者是AbsoluteLayout。这个规则以后可能发生,
* 如果想在其他布局管理器的情况下支持特殊的拖拽。待定。
*
* @return 是否可以拖拽,是为true,否则false
*/
public boolean isSelectedResizable() {
if (selection.isEmpty()) {
//1.选中的组件不为空
return false;
}
Container current = null;
for (Component comp : selection) {
Container parent = comp.getParent();
if ((parent == null) || (comp == designer.getRootComponent())) {
//2.选中的组件不是根组件
return false;
}
LayoutManager layout = parent.getLayout();
if ((layout != null) && (layout.getClass() != AbsoluteLayout.class)) {
//4.选中的组件的父亲容器的布局管理器为空,或者是AbsoluteLayout
return false;
}
if (current == null) {
//第一个组件的父容器
current = parent;
} else if (current != parent) {
//3.选中的组件的父亲容器必须是同一个容器
return false;
}
}
return true;
}
public void setSelectedComponent(Component comp) {
selection.clear();
selection.add(comp);
fireComponentSelected();
}
/**
* 鼠标点击一下,所选中的单个组件。按下Ctrl或者shift键时鼠标可以进行多选
*/
public void selectAComponentAtMouseEvent(MouseEvent e) {
if (!e.isControlDown() && !e.isShiftDown()) {
//如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件
selection.clear();
}
//获取e所在的组件
Component comp = designer.getComponentAt(e);
if (!((comp == null) || selection.contains(comp))) {
//如果e所在的地方有组件,并且已经选中的组件中不包含此组件,则添加进去
selection.add(comp);
}
//触发鼠标组件选择事件。
fireComponentSelected();
designer.repaint();
}
private void fireComponentSelected() {
DesignerEvent evt = new DesignerEvent(this);
evt.setSelectedComponents(selection);
designer.getEditListenerTable().fireComponentSelected(evt);
}
/**
* 在当前选中的组件中找出处于e鼠标事件所在的组件。
*/
public Component getSelectionAt(MouseEvent e) {
int x = e.getX() - designer.getOuterLeft();
int y = e.getY() - designer.getOuterTop();
for (Component comp : selection) {
//获取当前组件相对于根组件的相对位置
Rectangle rect = Util.getRelativeBounds(comp);
if ((x >= (rect.x - BOX_SIZE)) && (x <= (rect.x + rect.width + BOX_SIZE)) && (y >= (rect.y - BOX_SIZE)) && (y <= (rect.y + rect.height + BOX_SIZE))) {
return comp;
}
}
return null;
}
/**
* 将所选组件剪切到剪切板上
*/
public void cutSelectedComponent2ClipBoard() {
if (!selection.isEmpty()) {
//清空剪切板
clip_board.clear();
//找到所选择组件的根
ArrayList<Component> roots = getSelectedRoots();
for (Component root : roots) {
ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, root);
//添加他们的根组件
clip_board.add(adapter.clone());
}
for (Component component : roots) {
removeBeanFromContainer(component);
}
//触发事件
fireComponentCut();
//清除被选择的组件
selection.clear();
designer.repaint();
}
}
private void fireComponentCut() {
DesignerEvent evt = new DesignerEvent(this);
evt.setCutComponents(clip_board);
designer.getEditListenerTable().fireComponentCut(evt);
}
/**
* 获取当前被选中组件的根列表
*/
public ArrayList<Component> getSelectedRoots() {
ArrayList<Component> roots = new ArrayList<Component>();
for (Component current : selection) {
//如果当前不为根组件,并且当前组件在selection是根组件,则添加该组件
if ((current != designer.getRootComponent()) && isTopContainer(current, selection)) {
roots.add(current);
}
}
return roots;
}
/**
*判断comonent1在组件列表selection是否是根组件,即顶层容器组件
*/
private boolean isTopContainer(Component component1, ArrayList<Component> selection) {
for (Component component2 : selection) {
//查找每个组件
if ((component1 != component2) && SwingUtilities.isDescendingFrom(component1, component2) && (component2 != designer.getRootComponent())) {
//如果不是组件自身,切component1是component2的子或孙组件,并且component2不是根组件,那么不是顶层容器
return false;
}
}
return true;
}
/**
* 复制当前选中的组件到剪切板
*/
public void copySelectedComponent2ClipBoard() {
if (!selection.isEmpty()) {
//清空剪切板
clip_board.clear();
//获取被选中组件的根组件
ArrayList<Component> roots = getSelectedRoots();
for (Component root : roots) {
ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, root);
//放到剪切板中
clip_board.add(adapter.clone());
}
//触发事件
fireComponentCopyed();
}
}
private void fireComponentCopyed() {
DesignerEvent evt = new DesignerEvent(this);
evt.setCopyedComponents(clip_board);
designer.getEditListenerTable().fireComponentCopyed(evt);
}
/**
* 从剪切板粘帖组件
*/
public void pasteFromClipBoard() {
if (!clip_board.isEmpty()) {
if (!isPasteable()) {
//如果当前被选择的组件不是容器或者剪切板的内容不可以粘帖
Toolkit.getDefaultToolkit().beep();
} else {
//唯一的容器组件就是粘帖组件的地方
Component root = selection.get(0);
Container container = (Container) root;
for (Component comp : clip_board) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -