wiki:Help/Plugin/Scripting/Python/RCN_Route_Validator

Version 1 (modified by Polyglot, 14 years ago) ( diff )

The script is starting to become presentable

#!/bin/jython
'''
CheckRouteOrNetworkOrCollectionOfRoutes.jy
- Validation of a rcn route, network or collection of networks relation
- Depending on what is selected in JOSM when invoked

This code is released under the GNU General
Public License v2 or later.

The GPL v3 is accessible here:
http://www.gnu.org/licenses/gpl.html

The GPL v2 is accessible here:
http://www.gnu.org/licenses/old-licenses/gpl-2.0.html

It comes with no warranty whatsoever.

This code illustrates how to use Jython (Python in the scripting plugin of JOSM) to:
* loop over all members of a route relation
* find out whether the member is a node, a way or a relation
* add/change properties of a relation
* remove properties of a relation
* add members to a relation
* remove members from a relation
* sort all members backwards

* How to set an element selected

'''
from javax.swing import JOptionPane
from org.openstreetmap.josm import Main
import org.openstreetmap.josm.command as Command
import org.openstreetmap.josm.data.osm.Node as Node
import org.openstreetmap.josm.data.osm.Way as Way
import org.openstreetmap.josm.data.osm.Relation as Relation
import org.openstreetmap.josm.data.osm.TagCollection as TagCollection
import org.openstreetmap.josm.data.osm.DataSet as DataSet
import org.openstreetmap.josm.data.osm.RelationMember as RelationMember
import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask as DownloadRelationMemberTask
import org.openstreetmap.josm.actions.DownloadReferrersAction as DownloadReferrersAction
import org.openstreetmap.josm.actions.AutoScaleAction as AutoScaleAction
import re, time

# comment to disable side effect
sideEffects = {
    'addRouteToNetwork': None,
    'removeNameRefKey_xx-yyAndcreated_by': None, 
    'modifyNoteTo_xx-yy': None,
    'flipOrderOfMembers': None, # such that ways go from lower rcn_ref to higher rcn_ref
    'sortRouteRelations': None,
    'selectObjects': None,
    'zoomToSelection': None,
    #'downloadReferrersForNodes': None, # This will download all ways and relations for nodes with an rcn_ref
    #'downloadReferrersForWays': None, # This will download all relations for ways that have an endnode with an rcn_ref
    'downloadIncompleteMembers': None,
    'createWikiReport': None,
    'createGarminGPX': None,
    #'checkOneWays = False, # not implemented yet
    }

logVerbosity = 10
'''
10: only report problems that need fixing
20: report on collection
30: report on network nodes
40: report on which routes are being checked
50: report everything
'''
def getMapView():
    if Main.main and Main.main.map:
        return Main.main.map.mapView
    else:
        return None

def sortRouteRelation(route, nodesDict, beginAndEndnodes):
    # TODO This can still be improved a lot. Now it aborts at the first sign of probable failure.
    # TODO It sorts the simple cases though (i.e. the ones with no forward/backward roles which actually are continuous)
    nextNode = None
    routeToReturn = Relation(route)
    ##print dir (routeToReturn)
    #routeToReturn.clearOsmId()
    lowestNodeInt = 10000; lowPos = 0
    for nodeTuple in beginAndEndnodes:
        if nodeTuple[0] < lowestNodeInt:
            lowestNodeInt, nextNode = nodeTuple
    if not(nextNode):
        return route
    members=nodesDict[nextNode]
    processedMembers = {}
    #print len(nodesDict)
    #print dir(route)
    while lowPos<route.getMembersCount():
        #print 'in loop', routeToReturn
        if len(members) == 1:
            member = members[0]
        else:
            member = members[1]
            if member in processedMembers: member = members[0]
        processedMembers[member] = True
        way = member.getWay()
        routeToReturn.removeMembersFor(way)
        routeToReturn.addMember(lowPos,member)
        #routeToReturn.setModified(True)
        currentNode = nextNode
        nextNode = way.getNode(way.nodesCount-1).getUniqueId()
        if currentNode == nextNode:
            nextNode = way.getNode(0).getUniqueId()            
        if nextNode in nodesDict:
            members=nodesDict[nextNode]
        else:
            break
        del nodesDict[nextNode]
        #print len(nodesDict)
        if len(nodesDict)<3: break
        lowPos += 1
    #print 'before return', routeToReturn
    return routeToReturn

