예제 #1
0
파일: forest.py 프로젝트: silpol/tryton-bef
    def situation_map_gen(cls, records):
        """Render the situation map"""
        CadPlot = Pool().get('cadastre.parcelle')
        Plot = Pool().get('forest.plot')
        for record in records:
            cad_plots = [plot.geom for plot in record.cad_plots]
            cad_plots, envelope, cad_area = get_as_epsg4326(cad_plots)
            plots = [plot.geom for plot in record.plots]
            plots, plot_bbox, _plots_area = get_as_epsg4326(plots)

            if envelope is None:
                continue

            # Compute the envelope
            if plot_bbox is not None:
                envelope = envelope_union(envelope, plot_bbox)

            # Include the geometry of the town in the bbox of the map
            if record.address is not None and record.address.my_city is not None:
                # Include the town from the address in the bbox
                town_geo = osr_geo_from_field(record.address.my_city.contour)

                dst = osr.SpatialReference()
                dst.SetWellKnownGeogCS("EPSG:4326")
                town_geo.TransformTo(dst)
                envelope = envelope_union(envelope, town_geo.GetEnvelope())

            # Map title
            title = u'Plan de situation\n'
            title += u'Propriétaire: %s\n' % record.owner.name
            if record.address is not None \
                    and record.address.city is not None \
                    and record.address.my_city is not None:
                city = record.address.city
                dep = record.address.my_city.subdivision.parent.code.split('-')[1]
                title += u'Commune: %s (%s)\n' % (city, dep)
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(cad_area)
            title += date.today().strftime('%02d/%02m/%Y')

            m = MapRender(1024, 768, envelope, True)
            m.add_bg()
            for plot in cad_plots:
                m.plot_geom(plot, None, u'Bois de La Forêt', color=CadPlot.COLOR, bgcolor=CadPlot.BGCOLOR)
            for plot in plots:
                m.plot_geom(plot, None, u'Parcelle forestière', linestyle='--', color=Plot.COLOR, bgcolor=Plot.BGCOLOR)

            data_nl = m.render()
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {
                'situation_map': buffer(data),
                'situation_map_nl': buffer(data_nl),
            })
예제 #2
0
    def generate(cls, records):
        for record in records:
            if record.address is None:
                continue

            town, envelope, area = get_as_epsg4326([record.address.my_city.contour])
            
            # Calcule de la bbox contenant tout les points
            _envelope = None
            for points in cls.search([]):
                _points, envelope, _area = get_as_epsg4326([points.geom])
                if envelope is None:
                    continue
                _envelope = envelope_union(envelope, _envelope)

            # Léger dézoom pour afficher correctement les points qui touchent la bbox
            envelope = [
                _envelope[0] - 0.001,
                _envelope[1] + 0.001,
                _envelope[2] - 0.001,
                _envelope[3] + 0.001,
            ]
            
            m = MapRender(640, 480, envelope, True)
            m.add_bg()
            for entry in cls.search([]):
                points, _envelope, _area = get_as_epsg4326([entry.geom])
                if len(points) == 0:
                    continue
                if record == entry:
                    m.plot_geom(points[0], None, None, color=cls.COLOR, bgcolor=cls.BGCOLOR)
                else:
                    m.plot_geom(points[0], None, None, color=(0, 0, 1, 1), bgcolor=cls.BGCOLOR)
            data = m.render()
            cls.write([record], {'image_map': buffer(data)})
