001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.tagging.presets; 003 004import static java.util.Collections.singleton; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.util.ArrayList; 008import java.util.Arrays; 009import java.util.Collection; 010import java.util.List; 011 012import javax.swing.JLabel; 013 014import org.openstreetmap.josm.command.Command; 015import org.openstreetmap.josm.data.osm.DataSet; 016import org.openstreetmap.josm.data.osm.FilterModel; 017import org.openstreetmap.josm.data.osm.INode; 018import org.openstreetmap.josm.data.osm.IRelation; 019import org.openstreetmap.josm.data.osm.IWay; 020import org.openstreetmap.josm.data.osm.OsmPrimitive; 021import org.openstreetmap.josm.data.osm.Tag; 022import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 023import org.openstreetmap.josm.data.validation.OsmValidator; 024import org.openstreetmap.josm.data.validation.TestError; 025import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker; 026import org.openstreetmap.josm.data.validation.tests.OpeningHourTest; 027import org.openstreetmap.josm.gui.MainApplication; 028import org.openstreetmap.josm.gui.util.GuiHelper; 029import org.openstreetmap.josm.tools.Logging; 030import org.openstreetmap.josm.tools.SubclassFilteredCollection; 031import org.openstreetmap.josm.tools.Utils; 032 033/** 034 * Validates the preset user input a the given primitive. 035 */ 036interface TaggingPresetValidation { 037 038 /** 039 * Asynchronously validates the user input for the given primitive. 040 * @param original the primitive 041 * @param validationLabel the label for validation errors 042 * @param changedTags the list of tags that are set by this preset 043 */ 044 static void validateAsync(OsmPrimitive original, JLabel validationLabel, List<Tag> changedTags) { 045 OsmPrimitive primitive = applyChangedTags(original, changedTags); 046 MainApplication.worker.execute(() -> validate(primitive, validationLabel)); 047 } 048 049 /** 050 * Validates the user input for the given primitive. 051 * @param primitive the primitive 052 * @param validationLabel the label for validation errors 053 */ 054 static void validate(OsmPrimitive primitive, JLabel validationLabel) { 055 try { 056 MapCSSTagChecker mapCSSTagChecker = OsmValidator.getTest(MapCSSTagChecker.class); 057 OpeningHourTest openingHourTest = OsmValidator.getTest(OpeningHourTest.class); 058 OsmValidator.initializeTests(Arrays.asList(mapCSSTagChecker, openingHourTest)); 059 060 List<TestError> errors = new ArrayList<>(); 061 openingHourTest.addErrorsForPrimitive(primitive, errors); 062 errors.addAll(mapCSSTagChecker.getErrorsForPrimitive(primitive, ValidatorPrefHelper.PREF_OTHER.get())); 063 064 boolean visible = !errors.isEmpty(); 065 String toolTipText = "<html>" + Utils.joinAsHtmlUnorderedList(Utils.transform(errors, e -> 066 e.getDescription() == null ? e.getMessage() : tr("{0} ({1})", e.getMessage(), e.getDescription()))); 067 GuiHelper.runInEDTAndWait(() -> { 068 validationLabel.setVisible(visible); 069 validationLabel.setToolTipText(toolTipText); 070 }); 071 } catch (Exception e) { 072 Logging.warn("Failed to validate {0}", primitive); 073 Logging.warn(e); 074 } finally { 075 primitive.getDataSet().clear(); 076 } 077 } 078 079 static OsmPrimitive applyChangedTags(OsmPrimitive original, List<Tag> changedTags) { 080 DataSet ds = new DataSet(); 081 Collection<OsmPrimitive> primitives = FilterModel.getAffectedPrimitives(singleton(original)); 082 OsmPrimitive primitive = ds.clonePrimitives( 083 new SubclassFilteredCollection<>(primitives, INode.class::isInstance), 084 new SubclassFilteredCollection<>(primitives, IWay.class::isInstance), 085 new SubclassFilteredCollection<>(primitives, IRelation.class::isInstance)) 086 .get(original); 087 Command command = TaggingPreset.createCommand(singleton(primitive), changedTags); 088 if (command != null) { 089 command.executeCommand(); 090 } 091 return primitive; 092 } 093}