def checkForContinuity(membersList):
    listIsContinuous = True; prev_endnodes = []
    for member in membersList:
        if member.isWay():
            way = member.getWay()
            if logVerbosity > 50: print dir(way)
            if logVerbosity > 49:
                print way.getKeys()
                print way.get('name')
                print way.nodesCount-1, way
            if way.get('junction') == 'roundabout':
                endnodes = way.getNodes()
            else:
                if way.nodesCount:
                    endnodes = [way.getNode(0), way.getNode(way.nodesCount-1)]
                else:
                    endnodes = []
            foundTheNode = False
            for endnode in endnodes:
                if logVerbosity > 49: print endnode, prev_endnodes
                if endnode in prev_endnodes:
                    foundTheNode = True
            if prev_endnodes and not(foundTheNode):
                listIsContinuous = False
                if logVerbosity > 49:
                    print way
                    print endnodes
                    print prev_endnodes
                break
            prev_endnodes = endnodes
    return listIsContinuous

def checkRCNroute(route):
    if 'removeNameRefKey_xx-yyAndcreated_by' in sideEffects:
        commandsList = []
        reNumberDashNumber = re.compile(r'\d+-\d+')
        newRelation = Relation(route)
        relationChanged = False
        created_by = route.get('created_by')
        if created_by:
            print 'removing created_by'
            newRelation.remove('created_by')
            relationChanged = True
        name = route.get('name')
        if name:
            if reNumberDashNumber.match(name):
                print 'removing name when it is of the form ##-##'
                newRelation.remove('name')
                relationChanged = True
        else:
            name = ''
        ref = route.get('ref')
        if ref:
            if reNumberDashNumber.match(ref):
                print 'removing ref when it is of the form ##-##'
                newRelation.remove('ref')
                relationChanged = True
        else:
            ref = ''
        if relationChanged:
            commandsList.append(Command.ChangeCommand(route, newRelation))
            
            Main.main.undoRedo.add(Command.SequenceCommand("Removing name and/or ref and/or created_by" + name + '/' + ref, commandsList))
            commandsList = []

    fixme = route.get('fixme') == 'incomplete'
    rcn_refs = []; route_relation_names = []; memberslist = []; roleInNetwork = ''
    sameNodeNumberRepeated = False
    allWaysgoingFromLowerToHigher = []; allWaysgoingFromHigherToLower = []; branch = None
    newRelation = Relation(route); commandslist = []; i=0; roundabout = []

    if 'sortRouteRelations' in sideEffects: nodesForSorting = {}; beginAndEndNodes = []
    routeMembers = route.getMembers()
    for member in routeMembers:
        if member.isWay():
            role = member.getRole()
            memberslist.append(member)
            way = member.getWay()
            # print way.get('name')
            wayNodes = way.getNodes()

            notfoundyet = True
            for endnode in wayNodes:
                if 'sortRouteRelations' in sideEffects:
                    endnodeId = endnode.getUniqueId()
                    if not(endnodeId in nodesForSorting):
                        nodesForSorting[endnodeId] = []
                    nodesForSorting[endnodeId].append(member)

                rcn_ref = endnode.get('rcn_ref')
                if rcn_ref:
                    rcn_refAsInt = int(rcn_ref)
                    if 'sortRouteRelations' in sideEffects: beginAndEndNodes.append([rcn_refAsInt, endnodeId])
                    if not(rcn_refAsInt in rcn_refs):
                        rcn_refs.append(rcn_refAsInt)
                    else:
                        sameNodeNumberRepeated = True
                    referrersForNode = endnode.getReferrers(); networkNotFoundForNode = True
                    for referrer in referrersForNode:
                        if referrer.getType() is dummy_relation.getType():
                            if referrer.get('type') in ['network'] and referrer.get('network') in ['rcn']:
                                networkNotFoundForNode = False
                                break
                    if networkNotFoundForNode:
                        # node is not assigned to a network yet
                        Main.main.getCurrentDataSet().setSelected(endnode)
                        AutoScaleAction.zoomToSelection()
                        selectedNode = mv.editLayer.data.getSelected()
                        if 'downloadReferrersForNodes' in sideEffects:
                            print "Downloading referrers for ", endnode.get('rcn_ref'), ' ', wayNodes
                            DownloadReferrersAction.downloadReferrers(mv.editLayer, wayNodes)
                        else:
                            print "Would download referrers for ", endnode.get('rcn_ref'), ' ', wayNodes
                        referrersForNode = endnode.getReferrers()
                    for referrer in referrersForNode:
                        if referrer.getType() is dummy_relation.getType():
                            networkOrRouteType = referrer.get('type') in ['network'] #, 'route']
                            if referrer.get('network')=='rcn' and networkOrRouteType:
                                relname=referrer.get('name')
                                if relname:
                                    route_relation_names.append(relname)
                            elif not(referrer.get('type') in ['route']):
                                route_relation_names.append('Node not assigned to network yet')
                                # FIXME This is still buggy
            # build 2 structures to help check for continuity on ways
            if i==0:
                lastNodesBeforeSplit = [wayNodes]
            if role and role in ['forward', 'backward']:
                if not(branch):
                    print 'wayNodes', wayNodes
                    
                    if wayNodes:
                        if role in ['forward']:
                            lastNodesBeforeSplit = [wayNodes[0]]
                        else:
                            lastNodesBeforeSplit = [wayNodes[-1]]
                    else:
                        return '', True, '|align="right" | way has no nodes||align="right" | {{BrowseRoute|' + str(route.getId()) + '}}||align="right" needs to be downloaded first\n'
                if logVerbosity > 29:
                    print 'lastNodesBeforeSplit', lastNodesBeforeSplit
                    print way.getNodesCount(), 'startnode', wayNodes[0], 'endnode', wayNodes[-1]
                    print 'roundabout', roundabout
                    print wayNodes[-1].get('rcn_ref'),not(member.getUniqueId() == routeMembers[-1].getUniqueId())
                if role in ['forward'] and (wayNodes[-1] in lastNodesBeforeSplit or wayNodes[-1] in roundabout):
                    branch = 'HigherToLower'
                elif role in ['backward'] and wayNodes[0] in lastNodesBeforeSplit:
                    branch = 'HigherToLower'
                    
                elif not(allWaysgoingFromHigherToLower) and wayNodes[-1].get('rcn_ref') and not(member.getUniqueId() == routeMembers[-1].getUniqueId()):
                    # This is for when the route starts forked from a different rcn node (split node situation), we don't want it to kick in for the last member of the route
                    branch = 'HigherToLower'
                elif not(branch == 'HigherToLower'):
                    branch = 'LowerToHigher'
                print branch
                if branch == 'LowerToHigher':
                    allWaysgoingFromLowerToHigher.append(member)
                elif branch == 'HigherToLower':
                    allWaysgoingFromHigherToLower.append(member)
            else:
                branch = None; roundabout = []
                allWaysgoingFromLowerToHigher.append(member)
                allWaysgoingFromHigherToLower.append(member)
            if way.get('junction') == 'roundabout':
                roundabout = way.getNodes()
        i+=1
    #if modified:
        #commandsList.append(Command.ChangeCommand(route, newRelation))
        #Main.main.undoRedo.add(Command.SequenceCommand("Removing way which has no nodes", commandsList))
        #commandsList = []

    continuous_forward = True; continuous_backward = True
    if len(allWaysgoingFromLowerToHigher) > 1:
        continuous_forward = checkForContinuity(allWaysgoingFromLowerToHigher)
        if not(continuous_forward) and not(fixme) and 'sortRouteRelations' in sideEffects:
            sortedRelation = sortRouteRelation(route, nodesForSorting, beginAndEndNodes)

            if logVerbosity>49:
                print route
                print sortedRelation
            commandsList.append(Command.ChangeCommand(route, sortedRelation))
            Main.main.undoRedo.add(Command.SequenceCommand("Sorted route relation", commandsList))            
            allWaysgoingFromLowerToHigher = []; allWaysgoingFromHigherToLower = []

            routeMembers = route.getMembers(); i=0
            for member in routeMembers:
                if member.isWay():
                    role = member.getRole()
                    if i==0:
                        lastNodesBeforeSplit = [wayNodes]
                    if role and role in ['forward', 'backward']:
                        if not(branch):
                            if role in ['forward']:
                                lastNodesBeforeSplit = [wayNodes[0]]
                            else:
                                lastNodesBeforeSplit = [wayNodes[-1]]
                        if logVerbosity > 29:
                            print 'wayNodes', wayNodes
                            print 'lastNodesBeforeSplit', lastNodesBeforeSplit
                            print way.getNodesCount(), 'startnode', wayNodes[0], 'endnode', wayNodes[-1]
                            print 'roundabout', roundabout

                        if role in ['forward'] and (wayNodes[-1] in lastNodesBeforeSplit or wayNodes[-1] in roundabout):
                            branch = 'HigherToLower'
                        elif role in ['backward'] and wayNodes[0] in lastNodesBeforeSplit:
                            branch = 'HigherToLower'
                        elif wayNodes[-1].get('rcn_ref') and not(member.getUniqueId() == routeMembers[-1].getUniqueId()): # not(allWaysgoingFromHigherToLower) and ## this last part is probably not necessary anymore
                            # This is for when the route starts forked from a different rcn node (split node situation), we don't want it to kick in for the last member of the route
                            branch = 'HigherToLower'
                        elif not(branch == 'HigherToLower'):
                            branch = 'LowerToHigher'
                        print branch
                        if branch == 'LowerToHigher':
                            allWaysgoingFromLowerToHigher.append(member)
                        elif branch == 'HigherToLower':
                            allWaysgoingFromHigherToLower.append(member)
                    else:
                        branch = None; roundabout = []
                        allWaysgoingFromLowerToHigher.append(member)
                        allWaysgoingFromHigherToLower.append(member)
                    if way.get('junction') == 'roundabout':
                        roundabout = way.getNodes()
                i+=1
            continuous_forward = checkForContinuity(allWaysgoingFromLowerToHigher)
        #else:
    else:
        # a route relation with only one way member
        continuous_forward = True
    if len(allWaysgoingFromHigherToLower) > 1:
        continuous_backward = checkForContinuity(reversed(allWaysgoingFromHigherToLower))
    else:
        # a route relation with only one way member
        continuous_backward = True

    # Drawing conclusions about rcn_refs
    if logVerbosity > 39: print rcn_refs
    if sameNodeNumberRepeated:
        rcn_refs.append(rcn_refs[0])
    newNote = note = repr(rcn_refs)
    sortedRelation = route
    if len(rcn_refs) > 1:
        #newRelation = Relation(route)
        relationChanged = False

        if rcn_refs[0] > rcn_refs[1]:
            rcn_refs.sort()
            if len(memberslist)>1 and 'flipOrderOfMembers' in sideEffects:
                for member in reversed(memberslist):
                    sortedRelation.addMember( sortedRelation.getMembersCount(), member)
                    sortedRelation.removeMember (0)
                commandsList.append(Command.ChangeCommand(route, sortedRelation))
                Main.main.undoRedo.add(Command.SequenceCommand("Flipping order of members", commandsList))
                commandsList = []
        note = route.get('note')
        newNote = str(rcn_refs[0]).zfill(2) + '-' + str(rcn_refs[1]).zfill(2)
        #print note, newNote
        if 'modifyNoteTo_xx-yy' in sideEffects:
            if not(note) or note != newNote:
                if not(note): note = 'nothing'
                newRelation.put('note', newNote)
                relationChanged = True
                commandsList.append(Command.ChangeCommand(route, newRelation))
            
                Main.main.undoRedo.add(Command.SequenceCommand("Changing note from " + note + ' to ' + newNote, commandsList))
                if logVerbosity > 9: print 'Flipping members order for ', note
                commandsList = []

        if len(route_relation_names) > 1 and route_relation_names[0] != route_relation_names[1]:
            # print 'This is probably a CONNECTION to another network'
            if logVerbosity > 9: print route_relation_names
            roleInNetwork = 'connection'
    else:
        print 'less than 2 end nodes with rcn_ref found'
    if fixme and not(continuous_forward or continuous_backward):
        if logVerbosity > 1: print 'FIXME flag is INCOMPLETE'
    if continuous_forward:
        wikiCF = 'align="right" | continuous'
        if logVerbosity > 29: print 'route is continous in the forward direction'
    else:
        wikiCF = 'align="right" style="color:red" | NOT continuous'
        if logVerbosity > 9: print 'route ',newNote,' is NOT CONTINUOUS in the forward direction'
        if logVerbosity > 49: print allWaysgoingFromLowerToHigher
    if continuous_backward:
        wikiCB = 'align="right" | continuous'
        if logVerbosity > 29: print 'route is continous in the backward direction'
    else:
        wikiCB = 'align="right" style="color:red" | NOT continuous'
        if logVerbosity > 9: print 'route ',newNote,' is NOT CONTINUOUS in the backward direction'
        if logVerbosity > 49: print allWaysgoingFromHigherToLower
    print
    if fixme:
        wikiFM = 'style="color:red" | fixme' 
    else:
        wikiFM = ' | '
    if fixme or not(continuous_forward) or not(continuous_backward):
        problem = True
    else:
        problem = False
    return roleInNetwork, problem, '|align="right" | ' + note + '||align="right" | {{BrowseRoute|' + str(route.getId()) + '}}||align="right" ' + wikiFM + ' ||' + wikiCF + ' ||' + wikiCB + '\n'