예제 #3
0
파일: site.py 프로젝트: silpol/tryton-bef
    def situation_map_gen(cls, records):
        """Render the situation map"""        
        for record in records:
            # Récupère l'étendu de la zone de travaux
            areas, _envelope, _area = get_as_epsg4326([record.geom])
            
            # Léger dézoom pour afficher correctement les points qui touchent la bbox
            envelope = [
                _envelope[0] - 0.001,
                _envelope[1] + 0.001,
                _envelope[2] - 0.001,
                _envelope[3] + 0.001,
            ]  

            if envelope is None:
                continue
                   
            # Include the geometry of the town in the bbox of the map
            if record.commune is not None and record.commune.name is not None:
                # Include the town from the commune in the bbox
                town_geo = osr_geo_from_field(record.commune.contour)

                dst = osr.SpatialReference()
                dst.SetWellKnownGeogCS("EPSG:4326")
                town_geo.TransformTo(dst)
                envelope = envelope_union(envelope, town_geo.GetEnvelope())

            # Map title
            title = u'Plan de situation communal\n'
            title += u'Propriétaire: %s\n' % record.owner.name
            if record.commune is not None \
                    and record.commune.name is not None \
                    and record.commune.name is not None:
                city = record.commune.name
                dep = record.commune.subdivision.parent.code.split('-')[1]
                title += u'Commune: %s (%s)\n' % (city, dep)
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(_area)
            title += date.today().strftime('%02d/%02m/%Y')

            m = MapRender(1024, 768, envelope, True)
            # Ajoute le fond de carte
            m.add_bg()                     

            # Ajoute la zone de chantier
            m.plot_geom(areas[0], None, u'Site', color=cls.COLOR, bgcolor=cls.BGCOLOR) 

            data_nl = m.render()
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {
                'situation_map': buffer(data),
            })
예제 #4
0
파일: forest.py 프로젝트: silpol/tryton-bef
    def situation_closeup_map_gen(cls, records):
        """Render the situation map closeup"""
        CadPlot = Pool().get('cadastre.parcelle')
        Plot = Pool().get('forest.plot')
        for record in records:
            cad_plots = [plot.geom for plot in record.cad_plots]
            cad_plots, envelope, cad_area = get_as_epsg4326(cad_plots)
            plots = [plot.geom for plot in record.plots]
            plots, plot_bbox, _plots_area = get_as_epsg4326(plots)

            if envelope is None:
                continue

            # Compute the envelope
            if plot_bbox is not None:
                envelope = envelope_union(envelope, plot_bbox)

            # Map title
            title = u'Plan de situation\n'
            title += u'Propriétaire: %s\n' % record.owner.name
            if record.address is not None \
                    and record.address.city is not None \
                    and record.address.my_city is not None:
                city = record.address.city
                dep = record.address.my_city.subdivision.parent.code.split('-')[1]
                title += u'Commune: %s (%s)\n' % (city, dep)
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(cad_area)
            title += date.today().strftime('%02d/%02m/%Y')

            m = MapRender(1024, 768, envelope, True)
            m.add_bg()
            cls._plot_misc_areas(m, record, False)
            for plot in cad_plots:
                m.plot_geom(plot, None, u'Bois de La Forêt', color=CadPlot.COLOR, bgcolor=CadPlot.BGCOLOR)
            for plot, rec in zip(plots, record.plots):
                m.plot_geom(plot, rec.short_name, None, linestyle='--', color=Plot.COLOR, bgcolor=Plot.BGCOLOR)

            cls._plot_misc_points(m, record, False)
            data_nl = m.render()
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {
                'situation_closeup_map': buffer(data),
                'situation_closeup_map_nl': buffer(data_nl),
            })
예제 #5
0
파일: track.py 프로젝트: silpol/tryton-bef
    def get_image(self, ids):
        if self.forest is None:
            return buffer("")

        MiscObj = Pool().get(self.__name__)
        CadPlot = Pool().get("forest.cad_plot")
        objs = MiscObj.search([("forest", "=", self.forest.id)])
        misc_obj, envelope, area = get_as_epsg4326([obj.geom for obj in objs])

        if misc_obj == []:
            return buffer("")

        cad_plots = [plot.geom for plot in self.forest.cad_plots]
        if cad_plots != []:
            cad_plots, cad_bbox, cad_area = get_as_epsg4326(cad_plots)

            envelope = envelope_union(envelope, cad_bbox)
            envelope = bbox_aspect(envelope, 640, 480)

        m = MapRender(640, 480, envelope)
        for plot in cad_plots:
            m.plot_geom(plot, None, None, color=CadPlot.COLOR, bgcolor=CadPlot.BGCOLOR)
        m.plot_geom(get_as_epsg4326([self.geom])[0][0], None, None, color=self.COLOR, bgcolor=self.BGCOLOR)
        return buffer(m.render())
