if (srcLine.isUnknown()) {  SwingUtilities.invokeLater(new Runnable() { public void run() { sourceTextAreaScrollPane.getViewport().setViewPosition(new Point(0, 0)); } }); return true; }          SwingUtilities.invokeLater(new Runnable() { public void run() {    try { int startLine = srcLine.getStartLine() - 1; int endLine = srcLine.getEndLine();      JViewport viewport = sourceTextAreaScrollPane.getViewport(); Rectangle viewportRect = viewport.getViewRect(); int height = sourceTextArea.getHeight(); int topRow = sourceTextArea.getLineOfOffset(sourceTextArea.viewToModel(viewportRect.getLocation())); int bottomRow = sourceTextArea.getLineOfOffset( sourceTextArea.viewToModel(new Point(viewportRect.x, (viewportRect.y + viewportRect.height) - 1))); int numRowsVisible = bottomRow - topRow;    int viewLine = Math.max(startLine - (numRowsVisible > 0 ? numRowsVisible / 2 : 0), 0); int viewBegin = sourceTextArea.getLineStartOffset(viewLine); Rectangle viewRect = sourceTextArea.modelToView(viewBegin); viewport.setViewPosition(new Point(viewRect.x, viewRect.y));   int selBegin = sourceTextArea.getLineStartOffset(startLine); int selEnd = sourceTextArea.getLineStartOffset(endLine); sourceTextArea.select(selBegin, selEnd); sourceTextArea.getCaret().setSelectionVisible(true); } catch (javax.swing.text.BadLocationException e) { logger.logMessage(ConsoleLogger.ERROR, e.toString()); } } });  return true; }
    private boolean viewSource(Project project, AnalysisRun analysisRun, final SourceLineAnnotation srcLine)        throws IOException {        // Get rid of old source code text        sourceTextArea.setText("");                // There is nothing to do without a source annotation        // TODO: actually, might want to put a message in the source window        // explaining that we don't have the source file, and that        // they might want to recompile with debugging info turned on.        if (srcLine == null)            return false;                // Look up the source file for this class.        sourceFinder.setSourceBaseList(project.getSourceDirList());	String sourceFile = srcLine.getSourceFile();        if (sourceFile == null || sourceFile.equals("<Unknown>")) {            logger.logMessage(ConsoleLogger.WARNING, "No source file for class " + srcLine.getClassName());            return false;        }                // Try to open the source file and display its contents        // in the source text area.        InputStream in = sourceFinder.openSource(srcLine.getPackageName(), sourceFile);        BufferedReader reader = null;	try {	    reader = new BufferedReader(new InputStreamReader(in));                        String line;            while ((line = reader.readLine()) != null) {                sourceTextArea.append(line + "\n");            }        } finally {	    if (reader != null)        	reader.close();	}	if (srcLine.isUnknown()) {	    // No line number information, so can't highlight anything	    SwingUtilities.invokeLater(new Runnable() {		public void run() {		    sourceTextAreaScrollPane.getViewport().setViewPosition(new Point(0, 0));		}	    });	    return true;	}        // Highlight the annotation.        // There seems to be some bug in Swing that sometimes prevents this code        // from working when executed immediately after populating the        // text in the text area.  My guess is that when a large amount of text        // is added, Swing defers some UI update work until "later" that is needed        // to compute the visibility of text in the text area.        // So, post some code to do the update to the Swing event queue.        // Not really an ideal solution, but it seems to work.        SwingUtilities.invokeLater(new Runnable() {            public void run() {                // Highlight the lines from the source annotation.                // Note that the source lines start at 1, while the line numbers                // in the text area start at 0.                try {                    int startLine = srcLine.getStartLine() - 1;                    int endLine = srcLine.getEndLine();		    // Compute number of rows visible.		    // What a colossal pain in the ass this is.		    // You'd think there would be a convenient method to		    // return this information, but no.		    JViewport viewport = sourceTextAreaScrollPane.getViewport();		    Rectangle viewportRect = viewport.getViewRect();		    int height = sourceTextArea.getHeight();		    int topRow = sourceTextArea.getLineOfOffset(sourceTextArea.viewToModel(viewportRect.getLocation()));		    int bottomRow = sourceTextArea.getLineOfOffset(			sourceTextArea.viewToModel(new Point(viewportRect.x, (viewportRect.y + viewportRect.height) - 1)));		    int numRowsVisible = bottomRow - topRow;                                        // Scroll the window so the beginning of the		    // annotation text will be (approximately) centered.                    int viewLine = Math.max(startLine - (numRowsVisible > 0 ? numRowsVisible / 2 : 0), 0);                    int viewBegin = sourceTextArea.getLineStartOffset(viewLine);                    Rectangle viewRect = sourceTextArea.modelToView(viewBegin);                    viewport.setViewPosition(new Point(viewRect.x, viewRect.y));                                        // Select (and highlight) the annotation.                    int selBegin = sourceTextArea.getLineStartOffset(startLine);                    int selEnd = sourceTextArea.getLineStartOffset(endLine);                    sourceTextArea.select(selBegin, selEnd);                    sourceTextArea.getCaret().setSelectionVisible(true);                } catch (javax.swing.text.BadLocationException e) {                    logger.logMessage(ConsoleLogger.ERROR, e.toString());                }            }        });        return true;    }