/*
* $Id$
*
* Copyright (c) 2006 by the TeXlipse team.
* 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 net.sourceforge.texlipse.actions;
import java.io.File;
import java.text.MessageFormat;
import java.util.List;
import net.sourceforge.texlipse.TexlipsePlugin;
import net.sourceforge.texlipse.bibeditor.BibEditor;
import net.sourceforge.texlipse.builder.KpsewhichRunner;
import net.sourceforge.texlipse.editor.TexEditor;
import net.sourceforge.texlipse.model.AbstractEntry;
import net.sourceforge.texlipse.model.TexCommandEntry;
import net.sourceforge.texlipse.properties.TexlipseProperties;
import net.sourceforge.texlipse.texparser.LatexParserUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.SubStatusLineManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.ide.IDE;
/**
* This action opens the declaration of
* <ul><li>References</li>
* <li>Citations</li>
* <li>Custom commands (/newcommand)</li>
* <li>include, input and bibliography</li>
* </ul>
*
* @author Boris von Loesch
*/
public class OpenDeclarationAction implements IEditorActionDelegate {
private IEditorPart targetEditor;
/**
* Creates new action.
*/
public OpenDeclarationAction() {
super();
}
/* (non-Javadoc)
* @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart)
*/
public void setActiveEditor(IAction action, IEditorPart targetEditor) {
this.targetEditor = targetEditor;
}
/**
* Prints an error message on the status line and make a beep.
* @param message The error message
*/
private void createStatusLineErrorMessage(String message) {
TexEditor editor;
if (targetEditor instanceof TexEditor) {
editor = (TexEditor) targetEditor;
SubStatusLineManager slm =
(SubStatusLineManager) targetEditor.getEditorSite().getActionBars().getStatusLineManager();
slm.setErrorMessage(message);
slm.setVisible(true);
editor.getViewer().getTextWidget().getDisplay().beep();
}
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action) {
TexEditor editor;
if (targetEditor instanceof TexEditor) {
editor = (TexEditor) targetEditor;
} else {
throw new RuntimeException("Expecting text editor. Found: "+ targetEditor.getClass().getName());
}
IProject project = editor.getProject();
if (project == null)
return;
ITextSelection selection = (ITextSelection) editor.getSelectionProvider().getSelection();
IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
String docString = doc.get();
//Get command under cursor
IRegion comRegion = LatexParserUtils.getCommand(docString, selection.getOffset());
if (comRegion == null) {
createStatusLineErrorMessage(TexlipsePlugin.getResourceString("gotoDeclarationNoCommandFound"));
return;
}
String command = docString.substring(comRegion.getOffset(), comRegion.getOffset() + comRegion.getLength());
AbstractEntry refEntry = null;
if (selection.getOffset() < comRegion.getOffset() + comRegion.getLength()) {
//Cursor is over a command, not the argument, we first try to find the command in the user defined commands
List<TexCommandEntry> entries = editor.getDocumentModel().getRefMana().getCompletionsCom(command.substring(1), TexCommandEntry.NORMAL_CONTEXT);
if (entries != null && entries.size() > 0 && entries.get(0).fileName != null) {
//the command is defined by the user
refEntry = entries.get(0);
}
}
if (refEntry == null && (command.indexOf("ref") >= 0 || command.indexOf("cite") >=0 ||
command.equals("\\input") || command.equals("\\include")) ||
command.equals("\\bibliography")) {
//We need the argument
IRegion region = null;
region = LatexParserUtils.getCommandArgument(docString, comRegion.getOffset());
if (region == null) {
createStatusLineErrorMessage(TexlipsePlugin.getResourceString("gotoDeclarationNoArgumentFound"));
return;
}
String ref = docString.substring(region.getOffset(), region.getOffset() + region.getLength());
if (command.indexOf("ref") >= 0) {
//Find the matching label
refEntry = editor.getDocumentModel().getRefMana().getLabel(ref);
}
else if (command.indexOf("cite")>=0) {
//There could be more than one reference (e.g. cite1,cite2)
if (ref.indexOf(',') > 0) {
int cIndex = selection.getOffset() - region.getOffset();
if (cIndex < 0) {
createStatusLineErrorMessage(TexlipsePlugin.getResourceString("gotoDeclarationNoArgumentFound"));
return;
}
if (ref.charAt(cIndex) == ',') cIndex--;
int start = ref.lastIndexOf(',', cIndex) + 1;
if (start < 0)
start = 0;
int end = ref.indexOf(',', cIndex);
if (end < 0)
end = ref.length();
ref = ref.substring(start, end);
}
refEntry = editor.getDocumentModel().getRefMana().getBib(ref.trim());
}
else if (command.equals("\\include") || command.equals("\\input") ||
command.equals("\\bibliography")) {
if (command.equals("\\bibliography")) {
if (!ref.toLowerCase().endsWith(".bib")) {
ref = ref + ".bib";
}
}
else {
if (!ref.toLowerCase().endsWith(".tex")) {
ref = ref + ".tex";
}
}
IContainer dir = TexlipseProperties.getProjectSourceDir(project);
IResource file = dir.findMember(ref);
if (file == null) {
//Fallback strategy, try to find the file from the referring file ddir
IFile refFile = editor.getDocumentModel().getFile();
if (refFile != null) {
dir = refFile.getParent();
file = dir.findMember(ref);
}
}
if (file == null){
/* TODO: Kpsewhich support
KpsewhichRunner filesearch = new KpsewhichRunner();
try {
String filepath = filesearch.getFile(editor.getDocumentModel().getFile(), refEntry.fileName, "bibtex");
File f = new File(filepath);
//Open the correct document and jump to label
IDE.openEditor(editor.getEditorSite().getPage(), f.toURI(), BibEditor.ID, true);
} catch (PartInitException e) {
TexlipsePlugin.log("Jump2Label PartInitException", e);
} catch (CoreException ce) {
TexlipsePlugin.log ("Can't run Kpathsea", ce)
}*/
createStatusLineErrorMessage(MessageFormat.format(TexlipsePlugin.getResourceString("gotoDeclarationNoFileFound"),
new Object[]{ref}));
return;
}
try {
IDE.openEditor(editor.getEditorSite().getPage(), (IFile)file.getAdapter(IFile.class));
} catch (PartInitException e) {
TexlipsePlugin.log("Open declaration:", e);
}
return;
}
}
if (refEntry == null || refEntry.fileName == null) {
createStatusLineErrorMessage(TexlipsePlugin.getResourceString("gotoDeclarationNoDeclarationFound"));
return;
}
IFile file = project.getFile(refEntry.fileName);
try {
AbstractTextEditor part;
if (!file.exists()) {
//Try kpathsea
KpsewhichRunner filesearch = new KpsewhichRunner();
String filepath = filesearch.getFile(editor.getDocumentModel().getFile(), refEntry.fileName, "bibtex");
if ("".equals(filepath)) {
createStatusLineErrorMessage(TexlipsePlugin.getResourceString("gotoDeclarationNoDeclarationFound"));
return;
}
File f = new File(filepath);
//Open the correct document and jump to label
part = (AbstractTextEditor) IDE.openEditor(editor.getEditorSite().getPage(),
f.toURI(), BibEditor.ID, true);
}
else {
//Open the correct document and jump to label
part = (AbstractTextEditor) IDE.openEditor(editor.getEditorSite().getPage(), file);
}
IDocument doc2 = part.getDocumentProvider().getDocument(part.getEditorInput());
int lineOffset = doc2.getLineOffset(refEntry.startLine - 1);
int offset = 0;
if (command.indexOf("ref") >= 0 && refEntry.position != null) {
offset = refEntry.position.offset;
}
part.getEditorSite().getSelectionProvider().setSelection(
new TextSelection(lineOffset + offset, 0));
} catch (PartInitException e) {
TexlipsePlugin.log("Jump2Label PartInitException", e);
} catch (BadLocationException e) {
TexlipsePlugin.log("Jump2Label BadLocationException", e);
} catch (CoreException ce) {
TexlipsePlugin.log("Can't run Kpathsea", ce);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IAction action, ISelection selection) {
action.setEnabled(targetEditor instanceof TexEditor);
}
}