예제 #6
0
파일: forest.py 프로젝트: silpol/tryton-bef
    def tracks_map_gen(cls, records):
        """Render the tracks map"""
        Tracks = Pool().get('forest.track')
        CadPlot = Pool().get('cadastre.parcelle')
        Plot = Pool().get('forest.plot')
        for record in records:
            cad_plots = [plot.geom for plot in record.cad_plots]
            cad_plots, envelope, cad_area = get_as_epsg4326(cad_plots)
            plots = [plot.geom for plot in record.plots]
            plots, plot_bbox, _plots_area = get_as_epsg4326(plots)
            tracks = [track.geom for track in record.tracks]
            tracks, _tracks_bbox, _tracks_area = get_as_epsg4326(tracks)

            if envelope is None:
                continue

            # Compute the envelope
            if plot_bbox is not None:
                envelope = envelope_union(envelope, plot_bbox)

            # Map title
            title = u'Carte de la desserte\n'
            title += u'Propriétaire: %s\n' % record.owner.name
            if record.address is not None \
                    and record.address.city is not None \
                    and record.address.my_city is not None:
                city = record.address.city
                dep = record.address.my_city.subdivision.parent.code.split('-')[1]
                title += u'Commune: %s (%s)\n' % (city, dep)
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(cad_area)
            title += date.today().strftime('%02d/%02m/%Y')

            # Cadastral plots
            m = MapRender(1024, 768, envelope, True)
            for plot, rec in zip(cad_plots, record.cad_plots):
                m.plot_geom(plot, None, None, color=CadPlot.COLOR)
            cls._plot_misc_areas(m, record)
              
            # Forest plots
            for plot, rec in zip(plots, record.plots):
                m.plot_geom(plot, rec.short_name, u'Parcelle forestière', linestyle='--', color=Plot.COLOR, bgcolor=Plot.BGCOLOR)

            # Track plots
            # Legend Track
            #gris            
            colgris = (0, 0, 0, 0.3)
            #rouge            
            colred = (1, 0, 0, 1)
            #jaune            
            colyel = (1, 1, 0, 1)
            #blanc
            colwhi = (0, 0, 0, 1)
            m.add_legend(str('Piste'), '-', color=colwhi, bgstyle='-', bgcolor=colwhi)
            m.add_legend(str('Route en terrain naturel'), '-', color=colyel, bgstyle='-', bgcolor=colyel)
            m.add_legend(str('Route empierrée'), '-', color=colred, bgstyle='-', bgcolor=colred)
            m.add_legend(str('Route goudronnée'), '-', color=colgris, bgstyle='-', bgcolor=colgris)               
            
            # Track
            for track, rec in zip(tracks, record.tracks):
                if rec.typo == 'rgou':                    
                    m.plot_geom(track, rec.name, None, color=colgris, bgcolor=colgris)
                elif rec.typo == 'remp':                                        
                    m.plot_geom(track, rec.name, None, color=colred, bgcolor=colred)
                elif rec.typo == 'rternat':                    
                    m.plot_geom(track, rec.name, None, color=colyel, bgcolor=colyel)
                else:
                    m.plot_geom(track, rec.name, None, color=colwhi, bgcolor=colwhi)

            cls._plot_misc_points(m, record)
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {'tracks_map': buffer(data)})
예제 #7
0
파일: forest.py 프로젝트: silpol/tryton-bef
    def varieties_map_gen(cls, records):
        """Render the varieties map"""
        Varieties = Pool().get('forest.variety')
        CadPlot = Pool().get('cadastre.parcelle')
        Plot = Pool().get('forest.plot')
        for record in records:
            cad_plots = [plot.geom for plot in record.cad_plots]
            cad_plots, envelope, cad_area = get_as_epsg4326(cad_plots)
            plots = [plot.geom for plot in record.plots]
            plots, plot_bbox, _plots_area = get_as_epsg4326(plots)
            varieties = [variety.geom for variety in record.varieties]
            varieties, _varieties_bbox, _varieties_area = get_as_epsg4326(varieties)

            if envelope is None:
                continue

            # Compute the envelope
            if plot_bbox is not None:
                envelope = envelope_union(envelope, plot_bbox)

            # Map title
            title = u'Carte des peuplements\n'
            title += u'Propriétaire: %s\n' % record.owner.name
            if record.address is not None \
                    and record.address.city is not None \
                    and record.address.my_city is not None:
                city = record.address.city
                dep = record.address.my_city.subdivision.parent.code.split('-')[1]
                title += u'Commune: %s (%s)\n' % (city, dep)
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(cad_area)
            title += date.today().strftime('%02d/%02m/%Y')

            # Cadastral plots
            m = MapRender(1024, 768, envelope, True)
            for plot, rec in zip(cad_plots, record.cad_plots):
                m.plot_geom(plot, None, None, color=CadPlot.COLOR)
            cls._plot_misc_areas(m, record)

            # Stand plots
            # Legend Stand
            for stand, rec in zip(varieties, record.varieties):                
                if rec.stand is None:
                    bgcolor = (0, 0, 0, 0)
                else:
                    r = float(rec.stand.r)/float(255)
                    g = float(rec.stand.g)/float(255)
                    b = float(rec.stand.b)/float(255)
                    bgcolor = (r, g, b, 1)
                    m.add_legend(rec.stand.name, '-', color=(0, 0, 0, 1), bgstyle='-', bgcolor=bgcolor)
            # Stand
            for stand, rec in zip(varieties, record.varieties):
                if rec.stand is None:
                    bgcolor = (0, 0, 0, 0)
                else:
                    r = float(rec.stand.r)/float(255)
                    g = float(rec.stand.g)/float(255)
                    b = float(rec.stand.b)/float(255)
                    bgcolor = (r, g, b, 1)                    
                m.plot_geom(stand, None, None, color=(0, 0, 0, 1), bgcolor=bgcolor)

            # Legend Dom Species 1
            for stand, rec in zip(varieties, record.varieties):                
                if rec.domspecies1 is None:
                    bgcolor = (0, 0, 0, 0)                    
                else:
                    r = float(rec.domspecies1.r)/float(255)
                    g = float(rec.domspecies1.g)/float(255)
                    b = float(rec.domspecies1.b)/float(255)
                    bgcolor = (r, g, b, 1)                    
                    m.add_legend(rec.domspecies1.name, '-', color=(0, 0, 0, 1), bgstyle = None, bgcolor=bgcolor)
            # Dom Species 1
            for stand, rec in zip(varieties, record.varieties):
                if rec.domspecies1 is None:
                    bgcolor = (0, 0, 0, 0)
                    bgstyle = '.'
                else:
                    r = float(rec.domspecies1.r)/float(255)
                    g = float(rec.domspecies1.g)/float(255)
                    b = float(rec.domspecies1.b)/float(255)
                    bgcolor = (r, g, b, 1)
                    bgstyle = rec.domspecies1.form
                m.plot_geom(stand, None, None, color=(0, 0, 0, 1), bgstyle=bgstyle, bgcolor=bgcolor)

            # Forest plots
            for plot, rec in zip(plots, record.plots):
                m.plot_geom(plot, rec.short_name, u'Parcelle forestière', linestyle='--', color=Plot.COLOR, bgcolor=Plot.BGCOLOR)

            cls._plot_misc_points(m, record)
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {'varieties_map': buffer(data)})
예제 #8
0
    def situation_map_gen(cls, records):
        """Render the situation map"""        
        for record in records:
            _envelope = None                
            # Récupère les géométries de la zone d'information
            aires = [aire.geom for aire in record.pres_obj_poly]
            aires, _aires_bbox, _aires_area = get_as_epsg4326(aires)
            if _aires_bbox is None:
                _envelope = _envelope                    
            else:
                _envelope = envelope_union(_aires_bbox, _envelope)

            lignes = [ligne.geom for ligne in record.pres_obj_line]
            lignes, _lignes_bbox, _lignes_area = get_as_epsg4326(lignes)
            if _lignes_bbox is None:
                _envelope = _envelope              
            else:
                _envelope = envelope_union(_lignes_bbox, _envelope)

            points = [point.geom for point in record.pres_obj_point]
            points, _points_bbox, _points_area = get_as_epsg4326(points)
            if _points_bbox is None:
                _envelope = _envelope            
            else:
                _envelope = envelope_union(_points_bbox, _envelope)            

            # Léger dézoom pour afficher correctement les points qui touchent la bbox
            envelope = [
                _envelope[0] - 0.001,
                _envelope[1] + 0.001,
                _envelope[2] - 0.001,
                _envelope[3] + 0.001,
            ]

            # Map title
            title = u'Plan de situation\n'            
            title += u'Surface: %02i ha %02i a %02i ca\n\nLe ' % cls._area_to_a(_aires_area)
            title += date.today().strftime('%02d/%02m/%Y')

            m = MapRender(1024, 768, envelope, True)
            # Ajoute le fond de carte
            m.add_bg()                     

             # Ajoute les polygones
            for aire, rec in zip(aires, record.pres_obj_poly):
                m.plot_geom(aire, rec.name, u'Zones', color=(1, 1, 1, 1), bgcolor=(0, 0, 1, 0.2))

            # Ajoute les polylignes
            for ligne, rec in zip(lignes, record.pres_obj_line):
                m.plot_geom(ligne, rec.name, None, color=(1, 1, 1, 1), bgcolor=(1, 1, 1, 1))

            # Ajoute les points
            for point, rec in zip(points, record.pres_obj_point):
                m.plot_geom(point, rec.name, None, color=(1, 1, 1, 1), bgcolor=(1, 1, 1, 1))

            data_nl = m.render()
            m.plot_legend()
            m.plot_compass()
            m.plot_scaling()
            cls._plot_logo(m)
            m.plot_title(title)
            data = m.render()
            cls.write([record], {
                'situation_map': buffer(data),
            })