def checkNetwork(network):
    name = network.get('name')
    if logVerbosity>19:
        print '********************************************'
        print name
        print '********************************************'
    if 'createWikiReport' in sideEffects:
        wikiReportOnNodes = ('{| class="wikitable" align="left" style="margin:0 0 2em 2em;"\n|-\n|+' + name +
                             '\n|-\n!style="width:2.5em" | Node\n!Link\n! # Roads\n! # Relations\n|-\n')
        wikiReportOnRelations = ('{| class="wikitable" align="left" style="margin:0 0 2em 2em;"\n|-\n|+' + name +
                                 '\n|-\n!style="width:2.5em" | note\n!link\n!fixme\n! forward\n! backward\n|-\n')
    i=1
    for networkMember in network.getMembers():
        if networkMember.isRelation():
            routeRelation = networkMember.getRelation()
            if routeRelation.hasIncompleteMembers():
                if 'downloadIncompleteMembers' in sideEffects:
                    print 'Downloading incomplete members for', routeRelation.get('note')
                    DownloadRelationMemberTask.run(DownloadRelationMemberTask(routeRelation, routeRelation.getIncompleteMembers(), mv.editLayer ))
                    continue
                else:
                    JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the route relations first')
                    break
            roleFromRouteCheck, problemReported, wikiReport = checkRCNroute(routeRelation)
            if problemReported and 'createWikiReport' in sideEffects:
                wikiReportOnRelations += wikiReport + '\n|-\n'
            role = networkMember.getRole()
            if logVerbosity > 29 and role != roleFromRouteCheck:
                print
                print 'Role in network is ', role
                print 'Maybe this should be: ', roleFromRouteCheck
        if networkMember.isNode():
            node = networkMember.getNode()
            rcn_ref = node.get('rcn_ref')
            expected_rcn_route_relations = node.get('expected_rcn_route_relations')
            if expected_rcn_route_relations:
                expected_rcn_route_relations = int(expected_rcn_route_relations)
            else:
                expected_rcn_route_relations = 3
            if rcn_ref:
                if logVerbosity > 39: print rcn_ref
                referrersForNode = node.getReferrers()
                networkNotFoundForNode = True
                for referrer in referrersForNode:
                    if referrer.getType() is dummy_relation.getType():
                        if referrer.get('type') in ['network'] and referrer.get('network') in ['rcn']:
                            networkNotFoundForNode = False
                            break
                if networkNotFoundForNode and 'downloadReferrersNodes' in sideEffects:
                    Main.main.getCurrentDataSet().setSelected(node)
                    AutoScaleAction.zoomToSelection()
                    selectedNode = mv.editLayer.data.getSelected()
                    print 'Downloading referrers for ', selectedNode.get('rcn_ref')
                    DownloadReferrersAction.downloadReferrers(mv.editLayer, selectedNode)
                    referrersForNode = node.getReferrers()

                rcnNetworkCountForNode = roads = 0
                for referrer in referrersForNode:
                    if referrer.getType() is dummy_way.getType():
                        if referrer.get('highway'): roads += 1
                        referrersForWay = referrer.getReferrers()
                        if len(referrersForWay) < 1 and 'downloadReferrersForWays' in sideEffects:
                            Main.main.getCurrentDataSet().setSelected(referrer)
                            AutoScaleAction.zoomToSelection()
                            selectedWay = mv.editLayer.data.getSelected()
                            print 'Downloading referrers for ', referrer.get('name') , ' ', rcn_ref
                            DownloadReferrersAction.downloadReferrers(mv.editLayer, selectedWay)
                            referrersForWay = referrer.getReferrers()
                        for wayReferrer in referrersForWay:
                            if wayReferrer.getType() is dummy_relation.getType():
                                aRelation = wayReferrer
                                if aRelation.get('type') == 'route' and aRelation.get('network') == 'rcn': 
                                    rcnNetworkCountForNode+=1
                                networkMembersList = []
                                for subMember in network.getMembers():
                                    if subMember.isRelation():
                                        routeRelation = subMember.getRelation()
                                        networkMembersList.append(routeRelation.getUniqueId())
                                routeId = aRelation.getUniqueId()
                                if not(routeId in networkMembersList):
                                    if aRelation.get('network') == 'rcn':
                                        roleFromRouteCheck, problemReported, wikiReport = checkRCNroute(aRelation)
                                        if problemReported and 'createWikiReport' in sideEffects:
                                            wikiReportOnRelations += wikiReport + '\n|-\n'
                                        if 'addRouteToNetwork' in sideEffects:
                                            newRelation = Relation(network)
                                            newmember = RelationMember(roleFromRouteCheck, aRelation)
                                            if logVerbosity > 9: print newRelation.getMembersCount(), ' ',i, ' ', newmember
                                            newRelation.addMember( i, newmember)
                                            commandsList = []
                                            commandsList.append(Command.ChangeCommand(network, newRelation))
                                            note = aRelation.get('note')
                                            if not(note):
                                                note = ''
                                            Main.main.undoRedo.add(Command.SequenceCommand("Adding " + note + " to network", commandsList))
                                            commandsList = []
                                            if logVerbosity > 9: print 'Added newly found RCN route relation to network: ', note
                                            i+=1
                if rcnNetworkCountForNode < expected_rcn_route_relations:
                    if logVerbosity > 9: print 'Node ', rcn_ref, ' only has ', rcnNetworkCountForNode, ' rcn routes connected to it'
                    if 'createWikiReport' in sideEffects: wikiReportOnNodes += '|align="right" | ' + rcn_ref + '||align="right" | {{Node|' + str(node.getId()) + '}}||align="right" |' + str(roads) + ' ||align="right" style="color:red" | ' + str(rcnNetworkCountForNode) + '\n|-\n'

        i+=1
    if logVerbosity > 19: print
    if 'createWikiReport' in sideEffects:
        wikiReportOnNodes += ('|-\n|}\n')
        wikiReportOnRelations += ('|-\n|}\n<br style="clear:left;" />\n')
        fh = open('C:/wikiReport.txt', 'a')
        fh.write(wikiReportOnNodes)
        fh.write(wikiReportOnRelations)
        fh.close()


