Ignore:
Timestamp:
2016-12-29T20:05:17+01:00 (8 years ago)
Author:
darya
Message:

partial fix for #14116

Location:
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java

    r33091 r33108  
    4444public class PTAssistantValidatorTest extends Test {
    4545
    46     public static final int ERROR_CODE_SORTING = 3711;
    47     public static final int ERROR_CODE_ROAD_TYPE = 3721;
    48     public static final int ERROR_CODE_CONSTRUCTION = 3722;
    49     public static final int ERROR_CODE_DIRECTION = 3731;
    50     public static final int ERROR_CODE_END_STOP = 3741;
    51     public static final int ERROR_CODE_SPLIT_WAY = 3742;
    52     public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743;
    53     public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751;
    54     public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752;
    55     public static final int ERROR_CODE_STOP_NOT_SERVED = 3753;
    56     public static final int ERROR_CODE_STOP_BY_STOP = 3754;
    57     public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761;
    58     public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762;
    59     public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763;
    60     public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764;
    61 
    62     private PTAssistantLayer layer;
    63 
    64     public PTAssistantValidatorTest() {
    65         super(tr("Public Transport Assistant tests"),
    66                 tr("Check if route relations are compatible with public transport version 2"));
    67 
    68         layer = PTAssistantLayer.getLayer();
    69         DataSet.addSelectionListener(layer);
    70 
    71     }
    72 
    73     @Override
    74     public void visit(Node n) {
    75 
    76         if (n.isIncomplete()) {
    77             return;
    78         }
    79 
    80         NodeChecker nodeChecker = new NodeChecker(n, this);
    81 
    82         // select only stop_positions
    83         if (n.hasTag("public_transport", "stop_position")) {
    84 
    85             // check if stop positions are on a way:
    86             nodeChecker.performSolitaryStopPositionTest();
    87 
    88             if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) {
    89                 // check if stop positions are in any stop_area relation:
    90                 nodeChecker.performNodePartOfStopAreaTest();
    91             }
    92 
    93         }
    94 
    95         // select only platforms
    96         if (n.hasTag("public_transport", "platform")) {
    97 
    98             // check that platforms are not part of any way:
    99             nodeChecker.performPlatformPartOfWayTest();
    100 
    101             if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) {
    102                 // check if platforms are in any stop_area relation:
    103                 nodeChecker.performNodePartOfStopAreaTest();
    104             }
    105 
    106         }
    107 
    108         this.errors.addAll(nodeChecker.getErrors());
    109 
    110     }
    111 
    112     @Override
    113     public void visit(Relation r) {
    114 
    115         // Download incomplete members. If the download does not work, return
    116         // and do not do any testing.
    117         if (r.hasIncompleteMembers()) {
    118 
    119             boolean downloadSuccessful = this.downloadIncompleteMembers();
    120             if (!downloadSuccessful) {
    121                 return;
    122             }
    123         }
    124 
    125         if (r.hasIncompleteMembers()) {
    126             return;
    127         }
    128 
    129 
    130         // Do some testing on stop area relations
    131         if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true && StopUtils.isStopArea(r)) {
    132 
    133             StopChecker stopChecker = new StopChecker(r, this);
    134 
    135             // Check if stop area relation has one stop position.
    136             stopChecker.performStopAreaStopPositionTest();
    137 
    138             // Check if stop area relation has one platform.
    139             stopChecker.performStopAreaPlatformTest();
    140 
    141             // Check if stop position(s) belong the same route relation as
    142             // related platform(s)
    143             stopChecker.performStopAreaRelationsTest();
    144 
    145             // Attach thrown errors
    146             this.errors.addAll(stopChecker.getErrors());
    147         }
    148 
    149 
    150         if (!RouteUtils.isTwoDirectionRoute(r)) {
    151             return;
    152         }
    153 
    154         // Check individual ways using the oneway direction test and the road
    155         // type test:
    156         WayChecker wayChecker = new WayChecker(r, this);
    157         wayChecker.performDirectionTest();
    158         wayChecker.performRoadTypeTest();
    159         this.errors.addAll(wayChecker.getErrors());
    160 
    161         proceedWithSorting(r);
    162 
    163         // This allows to modify the route before the sorting and
    164         // SegmentChecker are carried out:
    165         // if (this.errors.isEmpty()) {
    166         // proceedWithSorting(r);
    167         // } else {
    168         // this.proceedAfterWayCheckerErrors(r);
    169         // }
    170 
    171     }
    172 
    173     /**
    174      * Downloads incomplete relation members in an extra thread (user input
    175      * required)
    176      *
    177      * @return true if successful, false if not successful
    178      */
    179     private boolean downloadIncompleteMembers() {
    180 
    181         final int[] userSelection = {0};
    182 
    183         try {
    184 
    185             if (SwingUtilities.isEventDispatchThread()) {
    186 
    187                 userSelection[0] = showIncompleteMembersDownloadDialog();
    188 
    189             } else {
    190 
    191                 SwingUtilities.invokeAndWait(new Runnable() {
    192                     @Override
    193                     public void run() {
    194                         try {
    195                             userSelection[0] = showIncompleteMembersDownloadDialog();
    196                         } catch (InterruptedException e) {
    197                             e.printStackTrace();
    198                         }
    199 
    200                     }
    201                 });
    202 
    203             }
    204 
    205         } catch (InterruptedException | InvocationTargetException e) {
    206             return false;
    207         }
    208 
    209         if (userSelection[0] == JOptionPane.YES_OPTION) {
    210 
    211             Thread t = new IncompleteMembersDownloadThread();
    212             t.start();
    213             synchronized (t) {
    214                 try {
    215                     t.wait();
    216                 } catch (InterruptedException e) {
    217                     return false;
    218                 }
    219             }
    220 
    221         }
    222 
    223         return true;
    224 
    225     }
    226 
    227     /**
    228      * Shows the dialog asking the user about an incomplete member download
    229      *
    230      * @return user's selection
    231      * @throws InterruptedException if interrupted
    232      */
    233     private int showIncompleteMembersDownloadDialog() throws InterruptedException {
    234 
    235         if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) {
    236             return JOptionPane.YES_OPTION;
    237         }
    238 
    239         if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) {
    240             return JOptionPane.NO_OPTION;
    241         }
    242 
    243         IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog();
    244         return incompleteMembersDownloadDialog.getUserSelection();
    245 
    246     }
    247 
    248     /**
    249      * Gets user input after errors were detected by WayChecker. Although this
    250      * method is not used in the current implementation, it can be used to fix
    251      * errors from the previous testing stage and modify the route before the
    252      * second stage of testing is carried out.
    253      */
    254     @SuppressWarnings("unused")
    255     private void proceedAfterWayCheckerErrors(Relation r) {
    256 
    257         // count errors of each type:
    258         int numberOfDirectionErrors = 0;
    259         int numberOfRoadTypeErrors = 0;
    260         for (TestError e : this.errors) {
    261             if (e.getCode() == ERROR_CODE_DIRECTION) {
    262                 numberOfDirectionErrors++;
    263             }
    264             if (e.getCode() == ERROR_CODE_ROAD_TYPE) {
    265                 numberOfRoadTypeErrors++;
    266             }
    267         }
    268 
    269         final int[] userInput = {0};
    270         final long idParameter = r.getId();
    271         final int directionErrorParameter = numberOfDirectionErrors;
    272         final int roadTypeErrorParameter = numberOfRoadTypeErrors;
    273 
    274         if (SwingUtilities.isEventDispatchThread()) {
    275 
    276             userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);
    277 
    278         } else {
    279 
    280             try {
    281                 SwingUtilities.invokeAndWait(new Runnable() {
    282                     @Override
    283                     public void run() {
    284                         userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);
    285 
    286                     }
    287                 });
    288             } catch (InvocationTargetException | InterruptedException e1) {
    289                 e1.printStackTrace();
    290             }
    291 
    292         }
    293 
    294         if (userInput[0] == 0) {
    295             this.fixErrorFromPlugin(this.errors);
    296             proceedWithSorting(r);
    297             return;
    298         }
    299 
    300         if (userInput[0] == 1) {
    301             JOptionPane.showMessageDialog(null, "This is not implemented yet!");
    302             return;
    303         }
    304 
    305         if (userInput[0] == 2) {
    306             proceedWithSorting(r);
    307         }
    308 
    309         // if userInput==-1 (i.e. no input), do nothing and stop testing of the
    310         // route.
    311 
    312     }
    313 
    314     private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {
    315 
    316         if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) {
    317             return 2;
    318         }
    319 
    320         if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) {
    321             return 0;
    322         }
    323 
    324         if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) {
    325             return 2;
    326         }
    327 
    328         ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors);
    329         return proceedDialog.getUserSelection();
    330 
    331     }
    332 
    333     /**
    334      * Carries out the second stage of the testing: sorting
    335      *
    336      * @param r relation
    337      */
    338     private void proceedWithSorting(Relation r) {
    339 
    340         // Check if the relation is correct, or only has a wrong sorting order:
    341         RouteChecker routeChecker = new RouteChecker(r, this);
    342         routeChecker.performSortingTest();
    343         List<TestError> routeCheckerErrors = routeChecker.getErrors();
    344 
    345         /*- At this point, there are 3 variants:
    346          *
    347          * 1) There are no errors => route is correct
    348          * 2) There is only a sorting error (can only be 1), but otherwise
    349          * correct.
    350          * 3) There are some other errors/gaps that cannot be fixed by
    351          * sorting => start further test (stop-by-stop)
    352          *
    353          * */
    354 
    355         if (!routeCheckerErrors.isEmpty()) {
    356             // Variant 2
    357             // If there is only the sorting error, add it
    358             this.errors.addAll(routeChecker.getErrors());
    359         }
    360 
    361         // if (!routeChecker.getHasGap()) {
    362         // // Variant 1
    363         // storeCorrectRouteSegments(r);
    364         // }
    365 
    366         // Variant 3:
    367         proceedAfterSorting(r);
    368 
    369     }
    370 
    371     /**
    372      * Carries out the stop-by-stop testing which includes building the route
    373      * data model.
    374      *
    375      * @param r route relation
    376      */
    377     private void proceedAfterSorting(Relation r) {
    378 
    379         SegmentChecker segmentChecker = new SegmentChecker(r, this);
    380 
    381         // Check if the creation of the route data model in the segment checker
    382         // worked. If it did not, it means the roles in the route relation do
    383         // not match the tags of the route members.
    384         if (!segmentChecker.getErrors().isEmpty()) {
    385             this.errors.addAll(segmentChecker.getErrors());
    386         }
    387 
    388         segmentChecker.performFirstStopTest();
    389         segmentChecker.performLastStopTest();
    390         segmentChecker.performStopNotServedTest();
    391 
    392         boolean sortingErrorFound = false;
    393         for (TestError error : this.errors) {
    394             if (error.getCode() == ERROR_CODE_SORTING) {
    395                 sortingErrorFound = true;
    396                 break;
    397             }
    398         }
    399         if (!sortingErrorFound) {
    400             segmentChecker.performStopByStopTest();
    401             segmentChecker.findFixes();
    402         }
    403 
    404         for (TestError error: segmentChecker.getErrors()) {
    405             if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) {
    406                 this.errors.add(error);
    407             }
    408         }
    409     }
    410    
    411     /**
    412      * Overrides the superclass method
    413      */
    414     public void startTest() {
    415         super.startTest(progressMonitor);
    416         SegmentChecker.reset();
    417     }
    418    
    419     /**
    420      * Method is called after all primitives has been visited, overrides the method of the superclass.
    421      */
    422     public void endTest() {
    423        
    424         // modify the error messages for the stop-by-stop test:
    425         SegmentChecker.modifyStopByStopErrorMessages();
    426        
    427         // add the stop-by-stop errors with modified messages:
    428         for (Entry<Builder, PTRouteSegment> entry: SegmentChecker.wrongSegmentBuilders.entrySet()) {                   
    429                 TestError error = entry.getKey().build();
    430                 SegmentChecker.wrongSegments.put(error, entry.getValue());
    431                 this.errors.add(error);
    432         }
    433        
    434         super.endTest();
    435 
    436     }
    437 
    438     /**
    439      * Creates the PTRouteSegments of a route that has been found correct and
    440      * stores them in the list of correct route segments
    441      *
    442      * @param r
    443      *            route relation
    444      */
    445     @SuppressWarnings("unused")
    446     private void storeCorrectRouteSegments(Relation r) {
    447         PTRouteDataManager manager = new PTRouteDataManager(r);
    448         StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays());
    449         if (manager.getPTStops().size() > 1) {
    450             for (int i = 1; i < manager.getPTStops().size(); i++) {
    451                 PTStop segmentStartStop = manager.getPTStops().get(i - 1);
    452                 PTStop segmentEndStop = manager.getPTStops().get(i);
    453                 Way segmentStartWay = assigner.get(segmentStartStop);
    454                 Way segmentEndWay = assigner.get(segmentEndStop);
    455                 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay);
    456                 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r);
    457                 SegmentChecker.addCorrectSegment(routeSegment);
    458             }
    459         }
    460     }
    461 
    462     /**
    463      * Checks if the test error is fixable
    464      */
    465     @Override
    466     public boolean isFixable(TestError testError) {
    467         if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE
    468                 || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING
    469                 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION
    470                 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {
    471             return true;
    472         }
    473 
    474         if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) {
    475             return true;
    476         }
    477 
    478         return false;
    479     }
    480 
    481     /**
    482      * Fixes the given error
    483      */
    484     @Override
    485     public Command fixError(TestError testError) {
    486 
    487         // repaint the relation in the pt_assistant layer:
    488         if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) {
    489             Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next();
    490             this.layer.repaint(relationToBeFixed);
    491         }
    492 
    493         // reset the last fix:
    494         PTAssistantPlugin.setLastFix(null);
    495 
    496         List<Command> commands = new ArrayList<>();
    497 
    498         if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) {
    499             commands.add(WayChecker.fixErrorByZooming(testError));
    500         }
    501 
    502         if (testError.getCode() == ERROR_CODE_DIRECTION) {
    503             commands.add(WayChecker.fixErrorByZooming(testError));
    504 
    505         }
    506 
    507         if (testError.getCode() == ERROR_CODE_SORTING) {
    508             commands.add(RouteChecker.fixSortingError(testError));
    509         }
    510 
    511         if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION
    512                 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {
    513             commands.add(NodeChecker.fixError(testError));
    514         }
    515 
    516         if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) {
    517             commands.add(SegmentChecker.fixError(testError));
    518             // make sure the primitives of this testError are selected:
    519             Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>();
    520             for (Object obj : testError.getPrimitives()) {
    521                 primitivesToSelect.add((OsmPrimitive) obj);
    522             }
    523             SelectCommand selectCommand = new SelectCommand(primitivesToSelect);
    524             SwingUtilities.invokeLater(new Runnable() {
    525                 @Override
    526                 public void run() {
    527                     selectCommand.executeCommand();
    528                 }
    529             });
    530         }
    531 
    532         if (commands.isEmpty()) {
    533             return null;
    534         }
    535 
    536         if (commands.size() == 1) {
    537             return commands.get(0);
    538         }
    539 
    540         return new SequenceCommand(tr("Fix error"), commands);
    541     }
    542 
    543     /**
    544      * This method is the counterpart of the fixError(TestError testError)
    545      * method. The fixError method is invoked from the core validator (e.g. when
    546      * user presses the "Fix" button in the validator). This method is invoken
    547      * when the fix is initiated from within the plugin (e.g. automated fixes).
    548      */
    549     private void fixErrorFromPlugin(List<TestError> testErrors) {
    550 
    551         // run fix task asynchronously
    552         FixTask fixTask = new FixTask(testErrors);
    553 
    554         Thread t = new Thread(fixTask);
    555         t.start();
    556         try {
    557             t.join();
    558             errors.removeAll(testErrors);
    559 
    560         } catch (InterruptedException e) {
    561             JOptionPane.showMessageDialog(null, "Error occurred during fixing");
    562         }
    563 
    564     }
    565 
    566     public void addFixVariants(List<List<PTWay>> fixVariants) {
    567         layer.addFixVariants(fixVariants);
    568     }
    569 
    570     public void clearFixVariants() {
    571         layer.clearFixVariants();
    572     }
    573 
    574     public List<PTWay> getFixVariant(Character c) {
    575         return layer.getFixVariant(c);
    576     }
    577 
    578     @SuppressWarnings("unused")
    579     private void performDummyTest(Relation r) {
    580         List<Relation> primitives = new ArrayList<>(1);
    581         primitives.add(r);
    582         Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION);
    583         builder.message(tr("PT: dummy test warning"));
    584         builder.primitives(primitives);
    585         errors.add(
    586                 builder.build());
    587     }
     46        public static final int ERROR_CODE_SORTING = 3711;
     47        public static final int ERROR_CODE_ROAD_TYPE = 3721;
     48        public static final int ERROR_CODE_CONSTRUCTION = 3722;
     49        public static final int ERROR_CODE_DIRECTION = 3731;
     50        public static final int ERROR_CODE_END_STOP = 3741;
     51        public static final int ERROR_CODE_SPLIT_WAY = 3742;
     52        public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743;
     53        public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751;
     54        public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752;
     55        public static final int ERROR_CODE_STOP_NOT_SERVED = 3753;
     56        public static final int ERROR_CODE_STOP_BY_STOP = 3754;
     57        public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761;
     58        public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762;
     59        public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763;
     60        public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764;
     61
     62        private PTAssistantLayer layer;
     63
     64        public PTAssistantValidatorTest() {
     65                super(tr("Public Transport Assistant tests"),
     66                                tr("Check if route relations are compatible with public transport version 2"));
     67
     68                layer = PTAssistantLayer.getLayer();
     69                DataSet.addSelectionListener(layer);
     70
     71        }
     72
     73        @Override
     74        public void visit(Node n) {
     75
     76                if (n.isIncomplete()) {
     77                        return;
     78                }
     79
     80                NodeChecker nodeChecker = new NodeChecker(n, this);
     81
     82                // select only stop_positions
     83                if (n.hasTag("public_transport", "stop_position")) {
     84
     85                        // check if stop positions are on a way:
     86                        nodeChecker.performSolitaryStopPositionTest();
     87
     88                        if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) {
     89                                // check if stop positions are in any stop_area relation:
     90                                nodeChecker.performNodePartOfStopAreaTest();
     91                        }
     92
     93                }
     94
     95                // select only platforms
     96                if (n.hasTag("public_transport", "platform")) {
     97
     98                        // check that platforms are not part of any way:
     99                        nodeChecker.performPlatformPartOfWayTest();
     100
     101                        if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) {
     102                                // check if platforms are in any stop_area relation:
     103                                nodeChecker.performNodePartOfStopAreaTest();
     104                        }
     105
     106                }
     107
     108                this.errors.addAll(nodeChecker.getErrors());
     109
     110        }
     111
     112        @Override
     113        public void visit(Relation r) {
     114
     115                // Download incomplete members. If the download does not work, return
     116                // and do not do any testing.
     117                if (r.hasIncompleteMembers()) {
     118
     119                        boolean downloadSuccessful = this.downloadIncompleteMembers();
     120                        if (!downloadSuccessful) {
     121                                return;
     122                        }
     123                }
     124
     125                if (r.hasIncompleteMembers()) {
     126                        return;
     127                }
     128
     129                // Do some testing on stop area relations
     130                if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true && StopUtils.isStopArea(r)) {
     131
     132                        StopChecker stopChecker = new StopChecker(r, this);
     133
     134                        // Check if stop area relation has one stop position.
     135                        stopChecker.performStopAreaStopPositionTest();
     136
     137                        // Check if stop area relation has one platform.
     138                        stopChecker.performStopAreaPlatformTest();
     139
     140                        // Check if stop position(s) belong the same route relation as
     141                        // related platform(s)
     142                        stopChecker.performStopAreaRelationsTest();
     143
     144                        // Attach thrown errors
     145                        this.errors.addAll(stopChecker.getErrors());
     146                }
     147
     148                if (!RouteUtils.isTwoDirectionRoute(r)) {
     149                        return;
     150                }
     151
     152                // Check individual ways using the oneway direction test and the road
     153                // type test:
     154                WayChecker wayChecker = new WayChecker(r, this);
     155                wayChecker.performDirectionTest();
     156                wayChecker.performRoadTypeTest();
     157                this.errors.addAll(wayChecker.getErrors());
     158
     159                proceedWithSorting(r);
     160
     161                // This allows to modify the route before the sorting and
     162                // SegmentChecker are carried out:
     163                // if (this.errors.isEmpty()) {
     164                // proceedWithSorting(r);
     165                // } else {
     166                // this.proceedAfterWayCheckerErrors(r);
     167                // }
     168
     169        }
     170
     171        /**
     172         * Downloads incomplete relation members in an extra thread (user input
     173         * required)
     174         *
     175         * @return true if successful, false if not successful
     176         */
     177        private boolean downloadIncompleteMembers() {
     178
     179                final int[] userSelection = { 0 };
     180
     181                try {
     182
     183                        if (SwingUtilities.isEventDispatchThread()) {
     184
     185                                userSelection[0] = showIncompleteMembersDownloadDialog();
     186
     187                        } else {
     188
     189                                SwingUtilities.invokeAndWait(new Runnable() {
     190                                        @Override
     191                                        public void run() {
     192                                                try {
     193                                                        userSelection[0] = showIncompleteMembersDownloadDialog();
     194                                                } catch (InterruptedException e) {
     195                                                        e.printStackTrace();
     196                                                }
     197
     198                                        }
     199                                });
     200
     201                        }
     202
     203                } catch (InterruptedException | InvocationTargetException e) {
     204                        return false;
     205                }
     206
     207                if (userSelection[0] == JOptionPane.YES_OPTION) {
     208
     209                        Thread t = new IncompleteMembersDownloadThread();
     210                        t.start();
     211                        synchronized (t) {
     212                                try {
     213                                        t.wait();
     214                                } catch (InterruptedException e) {
     215                                        return false;
     216                                }
     217                        }
     218
     219                }
     220
     221                return true;
     222
     223        }
     224
     225        /**
     226         * Shows the dialog asking the user about an incomplete member download
     227         *
     228         * @return user's selection
     229         * @throws InterruptedException
     230         *             if interrupted
     231         */
     232        private int showIncompleteMembersDownloadDialog() throws InterruptedException {
     233
     234                if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) {
     235                        return JOptionPane.YES_OPTION;
     236                }
     237
     238                if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) {
     239                        return JOptionPane.NO_OPTION;
     240                }
     241
     242                IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog();
     243                return incompleteMembersDownloadDialog.getUserSelection();
     244
     245        }
     246
     247        /**
     248         * Gets user input after errors were detected by WayChecker. Although this
     249         * method is not used in the current implementation, it can be used to fix
     250         * errors from the previous testing stage and modify the route before the
     251         * second stage of testing is carried out.
     252         */
     253        @SuppressWarnings("unused")
     254        private void proceedAfterWayCheckerErrors(Relation r) {
     255
     256                // count errors of each type:
     257                int numberOfDirectionErrors = 0;
     258                int numberOfRoadTypeErrors = 0;
     259                for (TestError e : this.errors) {
     260                        if (e.getCode() == ERROR_CODE_DIRECTION) {
     261                                numberOfDirectionErrors++;
     262                        }
     263                        if (e.getCode() == ERROR_CODE_ROAD_TYPE) {
     264                                numberOfRoadTypeErrors++;
     265                        }
     266                }
     267
     268                final int[] userInput = { 0 };
     269                final long idParameter = r.getId();
     270                final int directionErrorParameter = numberOfDirectionErrors;
     271                final int roadTypeErrorParameter = numberOfRoadTypeErrors;
     272
     273                if (SwingUtilities.isEventDispatchThread()) {
     274
     275                        userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);
     276
     277                } else {
     278
     279                        try {
     280                                SwingUtilities.invokeAndWait(new Runnable() {
     281                                        @Override
     282                                        public void run() {
     283                                                userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter);
     284
     285                                        }
     286                                });
     287                        } catch (InvocationTargetException | InterruptedException e1) {
     288                                e1.printStackTrace();
     289                        }
     290
     291                }
     292
     293                if (userInput[0] == 0) {
     294                        this.fixErrorFromPlugin(this.errors);
     295                        proceedWithSorting(r);
     296                        return;
     297                }
     298
     299                if (userInput[0] == 1) {
     300                        JOptionPane.showMessageDialog(null, "This is not implemented yet!");
     301                        return;
     302                }
     303
     304                if (userInput[0] == 2) {
     305                        proceedWithSorting(r);
     306                }
     307
     308                // if userInput==-1 (i.e. no input), do nothing and stop testing of the
     309                // route.
     310
     311        }
     312
     313        private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) {
     314
     315                if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) {
     316                        return 2;
     317                }
     318
     319                if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) {
     320                        return 0;
     321                }
     322
     323                if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) {
     324                        return 2;
     325                }
     326
     327                ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors);
     328                return proceedDialog.getUserSelection();
     329
     330        }
     331
     332        /**
     333         * Carries out the second stage of the testing: sorting
     334         *
     335         * @param r
     336         *            relation
     337         */
     338        private void proceedWithSorting(Relation r) {
     339
     340                // Check if the relation is correct, or only has a wrong sorting order:
     341                RouteChecker routeChecker = new RouteChecker(r, this);
     342                routeChecker.performSortingTest();
     343                List<TestError> routeCheckerErrors = routeChecker.getErrors();
     344
     345                /*- At this point, there are 3 variants:
     346                 *
     347                 * 1) There are no errors => route is correct
     348                 * 2) There is only a sorting error (can only be 1), but otherwise
     349                 * correct.
     350                 * 3) There are some other errors/gaps that cannot be fixed by
     351                 * sorting => start further test (stop-by-stop)
     352                 *
     353                 * */
     354
     355                if (!routeCheckerErrors.isEmpty()) {
     356                        // Variant 2
     357                        // If there is only the sorting error, add it
     358                        this.errors.addAll(routeChecker.getErrors());
     359                }
     360
     361                // if (!routeChecker.getHasGap()) {
     362                // // Variant 1
     363                // storeCorrectRouteSegments(r);
     364                // }
     365
     366                // Variant 3:
     367                proceedAfterSorting(r);
     368
     369        }
     370
     371        /**
     372         * Carries out the stop-by-stop testing which includes building the route
     373         * data model.
     374         *
     375         * @param r
     376         *            route relation
     377         */
     378        private void proceedAfterSorting(Relation r) {
     379
     380                SegmentChecker segmentChecker = new SegmentChecker(r, this);
     381
     382                // Check if the creation of the route data model in the segment checker
     383                // worked. If it did not, it means the roles in the route relation do
     384                // not match the tags of the route members.
     385                if (!segmentChecker.getErrors().isEmpty()) {
     386                        this.errors.addAll(segmentChecker.getErrors());
     387                }
     388
     389                segmentChecker.performFirstStopTest();
     390                segmentChecker.performLastStopTest();
     391                segmentChecker.performStopNotServedTest();
     392
     393                boolean sortingErrorFound = false;
     394                for (TestError error : this.errors) {
     395                        if (error.getCode() == ERROR_CODE_SORTING) {
     396                                sortingErrorFound = true;
     397                                break;
     398                        }
     399                }
     400                if (!sortingErrorFound) {
     401                        segmentChecker.performStopByStopTest();
     402                        segmentChecker.findFixes();
     403                }
     404
     405                for (TestError error : segmentChecker.getErrors()) {
     406                        if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) {
     407                                this.errors.add(error);
     408                        }
     409                }
     410        }
     411
     412        /**
     413         * Method is called after all primitives has been visited, overrides the
     414         * method of the superclass.
     415         */
     416        public void endTest() {
     417               
     418                // modify the error messages for the stop-by-stop test:
     419                SegmentChecker.modifyStopByStopErrorMessages();
     420
     421                // add the stop-by-stop errors with modified messages:
     422                for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) {
     423                        TestError error = entry.getKey().build();
     424                        SegmentChecker.wrongSegments.put(error, entry.getValue());
     425                        this.errors.add(error);
     426                }
     427               
     428                // reset the static collections in SegmentChecker:
     429                SegmentChecker.reset();
     430
     431                super.endTest();
     432
     433        }
     434
     435        /**
     436         * Creates the PTRouteSegments of a route that has been found correct and
     437         * stores them in the list of correct route segments
     438         *
     439         * @param r
     440         *            route relation
     441         */
     442        @SuppressWarnings("unused")
     443        private void storeCorrectRouteSegments(Relation r) {
     444                PTRouteDataManager manager = new PTRouteDataManager(r);
     445                StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays());
     446                if (manager.getPTStops().size() > 1) {
     447                        for (int i = 1; i < manager.getPTStops().size(); i++) {
     448                                PTStop segmentStartStop = manager.getPTStops().get(i - 1);
     449                                PTStop segmentEndStop = manager.getPTStops().get(i);
     450                                Way segmentStartWay = assigner.get(segmentStartStop);
     451                                Way segmentEndWay = assigner.get(segmentEndStop);
     452                                List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay);
     453                                PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r);
     454                                SegmentChecker.addCorrectSegment(routeSegment);
     455                        }
     456                }
     457        }
     458
     459        /**
     460         * Checks if the test error is fixable
     461         */
     462        @Override
     463        public boolean isFixable(TestError testError) {
     464                if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE
     465                                || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING
     466                                || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION
     467                                || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {
     468                        return true;
     469                }
     470
     471                if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) {
     472                        return true;
     473                }
     474
     475                return false;
     476        }
     477
     478        /**
     479         * Fixes the given error
     480         */
     481        @Override
     482        public Command fixError(TestError testError) {
     483
     484                // repaint the relation in the pt_assistant layer:
     485                if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) {
     486                        Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next();
     487                        this.layer.repaint(relationToBeFixed);
     488                }
     489
     490                // reset the last fix:
     491                PTAssistantPlugin.setLastFix(null);
     492
     493                List<Command> commands = new ArrayList<>();
     494
     495                if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) {
     496                        commands.add(WayChecker.fixErrorByZooming(testError));
     497                }
     498
     499                if (testError.getCode() == ERROR_CODE_DIRECTION) {
     500                        commands.add(WayChecker.fixErrorByZooming(testError));
     501
     502                }
     503
     504                if (testError.getCode() == ERROR_CODE_SORTING) {
     505                        commands.add(RouteChecker.fixSortingError(testError));
     506                }
     507
     508                if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION
     509                                || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) {
     510                        commands.add(NodeChecker.fixError(testError));
     511                }
     512
     513                if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) {
     514                        commands.add(SegmentChecker.fixError(testError));
     515                        // make sure the primitives of this testError are selected:
     516                        Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>();
     517                        for (Object obj : testError.getPrimitives()) {
     518                                primitivesToSelect.add((OsmPrimitive) obj);
     519                        }
     520                        SelectCommand selectCommand = new SelectCommand(primitivesToSelect);
     521                        SwingUtilities.invokeLater(new Runnable() {
     522                                @Override
     523                                public void run() {
     524                                        selectCommand.executeCommand();
     525                                }
     526                        });
     527                }
     528
     529                if (commands.isEmpty()) {
     530                        return null;
     531                }
     532
     533                if (commands.size() == 1) {
     534                        return commands.get(0);
     535                }
     536
     537                return new SequenceCommand(tr("Fix error"), commands);
     538        }
     539
     540        /**
     541         * This method is the counterpart of the fixError(TestError testError)
     542         * method. The fixError method is invoked from the core validator (e.g. when
     543         * user presses the "Fix" button in the validator). This method is invoken
     544         * when the fix is initiated from within the plugin (e.g. automated fixes).
     545         */
     546        private void fixErrorFromPlugin(List<TestError> testErrors) {
     547
     548                // run fix task asynchronously
     549                FixTask fixTask = new FixTask(testErrors);
     550
     551                Thread t = new Thread(fixTask);
     552                t.start();
     553                try {
     554                        t.join();
     555                        errors.removeAll(testErrors);
     556
     557                } catch (InterruptedException e) {
     558                        JOptionPane.showMessageDialog(null, "Error occurred during fixing");
     559                }
     560
     561        }
     562
     563        public void addFixVariants(List<List<PTWay>> fixVariants) {
     564                layer.addFixVariants(fixVariants);
     565        }
     566
     567        public void clearFixVariants() {
     568                layer.clearFixVariants();
     569        }
     570
     571        public List<PTWay> getFixVariant(Character c) {
     572                return layer.getFixVariant(c);
     573        }
     574
     575        @SuppressWarnings("unused")
     576        private void performDummyTest(Relation r) {
     577                List<Relation> primitives = new ArrayList<>(1);
     578                primitives.add(r);
     579                Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION);
     580                builder.message(tr("PT: dummy test warning"));
     581                builder.primitives(primitives);
     582                errors.add(builder.build());
     583        }
    588584
    589585}
  • applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java

    r33091 r33108  
    296296                        Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0));
    297297
    298                         // get last added TestErrorBuilder:
    299 
    300298                        if (firstNode == null) {
    301299                                // check if this error has just been reported:
    302                                 if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted.size() == 1
     300                                if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted != null && lastCreatedBuilderHighlighted.size() == 1
    303301                                                && lastCreatedBuilderHighlighted.get(0) == startWay) {
    304302                                        // do nothing, this error has already been reported in
Note: See TracChangeset for help on using the changeset viewer.