예제 #9
0
파일: qgis.py 프로젝트: silpol/tryton-bef
    def parse(cls, report, records, data, localcontext):
        """Create QGis project file based on the selected record:
            the fields referenced in the model FIELDS variable will each have
            a separate layer in the renderd file.
        """
        User = Pool().get('res.user')
        Translation = Pool().get('ir.translation')
        filename = os.path.join(os.path.dirname(__file__), 'qgis.qgs')
        report = RelatorioReport(filename, 'text/plain', ReportFactory(), MIMETemplateLoader())

        QGisConf = Pool().get('qgis.conf')
        conf = QGisConf.search([])
        if len(conf) != 0:
            version = conf[0].version
        else:
            version = '1.9.0-Master'

        legend = OrderedDict()
        if cls.FIELDS is None:
            layers, bbox, srid = cls.get_layer(records, records[0].__name__)

            for layer in layers:
                legend[layer['title']] = layer
        else:
            layers = []
            bbox = None
            Model = Pool().get(records[0].__name__)
            for field, val in cls.FIELDS.iteritems():
                if val is None:
                    fields = [field]
                else:
                    fields = val.keys()
                sublayers = []
                for _field in fields:
                    recs = getattr(records[0], _field)
                    relation = getattr(Model, _field).model_name
                    _layers, _bbox, srid = cls.get_layer(recs, relation)
                    if _bbox is not None:
                        bbox = envelope_union(_bbox, bbox)
                    sublayers += _layers

                # Remove sublayers that are already added
                _sublayers = []
                for layer in sublayers:
                    if layer['model'] in [_layer['model'] for _layer in layers]:
                        continue
                    _sublayers.append(layer)
                sublayers = _sublayers
                layers += sublayers

                if val is None:
                    for layer in sublayers:
                        legend[layer['title']] = layer
                else:
                    if field not in legend:
                        legend[field] = OrderedDict()
                    for layer in sublayers:
                        legend[field][layer['title']] = layer

        if bbox is None:
            bbox = [
                -357823.2365,
                6037008.6939,
                1313632.3628,
                7230727.3772
            ]

        WfsConf = Pool().get('wfs.conf')
        wfs_url = WfsConf.get_url()

        localcontext.update({
            'data': data,
            'user': User(Transaction().user),
            'formatLang': cls.format_lang,
            'StringIO': StringIO.StringIO,
            'time': time,
            'datetime': datetime,
            'context': Transaction().context,
            'qgis_version': version,
            'wfs_url': wfs_url,
            'bbox': bbox,
            'srid': srid,
            'layers': layers,
            'legend': legend,
        })

        translate = TranslateFactory(cls.__name__, Transaction().language, Translation)
        localcontext['setLang'] = lambda language: translate.set_language(language)
        translator = Translator(lambda text: translate(text))
        report.filters.insert(0, translator)

        localcontext = dict(map(lambda x: (str(x[0]), x[1]), localcontext.iteritems()))

        #Test compatibility with old relatorio version <= 0.3.0
        if len(inspect.getargspec(report.__call__)[0]) == 2:
            data = report(records, **localcontext).render().getvalue()
        else:
            localcontext['objects'] = records  # XXX to remove
            localcontext['records'] = records
            data = report(**localcontext).render()
            if hasattr(data, 'getvalue'):
                data = data.getvalue()
        return ('qgs', data)