dummy_way = Way()
dummy_relation = Relation()

mv = getMapView()
if mv and mv.editLayer and mv.editLayer.data:
    if 'createWikiReport' in sideEffects:
        fh = open('C:/wikiReport.txt', 'w')
        fh.close()
    selectedRelations = mv.editLayer.data.getSelectedRelations()

    if not(selectedRelations):
        JOptionPane.showMessageDialog(Main.parent, "Please select a route, network or collection relation")
    else:
        for relation in selectedRelations:
            if logVerbosity> 49: print relation
            if relation.hasIncompleteMembers():
                if 'downloadIncompleteMembers' in sideEffects:
                    print 'Downloading referrers for ', str(relation.get('name')), ' ', str(relation.get('note'))
                    DownloadRelationMemberTask.run(DownloadRelationMemberTask(relation, relation.getIncompleteMembers(), mv.editLayer ))
                    continue
                else:
                    JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the relations first')
                    break
            if relation.get('network') == 'rcn':
                relationType = relation.get('type')
                if relationType == 'route':
                    checkRCNroute(relation)
                elif relationType == 'network':
                    checkNetwork(relation)
                elif relationType == 'collection':
                    for collectionMember in relation.getMembers():
                        if collectionMember.isRelation():
                            networkRelation = collectionMember.getRelation()
                            if networkRelation.hasIncompleteMembers():
                                if 'downloadIncompleteMembers' in sideEffects:
                                    print 'Downloading referrers for ', relation.get('name')
                                    DownloadRelationMemberTask.run(DownloadRelationMemberTask(networkRelation, networkRelation.getIncompleteMembers(), mv.editLayer ))
                                    continue
                                else:
                                    JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the network relations first')
                                    break
                            checkNetwork(networkRelation)

Note: See TracWiki for help on using the wiki.