001: package org.drools.eclipse.editors.rete;
002:
003: /*
004: * Copyright 2006 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018: import java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021:
022: import org.drools.RuleBase;
023: import org.drools.RuleBaseFactory;
024: import org.drools.eclipse.DRLInfo;
025: import org.drools.eclipse.DroolsEclipsePlugin;
026: import org.drools.eclipse.editors.DRLRuleEditor;
027: import org.drools.eclipse.editors.rete.model.ReteGraph;
028: import org.drools.eclipse.editors.rete.part.VertexEditPartFactory;
029: import org.drools.reteoo.BaseVertex;
030: import org.drools.reteoo.ReteooRuleBase;
031: import org.drools.reteoo.ReteooVisitor;
032: import org.drools.rule.Package;
033: import org.eclipse.core.runtime.IProgressMonitor;
034: import org.eclipse.draw2d.ColorConstants;
035: import org.eclipse.draw2d.ConnectionLayer;
036: import org.eclipse.draw2d.ConnectionRouter;
037: import org.eclipse.draw2d.IFigure;
038: import org.eclipse.draw2d.ShortestPathConnectionRouter;
039: import org.eclipse.draw2d.geometry.Dimension;
040: import org.eclipse.draw2d.geometry.Point;
041: import org.eclipse.gef.DefaultEditDomain;
042: import org.eclipse.gef.EditPart;
043: import org.eclipse.gef.GraphicalEditPart;
044: import org.eclipse.gef.GraphicalViewer;
045: import org.eclipse.gef.LayerConstants;
046: import org.eclipse.gef.MouseWheelHandler;
047: import org.eclipse.gef.MouseWheelZoomHandler;
048: import org.eclipse.gef.editparts.LayerManager;
049: import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
050: import org.eclipse.gef.editparts.ZoomManager;
051: import org.eclipse.gef.ui.parts.GraphicalEditor;
052: import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
053: import org.eclipse.swt.SWT;
054:
055: /**
056: * GEF-based RETE Viewer
057: *
058: * @author Ahti Kitsik
059: *
060: */
061: public class ReteViewer extends GraphicalEditor {
062:
063: private static final String MSG_PARSE_ERROR = "Unable to parse rules to show RETE view!";
064:
065: private static final int SIMPLE_ROUTER_MIN_NODES = 100;
066:
067: ScalableFreeformRootEditPart rootEditPart = new ScalableFreeformRootEditPart();
068:
069: private ReteGraph diagram = new ReteGraph();
070:
071: private boolean relayoutRequired = true;
072:
073: private DRLRuleEditor drlEditor;
074:
075: /**
076: * Constructor.
077: *
078: * @param documentProvider documentProvider must contain Document with rules.
079: */
080: public ReteViewer(DRLRuleEditor drlEditor) {
081: this .drlEditor = drlEditor;
082: setEditDomain(new DefaultEditDomain(this ));
083: }
084:
085: /* (non-Javadoc)
086: * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
087: */
088: protected void configureGraphicalViewer() {
089: super .configureGraphicalViewer();
090: GraphicalViewer viewer = getGraphicalViewer();
091: viewer.getControl().setBackground(ColorConstants.white);
092: viewer.setEditPartFactory(new VertexEditPartFactory());
093: viewer.setRootEditPart(rootEditPart);
094: viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));
095: }
096:
097: /* (non-Javadoc)
098: * @see org.eclipse.gef.ui.parts.GraphicalEditor#getAdapter(java.lang.Class)
099: */
100: public Object getAdapter(Class type) {
101:
102: if (type == ZoomManager.class)
103: return ((ScalableFreeformRootEditPart) getGraphicalViewer()
104: .getRootEditPart()).getZoomManager();
105: if (type == GraphicalViewer.class)
106: return getGraphicalViewer();
107: if (type == EditPart.class && getGraphicalViewer() != null)
108: return getGraphicalViewer().getRootEditPart();
109: if (type == IFigure.class && getGraphicalViewer() != null)
110: return ((GraphicalEditPart) getGraphicalViewer()
111: .getRootEditPart()).getFigure();
112: return super .getAdapter(type);
113: }
114:
115: private RuleBase getRuleBase(String contents) {
116: try {
117: DRLInfo drlInfo = DroolsEclipsePlugin.getDefault()
118: .parseResource(drlEditor, true, true);
119: if (drlInfo != null) {
120: Package pkg = drlInfo.getPackage();
121: ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory
122: .newRuleBase(RuleBase.RETEOO);
123: ruleBase.addPackage(pkg);
124: return ruleBase;
125: }
126: } catch (Throwable t) {
127: DroolsEclipsePlugin.log(t);
128: }
129: return null;
130: }
131:
132: /**
133: * Loads model from rule base,
134: * calculates rete view and initializes diagram model.
135: * @param monitor
136: * @param contents
137: * @return
138: */
139: public ReteGraph loadReteModel(IProgressMonitor monitor,
140: String contents) throws Throwable {
141: if (relayoutRequired == false) {
142: return diagram;
143: }
144:
145: ReteGraph newDiagram = new ReteGraph();
146:
147: try {
148:
149: monitor.beginTask("Loading RETE Tree", 100);
150:
151: monitor.subTask("Loading Rule Base");
152: RuleBase ruleBase = getRuleBase(contents);
153: if (ruleBase == null) {
154: final Exception error = new Exception(MSG_PARSE_ERROR);
155: throw error;
156: }
157: monitor.worked(50);
158: if (monitor.isCanceled()) {
159: throw new InterruptedException();
160: }
161:
162: monitor.subTask("Building RETE Tree");
163: final ReteooVisitor visitor = new ReteooVisitor(newDiagram);
164: visitor.visit(ruleBase);
165: monitor.worked(30);
166: if (monitor.isCanceled()) {
167: throw new InterruptedException();
168: }
169:
170: monitor.subTask("Calculating RETE Tree Layout");
171: BaseVertex rootVertex = visitor.getRootVertex();
172: RowList rowList = ReteooLayoutFactory
173: .calculateReteRows(rootVertex);
174: ReteooLayoutFactory.layoutRowList(newDiagram, rowList);
175: zeroBaseDiagram(newDiagram);
176: monitor.worked(20);
177: if (monitor.isCanceled()) {
178: throw new InterruptedException();
179: }
180: monitor.done();
181:
182: } catch (Throwable t) {
183: if (!(t instanceof InterruptedException)) {
184: DroolsEclipsePlugin.log(t);
185: }
186: throw t;
187: }
188: relayoutRequired = false;
189: return newDiagram;
190: }
191:
192: private ReteGraph getModel() {
193: return diagram;
194: }
195:
196: /**
197: * Loads Rete model and initializes zoom manager.
198: *
199: */
200: protected void initializeGraphicalViewer() {
201: ZoomManager zoomManager = rootEditPart.getZoomManager();
202:
203: //List<String>
204: List zoomLevels = new ArrayList(3);
205:
206: zoomLevels.add(ZoomManager.FIT_ALL);
207: zoomLevels.add(ZoomManager.FIT_HEIGHT);
208: zoomLevels.add(ZoomManager.FIT_WIDTH);
209:
210: zoomManager.setZoomLevelContributions(zoomLevels);
211:
212: // Zoom mousewheel - Ctrl+Mousewheel for zoom in/out
213: getGraphicalViewer().setProperty(
214: MouseWheelHandler.KeyGenerator.getKey(SWT.MOD1),
215: MouseWheelZoomHandler.SINGLETON);
216:
217: }
218:
219: /**
220: * Moves all <code>diagram</code> nodes to upper left corner
221: * and shifting to right if neccessary to get rid of negative XY coordinates.
222: *
223: */
224: private void zeroBaseDiagram(ReteGraph graph) {
225:
226: Dimension dim = rootEditPart.getContentPane().getSize();
227:
228: int minx = 0, miny = 0, maxx = 0, x = dim.width;
229:
230: final Iterator nodeIter = graph.getChildren().iterator();
231: while (nodeIter.hasNext()) {
232: Point loc = ((BaseVertex) (nodeIter.next())).getLocation();
233: minx = Math.min(loc.x, minx);
234: maxx = Math.max(loc.x, maxx);
235: miny = Math.min(loc.y, miny);
236: }
237:
238: int delta = (x - (maxx - minx + 20)) / 2;
239: minx = minx - (delta);
240:
241: final Iterator nodeIter2 = graph.getChildren().iterator();
242: while (nodeIter2.hasNext()) {
243: final BaseVertex vertex = (BaseVertex) (nodeIter2.next());
244: Point loc = vertex.getLocation();
245: vertex.setLocation(new Point(loc.x - minx, loc.y - miny));
246: }
247: }
248:
249: /**
250: * No save operation in ReteViewer
251: */
252: public void doSave(IProgressMonitor monitor) {
253:
254: }
255:
256: /**
257: * ReteViewer is never dirty.
258: * This prevents editor close mechanism to ask file save confirmation
259: * even after one of the vertices is moved.
260: */
261: public boolean isDirty() {
262: return false;
263: }
264:
265: /**
266: * Fired when underlying source is modified.
267: * Marks graph viewer to be relayouted when activated.
268: */
269: public void fireDocumentChanged() {
270: relayoutRequired = true;
271: }
272:
273: /**
274: * Draws graph.
275: *
276: * @param newGraph used to replace existing graph. if null then existing graph is simply redrawn.
277: */
278: public void drawGraph(ReteGraph newGraph) {
279:
280: LayerManager manager = (LayerManager) getGraphicalViewer()
281: .getEditPartRegistry().get(LayerManager.ID);
282: ConnectionLayer connLayer = (ConnectionLayer) manager
283: .getLayer(LayerConstants.CONNECTION_LAYER);
284:
285: // Lazy-init model initialization
286: if (getGraphicalViewer().getContents() == null) {
287: getGraphicalViewer().setContents(getModel());
288: }
289:
290: final boolean isNewDiagram = newGraph != null
291: && newGraph != diagram;
292:
293: if (isNewDiagram) {
294: diagram.removeAll();
295: }
296:
297: // Update connection router according to new model size
298: ConnectionRouter router;
299: if ((isNewDiagram && newGraph.getChildren().size() < SIMPLE_ROUTER_MIN_NODES)
300: || (!isNewDiagram && getModel().getChildren().size() < SIMPLE_ROUTER_MIN_NODES)) {
301: router = new ShortestPathConnectionRouter(
302: (IFigure) rootEditPart.getContentPane()
303: .getChildren().get(0));
304: } else {
305: router = ConnectionRouter.NULL;
306: }
307: connLayer.setConnectionRouter(router);
308:
309: if (newGraph != null && newGraph != diagram) {
310: diagram.addAll(newGraph.getChildren());
311: }
312:
313: }
314:
315: }
|