diff --git a/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleErrorMarkerTest.groovy b/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleErrorMarkerTest.groovy index 41cfc6020..706da4963 100644 --- a/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleErrorMarkerTest.groovy +++ b/org.eclipse.buildship.core.test/src/main/groovy/org/eclipse/buildship/core/internal/marker/GradleErrorMarkerTest.groovy @@ -138,8 +138,7 @@ class GradleErrorMarkerTest extends ProjectSynchronizationSpecification { def problems = gradleInternal.services.get(Problems) problems.forNamespace("buildscript").reporting { - it.label("Problem label") - .category('deprecation', 'plugin') + it.id("Problem label", 'deprecation') .severity(Severity.WARNING) .solution("Please use 'standard-plugin-2' instead of this plugin") } @@ -152,7 +151,7 @@ class GradleErrorMarkerTest extends ProjectSynchronizationSpecification { then: numOfGradleErrorMarkers == 1 gradleErrorMarkers[0].getAttribute(IMarker.MESSAGE) == 'Problem label' - gradleErrorMarkers[0].getAttribute(GradleErrorMarker.ATTRIBUTE_PROBLEM_CATEGORY) == 'buildscript:deprecation:plugin' + gradleErrorMarkers[0].getAttribute(GradleErrorMarker.ATTRIBUTE_ID) == 'deprecation' } } diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/DefaultGradleBuild.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/DefaultGradleBuild.java index 0a774cdc9..b8201730e 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/DefaultGradleBuild.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/DefaultGradleBuild.java @@ -197,9 +197,9 @@ SynchronizationResult run(CancellationTokenSource tokenSource, IProgressMonitor CorePlugin.operationManager().run(this, tokenSource, monitor); for (SynchronizationProblem f : this.failures) { if (f.getSeverity() == IStatus.ERROR) { - GradleErrorMarker.createError(f.getResource(), this.gradleBuild, f.getMessage(), f.getException(), 0); + GradleErrorMarker.createError(f.getResource(), this.gradleBuild, f.getMessage(), f.getException()); } else if (f.getSeverity() == IStatus.WARNING) { - GradleErrorMarker.createWarning(f.getResource(), this.gradleBuild, f.getMessage(), f.getException(), 0); + GradleErrorMarker.createWarning(f.getResource(), this.gradleBuild, f.getMessage(), f.getException()); } } result = DefaultSynchronizationResult.from(getFailures()); diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java index e1634f2d8..4715ca107 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/marker/GradleErrorMarker.java @@ -10,8 +10,7 @@ package org.eclipse.buildship.core.internal.marker; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; +import java.util.function.Consumer; import com.google.common.base.Throwables; @@ -29,13 +28,14 @@ */ public class GradleErrorMarker { - public static String ID = CorePlugin.PLUGIN_ID + ".errormarker"; - public static String ATTRIBUTE_STACKTRACE = "stacktrace"; - public static String ATTRIBUTE_ROOT_DIR = "rootdir"; - public static String ATTRIBUTE_PROBLEM_CATEGORY = "problem.category"; - public static String ATTRIBUTE_PROBLEM_SOLUTIONS = "problem.solutions"; - public static String ATTRIBUTE_DOCUMENTATION_LINK = "problem.documentationlink"; - + public static final String ID = CorePlugin.PLUGIN_ID + ".errormarker"; + public static final String ATTRIBUTE_STACKTRACE = "stacktrace"; + public static final String ATTRIBUTE_ROOT_DIR = "rootdir"; + public static final String ATTRIBUTE_ID = "problem.id"; + public static final String ATTRIBUTE_LABEL = "problem.label"; + public static final String ATTRIBUTE_DETAILS = "problem.details"; + public static final String ATTRIBUTE_SOLUTIONS = "problem.solutions"; + public static final String ATTRIBUTE_DOCUMENTATION_LINK = "problem.documentationlink"; private GradleErrorMarker() { } @@ -45,50 +45,65 @@ public static boolean belongsToBuild(IMarker marker, InternalGradleBuild build) return build.getBuildConfig().getRootProjectDirectory().getAbsolutePath().equals(rootDir); } + public static void createError(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception) { + createMarker(IMarker.SEVERITY_ERROR, resource, gradleBuild, message, exception, 0); + } + public static void createError(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) { createMarker(IMarker.SEVERITY_ERROR, resource, gradleBuild, message, exception, lineNumber); } - public static void createWarning(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) { - createMarker(IMarker.SEVERITY_WARNING, resource, gradleBuild, message, exception,lineNumber); + public static void createWarning(IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception) { + createMarker(IMarker.SEVERITY_WARNING, resource, gradleBuild, message, exception, 0); } private static void createMarker(int severity, IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber) { - createMarker(severity, resource, gradleBuild, message, exception, lineNumber, null, null, null); - } - - public static void createMarker(int severity, IResource resource, InternalGradleBuild gradleBuild, String message, Throwable exception, int lineNumber, String category, - List solutions, String documentationLink) { - try { - IMarker marker = resource.createMarker(GradleErrorMarker.ID); - + String stacktrace = exception == null ? null : trimMarkerProperty(Throwables.getStackTraceAsString(exception)); + createMarker(resource, severity, gradleBuild, message, stacktrace, marker -> { if (lineNumber >= 0) { - marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + try { + marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + } catch (CoreException e) { + throw new RuntimeException(e); + } } + }); + } - marker.setAttribute(IMarker.MESSAGE, trimMarkerProperty(message)); - marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); - marker.setAttribute(IMarker.SEVERITY, severity); - marker.setAttribute(ATTRIBUTE_ROOT_DIR, gradleBuild.getBuildConfig().getRootProjectDirectory().getAbsolutePath()); - if (exception != null) { - String stackTrace = Throwables.getStackTraceAsString(exception); - marker.setAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, trimMarkerProperty(stackTrace)); + private static void createMarker(IResource resource, int severity, InternalGradleBuild gradleBuild, String message, String exception, Consumer customMarkerConfiguration) { + createMarker(resource, new Consumer() { + + @Override + public void accept(IMarker marker) { + try { + marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); + marker.setAttribute(IMarker.SEVERITY, severity); + marker.setAttribute(ATTRIBUTE_ROOT_DIR, gradleBuild.getBuildConfig().getRootProjectDirectory().getAbsolutePath()); + marker.setAttribute(IMarker.MESSAGE, trimMarkerProperty(message)); + if (exception != null) { + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, exception); + } + } catch (CoreException e) { + CorePlugin.logger().warn("Cannot create Gradle error marker", e); + throw new RuntimeException(e); + } } - if (category != null) { - marker.setAttribute(ATTRIBUTE_PROBLEM_CATEGORY, category); - } - if (solutions != null) { - String solutionsString = solutions.stream().collect(Collectors.joining(System.getProperty("line.separator"))); - marker.setAttribute(ATTRIBUTE_PROBLEM_SOLUTIONS, solutionsString); - } - if (documentationLink != null) { - marker.setAttribute(ATTRIBUTE_DOCUMENTATION_LINK, documentationLink); - } - } catch (CoreException e) { + }.andThen(customMarkerConfiguration)); + } + + private static void createMarker(IResource resource, Consumer markerConfiguration) { + try { + IMarker marker = resource.createMarker(GradleErrorMarker.ID); + markerConfiguration.accept(marker); + } catch (Exception e) { CorePlugin.logger().warn("Cannot create Gradle error marker", e); } } + public static void createProblemMarker(int severity, IResource resource, InternalGradleBuild gradleBuild, String message, String exception, Consumer problemPosition, Consumer problemDetails) { + createMarker(resource, severity, gradleBuild, message, exception, problemPosition.andThen(problemDetails)); + } + /* * The Eclipse platform will throw an exception if a marker property is longer than 65535 bytes * https://github.com/eclipse-platform/eclipse.platform/blob/97d555a8b563dcb3a32bd43ad58ba452fa027a73/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/MarkerInfo.java#L56-L60 diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemEventAdapter.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemEventAdapter.java new file mode 100644 index 000000000..25b07a050 --- /dev/null +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemEventAdapter.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2023 Gradle Inc. and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ +package org.eclipse.buildship.core.internal.util.progress; + +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.gradle.tooling.events.problems.ProblemGroup; +import org.gradle.tooling.events.problems.SingleProblemEvent; +import org.gradle.tooling.events.problems.Solution; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.buildship.core.internal.marker.GradleErrorMarker; + +public class ProblemEventAdapter implements Consumer { + + private final SingleProblemEvent problem; + + public ProblemEventAdapter(SingleProblemEvent problem) { + this.problem = problem; + } + + @Override + public void accept(IMarker marker) { + try { + String idInfo = this.problem.getDefinition().getId().getDisplayName() + " (id: " + fqid() + ")"; + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_ID, idInfo); + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_LABEL, this.problem.getContextualLabel().getContextualLabel()); + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_DETAILS, this.problem.getDetails().getDetails()); + List solutions = this.problem.getSolutions(); + if (solutions != null) { + String solutionsString = solutions.stream().map(Solution::getSolution).collect(Collectors.joining(System.getProperty("line.separator"))); + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_SOLUTIONS, solutionsString); + } + String documentationLink = this.problem.getDefinition().getDocumentationLink().getUrl(); + if (documentationLink != null) { + marker.setAttribute(GradleErrorMarker.ATTRIBUTE_DOCUMENTATION_LINK, documentationLink); + } + } catch (CoreException e) { + throw new RuntimeException(e); + } + } + + private String fqid() { + return groupFqid(this.problem.getDefinition().getId().getGroup()) + ":" + this.problem.getDefinition().getId().getName(); + } + + private String groupFqid(ProblemGroup group) { + if (group.getParent() == null) { + return group.getName(); + } else { + return groupFqid(group.getParent()) + ":" + group.getName(); + } + } +} diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemsReportingProgressListener.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemsReportingProgressListener.java index 4f3abe5ce..1bc3ec150 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemsReportingProgressListener.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/progress/ProblemsReportingProgressListener.java @@ -9,31 +9,31 @@ ******************************************************************************/ package org.eclipse.buildship.core.internal.util.progress; +import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; +import org.gradle.tooling.Failure; import org.gradle.tooling.events.ProgressEvent; import org.gradle.tooling.events.ProgressListener; -import org.gradle.tooling.events.problems.BaseProblemDescriptor; import org.gradle.tooling.events.problems.FileLocation; import org.gradle.tooling.events.problems.LineInFileLocation; -import org.gradle.tooling.events.problems.ProblemAggregation; -import org.gradle.tooling.events.problems.ProblemAggregationDescriptor; -import org.gradle.tooling.events.problems.ProblemDescriptor; +import org.gradle.tooling.events.problems.Location; +import org.gradle.tooling.events.problems.OffsetInFileLocation; +import org.gradle.tooling.events.problems.ProblemAggregationEvent; import org.gradle.tooling.events.problems.ProblemEvent; -import org.gradle.tooling.events.problems.Solution; +import org.gradle.tooling.events.problems.SingleProblemEvent; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.buildship.core.internal.CorePlugin; import org.eclipse.buildship.core.internal.marker.GradleErrorMarker; -import org.eclipse.buildship.core.internal.util.gradle.Pair; import org.eclipse.buildship.core.internal.workspace.InternalGradleBuild; public class ProblemsReportingProgressListener implements ProgressListener { @@ -48,16 +48,10 @@ public ProblemsReportingProgressListener(InternalGradleBuild gradleBuild) { public void statusChanged(ProgressEvent event) { if (event instanceof ProblemEvent) { ProblemEvent problemEvent = (ProblemEvent) event; - BaseProblemDescriptor eventDescriptor = problemEvent.getDescriptor(); try { - if (eventDescriptor instanceof ProblemDescriptor) { - reportProblem((ProblemDescriptor) eventDescriptor); - } else if (eventDescriptor instanceof ProblemAggregationDescriptor) { - for (ProblemAggregation aggregation : ((ProblemAggregationDescriptor) eventDescriptor).getAggregations()) { - for (ProblemDescriptor descriptor : aggregation.getProblemDescriptors()) { - reportProblem(descriptor); - } - } + if (problemEvent instanceof SingleProblemEvent) { + reportProblem((SingleProblemEvent) problemEvent); + } else if (problemEvent instanceof ProblemAggregationEvent) { } } catch (Exception e) { CorePlugin.logger().warn("Cannot report problem " + problemEvent, e); @@ -65,52 +59,106 @@ public void statusChanged(ProgressEvent event) { } } - private void reportProblem(ProblemDescriptor descriptor) { - Optional> location = resourceAndFileNumberOfFirstFileLocation(descriptor); - if (location.isPresent()) { - GradleErrorMarker.createMarker( - toMarkerSeverity(descriptor.getSeverity()), - location.get().getFirst(), this.gradleBuild, - descriptor.getLabel().getLabel(), - null, // TODO (donat) Gradle 8.7 descriptor.getException().getException(), - location.get().getSecond(), - toPath(descriptor.getCategory()), - descriptor.getSolutions().stream().map(Solution::getSolution).collect(Collectors.toList()), - descriptor.getDocumentationLink().getUrl() - ); - } else { - GradleErrorMarker.createMarker( - toMarkerSeverity(descriptor.getSeverity()), - ResourcesPlugin.getWorkspace().getRoot(), - this.gradleBuild, - descriptor.getLabel().getLabel(), - null, // TODO (donat) Gradle 8.7 descriptor.getException().getException(), - -1, - toPath(descriptor.getCategory()), - descriptor.getSolutions().stream().map(Solution::getSolution).collect(Collectors.toList()), - descriptor.getDocumentationLink().getUrl() - ); + private void reportProblem(SingleProblemEvent event) { + List locations = event.getLocations(); + + // 1/4 offset in file location + Optional offsetInFileLocation = locations.stream().filter(OffsetInFileLocation.class::isInstance).map(OffsetInFileLocation.class::cast).findFirst(); + if (offsetInFileLocation.isPresent()) { + IResource resource = toResource(offsetInFileLocation.get()); + + GradleErrorMarker.createProblemMarker( + toMarkerSeverity(event.getDefinition().getSeverity()), + resource, + this.gradleBuild, + markerMessage(event), + stacktraceStringFor(event.getFailure().getFailure()), + marker -> { + OffsetInFileLocation location = offsetInFileLocation.get(); + int startOffset = location.getOffset(); + int endOffset = location.getLength(); + try { + marker.setAttribute(IMarker.CHAR_START, startOffset); + marker.setAttribute(IMarker.CHAR_END, startOffset + endOffset); + } catch (CoreException e) { + throw new RuntimeException(e); + } + }, + new ProblemEventAdapter(event) + ); + return; + } + + // 2/4 line in file location + Optional lineInFileLocation = locations.stream().filter(LineInFileLocation.class::isInstance).map(LineInFileLocation.class::cast).findFirst(); + if (lineInFileLocation.isPresent()) { + IResource resource = toResource(lineInFileLocation.get()); + GradleErrorMarker.createProblemMarker( + toMarkerSeverity(event.getDefinition().getSeverity()), + resource, + this.gradleBuild, + markerMessage(event), + stacktraceStringFor(event.getFailure().getFailure()), + marker -> { + Integer lineNumber = lineNumberOf(lineInFileLocation.get()); + if (lineNumber >= 0) { + try { + marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + } catch (CoreException e) { + throw new RuntimeException(e); + } + } + }, + new ProblemEventAdapter(event) + ); + return; } - } - private static String toPath(org.gradle.tooling.events.problems.ProblemCategory problemCategory) { - StringBuilder sb = new StringBuilder(); - sb.append(problemCategory.getNamespace()); - sb.append(':'); - sb.append(problemCategory.getCategory()); - for (String sc : problemCategory.getSubcategories()) { - sb.append(':'); - sb.append(sc); + // 3/4 file location + Optional fileLocation = locations.stream().filter(FileLocation.class::isInstance).map(FileLocation.class::cast).findFirst(); + if (fileLocation.isPresent()) { + IResource resource = toResource(fileLocation.get()); + GradleErrorMarker.createProblemMarker( + toMarkerSeverity(event.getDefinition().getSeverity()), + resource, + this.gradleBuild, + markerMessage(event), + stacktraceStringFor(event.getFailure().getFailure()), + m -> {}, + new ProblemEventAdapter(event) + ); + return; } - return sb.toString(); + + // 4/4 no location + GradleErrorMarker.createProblemMarker( + toMarkerSeverity(event.getDefinition().getSeverity()), + ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(this.gradleBuild.getBuildConfig().getRootProjectDirectory().getAbsolutePath())), + this.gradleBuild, + markerMessage(event), + stacktraceStringFor(event.getFailure().getFailure()), + m -> {}, + new ProblemEventAdapter(event) + ); } - public Optional firstFileLocation(ProblemDescriptor descriptor) { - return descriptor.getLocations().stream().filter(FileLocation.class::isInstance).map(FileLocation.class::cast).findFirst(); + private static String markerMessage(SingleProblemEvent problem ) { + String result = problem.getDetails().getDetails(); + if (result == null) { + result = problem.getContextualLabel().getContextualLabel(); + } + if (result == null) { + result = problem.getDefinition().getId().getDisplayName(); + } + + return result == null ? "" : result; } - public Optional> resourceAndFileNumberOfFirstFileLocation(ProblemDescriptor descriptor) { - return firstFileLocation(descriptor).map(location -> new Pair<>(toResource(location), lineNumberOf(location))); + private static String stacktraceStringFor(Failure failure) { + if (failure == null) { + return null; + } + return failure.getDescription(); } private static IResource toResource(FileLocation location) { diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/WtpConfigurator.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/WtpConfigurator.java index f55fe801d..55a4c5573 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/WtpConfigurator.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/WtpConfigurator.java @@ -107,7 +107,7 @@ private static void updateWtpConfiguration(ProjectContext context, IJavaProject markAsNonDeployed(javaProject, monitor); } } catch (UnsupportedConfigurationException e) { - GradleErrorMarker.createError(javaProject.getProject(), gradleBuild, e.getMessage(), null, 0); + GradleErrorMarker.createError(javaProject.getProject(), gradleBuild, e.getMessage(), null); } } } diff --git a/org.eclipse.buildship.ui/plugin.xml b/org.eclipse.buildship.ui/plugin.xml index 4719cd31e..66c99c40b 100644 --- a/org.eclipse.buildship.ui/plugin.xml +++ b/org.eclipse.buildship.ui/plugin.xml @@ -595,7 +595,7 @@ diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/MarkersPropertyPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/GradleMarkerPropertyPage.java similarity index 52% rename from org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/MarkersPropertyPage.java rename to org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/GradleMarkerPropertyPage.java index 27b74eeda..c6e0b537a 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/MarkersPropertyPage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/marker/GradleMarkerPropertyPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 Gradle Inc. and others + * Copyright (c) 2024 Gradle Inc. and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -19,13 +19,18 @@ import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; @@ -33,13 +38,15 @@ import org.eclipse.buildship.core.internal.marker.GradleErrorMarker; /** - * Property page displaying details of Gradle problem markers. + * Property page for Gradle problems. * * @author Donat Csikos */ -public class MarkersPropertyPage extends PropertyPage { +public class GradleMarkerPropertyPage extends PropertyPage { - public MarkersPropertyPage() { + private Clipboard clipboard; + + public GradleMarkerPropertyPage() { super(); noDefaultAndApplyButton(); } @@ -47,8 +54,9 @@ public MarkersPropertyPage() { @Override protected Control createContents(Composite parent) { Composite composite = new Composite(parent, SWT.NULL); - GridLayoutFactory.swtDefaults().numColumns(2).margins(0, 0).spacing(5, 20).applyTo(composite); + GridLayoutFactory.swtDefaults().numColumns(3 ).margins(0, 0).spacing(10, 6).applyTo(composite); GridDataFactory.fillDefaults().applyTo(composite); + this.clipboard = new Clipboard(parent.getDisplay()); initializeDialogUnits(composite); doCreateContents(composite); @@ -59,58 +67,23 @@ protected Control createContents(Composite parent) { private void doCreateContents(Composite parent) { IMarker marker = (IMarker) getElement().getAdapter(IMarker.class); - String message = marker.getAttribute(IMarker.MESSAGE, "(no message provided)"); - String stacktrace = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, "(no stacktrace provided)"); - - Label messageLabel = new Label(parent, SWT.NONE); - messageLabel.setText("Message:"); - GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(messageLabel); - - Text messageText = new Text(parent, SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - - GridDataFactory.fillDefaults().hint(100, convertHeightInCharsToPixels(countLines(message))).align(SWT.FILL, SWT.TOP).grab(true, false).applyTo(messageText); - messageText.setText(message); - - Label stackTraceLabel = new Label(parent, SWT.NONE); - stackTraceLabel.setText("Stacktrace:"); - GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(stackTraceLabel); - - Text stacktraceAreaText = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - GridDataFactory.fillDefaults().hint(100, 100).grab(true, true).applyTo(stacktraceAreaText); - - stacktraceAreaText.setText(stacktrace); - - String category = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_PROBLEM_CATEGORY, "(no category provided)"); - - Label categoryLabel = new Label(parent, SWT.NONE); - categoryLabel.setText("Category:"); - GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(categoryLabel); - - Text categoryAreaText = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - GridDataFactory.fillDefaults().hint(100, 1).grab(true, false).applyTo(categoryAreaText); - - categoryAreaText.setText(category); - - String solutions = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_PROBLEM_SOLUTIONS, "(no solutions provided)"); - if (solutions.equals("")) { - solutions = "(no solutions provided)"; - } - Label solutionsLabel = new Label(parent, SWT.NONE); - solutionsLabel.setText("Solutions:"); - GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(solutionsLabel); - Text solutionsAreaText = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - GridDataFactory.fillDefaults().hint(100, 1).grab(true, false).applyTo(solutionsAreaText); + // problem name and id + Label idLabel = new Label(parent, SWT.NONE); + idLabel.setText("Problem:"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(idLabel); + Label idValue = new Label(parent, SWT.NONE); + idValue.setText(marker.getAttribute(GradleErrorMarker.ATTRIBUTE_ID, "")); + GridDataFactory.swtDefaults().span(2, 1).align(SWT.LEFT, SWT.TOP).applyTo(idValue); - solutionsAreaText.setText(solutions); - - String documentationLink = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_DOCUMENTATION_LINK, "(no documentation link provided)"); + // documentation + String documentationLink = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_DOCUMENTATION_LINK, ""); Label documentationLabel = new Label(parent, SWT.NONE); documentationLabel.setText("Documentation:"); GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(documentationLabel); - Link documentationAreaText = new Link(parent, SWT.BORDER | SWT.READ_ONLY); - GridDataFactory.fillDefaults().hint(100, 1).grab(true, false).applyTo(documentationAreaText); + Link documentationAreaText = new Link(parent, SWT.READ_ONLY); + GridDataFactory.fillDefaults().hint(100, 1).span(2, 1).grab(true, false).applyTo(documentationAreaText); documentationAreaText.addSelectionListener(new SelectionAdapter() { @Override @@ -123,6 +96,57 @@ public void widgetSelected(SelectionEvent event) { } }); documentationAreaText.setText("" + documentationLink + ""); + + + // contextual label + Label label = new Label(parent, SWT.NONE); + label.setText("Label:"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(label); + Label labelLvalue = new Label(parent, SWT.NONE); + labelLvalue.setText(marker.getAttribute(GradleErrorMarker.ATTRIBUTE_LABEL, "")); + GridDataFactory.swtDefaults().span(2, 1).align(SWT.LEFT, SWT.TOP).applyTo(labelLvalue); + + // details + Label details = new Label(parent, SWT.NONE); + details.setText("Details:"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(details); + Label detailsValue = new Label(parent, SWT.NONE); + detailsValue.setText(marker.getAttribute(GradleErrorMarker.ATTRIBUTE_DETAILS, "")); + GridDataFactory.swtDefaults().span(2, 1).align(SWT.LEFT, SWT.TOP).applyTo(detailsValue); + + // solutions + String solutions = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_SOLUTIONS, ""); + Label solutionsLabel = new Label(parent, SWT.READ_ONLY); + solutionsLabel.setText("Solutions:"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(solutionsLabel); + + Text solutionsAreaText = new Text(parent, SWT.MULTI | SWT.READ_ONLY); + GridDataFactory.fillDefaults().span(1, 1).hint(100, 50).grab(true, false).applyTo(solutionsAreaText); + solutionsAreaText.setText(solutions); + new Label(parent, SWT.NONE); // span + + // stacktrace + String stacktrace = marker.getAttribute(GradleErrorMarker.ATTRIBUTE_STACKTRACE, "(no stacktrace provided)"); + Label stackTraceLabel = new Label(parent, SWT.NONE); + stackTraceLabel.setText("Stacktrace:"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.TOP).applyTo(stackTraceLabel); + final Text stacktraceAreaText = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL); + GridDataFactory.fillDefaults().span(1, 1).hint(100, 100).grab(true, true).applyTo(stacktraceAreaText); + stacktraceAreaText.setText(stacktrace); + + Button copyButton = new Button(parent, SWT.CENTER); + copyButton.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_COPY)); + copyButton.setToolTipText("Copy stacktrace"); + GridDataFactory.swtDefaults().align(SWT.LEFT, SWT.BOTTOM).applyTo(copyButton); + copyButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + Object[] data = {stacktraceAreaText.getText()}; + Transfer[] dataTypes = {TextTransfer.getInstance()}; + GradleMarkerPropertyPage.this.clipboard.setContents(data, dataTypes); + } + }); } public static int countLines(String str) {