Skip to content
This repository has been archived by the owner on Sep 23, 2023. It is now read-only.

Commit

Permalink
Mark invalid configurations in the PMD property page with an icon
Browse files Browse the repository at this point in the history
Invalid configurations are marked with a warning icon (when they are not
activated) or an error icon (when they are activated). A tool tip shows
the actual absolute path of the configuration to help the user resolve
the problem.

This is the second part of resolving issue #20.
  • Loading branch information
acanda committed Feb 1, 2015
1 parent 4b7e353 commit 8968a84
Show file tree
Hide file tree
Showing 21 changed files with 572 additions and 138 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
package ch.acanda.eclipse.pmd.properties;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;

import org.eclipse.core.resources.IProject;
import org.junit.Test;

import ch.acanda.eclipse.pmd.domain.RuleSetModel;
Expand All @@ -37,7 +39,8 @@ public class PMDPropertyPageControllerTest {
public void removeSelectedConfigurations() {
final PMDPropertyPageController controller = new PMDPropertyPageController();
final PMDPropertyPageViewModel model = controller.getModel();
model.setInitialState(true, ImmutableSortedSet.<RuleSetModel>of());
final IProject project = mock(IProject.class);
model.setInitialState(true, ImmutableSortedSet.<RuleSetModel>of(), project);
final ImmutableList<RuleSetViewModel> ruleSets = createRuleSets();
model.setRuleSets(ruleSets);
model.setActiveRuleSets(ruleSets.subList(0, 2));
Expand All @@ -58,7 +61,8 @@ public void removeSelectedConfigurations() {
public void removeSelectedConfigurationsWithoutSelection() {
final PMDPropertyPageController controller = new PMDPropertyPageController();
final PMDPropertyPageViewModel model = controller.getModel();
model.setInitialState(true, ImmutableSortedSet.<RuleSetModel>of());
final IProject project = mock(IProject.class);
model.setInitialState(true, ImmutableSortedSet.<RuleSetModel>of(), project);
final ImmutableList<RuleSetViewModel> ruleSets = createRuleSets();
model.setRuleSets(ruleSets);
model.setActiveRuleSets(ruleSets.subList(0, 2));
Expand All @@ -84,10 +88,10 @@ public String apply(final RuleSetViewModel ruleSet) {
}

private ImmutableList<RuleSetViewModel> createRuleSets() {
return ImmutableList.of(new RuleSetViewModel("A", "A-Type", "A-Location"),
new RuleSetViewModel("B", "B-Type", "B-Location"),
new RuleSetViewModel("C", "C-Type", "C-Location"),
new RuleSetViewModel("D", "D-Type", "D-Location"));
return ImmutableList.of(new RuleSetViewModel("A", "A-Type", "A-Location", true, "A-LocationToolTip"),
new RuleSetViewModel("B", "B-Type", "B-Location", false, "B-LocationToolTip"),
new RuleSetViewModel("C", "C-Type", "C-Location", true, "C-LocationToolTip"),
new RuleSetViewModel("D", "D-Type", "D-Location", false, "D-LocationToolTip"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private String createXmlConfigurationWithoutRuleSets() {
private Iterable<RuleSetModel> createRuleSets() {
return Arrays.asList(new RuleSetModel("Project Rule Set", new Location("pmd.xml", LocationContext.PROJECT)),
new RuleSetModel("Workspace Rule Set", new Location("Projext X/pmd.xml", LocationContext.WORKSPACE)),
new RuleSetModel("Filesystem Rule Set", new Location("x:\\pmx.xml", LocationContext.FILESYSTEM)),
new RuleSetModel("Filesystem Rule Set", new Location("x:\\pmx.xml", LocationContext.FILE_SYSTEM)),
new RuleSetModel("Remote Rule Set", new Location("http://example.org/pmd.xml", LocationContext.REMOTE)));
}

Expand Down Expand Up @@ -187,7 +187,7 @@ public void deserializeFilesystemRuleSetModel() throws IOException {

final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");

assertRuleSetModel(projectModel, LocationContext.FILESYSTEM, "Filesystem Rule Set", "x:\\pmx.xml");
assertRuleSetModel(projectModel, LocationContext.FILE_SYSTEM, "Filesystem Rule Set", "x:\\pmx.xml");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void convertWorkspaceLocationFallback() {
final Location result = V07ToV08Converter.getLocation(config, workspaceRoot);

assertEquals("Location path", Paths.get("/home", "somewhere", "else", "pmd.xml").toString(), result.getPath());
assertEquals("Location context", LocationContext.FILESYSTEM, result.getContext());
assertEquals("Location context", LocationContext.FILE_SYSTEM, result.getContext());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
package ch.acanda.eclipse.pmd.builder;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -26,6 +28,8 @@
import com.google.common.base.Optional;

/**
* Utility class to resolve a {@link Location}.
*
* @author Philip Graf
*/
public final class LocationResolver {
Expand All @@ -34,23 +38,28 @@ private LocationResolver() {
// hide constructor of utility class
}

public static Optional<String> resolve(final Location location, final IProject project) {
/**
* Resolves the location and checks if it exist.
*
* @return The absolute location if it exist or {@code Optional#absent()} if it doesn't.
*/
public static Optional<String> resolveIfExists(final Location location, final IProject project) {
final Optional<String> path;
switch (location.getContext()) {
case WORKSPACE:
path = resolveWorkspaceLocation(location, project);
path = resolveWorkspaceLocationIfExists(location, project);
break;

case PROJECT:
path = resolveProjectLocation(location, project);
path = resolveProjectLocationIfExists(location, project);
break;

case FILESYSTEM:
path = resolveFileSystemLocation(location);
case FILE_SYSTEM:
path = resolveFileSystemLocationIfExists(location);
break;

case REMOTE:
path = resolveRemoteLocation(location);
path = resolveRemoteLocationIfExists(location);
break;

default:
Expand All @@ -59,43 +68,85 @@ public static Optional<String> resolve(final Location location, final IProject p
return path;
}

private static Optional<String> resolveWorkspaceLocation(final Location location, final IProject project) {
/**
* Resolves a location. Unlike {@link #resolveIfExists(Location, IProject)} this also resolves if the location does
* not exist.
*
* @return The absolute location or {@code null} if it cannot be resolved.
*/
public static String resolve(final Location location, final IProject project) {
final String resolvedLocation;
switch (location.getContext()) {
case WORKSPACE:
final Path workspacePath = resolveWorkspaceLocation(location, project);
resolvedLocation = workspacePath == null ? null : workspacePath.toString();
break;

case PROJECT:
final Path path = Paths.get(project.getLocationURI()).resolve(toOSPath(location.getPath()));
resolvedLocation = path.normalize().toString();
break;

case FILE_SYSTEM:
case REMOTE:
resolvedLocation = location.getPath();
break;

default:
throw new IllegalStateException("Unknown location context: " + location.getContext());
}
return resolvedLocation;
}

private static Optional<String> resolveWorkspaceLocationIfExists(final Location location, final IProject project) {
try {
// format of the location's path: <project-name>/<project-relative-path>
final Path locationPath = Paths.get(toOSPath(location.getPath()));
final String projectName = locationPath.getName(0).toString();
final Path projectRelativePath = locationPath.subpath(1, locationPath.getNameCount());
final IWorkspaceRoot root = project.getWorkspace().getRoot();
final URI locationURI = root.getProject(projectName).getLocationURI();
if (locationURI != null) {
return Optional.of(Paths.get(locationURI).resolve(projectRelativePath).toString());
final Path path = resolveWorkspaceLocation(location, project);
if (path != null && Files.exists(path)) {
return Optional.of(path.toString());
}
return Optional.absent();
} catch (final InvalidPathException e) {
return Optional.absent();
}
}

private static Optional<String> resolveProjectLocation(final Location location, final IProject project) {
private static Path resolveWorkspaceLocation(final Location location, final IProject project) {
// format of the location's path: <project-name>/<project-relative-path>
final Path locationPath = Paths.get(toOSPath(location.getPath()));
final String projectName = locationPath.getName(0).toString();
final IWorkspaceRoot root = project.getWorkspace().getRoot();
final URI locationURI = root.getProject(projectName).getLocationURI();
if (locationURI != null) {
final Path projectRelativePath = locationPath.subpath(1, locationPath.getNameCount());
return Paths.get(locationURI).resolve(projectRelativePath);
}
return null;
}

private static Optional<String> resolveProjectLocationIfExists(final Location location, final IProject project) {
try {
return Optional.of(Paths.get(project.getLocationURI()).resolve(toOSPath(location.getPath())).toString());
final Path path = Paths.get(project.getLocationURI()).resolve(toOSPath(location.getPath()));
return Files.exists(path) ? Optional.of(path.toString()) : Optional.<String>absent();
} catch (final InvalidPathException e) {
return Optional.absent();
}
}

private static Optional<String> resolveFileSystemLocation(final Location location) {
private static Optional<String> resolveFileSystemLocationIfExists(final Location location) {
try {
return Optional.of(Paths.get(location.getPath()).toString());
final Path path = Paths.get(location.getPath());
return Files.exists(path) ? Optional.of(path.toString()) : Optional.<String>absent();
} catch (final InvalidPathException e) {
return Optional.absent();
}
}

private static Optional<String> resolveRemoteLocation(final Location location) {
private static Optional<String> resolveRemoteLocationIfExists(final Location location) {
try {
return Optional.of(new URI(location.getPath()).toString());
} catch (final URISyntaxException e) {
final URI uri = new URI(location.getPath());
uri.toURL().openStream().close();
return Optional.of(uri.toString());
} catch (final URISyntaxException | IOException e) {
return Optional.absent();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private void startWatchingRuleSetFiles(final ProjectModel projectModel) {

for (final RuleSetModel ruleSetModel : projectModel.getRuleSets()) {
if (ruleSetModel.getLocation().getContext() != LocationContext.REMOTE) {
final Optional<String> resolvedLocation = LocationResolver.resolve(ruleSetModel.getLocation(), project);
final Optional<String> resolvedLocation = LocationResolver.resolveIfExists(ruleSetModel.getLocation(), project);
if (resolvedLocation.isPresent()) {
final Path file = Paths.get(resolvedLocation.get());
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public ToReferenceId(final String projectName) {

@Override
public Optional<RuleSetReferenceId> apply(final RuleSetModel model) {
final Optional<String> resolvedLocation = LocationResolver.resolve(model.getLocation(), project);
final Optional<String> resolvedLocation = LocationResolver.resolveIfExists(model.getLocation(), project);
return resolvedLocation.transform(new Function<String, RuleSetReferenceId>() {
@Override
public RuleSetReferenceId apply(final String location) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
package ch.acanda.eclipse.pmd.domain;

public enum LocationContext {
PROJECT, WORKSPACE, FILESYSTEM, REMOTE;
PROJECT, WORKSPACE, FILE_SYSTEM, REMOTE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// =====================================================================
//
// Copyright (C) 2012 - 2015, Philip Graf
//
// 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
//
// =====================================================================

package ch.acanda.eclipse.pmd.properties;

import org.eclipse.swt.graphics.Image;

import ch.acanda.eclipse.pmd.properties.PMDPropertyPageViewModel.RuleSetViewModel;

/**
* Provides the label and tool tip for the location column.
*
* @author Philip Graf
*/
final class LocationLabelProvider extends RuleSetConfigurationLabelProvider {

protected LocationLabelProvider(final PMDPropertyPageViewModel model) {
super(model);
}

@Override
protected String getText(final RuleSetViewModel ruleSet) {
return ruleSet.getLocation();
}

@Override
public String getToolTipText(final Object element) {
final RuleSetViewModel ruleSet = toRuleSet(element);
if (ruleSet.isLocationValid()) {
return ruleSet.getLocationToolTip();
}
return getErrorMessage(ruleSet);
}

@Override
public Image getToolTipImage(final Object element) {
return getImage(toRuleSet(element));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// =====================================================================
//
// Copyright (C) 2012 - 2015, Philip Graf
//
// 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
//
// =====================================================================

package ch.acanda.eclipse.pmd.properties;

import org.eclipse.swt.graphics.Image;

import ch.acanda.eclipse.pmd.properties.PMDPropertyPageViewModel.RuleSetViewModel;

/**
* Provides the label, image and tool tip for the name column.
*
* @author Philip Graf
*/
final class NameLabelProvider extends RuleSetConfigurationLabelProvider {

protected NameLabelProvider(final PMDPropertyPageViewModel model) {
super(model);
}

@Override
protected String getText(final RuleSetViewModel ruleSet) {
return ruleSet.getName();
}

@Override
public Image getImage(final Object element) {
return getImage(toRuleSet(element));
}

@Override
public String getToolTipText(final Object element) {
final RuleSetViewModel ruleSet = toRuleSet(element);
if (!ruleSet.isLocationValid()) {
return getErrorMessage(ruleSet);
}
return null;
}

@Override
public Image getToolTipImage(final Object element) {
return getImage(element);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ public void init(final IProject project) {
final WorkspaceModel workspaceModel = PMDPlugin.getDefault().getWorkspaceModel();

projectModel = workspaceModel.getOrCreateProject(project.getName());
model.setInitialState(projectModel.isPMDEnabled(), projectModel.getRuleSets());
model.setInitialState(projectModel.isPMDEnabled(), projectModel.getRuleSets(), project);
final ImmutableSortedSet.Builder<RuleSetModel> ruleSetBuilder = ImmutableSortedSet.orderedBy(ProjectModel.RULE_SET_COMPARATOR);
for (final ProjectModel projectModel : workspaceModel.getProjects()) {
ruleSetBuilder.addAll(projectModel.getRuleSets());
}
model.setRuleSets(ImmutableList.copyOf(toViewModels(ruleSetBuilder.build())));
model.setRuleSets(ImmutableList.copyOf(toViewModels(ruleSetBuilder.build(), project)));
reset();
}

public void reset() {
model.setActiveRuleSets(ImmutableSet.copyOf(toViewModels(projectModel.getRuleSets())));
model.setActiveRuleSets(ImmutableSet.copyOf(toViewModels(projectModel.getRuleSets(), project)));
model.setSelectedRuleSets(ImmutableList.<RuleSetViewModel>of());
model.setPMDEnabled(projectModel.isPMDEnabled());
}
Expand Down Expand Up @@ -108,7 +108,7 @@ public void addRuleSetConfiguration(final Shell shell) {
dialog.setPageSize(300, SWT.DEFAULT);
final int result = dialog.open();
if (result == Window.OK && wizard.getRuleSetModel() != null) {
final RuleSetViewModel viewModel = toViewModel(wizard.getRuleSetModel());
final RuleSetViewModel viewModel = toViewModel(wizard.getRuleSetModel(), project);
model.addRuleSet(viewModel);
final HashSet<RuleSetViewModel> activeConfigs = new HashSet<>(model.getActiveRuleSets());
activeConfigs.add(viewModel);
Expand Down
Loading

0 comments on commit 8968a84

Please sign in to comment.