package damp.ekeko.snippets.gui; import java.awt.HeadlessException; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.net.URI; import java.util.List; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.commands.operations.UndoContext; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.operations.UndoRedoActionGroup; import org.eclipse.ui.part.EditorPart; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.texteditor.ITextEditor; import baristaui.util.MarkerUtility; import clojure.lang.IFn; import damp.ekeko.JavaProjectModel; import damp.ekeko.snippets.EkekoSnippetsPlugin; import damp.ekeko.snippets.data.TemplateGroup; public class TemplateEditor extends EditorPart { public static final String ID = "damp.ekeko.snippets.gui.TemplateEditor"; //$NON-NLS-1$ //private String viewID; private TemplateGroup templateGroup; private TemplateGroupViewer templateGroupViewer; private TemplateTreeContentProvider contentProvider; //private OperatorOperandsViewer operatorOperandsViewer; //private BoundDirectivesViewer boundDirectivesViewer; //private String lastSelectedWorkspaceTextString; private ASTNode lastSelectedWorkspaceASTNode; private boolean isDirty = false; protected ToolBar toolBar; public static IFn FN_SNIPPET_ANCHOR; public static IFn FN_SNIPPET_VALUE_ANCHOR_RESOLVED; private ToolItem tltmRemove; private ToolItem tltmEditBoundDirectives; private ToolItem tltmRevealAnchor; private IUndoContext templateEditorUndoContext; private UndoRedoActionGroup templateEditorHistoryActionGroup; public TemplateEditor() { templateGroup = TemplateGroup.newFromGroupName("Anonymous Template Group"); } public void setGroup(TemplateGroup group) { templateGroup = group; refreshWidgets(); } public TemplateGroupViewer getTemplateGroupViewer() { return templateGroupViewer; } public TemplateGroup getGroup() { return templateGroup; } public IUndoContext getUndoContext() { return templateEditorUndoContext; } /** * Create contents of the view part. * @param parent */ @Override public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(1, false)); toolBar = new ToolBar(parent, SWT.FLAT | SWT.RIGHT); toolBar.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); ToolItem tltmAdd = new ToolItem(toolBar, SWT.NONE); tltmAdd.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addSnippet(); } }); tltmAdd.setImage(EkekoSnippetsPlugin.IMG_ADD); tltmAdd.setToolTipText("Add template"); ToolItem tltmAddFromText = new ToolItem(toolBar, SWT.NONE); tltmAddFromText.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { try { String data[] = {(String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor)}; System.out.println(data[0]); Object nodes = TemplateGroup.parseStringsToNodes(data); ASTNode node = ((List<ASTNode>) nodes).get(0); templateGroup.addSnippetCode(node); templateGroupViewer.clearSelection(); refreshWidgets(); becomeDirty(); } catch (Exception e1) { e1.printStackTrace(); } } }); tltmAddFromText.setImage(EkekoSnippetsPlugin.IMG_ADD); tltmAddFromText.setToolTipText("Add template from clipboard"); tltmRemove = new ToolItem(toolBar, SWT.NONE); tltmRemove.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeSnippet(); } }); tltmRemove.setImage(EkekoSnippetsPlugin.IMG_DELETE); tltmRemove.setDisabledImage(EkekoSnippetsPlugin.IMG_DELETE_DISABLED); tltmRemove.setToolTipText("Delete template"); tltmRemove.setEnabled(true); tltmEditBoundDirectives = new ToolItem(toolBar, SWT.NONE); tltmEditBoundDirectives.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { onEditBoundDirectives(templateGroup, templateGroupViewer.getSelectedSnippet(), templateGroupViewer.getSelectedSnippetNode()); } }); tltmEditBoundDirectives.setImage(EkekoSnippetsPlugin.IMG_TEMPLATE_EDIT); tltmEditBoundDirectives.setToolTipText("Edit directives of template element"); tltmEditBoundDirectives.setEnabled(false); tltmRevealAnchor = new ToolItem(toolBar, SWT.NONE); tltmRevealAnchor.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { revealProjectAnchor(); } }); tltmRevealAnchor.setImage(EkekoSnippetsPlugin.IMG_ANCHOR); tltmRevealAnchor.setToolTipText("Reveal project anchor"); tltmRevealAnchor.setEnabled(false); templateGroupViewer = new TemplateGroupViewer(parent, SWT.NONE); templateGroupViewer.setParentTemplateEditor(this); GridData gd_templateGroupViewer = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); gd_templateGroupViewer.heightHint = 400; templateGroupViewer.setLayoutData(gd_templateGroupViewer); templateGroupViewer.setInput(templateGroup, null, null); templateGroupViewer.addNodeSelectionListener(new TemplateGroupViewerNodeSelectionListener() { @Override public void nodeSelected(TemplateGroupViewerNodeSelectionEvent event) { onNodeSelected(event); } }); /* Group snippetOperatorGroup = new Group(container, SWT.NONE); snippetOperatorGroup.setLayout(new GridLayout(1, false)); ToolBar snippetOperatorGroupToolbar = new ToolBar(snippetOperatorGroup, SWT.FLAT | SWT.RIGHT); snippetOperatorGroupToolbar.setOrientation(SWT.RIGHT_TO_LEFT); snippetOperatorGroupToolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1)); Label lblOperator = new Label(snippetOperatorGroup, SWT.NONE); GridData gd_lblOperator = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); gd_lblOperator.heightHint = 22; lblOperator.setLayoutData(gd_lblOperator); lblOperator.setText(""); */ /* ToolItem tltmApplyOperator = new ToolItem(snippetOperatorGroupToolbar, SWT.NONE); tltmApplyOperator.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { onApplyOperator(); } }); tltmApplyOperator.setImage(ResourceManager.getPluginImage("org.eclipse.pde.ui", "/icons/etool16/validate.gif")); tltmApplyOperator.setToolTipText("Apply Operator"); */ /* ToolItem undoOperator = new ToolItem(snippetOperatorGroupToolbar, SWT.NONE); undoOperator.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { undo(); } }); undoOperator.setImage(ResourceManager.getPluginImage("org.eclipse.ui", "/icons/full/etool16/undo_edit.gif")); undoOperator.setToolTipText("Undo operator application"); ToolItem redoOperator = new ToolItem(snippetOperatorGroupToolbar, SWT.NONE); redoOperator.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { redo(); } }); redoOperator.setImage(ResourceManager.getPluginImage("org.eclipse.ui", "/icons/full/etool16/redo_edit.gif")); redoOperator.setToolTipText("Redo operator application"); */ /* operatorOperandsViewer = new OperatorOperandsViewer(snippetOperatorGroup, SWT.NONE); GridData gd_operatorOperandsViewer = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); gd_operatorOperandsViewer.heightHint = 297; operatorOperandsViewer.setLayoutData(gd_operatorOperandsViewer); */ /* boundDirectivesViewer = new BoundDirectivesViewer(snippetOperatorGroup, SWT.NONE); GridData gd_boundDirectivesViewer = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); gd_boundDirectivesViewer.heightHint = 297; boundDirectivesViewer.setLayoutData(gd_boundDirectivesViewer); templateGroupViewer.addNodeSelectionListener(new TemplateGroupViewerNodeSelectionListener() { @Override public void nodeSelected(TemplateGroupViewerNodeSelectionEvent event) { //event.getSelectedTemplateGroup(); //event.getSelectedTemplate(); //event.getSelectedTemplateNode(); updateOperators(); updateBoundDirectives(); } }); */ templateGroupViewer.addNodeDoubleClickListener(new TemplateGroupViewerNodeDoubleClickListener() { @Override public void nodeDoubleClicked(TemplateGroupViewerNodeSelectionEvent event) { onEditBoundDirectives(event.getSelectedTemplateGroup(), event.getSelectedTemplate(), event.getSelectedTemplateNode()); } }); ISelectionListener sl = new ISelectionListener() { @Override public void selectionChanged(IWorkbenchPart part, ISelection sel) { /* if(sel instanceof ITextSelection) { ITextSelection lastSelectedText = (ITextSelection) sel; if(!lastSelectedText.isEmpty()) lastSelectedWorkspaceTextString = lastSelectedText.getText(); } */ refreshWorkspaceSelection(part, sel); } }; //code also listen for JavaEditor selections only (JavaUI.ID_CU_EDITOR), //but people might be using different editors (e.g., WindowBuilder) getSite().getPage().addSelectionListener(sl); //does not work reliably, so reverting //getSite().setSelectionProvider(templateGroupViewer); try { IViewPart view = getSite().getPage().showView(OperatorOperandsView.ID); OperatorOperandsView operatorOperandsView = (OperatorOperandsView) view; operatorOperandsView.shouldRegisterAsListenerTo(templateGroupViewer); } catch (PartInitException e1) { e1.printStackTrace(); } } public static ASTNode resolvedProjectAnchorOfTemplateValue(Object template, Object templateValue) { if(templateValue == null || template == null) return null; Object anchor = FN_SNIPPET_VALUE_ANCHOR_RESOLVED.invoke(template, templateValue); if(!(anchor instanceof ASTNode)) return null; return (ASTNode) anchor; } public static Object projectAnchorOfTemplate(Object template) { if(template == null) return null; Object anchor = FN_SNIPPET_ANCHOR.invoke(template); return anchor; } protected void onNodeSelected(TemplateGroupViewerNodeSelectionEvent event) { Object selectedTemplate = event.getSelectedTemplate(); Object anchor = projectAnchorOfTemplate(selectedTemplate); if(anchor != null) { tltmRevealAnchor.setEnabled(true); } else { tltmRevealAnchor.setEnabled(false); } if(event.getSelectedTemplateNode() == null) { tltmRemove.setEnabled(false); tltmEditBoundDirectives.setEnabled(false); } else { tltmEditBoundDirectives.setEnabled(true); if(event.getSelectedTemplateNode().equals(TemplateGroup.getRootOfSnippet(event.getSelectedTemplate()))) tltmRemove.setEnabled(true); else tltmRemove.setEnabled(false); } } protected void revealProjectAnchor() { Object selectedSnippet = templateGroupViewer.getSelectedSnippet(); Object selectedSnippetNode = templateGroupViewer.getSelectedSnippetNode(); ASTNode anchorOfSelection = resolvedProjectAnchorOfTemplateValue(selectedSnippet, selectedSnippetNode); if(anchorOfSelection != null) { MarkerUtility.getInstance().createMarkerAndGoto(anchorOfSelection); } } //called by workspace listener protected void refreshWorkspaceSelection(IWorkbenchPart part, ISelection sel) { if(part instanceof IEditorPart) { IEditorPart editorPart = (IEditorPart) part; if(!(sel instanceof ITextSelection)) return; ITextSelection selection = (ITextSelection) sel; ITypeRoot typeRoot = JavaUI.getEditorInputTypeRoot(editorPart.getEditorInput()); if(typeRoot == null) return; ICompilationUnit icu = (ICompilationUnit) typeRoot.getAdapter(ICompilationUnit.class); if(icu == null) return; CompilationUnit cu = JavaProjectModel.parse(icu,null); if(cu == null) return; NodeFinder finder = new NodeFinder(cu, selection.getOffset(), selection.getLength()); lastSelectedWorkspaceASTNode = finder.getCoveringNode(); } } //manually called when view is opened for the first time public void setPreviouslyActiveEditor(IEditorPart activeEditor) { if(activeEditor instanceof ITextEditor) { ITextEditor textEditor = (ITextEditor) activeEditor; ITextSelection selection = (ITextSelection) textEditor.getSelectionProvider().getSelection(); if(selection != null) refreshWorkspaceSelection(textEditor, selection); } } protected void onEditBoundDirectives(TemplateGroup templateGroup, Object selectedTemplate, Object selectedNode) { BoundDirectivesEditorDialog dialog = new BoundDirectivesEditorDialog(getSite().getShell(), templateGroup, selectedTemplate, selectedNode); Object oldT = templateGroup.getGroup(); dialog.open(); Object newT = templateGroup.getGroup(); assert(!oldT.equals(newT)); refreshWidgets(); becomeDirty(); } @Override public void setFocus() { templateGroupViewer.setFocus(); } public TemplateTreeContentProvider getContentProvider() { return contentProvider; } /* public void setViewID(String secondaryId) { this.viewID = secondaryId; } */ public void addSnippet() { if (lastSelectedWorkspaceASTNode != null) { templateGroup.addSnippetCode(lastSelectedWorkspaceASTNode); templateGroupViewer.clearSelection(); refreshWidgets(); } becomeDirty(); } public void viewSnippet() { //removed plain snippet viewer //snippetGroup.viewSnippet(getSelectedSnippet()); } public void removeSnippet() { Object selected = templateGroupViewer.getSelectedSnippet(); if(selected == null) return; if(!MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "Delete template", "Are you sure you want to delete the selected template?")) return; templateGroup.removeSnippet(selected); templateGroupViewer.clearSelection(); refreshWidgets(); becomeDirty(); } /* public void viewQuery() { String query = templateGroup.getQuery(templateGroupViewer.getSelectedSnippet()); QueryInspectorDialog dlg = new QueryInspectorDialog(Display.getCurrent().getActiveShell(), "Query", query, "\nExecute the Query?", null, null); dlg.create(); if (dlg.open() == Window.OK) runQuery(); } */ public void runQuery() { templateGroup.runQuery(templateGroupViewer.getSelectedSnippet()); } protected void refreshWidgets() { templateGroupViewer.clearSelection(); templateGroupViewer.setInput(templateGroup, null, null); templateGroupViewer.updateWidgets(); } @Override public void doSave(IProgressMonitor monitor) { IEditorInput input = getEditorInput(); if(!(input instanceof TemplateEditorInput)) return; String absoluteFilePathString; ClojureFileEditorInput teinput = (ClojureFileEditorInput) input; if(!teinput.isAssociatedWithPersistentFile()) { FileDialog fileDialog = new FileDialog(getSite().getShell(), SWT.SAVE); fileDialog.setFilterExtensions(new String[] { "*.ekt" }); fileDialog.setFilterNames(new String[] { "Ekeko/X template file (*.ekt)" }); absoluteFilePathString = fileDialog.open(); if(absoluteFilePathString == null) return; teinput.setPathToPersistentFile(absoluteFilePathString); } else { absoluteFilePathString = teinput.getPathToPersistentFile(); } try { TemplateEditorInput.serializeClojureTemplateGroup(templateGroup.getGroup(), absoluteFilePathString); isDirty = false; firePropertyChange(IEditorPart.PROP_DIRTY); } catch (Exception e) { e.printStackTrace(); } } @Override public void doSaveAs() { IEditorInput input = getEditorInput(); if(!(input instanceof TemplateEditorInput)) return; TemplateEditorInput newInput = new TemplateEditorInput(); setInput(newInput); //fires no prop change, only sets field try { doSave(new NullProgressMonitor()); //serializes to new file updateInput(newInput); //deserializes from file } catch (Exception e) { e.printStackTrace(); setInput(input); } } private void updateInput(IEditorInput input) throws PartInitException { setPartName(input.getName()); if(input instanceof FileStoreEditorInput || input instanceof FileEditorInput) { String pathToFile = ""; if(input instanceof FileStoreEditorInput) { //outside workspace FileStoreEditorInput fileInput = (FileStoreEditorInput) input; URI uri = fileInput.getURI(); pathToFile = uri.getPath(); } else if(input instanceof FileEditorInput) { //within workspace FileEditorInput fileInput = (FileEditorInput) input; IFile ifile = fileInput.getFile(); pathToFile = ifile.getLocation().toString(); } else { setInput(new TemplateEditorInput()); return; } TemplateEditorInput actualInput = new TemplateEditorInput(); actualInput.setPathToPersistentFile(pathToFile); setInput(actualInput); try { Object clojureTemplateGroup = TemplateEditorInput.deserializeClojureTemplateGroup(pathToFile); this.templateGroup = TemplateGroup.newFromClojureGroup(clojureTemplateGroup); } catch (Exception e) { e.printStackTrace(); } return; } if(input instanceof TemplateEditorInput) { TemplateEditorInput actualInput = (TemplateEditorInput) input; if(actualInput.associatedPersistentFileExists()) { try { Object clojureTemplateGroup = TemplateEditorInput.deserializeClojureTemplateGroup(actualInput.getPathToPersistentFile()); this.templateGroup = TemplateGroup.newFromClojureGroup(clojureTemplateGroup); } catch (Exception e) { e.printStackTrace(); } } setInput(input); return; } throw new PartInitException("Unexpected input for TemplateEditor: " + input.toString()); } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { setSite(site); updateInput(input); templateEditorUndoContext = new UndoContext(); templateEditorHistoryActionGroup = new UndoRedoActionGroup(site, templateEditorUndoContext, true); templateEditorHistoryActionGroup.fillActionBars(site.getActionBars()); } @Override public boolean isDirty() { return isDirty; } @Override public boolean isSaveAsAllowed() { return true; } public void becomeDirty() { isDirty = true; firePropertyChange(IEditorPart.PROP_DIRTY); } public void becomeClean() { isDirty = false; firePropertyChange(IEditorPart.PROP_DIRTY); } /* @Override public void saveState(IMemento memento) { TemplateEditorInput input = (TemplateEditorInput) getEditorInput(); IMemento storedTemplate = memento.createChild("Template"); storedTemplate.putString("TemplateFilePath", input.getPathToPersistentFile()); } @Override public void restoreState(IMemento memento) { storedTemplate.putString("TemplateFilePath", input.getPathToPersistentFile()); } */ }