changeset 5738:50dbe728da9e

log viewer source code cleanup
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 02 Jul 2012 16:31:30 +0200
parents f2fc4d13975a
children dba56a3344ba
files visualizer/LogViewer/build.xml visualizer/LogViewer/manifest.mf visualizer/LogViewer/nbproject/build-impl.xml visualizer/LogViewer/nbproject/project.xml visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory visualizer/LogViewer/src/at/ssw/visualizer/logviewer/Bundle.properties visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewer.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewerFactory.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/layer.xml visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogLine.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogModel.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogParser.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Method.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Node.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Scope.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/Filter.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FilterManager.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FullTextFilter.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/MethodFilter.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/NodeFilter.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/ScopeFilter.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/FileLine.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/ProgressMonitor.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFile.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFileReader.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkDialog.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkableLogViewer.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/ImportLogErrorDialog.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/LogScene.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/actions/ImportLogAction.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_down.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_up.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_back.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_forward.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_list.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/import_log.png visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/loading.gif visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/LogTableModel.java visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/TableLine.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/Bundle.properties visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewer.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewerFactory.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/layer.xml visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogLine.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogModel.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogParser.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Method.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Node.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Scope.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/Filter.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FilterManager.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FullTextFilter.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/MethodFilter.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/NodeFilter.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/ScopeFilter.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/FileLine.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/ProgressMonitor.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFile.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFileReader.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkDialog.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkableLogViewer.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/ImportLogErrorDialog.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/LogScene.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/actions/ImportLogAction.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_down.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_up.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_back.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_forward.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_list.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/import_log.png visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/loading.gif visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/LogTableModel.java visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/TableLine.java visualizer/nbproject/project.properties
diffstat 74 files changed, 3062 insertions(+), 2585 deletions(-) [+]
line wrap: on
line diff
--- a/visualizer/LogViewer/build.xml	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/LogViewer/build.xml	Mon Jul 02 16:31:30 2012 +0200
@@ -2,7 +2,7 @@
 <!-- You may freely edit this file. See harness/README in the NetBeans platform -->
 <!-- for some information on what you could do (e.g. targets to override). -->
 <!-- If you delete this file and reopen the project it will be recreated. -->
-<project name="at.ssw.visualizer.logviewer" default="netbeans" basedir=".">
-    <description>Builds, tests, and runs the project at.ssw.visualizer.logviewer.</description>
+<project name="com.oracle.graal.visualizer.logviewer" default="netbeans" basedir=".">
+    <description>Builds, tests, and runs the project com.oracle.graal.visualizer.logviewer.</description>
     <import file="nbproject/build-impl.xml"/>
 </project>
--- a/visualizer/LogViewer/manifest.mf	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/LogViewer/manifest.mf	Mon Jul 02 16:31:30 2012 +0200
@@ -1,6 +1,6 @@
 Manifest-Version: 1.0
-OpenIDE-Module: at.ssw.visualizer.logviewer
-OpenIDE-Module-Layer: at/ssw/visualizer/logviewer/layer.xml
-OpenIDE-Module-Localizing-Bundle: at/ssw/visualizer/logviewer/Bundle.properties
+OpenIDE-Module: com.oracle.graal.visualizer.logviewer
+OpenIDE-Module-Layer: com/oracle/graal/visualizer/logviewer/layer.xml
+OpenIDE-Module-Localizing-Bundle: com/oracle/graal/visualizer/logviewer/Bundle.properties
 OpenIDE-Module-Specification-Version: 1.0
 
--- a/visualizer/LogViewer/nbproject/build-impl.xml	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/LogViewer/nbproject/build-impl.xml	Mon Jul 02 16:31:30 2012 +0200
@@ -3,7 +3,7 @@
 *** GENERATED FROM project.xml - DO NOT EDIT  ***
 ***         EDIT ../build.xml INSTEAD         ***
 -->
-<project name="at.ssw.visualizer.logviewer-impl" basedir="..">
+<project name="com.oracle.graal.visualizer.logviewer-impl" basedir="..">
     <fail message="Please build using Ant 1.7.1 or higher.">
         <condition>
             <not>
--- a/visualizer/LogViewer/nbproject/project.xml	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/LogViewer/nbproject/project.xml	Mon Jul 02 16:31:30 2012 +0200
@@ -3,7 +3,7 @@
     <type>org.netbeans.modules.apisupport.project</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
-            <code-name-base>at.ssw.visualizer.logviewer</code-name-base>
+            <code-name-base>com.oracle.graal.visualizer.logviewer</code-name-base>
             <suite-component/>
             <module-dependencies>
                 <dependency>
@@ -134,12 +134,12 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>6.48.2</specification-version>
+                        <specification-version>6.39.1</specification-version>
                     </run-dependency>
                 </dependency>
             </module-dependencies>
             <public-packages>
-                <package>at.ssw.visualizer.logviewer</package>
+                <package>com.oracle.graal.visualizer.logviewer</package>
             </public-packages>
         </data>
     </configuration>
