001: package org.drools.eclipse.dsl.editor;
002:
003: import java.io.File;
004: import java.io.FileWriter;
005: import java.io.IOException;
006: import java.io.InputStream;
007: import java.io.InputStreamReader;
008: import java.util.ArrayList;
009: import java.util.Iterator;
010: import java.util.List;
011:
012: import org.drools.eclipse.DroolsEclipsePlugin;
013: import org.drools.eclipse.builder.IDroolsModelMarker;
014: import org.drools.lang.dsl.DSLMappingEntry;
015: import org.drools.lang.dsl.DSLMappingFile;
016: import org.drools.lang.dsl.DefaultDSLMappingEntry;
017: import org.drools.lang.dsl.MappingError;
018: import org.eclipse.core.resources.IMarker;
019: import org.eclipse.core.resources.IResource;
020: import org.eclipse.core.resources.IWorkspace;
021: import org.eclipse.core.resources.IWorkspaceRunnable;
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.jface.viewers.IStructuredSelection;
025: import org.eclipse.jface.viewers.TableViewer;
026: import org.eclipse.swt.SWT;
027: import org.eclipse.swt.events.ModifyEvent;
028: import org.eclipse.swt.events.ModifyListener;
029: import org.eclipse.swt.events.MouseEvent;
030: import org.eclipse.swt.events.MouseListener;
031: import org.eclipse.swt.events.SelectionAdapter;
032: import org.eclipse.swt.events.SelectionEvent;
033: import org.eclipse.swt.events.SelectionListener;
034: import org.eclipse.swt.layout.GridData;
035: import org.eclipse.swt.layout.GridLayout;
036: import org.eclipse.swt.widgets.Button;
037: import org.eclipse.swt.widgets.Combo;
038: import org.eclipse.swt.widgets.Composite;
039: import org.eclipse.swt.widgets.Label;
040: import org.eclipse.swt.widgets.Table;
041: import org.eclipse.swt.widgets.TableColumn;
042: import org.eclipse.swt.widgets.Text;
043: import org.eclipse.ui.IEditorInput;
044: import org.eclipse.ui.IEditorSite;
045: import org.eclipse.ui.PartInitException;
046: import org.eclipse.ui.part.EditorPart;
047: import org.eclipse.ui.part.FileEditorInput;
048:
049: /**
050: * This is the tablular DSL configuration editor.
051: * @author Michael Neale
052: */
053: public class DSLEditor extends EditorPart {
054:
055: private Table table;
056: private TableViewer tableViewer;
057: private NLGrammarModel model; //this is the model that does all the work (from drools-compiler)
058: private boolean dirty = false; //editing or deleting will make it dirty
059: private Text exprText; //for language expression
060: private Text mappingText; //for target rule expression
061: private Text descriptionText; //just a comment field
062: private Text objText; // for the object name
063: private Combo sortCombo; // for the sort field
064:
065: public void doSave(IProgressMonitor monitor) {
066:
067: FileEditorInput input = (FileEditorInput) getEditorInput();
068: File outputFile = input.getFile().getLocation().toFile();
069: saveFile(monitor, outputFile, input);
070:
071: }
072:
073: private void saveFile(IProgressMonitor monitor, File outputFile,
074: FileEditorInput input) {
075: try {
076: validate(input);
077:
078: FileWriter writer = new FileWriter(outputFile);
079: DSLMappingFile.saveMapping(writer, model);
080:
081: makeClean();
082: writer.close();
083: input.getFile().getProject().refreshLocal(
084: IResource.DEPTH_INFINITE, monitor);
085: } catch (IOException e) {
086: throw new IllegalStateException(
087: "Unable to save DSL configuration file. (IOException: "
088: + e.getMessage() + ")");
089: } catch (CoreException e) {
090: throw new IllegalStateException(
091: "Unable to resync workbench after DSL save. (CoreException: "
092: + e.getMessage() + ")");
093: }
094: }
095:
096: private void validate(FileEditorInput input) {
097: removeProblemsFor(input.getFile());
098: List errs = new ArrayList();
099: for (Iterator iter = model.getEntries().iterator(); iter
100: .hasNext();) {
101: DSLMappingEntry item = (DSLMappingEntry) iter.next();
102: errs.addAll(item.getErrors());
103: }
104: if (errs.size() > 0) {
105: for (Iterator iter = errs.iterator(); iter.hasNext();) {
106: MappingError mapEr = (MappingError) iter.next();
107: createMarker(input.getFile(), mapEr.getMessage()
108: + " From [" + mapEr.getTemplateText() + "]",
109: -1);
110: }
111: }
112: }
113:
114: private void createMarker(final IResource res,
115: final String message, final int lineNumber) {
116: try {
117: IWorkspaceRunnable r = new IWorkspaceRunnable() {
118: public void run(IProgressMonitor monitor)
119: throws CoreException {
120: IMarker marker = res
121: .createMarker(IDroolsModelMarker.DROOLS_MODEL_PROBLEM_MARKER);
122: marker.setAttribute(IMarker.MESSAGE, message);
123: marker.setAttribute(IMarker.SEVERITY,
124: IMarker.SEVERITY_WARNING);
125: marker
126: .setAttribute(IMarker.LINE_NUMBER,
127: lineNumber);
128: }
129: };
130: res.getWorkspace().run(r, null, IWorkspace.AVOID_UPDATE,
131: null);
132: } catch (CoreException e) {
133: DroolsEclipsePlugin.log(e);
134: }
135: }
136:
137: private void removeProblemsFor(IResource resource) {
138: try {
139: if (resource != null && resource.exists()) {
140: resource.deleteMarkers(
141: IDroolsModelMarker.DROOLS_MODEL_PROBLEM_MARKER,
142: false, IResource.DEPTH_INFINITE);
143: }
144: } catch (CoreException e) {
145: DroolsEclipsePlugin.log(e);
146: }
147: }
148:
149: void makeClean() {
150: this .dirty = false;
151: firePropertyChange(PROP_DIRTY);
152:
153: }
154:
155: public void doSaveAs() {
156: // TODO Implement this.
157: }
158:
159: public void init(IEditorSite site, IEditorInput editorInput)
160: throws PartInitException {
161: FileEditorInput input = (FileEditorInput) editorInput;
162: setSite(site);
163: setInput(editorInput);
164: setVisibleName(input);
165:
166: try {
167: InputStream stream = input.getFile().getContents();
168: model = new NLGrammarModel();
169: DSLMappingFile file = new DSLMappingFile();
170: file.parseAndLoad(new InputStreamReader(stream));
171: model.addEntries(file.getMapping().getEntries());
172: stream.close();
173:
174: } catch (CoreException e) {
175: throw new IllegalStateException(
176: "Unable to load DSL configuration file. (CoreException: "
177: + e.getMessage() + ")");
178: } catch (IOException e) {
179: throw new IllegalStateException(
180: "Unabel to close stream fo DSL config file. (IOException: "
181: + e.getMessage() + ")");
182: }
183:
184: }
185:
186: private void setVisibleName(FileEditorInput input) {
187: setPartName(input.getFile().getName());
188: setContentDescription("Editing Domain specific language: ["
189: + input.getFile().getFullPath().toString() + "]");
190: }
191:
192: public boolean isDirty() {
193: return dirty;
194: }
195:
196: /**
197: * Sets the dirty flag, and notifies the workbench.
198: */
199: void makeDirty() {
200: dirty = true;
201: firePropertyChange(PROP_DIRTY);
202: }
203:
204: /**
205: * The method sorts th e
206: *
207: */
208: public void sortModel() {
209: if (sortCombo.getSelectionIndex() == DSLMappingSorter.EXPRESSION) {
210: tableViewer.setSorter(new DSLMappingSorter(
211: DSLMappingSorter.EXPRESSION));
212: } else if (sortCombo.getSelectionIndex() == DSLMappingSorter.OBJECT) {
213: tableViewer.setSorter(new DSLMappingSorter(
214: DSLMappingSorter.OBJECT));
215: } else if (sortCombo.getSelectionIndex() == DSLMappingSorter.SCOPE) {
216: tableViewer.setSorter(new DSLMappingSorter(
217: DSLMappingSorter.SCOPE));
218: } else if (sortCombo.getSelectionIndex() == DSLMappingSorter.MAPPING) {
219: tableViewer.setSorter(new DSLMappingSorter(
220: DSLMappingSorter.MAPPING));
221: }
222: }
223:
224: public boolean isSaveAsAllowed() {
225: // TODO implement SaveAs
226: return false;
227: }
228:
229: public void createPartControl(Composite parent) {
230:
231: GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
232: | GridData.FILL_BOTH);
233: parent.setLayoutData(gridData);
234:
235: // Set numColumns to 3 in the overall grid
236: GridLayout layout = new GridLayout(3, false);
237: layout.marginWidth = 4;
238: parent.setLayout(layout);
239:
240: //create the overall desc field (comments).
241: createDescriptionField(parent);
242:
243: // create the table
244: createTable(parent);
245:
246: // Create and setup the TableViewer
247: createTableViewer();
248:
249: //set up the table "binding" with the model
250: tableViewer.setContentProvider(new DSLContentProvider(
251: tableViewer, model));
252: tableViewer.setLabelProvider(new DSLLabelProvider());
253: refreshModel();
254:
255: //setup the fields below the table
256: createExpressionViewField(parent);
257: createEditButton(parent);
258: createMappingViewField(parent);
259: createDeleteButton(parent);
260: createObjectViewField(parent);
261: createAddButton(parent);
262: createSortField(parent);
263: createSortButton(parent);
264: createCopyButton(parent);
265:
266: //listeners on the table...
267: createTableListeners();
268:
269: }
270:
271: /**
272: * Setup table listeners for GUI events.
273: */
274: private void createTableListeners() {
275:
276: //setup views into current selected
277: table.addSelectionListener(new SelectionListener() {
278:
279: public void widgetSelected(SelectionEvent e) {
280: populate();
281: }
282:
283: public void widgetDefaultSelected(SelectionEvent e) {
284: populate();
285: }
286:
287: private void populate() {
288: DSLMappingEntry selected = getCurrentSelected();
289: exprText.setText(selected.getMappingKey());
290: mappingText.setText(selected.getMappingValue());
291: objText
292: .setText(selected.getMetaData().getMetaData() == null ? ""
293: : selected.getMetaData().getMetaData());
294: }
295:
296: });
297:
298: //double click support
299: table.addMouseListener(new MouseListener() {
300:
301: public void mouseDoubleClick(MouseEvent e) {
302: showEditPopup();
303: }
304:
305: public void mouseDown(MouseEvent e) {
306: }
307:
308: public void mouseUp(MouseEvent e) {
309: }
310:
311: });
312:
313: }
314:
315: private void createDescriptionField(Composite parent) {
316: Label descLbl = new Label(parent, SWT.NONE);
317: descLbl.setText("Description:");
318: GridData gridData = new GridData(
319: GridData.HORIZONTAL_ALIGN_BEGINNING);
320: gridData.widthHint = 80;
321: descLbl.setLayoutData(gridData);
322:
323: descriptionText = new Text(parent, SWT.BORDER);
324: descriptionText.setLayoutData(new GridData(
325: GridData.FILL_HORIZONTAL));
326: descriptionText.setText(model.getDescription() == null ? ""
327: : model.getDescription());
328: descriptionText.addModifyListener(new ModifyListener() {
329:
330: public void modifyText(ModifyEvent e) {
331: String text = descriptionText.getText();
332: if (!text.equals(model.getDescription())) {
333: model.setDescription(text);
334: makeDirty();
335: }
336: }
337:
338: });
339: }
340:
341: private void createMappingViewField(Composite parent) {
342: Label mapping = new Label(parent, SWT.NONE);
343: mapping.setText("Mapping:");
344: GridData gridData = new GridData(
345: GridData.HORIZONTAL_ALIGN_BEGINNING);
346: gridData.widthHint = 80;
347: mapping.setLayoutData(gridData);
348:
349: mappingText = new Text(parent, SWT.BORDER);
350: mappingText.setEditable(false);
351:
352: mappingText
353: .setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
354: }
355:
356: private void createExpressionViewField(Composite parent) {
357:
358: Label expr = new Label(parent, SWT.NONE);
359: expr.setText("Expression:");
360: GridData gridData = new GridData(
361: GridData.HORIZONTAL_ALIGN_BEGINNING);
362: gridData.widthHint = 80;
363: expr.setLayoutData(gridData);
364:
365: exprText = new Text(parent, SWT.BORDER);
366: exprText.setEditable(false);
367: gridData = new GridData(GridData.FILL_HORIZONTAL);
368:
369: exprText.setLayoutData(gridData);
370:
371: }
372:
373: private void createObjectViewField(Composite parent) {
374:
375: Label obj = new Label(parent, SWT.NONE);
376: obj.setText("Object:");
377: GridData gridData = new GridData(
378: GridData.HORIZONTAL_ALIGN_BEGINNING);
379: gridData.widthHint = 80;
380: obj.setLayoutData(gridData);
381:
382: objText = new Text(parent, SWT.BORDER);
383: objText.setEditable(false);
384: gridData = new GridData(GridData.FILL_HORIZONTAL);
385:
386: objText.setLayoutData(gridData);
387:
388: }
389:
390: private void createSortField(Composite parent) {
391: Label sort = new Label(parent, SWT.NONE);
392: sort.setText("Sort by:");
393: GridData gridData = new GridData(
394: GridData.HORIZONTAL_ALIGN_BEGINNING);
395: gridData.widthHint = 80;
396: sort.setLayoutData(gridData);
397:
398: sortCombo = new Combo(parent, SWT.READ_ONLY);
399: sortCombo.add("Object", DSLMappingSorter.OBJECT);
400: sortCombo.add("Language Expression",
401: DSLMappingSorter.EXPRESSION);
402: sortCombo
403: .add("Rule Language Mapping", DSLMappingSorter.MAPPING);
404: sortCombo.add("Scope", DSLMappingSorter.SCOPE);
405: gridData = new GridData(GridData.FILL_HORIZONTAL);
406:
407: sortCombo.setLayoutData(gridData);
408: }
409:
410: /** Refreshes the table do make sure it is up to date with the model. */
411: private void refreshModel() {
412: tableViewer.setInput(model);
413: }
414:
415: private void createEditButton(Composite parent) {
416: // Create and configure the "Add" button
417: Button add = new Button(parent, SWT.PUSH | SWT.CENTER);
418: add.setText("Edit");
419:
420: GridData gridData = new GridData(
421: GridData.HORIZONTAL_ALIGN_BEGINNING);
422: gridData.widthHint = 80;
423: add.setLayoutData(gridData);
424:
425: add.addSelectionListener(new SelectionAdapter() {
426:
427: // Add a task to the ExampleTaskList and refresh the view
428: public void widgetSelected(SelectionEvent e) {
429: showEditPopup();
430: }
431:
432: });
433: }
434:
435: private void showEditPopup() {
436: DSLMappingEntry selected = getCurrentSelected();
437: if (selected != null) {
438: MappingEditor editor = new MappingEditor(getSite()
439: .getShell());
440: editor.create();
441: editor.getShell().setText("Edit language mapping");
442: editor.setTitle("Edit an existing language mapping item.");
443: editor.setTitleImage(getTitleImage());
444:
445: editor.setNLMappingItem(selected);
446:
447: editor.open();
448: if (!editor.isCancelled()) {
449: refreshModel();
450: makeDirty();
451: }
452: }
453: }
454:
455: private void createDeleteButton(Composite parent) {
456: // Create and configure the "Add" button
457: Button add = new Button(parent, SWT.PUSH | SWT.CENTER);
458: add.setText("Remove");
459:
460: GridData gridData = new GridData(
461: GridData.HORIZONTAL_ALIGN_BEGINNING);
462: gridData.widthHint = 80;
463: add.setLayoutData(gridData);
464: add.addSelectionListener(new SelectionAdapter() {
465: // Add a task to the ExampleTaskList and refresh the view
466: public void widgetSelected(SelectionEvent e) {
467: model.removeEntry(getCurrentSelected());
468: refreshModel();
469: makeDirty();
470: exprText.setText("");
471: mappingText.setText("");
472: objText.setText("");
473: }
474: });
475: }
476:
477: private void createSortButton(Composite parent) {
478: // Create and configure the "Add" button
479: Button sort = new Button(parent, SWT.PUSH | SWT.CENTER);
480: sort.setText("Sort");
481:
482: GridData gridData = new GridData(
483: GridData.HORIZONTAL_ALIGN_BEGINNING);
484: gridData.widthHint = 80;
485: sort.setLayoutData(gridData);
486: sort.addSelectionListener(new SelectionAdapter() {
487: // Add a task to the ExampleTaskList and refresh the view
488: public void widgetSelected(SelectionEvent e) {
489: sortModel();
490: refreshModel();
491: makeDirty();
492: }
493:
494: });
495: }
496:
497: /**
498: * Return the selected item from the table grid thingy.
499: */
500: private DSLMappingEntry getCurrentSelected() {
501: return (DSLMappingEntry) ((IStructuredSelection) tableViewer
502: .getSelection()).getFirstElement();
503: }
504:
505: private void createAddButton(Composite parent) {
506: // Create and configure the "Add" button
507: Button add = new Button(parent, SWT.PUSH | SWT.CENTER);
508: add.setText("Add");
509:
510: GridData gridData = new GridData(
511: GridData.HORIZONTAL_ALIGN_BEGINNING);
512: gridData.widthHint = 80;
513: add.setLayoutData(gridData);
514:
515: add.addSelectionListener(new SelectionAdapter() {
516:
517: // Add an item, should pop up the editor
518: public void widgetSelected(SelectionEvent e) {
519:
520: DSLMappingEntry newItem = new DefaultDSLMappingEntry();
521:
522: MappingEditor editor = new MappingEditor(getSite()
523: .getShell());//shell);
524: editor.create();
525: editor.getShell().setText("New language mapping");
526: editor
527: .setTitle("Create a new language element mapping.");
528: editor.setTitleImage(getTitleImage());
529:
530: editor.setNLMappingItem(newItem);
531:
532: editor.open();
533: if (!editor.isCancelled()) {
534: model.addEntry(newItem);
535: refreshModel();
536: makeDirty();
537: }
538:
539: }
540: });
541: }
542:
543: private void createCopyButton(Composite parent) {
544: // Create and configure the "Add" button
545: Button copy = new Button(parent, SWT.PUSH | SWT.CENTER);
546: copy.setText("Copy");
547:
548: GridData gridData = new GridData(
549: GridData.HORIZONTAL_ALIGN_BEGINNING);
550: gridData.widthHint = 80;
551: copy.setLayoutData(gridData);
552:
553: copy.addSelectionListener(new SelectionAdapter() {
554:
555: // Add an item, should pop up the editor
556: public void widgetSelected(SelectionEvent e) {
557:
558: DSLMappingEntry curr = getCurrentSelected();
559: if (curr != null) {
560: DSLMappingEntry newItem = new DefaultDSLMappingEntry(
561: curr.getSection(), curr.getMetaData(), curr
562: .getMappingKey(), curr
563: .getMappingValue());
564:
565: MappingEditor editor = new MappingEditor(getSite()
566: .getShell());//shell);
567: editor.create();
568: editor.getShell().setText("New language mapping");
569: editor
570: .setTitle("Create a new language element mapping from a copy.");
571: editor.setTitleImage(getTitleImage());
572:
573: editor.setNLMappingItem(newItem);
574:
575: editor.open();
576: if (!editor.isCancelled()) {
577: model.addEntry(newItem);
578: refreshModel();
579: makeDirty();
580: }
581: }
582: }
583: });
584: }
585:
586: /**
587: * Create the viewer.
588: */
589: private void createTableViewer() {
590: tableViewer = new TableViewer(table);
591: tableViewer.setUseHashlookup(true);
592: //following is if we want default sorting... my thought is no...
593: }
594:
595: /**
596: * Create the Table
597: */
598: private void createTable(Composite parent) {
599: int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL
600: | SWT.V_SCROLL | SWT.FULL_SELECTION
601: | SWT.HIDE_SELECTION;
602:
603: table = new Table(parent, style);
604:
605: GridData gridData = new GridData(GridData.FILL_BOTH);
606: gridData.grabExcessVerticalSpace = true;
607: gridData.horizontalSpan = 3;
608: table.setLayoutData(gridData);
609:
610: table.setLinesVisible(true);
611: table.setHeaderVisible(true);
612:
613: TableColumn column;
614:
615: //Expression col
616: column = new TableColumn(table, SWT.LEFT, 0);
617: column.setText("Language Expression");
618: column.setWidth(350);
619: // Add listener to column so sorted when clicked
620: column.addSelectionListener(new SelectionAdapter() {
621:
622: public void widgetSelected(SelectionEvent e) {
623: tableViewer.setSorter(new DSLMappingSorter(
624: DSLMappingSorter.EXPRESSION));
625: }
626: });
627:
628: // 3rd column with task Owner
629: column = new TableColumn(table, SWT.LEFT, 1);
630: column.setText("Rule Language Mapping");
631: column.setWidth(200);
632: // Add listener to column so sorted when clicked
633: column.addSelectionListener(new SelectionAdapter() {
634:
635: public void widgetSelected(SelectionEvent e) {
636: tableViewer.setSorter(new DSLMappingSorter(
637: DSLMappingSorter.MAPPING));
638: }
639: });
640:
641: // 4th column with task PercentComplete
642: column = new TableColumn(table, SWT.LEFT, 2);
643: column.setText("Object");
644: column.setWidth(80);
645:
646: // 5th column with task PercentComplete
647: column = new TableColumn(table, SWT.LEFT, 3);
648: column.setText("Scope");
649: column.setWidth(80);
650:
651: // Add listener to column so tasks are sorted when clicked
652: column.addSelectionListener(new SelectionAdapter() {
653:
654: public void widgetSelected(SelectionEvent e) {
655: tableViewer.setSorter(new DSLMappingSorter(
656: DSLMappingSorter.SCOPE));
657: }
658: });
659:
660: }
661:
662: public void setFocus() {
663: }
664:
665: public void dispose() {
666: super.dispose();
667: }
668:
669: }
|