/* * $Id$ * * Copyright (c) 2004-2005 by the TeXlapse 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.viewer; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import net.sourceforge.texlipse.TexlipsePlugin; import net.sourceforge.texlipse.properties.TexlipseProperties; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.texteditor.MarkerUtilities; /** * Monitor the output of an external viewer program and open the * file from the correct location when viewer outputs * a "file:lineNumber" -string. * * @author Kimmo Karlsson */ public class ViewerOutputScanner implements Runnable { // the stream reader private BufferedReader br; // the project this viewer is viewing private IProject project; /** * Create a new scanner. * @param project * @param in */ public ViewerOutputScanner(IProject project, InputStream in) { this.project = project; this.br = new BufferedReader(new InputStreamReader(in)); } /** * Empty constructor for the static version of the file open method. */ protected ViewerOutputScanner(IProject project) { this.project = project; } /** * Convenience method for outsiders. * @param proj the current project * @param file file name, relative or absolute * @param lineNumber line number */ public static void openInEditor(IProject proj, String file, int lineNumber) { new ViewerOutputScanner(proj).openFileFromLineNumber(file, lineNumber); } /** * Parse filename and line number from the given line of text. * * @param line line of text from viewer, possibly a line number event */ private void checkLine(String line) { int index = line.indexOf(':'); if (index < 0) { return; } String file = line.substring(0, index); String number = line.substring(index+1); int lineNumber = -1; try { lineNumber = Integer.parseInt(number); } catch (NumberFormatException e) { } if (lineNumber >= 0) { openFileFromLineNumber(file, lineNumber); } } /** * Opens the given file from the given location if the file belongs * to the currently open project. * * There is basically two possibilities for the filename: * 1) Path is relative: the filename represents a relative path * from the current directory (project source dir) to the output dir. * 2) Path is absolute: the filename is an absolute * path from the filesystem root to the project dir. * * @param file the file name, relative or absolute * @param lineNumber line number */ protected void openFileFromLineNumber(String file, int lineNumber) { if (project == null) { return; } IResource resource = null; //Patch for wrong directory seperators used by Yap if (File.separatorChar == '\\') { file = file.replace('/', '\\'); } // path may contain project path String projDir = project.getLocation().addTrailingSeparator().toOSString(); int index = file.indexOf(projDir); if (index == 0) { // remove the project path (external or inside workspace) file = file.substring(projDir.length()); // yap also adds the output dir IFolder outdir = TexlipseProperties.getProjectOutputDir(project); if (outdir != null) { String outdirName = outdir.getProjectRelativePath().toString() + File.separator; index = file.indexOf(outdirName); if (index == 0) { // remove output path file = file.substring(outdirName.length()); } } resource = project.findMember(file); if (resource == null) { //maybe in src folder IContainer srcDir = TexlipseProperties.getProjectSourceDir(project); resource = srcDir.findMember(file); } } else { // path is relative if (file.startsWith("..")) { // remove dots and 'File.separator' file = file.substring(3); } String outDir = TexlipseProperties.getProjectProperty(project, TexlipseProperties.OUTPUT_DIR_PROPERTY); if (outDir != null && outDir.length() > 0) { if (outDir.endsWith("/") || outDir.endsWith("\\")) { outDir = outDir.substring(0, outDir.length()-1); } outDir = outDir.trim(); if (file.indexOf(outDir) == 0) { // remove output dir from path file = file.substring(outDir.length()+1); } } IContainer srcDir = TexlipseProperties.getProjectSourceDir(project); resource = srcDir.findMember(file); } if (resource == null) { return; } IMarker mark = null; try { mark = resource.createMarker(IMarker.BOOKMARK); MarkerUtilities.setLineNumber(mark, lineNumber); } catch (CoreException e) { } if (mark != null) { Display display = TexlipsePlugin.getDefault().getWorkbench().getDisplay(); display.syncExec(new EditorOpener(mark)); try { mark.delete(); } catch (CoreException e) { } new Thread(new Runnable() { public void run() { ViewerManager.returnFocusToEclipse( TexlipsePlugin.getDefault().getPreferenceStore().getBoolean( TexlipseProperties.BUILDER_FORCE_RETURN_FOCUS)); } }).start(); } } /** * Editor opener task. Opens a file containing the given marker * to a new window in the editor and scrolls the editor window * to the right position. */ class EditorOpener implements Runnable { private IMarker marker; public EditorOpener(IMarker marker) { this.marker = marker; } public void run() { IWorkbenchPage page = TexlipsePlugin.getCurrentWorkbenchPage(); if (page == null) { return; } try { IDE.openEditor(page, marker, false); } catch (PartInitException e) { } } } /** * Monitor the stream line by line. */ public void run() { String line = null; try { while ((line = br.readLine()) != null) { checkLine(line); } } catch (IOException e) { } } }