/*******************************************************************************
* Copyright © 2000, 2013 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.ui.internal.handlers;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.edt.ide.core.model.EGLCore;
import org.eclipse.edt.ide.core.model.IBuffer;
import org.eclipse.edt.ide.core.model.IEGLElement;
import org.eclipse.edt.ide.core.model.IEGLFile;
import org.eclipse.edt.ide.core.model.IRegion;
import org.eclipse.edt.ide.ui.EDTUIPlugin;
import org.eclipse.edt.ide.ui.internal.CodeFormatterUtil;
import org.eclipse.edt.ide.ui.internal.EGLUI;
import org.eclipse.edt.ide.ui.internal.UINlsStrings;
import org.eclipse.edt.ide.ui.internal.actions.WorkbenchRunnableAdapter;
import org.eclipse.edt.ide.ui.internal.codemanipulation.OrganizeImportsOperation.SyntaxErrorHelper;
import org.eclipse.edt.ide.ui.internal.dialogs.OptionalMessageDialog;
import org.eclipse.edt.ide.ui.internal.dialogs.ProblemDialog;
import org.eclipse.edt.ide.ui.internal.editor.DocumentAdapter;
import org.eclipse.edt.ide.ui.internal.editor.EGLEditor;
import org.eclipse.edt.ide.ui.internal.formatting.FormattingStrategy;
import org.eclipse.edt.ide.ui.internal.formatting.ui.ProfileManager;
import org.eclipse.edt.ide.ui.internal.util.EditorUtility;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.formatter.FormattingContext;
import org.eclipse.jface.text.formatter.FormattingContextProperties;
import org.eclipse.jface.text.formatter.IFormattingContext;
import org.eclipse.jface.text.formatter.MultiPassContentFormatter;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.texteditor.ITextEditor;
public class FormattingHandler extends EGLHandler {
private DocumentRewriteSession fRewriteSession;
private IRegion fPartialRegion = null;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// Initialize editor if called from EGL Editor
if(isInvokedFromEditorContext(event)){
IEditorPart editor = getCurrentActiveEditor( event );
if( editor instanceof EGLEditor ) {
fEditor = (EGLEditor)editor;
if(editor != null)
{
IEditorInput editorInput = editor.getEditorInput();
// Could be a VirtualEditorInput if coming from PageDesigners QEV
if (editorInput instanceof IFileEditorInput) {
IResource resource = ((IFileEditorInput) editorInput).getFile();
IEGLElement element = EGLCore.create(resource);
fSite = editor.getSite();
fSelection = new StructuredSelection( element );
}
}
}
}
if( fSelection != null )
{
run();
}
return null;
}
public void run() {
List eglFiles = getEGLFiles( fSelection );
int selCnt = eglFiles.size();
if( selCnt == 0 )
return;
if( selCnt > 1 && fSite != null ){
int returnCode = OptionalMessageDialog.open("EGLFormat", //$NON-NLS-1$
fSite.getShell(),
UINlsStrings.FormatTitle, null,
UINlsStrings.UndoNotSupportedMsg,
MessageDialog.WARNING,
new String[] {IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL}, 0);
if( returnCode != OptionalMessageDialog.NOT_SHOWN &&
returnCode != Window.OK ) {
return;
}
}
if( selCnt > 1 ) {
runOnMultiple( eglFiles, null );
} else {
runOnSingle((IEGLFile)eglFiles.get(0));
}
}
private void runOnMultiple(final List eglfiles, final String formatProfileName){
String message = UINlsStrings.FormatComplete;
final MultiStatus status = new MultiStatus( EDTUIPlugin.PLUGIN_ID, IStatus.OK, message, null );
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
try{
if(eglfiles.size() == 1){
Object eglFile = eglfiles.get(0);
EditorUtility.openInEditor(eglFile);
fileNeedsSave.put(eglFile, EditorUtility.isOpenInEditor(eglFile));
}
progressService.run(true, true, new WorkbenchRunnableAdapter(new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
doRunOnMultiple(eglfiles, formatProfileName, status, monitor);
}
}));
if(!status.isOK() && fSite != null){
String title = UINlsStrings.EGLFormatting;
ProblemDialog.open(fSite.getShell(), title, null, status);
}
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
//cancel by user
}
catch(CoreException ex){
ex.printStackTrace();
}
}
private void doRunOnMultiple(List eglfiles, String formatProfileName, MultiStatus status, IProgressMonitor monitor) throws OperationCanceledException{
if( monitor == null ) {
monitor = new NullProgressMonitor();
}
monitor.setTaskName( UINlsStrings.FormattingProgress );
int size = eglfiles.size();
monitor.beginTask("", size*4); //$NON-NLS-1$
try{
for(int i=0; i<size; i++){
if(monitor.isCanceled()) {
throw new OperationCanceledException();
}
IEGLFile eglfile = (IEGLFile)(eglfiles.get(i));
try {
SyntaxErrorHelper synErr = runFormat(eglfile, formatProfileName, monitor);
if(synErr != null){
String msg = UINlsStrings.bind( UINlsStrings.SyntaxError, new String[]{eglfile.getPath().makeRelative().toString()} );
status.add(new Status(IStatus.INFO, EDTUIPlugin.PLUGIN_ID, IStatus.ERROR, msg, null));
}
} catch (CoreException e) {
status.add(e.getStatus());
}
}
}
finally{
monitor.done();
}
}
private SyntaxErrorHelper runFormat(IEGLFile eglfile, String formatProfileName, IProgressMonitor monitor) throws CoreException{
IPath path = eglfile.getPath();
SyntaxErrorHelper synErr = null;
ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
boolean connectedTextBuffer = false;
IEGLFile workingCopy = null;
try{
Object editorpart = fileNeedsSave.get(eglfile);
boolean needSave = editorpart == null;
IDocument doc = null;
if(!needSave){//means the file is opened in an editor
if(editorpart instanceof EGLEditor ||
editorpart instanceof MultiPageEditorPart){
synchronized( eglfile ){
workingCopy = (IEGLFile)(eglfile.getSharedWorkingCopy(null, EGLUI.getBufferFactory(), null));
}
IBuffer buf = workingCopy.getBuffer();
if( buf instanceof DocumentAdapter ){
doc = ((DocumentAdapter)buf).getDocument();
}
}
}
ITextFileBuffer filebuffer = null;
if(doc == null){
manager.connect(path, new SubProgressMonitor(monitor, 1));
connectedTextBuffer = true;
filebuffer = manager.getTextFileBuffer(path);
doc = filebuffer.getDocument();
}
String filePathLocation = path.makeRelative().toString();
monitor.subTask(filePathLocation);
synErr = formatEGLFile(doc, formatProfileName, needSave);
//synErr = doFormat(doc, formatProfileName);
if(needSave && filebuffer != null && filebuffer.isDirty()){
filebuffer.commit(new SubProgressMonitor(monitor, 2), false);
}
else
monitor.worked(2);
}
finally{
if(workingCopy != null)
workingCopy.destroy();
if(connectedTextBuffer)
manager.disconnect(path, new SubProgressMonitor(monitor, 1));
}
return synErr;
}
private SyntaxErrorHelper formatEGLFile(final IDocument document, final String formatProfileName, final boolean needSave){
final SyntaxErrorHelper[] synErr = new SyntaxErrorHelper[1];
if(!needSave && fSite != null){
fSite.getShell().getDisplay().syncExec(new Runnable(){
public void run() {
synErr[0] = doFormat(document, formatProfileName);
}
});
}
else{
synErr[0] = doFormat(document, formatProfileName); //run in context thread
}
return synErr[0];
}
private SyntaxErrorHelper doFormat(IDocument document, String formatProfileName){
ProfileManager profileMgr = ProfileManager.getInstance();
//save the original selected profile
EObject originalSelProfile = profileMgr.getSelectedProfile();
Map options = CodeFormatterUtil.getFormattingOptionMapByProfileName(formatProfileName, profileMgr);
final IFormattingContext context = new FormattingContext();
FormattingStrategy eglFormattingStrategy = new FormattingStrategy();
try{
context.setProperty(FormattingContextProperties.CONTEXT_PREFERENCES, options);
if(fPartialRegion != null){
context.setProperty(FormattingContextProperties.CONTEXT_REGION, fPartialRegion);
context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.FALSE);
}
else
context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.TRUE);
final MultiPassContentFormatter formatter= new MultiPassContentFormatter(IDocumentExtension3.DEFAULT_PARTITIONING, IDocument.DEFAULT_CONTENT_TYPE);
formatter.setMasterStrategy(eglFormattingStrategy);;
try{
startSequentialRewriteMode(document);
formatter.format(document, context);
}
finally {
stopSequentialRewriteMode(document);
}
}
finally{
context.dispose();
//reset the current format profile selection back to its original
profileMgr.setSelectedProfile(originalSelProfile);
}
SyntaxErrorHelper synErr = eglFormattingStrategy.get1stSyntaxErrorMsg();
return synErr;
}
private void startSequentialRewriteMode(IDocument document) {
if (document instanceof IDocumentExtension4) {
IDocumentExtension4 extension= (IDocumentExtension4) document;
fRewriteSession= extension.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL);
} else if (document instanceof IDocumentExtension) {
IDocumentExtension extension= (IDocumentExtension) document;
extension.startSequentialRewrite(false);
}
}
private void stopSequentialRewriteMode(IDocument document) {
if (document instanceof IDocumentExtension4) {
IDocumentExtension4 extension= (IDocumentExtension4) document;
extension.stopRewriteSession(fRewriteSession);
} else if (document instanceof IDocumentExtension) {
IDocumentExtension extension= (IDocumentExtension)document;
extension.stopSequentialRewrite();
}
}
private void runOnSingle(final IEGLFile eglFile){
try
{
IEditorPart editor = EditorUtility.openInEditor(eglFile);
fileNeedsSave.put(eglFile, EditorUtility.isOpenInEditor(eglFile));
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
IRunnableContext context= fSite != null ? fSite.getWorkbenchWindow() : null;
if (context == null) {
context= progressService;
}
final SyntaxErrorHelper[] synErr = new SyntaxErrorHelper[1];
progressService.run(true, true,
new WorkbenchRunnableAdapter(new IWorkspaceRunnable(){
public void run(final IProgressMonitor monitor) throws CoreException {
synErr[0] = runFormat(eglFile, null, monitor);
}
}));
postRun(synErr[0], (editor instanceof ITextEditor) ? (ITextEditor)editor : null);
}
catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InterruptedException e) {
}
catch(CoreException ex){
ex.printStackTrace();
}
}
protected void postRun(SyntaxErrorHelper syntaxErr, ITextEditor editor) {
if(syntaxErr != null)
{
MessageDialog.openInformation(fSite.getShell(), UINlsStrings.EGLFormatting, syntaxErr.fErrMsg);
//highlight the syntax error location
if(editor != null && syntaxErr.fSynErr.startOffset > 0)
editor.selectAndReveal(syntaxErr.fSynErr.startOffset, syntaxErr.fSynErr.endOffset-syntaxErr.fSynErr.startOffset+1);
}
}
}