--- a/visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory	Mon Jul 02 16:31:30 2012 +0200
@@ -1,1 +1,1 @@
-at.ssw.visualizer.logviewer.LogCompilationViewerFactory
\ No newline at end of file
+com.oracle.graal.visualizer.logviewer.LogCompilationViewerFactory
\ No newline at end of file
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/Bundle.properties	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-OpenIDE-Module-Name=LogViewer
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewer.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package at.ssw.visualizer.logviewer;
-
-import at.ssw.visualizer.logviewer.scene.LogScene;
-import com.oracle.graal.visualizer.editor.CompilationViewer;
-import com.sun.hotspot.igv.data.InputGraph;
-import java.awt.Component;
-import org.openide.util.Lookup;
-import org.openide.util.lookup.Lookups;
-
-class LogCompilationViewer implements CompilationViewer {
-
-    private LogScene scene;
-
-    public LogCompilationViewer() {
-        this.scene = new LogScene();
-    }
-
-    @Override
-    public Lookup getLookup() {
-        return Lookups.fixed();
-    }
-
-    @Override
-    public Component getComponent() {
-        return scene;
-    }
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewerFactory.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package at.ssw.visualizer.logviewer;
-
-import com.oracle.graal.visualizer.editor.CompilationViewer;
-import com.oracle.graal.visualizer.editor.SplitCompilationViewerFactory;
-import com.sun.hotspot.igv.data.InputGraph;
-
-public class LogCompilationViewerFactory extends SplitCompilationViewerFactory {
-
-    @Override
-    public String getName() {
-        return "Log";
-    }
-
-    @Override
-    protected CompilationViewer createViewer(InputGraph graph) {
-        return new LogCompilationViewer();
-    }
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/layer.xml	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
-<filesystem>
-    <folder name="CompilationViewer">
-        <folder name="Log">
-            <folder name="Actions">
-                <file name="at-ssw-visualizer-logviewer-scene-actions-ImportLogAction.shadow">
-                    <attr name="originalFile" stringvalue="Actions/File/at-ssw-visualizer-logviewer-scene-actions-ImportLogActions.instance"/>
-                </file>
-            </folder>
-        </folder>
-    </folder>
-</filesystem>
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogLine.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class LogLine {
-
-    private final int lineNum;
-	private final CharSequence text;
-	private final Method method;
-	private final Scope scope;
-	private final Node node;
-	
-	LogLine(int lineNum, CharSequence text, Method method, Scope scope, Node node) {
-		this.lineNum = lineNum;
-        this.text = text;
-		this.method = method;
-		this.scope = scope;
-		this.node = node;
-	}
-    
-    /**
-     * Returns the number of the line in the log file
-     * @return file line number
-     */
-    public int getLineNumber() {
-        return lineNum;
-    }
-	
-	/**
-	 * Returns the text of the log line
-	 * @return log line text
-	 */
-	public String getText() {
-		return text.toString();
-	}
-	
-	/**
-	 * Returns the parent method
-	 * @return the parent method
-	 */
-	public Method getMethod() {
-		return method;
-	}
-	
-	/**
-	 * Returns the parent scope
-	 * @return the parent scope
-	 */
-	public Scope getScope() {
-		return scope;
-	}
-	
-	/**
-	 * Returns the parent node
-	 * @return the parent node (or <code>null</code> if the log is not in a node's context)
-	 */
-	public Node getNode() {
-		return node;
-	}
-	
-	/**
-	 * The string representation of a log line is the text of it.
-	 */
-	@Override
-	public String toString() {
-		return getText();
-	}
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogModel.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class LogModel {
-
-	private List<Method> methods = new ArrayList<>();
-	private List<LogLine> logs = new ArrayList<>();
-	
-	void add(Method method) {
-		methods.add(method);
-	}
-	
-	/**
-	 * Returns a list of all methods within the log model.
-	 * @return list of methods
-	 */
-	public List<Method> getMethods() {
-		return Collections.unmodifiableList(methods);
-	}
-	
-	void add(LogLine log) {
-		logs.add(log);
-	}
-	
-	/**
-	 * Returns a list of all logs
-	 * @return list of log lines
-	 */
-	public List<LogLine> getLogs() {
-		return Collections.unmodifiableList(logs);
-	}
-	
-	/**
-	 * Returns a list of logs which are before and after a specific log line (and the line itself).
-	 * @param log reference log line
-	 * @param pre number of lines before the reference line
-	 * @param post number of lines after the reference line
-	 * @return list of log lines (size: pre + post + 1)
-	 */
-	public List<LogLine> range(LogLine log, int pre, int post) {
-		if(log == null) throw new NoSuchElementException();
-		
-		List<LogLine> logs = getLogs();
-		int index = logs.indexOf(log);
-		
-		if(index == -1) throw new NoSuchElementException();
-		
-		int fromIndex = index - pre;
-		int toIndex = index + post + 1;
-		
-		return getLogs().subList(fromIndex > 0 ? fromIndex : 0, toIndex < logs.size() ? toIndex : logs.size());
-	}
-	
-	/**
-	 * Returns a string with log l which are before and after a specific log line (and the line itself).
-	 * @param log reference log line
-	 * @param pre number of lines before the reference line
-	 * @param post number of lines after the reference line
-	 * @return list of log lines (size: pre + post + 1)
-	 */
-	public String rangeAsString(LogLine log, int pre, int post) {
-		List<LogLine> list = range(log, pre, post);
-		
-		String ls = System.getProperty("line.separator");
-		
-		boolean first = true;
-		StringBuilder buf = new StringBuilder();
-		for(LogLine line : list) {
-			if(!first) buf.append(ls);
-			else first = false;
-			
-			buf.append(line);
-		}
-		
-		return buf.toString();
-	}
-	
-	public LogLine getLogLine(int lineNum) {
-		int index = lineNum;
-		if(index >= logs.size()) index = logs.size()-1;
-		
-		LogLine logLine = logs.get(lineNum);
-		while(logLine.getLineNumber() > lineNum) {
-			logLine = logs.get(--index);
-		}
-		while(logLine.getLineNumber() < lineNum) {
-			logLine = logs.get(++index);
-		}
-		
-		return logLine;
-	}
-	
-	public List<LogLine> range(int lineNum, int pre, int post) {
-		LogLine logLine = getLogLine(lineNum);
-		return range(logLine, pre, post);
-	}
-	
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogParser.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-import at.ssw.visualizer.logviewer.model.io.FileLine;
-import at.ssw.visualizer.logviewer.model.io.ProgressMonitor;
-import at.ssw.visualizer.logviewer.model.io.SeekableFile;
-import at.ssw.visualizer.logviewer.model.io.SeekableFileReader;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class LogParser {
-	
-	private static final Pattern METHOD_PATTERN =
-		Pattern.compile("Finished target method HotSpotMethod<(.+?)>, isStub (true|false)");
-	private static final Pattern SCOPE_PATTERN =
-		Pattern.compile("scope: (.+?)");
-	private static final Pattern NODE_PATTERN =
-		Pattern.compile(".*?([0-9]+)\\|([0-9a-zA-Z.]+).*?");
-	
-	private final List<ParseErrorListener> errorListeners = new ArrayList<>();
-	private final List<ParseError> errors = new ArrayList<>();
-	
-	/**
-	 * Parses a log file without any feedback. When the parsing process is finished, the method returns a LogModel-object.
-	 * @param file log file
-	 * @return model-object
-	 * @throws IOException
-	 * @throws LogParserException
-	 */
-	public LogModel parse(File file) throws IOException {
-		return parse(file, null);
-	}
-	
-	/**
-	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
-	 * @param file log file
-	 * @param monitor monitor for progress monitoring (uses default gap)
-	 * @return model-object
-	 * @throws IOException
-	 * @throws LogParserException
-	 */
-	public LogModel parse(File file, ProgressMonitor monitor) throws IOException {
-		return parse(file, monitor, SeekableFileReader.DEFAULT_GAP);
-	} 
-	
-	/**
-	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
-	 * @param file log file
-	 * @param monitor monitor for progress monitoring (uses custom gap)
-	 * @param gap custom gap (every x bytes read from the file, the monitor will be informed)
-	 * @return model-object
-	 * @throws IOException
-	 * @throws LogParserException
-	 */
-	public LogModel parse(File file, ProgressMonitor monitor, int gap) throws IOException {
-		errors.clear();
-		SeekableFileReader reader = new SeekableFileReader(file, monitor, gap);
-		SeekableFile seekableFile = reader.getSeekableFile();
-		BufferedReader r = new BufferedReader(reader);
-		
-		LogModel model = new LogModel();
-		Method currentMethod = new Method(model);
-		Scope currentScope = null;
-		
-		Matcher matcher;
-		boolean methodNameSet = false;
-		
-		int lineNum = -1;
-		String line;
-		while((line = r.readLine()) != null) {
-			lineNum++;
-			
-			methodNameSet = false;
-			
-			matcher = SCOPE_PATTERN.matcher(line);
-			if(matcher.matches()) {
-				String name = matcher.group(1);
-				currentScope = new Scope(name, currentMethod);
-				currentMethod.add(currentScope);
-			}
-            
-            matcher = METHOD_PATTERN.matcher(line);
-            boolean methodPatternMatches = matcher.matches();
-            
-            if(methodPatternMatches){
-                currentScope = null;
-				String name = matcher.group(1);
-				boolean isStub = Boolean.parseBoolean(matcher.group(2));
-				currentMethod.init(name, isStub);
-				model.add(currentMethod);
-				methodNameSet = true;
-            }
-			
-			Node currentNode = null;
-			matcher = NODE_PATTERN.matcher(line);
-			if(matcher.matches()) {
-                if(currentScope == null){
-                	raiseError(lineNum, line, "scope is missing");
-                	continue;
-                }
-				int number = Integer.parseInt(matcher.group(1));
-				currentNode = currentScope.getNode(number);
-				if(currentNode == null) {
-					String name = matcher.group(2);
-					currentNode = new Node(number, name, currentScope);
-					currentScope.add(currentNode);
-				}
-			}
-			
-			FileLine fileLine = seekableFile.get(lineNum);
-			LogLine log = new LogLine(lineNum, fileLine, currentMethod, currentScope, currentNode);
-			if(currentNode != null) currentNode.add(log);
-			if(currentScope != null) currentScope.add(log);
-			currentMethod.add(log);
-			model.add(log);
-            
-            if(methodPatternMatches) {
-				currentMethod = new Method(model);
-			}
-		}
-		
-		if(!methodNameSet) raiseError(lineNum, line, "unexpected end of stream");
-		
-		return model;
-	}
-	
-	private void raiseError(int lineNum, String line, String message) {
-		ParseError error = new ParseError(lineNum, line, message);
-		errors.add(error);
-		for(ParseErrorListener listener : errorListeners) {
-			listener.errorOccurred(error);
-		}
-	}
-	
-	/**
-	 * Adds a ParseErrorListener to the listeners
-	 * @param listener
-	 */
-	public void addParseErrorListener(ParseErrorListener listener) {
-		errorListeners.add(listener);
-	}
-	
-	public void removeParseErrorListener(ParseErrorListener listener) {
-		errorListeners.remove(listener);
-	}
-	
-	/**
-	 * Checks if errors occurred during the parsing process
-	 * @return <code>true</code> if there are errors stored, <code>false</code> otherwise
-	 */
-	public boolean hasErrors() {
-		return !errors.isEmpty();
-	}
-	
-	/**
-	 * Returns a list of all errors.
-	 * @return error list
-	 */
-	public List<ParseError> getErrors() {
-		return Collections.unmodifiableList(errors);
-	}
-	
-	public static class ParseError {
-		
-		private final int lineNum;
-		private final String line;
-		private final String message;
-		
-		private ParseError(int lineNum, String line, String message) {
-			this.lineNum = lineNum;
-			this.message = message;
-			this.line = line;
-		}
-		
-		public int getLineNumber() {
-			return lineNum;
-		}
-		
-		public String getLine() {
-			return line;
-		}
-		
-		public String getMessage() {
-			return message;
-		}
-		
-	}
-	
-	public static interface ParseErrorListener {
-		
-		/**
-		 * Called when a new error occurs.<br><br>
-		 * <b>Attention</b>: This method runs on the same thread as the parsing process.
-		 * If time-consuming tasks should be executed, please consider multithreading.
-		 * @param error
-		 */
-		public void errorOccurred(ParseError error);
-		
-	}
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Method.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class Method {
-
-	private String name;
-	private boolean isStub;
-	private final LogModel model;
-	private List<Scope> scopes = new ArrayList<>();
-	private List<LogLine> logs = new ArrayList<>();
-	
-	Method(LogModel model) {
-		name = null;
-		isStub = false;
-		this.model = model;
-	}
-	
-	void init(String name, boolean isStub) {
-		this.name = name;
-		this.isStub = isStub;
-	}
-	
-	/**
-	 * Returns the name of the method
-	 * @return the method name
-	 */
-	public String getName() {
-		return name;
-	}
-	
-	/**
-	 * Returns <code>true</code> if this is a stub method.
-	 * @return <code>true</code> if is stub, <code>false</code> otherwise
-	 */
-	public boolean isStub() {
-		return isStub;
-	}
-	
-	/**
-	 * Returns the model which holds this method.
-	 * @return model-object
-	 */
-	public LogModel getModel() {
-		return model;
-	}
-	
-	void add(Scope scope) {
-		scopes.add(scope);
-	}
-	
-	/**
-	 * Returns a list of all scopes inside a target method.
-	 * @return list of scopes
-	 */
-	public List<Scope> getScopes() {
-		return scopes;
-	}
-	
-	void add(LogLine log) {
-		logs.add(log);
-	}
-	
-	/**
-	 * Returns a list of all logs in the context of the method.
-	 * @return list of log lines
-	 */
-	public List<LogLine> getLogs() {
-		return Collections.unmodifiableList(logs);
-	}
-	
-	/**
-	 * The string representation of a method is its name.
-	 */
-	@Override
-	public String toString() {
-		return getName();
-	}
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Node.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class Node {
-
-	private final int number;
-	private final String name;
-	private final Scope scope;
-	private List<LogLine> logs = new ArrayList<>();
-	
-	
-	Node(int number, String name, Scope scope) {
-		this.number = number;
-		this.name = name;
-		this.scope = scope;
-	}
-	
-	/**
-	 * Returns the node number.
-	 * @return the node number
-	 */
-	public int getNumber() {
-		return number;
-	}
-	
-	/**
-	 * Returns the node name.
-	 * @return the node name
-	 */
-	public String getName() {
-		return name;
-	}
-	
-	/**
-	 * Returns the parent scope.
-	 * @return the parent scope
-	 */
-	public Scope getScope() {
-		return scope;
-	}
-	
-	void add(LogLine log) {
-		logs.add(log);
-	}
-	
-	/**
-	 * Returns a list of all logs within a nodes context.
-	 * @return list of log lines
-	 */
-	public List<LogLine> getLogs() {
-		return Collections.unmodifiableList(logs);
-	}
-	
-	/**
-	 * The string represenation of a node is &quot;&lt;name&gt; (&lt;number&gt;)&quot;.
-	 */
-	@Override
-	public String toString() {
-		return getName() + "(" + getNumber() + ")";
-	}
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Scope.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-package at.ssw.visualizer.logviewer.model;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class Scope {
-
-	private final String name;
-	private final Method method;
-	private List<Node> nodes = new ArrayList<>();
-	private List<LogLine> logs = new ArrayList<>();
-	
-	Scope(String name, Method method) {
-		this.name = name;
-		this.method = method;
-	}
-	
-	/**
-	 * Returns the scope name.
-	 * @return the scope name
-	 */
-	public String getName() {
-		return name;
-	}
-	
-	/**
-	 * Returns the parent method.
-	 * @return the parent method
-	 */
-	public Method getMethod() {
-		return method;
-	}
-	
-	void add(Node node) {
-		nodes.add(node);
-	}
-	
-	/**
-	 * Returns a list of all node-objects inside a scope.
-	 * @return list of nodes
-	 */
-	public List<Node> getNodes() {
-		return Collections.unmodifiableList(nodes);
-	}
-	
-	void add(LogLine log) {
-		logs.add(log);
-	}
-	
-	/**
-	 * Returns a list of all logs inside a scope.
-	 * @return list of log lines
-	 */
-	public List<LogLine> getLogs() {
-		return logs;
-	}
-	
-	/**
-	 * Returns the node inside a scope with the given number.
-	 * @param number node number
-	 * @return node-object
-	 */
-	public Node getNode(int number) {
-		for(Node node : nodes) {
-			if(node.getNumber() == number) return node;
-		}
-		return null;
-	}
-	
-	/**
-	 * The string representation of a scope is its name.
-	 * @see java.lang.Object#toString()
-	 */
-	@Override
-	public String toString() {
-		return getName();
-	}
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/Filter.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public interface Filter {
-
-	/**
-	 * Sets the constraints for a filter.<br>
-	 * They can be every type of objects. In general these are strings, but it can also be
-	 * a Integer (like in the <code>NodeFilter</code>):<br>
-	 * <code>Filter nodeFilter = filterManager.getNodeFilter();
-	 * filter.setConstraints((String)nodeName, (Integer)nodeNumber);</code>
-	 * @param constraints filter constraints
-	 */
-	void setConstraints(Object ... constraints);
-	
-	/**
-	 * Indicates whether to keep a log line in the filter results, or not.
-	 * @param line log line which should be checked
-	 * @return <code>true</code> if the line should be kept, <code>false</code> otherwise
-	 */
-	boolean keep(LogLine line);
-	
-	/**
-	 * Activates or deactivates a filter. Deactivated filters will be ignored.
-	 * @param active <code>true</code> to activate, <code>false</code> to deactivate
-	 */
-	void setActive(boolean active);
-	
-	/**
-	 * Returns the activation status
-	 * @return <code>true</code> for an active filter, <code>false</code> otherwise
-	 */
-	boolean isActive();
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FilterManager.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import at.ssw.visualizer.logviewer.model.LogModel;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class FilterManager {
-	
-	private final List<Filter> filters = new ArrayList<>();
-	private final Filter methodFilter, scopeFilter, nodeFilter, fulltextFilter;
-	
-	/**
-	 * Creates a new instance of the filter manager.
-	 */
-	public FilterManager() {
-		add(methodFilter = new MethodFilter());
-		add(scopeFilter = new ScopeFilter());
-		add(nodeFilter = new NodeFilter());
-		add(fulltextFilter = new FullTextFilter());
-	}
-	
-	/**
-	 * Executes a filtering process with the given log model as subject. Inactive filters will be ignored.
-	 * @param model subject
-	 * @return filtered list of log lines
-	 * @throws InterruptedException 
-	 */
-	public List<LogLine> execute(LogModel model) throws InterruptedException {
-		List<LogLine> input = model.getLogs();
-		List<LogLine> output = new ArrayList<>();
-		
-		for(LogLine line : input) {
-			if(Thread.interrupted()) throw new InterruptedException();
-			if(keep(line)) output.add(line);
-		}
-		
-		if(Thread.interrupted()) throw new InterruptedException();
-		
-		return output;
-	}
-	
-	private boolean keep(LogLine line) {
-		boolean keep = true;
-		for(Filter filter : filters) {
-			keep = keep && (!filter.isActive() || filter.keep(line));
-		}
-		return keep;
-	}
-	
-	private Filter add(Filter filter) {
-		filters.add(filter);
-		return filter;
-	}
-	
-	/**
-	 * Returns the instance of a method filter
-	 * @return method filter
-	 */
-	public Filter getMethodFilter() {
-		return methodFilter;
-	}
-	
-	/**
-	 * Returns the instance of a scope filter
-	 * @return scope filter
-	 */
-	public Filter getScopeFilter() {
-		return scopeFilter;
-	}
-	
-	/**
-	 * Returns the instance of a node filter
-	 * @return node filter
-	 */
-	public Filter getNodeFilter() {
-		return nodeFilter;
-	}
-	
-	/**
-	 * Returns the instance of a full text filter
-	 * @return full text filter
-	 */
-	public Filter getFullTextFilter() {
-		return fulltextFilter;
-	}
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FullTextFilter.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author Alexander Stipsits
- */
-class FullTextFilter implements Filter {
-
-	private Pattern p;
-	private boolean active = true;
-	
-	@Override
-	public void setConstraints(Object ... constraints) {
-        this.p = null;
-		for(Object constraint : constraints) {
-			setConstraint(constraint);
-		}
-	}
-	
-	private void setConstraint(Object constraint) {
-		if(constraint instanceof String) {
-			if(((String)constraint).trim().length() > 0) {
-				this.p = Pattern.compile((String)constraint);
-			}
-			else {
-				this.p = null;
-			}
-		}
-	}
-
-	@Override
-	public boolean keep(LogLine line) {
-		if(p == null) return true;
-		
-		Matcher matcher = p.matcher(line.getText());
-		return matcher.find();
-	}
-
-	@Override
-	public void setActive(boolean active) {
-		this.active = active;
-	}
-
-	@Override
-	public boolean isActive() {
-		return active;
-	}
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/MethodFilter.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author Alexander Stipsits
- */
-class MethodFilter implements Filter {
-
-	private Pattern p;
-	private boolean active = true;
-	
-	@Override
-	public void setConstraints(Object ... constraints) {
-        this.p = null;
-		for(Object constraint : constraints) {
-			setConstraint(constraint);
-		}
-	}
-	
-	private void setConstraint(Object constraint) {
-		if(constraint instanceof String) {
-			if(((String)constraint).trim().length() > 0) {
-				this.p = Pattern.compile((String)constraint);
-			}
-			else {
-				this.p = null;
-			}
-		}
-	}
-
-	@Override
-	public boolean keep(LogLine line) {
-		if(p == null) return true;
-		
-		Matcher matcher = p.matcher(line.getMethod().getName());
-		return matcher.find();
-	}
-
-	@Override
-	public void setActive(boolean active) {
-		this.active = active;
-	}
-
-	@Override
-	public boolean isActive() {
-		return active;
-	}
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/NodeFilter.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author Alexander Stipsits
- */
-class NodeFilter implements Filter {
-
-	private Pattern p;
-	private Integer nodeNum;
-	private boolean active = true;
-	
-	@Override
-	public void setConstraints(Object ... constraints) {
-        this.nodeNum = null;
-        this.p = null;
-		for(Object constraint : constraints) {
-			setConstraint(constraint);
-		}
-	}
-	
-	private void setConstraint(Object constraint) {
-		if(constraint instanceof String) {
-		
-			if(((String)constraint).trim().length() > 0) {
-				this.p = Pattern.compile((String)constraint);
-			}
-			else {
-				this.p = null;
-			}
-		}
-		else if(constraint instanceof Integer) {
-			this.nodeNum = (Integer)constraint;
-		}
-		
-	}
-
-	@Override
-	public boolean keep(LogLine line) {
-		if(p == null && nodeNum == null) return true; 
-		
-		if(line.getNode() == null) return false;
-		
-		boolean keep = false;
-		
-		if(p != null) {
-			Matcher matcher = p.matcher(line.getNode().getName());
-			keep = keep || matcher.find();
-		}
-		if(nodeNum != null) {
-			keep = keep || nodeNum.equals(line.getNode().getNumber());
-		}
-		
-		return keep;		
-	}
-
-	@Override
-	public void setActive(boolean active) {
-		this.active = active;
-	}
-
-	@Override
-	public boolean isActive() {
-		return active;
-	}
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/ScopeFilter.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-package at.ssw.visualizer.logviewer.model.filter;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author Alexander Stipsits
- */
-class ScopeFilter implements Filter {
-
-	private Pattern p;
-	private boolean active = true;
-	
-	@Override
-	public void setConstraints(Object ... constraints) {
-        this.p = null;
-		for(Object constraint : constraints) {
-			setConstraint(constraint);
-		}
-	}
-	
-	private void setConstraint(Object constraint) {
-		if(constraint instanceof String) {
-			if(((String)constraint).trim().length() > 0) {
-				this.p = Pattern.compile((String)constraint);
-			}
-			else {
-				this.p = null;
-			}
-		}
-	}
-
-	@Override
-	public boolean keep(LogLine line) {
-		if(p == null) return true;
-        
-        if(line.getScope() == null) return false;
-		
-		Matcher matcher = p.matcher(line.getScope().getName());
-		return matcher.find();
-	}
-
-	@Override
-	public void setActive(boolean active) {
-		this.active = active;
-	}
-
-	@Override
-	public boolean isActive() {
-		return active;
-	}
-
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/FileLine.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-package at.ssw.visualizer.logviewer.model.io;
-
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class FileLine implements CharSequence {
-
-	private final SeekableFile seekableFile;
-	private WeakReference<String> cache;
-	public final long off;
-	public final int len;
-	
-	public FileLine(SeekableFile seekableFile, long off, int len) {
-		this.seekableFile = seekableFile;
-		this.off = off;
-		this.len = len;
-	}
-	
-	@Override
-	public String toString() {
-		String line = null;
-		
-		if(cache != null) line = cache.get();
-		
-		if(line == null) {
-			try {
-				line = seekableFile.read(this);
-				cache = new WeakReference<>(line);
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-		}
-		
-		return line;
-	}
-
-	@Override
-	public int length() {
-		return len;
-	}
-
-	@Override
-	public char charAt(int index) {
-		String line = toString();
-		return line != null ? line.charAt(index) : 0;
-	}
-
-	@Override
-	public CharSequence subSequence(int start, int end) {
-		String line = toString();
-		return line != null ? line.subSequence(start, end) : "";
-	}
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/ProgressMonitor.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-package at.ssw.visualizer.logviewer.model.io;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public interface ProgressMonitor {
-
-	/**
-	 * Triggered when some work has been done.<br><br>
-	 * <b>Attention</b>: This method runs on the same thread as the reading process.
-	 * If time-consuming tasks should be executed, please consider multithreading.
-	 * @param percentage Value in range between 0 and 1 to indicate how much work has been done.
-	 */
-	public void worked(float percentage);
-	
-	/**
-	 * Triggered when work is done completely.<br><br>
-	 * <b>Attention</b>: This method runs on the same thread as the reading process.
-	 * If time-consuming tasks should be executed, please consider multithreading.
-	 */
-	public void finished();
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFile.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-package at.ssw.visualizer.logviewer.model.io;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class SeekableFile implements Closeable {
-
-	private final RandomAccessFile raf;
-	private List<FileLine> lines = new ArrayList<>();
-	
-	SeekableFile(File file) throws FileNotFoundException {
-		raf = new RandomAccessFile(file, "r");
-	}
-	
-	void addLine(long off, int len) {
-		lines.add(new FileLine(this, off, len));
-	}
-	
-	public int size() {
-		return lines.size();
-	}
-	
-	public FileLine get(int lineNum) throws IOException {
-		FileLine line = lines.get(lineNum);
-		return line;
-	}
-	
-	String read(FileLine line) throws IOException {
-		if(line == null) throw new IllegalArgumentException("line is null");
-		raf.seek(line.off);
-
-		byte [] buf = new byte[line.len];
-		
-		if(raf.read(buf) != line.len) throw new IOException("error while reading line");
-		
-		return new String(buf);
-	}
-
-	@Override
-	public void close() throws IOException {
-		raf.close();
-	}
-	
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFileReader.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-package at.ssw.visualizer.logviewer.model.io;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-
-/**
- *
- * @author Alexander Stipsits
- */
-public class SeekableFileReader extends Reader {
-	
-	public static final int DEFAULT_GAP = 1024; // in bytes
-
-	private final FileReader reader;
-	private SeekableFile seekableFile;
-	private ProgressMonitor monitor;
-	private long filelen;
-	private int gap;
-	
-	public SeekableFileReader(File file) throws IOException {
-		super(file);
-		reader = new FileReader(file);
-		seekableFile = new SeekableFile(file);
-	}
-	
-	public SeekableFileReader(File file, ProgressMonitor monitor, int gap) throws IOException {
-		this(file);
-		this.monitor = monitor;
-		this.filelen = file.length();
-		this.gap = gap;
-	}
-	
-	public SeekableFileReader(File file, ProgressMonitor monitor) throws IOException {
-		this(file, monitor, DEFAULT_GAP);
-	}
-	
-	public SeekableFile getSeekableFile() {
-		return seekableFile;
-	}
-
-    @Override
-	public void close() throws IOException {
-		reader.close();		
-	}
-	
-	private long bytes = 0;
-	private boolean skipLF = false;
-	private long off;
-	private long lastGapped = 0;
-	private boolean finished = false;
-
-	@Override
-	public int read(char[] cbuf, int offset, int length) throws IOException {
-		
-		int l = reader.read(cbuf, offset, length);
-		
-		if(l == -1 && !finished) {
-			seekableFile.addLine(off, (int)(bytes-off));
-			finished = true;
-			if(monitor != null) {
-				monitor.worked(1);
-				monitor.finished();
-			}
-		}
-		
-		for(int i = 0; i < l; ++i) {
-			Character ch = new Character(cbuf[i]);
-			int chlen = ch.toString().getBytes(reader.getEncoding()).length;
-				
-			if(skipLF && ch != '\n') {
-				seekableFile.addLine(off, (int)(bytes-off-chlen));
-				off = bytes;
-				skipLF = false;
-			}
-			
-			bytes += chlen;
-			
-			if(monitor != null) {
-				if(bytes > lastGapped+gap) {
-					lastGapped = bytes;
-					monitor.worked(((float)bytes)/((float)filelen));
-				}
-			}
-			
-			if(ch == '\r') {
-				skipLF = true;
-			}
-			if(ch == '\n') {
-				seekableFile.addLine(off, (int)(bytes-off-(skipLF ? 2*chlen : chlen)));
-				off = bytes;
-				skipLF = false;
-			}
-		}
-		
-		return l;
-	}
-	
-	
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkDialog.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-package at.ssw.visualizer.logviewer.scene;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.GridLayout;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.List;
-import javax.swing.*;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class BookmarkDialog extends JDialog {
-    
-    private JList lstBookmarks;
-    private List<LogLine> logLines;
-    
-    public BookmarkDialog(List<LogLine> bookmarks, Window parent) {
-        super(parent, JDialog.ModalityType.APPLICATION_MODAL);
-        
-        this.logLines = bookmarks;
-        
-        DefaultListModel mdlBookmarks = new DefaultListModel();
-        lstBookmarks = new JList(mdlBookmarks);
-        JScrollPane jspBookmarks = new JScrollPane(lstBookmarks);
-        
-        for (LogLine bookmark : bookmarks) {
-            mdlBookmarks.addElement(bookmark.getLineNumber() + ": Method " + bookmark.getMethod() + " - Scope " + bookmark.getScope() + " - " + bookmark.getText());
-        }
-        
-        JButton btnOk = new JButton("Go to");
-        JButton btnCancel = new JButton("Cancel");
-
-        // init listeners
-        lstBookmarks.addMouseListener(new MouseAdapter() {
-            @Override
-            public void mouseClicked(MouseEvent e) {
-                if (e.getClickCount() == 2) {
-                    close();
-                }
-            }
-        });
-        
-        btnOk.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                if (lstBookmarks.isSelectionEmpty())
-                    return;
-                close();
-            }
-        });
-        btnCancel.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                lstBookmarks.clearSelection();
-                close();
-            }
-        });
-        
-        // build layout
-        JPanel pnlButtons = new JPanel();
-        
-        pnlButtons.setLayout(new GridLayout(1, 2));
-        pnlButtons.add(btnOk);
-        pnlButtons.add(btnCancel);
-        
-        this.setLayout(new BorderLayout());
-        this.add(jspBookmarks, BorderLayout.CENTER);
-        this.add(pnlButtons, BorderLayout.SOUTH);
-        
-        this.pack();
-        this.setMinimumSize(new Dimension(600, this.getPreferredSize().height));
-        this.setLocationRelativeTo(parent);
-        this.setResizable(false);
-        this.setVisible(true);
-    }
-    
-    public LogLine getTarget() {
-        if (lstBookmarks.isSelectionEmpty())
-            return null;
-        return logLines.get(lstBookmarks.getSelectedIndex());
-    }
-    
-    private void close() {
-        this.setVisible(false);
-        this.dispose();
-    }
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkableLogViewer.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +0,0 @@
-package at.ssw.visualizer.logviewer.scene;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextPane;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.DefaultHighlighter;
-import javax.swing.text.Highlighter;
-import javax.swing.text.JTextComponent;
-import org.openide.util.Exceptions;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class BookmarkableLogViewer extends JPanel {
-
-    private static final Color BOOKMARK_COLOR = Color.CYAN;
-    
-    private static final Highlighter.HighlightPainter BOOKMARK_PAINTER =
-            new DefaultHighlighter.DefaultHighlightPainter(BOOKMARK_COLOR);
-    
-    private JTextPane txpText;
-    private JTextPane txpLines;
-    private Highlighter textHighlighter;
-    private Highlighter lineHighlighter;
-    private FontMetrics fm;
-    private Map<Integer, Bookmark> bookmarks = new TreeMap<>();
-    private List<LogLine> logLines = new ArrayList<>();
-
-    public BookmarkableLogViewer() {
-        init();
-    }
-
-    private void init() {
-        txpText = new JTextPane();
-        txpLines = new JTextPane();
-
-        // needed for correct layouting
-        Insets ins = txpLines.getInsets();
-        txpLines.setMargin(new Insets(ins.top + 1, ins.left, ins.bottom, ins.right));
-
-        textHighlighter = new BookmarkHighlighter();
-        lineHighlighter = new BookmarkHighlighter();
-
-        txpText.setHighlighter(textHighlighter);
-        //txpText.setMinimumSize(new Dimension(100, 100));
-        txpText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
-        txpText.setEditable(false);
-
-        txpLines.setHighlighter(lineHighlighter);
-        txpLines.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
-        txpLines.setBackground(Color.LIGHT_GRAY);
-        txpLines.setEnabled(false);
-        txpLines.setForeground(Color.BLACK);
-        txpLines.addMouseListener(mouseInputListener);
-
-        fm = txpText.getFontMetrics(txpText.getFont());
-
-        JPanel pnlBookmarks = new JPanel();
-        pnlBookmarks.setLayout(new BorderLayout());
-        pnlBookmarks.add(txpText, BorderLayout.CENTER);
-
-        JScrollPane jspBookmarks = new JScrollPane(pnlBookmarks);
-        jspBookmarks.setRowHeaderView(txpLines);
-        jspBookmarks.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
-        jspBookmarks.getVerticalScrollBar().setUnitIncrement(15);
-
-        this.setLayout(new BorderLayout());
-        this.add(jspBookmarks, BorderLayout.CENTER);
-    }
-   
-    public int getCurrentlyDisplayedTopLine() {
-        Rectangle view = txpText.getVisibleRect();
-        return getAbsoluteLine((int) Math.ceil(view.y/fm.getHeight()));
-    }
-    
-    public int getCurrentTopLine() {
-        return logLines.get(0).getLineNumber();
-    }
-    
-    public int getCurrentBottomLine() {
-        return logLines.get(logLines.size()-1).getLineNumber();
-    }
-
-    public void clearLogLines() {
-        this.logLines = new ArrayList<>();
-        txpText.setText("");
-        txpLines.setText("");
-        clearHighlighter();
-    }
-
-    public void setLogLines(List<LogLine> logLines) {
-        this.logLines = logLines;
-
-        clearHighlighter();
-        clearLineNumbers();
-        String text = "";
-        for (int i = 0; i < logLines.size(); i++) {
-            text += logLines.get(i).getText();
-            if (i < logLines.size() - 1) {
-                text += "\n";
-            }
-        }
-        txpText.setText(text);
-        setLineNumbers();
-   
-        txpText.setCaretPosition(0);
-        txpLines.setCaretPosition(0);
-
-        for (int bookmark : bookmarks.keySet()) {
-            if (bookmark < logLines.get(0).getLineNumber()) {
-                continue;
-            }
-            if (bookmark > logLines.get(logLines.size() - 1).getLineNumber()) {
-                break;
-            }
-
-            int line = getRelativeLine(bookmark);
-
-            addHighlight(logLines.get(line));
-        }
-    }
-
-    public void setLogLines(List<LogLine> logLines, int focus) {
-        setLogLines(logLines);
-        
-        //does not work for some reason - jtextpane jumps to caret position afterwards
-        //moveToBookmark(focus);
-        
-        //workaround - set caret position bevore moving
-        Rectangle visible = txpText.getVisibleRect();
-        int visibleLines = (int)(Math.ceil(visible.height/fm.getHeight()));
-
-        String text = txpText.getText();
-        int line = logLines.get(0).getLineNumber();
-        for (int i = 0; i < text.length(); i++) {
-            if (text.charAt(i) == '\n')
-                line++;
-            if (line == focus+visibleLines || i == text.length() - 1) {
-                txpText.setCaretPosition(i);
-                break;
-            }
-        }
-        moveToBookmark(focus);
-    }
-
-    public List<LogLine> getBookmarkedLines() {
-        List<LogLine> lines = new ArrayList<>();
-        for (int bookmark : bookmarks.keySet()) {
-            lines.add(bookmarks.get(bookmark).logLine);
-        }
-        return lines;
-    }
-
-    public int tryLastBookmark() {
-        int line = getCurrentlyDisplayedTopLine();
-        
-        int firstShownLine = getCurrentTopLine();
-
-        int bookmarkKey = -1;
-        for (int key : bookmarks.keySet()) {
-            if (key >= line) {
-                break;
-            }
-
-            bookmarkKey = key;
-        }
-
-        if (bookmarkKey >= firstShownLine) {
-            moveToBookmark(bookmarkKey);
-            return -1;
-        }
-
-        return bookmarkKey;
-    }
-
-    public int tryNextBookmark() {
-        Rectangle visible = txpText.getVisibleRect();
-        int lastLine = (int) Math.floor((visible.y + visible.height) / fm.getHeight());
-        lastLine = getAbsoluteLine(lastLine);
-
-        int lastShownLine = getCurrentBottomLine();
-
-        int bookmarkKey = -1;
-        for (int key : bookmarks.keySet()) {
-            if (key > lastLine) {
-                bookmarkKey = key;
-                break;
-            }
-            if (key > lastShownLine) {
-                break;
-            }
-        }
-
-        if (bookmarkKey > 0 && bookmarkKey <= lastShownLine) {
-            moveToBookmark(bookmarkKey);
-            return -1;
-        }
-
-        return bookmarkKey;
-    }
-
-    private void moveToBookmark(int line) {
-        int relLine = getRelativeLine(line);
-        Rectangle visible = txpText.getVisibleRect();
-        Rectangle position = new Rectangle(0, relLine * fm.getHeight(), visible.width, visible.height);
-        txpText.scrollRectToVisible(position);
-    }
-
-    private int getAbsoluteLine(int line) {
-        return logLines.get(0).getLineNumber() + line;
-    }
-
-    private int getRelativeLine(int line) {
-        return line - logLines.get(0).getLineNumber();
-    }
-
-    private int getStartOffset(JTextComponent component, int line) {
-        return component.getDocument().getDefaultRootElement().getElement(line).getStartOffset();
-    }
-
-    private int getEndOffset(JTextComponent component, int line) {
-        return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset();
-    }
-
-    private void addHighlight(LogLine logLine) {
-        try {
-            int line = logLine.getLineNumber();
-            int relativeLine = getRelativeLine(line);
-
-            Object hl1 = textHighlighter.addHighlight(getStartOffset(txpText, relativeLine), getEndOffset(txpText, relativeLine), BOOKMARK_PAINTER);
-            Object hl2 = lineHighlighter.addHighlight(getStartOffset(txpLines, relativeLine), getEndOffset(txpLines, relativeLine), BOOKMARK_PAINTER);
-            bookmarks.put(line, new Bookmark(logLine, hl1, hl2));
-        } catch (BadLocationException ex) {
-            Exceptions.printStackTrace(ex);
-        }
-    }
-
-    private void removeHighlight(int line) {
-        int abs = getAbsoluteLine(line);
-        Bookmark bookmark = bookmarks.get(abs);
-        textHighlighter.removeHighlight(bookmark.hl1);
-        lineHighlighter.removeHighlight(bookmark.hl2);
-        bookmarks.remove(abs);
-    }
-
-    public void clearBookmarks() {
-        bookmarks = new TreeMap<>();
-        clearHighlighter();
-    }
-
-    private void clearHighlighter() {
-        textHighlighter.removeAllHighlights();
-        lineHighlighter.removeAllHighlights();
-    }
-
-    private void clearLineNumbers() {
-        txpLines.setText("");
-    }
-
-    private void setLineNumbers() {
-        clearLineNumbers();
-
-        if (logLines.isEmpty()) {
-            return;
-        }
-
-        int colCnt = String.valueOf(logLines.get(logLines.size() - 1).getLineNumber()).length() + 2;
-
-        int firstNr = logLines.get(0).getLineNumber();
-        String text = String.format("%" + colCnt + "s", firstNr + " ");
-        for (int i = 1; i < logLines.size(); i++) {
-            text += "\n";
-            text += String.format("%" + colCnt + "s", (firstNr + i) + " ");
-        }
-        txpLines.setText(text);
-    }
-
-    private MouseListener mouseInputListener = new MouseAdapter() {
-
-        @Override
-        public void mouseClicked(MouseEvent me) {
-            if (txpLines.getText().length() == 0) {
-                return;
-            }
-            if (me.getClickCount() == 2) {
-                int caretPos = txpLines.getCaretPosition();
-
-                int lineOffset = txpLines.getDocument().getDefaultRootElement().getElementIndex(caretPos);
-                if (txpLines.getText().charAt(caretPos - 1) == '\n') {
-                    lineOffset--;
-                }
-
-                if (bookmarks.containsKey(getAbsoluteLine(lineOffset))) {
-                    removeHighlight(lineOffset);
-                } else {
-                    addHighlight(logLines.get(lineOffset));
-                }
-            }
-        }
-    };
-
-    class Bookmark {
-
-        public final LogLine logLine;
-        public final Object hl1;
-        public final Object hl2;
-
-        public Bookmark(LogLine logLine, Object hl1, Object hl2) {
-            this.logLine = logLine;
-            this.hl1 = hl1;
-            this.hl2 = hl2;
-        }
-    }
-
-    class BookmarkHighlighter extends DefaultHighlighter {
-
-        private JTextComponent component;
-
-        @Override
-        public void install(JTextComponent component) {
-            super.install(component);
-            this.component = component;
-        }
-
-        @Override
-        public void deinstall(JTextComponent component) {
-            super.deinstall(component);
-            this.component = null;
-        }
-
-        @Override
-        public void paint(Graphics g) {
-            Highlighter.Highlight[] highlights = getHighlights();
-
-            for (int i = 0; i < highlights.length; i++) {
-                Highlighter.Highlight hl = highlights[i];
-                Rectangle bg = component.getBounds();
-                Insets insets = component.getInsets();
-                bg.x = insets.left;
-                bg.y = insets.top;
-                bg.height = insets.top + insets.bottom;
-                Highlighter.HighlightPainter painter = hl.getPainter();
-                painter.paint(g, hl.getStartOffset(), hl.getEndOffset(), bg, component);
-            }
-        }
-    }
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/ImportLogErrorDialog.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-package at.ssw.visualizer.logviewer.scene;
-
-import at.ssw.visualizer.logviewer.model.LogParser;
-import java.awt.Component;
-import java.util.List;
-import javax.swing.JOptionPane;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class ImportLogErrorDialog {
-    
-    public static void showDialog(Component parent, List<LogParser.ParseError> errors) {
-        JTextArea txaErrors = new JTextArea();
-        
-        for (LogParser.ParseError error : errors) {
-            txaErrors.append("Error at line " + error.getLineNumber());
-            txaErrors.append(": " + error.getMessage());
-            txaErrors.append("\n");
-            txaErrors.append("Log line: " + error.getLine());
-            txaErrors.append("\n");
-        }
-        
-        JScrollPane scpErrors = new JScrollPane(txaErrors);
-        
-        JOptionPane.showMessageDialog(parent, scpErrors, "Parse errors", JOptionPane.ERROR_MESSAGE);
-    }
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/LogScene.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,651 +0,0 @@
-package at.ssw.visualizer.logviewer.scene;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-import at.ssw.visualizer.logviewer.model.LogModel;
-import at.ssw.visualizer.logviewer.model.LogParser;
-import at.ssw.visualizer.logviewer.model.filter.Filter;
-import at.ssw.visualizer.logviewer.model.filter.FilterManager;
-import at.ssw.visualizer.logviewer.model.io.ProgressMonitor;
-import at.ssw.visualizer.logviewer.scene.model.LogTableModel;
-import at.ssw.visualizer.logviewer.scene.model.TableLine;
-import java.awt.*;
-import java.awt.event.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.regex.PatternSyntaxException;
-import javax.swing.*;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.TableCellRenderer;
-import javax.swing.table.TableColumn;
-import org.openide.util.Exceptions;
-import org.openide.util.NbPreferences;
-import sun.awt.CausedFocusEvent;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class LogScene extends JPanel {
-    private static final String PREFERENCE_DIR = "dir";
-    
-    private static final String ICON_PREFIX = "/at/ssw/visualizer/logviewer/scene/icons/";
-    private static final String ICON_ARROW_DOWN = ICON_PREFIX + "arrow_down.png";
-    private static final String ICON_ARROW_UP = ICON_PREFIX + "arrow_up.png";
-    private static final String ICON_BOOKMARK_BACK = ICON_PREFIX + "bookmark_back.png";
-    private static final String ICON_BOOKMARK_FWD = ICON_PREFIX + "bookmark_forward.png";
-    private static final String ICON_BOOKMARK_LIST = ICON_PREFIX + "bookmark_list.png";
-    private static final String ICON_LOAD = ICON_PREFIX + "loading.gif";
-    
-    private static final ImageIcon IMGICON_LOAD = new ImageIcon(LogScene.class.getResource(ICON_LOAD));
-    
-    private static final int LOG_LINES = 50;
-    private static final int KEYSTROKE_RATE = 100; // rate at which the keystrokes are checked
-    private static final int KEYSTROKE_TRESHOLD = 400; // time in ms after which a search is triggered
-            
-    private FilterManager filterManager;
-    private Thread filterRunThread;
-    
-    private int timeSinceLastKeystroke = -1;
-    
-    private JLabel lblMessage;
-    private JLabel lblIcon;
-    
-    private JLabel lblMethodFilter;
-    private JLabel lblScopeFilter;
-    private JLabel lblNodeFilter;
-    private JLabel lblFulltextFilter;
-    private JTextField txfMethodFilter;
-    private JTextField txfScopeFilter;
-    private JTextField txfNodeFilter;
-    private JTextField txfFulltextFilter;
-    
-    private JTable tblResult;
-    private LogTableModel tblResultModel;
-    
-    private BookmarkableLogViewer logViewer;
-    private JButton btnBookmarkBack;
-    private JButton btnBookmarkFwd;
-    private JButton btnBookmarkList;
-    private JButton btnLoadMoreUp;
-    private JButton btnLoadMoreDown;
-    
-    private LogParser parser = new LogParser();
-    private LogModel logModel = null;
-    private LogStatus logStatus = LogStatus.NO_LOG;
-    
-    private static LogScene instance;
-    
-    private enum LogStatus {
-        NO_LOG, LOADING, ACTIVE
-    }
-
-    public static LogScene getInstance() {
-        return instance;
-    }
-    
-    public LogScene() {
-        initComponents();
-    }
-    
-    private void initComponents() {
-        filterManager = new FilterManager();
-        
-        lblMessage = new JLabel("No logfile loaded.");
-        lblIcon = new JLabel("");
-        
-        // Initialize filter components
-        lblMethodFilter = new JLabel("Target Method:");
-        lblScopeFilter = new JLabel("Scope:");
-        lblNodeFilter = new JLabel("Node:");
-        lblFulltextFilter = new JLabel("Fulltext:");
-        
-        txfMethodFilter = new JTextField();
-        txfScopeFilter = new JTextField();
-        txfNodeFilter = new JTextField();
-        txfFulltextFilter = new JTextField();
-        
-        tblResultModel = new LogTableModel();
-        tblResult = new JTable(tblResultModel);
-        tblResult.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        tblResult.getTableHeader().setReorderingAllowed(false);
-        tblResult.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
-        
-        Dimension dim = tblResult.getPreferredScrollableViewportSize();
-        tblResult.setPreferredScrollableViewportSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
-        JScrollPane scpTblResult = new JScrollPane(tblResult);
-        scpTblResult.setMinimumSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
-        
-        logViewer = new BookmarkableLogViewer();
-        
-        btnLoadMoreUp = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_UP)));
-        btnLoadMoreDown = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_DOWN)));
-        
-        btnLoadMoreUp.setFocusable(false);
-        btnLoadMoreUp.setToolTipText("Load more previous log lines");
-        
-        btnLoadMoreDown.setFocusable(false);
-        btnLoadMoreDown.setToolTipText("Load more following log lines");
-        
-        btnBookmarkBack = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_BACK)));
-        btnBookmarkList = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_LIST)));
-        btnBookmarkFwd = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_FWD)));
-        
-        btnBookmarkBack.setFocusable(false);
-        btnBookmarkBack.setToolTipText("Navigate to the last bookmark.");
-        
-        btnBookmarkFwd.setFocusable(false);
-        btnBookmarkFwd.setToolTipText("Navigate to the next bookmark.");
-        
-        btnBookmarkList.setFocusable(false);
-        btnBookmarkList.setToolTipText("List all known bookmarks.");
-        
-        JPanel pnl = new JPanel();
-        pnl.setLayout(new GridBagLayout());
-        pnl.setOpaque(false);
-        
-        JPanel logViewerPanel = new JPanel();
-        logViewerPanel.setLayout(new GridBagLayout());
-        logViewerPanel.setOpaque(false);
-        
-        JPanel messagePanel = new JPanel();
-        messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.LINE_AXIS));
-        messagePanel.setOpaque(false);
-        
-        // Initialize Listeners
-        initListeners();
-        
-        // Layout components
-        GridBagConstraints gbc = new GridBagConstraints();
-        
-        messagePanel.add(lblMessage);
-        messagePanel.add(Box.createHorizontalGlue());
-        messagePanel.add(lblIcon);
-        
-        Insets standardInsets = gbc.insets;
-        
-        gbc.gridx = 0;
-        gbc.gridy = 0;
-        gbc.anchor = GridBagConstraints.WEST;
-        gbc.fill = GridBagConstraints.HORIZONTAL;
-        gbc.weightx = 1;
-        gbc.weighty = 0;
-        gbc.gridwidth = 2;
-        gbc.insets = new Insets(2, 0, 2, 0);
-        pnl.add(messagePanel, gbc);
-        
-        gbc.fill = GridBagConstraints.NONE;
-        gbc.gridwidth = 1;
-        gbc.weightx = 0;
-        gbc.weighty = 0;
-        gbc.gridy++;
-        gbc.insets = standardInsets;
-        pnl.add(lblMethodFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(lblScopeFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(lblNodeFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(lblFulltextFilter, gbc);
-        
-        gbc.gridx++;
-        gbc.gridy = 1;
-        gbc.fill = GridBagConstraints.HORIZONTAL;
-        gbc.weightx = 0.75;
-        pnl.add(txfMethodFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(txfScopeFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(txfNodeFilter, gbc);
-        
-        gbc.gridy++;
-        pnl.add(txfFulltextFilter, gbc);
-        
-        gbc.gridx = 0;
-        //gbc.gridy++;
-        gbc.gridwidth = 2;
-        gbc.weightx = 1;
-        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
-        //pnl.add(btnSearch, gbc);
-        
-        gbc.gridy++;
-        pnl.add(scpTblResult, gbc);
-        
-        gbc.gridy++;
-        gbc.weighty = 1;
-        gbc.fill = GridBagConstraints.BOTH;
-        pnl.add(logViewerPanel, gbc);
-        
-        gbc = new GridBagConstraints();
-        gbc.gridx = 0;
-        gbc.gridy = 0;
-        gbc.gridheight = 6;
-        gbc.weightx = 1;
-        gbc.weighty = 1;
-        gbc.fill = GridBagConstraints.BOTH;
-        logViewerPanel.add(logViewer, gbc);
-        
-        gbc.gridx++;
-        gbc.weightx = 0;
-        gbc.weighty = 0;
-        gbc.fill = GridBagConstraints.NONE;
-        gbc.anchor = GridBagConstraints.PAGE_START;
-        gbc.gridheight = 1;
-        logViewerPanel.add(btnLoadMoreUp, gbc);
-        
-        gbc.gridy++;
-        logViewerPanel.add(btnLoadMoreDown, gbc);
-        
-        gbc.gridy++;
-        logViewerPanel.add(Box.createRigidArea(btnLoadMoreUp.getSize()));
-        
-        gbc.gridy++;
-        logViewerPanel.add(btnBookmarkBack, gbc);
-        
-        gbc.gridy++;
-        logViewerPanel.add(btnBookmarkFwd, gbc);
-        
-        gbc.gridy++;
-        logViewerPanel.add(btnBookmarkList, gbc);
-        
-        this.setLayout(new BorderLayout());
-        this.add(pnl, BorderLayout.CENTER);
-        
-        Timer keyTimer = new Timer();
-        keyTimer.scheduleAtFixedRate(new KeystrokeTimer(), KEYSTROKE_RATE, KEYSTROKE_RATE);
-        
-        LogScene.instance = this;
-    }
-    
-    private void initListeners() {
-        txfMethodFilter.addKeyListener(new FilterKeyListener());
-        txfScopeFilter.addKeyListener(new FilterKeyListener());
-        txfNodeFilter.addKeyListener(new FilterKeyListener());
-        txfFulltextFilter.addKeyListener(new FilterKeyListener());
-        
-        txfMethodFilter.addFocusListener(new FilterFocusListener());
-        txfScopeFilter.addFocusListener(new FilterFocusListener());
-        txfNodeFilter.addFocusListener(new FilterFocusListener());
-        txfFulltextFilter.addFocusListener(new FilterFocusListener());
-        
-        btnLoadMoreUp.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                int line = logViewer.getCurrentlyDisplayedTopLine();
-                int top = logViewer.getCurrentTopLine();
-                int bottom = logViewer.getCurrentBottomLine();
-                logViewer.setLogLines(logModel.range(line, line - top + LOG_LINES, bottom - line), line); 
-            } 
-        });
-        
-        btnLoadMoreDown.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                int line = logViewer.getCurrentlyDisplayedTopLine();
-                int top = logViewer.getCurrentTopLine();
-                int bottom = logViewer.getCurrentBottomLine();
-                logViewer.setLogLines(logModel.range(line, line - top, bottom - line + LOG_LINES), line); 
-            } 
-        });
-        
-        btnBookmarkBack.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                int result = logViewer.tryLastBookmark();
-                if (result >= 0) {
-                    tblResult.clearSelection();
-                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result); 
-                }
-            }
-        });
-        
-        btnBookmarkFwd.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                int result = logViewer.tryNextBookmark();
-                if (result >= 0) {
-                    tblResult.clearSelection();
-                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result);
-                }
-            }
-        });
-        
-        btnBookmarkList.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent ae) {
-                List<LogLine> bookmarkedLines = logViewer.getBookmarkedLines();
-                if (bookmarkedLines.size() > 0) {
-                    BookmarkDialog bd = new BookmarkDialog(bookmarkedLines, null);
-                    if (bd.getTarget() != null) {
-                        LogLine target = bd.getTarget();
-                        int line = target.getLineNumber();
-                        logViewer.setLogLines(logModel.range(line, LOG_LINES, LOG_LINES), line); 
-                    }
-                } else {
-                    JOptionPane.showMessageDialog(LogScene.this, "No bookmarks set.", "", JOptionPane.INFORMATION_MESSAGE);
-                }
-            }
-        });
-        
-        tblResult.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-            @Override
-            public void valueChanged(ListSelectionEvent lse) {
-                if (tblResult.getSelectedRow() == -1) {
-                    logViewer.clearLogLines();
-                    return;
-                }
-                
-                TableLine selectedLine = tblResultModel.getTableLine(tblResult.getSelectedRow());
-                int firstLine = selectedLine.getFirstLine();
-                int lastLine = selectedLine.getLastLine();
-                
-                if (firstLine == lastLine) { 
-                    // only display selected line
-                    List<LogLine> line = new ArrayList<>();
-                    line.add(selectedLine.getLogLine());
-                    logViewer.setLogLines(line);
-                } else {
-                    // display selected range
-                    int pre = firstLine==lastLine?LOG_LINES:selectedLine.getLogLine().getLineNumber()-firstLine;
-                    int post = firstLine==lastLine?LOG_LINES:lastLine-selectedLine.getLogLine().getLineNumber();
-
-                    logViewer.setLogLines(logModel.range(selectedLine.getLogLine(), pre, post));           
-                }
-            }
-        });
-    }
-    
-    private boolean executeFilters() {
-        if (logStatus == LogStatus.NO_LOG) {
-            loadLogFile();
-            return false;
-        }
-        if (logStatus == LogStatus.LOADING) {
-            return false;
-        }
-
-        boolean execute = trySetFilter(filterManager.getMethodFilter(), txfMethodFilter.getText().trim(), lblMethodFilter);
-        execute = trySetFilter(filterManager.getScopeFilter(), txfScopeFilter.getText().trim(), lblScopeFilter) || execute;
-        try {
-            // node number
-            int node = Integer.parseInt(txfNodeFilter.getText().trim());
-            execute = trySetFilter(filterManager.getNodeFilter(), node, lblNodeFilter) || execute;
-        } catch (Exception e) {
-            // node name
-            execute = trySetFilter(filterManager.getNodeFilter(), txfNodeFilter.getText().trim(), lblNodeFilter) || execute;
-        }
-        execute = trySetFilter(filterManager.getFullTextFilter(), txfFulltextFilter.getText().trim(), lblFulltextFilter) || execute;
-
-        if (!execute)
-            return true;
-        
-        tryInterruptFilter();
-
-        filterRunThread = new Thread(new Runnable() {
-
-            @Override
-            public void run() {
-                try {
-                    List<LogLine> result = filterManager.execute(logModel);
-                    lblIcon.setIcon(null);
-
-                    if (!Thread.interrupted())
-                        buildTableEntries(result);
-                } catch (InterruptedException e) {
-                }
-            }
-
-        });
-        lblIcon.setIcon(IMGICON_LOAD);
-        filterRunThread.start();
-        
-        return true;
-    }
-    
-    private boolean trySetFilter(Filter filter, Object constraint, JLabel marker) {
-        try {
-            filter.setConstraints(constraint);
-            marker.setForeground(Color.BLACK);
-            return constraint != null && (!(constraint instanceof String) || (constraint instanceof String && ((String)constraint).trim().length() > 0));
-        } catch (PatternSyntaxException e) {
-            filter.setConstraints(new Object[]{});
-            marker.setForeground(Color.RED);
-            return false;
-        }
-    }
-    
-    private void tryInterruptFilter() {
-        if (filterRunThread != null && (filterRunThread.isAlive() || !filterRunThread.isInterrupted())) {
-            lblIcon.setIcon(null);
-            filterRunThread.interrupt();
-        }
-    }
-    
-    private void buildTableEntries(List<LogLine> filterResult) {
-        List<TableLine> tableEntries;
-        
-        int methodLength = txfMethodFilter.getText().trim().length();
-        int scopeLength = txfScopeFilter.getText().trim().length();
-        int nodeLength = txfNodeFilter.getText().trim().length();
-        int fulltextLength = txfFulltextFilter.getText().trim().length();
-        
-        boolean preventGrouping = nodeLength != 0 || fulltextLength != 0;
-        
-        if (!preventGrouping && methodLength > 0 && scopeLength == 0) {
-            tableEntries = groupByMethod(filterResult);
-        } else if (!preventGrouping && scopeLength > 0) {
-            tableEntries = groupByScope(filterResult);
-        } else {
-            tableEntries = showAllLines(filterResult);
-        }
-        
-        tblResultModel.setLogEntries(tableEntries);
-        
-        int width = 0;
-        for (int i = 0; i < tableEntries.size(); i++) {
-            TableCellRenderer tcr = tblResult.getCellRenderer(i, 0);
-            Component c = tcr.getTableCellRendererComponent(tblResult, tblResultModel.getValueAt(i, 0), false, false, i, 0);
-            if (c instanceof JLabel) {
-                JLabel l = (JLabel) c;
-                FontMetrics fm = l.getFontMetrics(l.getFont());
-                width = Math.max(width, fm.stringWidth(l.getText()));
-            }
-        }
-       
-        // proper resizing of column
-        // setWidth and setPreferredWidth do not trigger resize
-        TableColumn col = tblResult.getColumnModel().getColumn(0);
-        col.setMinWidth(width+5);
-        col.setMaxWidth(width+5);
-        
-        // reenable resizing for user
-        col.setMinWidth(0);
-        col.setMaxWidth(999);
-    }
-    
-    private List<TableLine> groupByMethod(List<LogLine> filterResult) {
-        List<TableLine> tableEntries = new ArrayList<>();
-        int firstLine = -1;
-        for (int i = 0; i < filterResult.size(); i++) {
-            LogLine line = filterResult.get(i);
-            
-            if (firstLine < 0)
-                firstLine = line.getLineNumber();
-
-            if (i < filterResult.size() - 1) {
-                LogLine next = filterResult.get(i+1);
-                if (line.getMethod() != next.getMethod()) {
-                    tableEntries.add(new TableLine(line, firstLine));
-                    firstLine = next.getLineNumber();
-                }
-            } else {
-                tableEntries.add(new TableLine(line, firstLine));
-            }
-        }
-        return tableEntries;
-    }
-    
-    private List<TableLine> groupByScope(List<LogLine> filterResult) {
-        List<TableLine> tableEntries = new ArrayList<>();
-        LogLine firstScopeLine = null;
-        for (int i = 0; i < filterResult.size(); i++) {
-            LogLine line = filterResult.get(i);
-            
-            if (firstScopeLine == null)
-                firstScopeLine = line;
-
-            if (i < filterResult.size() - 1) {
-                LogLine next = filterResult.get(i+1);
-                if (line.getScope() != next.getScope()) {
-                    tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
-                    firstScopeLine = next;
-                }
-            } else {
-                tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
-            }
-        }
-        return tableEntries;
-    }
-    
-    private List<TableLine> showAllLines(List<LogLine> filterResult) {
-        List<TableLine> tableEntries = new ArrayList<>();
-        for (LogLine line : filterResult) {
-            tableEntries.add(new TableLine(line));
-        }
-        return tableEntries;
-    }
-    
-    public void loadLogFile() {
-        JFileChooser fc = new JFileChooser();
-        fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
-
-            @Override
-            public boolean accept(File f) {
-                return f.isDirectory() ||
-                       f.getName().toLowerCase().endsWith(".txt") ||
-                       f.getName().toLowerCase().endsWith(".log");
-            }
-
-            @Override
-            public String getDescription() {
-                return "Log files (*.txt, *.log)";
-            }
-        });
-        fc.setCurrentDirectory(new File(NbPreferences.forModule(LogScene.class).get(PREFERENCE_DIR, "~")));
-        fc.setDialogTitle("Load log file");
-
-        if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
-            tryInterruptFilter();
-            
-            final File file = fc.getSelectedFile();
-            
-            NbPreferences.forModule(LogScene.class).put(PREFERENCE_DIR, file.getParent());
-            
-            lblIcon.setIcon(IMGICON_LOAD);
-            logStatus = LogStatus.LOADING;
-            new Thread(new Runnable(){
-
-                @Override
-                public void run() {
-                    try {
-                        logModel = parser.parse(file, new LoadProgressMonitor(lblMessage, "Loading file " + file.getName() + "..."));
-                        lblIcon.setIcon(null);
-                        lblMessage.setText("Current logfile: " + file.getName());
-                        logStatus = LogStatus.ACTIVE;
-                    } catch (IOException ex) {
-                        Exceptions.printStackTrace(ex);
-                    }
-                }
-
-            }).start();
-        }
-    }
-    
-    private class FilterKeyListener extends KeyAdapter {
-        @Override
-        public void keyTyped(KeyEvent e) {
-            tryInterruptFilter();
-            timeSinceLastKeystroke = 0;
-        }
-    }
-    
-    private class FilterFocusListener implements FocusListener {
-        private boolean ignore = false;
-        
-        @Override
-        public void focusGained(FocusEvent fe) {
-            if (!ignore && logStatus == LogStatus.NO_LOG) {
-                ignore = true;
-                loadLogFile();
-            }
-        }
-
-        @Override
-        public void focusLost(FocusEvent fe) {
-            if (fe instanceof CausedFocusEvent) {
-                CausedFocusEvent cfe = (CausedFocusEvent) fe;
-                ignore = ignore && // don't change ignore to true if it is already false
-                         cfe.getCause() == CausedFocusEvent.Cause.ACTIVATION; // ACTIVATION is triggered if the
-                                                                              // FileChooser is opened
-            }
-        }
-        
-    }
-    
-    private class KeystrokeTimer extends TimerTask {
-        @Override
-        public void run() {
-            if (timeSinceLastKeystroke < 0)
-                return;
-            
-            timeSinceLastKeystroke += KEYSTROKE_RATE;
-            
-            if (timeSinceLastKeystroke >= KEYSTROKE_TRESHOLD) {
-                int save = timeSinceLastKeystroke;
-                timeSinceLastKeystroke = -1; // needs to be set to -1 to prevent 
-                                             // multiple parallel filter execution
-                
-                if (!executeFilters())
-                    timeSinceLastKeystroke = save;
-            }
-        }
-    }
-    
-    private class LoadProgressMonitor implements ProgressMonitor {
-        private String staticText;
-        private JLabel lblStatus;
-        
-        public LoadProgressMonitor(JLabel lblStatus, String staticText) {
-            this.lblStatus = lblStatus;
-            this.staticText = staticText;
-            
-            lblStatus.setText(staticText);
-        }
-        
-        @Override
-        public void worked(float percentage) {
-            int perc = Math.round(percentage*100);
-            lblStatus.setText(staticText + " (" + perc + " %)");
-        }
-
-        @Override
-        public void finished() {
-            if (parser.hasErrors()) {
-                if (JOptionPane.showConfirmDialog(LogScene.this, "Parsing log file finished with errors. Show error messages?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
-                    List<LogParser.ParseError> errors = parser.getErrors();
-                    ImportLogErrorDialog.showDialog(LogScene.this, errors);
-                }
-            }
-        }
-        
-    };
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/actions/ImportLogAction.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-package at.ssw.visualizer.logviewer.scene.actions;
-
-import at.ssw.visualizer.logviewer.scene.LogScene;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import org.openide.awt.ActionID;
-import org.openide.awt.ActionReference;
-import org.openide.awt.ActionRegistration;
-
-
-/**
- *
- * @author Katrin Strassl
- */
-
-@ActionID(id = "at.ssw.visualizer.logviewer.scene.actions.ImportLogActions", category = "File")
-@ActionRegistration(displayName = "Import Log", iconBase = "at/ssw/visualizer/logviewer/scene/icons/import_log.png")
-@ActionReference(path = "Menu/File", position = 600)
-public class ImportLogAction implements ActionListener {
-
-    @Override
-    public void actionPerformed(ActionEvent ae) {
-        LogScene.getInstance().loadLogFile();
-    }
-}
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_down.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_up.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_back.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_forward.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_list.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/import_log.png has changed
Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/loading.gif has changed
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/LogTableModel.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-package at.ssw.visualizer.logviewer.scene.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.swing.table.AbstractTableModel;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class LogTableModel extends AbstractTableModel {
-    private final static String[] columnNames = {"Line #", "Method", "Scope", "Node", "Log Text"};
-    
-    private List<TableLine> entries = new ArrayList<>();
-    
-    public void setLogEntries(List<TableLine> entries) {
-        this.entries = entries;
-        fireTableDataChanged();
-    }
-    
-    public TableLine getTableLine(int line) {
-        return entries.get(line);
-    }
-    
-    @Override
-    public int getRowCount() {
-        return entries.size();
-    }
-
-    @Override
-    public int getColumnCount() {
-        return columnNames.length;
-    }
-
-    @Override
-    public String getColumnName(int column) {
-        return columnNames[column];
-    }
-
-    @Override
-    public Object getValueAt(int i, int i1) {
-        switch (i1) {
-            case 0:
-                return entries.get(i).getLineNr();
-            case 1:
-                return entries.get(i).getLogLine().getMethod().getName();
-            case 2:
-                return entries.get(i).getLogLine().getScope()!=null?
-                           entries.get(i).getLogLine().getScope().getName():"";
-            case 3:
-                return entries.get(i).getLogLine().getNode()!=null?
-                           entries.get(i).getLogLine().getNode().getName():"";
-            case 4:
-                return entries.get(i).getLogLine().getText();
-        }
-        return null;
-    }
-    
-}
--- a/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/TableLine.java	Wed Jun 27 17:35:32 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-package at.ssw.visualizer.logviewer.scene.model;
-
-import at.ssw.visualizer.logviewer.model.LogLine;
-
-/**
- *
- * @author Katrin Strassl
- */
-public class TableLine {
-
-    private int lineNr;
-    private LogLine logLine;
-    
-    // display single log line
-    public TableLine(LogLine logLine) {
-        this(logLine, logLine.getLineNumber());
-    }
-    
-    // display line number range (from logLine to lineNr or vice versa)
-    public TableLine(LogLine logLine, int lineNr) {
-        this.logLine = logLine;
-        this.lineNr = lineNr;
-    }
-    
-    public int getFirstLine() {
-        return lineNr < logLine.getLineNumber()?lineNr:logLine.getLineNumber();
-    }
-    
-    public int getLastLine() {
-        return lineNr > logLine.getLineNumber()?lineNr:logLine.getLineNumber();
-    }
-    
-    public String getLineNr() {
-        if (lineNr == logLine.getLineNumber()) {
-            return String.valueOf(lineNr);
-        }
-        return getFirstLine() + "-" + getLastLine();
-    }
-    
-    public LogLine getLogLine() {
-        return logLine;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/Bundle.properties	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,1 @@
+OpenIDE-Module-Name=LogViewer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewer.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer;
+
+import com.oracle.graal.visualizer.logviewer.scene.LogScene;
+import com.oracle.graal.visualizer.editor.CompilationViewer;
+import com.sun.hotspot.igv.data.InputGraph;
+import java.awt.Component;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+class LogCompilationViewer implements CompilationViewer {
+
+    private LogScene scene;
+
+    public LogCompilationViewer() {
+        this.scene = new LogScene();
+    }
+
+    @Override
+    public Lookup getLookup() {
+        return Lookups.fixed();
+    }
+
+    @Override
+    public Component getComponent() {
+        return scene;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewerFactory.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer;
+
+import com.oracle.graal.visualizer.editor.CompilationViewer;
+import com.oracle.graal.visualizer.editor.SplitCompilationViewerFactory;
+import com.sun.hotspot.igv.data.InputGraph;
+
+public class LogCompilationViewerFactory extends SplitCompilationViewerFactory {
+
+    @Override
+    public String getName() {
+        return "Log";
+    }
+
+    @Override
+    protected CompilationViewer createViewer(InputGraph graph) {
+        return new LogCompilationViewer();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/layer.xml	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
+<filesystem>
+    <folder name="CompilationViewer">
+        <folder name="Log">
+            <folder name="Actions">
+                <file name="com-oracle-graal-visualizer-logviewer-scene-actions-ImportLogAction.shadow">
+                    <attr name="originalFile" stringvalue="Actions/File/com-oracle-graal-visualizer-logviewer-scene-actions-ImportLogActions.instance"/>
+                </file>
+            </folder>
+        </folder>
+    </folder>
+</filesystem>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogLine.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+public class LogLine {
+
+    private final int lineNum;
+	private final CharSequence text;
+	private final Method method;
+	private final Scope scope;
+	private final Node node;
+	
+	LogLine(int lineNum, CharSequence text, Method method, Scope scope, Node node) {
+		this.lineNum = lineNum;
+        this.text = text;
+		this.method = method;
+		this.scope = scope;
+		this.node = node;
+	}
+    
+    /**
+     * Returns the number of the line in the log file
+     * @return file line number
+     */
+    public int getLineNumber() {
+        return lineNum;
+    }
+	
+	/**
+	 * Returns the text of the log line
+	 * @return log line text
+	 */
+	public String getText() {
+		return text.toString();
+	}
+	
+	/**
+	 * Returns the parent method
+	 * @return the parent method
+	 */
+	public Method getMethod() {
+		return method;
+	}
+	
+	/**
+	 * Returns the parent scope
+	 * @return the parent scope
+	 */
+	public Scope getScope() {
+		return scope;
+	}
+	
+	/**
+	 * Returns the parent node
+	 * @return the parent node (or <code>null</code> if the log is not in a node's context)
+	 */
+	public Node getNode() {
+		return node;
+	}
+	
+	/**
+	 * The string representation of a log line is the text of it.
+	 */
+	@Override
+	public String toString() {
+		return getText();
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogModel.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+public class LogModel {
+
+	private List<Method> methods = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	void add(Method method) {
+		methods.add(method);
+	}
+	
+	/**
+	 * Returns a list of all methods within the log model.
+	 * @return list of methods
+	 */
+	public List<Method> getMethods() {
+		return Collections.unmodifiableList(methods);
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * Returns a list of logs which are before and after a specific log line (and the line itself).
+	 * @param log reference log line
+	 * @param pre number of lines before the reference line
+	 * @param post number of lines after the reference line
+	 * @return list of log lines (size: pre + post + 1)
+	 */
+	public List<LogLine> range(LogLine log, int pre, int post) {
+		if(log == null) throw new NoSuchElementException();
+		
+		List<LogLine> logs = getLogs();
+		int index = logs.indexOf(log);
+		
+		if(index == -1) throw new NoSuchElementException();
+		
+		int fromIndex = index - pre;
+		int toIndex = index + post + 1;
+		
+		return getLogs().subList(fromIndex > 0 ? fromIndex : 0, toIndex < logs.size() ? toIndex : logs.size());
+	}
+	
+	/**
+	 * Returns a string with log l which are before and after a specific log line (and the line itself).
+	 * @param log reference log line
+	 * @param pre number of lines before the reference line
+	 * @param post number of lines after the reference line
+	 * @return list of log lines (size: pre + post + 1)
+	 */
+	public String rangeAsString(LogLine log, int pre, int post) {
+		List<LogLine> list = range(log, pre, post);
+		
+		String ls = System.getProperty("line.separator");
+		
+		boolean first = true;
+		StringBuilder buf = new StringBuilder();
+		for(LogLine line : list) {
+			if(!first) buf.append(ls);
+			else first = false;
+			
+			buf.append(line);
+		}
+		
+		return buf.toString();
+	}
+	
+	public LogLine getLogLine(int lineNum) {
+		int index = lineNum;
+		if(index >= logs.size()) index = logs.size()-1;
+		
+		LogLine logLine = logs.get(lineNum);
+		while(logLine.getLineNumber() > lineNum) {
+			logLine = logs.get(--index);
+		}
+		while(logLine.getLineNumber() < lineNum) {
+			logLine = logs.get(++index);
+		}
+		
+		return logLine;
+	}
+	
+	public List<LogLine> range(int lineNum, int pre, int post) {
+		LogLine logLine = getLogLine(lineNum);
+		return range(logLine, pre, post);
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogParser.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import com.oracle.graal.visualizer.logviewer.model.io.FileLine;
+import com.oracle.graal.visualizer.logviewer.model.io.ProgressMonitor;
+import com.oracle.graal.visualizer.logviewer.model.io.SeekableFile;
+import com.oracle.graal.visualizer.logviewer.model.io.SeekableFileReader;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LogParser {
+	
+	private static final Pattern METHOD_PATTERN =
+		Pattern.compile("Finished target method HotSpotMethod<(.+?)>, isStub (true|false)");
+	private static final Pattern SCOPE_PATTERN =
+		Pattern.compile("scope: (.+?)");
+	private static final Pattern NODE_PATTERN =
+		Pattern.compile(".*?([0-9]+)\\|([0-9a-zA-Z.]+).*?");
+	
+	private final List<ParseErrorListener> errorListeners = new ArrayList<>();
+	private final List<ParseError> errors = new ArrayList<>();
+	
+	/**
+	 * Parses a log file without any feedback. When the parsing process is finished, the method returns a LogModel-object.
+	 * @param file log file
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file) throws IOException {
+		return parse(file, null);
+	}
+	
+	/**
+	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
+	 * @param file log file
+	 * @param monitor monitor for progress monitoring (uses default gap)
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file, ProgressMonitor monitor) throws IOException {
+		return parse(file, monitor, SeekableFileReader.DEFAULT_GAP);
+	} 
+	
+	/**
+	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
+	 * @param file log file
+	 * @param monitor monitor for progress monitoring (uses custom gap)
+	 * @param gap custom gap (every x bytes read from the file, the monitor will be informed)
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file, ProgressMonitor monitor, int gap) throws IOException {
+		errors.clear();
+		SeekableFileReader reader = new SeekableFileReader(file, monitor, gap);
+		SeekableFile seekableFile = reader.getSeekableFile();
+		BufferedReader r = new BufferedReader(reader);
+		
+		LogModel model = new LogModel();
+		Method currentMethod = new Method(model);
+		Scope currentScope = null;
+		
+		Matcher matcher;
+		boolean methodNameSet = false;
+		
+		int lineNum = -1;
+		String line;
+		while((line = r.readLine()) != null) {
+			lineNum++;
+			
+			methodNameSet = false;
+			
+			matcher = SCOPE_PATTERN.matcher(line);
+			if(matcher.matches()) {
+				String name = matcher.group(1);
+				currentScope = new Scope(name, currentMethod);
+				currentMethod.add(currentScope);
+			}
+            
+            matcher = METHOD_PATTERN.matcher(line);
+            boolean methodPatternMatches = matcher.matches();
+            
+            if(methodPatternMatches){
+                currentScope = null;
+				String name = matcher.group(1);
+				boolean isStub = Boolean.parseBoolean(matcher.group(2));
+				currentMethod.init(name, isStub);
+				model.add(currentMethod);
+				methodNameSet = true;
+            }
+			
+			Node currentNode = null;
+			matcher = NODE_PATTERN.matcher(line);
+			if(matcher.matches()) {
+                if(currentScope == null){
+                	raiseError(lineNum, line, "scope is missing");
+                	continue;
+                }
+				int number = Integer.parseInt(matcher.group(1));
+				currentNode = currentScope.getNode(number);
+				if(currentNode == null) {
+					String name = matcher.group(2);
+					currentNode = new Node(number, name, currentScope);
+					currentScope.add(currentNode);
+				}
+			}
+			
+			FileLine fileLine = seekableFile.get(lineNum);
+			LogLine log = new LogLine(lineNum, fileLine, currentMethod, currentScope, currentNode);
+			if(currentNode != null) currentNode.add(log);
+			if(currentScope != null) currentScope.add(log);
+			currentMethod.add(log);
+			model.add(log);
+            
+            if(methodPatternMatches) {
+				currentMethod = new Method(model);
+			}
+		}
+		
+		if(!methodNameSet) raiseError(lineNum, line, "unexpected end of stream");
+		
+		return model;
+	}
+	
+	private void raiseError(int lineNum, String line, String message) {
+		ParseError error = new ParseError(lineNum, line, message);
+		errors.add(error);
+		for(ParseErrorListener listener : errorListeners) {
+			listener.errorOccurred(error);
+		}
+	}
+	
+	/**
+	 * Adds a ParseErrorListener to the listeners
+	 * @param listener
+	 */
+	public void addParseErrorListener(ParseErrorListener listener) {
+		errorListeners.add(listener);
+	}
+	
+	public void removeParseErrorListener(ParseErrorListener listener) {
+		errorListeners.remove(listener);
+	}
+	
+	/**
+	 * Checks if errors occurred during the parsing process
+	 * @return <code>true</code> if there are errors stored, <code>false</code> otherwise
+	 */
+	public boolean hasErrors() {
+		return !errors.isEmpty();
+	}
+	
+	/**
+	 * Returns a list of all errors.
+	 * @return error list
+	 */
+	public List<ParseError> getErrors() {
+		return Collections.unmodifiableList(errors);
+	}
+	
+	public static class ParseError {
+		
+		private final int lineNum;
+		private final String line;
+		private final String message;
+		
+		private ParseError(int lineNum, String line, String message) {
+			this.lineNum = lineNum;
+			this.message = message;
+			this.line = line;
+		}
+		
+		public int getLineNumber() {
+			return lineNum;
+		}
+		
+		public String getLine() {
+			return line;
+		}
+		
+		public String getMessage() {
+			return message;
+		}
+		
+	}
+	
+	public static interface ParseErrorListener {
+		
+		/**
+		 * Called when a new error occurs.<br><br>
+		 * <b>Attention</b>: This method runs on the same thread as the parsing process.
+		 * If time-consuming tasks should be executed, please consider multithreading.
+		 * @param error
+		 */
+		public void errorOccurred(ParseError error);
+		
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Method.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Method {
+
+	private String name;
+	private boolean isStub;
+	private final LogModel model;
+	private List<Scope> scopes = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	Method(LogModel model) {
+		name = null;
+		isStub = false;
+		this.model = model;
+	}
+	
+	void init(String name, boolean isStub) {
+		this.name = name;
+		this.isStub = isStub;
+	}
+	
+	/**
+	 * Returns the name of the method
+	 * @return the method name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns <code>true</code> if this is a stub method.
+	 * @return <code>true</code> if is stub, <code>false</code> otherwise
+	 */
+	public boolean isStub() {
+		return isStub;
+	}
+	
+	/**
+	 * Returns the model which holds this method.
+	 * @return model-object
+	 */
+	public LogModel getModel() {
+		return model;
+	}
+	
+	void add(Scope scope) {
+		scopes.add(scope);
+	}
+	
+	/**
+	 * Returns a list of all scopes inside a target method.
+	 * @return list of scopes
+	 */
+	public List<Scope> getScopes() {
+		return scopes;
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs in the context of the method.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * The string representation of a method is its name.
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Node.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Node {
+
+	private final int number;
+	private final String name;
+	private final Scope scope;
+	private List<LogLine> logs = new ArrayList<>();
+	
+	
+	Node(int number, String name, Scope scope) {
+		this.number = number;
+		this.name = name;
+		this.scope = scope;
+	}
+	
+	/**
+	 * Returns the node number.
+	 * @return the node number
+	 */
+	public int getNumber() {
+		return number;
+	}
+	
+	/**
+	 * Returns the node name.
+	 * @return the node name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns the parent scope.
+	 * @return the parent scope
+	 */
+	public Scope getScope() {
+		return scope;
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs within a nodes context.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * The string represenation of a node is &quot;&lt;name&gt; (&lt;number&gt;)&quot;.
+	 */
+	@Override
+	public String toString() {
+		return getName() + "(" + getNumber() + ")";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Scope.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Scope {
+
+	private final String name;
+	private final Method method;
+	private List<Node> nodes = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	Scope(String name, Method method) {
+		this.name = name;
+		this.method = method;
+	}
+	
+	/**
+	 * Returns the scope name.
+	 * @return the scope name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns the parent method.
+	 * @return the parent method
+	 */
+	public Method getMethod() {
+		return method;
+	}
+	
+	void add(Node node) {
+		nodes.add(node);
+	}
+	
+	/**
+	 * Returns a list of all node-objects inside a scope.
+	 * @return list of nodes
+	 */
+	public List<Node> getNodes() {
+		return Collections.unmodifiableList(nodes);
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs inside a scope.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return logs;
+	}
+	
+	/**
+	 * Returns the node inside a scope with the given number.
+	 * @param number node number
+	 * @return node-object
+	 */
+	public Node getNode(int number) {
+		for(Node node : nodes) {
+			if(node.getNumber() == number) return node;
+		}
+		return null;
+	}
+	
+	/**
+	 * The string representation of a scope is its name.
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/Filter.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+
+public interface Filter {
+
+	/**
+	 * Sets the constraints for a filter.<br>
+	 * They can be every type of objects. In general these are strings, but it can also be
+	 * a Integer (like in the <code>NodeFilter</code>):<br>
+	 * <code>Filter nodeFilter = filterManager.getNodeFilter();
+	 * filter.setConstraints((String)nodeName, (Integer)nodeNumber);</code>
+	 * @param constraints filter constraints
+	 */
+	void setConstraints(Object ... constraints);
+	
+	/**
+	 * Indicates whether to keep a log line in the filter results, or not.
+	 * @param line log line which should be checked
+	 * @return <code>true</code> if the line should be kept, <code>false</code> otherwise
+	 */
+	boolean keep(LogLine line);
+	
+	/**
+	 * Activates or deactivates a filter. Deactivated filters will be ignored.
+	 * @param active <code>true</code> to activate, <code>false</code> to deactivate
+	 */
+	void setActive(boolean active);
+	
+	/**
+	 * Returns the activation status
+	 * @return <code>true</code> for an active filter, <code>false</code> otherwise
+	 */
+	boolean isActive();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FilterManager.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import com.oracle.graal.visualizer.logviewer.model.LogModel;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FilterManager {
+	
+	private final List<Filter> filters = new ArrayList<>();
+	private final Filter methodFilter, scopeFilter, nodeFilter, fulltextFilter;
+	
+	/**
+	 * Creates a new instance of the filter manager.
+	 */
+	public FilterManager() {
+		add(methodFilter = new MethodFilter());
+		add(scopeFilter = new ScopeFilter());
+		add(nodeFilter = new NodeFilter());
+		add(fulltextFilter = new FullTextFilter());
+	}
+	
+	/**
+	 * Executes a filtering process with the given log model as subject. Inactive filters will be ignored.
+	 * @param model subject
+	 * @return filtered list of log lines
+	 * @throws InterruptedException 
+	 */
+	public List<LogLine> execute(LogModel model) throws InterruptedException {
+		List<LogLine> input = model.getLogs();
+		List<LogLine> output = new ArrayList<>();
+		
+		for(LogLine line : input) {
+			if(Thread.interrupted()) throw new InterruptedException();
+			if(keep(line)) output.add(line);
+		}
+		
+		if(Thread.interrupted()) throw new InterruptedException();
+		
+		return output;
+	}
+	
+	private boolean keep(LogLine line) {
+		boolean keep = true;
+		for(Filter filter : filters) {
+			keep = keep && (!filter.isActive() || filter.keep(line));
+		}
+		return keep;
+	}
+	
+	private Filter add(Filter filter) {
+		filters.add(filter);
+		return filter;
+	}
+	
+	/**
+	 * Returns the instance of a method filter
+	 * @return method filter
+	 */
+	public Filter getMethodFilter() {
+		return methodFilter;
+	}
+	
+	/**
+	 * Returns the instance of a scope filter
+	 * @return scope filter
+	 */
+	public Filter getScopeFilter() {
+		return scopeFilter;
+	}
+	
+	/**
+	 * Returns the instance of a node filter
+	 * @return node filter
+	 */
+	public Filter getNodeFilter() {
+		return nodeFilter;
+	}
+	
+	/**
+	 * Returns the instance of a full text filter
+	 * @return full text filter
+	 */
+	public Filter getFullTextFilter() {
+		return fulltextFilter;
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FullTextFilter.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class FullTextFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+		
+		Matcher matcher = p.matcher(line.getText());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/MethodFilter.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class MethodFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+		
+		Matcher matcher = p.matcher(line.getMethod().getName());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/NodeFilter.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class NodeFilter implements Filter {
+
+	private Pattern p;
+	private Integer nodeNum;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.nodeNum = null;
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+		
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+		else if(constraint instanceof Integer) {
+			this.nodeNum = (Integer)constraint;
+		}
+		
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null && nodeNum == null) return true; 
+		
+		if(line.getNode() == null) return false;
+		
+		boolean keep = false;
+		
+		if(p != null) {
+			Matcher matcher = p.matcher(line.getNode().getName());
+			keep = keep || matcher.find();
+		}
+		if(nodeNum != null) {
+			keep = keep || nodeNum.equals(line.getNode().getNumber());
+		}
+		
+		return keep;		
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/ScopeFilter.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class ScopeFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+        
+        if(line.getScope() == null) return false;
+		
+		Matcher matcher = p.matcher(line.getScope().getName());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/FileLine.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+public class FileLine implements CharSequence {
+
+	private final SeekableFile seekableFile;
+	private WeakReference<String> cache;
+	public final long off;
+	public final int len;
+	
+	public FileLine(SeekableFile seekableFile, long off, int len) {
+		this.seekableFile = seekableFile;
+		this.off = off;
+		this.len = len;
+	}
+	
+	@Override
+	public String toString() {
+		String line = null;
+		
+		if(cache != null) line = cache.get();
+		
+		if(line == null) {
+			try {
+				line = seekableFile.read(this);
+				cache = new WeakReference<>(line);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		return line;
+	}
+
+	@Override
+	public int length() {
+		return len;
+	}
+
+	@Override
+	public char charAt(int index) {
+		String line = toString();
+		return line != null ? line.charAt(index) : 0;
+	}
+
+	@Override
+	public CharSequence subSequence(int start, int end) {
+		String line = toString();
+		return line != null ? line.subSequence(start, end) : "";
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/ProgressMonitor.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+public interface ProgressMonitor {
+
+	/**
+	 * Triggered when some work has been done.<br><br>
+	 * <b>Attention</b>: This method runs on the same thread as the reading process.
+	 * If time-consuming tasks should be executed, please consider multithreading.
+	 * @param percentage Value in range between 0 and 1 to indicate how much work has been done.
+	 */
+	public void worked(float percentage);
+	
+	/**
+	 * Triggered when work is done completely.<br><br>
+	 * <b>Attention</b>: This method runs on the same thread as the reading process.
+	 * If time-consuming tasks should be executed, please consider multithreading.
+	 */
+	public void finished();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFile.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SeekableFile implements Closeable {
+
+	private final RandomAccessFile raf;
+	private List<FileLine> lines = new ArrayList<>();
+	
+	SeekableFile(File file) throws FileNotFoundException {
+		raf = new RandomAccessFile(file, "r");
+	}
+	
+	void addLine(long off, int len) {
+		lines.add(new FileLine(this, off, len));
+	}
+	
+	public int size() {
+		return lines.size();
+	}
+	
+	public FileLine get(int lineNum) throws IOException {
+		FileLine line = lines.get(lineNum);
+		return line;
+	}
+	
+	String read(FileLine line) throws IOException {
+		if(line == null) throw new IllegalArgumentException("line is null");
+		raf.seek(line.off);
+
+		byte [] buf = new byte[line.len];
+		
+		if(raf.read(buf) != line.len) throw new IOException("error while reading line");
+		
+		return new String(buf);
+	}
+
+	@Override
+	public void close() throws IOException {
+		raf.close();
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFileReader.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+public class SeekableFileReader extends Reader {
+	
+	public static final int DEFAULT_GAP = 1024; // in bytes
+
+	private final FileReader reader;
+	private SeekableFile seekableFile;
+	private ProgressMonitor monitor;
+	private long filelen;
+	private int gap;
+	
+	public SeekableFileReader(File file) throws IOException {
+		super(file);
+		reader = new FileReader(file);
+		seekableFile = new SeekableFile(file);
+	}
+	
+	public SeekableFileReader(File file, ProgressMonitor monitor, int gap) throws IOException {
+		this(file);
+		this.monitor = monitor;
+		this.filelen = file.length();
+		this.gap = gap;
+	}
+	
+	public SeekableFileReader(File file, ProgressMonitor monitor) throws IOException {
+		this(file, monitor, DEFAULT_GAP);
+	}
+	
+	public SeekableFile getSeekableFile() {
+		return seekableFile;
+	}
+
+    @Override
+	public void close() throws IOException {
+		reader.close();		
+	}
+	
+	private long bytes = 0;
+	private boolean skipLF = false;
+	private long off;
+	private long lastGapped = 0;
+	private boolean finished = false;
+
+	@Override
+	public int read(char[] cbuf, int offset, int length) throws IOException {
+		
+		int l = reader.read(cbuf, offset, length);
+		
+		if(l == -1 && !finished) {
+			seekableFile.addLine(off, (int)(bytes-off));
+			finished = true;
+			if(monitor != null) {
+				monitor.worked(1);
+				monitor.finished();
+			}
+		}
+		
+		for(int i = 0; i < l; ++i) {
+			Character ch = new Character(cbuf[i]);
+			int chlen = ch.toString().getBytes(reader.getEncoding()).length;
+				
+			if(skipLF && ch != '\n') {
+				seekableFile.addLine(off, (int)(bytes-off-chlen));
+				off = bytes;
+				skipLF = false;
+			}
+			
+			bytes += chlen;
+			
+			if(monitor != null) {
+				if(bytes > lastGapped+gap) {
+					lastGapped = bytes;
+					monitor.worked(((float)bytes)/((float)filelen));
+				}
+			}
+			
+			if(ch == '\r') {
+				skipLF = true;
+			}
+			if(ch == '\n') {
+				seekableFile.addLine(off, (int)(bytes-off-(skipLF ? 2*chlen : chlen)));
+				off = bytes;
+				skipLF = false;
+			}
+		}
+		
+		return l;
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkDialog.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.List;
+import javax.swing.*;
+
+public class BookmarkDialog extends JDialog {
+    
+    private JList lstBookmarks;
+    private List<LogLine> logLines;
+    
+    public BookmarkDialog(List<LogLine> bookmarks, Window parent) {
+        super(parent, JDialog.ModalityType.APPLICATION_MODAL);
+        
+        this.logLines = bookmarks;
+        
+        DefaultListModel mdlBookmarks = new DefaultListModel();
+        lstBookmarks = new JList(mdlBookmarks);
+        JScrollPane jspBookmarks = new JScrollPane(lstBookmarks);
+        
+        for (LogLine bookmark : bookmarks) {
+            mdlBookmarks.addElement(bookmark.getLineNumber() + ": Method " + bookmark.getMethod() + " - Scope " + bookmark.getScope() + " - " + bookmark.getText());
+        }
+        
+        JButton btnOk = new JButton("Go to");
+        JButton btnCancel = new JButton("Cancel");
+
+        // init listeners
+        lstBookmarks.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    close();
+                }
+            }
+        });
+        
+        btnOk.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                if (lstBookmarks.isSelectionEmpty())
+                    return;
+                close();
+            }
+        });
+        btnCancel.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                lstBookmarks.clearSelection();
+                close();
+            }
+        });
+        
+        // build layout
+        JPanel pnlButtons = new JPanel();
+        
+        pnlButtons.setLayout(new GridLayout(1, 2));
+        pnlButtons.add(btnOk);
+        pnlButtons.add(btnCancel);
+        
+        this.setLayout(new BorderLayout());
+        this.add(jspBookmarks, BorderLayout.CENTER);
+        this.add(pnlButtons, BorderLayout.SOUTH);
+        
+        this.pack();
+        this.setMinimumSize(new Dimension(600, this.getPreferredSize().height));
+        this.setLocationRelativeTo(parent);
+        this.setResizable(false);
+        this.setVisible(true);
+    }
+    
+    public LogLine getTarget() {
+        if (lstBookmarks.isSelectionEmpty())
+            return null;
+        return logLines.get(lstBookmarks.getSelectedIndex());
+    }
+    
+    private void close() {
+        this.setVisible(false);
+        this.dispose();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkableLogViewer.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import org.openide.util.Exceptions;
+
+public class BookmarkableLogViewer extends JPanel {
+
+    private static final Color BOOKMARK_COLOR = Color.CYAN;
+    
+    private static final Highlighter.HighlightPainter BOOKMARK_PAINTER =
+            new DefaultHighlighter.DefaultHighlightPainter(BOOKMARK_COLOR);
+    
+    private JTextPane txpText;
+    private JTextPane txpLines;
+    private Highlighter textHighlighter;
+    private Highlighter lineHighlighter;
+    private FontMetrics fm;
+    private Map<Integer, Bookmark> bookmarks = new TreeMap<>();
+    private List<LogLine> logLines = new ArrayList<>();
+
+    public BookmarkableLogViewer() {
+        init();
+    }
+
+    private void init() {
+        txpText = new JTextPane();
+        txpLines = new JTextPane();
+
+        // needed for correct layouting
+        Insets ins = txpLines.getInsets();
+        txpLines.setMargin(new Insets(ins.top + 1, ins.left, ins.bottom, ins.right));
+
+        textHighlighter = new BookmarkHighlighter();
+        lineHighlighter = new BookmarkHighlighter();
+
+        txpText.setHighlighter(textHighlighter);
+        //txpText.setMinimumSize(new Dimension(100, 100));
+        txpText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+        txpText.setEditable(false);
+
+        txpLines.setHighlighter(lineHighlighter);
+        txpLines.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+        txpLines.setBackground(Color.LIGHT_GRAY);
+        txpLines.setEnabled(false);
+        txpLines.setForeground(Color.BLACK);
+        txpLines.addMouseListener(mouseInputListener);
+
+        fm = txpText.getFontMetrics(txpText.getFont());
+
+        JPanel pnlBookmarks = new JPanel();
+        pnlBookmarks.setLayout(new BorderLayout());
+        pnlBookmarks.add(txpText, BorderLayout.CENTER);
+
+        JScrollPane jspBookmarks = new JScrollPane(pnlBookmarks);
+        jspBookmarks.setRowHeaderView(txpLines);
+        jspBookmarks.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+        jspBookmarks.getVerticalScrollBar().setUnitIncrement(15);
+
+        this.setLayout(new BorderLayout());
+        this.add(jspBookmarks, BorderLayout.CENTER);
+    }
+   
+    public int getCurrentlyDisplayedTopLine() {
+        Rectangle view = txpText.getVisibleRect();
+        return getAbsoluteLine((int) Math.ceil(view.y/fm.getHeight()));
+    }
+    
+    public int getCurrentTopLine() {
+        return logLines.get(0).getLineNumber();
+    }
+    
+    public int getCurrentBottomLine() {
+        return logLines.get(logLines.size()-1).getLineNumber();
+    }
+
+    public void clearLogLines() {
+        this.logLines = new ArrayList<>();
+        txpText.setText("");
+        txpLines.setText("");
+        clearHighlighter();
+    }
+
+    public void setLogLines(List<LogLine> logLines) {
+        this.logLines = logLines;
+
+        clearHighlighter();
+        clearLineNumbers();
+        String text = "";
+        for (int i = 0; i < logLines.size(); i++) {
+            text += logLines.get(i).getText();
+            if (i < logLines.size() - 1) {
+                text += "\n";
+            }
+        }
+        txpText.setText(text);
+        setLineNumbers();
+   
+        txpText.setCaretPosition(0);
+        txpLines.setCaretPosition(0);
+
+        for (int bookmark : bookmarks.keySet()) {
+            if (bookmark < logLines.get(0).getLineNumber()) {
+                continue;
+            }
+            if (bookmark > logLines.get(logLines.size() - 1).getLineNumber()) {
+                break;
+            }
+
+            int line = getRelativeLine(bookmark);
+
+            addHighlight(logLines.get(line));
+        }
+    }
+
+    public void setLogLines(List<LogLine> logLines, int focus) {
+        setLogLines(logLines);
+        
+        //does not work for some reason - jtextpane jumps to caret position afterwards
+        //moveToBookmark(focus);
+        
+        //workaround - set caret position bevore moving
+        Rectangle visible = txpText.getVisibleRect();
+        int visibleLines = (int)(Math.ceil(visible.height/fm.getHeight()));
+
+        String text = txpText.getText();
+        int line = logLines.get(0).getLineNumber();
+        for (int i = 0; i < text.length(); i++) {
+            if (text.charAt(i) == '\n')
+                line++;
+            if (line == focus+visibleLines || i == text.length() - 1) {
+                txpText.setCaretPosition(i);
+                break;
+            }
+        }
+        moveToBookmark(focus);
+    }
+
+    public List<LogLine> getBookmarkedLines() {
+        List<LogLine> lines = new ArrayList<>();
+        for (int bookmark : bookmarks.keySet()) {
+            lines.add(bookmarks.get(bookmark).logLine);
+        }
+        return lines;
+    }
+
+    public int tryLastBookmark() {
+        int line = getCurrentlyDisplayedTopLine();
+        
+        int firstShownLine = getCurrentTopLine();
+
+        int bookmarkKey = -1;
+        for (int key : bookmarks.keySet()) {
+            if (key >= line) {
+                break;
+            }
+
+            bookmarkKey = key;
+        }
+
+        if (bookmarkKey >= firstShownLine) {
+            moveToBookmark(bookmarkKey);
+            return -1;
+        }
+
+        return bookmarkKey;
+    }
+
+    public int tryNextBookmark() {
+        Rectangle visible = txpText.getVisibleRect();
+        int lastLine = (int) Math.floor((visible.y + visible.height) / fm.getHeight());
+        lastLine = getAbsoluteLine(lastLine);
+
+        int lastShownLine = getCurrentBottomLine();
+
+        int bookmarkKey = -1;
+        for (int key : bookmarks.keySet()) {
+            if (key > lastLine) {
+                bookmarkKey = key;
+                break;
+            }
+            if (key > lastShownLine) {
+                break;
+            }
+        }
+
+        if (bookmarkKey > 0 && bookmarkKey <= lastShownLine) {
+            moveToBookmark(bookmarkKey);
+            return -1;
+        }
+
+        return bookmarkKey;
+    }
+
+    private void moveToBookmark(int line) {
+        int relLine = getRelativeLine(line);
+        Rectangle visible = txpText.getVisibleRect();
+        Rectangle position = new Rectangle(0, relLine * fm.getHeight(), visible.width, visible.height);
+        txpText.scrollRectToVisible(position);
+    }
+
+    private int getAbsoluteLine(int line) {
+        return logLines.get(0).getLineNumber() + line;
+    }
+
+    private int getRelativeLine(int line) {
+        return line - logLines.get(0).getLineNumber();
+    }
+
+    private int getStartOffset(JTextComponent component, int line) {
+        return component.getDocument().getDefaultRootElement().getElement(line).getStartOffset();
+    }
+
+    private int getEndOffset(JTextComponent component, int line) {
+        return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset();
+    }
+
+    private void addHighlight(LogLine logLine) {
+        try {
+            int line = logLine.getLineNumber();
+            int relativeLine = getRelativeLine(line);
+
+            Object hl1 = textHighlighter.addHighlight(getStartOffset(txpText, relativeLine), getEndOffset(txpText, relativeLine), BOOKMARK_PAINTER);
+            Object hl2 = lineHighlighter.addHighlight(getStartOffset(txpLines, relativeLine), getEndOffset(txpLines, relativeLine), BOOKMARK_PAINTER);
+            bookmarks.put(line, new Bookmark(logLine, hl1, hl2));
+        } catch (BadLocationException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    private void removeHighlight(int line) {
+        int abs = getAbsoluteLine(line);
+        Bookmark bookmark = bookmarks.get(abs);
+        textHighlighter.removeHighlight(bookmark.hl1);
+        lineHighlighter.removeHighlight(bookmark.hl2);
+        bookmarks.remove(abs);
+    }
+
+    public void clearBookmarks() {
+        bookmarks = new TreeMap<>();
+        clearHighlighter();
+    }
+
+    private void clearHighlighter() {
+        textHighlighter.removeAllHighlights();
+        lineHighlighter.removeAllHighlights();
+    }
+
+    private void clearLineNumbers() {
+        txpLines.setText("");
+    }
+
+    private void setLineNumbers() {
+        clearLineNumbers();
+
+        if (logLines.isEmpty()) {
+            return;
+        }
+
+        int colCnt = String.valueOf(logLines.get(logLines.size() - 1).getLineNumber()).length() + 2;
+
+        int firstNr = logLines.get(0).getLineNumber();
+        String text = String.format("%" + colCnt + "s", firstNr + " ");
+        for (int i = 1; i < logLines.size(); i++) {
+            text += "\n";
+            text += String.format("%" + colCnt + "s", (firstNr + i) + " ");
+        }
+        txpLines.setText(text);
+    }
+
+    private MouseListener mouseInputListener = new MouseAdapter() {
+
+        @Override
+        public void mouseClicked(MouseEvent me) {
+            if (txpLines.getText().length() == 0) {
+                return;
+            }
+            if (me.getClickCount() == 2) {
+                int caretPos = txpLines.getCaretPosition();
+
+                int lineOffset = txpLines.getDocument().getDefaultRootElement().getElementIndex(caretPos);
+                if (txpLines.getText().charAt(caretPos - 1) == '\n') {
+                    lineOffset--;
+                }
+
+                if (bookmarks.containsKey(getAbsoluteLine(lineOffset))) {
+                    removeHighlight(lineOffset);
+                } else {
+                    addHighlight(logLines.get(lineOffset));
+                }
+            }
+        }
+    };
+
+    class Bookmark {
+
+        public final LogLine logLine;
+        public final Object hl1;
+        public final Object hl2;
+
+        public Bookmark(LogLine logLine, Object hl1, Object hl2) {
+            this.logLine = logLine;
+            this.hl1 = hl1;
+            this.hl2 = hl2;
+        }
+    }
+
+    class BookmarkHighlighter extends DefaultHighlighter {
+
+        private JTextComponent component;
+
+        @Override
+        public void install(JTextComponent component) {
+            super.install(component);
+            this.component = component;
+        }
+
+        @Override
+        public void deinstall(JTextComponent component) {
+            super.deinstall(component);
+            this.component = null;
+        }
+
+        @Override
+        public void paint(Graphics g) {
+            Highlighter.Highlight[] highlights = getHighlights();
+
+            for (int i = 0; i < highlights.length; i++) {
+                Highlighter.Highlight hl = highlights[i];
+                Rectangle bg = component.getBounds();
+                Insets insets = component.getInsets();
+                bg.x = insets.left;
+                bg.y = insets.top;
+                bg.height = insets.top + insets.bottom;
+                Highlighter.HighlightPainter painter = hl.getPainter();
+                painter.paint(g, hl.getStartOffset(), hl.getEndOffset(), bg, component);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/ImportLogErrorDialog.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogParser;
+import java.awt.Component;
+import java.util.List;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public class ImportLogErrorDialog {
+    
+    public static void showDialog(Component parent, List<LogParser.ParseError> errors) {
+        JTextArea txaErrors = new JTextArea();
+        
+        for (LogParser.ParseError error : errors) {
+            txaErrors.append("Error at line " + error.getLineNumber());
+            txaErrors.append(": " + error.getMessage());
+            txaErrors.append("\n");
+            txaErrors.append("Log line: " + error.getLine());
+            txaErrors.append("\n");
+        }
+        
+        JScrollPane scpErrors = new JScrollPane(txaErrors);
+        
+        JOptionPane.showMessageDialog(parent, scpErrors, "Parse errors", JOptionPane.ERROR_MESSAGE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/LogScene.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import com.oracle.graal.visualizer.logviewer.model.LogModel;
+import com.oracle.graal.visualizer.logviewer.model.LogParser;
+import com.oracle.graal.visualizer.logviewer.model.filter.Filter;
+import com.oracle.graal.visualizer.logviewer.model.filter.FilterManager;
+import com.oracle.graal.visualizer.logviewer.model.io.ProgressMonitor;
+import com.oracle.graal.visualizer.logviewer.scene.model.LogTableModel;
+import com.oracle.graal.visualizer.logviewer.scene.model.TableLine;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.regex.PatternSyntaxException;
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import org.openide.util.Exceptions;
+import org.openide.util.NbPreferences;
+import sun.awt.CausedFocusEvent;
+
+public class LogScene extends JPanel {
+    private static final String PREFERENCE_DIR = "dir";
+    
+    private static final String ICON_PREFIX = "/com/oracle/graal/visualizer/logviewer/scene/icons/";
+    private static final String ICON_ARROW_DOWN = ICON_PREFIX + "arrow_down.png";
+    private static final String ICON_ARROW_UP = ICON_PREFIX + "arrow_up.png";
+    private static final String ICON_BOOKMARK_BACK = ICON_PREFIX + "bookmark_back.png";
+    private static final String ICON_BOOKMARK_FWD = ICON_PREFIX + "bookmark_forward.png";
+    private static final String ICON_BOOKMARK_LIST = ICON_PREFIX + "bookmark_list.png";
+    private static final String ICON_LOAD = ICON_PREFIX + "loading.gif";
+    
+    private static final ImageIcon IMGICON_LOAD = new ImageIcon(LogScene.class.getResource(ICON_LOAD));
+    
+    private static final int LOG_LINES = 50;
+    private static final int KEYSTROKE_RATE = 100; // rate at which the keystrokes are checked
+    private static final int KEYSTROKE_TRESHOLD = 400; // time in ms after which a search is triggered
+            
+    private FilterManager filterManager;
+    private Thread filterRunThread;
+    
+    private int timeSinceLastKeystroke = -1;
+    
+    private JLabel lblMessage;
+    private JLabel lblIcon;
+    
+    private JLabel lblMethodFilter;
+    private JLabel lblScopeFilter;
+    private JLabel lblNodeFilter;
+    private JLabel lblFulltextFilter;
+    private JTextField txfMethodFilter;
+    private JTextField txfScopeFilter;
+    private JTextField txfNodeFilter;
+    private JTextField txfFulltextFilter;
+    
+    private JTable tblResult;
+    private LogTableModel tblResultModel;
+    
+    private BookmarkableLogViewer logViewer;
+    private JButton btnBookmarkBack;
+    private JButton btnBookmarkFwd;
+    private JButton btnBookmarkList;
+    private JButton btnLoadMoreUp;
+    private JButton btnLoadMoreDown;
+    
+    private LogParser parser = new LogParser();
+    private LogModel logModel = null;
+    private LogStatus logStatus = LogStatus.NO_LOG;
+    
+    private static LogScene instance;
+    
+    private enum LogStatus {
+        NO_LOG, LOADING, ACTIVE
+    }
+
+    public static LogScene getInstance() {
+        return instance;
+    }
+    
+    public LogScene() {
+        initComponents();
+    }
+    
+    private void initComponents() {
+        filterManager = new FilterManager();
+        
+        lblMessage = new JLabel("No logfile loaded.");
+        lblIcon = new JLabel("");
+        
+        // Initialize filter components
+        lblMethodFilter = new JLabel("Target Method:");
+        lblScopeFilter = new JLabel("Scope:");
+        lblNodeFilter = new JLabel("Node:");
+        lblFulltextFilter = new JLabel("Fulltext:");
+        
+        txfMethodFilter = new JTextField();
+        txfScopeFilter = new JTextField();
+        txfNodeFilter = new JTextField();
+        txfFulltextFilter = new JTextField();
+        
+        tblResultModel = new LogTableModel();
+        tblResult = new JTable(tblResultModel);
+        tblResult.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        tblResult.getTableHeader().setReorderingAllowed(false);
+        tblResult.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+        
+        Dimension dim = tblResult.getPreferredScrollableViewportSize();
+        tblResult.setPreferredScrollableViewportSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
+        JScrollPane scpTblResult = new JScrollPane(tblResult);
+        scpTblResult.setMinimumSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
+        
+        logViewer = new BookmarkableLogViewer();
+        
+        btnLoadMoreUp = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_UP)));
+        btnLoadMoreDown = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_DOWN)));
+        
+        btnLoadMoreUp.setFocusable(false);
+        btnLoadMoreUp.setToolTipText("Load more previous log lines");
+        
+        btnLoadMoreDown.setFocusable(false);
+        btnLoadMoreDown.setToolTipText("Load more following log lines");
+        
+        btnBookmarkBack = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_BACK)));
+        btnBookmarkList = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_LIST)));
+        btnBookmarkFwd = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_FWD)));
+        
+        btnBookmarkBack.setFocusable(false);
+        btnBookmarkBack.setToolTipText("Navigate to the last bookmark.");
+        
+        btnBookmarkFwd.setFocusable(false);
+        btnBookmarkFwd.setToolTipText("Navigate to the next bookmark.");
+        
+        btnBookmarkList.setFocusable(false);
+        btnBookmarkList.setToolTipText("List all known bookmarks.");
+        
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new GridBagLayout());
+        pnl.setOpaque(false);
+        
+        JPanel logViewerPanel = new JPanel();
+        logViewerPanel.setLayout(new GridBagLayout());
+        logViewerPanel.setOpaque(false);
+        
+        JPanel messagePanel = new JPanel();
+        messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.LINE_AXIS));
+        messagePanel.setOpaque(false);
+        
+        // Initialize Listeners
+        initListeners();
+        
+        // Layout components
+        GridBagConstraints gbc = new GridBagConstraints();
+        
+        messagePanel.add(lblMessage);
+        messagePanel.add(Box.createHorizontalGlue());
+        messagePanel.add(lblIcon);
+        
+        Insets standardInsets = gbc.insets;
+        
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.anchor = GridBagConstraints.WEST;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.weightx = 1;
+        gbc.weighty = 0;
+        gbc.gridwidth = 2;
+        gbc.insets = new Insets(2, 0, 2, 0);
+        pnl.add(messagePanel, gbc);
+        
+        gbc.fill = GridBagConstraints.NONE;
+        gbc.gridwidth = 1;
+        gbc.weightx = 0;
+        gbc.weighty = 0;
+        gbc.gridy++;
+        gbc.insets = standardInsets;
+        pnl.add(lblMethodFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblScopeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblNodeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblFulltextFilter, gbc);
+        
+        gbc.gridx++;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.weightx = 0.75;
+        pnl.add(txfMethodFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfScopeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfNodeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfFulltextFilter, gbc);
+        
+        gbc.gridx = 0;
+        //gbc.gridy++;
+        gbc.gridwidth = 2;
+        gbc.weightx = 1;
+        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
+        //pnl.add(btnSearch, gbc);
+        
+        gbc.gridy++;
+        pnl.add(scpTblResult, gbc);
+        
+        gbc.gridy++;
+        gbc.weighty = 1;
+        gbc.fill = GridBagConstraints.BOTH;
+        pnl.add(logViewerPanel, gbc);
+        
+        gbc = new GridBagConstraints();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.gridheight = 6;
+        gbc.weightx = 1;
+        gbc.weighty = 1;
+        gbc.fill = GridBagConstraints.BOTH;
+        logViewerPanel.add(logViewer, gbc);
+        
+        gbc.gridx++;
+        gbc.weightx = 0;
+        gbc.weighty = 0;
+        gbc.fill = GridBagConstraints.NONE;
+        gbc.anchor = GridBagConstraints.PAGE_START;
+        gbc.gridheight = 1;
+        logViewerPanel.add(btnLoadMoreUp, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnLoadMoreDown, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(Box.createRigidArea(btnLoadMoreUp.getSize()));
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkBack, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkFwd, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkList, gbc);
+        
+        this.setLayout(new BorderLayout());
+        this.add(pnl, BorderLayout.CENTER);
+        
+        Timer keyTimer = new Timer();
+        keyTimer.scheduleAtFixedRate(new KeystrokeTimer(), KEYSTROKE_RATE, KEYSTROKE_RATE);
+        
+        LogScene.instance = this;
+    }
+    
+    private void initListeners() {
+        txfMethodFilter.addKeyListener(new FilterKeyListener());
+        txfScopeFilter.addKeyListener(new FilterKeyListener());
+        txfNodeFilter.addKeyListener(new FilterKeyListener());
+        txfFulltextFilter.addKeyListener(new FilterKeyListener());
+        
+        txfMethodFilter.addFocusListener(new FilterFocusListener());
+        txfScopeFilter.addFocusListener(new FilterFocusListener());
+        txfNodeFilter.addFocusListener(new FilterFocusListener());
+        txfFulltextFilter.addFocusListener(new FilterFocusListener());
+        
+        btnLoadMoreUp.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int line = logViewer.getCurrentlyDisplayedTopLine();
+                int top = logViewer.getCurrentTopLine();
+                int bottom = logViewer.getCurrentBottomLine();
+                logViewer.setLogLines(logModel.range(line, line - top + LOG_LINES, bottom - line), line); 
+            } 
+        });
+        
+        btnLoadMoreDown.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int line = logViewer.getCurrentlyDisplayedTopLine();
+                int top = logViewer.getCurrentTopLine();
+                int bottom = logViewer.getCurrentBottomLine();
+                logViewer.setLogLines(logModel.range(line, line - top, bottom - line + LOG_LINES), line); 
+            } 
+        });
+        
+        btnBookmarkBack.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int result = logViewer.tryLastBookmark();
+                if (result >= 0) {
+                    tblResult.clearSelection();
+                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result); 
+                }
+            }
+        });
+        
+        btnBookmarkFwd.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int result = logViewer.tryNextBookmark();
+                if (result >= 0) {
+                    tblResult.clearSelection();
+                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result);
+                }
+            }
+        });
+        
+        btnBookmarkList.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                List<LogLine> bookmarkedLines = logViewer.getBookmarkedLines();
+                if (bookmarkedLines.size() > 0) {
+                    BookmarkDialog bd = new BookmarkDialog(bookmarkedLines, null);
+                    if (bd.getTarget() != null) {
+                        LogLine target = bd.getTarget();
+                        int line = target.getLineNumber();
+                        logViewer.setLogLines(logModel.range(line, LOG_LINES, LOG_LINES), line); 
+                    }
+                } else {
+                    JOptionPane.showMessageDialog(LogScene.this, "No bookmarks set.", "", JOptionPane.INFORMATION_MESSAGE);
+                }
+            }
+        });
+        
+        tblResult.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent lse) {
+                if (tblResult.getSelectedRow() == -1) {
+                    logViewer.clearLogLines();
+                    return;
+                }
+                
+                TableLine selectedLine = tblResultModel.getTableLine(tblResult.getSelectedRow());
+                int firstLine = selectedLine.getFirstLine();
+                int lastLine = selectedLine.getLastLine();
+                
+                if (firstLine == lastLine) { 
+                    // only display selected line
+                    List<LogLine> line = new ArrayList<>();
+                    line.add(selectedLine.getLogLine());
+                    logViewer.setLogLines(line);
+                } else {
+                    // display selected range
+                    int pre = firstLine==lastLine?LOG_LINES:selectedLine.getLogLine().getLineNumber()-firstLine;
+                    int post = firstLine==lastLine?LOG_LINES:lastLine-selectedLine.getLogLine().getLineNumber();
+
+                    logViewer.setLogLines(logModel.range(selectedLine.getLogLine(), pre, post));           
+                }
+            }
+        });
+    }
+    
+    private boolean executeFilters() {
+        if (logStatus == LogStatus.NO_LOG) {
+            loadLogFile();
+            return false;
+        }
+        if (logStatus == LogStatus.LOADING) {
+            return false;
+        }
+
+        boolean execute = trySetFilter(filterManager.getMethodFilter(), txfMethodFilter.getText().trim(), lblMethodFilter);
+        execute = trySetFilter(filterManager.getScopeFilter(), txfScopeFilter.getText().trim(), lblScopeFilter) || execute;
+        try {
+            // node number
+            int node = Integer.parseInt(txfNodeFilter.getText().trim());
+            execute = trySetFilter(filterManager.getNodeFilter(), node, lblNodeFilter) || execute;
+        } catch (Exception e) {
+            // node name
+            execute = trySetFilter(filterManager.getNodeFilter(), txfNodeFilter.getText().trim(), lblNodeFilter) || execute;
+        }
+        execute = trySetFilter(filterManager.getFullTextFilter(), txfFulltextFilter.getText().trim(), lblFulltextFilter) || execute;
+
+        if (!execute)
+            return true;
+        
+        tryInterruptFilter();
+
+        filterRunThread = new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    List<LogLine> result = filterManager.execute(logModel);
+                    lblIcon.setIcon(null);
+
+                    if (!Thread.interrupted())
+                        buildTableEntries(result);
+                } catch (InterruptedException e) {
+                }
+            }
+
+        });
+        lblIcon.setIcon(IMGICON_LOAD);
+        filterRunThread.start();
+        
+        return true;
+    }
+    
+    private boolean trySetFilter(Filter filter, Object constraint, JLabel marker) {
+        try {
+            filter.setConstraints(constraint);
+            marker.setForeground(Color.BLACK);
+            return constraint != null && (!(constraint instanceof String) || (constraint instanceof String && ((String)constraint).trim().length() > 0));
+        } catch (PatternSyntaxException e) {
+            filter.setConstraints(new Object[]{});
+            marker.setForeground(Color.RED);
+            return false;
+        }
+    }
+    
+    private void tryInterruptFilter() {
+        if (filterRunThread != null && (filterRunThread.isAlive() || !filterRunThread.isInterrupted())) {
+            lblIcon.setIcon(null);
+            filterRunThread.interrupt();
+        }
+    }
+    
+    private void buildTableEntries(List<LogLine> filterResult) {
+        List<TableLine> tableEntries;
+        
+        int methodLength = txfMethodFilter.getText().trim().length();
+        int scopeLength = txfScopeFilter.getText().trim().length();
+        int nodeLength = txfNodeFilter.getText().trim().length();
+        int fulltextLength = txfFulltextFilter.getText().trim().length();
+        
+        boolean preventGrouping = nodeLength != 0 || fulltextLength != 0;
+        
+        if (!preventGrouping && methodLength > 0 && scopeLength == 0) {
+            tableEntries = groupByMethod(filterResult);
+        } else if (!preventGrouping && scopeLength > 0) {
+            tableEntries = groupByScope(filterResult);
+        } else {
+            tableEntries = showAllLines(filterResult);
+        }
+        
+        tblResultModel.setLogEntries(tableEntries);
+        
+        int width = 0;
+        for (int i = 0; i < tableEntries.size(); i++) {
+            TableCellRenderer tcr = tblResult.getCellRenderer(i, 0);
+            Component c = tcr.getTableCellRendererComponent(tblResult, tblResultModel.getValueAt(i, 0), false, false, i, 0);
+            if (c instanceof JLabel) {
+                JLabel l = (JLabel) c;
+                FontMetrics fm = l.getFontMetrics(l.getFont());
+                width = Math.max(width, fm.stringWidth(l.getText()));
+            }
+        }
+       
+        // proper resizing of column
+        // setWidth and setPreferredWidth do not trigger resize
+        TableColumn col = tblResult.getColumnModel().getColumn(0);
+        col.setMinWidth(width+5);
+        col.setMaxWidth(width+5);
+        
+        // reenable resizing for user
+        col.setMinWidth(0);
+        col.setMaxWidth(999);
+    }
+    
+    private List<TableLine> groupByMethod(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        int firstLine = -1;
+        for (int i = 0; i < filterResult.size(); i++) {
+            LogLine line = filterResult.get(i);
+            
+            if (firstLine < 0)
+                firstLine = line.getLineNumber();
+
+            if (i < filterResult.size() - 1) {
+                LogLine next = filterResult.get(i+1);
+                if (line.getMethod() != next.getMethod()) {
+                    tableEntries.add(new TableLine(line, firstLine));
+                    firstLine = next.getLineNumber();
+                }
+            } else {
+                tableEntries.add(new TableLine(line, firstLine));
+            }
+        }
+        return tableEntries;
+    }
+    
+    private List<TableLine> groupByScope(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        LogLine firstScopeLine = null;
+        for (int i = 0; i < filterResult.size(); i++) {
+            LogLine line = filterResult.get(i);
+            
+            if (firstScopeLine == null)
+                firstScopeLine = line;
+
+            if (i < filterResult.size() - 1) {
+                LogLine next = filterResult.get(i+1);
+                if (line.getScope() != next.getScope()) {
+                    tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
+                    firstScopeLine = next;
+                }
+            } else {
+                tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
+            }
+        }
+        return tableEntries;
+    }
+    
+    private List<TableLine> showAllLines(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        for (LogLine line : filterResult) {
+            tableEntries.add(new TableLine(line));
+        }
+        return tableEntries;
+    }
+    
+    public void loadLogFile() {
+        JFileChooser fc = new JFileChooser();
+        fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
+
+            @Override
+            public boolean accept(File f) {
+                return f.isDirectory() ||
+                       f.getName().toLowerCase().endsWith(".txt") ||
+                       f.getName().toLowerCase().endsWith(".log");
+            }
+
+            @Override
+            public String getDescription() {
+                return "Log files (*.txt, *.log)";
+            }
+        });
+        fc.setCurrentDirectory(new File(NbPreferences.forModule(LogScene.class).get(PREFERENCE_DIR, "~")));
+        fc.setDialogTitle("Load log file");
+
+        if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+            tryInterruptFilter();
+            
+            final File file = fc.getSelectedFile();
+            
+            NbPreferences.forModule(LogScene.class).put(PREFERENCE_DIR, file.getParent());
+            
+            lblIcon.setIcon(IMGICON_LOAD);
+            logStatus = LogStatus.LOADING;
+            new Thread(new Runnable(){
+
+                @Override
+                public void run() {
+                    try {
+                        logModel = parser.parse(file, new LoadProgressMonitor(lblMessage, "Loading file " + file.getName() + "..."));
+                        lblIcon.setIcon(null);
+                        lblMessage.setText("Current logfile: " + file.getName());
+                        logStatus = LogStatus.ACTIVE;
+                    } catch (IOException ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                }
+
+            }).start();
+        }
+    }
+    
+    private class FilterKeyListener extends KeyAdapter {
+        @Override
+        public void keyTyped(KeyEvent e) {
+            tryInterruptFilter();
+            timeSinceLastKeystroke = 0;
+        }
+    }
+    
+    private class FilterFocusListener implements FocusListener {
+        private boolean ignore = false;
+        
+        @Override
+        public void focusGained(FocusEvent fe) {
+            if (!ignore && logStatus == LogStatus.NO_LOG) {
+                ignore = true;
+                loadLogFile();
+            }
+        }
+
+        @Override
+        public void focusLost(FocusEvent fe) {
+            if (fe instanceof CausedFocusEvent) {
+                CausedFocusEvent cfe = (CausedFocusEvent) fe;
+                ignore = ignore && // don't change ignore to true if it is already false
+                         cfe.getCause() == CausedFocusEvent.Cause.ACTIVATION; // ACTIVATION is triggered if the
+                                                                              // FileChooser is opened
+            }
+        }
+        
+    }
+    
+    private class KeystrokeTimer extends TimerTask {
+        @Override
+        public void run() {
+            if (timeSinceLastKeystroke < 0)
+                return;
+            
+            timeSinceLastKeystroke += KEYSTROKE_RATE;
+            
+            if (timeSinceLastKeystroke >= KEYSTROKE_TRESHOLD) {
+                int save = timeSinceLastKeystroke;
+                timeSinceLastKeystroke = -1; // needs to be set to -1 to prevent 
+                                             // multiple parallel filter execution
+                
+                if (!executeFilters())
+                    timeSinceLastKeystroke = save;
+            }
+        }
+    }
+    
+    private class LoadProgressMonitor implements ProgressMonitor {
+        private String staticText;
+        private JLabel lblStatus;
+        
+        public LoadProgressMonitor(JLabel lblStatus, String staticText) {
+            this.lblStatus = lblStatus;
+            this.staticText = staticText;
+            
+            lblStatus.setText(staticText);
+        }
+        
+        @Override
+        public void worked(float percentage) {
+            int perc = Math.round(percentage*100);
+            lblStatus.setText(staticText + " (" + perc + " %)");
+        }
+
+        @Override
+        public void finished() {
+            if (parser.hasErrors()) {
+                if (JOptionPane.showConfirmDialog(LogScene.this, "Parsing log file finished with errors. Show error messages?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
+                    List<LogParser.ParseError> errors = parser.getErrors();
+                    ImportLogErrorDialog.showDialog(LogScene.this, errors);
+                }
+            }
+        }
+        
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/actions/ImportLogAction.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.actions;
+
+import com.oracle.graal.visualizer.logviewer.scene.LogScene;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionRegistration;
+
+@ActionID(id = "com.oracle.graal.visualizer.logviewer.scene.actions.ImportLogActions", category = "File")
+@ActionRegistration(displayName = "Import Log", iconBase = "com/oracle/graal/visualizer/logviewer/scene/icons/import_log.png")
+@ActionReference(path = "Menu/File", position = 600)
+public class ImportLogAction implements ActionListener {
+
+    @Override
+    public void actionPerformed(ActionEvent ae) {
+        LogScene.getInstance().loadLogFile();
+    }
+}
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_down.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_up.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_back.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_forward.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_list.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/import_log.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/loading.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/LogTableModel.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.table.AbstractTableModel;
+
+public class LogTableModel extends AbstractTableModel {
+    private final static String[] columnNames = {"Line #", "Method", "Scope", "Node", "Log Text"};
+    
+    private List<TableLine> entries = new ArrayList<>();
+    
+    public void setLogEntries(List<TableLine> entries) {
+        this.entries = entries;
+        fireTableDataChanged();
+    }
+    
+    public TableLine getTableLine(int line) {
+        return entries.get(line);
+    }
+    
+    @Override
+    public int getRowCount() {
+        return entries.size();
+    }
+
+    @Override
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    @Override
+    public String getColumnName(int column) {
+        return columnNames[column];
+    }
+
+    @Override
+    public Object getValueAt(int i, int i1) {
+        switch (i1) {
+            case 0:
+                return entries.get(i).getLineNr();
+            case 1:
+                return entries.get(i).getLogLine().getMethod().getName();
+            case 2:
+                return entries.get(i).getLogLine().getScope()!=null?
+                           entries.get(i).getLogLine().getScope().getName():"";
+            case 3:
+                return entries.get(i).getLogLine().getNode()!=null?
+                           entries.get(i).getLogLine().getNode().getName():"";
+            case 4:
+                return entries.get(i).getLogLine().getText();
+        }
+        return null;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/TableLine.java	Mon Jul 02 16:31:30 2012 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.model;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+
+public class TableLine {
+
+    private int lineNr;
+    private LogLine logLine;
+    
+    // display single log line
+    public TableLine(LogLine logLine) {
+        this(logLine, logLine.getLineNumber());
+    }
+    
+    // display line number range (from logLine to lineNr or vice versa)
+    public TableLine(LogLine logLine, int lineNr) {
+        this.logLine = logLine;
+        this.lineNr = lineNr;
+    }
+    
+    public int getFirstLine() {
+        return lineNr < logLine.getLineNumber()?lineNr:logLine.getLineNumber();
+    }
+    
+    public int getLastLine() {
+        return lineNr > logLine.getLineNumber()?lineNr:logLine.getLineNumber();
+    }
+    
+    public String getLineNr() {
+        if (lineNr == logLine.getLineNumber()) {
+            return String.valueOf(lineNr);
+        }
+        return getFirstLine() + "-" + getLastLine();
+    }
+    
+    public LogLine getLogLine() {
+        return logLine;
+    }
+}
--- a/visualizer/nbproject/project.properties	Wed Jun 27 17:35:32 2012 +0200
+++ b/visualizer/nbproject/project.properties	Mon Jul 02 16:31:30 2012 +0200
@@ -22,9 +22,9 @@
     ${project.com.oracle.graal.visualizer.outline}:\
     ${project.com.oracle.graal.visualizer.snapshots}:\
     ${project.com.oracle.graal.visualizer.sharedactions}:\
-    ${project.at.ssw.visualizer.logviewer}
+    ${project.com.oracle.graal.visualizer.logviewer}
 project.at.ssw.visualizer.cfg=ControlFlowEditor
-project.at.ssw.visualizer.logviewer=LogViewer
+project.com.oracle.graal.visualizer.logviewer=LogViewer
 project.com.oracle.graal.visualizer.editor=Editor
 project.com.oracle.graal.visualizer.outline=OutlineView
 project.com.oracle.graal.visualizer.sharedactions=SharedActions