# HG changeset patch # User Lukas Stadler # Date 1340811332 -7200 # Node ID f2fc4d13975a926763f4a7f553989fcaebd7ca32 # Parent f96e7b39e9fe0b0a074f6bdf6969cfdca5cc6731# Parent 915952ed97c0f13750aface1b7f8f13386a2bccc Merge. diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/build.xml Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,8 @@ + + + + + + Builds, tests, and runs the project at.ssw.visualizer.logviewer. + + diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/manifest.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/manifest.mf Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +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-Specification-Version: 1.0 + diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/nbproject/build-impl.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/nbproject/build-impl.xml Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,45 @@ + + + + + + + + + + + + + You must set 'suite.dir' to point to your containing module suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/nbproject/genfiles.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/nbproject/genfiles.properties Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,8 @@ +build.xml.data.CRC32=979ec129 +build.xml.script.CRC32=1c914106 +build.xml.stylesheet.CRC32=a56c6a5b@2.47.2 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=979ec129 +nbproject/build-impl.xml.script.CRC32=712ab216 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.47.2 diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/nbproject/project.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/nbproject/project.properties Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,2 @@ +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/nbproject/project.xml Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,146 @@ + + + org.netbeans.modules.apisupport.project + + + at.ssw.visualizer.logviewer + + + + com.oracle.graal.visualizer.editor + + + + 1.0 + + + + com.oracle.graal.visualizer.sharedactions + + + + 1.0 + + + + com.sun.hotspot.igv.data + + + + 1.0 + + + + org.eclipse.draw2d + + + + 1.0 + + + + org.jdesktop.layout + + + + 1 + 1.19.1 + + + + org.netbeans.api.visual + + + + 2.30.1 + + + + org.netbeans.modules.options.api + + + + 1 + 1.24.1 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.40.1 + + + + org.openide.actions + + + + 6.24.1 + + + + org.openide.awt + + + + 7.39.1 + + + + org.openide.dialogs + + + + 7.23.1 + + + + org.openide.loaders + + + + 7.32.1 + + + + org.openide.nodes + + + + 7.25.1 + + + + org.openide.util + + + + 8.19.1 + + + + org.openide.util.lookup + + + + 8.11.1 + + + + org.openide.windows + + + + 6.48.2 + + + + + at.ssw.visualizer.logviewer + + + + diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/nbproject/suite.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/nbproject/suite.properties Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,1 @@ +suite.dir=${basedir}/.. diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,1 @@ +at.ssw.visualizer.logviewer.LogCompilationViewerFactory \ No newline at end of file diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/Bundle.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/Bundle.properties Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,1 @@ +OpenIDE-Module-Name=LogViewer diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewer.java Wed Jun 27 17:35:32 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 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; + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/LogCompilationViewerFactory.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,24 @@ +/* + * 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(); + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/layer.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/layer.xml Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogLine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogLine.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,71 @@ +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 null 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(); + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogModel.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,107 @@ +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 methods = new ArrayList<>(); + private List 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 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 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 range(LogLine log, int pre, int post) { + if(log == null) throw new NoSuchElementException(); + + List 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 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 range(int lineNum, int pre, int post) { + LogLine logLine = getLogLine(lineNum); + return range(logLine, pre, post); + } + + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/LogParser.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,210 @@ +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 errorListeners = new ArrayList<>(); + private final List 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 true if there are errors stored, false otherwise + */ + public boolean hasErrors() { + return !errors.isEmpty(); + } + + /** + * Returns a list of all errors. + * @return error list + */ + public List 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.