예제 #10
0
파일: qgis.py 프로젝트: silpol/tryton-bef
    def get_layer(cls, records, model_name):
        """Return parameters for the model @model_name@.
        If some records of the model are not contained in @records@,
        then those record are returned in a separate layer that will is displayed
        as "Unselected" values.
        """
        # Look for a geometric field
        Field = Pool().get('ir.model.field')
        Model = Pool().get('ir.model')
        RecordModel = Pool().get(model_name)

        geo_field_name = ''
        geo_field = None
        m2o_fields = []
        for attr_name in dir(RecordModel):
            if attr_name in TRYTON_FIELDS:
                continue
            attr = getattr(RecordModel, attr_name)
            if isinstance(attr, fields.Many2One):
                m2o_fields.append(attr)
            if isinstance(attr, fields.Geometry):
                geo_field = attr
                geo_field_name = attr_name

        bbox = None
        unselected = set()
        srid = getattr(RecordModel, geo_field_name).srid

        for record in records:
            geo_value = getattr(record, geo_field_name)
            if geo_value is not None:
                geo = osr_geo_from_field(geo_value)
                bbox = envelope_union(geo.GetEnvelope(), bbox)

        # Look for unselected related records
        for m2o_field in m2o_fields:
            # Find the corresponding one2many field in the parent
            parent_model = Model.search([('model', '=', m2o_field.model_name)], limit=1)[0]
            Parent = Pool().get(m2o_field.model_name)
            o2mfield = Field.search([('ttype', '=', 'one2many'),
                                     ('model', '=', parent_model.id)])

            for o2m in o2mfield:
                parent_field = getattr(Parent, o2m.name)
                if parent_field.model_name == model_name and m2o_field.name == parent_field.field:
                    break
            else:
                continue

            for record in records:
                parent_record = getattr(record, m2o_field.name)
                for child in getattr(parent_record, parent_field.name):
                    if child in records:
                        continue
                    unselected.add(child.id)
            break

        layers = []
        layers.append({
            'model': model_name,
            'title': cls.TITLES.get(model_name, RecordModel.__doc__),
            'layerid': 'tryton_%s' % model_name.replace('.', '_'),
            'geo': True,
            'srid': srid,
            'filter': get_wfs_id_filter(sorted([record.id for record in records])),
            'color': cls._qgis_color(RecordModel.BGCOLOR),
            'color_border': cls._qgis_color(RecordModel.COLOR),
            'edittypes': {'id': {'type': QGIS_WIDGET_HIDDEN}},
            'geo_type': TRYTON_TO_QGIS[geo_field._type],
            'unfolded': 'true',
            'aliases': cls._get_aliases(model_name),
        })

        if len(unselected) != 0:
            layers.append({
                'model': model_name,
                'title': cls.TITLES.get(model_name, RecordModel.__doc__) + ' (unselected)',
                'layerid': 'tryton_unselected_%s' % model_name.replace('.', '_'),
                'geo': True,
                'srid': srid,
                'filter': get_wfs_id_filter(sorted(unselected)),
                'color': '255,255,255,0',
                'color_border': cls._qgis_color(RecordModel.BGCOLOR),
                'edittypes': {'id': {'type': QGIS_WIDGET_HIDDEN}},
                'geo_type': TRYTON_TO_QGIS[geo_field._type],
                'unfolded': 'false',
                'aliases': cls._get_aliases(model_name),
            })
        base_layers = layers

        deps_models = set()
        Record = Pool().get(model_name)
        symbols = []
        # Add dependency tables
        for m2o_field in m2o_fields:
            # Find the corresponding one2many field in the parent
            other_model_name = getattr(Record, m2o_field.name).model_name
            OtherModel = Pool().get(other_model_name)
            other_model = Model.search([('model', '=', other_model_name)], limit=1)[0]

            if OtherModel in deps_models:
                continue
            deps_models.add(OtherModel)

            layer_id = 'tryton_%s' % other_model.model.replace('.', '_')
            layers.append({
                'model': other_model.model,
                'title': cls.TITLES.get(other_model.model, other_model.name),
                'layerid': layer_id,
                'geo': False,
                'filter': None,
                'edittypes': {'id': {'type': QGIS_WIDGET_HIDDEN}},
                'unfolded': 'false',
                'aliases': cls._get_aliases(other_model.model),
            })

            for layer in base_layers:
                layer['edittypes'][m2o_field.name] = {
                    'type': QGIS_WIDGET_RELATIONAL,
                    'layer': layer_id,
                    'value': 'name',
                }

            if symbols == [] and (parent_model is None or other_model_name != parent_model.model):
                symbol_recs = Record.search([('id', 'in', list(unselected) + [record.id for record in records])])
                symbol_recs = set([getattr(symbol_rec, m2o_field.name) for symbol_rec in symbol_recs])
                symbol_recs -= set([None])

                for no, symbol in enumerate(symbol_recs):
                    color = no * 255 / len(symbol_recs)
                    symbols.append({
                        'no': no,
                        'value': symbol.id,
                        'label': symbol.rec_name,
                        'color': '%i,%i,255,255' % (color, color),
                        'color_border': '0,0,0,0',
                    })

                if geo_field._type in ('linestring', 'multilinestring'):
                    none_color = '0,0,0,255'
                else:
                    none_color = '255,255,255,255'

                symbols.append({
                    'no': len(symbol_recs),
                    'value': '',
                    'label': '(None)',
                    'color': none_color,
                    'color_border': '0,0,0,255',
                })

                base_layers[0].update({
                    'symbols': symbols,
                    'symbols_attr': m2o_field.name,
                })

                cls._add_symbol_style(base_layers[0], geo_field)

                if len(base_layers) > 1:
                    symbols = deepcopy(symbols)
                    # Set the border color to black for selected geometries
                    for symbol in symbols:
                        symbol['color_border'] = '0,0,0,255'

                    base_layers[1].update({
                        'symbols': symbols,
                        'symbols_attr': m2o_field.name,
                    })
                    cls._add_symbol_style(base_layers[1], geo_field)

        return layers, bbox, srid