1 | /** |
2 | * |
3 | */ |
4 | package de.uka.ipd.sdq.pcm.dialogs.stoex; |
5 | |
6 | import org.antlr.runtime.Lexer; |
7 | import org.antlr.runtime.RecognitionException; |
8 | import org.eclipse.emf.ecore.EObject; |
9 | import org.eclipse.jface.dialogs.IDialogConstants; |
10 | import org.eclipse.jface.dialogs.IMessageProvider; |
11 | import org.eclipse.jface.dialogs.TitleAreaDialog; |
12 | import org.eclipse.jface.text.Document; |
13 | import org.eclipse.jface.text.ITextListener; |
14 | import org.eclipse.jface.text.Position; |
15 | import org.eclipse.jface.text.TextEvent; |
16 | import org.eclipse.jface.text.source.Annotation; |
17 | import org.eclipse.jface.text.source.AnnotationModel; |
18 | import org.eclipse.jface.text.source.AnnotationPainter; |
19 | import org.eclipse.jface.text.source.AnnotationRulerColumn; |
20 | import org.eclipse.jface.text.source.CompositeRuler; |
21 | import org.eclipse.jface.text.source.IAnnotationAccess; |
22 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; |
23 | import org.eclipse.jface.text.source.ImageUtilities; |
24 | import org.eclipse.jface.text.source.SourceViewer; |
25 | import org.eclipse.swt.SWT; |
26 | import org.eclipse.swt.custom.StyledText; |
27 | import org.eclipse.swt.graphics.Color; |
28 | import org.eclipse.swt.graphics.GC; |
29 | import org.eclipse.swt.graphics.RGB; |
30 | import org.eclipse.swt.graphics.Rectangle; |
31 | import org.eclipse.swt.layout.FillLayout; |
32 | import org.eclipse.swt.layout.GridData; |
33 | import org.eclipse.swt.widgets.Canvas; |
34 | import org.eclipse.swt.widgets.Composite; |
35 | import org.eclipse.swt.widgets.Control; |
36 | import org.eclipse.swt.widgets.Display; |
37 | import org.eclipse.swt.widgets.Event; |
38 | import org.eclipse.swt.widgets.Group; |
39 | import org.eclipse.swt.widgets.Listener; |
40 | import org.eclipse.swt.widgets.Shell; |
41 | import org.eclipse.ui.PlatformUI; |
42 | |
43 | import de.uka.ipd.sdq.errorhandling.IIssue; |
44 | import de.uka.ipd.sdq.pcm.dialogs.DialogsImages; |
45 | import de.uka.ipd.sdq.pcm.dialogs.SWTResourceManager; |
46 | import de.uka.ipd.sdq.pcm.repository.Parameter; |
47 | import de.uka.ipd.sdq.pcm.stochasticexpressions.parser.ErrorEntry; |
48 | |
49 | /** |
50 | * @author Snowball |
51 | */ |
52 | public abstract class AbstractGrammerBasedEditDialog extends TitleAreaDialog { |
53 | |
54 | private String DIALOG_TITLE = "Edit a stochastic expression"; |
55 | |
56 | public static final String ERROR_TYPE = "ERROR"; |
57 | public static final String WARNING_TYPE = "WARNING"; |
58 | |
59 | // private Text editText; |
60 | private SourceViewer textViewer; |
61 | |
62 | protected String newText = null; |
63 | |
64 | private AnnotationModel fAnnotationModel; |
65 | |
66 | private Object result = null; |
67 | private String resultText = null; |
68 | |
69 | protected Parameter[] context = null; |
70 | |
71 | /** |
72 | * Constructor. |
73 | * |
74 | * @param parent |
75 | * shell |
76 | */ |
77 | public AbstractGrammerBasedEditDialog(Shell parent) { |
78 | super(parent); |
79 | newText = getInitialText(); |
80 | this.context = new Parameter[]{}; |
81 | // make the possible change dialogue size. |
82 | this.setShellStyle(SWT.RESIZE|SWT.MAX); |
83 | } |
84 | |
85 | /** |
86 | * Constructor. |
87 | * |
88 | * @param parent |
89 | * shell |
90 | * @param context - |
91 | * A list of parameters used in code completion |
92 | */ |
93 | public AbstractGrammerBasedEditDialog(Shell parent, Parameter[] context) { |
94 | super(parent); |
95 | newText = getInitialText(); |
96 | this.context = context; |
97 | // make the possible change dialogue size. |
98 | setShellStyle(SWT.RESIZE|SWT.MAX); |
99 | // activate help |
100 | this.setHelpAvailable(true); |
101 | } |
102 | |
103 | protected abstract String getInitialText(); |
104 | |
105 | public void setDisplayTitle(String newTitle) { |
106 | this.DIALOG_TITLE = newTitle; |
107 | } |
108 | |
109 | @Override |
110 | protected void cancelPressed() { |
111 | super.cancelPressed(); |
112 | result = null; |
113 | resultText = ""; |
114 | } |
115 | |
116 | @Override |
117 | protected Control createDialogArea(Composite parent) { |
118 | Composite area = (Composite) super.createDialogArea(parent); |
119 | Composite container = new Composite(area, SWT.NONE); |
120 | container.setLayout(new FillLayout()); |
121 | container.setLayoutData(new GridData(GridData.FILL_BOTH)); |
122 | |
123 | this.setTitle(DIALOG_TITLE); |
124 | PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, "de.uka.ipd.sdq.pcmbench.help.stoexdialog"); |
125 | |
126 | IAnnotationAccess fAnnotationAccess = new AnnotationMarkerAccess(); |
127 | |
128 | final Group editStochasticExpressionGroup = new Group(container, SWT.NONE); |
129 | editStochasticExpressionGroup.setText(""); |
130 | editStochasticExpressionGroup.setLayout(new FillLayout()); |
131 | |
132 | fAnnotationModel = new AnnotationModel(); |
133 | CompositeRuler fCompositeRuler = new CompositeRuler(); |
134 | AnnotationRulerColumn annotationRuler = new AnnotationRulerColumn( |
135 | fAnnotationModel, 16, fAnnotationAccess); |
136 | fCompositeRuler.setModel(fAnnotationModel); |
137 | // annotation ruler is decorating our composite ruler |
138 | fCompositeRuler.addDecorator(0, annotationRuler); |
139 | |
140 | // add what types are show on the different rulers |
141 | annotationRuler.addAnnotationType(ERROR_TYPE); |
142 | annotationRuler.addAnnotationType(WARNING_TYPE); |
143 | textViewer = new SourceViewer(editStochasticExpressionGroup, |
144 | fCompositeRuler, SWT.V_SCROLL | SWT.MULTI | SWT.H_SCROLL | SWT.RESIZE); |
145 | final StyledText styledText = textViewer.getTextWidget(); |
146 | styledText.setWordWrap(true); |
147 | final AbstractGrammarBasedViewerConfiguration config = new AbstractGrammarBasedViewerConfiguration(fAnnotationModel,context,getLexerClass(),getTokenMapper()); |
148 | styledText.setFont(SWTResourceManager.getFont("Courier New", 12, |
149 | SWT.NONE)); |
150 | styledText.addListener(SWT.KeyDown, new Listener(){ |
151 | |
152 | public void handleEvent(Event event) { |
153 | if (event.character == ' ' && (event.stateMask & SWT.CTRL) == SWT.CTRL){ |
154 | config.getContentAssistant(textViewer).showPossibleCompletions(); |
155 | } |
156 | |
157 | } |
158 | |
159 | }); |
160 | |
161 | // to paint the annotations |
162 | AnnotationPainter ap = new AnnotationPainter(textViewer, |
163 | fAnnotationAccess); |
164 | ap.addAnnotationType(ERROR_TYPE); |
165 | ap.setAnnotationTypeColor(ERROR_TYPE, new Color(Display.getDefault(), |
166 | new RGB(255, 0, 0))); |
167 | ap.addAnnotationType(WARNING_TYPE); |
168 | ap.setAnnotationTypeColor(WARNING_TYPE, new Color(Display.getDefault(), |
169 | new RGB(255, 255, 0))); |
170 | |
171 | // this will draw the squigglies under the text |
172 | textViewer.addPainter(ap); |
173 | |
174 | textViewer.configure(config); |
175 | GridData layoutData = new GridData(GridData.FILL_BOTH);//new GridData(GridData.FILL_BOTH |
176 | //| GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); |
177 | //layoutData.heightHint = 300; |
178 | //layoutData.widthHint = 450; |
179 | |
180 | //textViewer.getControl().setLayoutData(layoutData); |
181 | // editText.setText(newText); |
182 | textViewer.setDocument(new Document(newText), fAnnotationModel); |
183 | textViewer.addTextListener(new ITextListener(){ |
184 | |
185 | public void textChanged(TextEvent event) { |
186 | if (event.getDocumentEvent() != null) |
187 | { |
188 | parseInputAndRefreshAnnotations(); |
189 | } |
190 | } |
191 | |
192 | }); |
193 | return textViewer.getControl(); |
194 | } |
195 | |
196 | @Override |
197 | protected Control createContents(Composite parent) { |
198 | Control result = super.createContents(parent); |
199 | parseInputAndRefreshAnnotations(); |
200 | return result; |
201 | } |
202 | |
203 | protected abstract ITokenMapper getTokenMapper(); |
204 | protected abstract Class<?> getLexerClass(); |
205 | |
206 | protected abstract String getTitle(); |
207 | |
208 | protected void parseInputAndRefreshAnnotations() { |
209 | EObject value = null; |
210 | fAnnotationModel.removeAllAnnotations(); |
211 | Lexer lexer = null; |
212 | boolean hasErrors = false, hasWarnings = false; |
213 | try { |
214 | String text = this.textViewer.getDocument().get(); |
215 | lexer = getLexer(text); |
216 | value = parse(lexer); |
217 | } catch (RecognitionException e) { |
218 | showInputInvalidInfo(e); |
219 | return; |
220 | } catch (StoExParserException e) { |
221 | for (IIssue ex : e.getIssuesList()) { |
222 | if (ex instanceof ErrorEntry) { |
223 | showInputInvalidInfo((ErrorEntry)ex); |
224 | hasErrors = true; |
225 | } |
226 | else { |
227 | hasWarnings = true; |
228 | showInputWarning(ex); |
229 | } |
230 | } |
231 | if (hasErrors) |
232 | return; |
233 | else if (hasWarnings) |
234 | this.setMessage(e.getIssuesList().get(0).getMessage(), IMessageProvider.WARNING); |
235 | } catch (Exception e) { |
236 | showInputInvalidInfo(e); |
237 | return; |
238 | } |
239 | this.getButton(IDialogConstants.OK_ID).setEnabled(true); |
240 | if (!hasErrors) |
241 | this.setErrorMessage(null); |
242 | if (!hasWarnings) |
243 | this.setMessage(null); |
244 | result = value; |
245 | resultText = this.textViewer.getDocument().get(); |
246 | } |
247 | |
248 | private void showInputWarning(IIssue ex) { |
249 | fAnnotationModel.addAnnotation( |
250 | new Annotation(WARNING_TYPE, false, |
251 | ex.getMessage()), |
252 | new Position(0, textViewer.getDocument().getLength())); |
253 | } |
254 | |
255 | protected abstract Lexer getLexer(String text); |
256 | protected abstract EObject parse(Lexer lexer) throws RecognitionException, StoExParserException; |
257 | |
258 | // private void showInputInvalidInfo(TokenStreamException e,CharScanner scanner) { |
259 | // result = null; |
260 | // fAnnotationModel.addAnnotation( |
261 | // new Annotation(ERROR_TYPE, false, |
262 | // e.getMessage()), |
263 | // new Position(ParserHelper.positionToOffset(textViewer.getDocument(), scanner.getLine(), scanner.getColumn()),1)); |
264 | // this.getButton(IDialogConstants.OK_ID).setEnabled(false); |
265 | // this.setErrorMessage("Entered stochastic expression is invalid. Cause given: "+e.getMessage()); |
266 | // } |
267 | |
268 | /** |
269 | * @param e |
270 | */ |
271 | private void showInputInvalidInfo(Exception e) { |
272 | result = null; |
273 | fAnnotationModel.addAnnotation( |
274 | new Annotation(ERROR_TYPE, false, |
275 | e.getMessage() == null ? e.getClass().getName() : e.getMessage()), |
276 | guessPosition(e)); |
277 | this.getButton(IDialogConstants.OK_ID).setEnabled(false); |
278 | this.setErrorMessage("Entered stochastic expression is invalid. Cause given: "+e.getLocalizedMessage()); |
279 | } |
280 | |
281 | private void showInputInvalidInfo(ErrorEntry e) { |
282 | result = null; |
283 | fAnnotationModel.addAnnotation( |
284 | new Annotation(ERROR_TYPE, false, |
285 | e.getMessage()), |
286 | guessPosition(e.getEx())); |
287 | this.getButton(IDialogConstants.OK_ID).setEnabled(false); |
288 | this.setErrorMessage("Entered stochastic expression is invalid. Cause given: "+e.getMessage()); |
289 | } |
290 | |
291 | /** |
292 | * @param e |
293 | * @return |
294 | */ |
295 | private Position guessPosition(Exception e) { |
296 | if (e instanceof RecognitionException) |
297 | { |
298 | RecognitionException recException = (RecognitionException) e; |
299 | int col = recException.charPositionInLine; |
300 | int line = recException.line; |
301 | int offset = ParserHelper.positionToOffset(textViewer.getDocument(),line,col); |
302 | offset = offset < 0 ? 0 : offset; |
303 | return new Position(offset, textViewer.getDocument().getLength()-offset); |
304 | } |
305 | return new Position(0, textViewer.getDocument().getLength()); |
306 | } |
307 | |
308 | protected Object getResult() |
309 | { |
310 | return result; |
311 | } |
312 | |
313 | @Override |
314 | protected void configureShell(Shell newShell) { |
315 | super.configureShell(newShell); |
316 | newShell.setText(getTitle()); |
317 | } |
318 | |
319 | public String getResultText() { |
320 | return resultText; |
321 | } |
322 | } |
323 | |
324 | class AnnotationMarkerAccess implements IAnnotationAccess, |
325 | IAnnotationAccessExtension { |
326 | |
327 | public String getType(Annotation annotation) { |
328 | return annotation.getType(); |
329 | } |
330 | |
331 | public boolean isMultiLine(Annotation annotation) { |
332 | return true; |
333 | } |
334 | |
335 | public boolean isTemporary(Annotation annotation) { |
336 | return !annotation.isPersistent(); |
337 | } |
338 | |
339 | public String getTypeLabel(Annotation annotation) { |
340 | if (getType(annotation).equals(AbstractGrammerBasedEditDialog.ERROR_TYPE)) |
341 | return "Errors"; |
342 | if (getType(annotation).equals(AbstractGrammerBasedEditDialog.WARNING_TYPE)) |
343 | return "Warnings"; |
344 | return null; |
345 | } |
346 | |
347 | public int getLayer(Annotation annotation) { |
348 | return 0; |
349 | } |
350 | |
351 | public void paint(Annotation annotation, GC gc, Canvas canvas, |
352 | Rectangle bounds) { |
353 | if (getType(annotation).equals(AbstractGrammerBasedEditDialog.ERROR_TYPE)) |
354 | ImageUtilities.drawImage( |
355 | DialogsImages.imageRegistry.get(DialogsImages.ERROR),gc,canvas,bounds,SWT.CENTER); |
356 | else if (getType(annotation).equals(AbstractGrammerBasedEditDialog.WARNING_TYPE)) |
357 | ImageUtilities.drawImage( |
358 | DialogsImages.imageRegistry.get(DialogsImages.WARNING),gc,canvas,bounds,SWT.CENTER); |
359 | } |
360 | |
361 | public boolean isPaintable(Annotation annotation) { |
362 | return true; |
363 | } |
364 | |
365 | public boolean isSubtype(Object annotationType, Object potentialSupertype) { |
366 | if (annotationType.equals(potentialSupertype)) |
367 | return true; |
368 | |
369 | return false; |
370 | } |
371 | |
372 | public Object[] getSupertypes(Object annotationType) { |
373 | return new Object[0]; |
374 | } |
375 | } |