+ * Attention: 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); + + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Method.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Method.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,86 @@ +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 scopes = new ArrayList<>(); + private List 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 true if this is a stub method. + * @return true if is stub, false 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 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 getLogs() { + return Collections.unmodifiableList(logs); + } + + /** + * The string representation of a method is its name. + */ + @Override + public String toString() { + return getName(); + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Node.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Node.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,68 @@ +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 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 getLogs() { + return Collections.unmodifiableList(logs); + } + + /** + * The string represenation of a node is "<name> (<number>)". + */ + @Override + public String toString() { + return getName() + "(" + getNumber() + ")"; + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Scope.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/Scope.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,84 @@ +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 nodes = new ArrayList<>(); + private List 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 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 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(); + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/Filter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/Filter.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,40 @@ +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.
+ * They can be every type of objects. In general these are strings, but it can also be + * a Integer (like in the NodeFilter):
+ * Filter nodeFilter = filterManager.getNodeFilter(); + * filter.setConstraints((String)nodeName, (Integer)nodeNumber); + * @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 true if the line should be kept, false otherwise + */ + boolean keep(LogLine line); + + /** + * Activates or deactivates a filter. Deactivated filters will be ignored. + * @param active true to activate, false to deactivate + */ + void setActive(boolean active); + + /** + * Returns the activation status + * @return true for an active filter, false otherwise + */ + boolean isActive(); + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FilterManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FilterManager.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,92 @@ +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 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 execute(LogModel model) throws InterruptedException { + List input = model.getLogs(); + List 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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FullTextFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/FullTextFilter.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,53 @@ +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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/MethodFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/MethodFilter.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,53 @@ +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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/NodeFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/NodeFilter.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,71 @@ +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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/ScopeFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/filter/ScopeFilter.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,55 @@ +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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/FileLine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/FileLine.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,58 @@ +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 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) : ""; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/ProgressMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/ProgressMonitor.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,24 @@ +package at.ssw.visualizer.logviewer.model.io; + +/** + * + * @author Alexander Stipsits + */ +public interface ProgressMonitor { + + /** + * Triggered when some work has been done.

+ * Attention: 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.

+ * Attention: This method runs on the same thread as the reading process. + * If time-consuming tasks should be executed, please consider multithreading. + */ + public void finished(); + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFile.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,50 @@ +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 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(); + } + + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFileReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/model/io/SeekableFileReader.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,101 @@ +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; + } + + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkDialog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkDialog.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,94 @@ +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 logLines; + + public BookmarkDialog(List 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(); + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkableLogViewer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/BookmarkableLogViewer.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,358 @@ +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 bookmarks = new TreeMap<>(); + private List 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 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 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 getBookmarkedLines() { + List 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); + } + } + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/ImportLogErrorDialog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/ImportLogErrorDialog.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,31 @@ +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 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); + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/LogScene.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/LogScene.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,651 @@ +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 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 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 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 filterResult) { + List 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 groupByMethod(List filterResult) { + List 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 groupByScope(List filterResult) { + List 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 showAllLines(List filterResult) { + List 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 errors = parser.getErrors(); + ImportLogErrorDialog.showDialog(LogScene.this, errors); + } + } + } + + }; +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/actions/ImportLogAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/actions/ImportLogAction.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,25 @@ +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(); + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_down.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_down.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_up.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/arrow_up.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_back.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_back.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_forward.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_forward.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_list.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/bookmark_list.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/import_log.png Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/import_log.png has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/loading.gif Binary file visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/icons/loading.gif has changed diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/LogTableModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/LogTableModel.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,59 @@ +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 entries = new ArrayList<>(); + + public void setLogEntries(List 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; + } + +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/TableLine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visualizer/LogViewer/src/at/ssw/visualizer/logviewer/scene/model/TableLine.java Wed Jun 27 17:35:32 2012 +0200 @@ -0,0 +1,43 @@ +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; + } +} diff -r f96e7b39e9fe -r f2fc4d13975a visualizer/nbproject/project.properties --- a/visualizer/nbproject/project.properties Wed Jun 27 15:40:03 2012 +0200 +++ b/visualizer/nbproject/project.properties Wed Jun 27 17:35:32 2012 +0200 @@ -1,48 +1,50 @@ -app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif -app.name=graalvisualizer -app.title=Graal Visualizer -branding.token=${app.name} -modules=\ - ${project.com.sun.hotspot.igv.graph}:\ - ${project.com.sun.hotspot.igv.filter}:\ - ${project.com.sun.hotspot.igv.hierarchicallayout}:\ - ${project.com.sun.hotspot.igv.layout}:\ - ${project.com.sun.hotspot.igv.data}:\ - ${project.com.sun.hotspot.igv.view}:\ - ${project.com.sun.hotspot.igv.bytecodes}:\ - ${project.com.sun.hotspot.igv.difference}:\ - ${project.com.sun.hotspot.igv.settings}:\ - ${project.com.sun.hotspot.igv.util}:\ - ${project.com.sun.hotspot.igv.svg}:\ - ${project.com.sun.hotspot.igv.filterwindow}:\ - ${project.com.sun.hotspot.igv.graal}:\ - ${project.at.ssw.visualizer.cfg}:\ - ${project.org.eclipse.draw2d}:\ - ${project.com.oracle.graal.visualizer.editor}:\ - ${project.com.oracle.graal.visualizer.outline}:\ - ${project.com.oracle.graal.visualizer.snapshots}:\ - ${project.com.oracle.graal.visualizer.sharedactions} -project.at.ssw.visualizer.cfg=ControlFlowEditor -project.com.oracle.graal.visualizer.editor=Editor -project.com.oracle.graal.visualizer.outline=OutlineView -project.com.oracle.graal.visualizer.sharedactions=SharedActions -project.com.oracle.graal.visualizer.snapshots=SnapshotsView -project.com.sun.hotspot.igv.bytecodes=Bytecodes -project.com.sun.hotspot.igv.data=Data -project.com.sun.hotspot.igv.difference=Difference -project.com.sun.hotspot.igv.filter=Filter -project.com.sun.hotspot.igv.filterwindow=FilterWindow -project.com.sun.hotspot.igv.graal=Graal -project.com.sun.hotspot.igv.graph=Graph -project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout -project.com.sun.hotspot.igv.layout=Layout -project.com.sun.hotspot.igv.settings=Settings -project.com.sun.hotspot.igv.svg=BatikSVGProxy -project.com.sun.hotspot.igv.view=View -project.com.sun.hotspot.igv.util=Util - -project.org.eclipse.draw2d=Draw2DLibrary -# Disable assertions for RequestProcessor to prevent annoying messages in case -# of multiple SceneAnimator update tasks in the default RequestProcessor. -run.args.extra = -J-client -J-da:org.openide.util.RequestProcessor -debug.args.extra = -J-client -J-da:org.openide.util.RequestProcessor +app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif +app.name=graalvisualizer +app.title=Graal Visualizer +branding.token=${app.name} +modules=\ + ${project.com.sun.hotspot.igv.graph}:\ + ${project.com.sun.hotspot.igv.filter}:\ + ${project.com.sun.hotspot.igv.hierarchicallayout}:\ + ${project.com.sun.hotspot.igv.layout}:\ + ${project.com.sun.hotspot.igv.data}:\ + ${project.com.sun.hotspot.igv.view}:\ + ${project.com.sun.hotspot.igv.bytecodes}:\ + ${project.com.sun.hotspot.igv.difference}:\ + ${project.com.sun.hotspot.igv.settings}:\ + ${project.com.sun.hotspot.igv.util}:\ + ${project.com.sun.hotspot.igv.svg}:\ + ${project.com.sun.hotspot.igv.filterwindow}:\ + ${project.com.sun.hotspot.igv.graal}:\ + ${project.at.ssw.visualizer.cfg}:\ + ${project.org.eclipse.draw2d}:\ + ${project.com.oracle.graal.visualizer.editor}:\ + ${project.com.oracle.graal.visualizer.outline}:\ + ${project.com.oracle.graal.visualizer.snapshots}:\ + ${project.com.oracle.graal.visualizer.sharedactions}:\ + ${project.at.ssw.visualizer.logviewer} +project.at.ssw.visualizer.cfg=ControlFlowEditor +project.at.ssw.visualizer.logviewer=LogViewer +project.com.oracle.graal.visualizer.editor=Editor +project.com.oracle.graal.visualizer.outline=OutlineView +project.com.oracle.graal.visualizer.sharedactions=SharedActions +project.com.oracle.graal.visualizer.snapshots=SnapshotsView +project.com.sun.hotspot.igv.bytecodes=Bytecodes +project.com.sun.hotspot.igv.data=Data +project.com.sun.hotspot.igv.difference=Difference +project.com.sun.hotspot.igv.filter=Filter +project.com.sun.hotspot.igv.filterwindow=FilterWindow +project.com.sun.hotspot.igv.graal=Graal +project.com.sun.hotspot.igv.graph=Graph +project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout +project.com.sun.hotspot.igv.layout=Layout +project.com.sun.hotspot.igv.settings=Settings +project.com.sun.hotspot.igv.svg=BatikSVGProxy +project.com.sun.hotspot.igv.view=View +project.com.sun.hotspot.igv.util=Util + +project.org.eclipse.draw2d=Draw2DLibrary +# Disable assertions for RequestProcessor to prevent annoying messages in case +# of multiple SceneAnimator update tasks in the default RequestProcessor. +run.args.extra = -J-client -J-da:org.openide.util.RequestProcessor +debug.args.extra = -J-client -J-da:org.openide.util.RequestProcessor