### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.ui Index: src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlink.java =================================================================== RCS file: src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlink.java diff -N src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlink.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlink.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + package org.eclipse.pde.internal.ui.util; + +import com.ibm.icu.text.MessageFormat; +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.ui.IDebugModelPresentation; +import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; +import org.eclipse.jdt.internal.debug.ui.actions.OpenTypeAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.text.*; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.jface.window.Window; +import org.eclipse.pde.internal.ui.PDEUIMessages; +import org.eclipse.ui.*; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * A hyperlink from LogView event details stacktrace line. + */ +public class JavaStackTraceHyperlink implements IHyperlink { + + private IRegion region; + private String clazz; + private String file; + + /** + * Window to be closed when link target is found + */ + private Window window; + + /** + * Constructor for JavaStackTraceHyperlink + */ + public JavaStackTraceHyperlink(Window window, IRegion region, String clazz, String file) { + this.window = window; + this.region = region; + this.clazz = clazz; + this.file = file; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.text.hyperlink.IHyperlink#open() + */ + public void open() { + + String typeName = getTypeName(); + int lineNumber = getLineNumber(); + + // documents start at 0 + if (lineNumber > 0) { + lineNumber--; + } + + startSourceSearch(typeName, lineNumber); + } + + /** + * Starts a search for the type with the given name. Reports back to 'searchCompleted(...)'. + * + * @param typeName the type to search for + */ + protected void startSourceSearch(final String typeName, final int lineNumber) { + Job search = new Job(PDEUIMessages.JavaStackTraceHyperlink_Searching) { + protected IStatus run(IProgressMonitor monitor) { + try { + // search for the type in the workspace + Object result = OpenTypeAction.findTypeInWorkspace(typeName); + searchCompleted(result, typeName, lineNumber, null); + } catch (CoreException e) { + searchCompleted(null, typeName, lineNumber, e.getStatus()); + } + return Status.OK_STATUS; + } + + }; + search.schedule(); + } + + protected void searchCompleted(final Object source, final String typeName, final int lineNumber, final IStatus status) { + UIJob job = new UIJob("link search complete") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + if (source == null) { + if (status == null) { + // did not find source + MessageDialog.openInformation(window.getShell(), PDEUIMessages.JavaStackTraceHyperlink_Information, MessageFormat.format(PDEUIMessages.JavaStackTraceHyperlink_SourceNotFoundFor, new String[] {typeName})); + } else { + MessageDialog.openInformation(window.getShell(), PDEUIMessages.JavaStackTraceHyperlink_Information, PDEUIMessages.JavaStackTraceHyperlink_SourceNotFound); + } + } else { + processSearchResult(source, typeName, lineNumber); + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + + /** + * The search succeeded with the given result + * + * @param source resolved source object for the search + * @param typeName type name searched for + * @param lineNumber line number on link + */ + protected void processSearchResult(Object source, String typeName, int lineNumber) { + IDebugModelPresentation presentation = JDIDebugUIPlugin.getDefault().getModelPresentation(); + IEditorInput editorInput = presentation.getEditorInput(source); + if (editorInput != null) { + String editorId = presentation.getEditorId(editorInput, source); + if (editorId != null) { + try { + IEditorPart editorPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(editorInput, editorId); + if (editorPart instanceof ITextEditor && lineNumber >= 0) { + ITextEditor textEditor = (ITextEditor) editorPart; + IDocumentProvider provider = textEditor.getDocumentProvider(); + provider.connect(editorInput); + IDocument document = provider.getDocument(editorInput); + try { + IRegion line = document.getLineInformation(lineNumber); + textEditor.selectAndReveal(line.getOffset(), line.getLength()); + } catch (BadLocationException e) { + MessageDialog.openInformation(window.getShell(), PDEUIMessages.JavaStackTraceHyperlink_InvalidLineNumber, MessageFormat.format(PDEUIMessages.JavaStackTraceHyperlink_IsNotValidLineNumber, new String[] {(lineNumber + 1) + "", typeName})); //$NON-NLS-1$ + } + provider.disconnect(editorInput); + + window.close(); + } + } catch (CoreException e) { + MessageDialog.openError(window.getShell(), PDEUIMessages.JavaStackTraceHyperlink_OpenStackTraceHyperlink, e.getMessage()); + } + } + } + } + + private String getTypeName() { + // strip method name + int methodOffset = clazz.lastIndexOf('.'); + return (methodOffset >= 0) ? clazz.substring(0, methodOffset) : clazz; + } + + private int getLineNumber() { + // strip file name and ':' + int colonOffset = file.indexOf(':'); + return colonOffset >= 0 ? Integer.parseInt(file.substring(colonOffset + 1)) : 0; + } + + public IRegion getHyperlinkRegion() { + return region; + } + + public String getHyperlinkText() { + return null; + } + + public String getTypeLabel() { + return null; + } + +} Index: src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlinkDetector.java =================================================================== RCS file: src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlinkDetector.java diff -N src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlinkDetector.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/pde/internal/ui/util/JavaStackTraceHyperlinkDetector.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.pde.internal.ui.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.jface.text.*; +import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.jface.window.Window; + +/** + * Detects hyperlinks of pattern *(*.java:*) in LogView event details. + * If hyperlink is found, event details dialog is closed. + */ +public class JavaStackTraceHyperlinkDetector extends AbstractHyperlinkDetector { + + private static final Pattern stackTracePattern = Pattern.compile("(\\S*)\\((\\S*\\.java:\\d*)\\)", //$NON-NLS-1$ + Pattern.CASE_INSENSITIVE); + + /* + * (non-Javadoc) + * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean) + */ + public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { + + if (region == null || textViewer == null) + return null; + + IDocument document = textViewer.getDocument(); + + int offset = region.getOffset(); + + Window window = (Window) getAdapter(Window.class); + + if (document == null) + return null; + + IRegion lineInfo; + String line; + try { + lineInfo = document.getLineInformationOfOffset(offset); + line = document.get(lineInfo.getOffset(), lineInfo.getLength()); + } catch (BadLocationException ex) { + return null; + } + + Matcher m = stackTracePattern.matcher(line); + + if (m.find()) { + IRegion urlRegion = new Region(lineInfo.getOffset() + m.start(), m.end() - m.start()); + return new IHyperlink[] {new JavaStackTraceHyperlink(window, urlRegion, m.group(1), m.group(2))}; + } + + return null; + } + +} #P org.eclipse.ui.views.log Index: src/org/eclipse/ui/internal/views/log/Activator.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ui.views.log/src/org/eclipse/ui/internal/views/log/Activator.java,v retrieving revision 1.3 diff -u -r1.3 Activator.java --- src/org/eclipse/ui/internal/views/log/Activator.java 31 Dec 2007 00:37:51 -0000 1.3 +++ src/org/eclipse/ui/internal/views/log/Activator.java 4 Feb 2008 02:36:30 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * Copyright (c) 2007, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,6 +15,8 @@ import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; +import org.osgi.service.packageadmin.PackageAdmin; +import org.osgi.util.tracker.ServiceTracker; /** * The activator class controls the plug-in life cycle @@ -27,6 +29,9 @@ // The shared instance private static Activator plugin; + // PackageAdmin service + private ServiceTracker packageAdminTracker; + /** * The constructor */ @@ -40,6 +45,9 @@ public void start(BundleContext context) throws Exception { super.start(context); plugin = this; + + packageAdminTracker = new ServiceTracker(context, PackageAdmin.class.getName(), null); + packageAdminTracker.open(); } /* @@ -88,4 +96,11 @@ return imageDescriptorFromPlugin(PLUGIN_ID, id); } + /** + * Returns whether bundle with given name is available or not. + */ + public boolean isRequiredBundleAvailable(String symbolicName) { + return ((PackageAdmin) packageAdminTracker.getService()).getRequiredBundles(symbolicName) != null; + } + } Index: src/org/eclipse/ui/internal/views/log/EventDetailsDialog.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ui.views.log/src/org/eclipse/ui/internal/views/log/EventDetailsDialog.java,v retrieving revision 1.9 diff -u -r1.9 EventDetailsDialog.java --- src/org/eclipse/ui/internal/views/log/EventDetailsDialog.java 8 Jan 2008 04:03:09 -0000 1.9 +++ src/org/eclipse/ui/internal/views/log/EventDetailsDialog.java 4 Feb 2008 02:36:31 -0000 @@ -37,7 +37,7 @@ * contain event date, message and severity. Stack trace is displayed if an exception is bound * to event. Stack trace entries can be filtered. */ -public class EventDetailsDialog extends TrayDialog { +public class EventDetailsDialog extends TrayDialog implements IAdaptable { public static final String FILTER_ENABLED = "detailsStackFilterEnabled"; //$NON-NLS-1$ public static final String FILTER_LIST = "detailsStackFilterList"; //$NON-NLS-1$ @@ -63,6 +63,7 @@ private Label severityLabel; private Text msgText; private Text stackTraceText; + private HyperlinkStackTraceViewer stackTraceViewer; private Text sessionDataText; private Clipboard clipboard; private Button copyButton; @@ -336,9 +337,9 @@ if (stack != null) { stack = filterStack(stack); - stackTraceText.setText(stack); + setStackTrace(stack); } else { - stackTraceText.setText(Messages.EventDetailsDialog_noStack); + setStackTrace(Messages.EventDetailsDialog_noStack); } String session = logEntry.getSession().getSessionData(); @@ -351,7 +352,7 @@ severityImageLabel.setImage(null); severityLabel.setText(""); //$NON-NLS-1$ msgText.setText(""); //$NON-NLS-1$ - stackTraceText.setText(""); //$NON-NLS-1$ + setStackTrace(""); //$NON-NLS-1$ sessionDataText.setText(""); //$NON-NLS-1$ } @@ -628,12 +629,20 @@ gd.verticalAlignment = SWT.BOTTOM; label.setLayoutData(gd); - stackTraceText = new Text(container, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); - gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL); - gd.grabExcessHorizontalSpace = true; - gd.horizontalSpan = 2; - stackTraceText.setLayoutData(gd); - stackTraceText.setEditable(false); + // if optional bundles org.eclipse.jface.text and org.eclipse.ui.editors available, + // create stack trace viewer supporting hyperlinks + if (Activator.getDefault().isRequiredBundleAvailable("org.eclipse.jface.text") && //$NON-NLS-1$ + Activator.getDefault().isRequiredBundleAvailable("org.eclipse.ui.editors")) { //$NON-NLS-1$ + stackTraceViewer = new HyperlinkStackTraceViewer(this); + stackTraceViewer.createPartControl(container); + } else { + stackTraceText = new Text(container, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); + gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL); + gd.grabExcessHorizontalSpace = true; + gd.horizontalSpan = 2; + stackTraceText.setLayoutData(gd); + stackTraceText.setEditable(false); + } } private void createSessionSection(Composite parent) { @@ -721,6 +730,18 @@ return result.toString(); } + /** + * Sets stack trace view contents + * @param text new contents + */ + private void setStackTrace(String text) { + if (stackTraceText != null) { + stackTraceText.setText(text); + } else if (stackTraceViewer != null) { + stackTraceViewer.setText(text); + } + } + //--------------- configuration handling -------------- /** @@ -793,4 +814,12 @@ private AbstractEntry[] getElements() { return (AbstractEntry[]) ((ITreeContentProvider) provider.getContentProvider()).getElements(null); } + + public Object getAdapter(Class adapter) { + if (adapter.equals(Window.class)) { + return this; + } + + return null; + } } Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ui.views.log/META-INF/MANIFEST.MF,v retrieving revision 1.3 diff -u -r1.3 MANIFEST.MF --- META-INF/MANIFEST.MF 31 Jan 2008 15:58:43 -0000 1.3 +++ META-INF/MANIFEST.MF 4 Feb 2008 02:36:29 -0000 @@ -8,7 +8,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.filesystem;bundle-version="[1.1.0,2.0.0)";resolution:=optional, org.eclipse.ui;bundle-version="[3.3.0,4.0.0)", - org.eclipse.ui.ide;bundle-version="[3.3.0,4.0.0)";resolution:=optional + org.eclipse.ui.ide;bundle-version="[3.3.0,4.0.0)";resolution:=optional, + org.eclipse.jface.text;bundle-version="[3.4.0,4.0.0)";resolution:=optional, + org.eclipse.ui.editors;bundle-version="[3.4.0,4.0.0)";resolution:=optional Import-Package: com.ibm.icu.text Eclipse-LazyStart: true Bundle-RequiredExecutionEnvironment: J2SE-1.4 Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ui.views.log/plugin.xml,v retrieving revision 1.3 diff -u -r1.3 plugin.xml --- plugin.xml 4 Oct 2007 16:07:18 -0000 1.3 +++ plugin.xml 4 Feb 2008 02:36:29 -0000 @@ -58,4 +58,11 @@ priority="high"> + + + + Index: plugin.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ui.views.log/plugin.properties,v retrieving revision 1.3 diff -u -r1.3 plugin.properties --- plugin.properties 31 Dec 2007 19:34:51 -0000 1.3 +++ plugin.properties 4 Feb 2008 02:36:29 -0000 @@ -16,4 +16,4 @@ ViewCommand.logView.name= Error Log ViewCommand.logView.description= Show the Error Log content-type.name.log = Runtime log files - +hyperlinkdetector-target.name = Error Log event details Index: src/org/eclipse/ui/internal/views/log/HyperlinkStackTraceViewer.java =================================================================== RCS file: src/org/eclipse/ui/internal/views/log/HyperlinkStackTraceViewer.java diff -N src/org/eclipse/ui/internal/views/log/HyperlinkStackTraceViewer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/ui/internal/views/log/HyperlinkStackTraceViewer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.views.log; + +import java.util.Map; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; + +/** + * StackTrace viewer with hyperlinks support. + * Used when org.eclipse.jface.text and org.eclipse.ui.editors bundles are available. + * Provides "org.eclipse.ui.views.log" hyperlinkDetectorTarget to hyperlink detectors registry. + */ +public class HyperlinkStackTraceViewer { + + /** + * Reference to dialog containing viewer + */ + private EventDetailsDialog dialog; + + /** + * Contained viewer. + * + * Note: StackTraceViewer contains and not extends SourceViewer to + * guarantee, that other classes (e.g. EventDetailsDialog) will be able + * to reference it even if it can't be instantiated. + */ + private SourceViewer stackTraceViewer; + + /** + * Configuration supporting HyperlinkDetectorRegistry. + */ + private TextSourceViewerConfiguration configuration = new TextSourceViewerConfiguration() { + + public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { + return getRegisteredHyperlinkDetectors(sourceViewer); + } + + protected Map getHyperlinkDetectorTargets(ISourceViewer sourceViewer) { + Map targets = super.getHyperlinkDetectorTargets(sourceViewer); + targets.put("org.eclipse.ui.views.log", dialog); //$NON-NLS-1$ + return targets; + } + + }; + + /** + * StackTraceViewer constructor. + * + * @param dialog reference to containing dialog + */ + public HyperlinkStackTraceViewer(EventDetailsDialog dialog) { + this.dialog = dialog; + } + + /** + * Create viewer widgetry in container. + */ + public void createPartControl(Composite container) { + stackTraceViewer = new SourceViewer(container, null, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); // new Text(container, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); + stackTraceViewer.getControl().setBackground(container.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + GridData gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL); + gd.grabExcessHorizontalSpace = true; + gd.horizontalSpan = 2; + stackTraceViewer.getControl().setLayoutData(gd); + stackTraceViewer.setEditable(false); + + stackTraceViewer.configure(configuration); + } + + /** + * Set viewer text. + * @param text text to display + */ + public void setText(String text) { + stackTraceViewer.setDocument(new Document(text)); + } +}