Posted on 2008-01-02 15:32
玩转Java 阅读(1693)
评论(4) 编辑 收藏 所属分类:
Java插件开发
我自从进入公司后,一直从事有关gef方面的开发工作,在这期间,走过不少弯路,仅仅是把GEF框架弄明白,就费了很大力气,所以,现在想写一点东西出来,供初学者阅读。
GEF(Graphical Editing Framework)是图形化编辑器开发的工具,比较典型的应用就是IBM 的Rose,它是一个模型驱动的MVC框架,控制器(EditPart)作为模型的侦听器,侦听模型的变化,如果模型的属性发生变化,它会通知控制器,控制器就会刷新模型对应的视图(Figure)。可以看出模型和视图之间没有直接联系,它们通过控制器而间接联系,可见控制器在gef框架中有着很重要的重要。
下面我们将从最基本的开始,介绍如何用GEF框架开发出一个流程设计器(开发工具Eclipse3.2.1包含插件包gef3.2.1和draw2d3.2.1)。
我们首先从模型开始,流程设计器顶层模型是流程(WorkflowProcess),流程有活动和链接这些活动的转移组成,其中活动又可以分为开始活动,普通活动,结束活动。理解了模型之间的组成关系,我们就可以设计模型对应的类了。由于上面提到,模型的属性变化了,必须通知控制器,由它来刷新模型对应的视图,所以控制器必须注册为模型的侦听器。由于每个模型都有相应的控制器侦听器侦听它属性的变化,我们把这方面的功能都放在父类中,定义一个ModelElement父类,具体代码如下:
1
package com.example.workflow.model;
2
3
import java.beans.PropertyChangeListener;
4
import java.beans.PropertyChangeSupport;
5
import java.io.IOException;
6
import java.io.ObjectInputStream;
7
import java.io.Serializable;
8
publicclass ModelElement implements Serializable
{
9
privatestaticfinallongserialVersionUID = -5117340723140888394L;
10
privatetransient PropertyChangeSupport pcsDelegate = new PropertyChangeSupport(this);
11
12
publicsynchronizedvoid addPropertyChangeListener(PropertyChangeListener l)
{
13
if (l == null)
{
14
thrownew IllegalArgumentException();
15
}
16
pcsDelegate.addPropertyChangeListener(l);
17
}
18
19
protectedvoid firePropertyChange(String property, Object oldValue, Object newValue)
{
20
if (pcsDelegate.hasListeners(property))
{
21
pcsDelegate.firePropertyChange(property, oldValue, newValue);
22
}
23
}
24
25
privatevoid readObject(ObjectInputStream in)
26
throws IOException, ClassNotFoundException
{
27
in.defaultReadObject();
28
pcsDelegate = new PropertyChangeSupport(this);
29
}
30
31
publicsynchronizedvoid removePropertyChangeListener(PropertyChangeListener l)
{
32
if (l != null)
{
33
pcsDelegate.removePropertyChangeListener(l);
34
}
35
}
36
37
}
38
接下来我们定义流程,活动,转移模型,让这些模型都继承这个父类ModelElement,我们注意到活动由开始活动,普通活动,结束活动组成,这三类活动由很多相同的属性,例如活动的位置,名称,大小等等,所以给这三类活动进行抽象,定义一个父类AbstractActivity,把这些公共属性都放在这个父类中,父类的代码如下:
1
package com.example.workflow.model;
2
3
import java.util.ArrayList;
4
import java.util.List;
5
6
import org.eclipse.draw2d.geometry.Dimension;
7
import org.eclipse.draw2d.geometry.Point;
8
9
/** *//**
10
* Abstract prototype of a Activity.
11
* Has a size (width and height), a location (x and y position) and a list of incoming
12
* and outgoing connections. Use subclasses to instantiate a specific Activity.
13
* @see com.example.workflow.model.Activity
14
* @see com.example.workflow.model.StartActivity
15
* @see com.example.workflow.model.EndActivity
16
*/
17
public class AbstractActivity extends ModelElement
{
18
19
private static final long serialVersionUID = 3023802629976246906L;
20
/** *//** Property ID to use when the location of this Activity is modified. */
21
public static final String LOCATION_PROP = "Activity.Location";
22
/** *//** Property ID to use then the size of this Activity is modified. */
23
public static final String SIZE_PROP = "Activity.Size";
24
/** *//** ID for the Name property value (used for by the corresponding property descriptor). */
25
public static final String NAME_PROP = "Activity.Name";
26
27
/** *//** Property ID to use when the list of outgoing transitions is modified. */
28
public static final String SOURCE_TRANSITIONS_PROP = "Activity.SourceTran";
29
/** *//** Property ID to use when the list of incoming transitions is modified. */
30
public static final String TARGET_TRANSITIONS_PROP = "Activity.TargetTran";
31
/** *//** ID for the Width property value (used for by the corresponding property descriptor). */
32
private static final String WIDTH_PROP = "Activity.Width";
33
/** *//** ID for the X property value (used for by the corresponding property descriptor). */
34
private static final String XPOS_PROP = "Activity.xPos";
35
/** *//** ID for the Y property value (used for by the corresponding property descriptor). */
36
private static final String YPOS_PROP = "Activity.yPos";
37
38
39
/** *//** Name of this Activity. */
40
private String name = new String("");
41
/** *//** Location of this Activity. */
42
private Point location = new Point(0, 0);
43
/** *//** Size of this Activity. */
44
private Dimension size = new Dimension(50, 50);
45
/** *//** List of outgoing Transitions. */
46
private List sourceTransitions = new ArrayList();
47
/** *//** List of incoming Transitions. */
48
private List targetTransitions = new ArrayList();
49
50
/** *//**
51
* Add an incoming or outgoing connection to this Activity.
52
* @param conn a non-null Transition instance
53
* @throws IllegalArgumentException if the Transition is null or has not distinct endpoints
54
*/
55
void addTransition(Transition tran)
{
56
if (tran == null || tran.getSource() == tran.getTarget())
{
57
throw new IllegalArgumentException();
58
}
59
if (tran.getSource() == this)
{
60
sourceTransitions.add(tran);
61
firePropertyChange(SOURCE_TRANSITIONS_PROP, null, tran);
62
} else if (tran.getTarget() == this)
{
63
targetTransitions.add(tran);
64
firePropertyChange(TARGET_TRANSITIONS_PROP, null, tran);
65
}
66
}
67
68
/** *//**
69
* Return the Name of this Activity.
70
* @return name
71
*/
72
public String getName()
{
73
return name;
74
}
75
76
/** *//**
77
* Return the Location of this Activity.
78
* @return a non-null location instance
79
*/
80
public Point getLocation()
{
81
return location.getCopy();
82
}
83
84
/** *//**
85
* Return the Size of this Activity.
86
* @return a non-null Dimension instance
87
*/
88
public Dimension getSize()
{
89
return size.getCopy();
90
}
91
92
/** *//**
93
* Return a List of outgoing Transitions.
94
*/
95
public List getSourceTransitions()
{
96
return new ArrayList(sourceTransitions);
97
}
98
99
/** *//**
100
* Return a List of incoming Transitions.
101
*/
102
public List getTargetTransitions()
{
103
return new ArrayList(targetTransitions);
104
}
105
106
/** *//**
107
* Remove an incoming or outgoing Transition from this Activity.
108
* @param conn a non-null Transition instance
109
* @throws IllegalArgumentException if the parameter is null
110
*/
111
void removeTransition(Transition tran)
{
112
if (tran == null)
{
113
throw new IllegalArgumentException();
114
}
115
if (tran.getSource() == this)
{
116
sourceTransitions.remove(tran);
117
firePropertyChange(SOURCE_TRANSITIONS_PROP, null, tran);
118
} else if (tran.getTarget() == this)
{
119
targetTransitions.remove(tran);
120
firePropertyChange(TARGET_TRANSITIONS_PROP, null, tran);
121
}
122
}
123
124
/** *//**
125
* Set the Name of this Activity.
126
* @param newName
127
* @throws IllegalArgumentException if the parameter is null
128
*/
129
public void setName(String newName)
{
130
if (newName == null)
{
131
throw new IllegalArgumentException();
132
}
133
this.name = newName;
134
firePropertyChange(LOCATION_PROP, null, name);
135
}
136
137
/** *//**
138
* Set the Location of this Activity.
139
* @param newLocation a non-null Point instance
140
* @throws IllegalArgumentException if the parameter is null
141
*/
142
public void setLocation(Point newLocation)
{
143
if (newLocation == null)
{
144
throw new IllegalArgumentException();
145
}
146
location.setLocation(newLocation);
147
firePropertyChange(LOCATION_PROP, null, location);
148
}
149