001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions.upload; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Dimension; 007import java.awt.GridBagLayout; 008import java.util.ArrayList; 009import java.util.Collection; 010import java.util.List; 011 012import javax.swing.JPanel; 013import javax.swing.JScrollPane; 014 015import org.openstreetmap.josm.data.APIDataSet; 016import org.openstreetmap.josm.data.osm.OsmPrimitive; 017import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 018import org.openstreetmap.josm.data.validation.OsmValidator; 019import org.openstreetmap.josm.data.validation.Severity; 020import org.openstreetmap.josm.data.validation.Test; 021import org.openstreetmap.josm.data.validation.TestError; 022import org.openstreetmap.josm.data.validation.util.AggregatePrimitivesVisitor; 023import org.openstreetmap.josm.gui.ExtendedDialog; 024import org.openstreetmap.josm.gui.MainApplication; 025import org.openstreetmap.josm.gui.MapFrame; 026import org.openstreetmap.josm.gui.dialogs.validator.ValidatorTreePanel; 027import org.openstreetmap.josm.gui.layer.OsmDataLayer; 028import org.openstreetmap.josm.gui.layer.ValidatorLayer; 029import org.openstreetmap.josm.gui.util.GuiHelper; 030import org.openstreetmap.josm.gui.widgets.HtmlPanel; 031import org.openstreetmap.josm.tools.GBC; 032 033/** 034 * The action that does the validate thing. 035 * <p> 036 * This action iterates through all active tests and give them the data, so that 037 * each one can test it. 038 * 039 * @author frsantos 040 * @since 3669 041 */ 042public class ValidateUploadHook implements UploadHook { 043 044 /** 045 * Validate the modified data before uploading 046 * @param apiDataSet contains primitives to be uploaded 047 * @return true if upload should continue, else false 048 */ 049 @Override 050 public boolean checkUpload(APIDataSet apiDataSet) { 051 052 OsmValidator.initializeTests(); 053 Collection<Test> tests = OsmValidator.getEnabledTests(true); 054 if (tests.isEmpty()) 055 return true; 056 057 AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor(); 058 v.visit(apiDataSet.getPrimitivesToAdd()); 059 Collection<OsmPrimitive> selection = v.visit(apiDataSet.getPrimitivesToUpdate()); 060 061 List<TestError> errors = new ArrayList<>(30); 062 for (Test test : tests) { 063 test.setBeforeUpload(true); 064 test.setPartialSelection(true); 065 test.startTest(null); 066 test.visit(selection); 067 test.endTest(); 068 if (ValidatorPrefHelper.PREF_OTHER.get() && ValidatorPrefHelper.PREF_OTHER_UPLOAD.get()) { 069 errors.addAll(test.getErrors()); 070 } else { 071 for (TestError e : test.getErrors()) { 072 if (e.getSeverity() != Severity.OTHER) { 073 errors.add(e); 074 } 075 } 076 } 077 test.clear(); 078 } 079 080 if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) { 081 boolean allIgnored = true; 082 for (TestError error : errors) { 083 if (!error.updateIgnored()) { 084 allIgnored = false; 085 } 086 } 087 if (allIgnored) 088 return true; 089 } 090 091 OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer(); 092 if (editLayer != null) { 093 editLayer.validationErrors.clear(); 094 editLayer.validationErrors.addAll(errors); 095 } 096 MapFrame map = MainApplication.getMap(); 097 if (map != null) { 098 map.validatorDialog.tree.setErrors(errors); 099 } 100 if (errors.isEmpty()) 101 return true; 102 103 return displayErrorScreen(errors); 104 } 105 106 /** 107 * Displays a screen where the actions that would be taken are displayed and 108 * give the user the possibility to cancel the upload. 109 * @param errors The errors displayed in the screen 110 * @return <code>true</code>, if the upload should continue. <code>false</code> 111 * if the user requested cancel. 112 */ 113 private static boolean displayErrorScreen(List<TestError> errors) { 114 JPanel p = new JPanel(new GridBagLayout()); 115 ValidatorTreePanel errorPanel = new ValidatorTreePanel(errors); 116 errorPanel.expandAll(); 117 HtmlPanel pnlMessage = new HtmlPanel(); 118 pnlMessage.setText("<html><body>" 119 + tr("The following are results of automatic validation. Try fixing" 120 + " these, but be careful (don''t destroy valid data)." 121 + " When in doubt ignore them.<br>When you" 122 + " cancel this dialog, you can find the entries in the validator" 123 + " side panel to inspect them.") 124 + "<table align=\"center\">" 125 + "<tr><td align=\"left\"><b>"+tr("Errors") 126 + " </b></td><td align=\"left\">" 127 + tr("Usually this should be fixed.")+"</td></tr>" 128 + "<tr><td align=\"left\"><b>"+tr("Warnings") 129 + " </b></td><td align=\"left\">" 130 + tr("Fix these when possible.")+"</td></tr>" 131 + "<tr><td align=\"left\"><b>"+tr("Other") 132 + " </b></td><td align=\"left\">" 133 + tr("Informational warnings, expect many false entries.")+"</td></tr>" 134 + "</table>" 135 ); 136 pnlMessage.setPreferredSize(new Dimension(500, 150)); 137 p.add(pnlMessage, GBC.eol().fill(GBC.HORIZONTAL)); 138 p.add(new JScrollPane(errorPanel), GBC.eol().fill(GBC.BOTH)); 139 140 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), 141 tr("Suspicious data found. Upload anyway?"), 142 tr("Continue upload"), tr("Cancel")) 143 .setButtonIcons("ok", "cancel") 144 .setContent(p); 145 int rc = ed.showDialog().getValue(); 146 GuiHelper.destroyComponents(ed, false); 147 ed.dispose(); 148 if (rc != 1) { 149 OsmValidator.initializeTests(); 150 OsmValidator.initializeErrorLayer(); 151 MainApplication.getMap().validatorDialog.unfurlDialog(); 152 MainApplication.getLayerManager().getLayersOfType(ValidatorLayer.class).forEach(ValidatorLayer::invalidate); 153 return false; 154 } 155 return true; 156 } 157}