/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH 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
*******************************************************************************/
package de.gebit.integrity.ui.linking;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.texteditor.ITextEditor;
import com.google.inject.Inject;
import de.gebit.integrity.ui.search.IntegritySearch;
/**
* The default implementation of an {@link IntegrityURLResolver}.
*
* @author Rene Schneider - initial API and implementation
*
*/
public class DefaultIntegrityURLResolver implements IntegrityURLResolver {
/**
* The {@link IntegritySearch} engine.
*/
@Inject
protected IntegritySearch integritySearch;
/**
* The pattern to match URLs.
*/
private static final Pattern INTEGRITY_URL_PATTERN = Pattern.compile("integrity:\\/\\/([^#]+?)\\/?(?:\\#(\\d+))?");
@Override
public boolean parseURL(String anURL) {
Matcher tempMatcher = INTEGRITY_URL_PATTERN.matcher(anURL);
if (tempMatcher.matches()) {
String tempSuiteName = tempMatcher.group(1);
boolean tempHasLineNumber = tempMatcher.groupCount() > 1 && tempMatcher.group(2) != null;
IEditorPart tempEditor = integritySearch.openSuiteDefinitionByName(tempSuiteName, !tempHasLineNumber);
if (tempEditor == null) {
showError("Could not find a suite named '" + tempSuiteName + "' in your workspace.");
} else {
if (tempHasLineNumber) {
int tempLineNumber = Integer.parseInt(tempMatcher.group(2));
if (!jumpToLine(tempEditor, tempLineNumber)) {
showError("Could not find line number " + tempLineNumber + " in suite '" + tempSuiteName + "'");
}
}
}
return true;
}
return false;
}
private void showError(final String aMessage) {
Runnable tempRunnable = new Runnable() {
@Override
public void run() {
MessageDialog.openError(null, "Integrity Editor", aMessage);
}
};
Display.getDefault().asyncExec(tempRunnable);
}
private boolean jumpToLine(IEditorPart anEditor, int aLineNumber) {
if (!(anEditor instanceof ITextEditor) || aLineNumber <= 0) {
return false;
}
final ITextEditor tempEditor = (ITextEditor) anEditor;
IDocument tempDocument = tempEditor.getDocumentProvider().getDocument(tempEditor.getEditorInput());
if (tempDocument != null) {
try {
final IRegion tempLineInfo = tempDocument.getLineInformation(aLineNumber - 1);
if (tempLineInfo != null) {
// This is performed asynchronously because Xtext does it in the same way since 2.8 or so.
// The Xtext change originally caused issue #110: Jumping to test/call/suite invocations via
// integrity:// URLs jumps to suitedef instead
Job tempSelectAndRevealJob = new Job("Select and reveal line " + aLineNumber) {
@Override
protected IStatus run(IProgressMonitor aMonitor) {
tempEditor.getSite().getWorkbenchWindow().getWorkbench().getDisplay()
.asyncExec(new Runnable() {
@Override
public void run() {
tempEditor.selectAndReveal(tempLineInfo.getOffset(),
tempLineInfo.getLength());
}
});
return Status.OK_STATUS;
}
};
tempSelectAndRevealJob.setSystem(true);
tempSelectAndRevealJob.setPriority(Job.SHORT);
tempSelectAndRevealJob.schedule();
return true;
} else {
return false;
}
} catch (BadLocationException exc) {
return false;
}
}
return false;
}
}