/*******************************************************************************
* Copyright (c) 2009, 2010 Innovation Gate GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Innovation Gate GmbH - initial API and implementation
******************************************************************************/
package de.innovationgate.eclipse.editors.tml;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import de.innovationgate.eclipse.editors.Plugin;
import de.innovationgate.eclipse.editors.ResourceIDs;
import de.innovationgate.eclipse.editors.all.InvalidCharacterCompletionProposal;
import de.innovationgate.eclipse.editors.all.WGADesignResourceValidator;
import de.innovationgate.eclipse.editors.design.wizards.NewWGAPortlet;
import de.innovationgate.eclipse.editors.helpers.MarkerFactory;
import de.innovationgate.eclipse.editors.helpers.TextStyles;
import de.innovationgate.eclipse.editors.tml.markers.ReferenceValidator;
import de.innovationgate.eclipse.editors.tml.markers.TMLLabelTagValidator;
import de.innovationgate.eclipse.editors.tmlscript.NonRuleBasedDamagerRepairer;
import de.innovationgate.eclipse.editors.tmlscript.TMLScriptPartitionScanner;
import de.innovationgate.eclipse.editors.tmlscript.TMLScriptScanner;
import de.innovationgate.eclipse.utils.WorkbenchUtils;
import de.innovationgate.eclipse.utils.ui.SingleStructuredSelection;
import de.innovationgate.eclipse.utils.wga.WGADesignStructureHelper;
public class TMLEditorConfiguration extends TextSourceViewerConfiguration {
private ContentAssistant _contentAssistent = null;
private TMLStartTagContentScanner _tagStartTagContentScanner = new TMLStartTagContentScanner();
private TMLEndTagContentScanner _tagEndTagContentScanner = new TMLEndTagContentScanner();
private TagScanner _tagScanner = new TagScanner();
private TMLScriptScanner _tmlScriptScanner = new TMLScriptScanner();
public TMLEditorConfiguration() {
Plugin.getDefault().getContextInformationProvider().reset();
}
@Override
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
_contentAssistent = new ContentAssistant();
_contentAssistent.enableAutoActivation(true);
_contentAssistent.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
_contentAssistent.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE);
_contentAssistent.setInformationControlCreator(getInformationControlCreator(sourceViewer));
_contentAssistent.setRepeatedInvocationMode(true);
_contentAssistent.setRepeatedInvocationTrigger(KeySequence.getInstance(KeyStroke.getInstance('\r')));
TMLContentAssistProcessor tmlContentAssistProcessor = new TMLContentAssistProcessor();
_contentAssistent.setContentAssistProcessor(tmlContentAssistProcessor, TMLPartitionScanner.TML_TAG_START);
_contentAssistent.setContentAssistProcessor(tmlContentAssistProcessor, IDocument.DEFAULT_CONTENT_TYPE);
CloseTagContentAssistProcessor closeTagContentAssistProcessor = new CloseTagContentAssistProcessor();
_contentAssistent.setContentAssistProcessor(closeTagContentAssistProcessor, TMLPartitionScanner.TML_TAG_STOP);
_contentAssistent.setContentAssistProcessor(closeTagContentAssistProcessor, TMLPartitionScanner.TML_COMMENT);
_contentAssistent.setContentAssistProcessor(closeTagContentAssistProcessor, TMLPartitionScanner.TML_DISABLE);
TMLScriptContentAssistProcessor tmlScriptContentAssistProcessor = new TMLScriptContentAssistProcessor();
_contentAssistent.setContentAssistProcessor(tmlScriptContentAssistProcessor, TMLScriptPartitionScanner.TMLSCRIPT);
_contentAssistent.enablePrefixCompletion(true);
//TMLCommentPartitionContentAssistProcessor tmlCommentPartitionContentAssistProcessor = new TMLCommentPartitionContentAssistProcessor();
//_contentAssistent.setContentAssistProcessor(tmlCommentPartitionContentAssistProcessor, TMLPartitionScanner.TML_COMMENT);
//TMLDisablePartitionContentAssistProcessor tmlDisablePartitionContentAssistProcessor = new TMLDisablePartitionContentAssistProcessor();
//_contentAssistent.setContentAssistProcessor(tmlDisablePartitionContentAssistProcessor, TMLPartitionScanner.TML_DISABLE);
// TODO add preferences field for activation delay
_contentAssistent.setAutoActivationDelay(250);
return _contentAssistent;
}
public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
List<String> contentTypes = new ArrayList<String>();
contentTypes.addAll(Arrays.asList(TMLPartitionScanner.PARTITIONS));
contentTypes.add(IDocument.DEFAULT_CONTENT_TYPE);
return contentTypes.toArray(new String[0]);
}
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
PresentationReconciler reconciler = new PresentationReconciler();
DefaultDamagerRepairer dr = null;
dr = new DefaultDamagerRepairer(_tagScanner);
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
dr = new DefaultDamagerRepairer(_tagStartTagContentScanner);
reconciler.setDamager(dr, TMLPartitionScanner.TML_TAG_START);
reconciler.setRepairer(dr, TMLPartitionScanner.TML_TAG_START);
dr = new DefaultDamagerRepairer(_tagEndTagContentScanner);
reconciler.setDamager(dr, TMLPartitionScanner.TML_TAG_STOP);
reconciler.setRepairer(dr, TMLPartitionScanner.TML_TAG_STOP);
dr = new DefaultDamagerRepairer(_tmlScriptScanner);
reconciler.setDamager(dr, TMLScriptPartitionScanner.TMLSCRIPT);
reconciler.setRepairer(dr, TMLScriptPartitionScanner.TMLSCRIPT);
NonRuleBasedDamagerRepairer ndr = new NonRuleBasedDamagerRepairer(TextStyles.COMMENT);
reconciler.setDamager(ndr, TMLPartitionScanner.COMMENT);
reconciler.setRepairer(ndr, TMLPartitionScanner.COMMENT);
ndr = new NonRuleBasedDamagerRepairer(TextStyles.COMMENT);
reconciler.setDamager(ndr, TMLPartitionScanner.TML_COMMENT);
reconciler.setRepairer(ndr, TMLPartitionScanner.TML_COMMENT);
ndr = new NonRuleBasedDamagerRepairer(TextStyles.COMMENT);
reconciler.setDamager(ndr, TMLScriptPartitionScanner.MCOMMENT);
reconciler.setRepairer(ndr, TMLScriptPartitionScanner.MCOMMENT);
ndr = new NonRuleBasedDamagerRepairer(TextStyles.COMMENT);
reconciler.setDamager(ndr, TMLScriptPartitionScanner.SCOMMENT);
reconciler.setRepairer(ndr, TMLScriptPartitionScanner.SCOMMENT);
ndr = new NonRuleBasedDamagerRepairer(TextStyles.DISABLED);
reconciler.setDamager(ndr, TMLPartitionScanner.TML_DISABLE);
reconciler.setRepairer(ndr, TMLPartitionScanner.TML_DISABLE);
ndr = new NonRuleBasedDamagerRepairer(TextStyles.TML_METAHEADER);
reconciler.setDamager(ndr, TMLPartitionScanner.TML_METAHEADER);
reconciler.setRepairer(ndr, TMLPartitionScanner.TML_METAHEADER);
return reconciler;
}
@Override
public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
IHyperlinkDetector[] detectors = new IHyperlinkDetector[1];
detectors[0] = new TMLHyperlinkDetector();
return detectors;
}
@Override
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
return null;//new TMLTextHover();
}
@Override
public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
IQuickAssistAssistant assistant = new QuickAssistAssistant();
assistant.setQuickAssistProcessor(new IQuickAssistProcessor() {
public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
return false;
}
public boolean canFix(Annotation annotation) {
boolean canFix = false;
if (annotation instanceof MarkerAnnotation) {
MarkerAnnotation markerAnnotation = (MarkerAnnotation) annotation;
try {
if (markerAnnotation.getMarker().getType().equals(ResourceIDs.MARKER_TML_REFERENCES)) {
String refType = markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_REFERENCE_TYPE, "");
canFix = refType.equals(ReferenceValidator.REFERENCE_TYPE_TML) || refType.equals(ReferenceValidator.REFERENCE_TYPE_SCRIPT);
} else if (markerAnnotation.getMarker().getType().equals(ResourceIDs.MARKER_TML_LABEL)) {
return true;
} else if (markerAnnotation.getMarker().getType().equals(ResourceIDs.MARKER_INVALID_CHARACTER)) {
return InvalidCharacterCompletionProposal.canCorrect(markerAnnotation);
}
} catch (CoreException e) {;
}
}
return canFix;
}
public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) {
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
MarkerAnnotation markerAnnotation = MarkerFactory.findMarkerAnnotationByTypeAndOffset(ResourceIDs.MARKER_TML_REFERENCES, invocationContext.getOffset(), invocationContext.getSourceViewer());
if (markerAnnotation != null && markerAnnotation.isQuickFixable()) {
String refType = markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_REFERENCE_TYPE, "");
boolean isPortletReference = markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_IS_PORTLET_REFERENCE, false);
if (refType.equals(ReferenceValidator.REFERENCE_TYPE_TML)) {
proposals.add(new CreateTMLFileReferenceCompletionProposal(markerAnnotation));
if (isPortletReference) {
// check if we can handle this missing portlet reference with our wizzard
String ref = markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_MISSING_REFERENCE_PATH, null);
if (ref != null && ref.endsWith("/portlet.tml")) {
String[] parts = ref.split("/");
if (parts.length > 1) {
String portletNameToCreate = parts[parts.length - 2];
proposals.add(new CreateTMLPortletReferenceCompletionProposal(markerAnnotation, portletNameToCreate));
}
}
}
} else if (refType.equals(ReferenceValidator.REFERENCE_TYPE_SCRIPT)) {
proposals.add(new CreateScriptFileReferenceCompletionProposal(markerAnnotation));
}
}
markerAnnotation = MarkerFactory.findMarkerAnnotationByTypeAndOffset(ResourceIDs.MARKER_TML_LABEL, invocationContext.getOffset(), invocationContext.getSourceViewer());
if (markerAnnotation != null && markerAnnotation.isQuickFixable()) {
proposals.add(new CreateTMLLabelCompletionProposal(markerAnnotation));
}
markerAnnotation = MarkerFactory.findMarkerAnnotationByTypeAndOffset(ResourceIDs.MARKER_INVALID_CHARACTER, invocationContext.getOffset(), invocationContext.getSourceViewer());
if (markerAnnotation != null && markerAnnotation.isQuickFixable()) {
InvalidCharacterCompletionProposal proposal = new InvalidCharacterCompletionProposal(markerAnnotation);
proposals.add(proposal);
}
return proposals.toArray(new ICompletionProposal[0]);
}
public String getErrorMessage() {
return null;
}
});
assistant.install(sourceViewer);
return assistant;
}
private class CreateTMLFileReferenceCompletionProposal implements ICompletionProposal {
private MarkerAnnotation _markerAnnotation;
private String _refPath;
public CreateTMLFileReferenceCompletionProposal(MarkerAnnotation markerAnnotation) {
_markerAnnotation = markerAnnotation;
_refPath = _markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_MISSING_REFERENCE_PATH, "");
}
public void apply(IDocument document) {
IResource resource = _markerAnnotation.getMarker().getResource();
if (resource instanceof IFile) {
IFile referer = (IFile) resource;
IFolder tmlFolder = new WGADesignStructureHelper(referer).getTmlRoot();
IFile fileToCreate = tmlFolder.getFile(new Path(_refPath));
if (!fileToCreate.exists()) {
try {
// mkdir
IContainer parent = fileToCreate.getParent();
List<IFolder> foldersToCreate = new ArrayList<IFolder>();
while (!parent.exists()) {
if (parent instanceof IFolder) {
foldersToCreate.add((IFolder)parent);
}
parent = parent.getParent();
}
for (int i=foldersToCreate.size() - 1; i >= 0; i--) {
foldersToCreate.get(i).create(false, true, new NullProgressMonitor());
}
// create tml file
String header = Plugin.getDefault().getHeaderFileMap().get(Plugin.HEADER_TML_MODUL).getHeaderForProject(fileToCreate.getProject());
fileToCreate.create(new ByteArrayInputStream(header.getBytes()), true, new NullProgressMonitor());
// open editor
WorkbenchUtils.openEditor(Plugin.getDefault().getWorkbench(), fileToCreate, ResourceIDs.EDITOR_TML);
} catch (CoreException e) {
}
}
}
}
public String getAdditionalProposalInfo() {
return null;
}
public IContextInformation getContextInformation() {
return null;
}
public String getDisplayString() {
return "create tml file '" + _refPath + "'";
}
public Image getImage() {
return Plugin.getDefault().getImageRegistry().get(Plugin.IMAGE_TML_FILE_CREATE);
}
public Point getSelection(IDocument document) {
return null;
}
}
private class CreateTMLPortletReferenceCompletionProposal implements ICompletionProposal {
private MarkerAnnotation _markerAnnotation;
private String _refPath;
private String _portletNameToCreate;
public CreateTMLPortletReferenceCompletionProposal(MarkerAnnotation markerAnnotation, String portletNameToCreate) {
_markerAnnotation = markerAnnotation;
_refPath = _markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_MISSING_REFERENCE_PATH, "");
_portletNameToCreate = portletNameToCreate;
}
public void apply(IDocument document) {
IWorkbench workbench = Plugin.getDefault().getWorkbench();
NewWGAPortlet wizard = new NewWGAPortlet();
wizard.setDefaultPortletName(_portletNameToCreate);
IEditorPart editorPart = workbench.getActiveWorkbenchWindow().getActivePage().getActiveEditor();
if (editorPart != null && editorPart.getEditorInput() instanceof FileEditorInput) {
FileEditorInput input = (FileEditorInput) editorPart.getEditorInput();
wizard.init(workbench, new SingleStructuredSelection(input.getFile().getParent()));
WizardDialog dialog = new WizardDialog(workbench.getActiveWorkbenchWindow().getShell(), wizard);
dialog.open();
}
}
public String getAdditionalProposalInfo() {
return null;
}
public IContextInformation getContextInformation() {
return null;
}
public String getDisplayString() {
return "create tml-portlet '" + _portletNameToCreate + "'";
}
public Image getImage() {
return Plugin.getDefault().getImageRegistry().get(Plugin.IMAGE_TML_PORTLET_CREATE);
}
public Point getSelection(IDocument document) {
return null;
}
}
private class CreateScriptFileReferenceCompletionProposal implements ICompletionProposal {
private MarkerAnnotation _markerAnnotation;
private String _refPath;
public CreateScriptFileReferenceCompletionProposal(MarkerAnnotation markerAnnotation) {
_markerAnnotation = markerAnnotation;
_refPath = _markerAnnotation.getMarker().getAttribute(ReferenceValidator.ATTRIBUTE_MISSING_REFERENCE_PATH, "");
}
public void apply(IDocument document) {
IResource resource = _markerAnnotation.getMarker().getResource();
if (resource instanceof IFile) {
IFile referer = (IFile) resource;
WGADesignStructureHelper helper = new WGADesignStructureHelper(referer);
IFolder scriptFolder = helper.getScriptsRoot();
IFile fileToCreate = scriptFolder.getFile(new Path(_refPath));
if (!fileToCreate.exists()) {
try {
// mkdir
IContainer parent = fileToCreate.getParent();
List<IFolder> foldersToCreate = new ArrayList<IFolder>();
while (!parent.exists()) {
if (parent instanceof IFolder) {
foldersToCreate.add((IFolder)parent);
}
parent = parent.getParent();
}
for (int i=foldersToCreate.size() - 1; i >= 0; i--) {
foldersToCreate.get(i).create(false, true, new NullProgressMonitor());
}
// create tml file
fileToCreate.create(new ByteArrayInputStream(new byte[0]), true, new NullProgressMonitor());
// open editor
WorkbenchUtils.openEditor(Plugin.getDefault().getWorkbench(), fileToCreate);
} catch (CoreException e) {
}
}
}
}
public String getAdditionalProposalInfo() {
return null;
}
public IContextInformation getContextInformation() {
return null;
}
public String getDisplayString() {
return "create script '" + _refPath + "'";
}
public Image getImage() {
return null;
}
public Point getSelection(IDocument document) {
return null;
}
}
private class CreateTMLLabelCompletionProposal implements ICompletionProposal {
private MarkerAnnotation _markerAnnotation;
private String _labelFilename;
private String _labelKey;
public CreateTMLLabelCompletionProposal(MarkerAnnotation markerAnnotation) {
_markerAnnotation = markerAnnotation;
_labelFilename = markerAnnotation.getMarker().getAttribute(TMLLabelTagValidator.ATTRIBUTE_LABELFILENAME, "general");
_labelKey = markerAnnotation.getMarker().getAttribute(TMLLabelTagValidator.ATTRIBUTE_LABELKEY, "");
}
public void apply(IDocument document) {
IResource resource = _markerAnnotation.getMarker().getResource();
if (resource instanceof IFile) {
IFile referer = (IFile) resource;
WGADesignStructureHelper helper = new WGADesignStructureHelper(referer);
try {
helper.createLabel(_labelFilename, _labelKey, "");
// revalidate tmlfile and open editor
WGADesignResourceValidator.validate(referer);
Plugin.getDefault().openLabelEditor(helper.getLabelFile(_labelFilename), _labelKey);
} catch (CoreException e) {
}
}
}
public String getAdditionalProposalInfo() {
return null;
}
public IContextInformation getContextInformation() {
return null;
}
public String getDisplayString() {
return "create label for key '" + _labelKey + "' in file '" + _labelFilename + "'.";
}
public Image getImage() {
return null;
}
public Point getSelection(IDocument document) {
return null;
}
}
/*
@Override
public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) {
ContentFormatter formatter = new ContentFormatter();
IFormattingStrategy strategy = new IFormattingStrategy() {
public String format(String content, boolean isLineStart, String indentation, int[] positions) {
System.out.println("format: " + content);
System.out.println(isLineStart);
//System.out.println(indentation);
return content;
}
public void formatterStarts(String initialIndentation) {
System.out.println("FormatterStarts: #" + initialIndentation + "#");
}
public void formatterStops() {
System.out.println("FormatterStops");
}
};
formatter.setFormattingStrategy(new XMLFormattingStrategy(), TMLPartitionScanner.TML_TAG_START);
formatter.setFormattingStrategy(new XMLFormattingStrategy(), TMLPartitionScanner.TML_TAG_STOP);
return formatter;
}*/
}