nhueffme: thuban/Extensions/ogr ogrdialog.py, 1.2, 1.3 ogrshapes.py, 1.5, 1.6 ogrstart.py, 1.4, 1.5

cvs@intevation.de cvs at intevation.de
Fri Mar 4 16:08:01 CET 2005


Author: nhueffme

Update of /thubanrepository/thuban/Extensions/ogr
In directory doto:/tmp/cvs-serv30928/Extensions/ogr

Modified Files:
	ogrdialog.py ogrshapes.py ogrstart.py 
Log Message:
Latest changes on OGR extension.

Added another menu item to open OGR datasource, handling of geometry collections
possible.


Index: ogrdialog.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrdialog.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ogrdialog.py	8 Feb 2005 09:52:56 -0000	1.2
+++ ogrdialog.py	4 Mar 2005 15:07:59 -0000	1.3
@@ -16,18 +16,12 @@
 try:
     import ogr
 except ImportError:
-    psycopg = None
+    ogr = None
 
 from Thuban import _
-from Thuban.UI.dialogs import NonModalDialog
 from Thuban.Model.table import FIELDTYPE_INT
 from Extensions.ogr import ogrshapes
-from Thuban.Model.messages import DBCONN_ADDED, DBCONN_REMOVED
-from Thuban.UI.messages import SESSION_REPLACED
-
 
-ID_DB_ADD    = 9101
-ID_DB_REMOVE = 9102
 
 ID_DBCHOOSE_RETRIEVE = 9201
 ID_DBCHOOSE_OK       = 9202
@@ -36,8 +30,11 @@
 
 
 class ChooseFileFormat(wxDialog):
-
+    """This dialog lists all available drivers.
+    """
     def __init__(self, parent, session):
+        """Initialize the dialog.
+        """
         wxDialog.__init__(self, parent, -1, _("Choose file format"),
                           style = wxDIALOG_MODAL|wxCAPTION)
         self.session = session
@@ -50,12 +47,12 @@
         # Sizer for the entire dialog
         top = wxFlexGridSizer(2, 1, 0, 0)
 
-        # Sizer for the main part with the list boxes
+        # Sizer for the main part with the list box
         main_sizer = wxBoxSizer(wxHORIZONTAL)
         top.Add(main_sizer, 1, wxEXPAND, 0)
 
         # The list box with the drivers
-        static_box = wxStaticBoxSizer(wxStaticBox(self, -1, _("File formats")),
+        static_box = wxStaticBoxSizer(wxStaticBox(self, -1, "File formats"),
                                    wxHORIZONTAL)
         self.lb_drivers = wxListBox(self, -1)
         static_box.Add(self.lb_drivers, 0, wxEXPAND, 0)
@@ -66,41 +63,6 @@
         if self.lb_drivers.GetCount() > 0:
             self.lb_drivers.SetSelection(0, True)
 
-        # The button box between the connections list box and the table
-        # list box
-        buttons = wxFlexGridSizer(3, 1, 0, 0)
-        buttons.Add(20, 80, 0, wxEXPAND, 0)
-        retrieve_button = wxButton(self, ID_DBCHOOSE_RETRIEVE, _("Retrieve"))
-        EVT_BUTTON(self, ID_DBCHOOSE_RETRIEVE, self.OnRetrieve)
-        buttons.Add(retrieve_button, 0, wxALL
-                    |wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4)
-        buttons.Add(20, 80, 0, wxEXPAND, 0)
-        main_sizer.Add(buttons, 0, wxEXPAND, 0)
-
-        # The list box with the tables
-        static_box = wxStaticBoxSizer(wxStaticBox(self, -1, _("Tables")),
-                                   wxHORIZONTAL)
-        self.lb_tables = wxListBox(self, ID_LB_DCLICK)
-        EVT_LISTBOX(self, ID_LB_DCLICK, self.OnTableSelect)
-        EVT_LISTBOX_DCLICK(self, ID_LB_DCLICK, self.OnLBDClick)
-        static_box.Add(self.lb_tables, 0, wxEXPAND, 0)
-        main_sizer.Add(static_box, 1, wxEXPAND, 0)
-
-        # id column and geometry column selection
-        box = wxBoxSizer(wxVERTICAL)
-        box.Add(wxStaticText(self, -1, _("ID Column")), 0,
-                wxALL|wxALIGN_CENTER_VERTICAL, 4)
-        self.text_id_column = wxComboBox(self, -1, "")
-        box.Add(self.text_id_column, 0,
-                wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
-
-        box.Add(wxStaticText(self, -1, _("Geometry Column")), 0,
-                wxALL|wxALIGN_CENTER_VERTICAL, 4)
-        self.text_geo_column = wxComboBox(self, -1, "")
-        box.Add(self.text_geo_column, 0,
-                wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
-        main_sizer.Add(box, 1, wxEXPAND, 0)
-
         # The standard button box at the bottom of the dialog
         buttons = wxFlexGridSizer(1, 2, 0, 0)
         ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
@@ -120,48 +82,39 @@
 
 
     def GetTable(self):
-        i = self.lb_tables.GetSelection()
-        if i >= 0:
-            return (self.selected_conn, self.tables[i],
-                    self.text_id_column.GetValue(),
-                    self.text_geo_column.GetValue())
+        """no functionality
+        """
         return None
 
-    def OnRetrieve(self, event):
-        i = self.lb_driver.GetSelection()
-        if i >= 0:
-            self.selected_conn = self.dbconns[i]
-            self.tables = self.selected_conn.GeometryTables()
-            self.lb_tables.Set(self.tables)
-
-    def OnTableSelect(self, event):
-        i = self.lb_tables.GetSelection()
-        self.text_id_column.Clear()
-        self.text_geo_column.Clear()
-        if i >= 0:
-            for name, typ in self.selected_conn.table_columns(self.tables[i]):
-                if typ == "geometry":
-                    self.text_geo_column.Append(name)
-                elif typ == FIELDTYPE_INT:
-                    self.text_id_column.Append(name)
-
     def OnLBDClick(self, event):
+        """Close dialog.
+        """
         if self.lb_tables.GetSelection() >= 0:
             self.EndModal(wxID_OK)
             self.Show(False)
 
     def OnOK(self, event):
+        """Close dialog.
+        """
         self.EndModal(wxID_OK)
         self.Show(False)
 
     def OnCancel(self, event):
+        """Close dialog.
+        """
         self.EndModal(wxID_CANCEL)
         self.Show(False)
 
 
 class ChooseLayer(wxDialog):
+    """This dialog lists all the layers contained in the given datasource.
+
+    One layer can be chosen, which is then opened.
+    """
 
     def __init__(self, parent, filename):
+        """Initialize the dialog.
+        """
         wxDialog.__init__(self, parent, -1, _("Choose layer"),
                           style = wxDIALOG_MODAL|wxCAPTION)
         self.tables = []
@@ -210,6 +163,9 @@
         self.Layout()
 
     def end_dialog(self, result):
+        """If the dialog is closed with OK, set chosen layer as layer 
+        to be opened.
+        """
         self.result = result
         if result is not None:
             self.EndModal(wxID_OK)
@@ -218,18 +174,31 @@
         self.Show(False)
 
     def OnOK(self, event):
+        """Dialog closed with OK button.
+        """
         self.end_dialog(self.lb_drivers.GetSelection())
 
     def OnCancel(self, event):
+        """Dialog closed with Cancel.
+        """
         self.end_dialog(None)
 
     def GetLayer(self):
+        """Return the selected layer."""
         return self.layer[self.lb_drivers.GetSelection()].GetName()
 
 
 class ChooseOGRDBTableDialog(wxDialog):
+    """This dialog opens a datasource from an existing database connection.
+
+    A list of all available database connections is offered. If one connection
+    is selected and the button "Retrieve" is clicked, all layers are listed.
+    One of these layers can be chosen to be opened.
+    An ID column can be chosen, too."""
 
     def __init__(self, parent, session):
+        """Initialize the dialog.
+        """
         wxDialog.__init__(self, parent, -1, _("Choose layer from database"),
                           style = wxDIALOG_MODAL|wxCAPTION)
         self.session = session
@@ -279,6 +248,15 @@
         static_box.Add(self.lb_tables, 0, wxEXPAND, 0)
         main_sizer.Add(static_box, 1, wxEXPAND, 0)
 
+        # id column and geometry column selection
+        box = wxBoxSizer(wxVERTICAL)
+        box.Add(wxStaticText(self, -1, _("ID Column")), 0,
+                wxALL|wxALIGN_CENTER_VERTICAL, 4)
+        self.text_id_column = wxComboBox(self, -1, "")
+        box.Add(self.text_id_column, 0,
+                wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 4)
+        main_sizer.Add(box, 1, wxEXPAND, 0)
+
         # The standard button box at the bottom of the dialog
         buttons = wxFlexGridSizer(1, 2, 0, 0)
         ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
@@ -298,46 +276,141 @@
 
 
     def GetTable(self):
+        """Return the chosen DB connection, the table to be opened, 
+        the connection string for ogr and the ID column.
+        """
         i = self.lb_tables.GetSelection()
         if i >= 0:
-            return (self.selected_conn, self.tables[i])
+            return (self.selected_conn, self.connString, self.tables[i],
+                    self.text_id_column.GetValue())
         return None
 
     def OnRetrieve(self, event):
+        """Provide a list of all available layers in the selected datasource.
+        """
         i = self.lb_connections.GetSelection()
         if i >= 0:
             self.selected_conn = self.dbconns[i]
-            connString = ("PG: host=%s dbname=%s user=%s port=%s"
-                          %(self.selected_conn.host, self.selected_conn.dbname,
-                            self.selected_conn.user, self.selected_conn.port))
-            ds = ogr.Open(connString)
+            self.connString = "PG: dbname=%s" %self.selected_conn.dbname
+            if self.selected_conn.host is not "":
+                self.connString = (self.connString + " host=%s"
+                                    %self.selected_conn.host)
+            if self.selected_conn.user is not "":
+                self.connString = (self.connString + " user=%s"
+                                    %self.selected_conn.user)
+            if self.selected_conn.password is not "":
+                self.connString = (self.connString + " password=%s"
+                                    %self.selected_conn.password)
+            if self.selected_conn.port is not "":
+                self.connString = (self.connString + " port= %s"
+                                    %self.selected_conn.port)
+            ds = ogr.Open(self.connString)
             if ds:
                 for i in range(ds.GetLayerCount()):
                     self.tables.append(ds.GetLayer(i).GetName())
                 self.lb_tables.Set(self.tables)
 
     def OnTableSelect(self, event):
+        """If a table is selected, list all possible ID columns.
+        """
         i = self.lb_tables.GetSelection()
- #       self.text_id_column.Clear()
-  #      self.text_geo_column.Clear()
-   #     if i >= 0:
-    #        for name, typ in self.selected_conn.table_columns(self.tables[i]):
-     #           if typ == "geometry":
-      #              self.text_geo_column.Append(name)
-       #         elif typ == FIELDTYPE_INT:
-        #            self.text_id_column.Append(name)
+        self.text_id_column.Clear()
+        if i >= 0:
+            for name, typ in self.selected_conn.table_columns(self.tables[i]):
+                if typ == FIELDTYPE_INT:
+                    self.text_id_column.Append(name)
 
     def OnLBDClick(self, event):
+        """Close dialog.
+        """
         if self.lb_tables.GetSelection() >= 0:
             self.EndModal(wxID_OK)
             self.Show(False)
 
     def OnOK(self, event):
+        """Dialog closed with OK button.
+        """
         self.EndModal(wxID_OK)
         self.Show(False)
 
     def OnCancel(self, event):
+        """Dialog closed with Cancel.
+        """
         self.EndModal(wxID_CANCEL)
         self.Show(False)
 
+
+class OGRConnectionDialog(wxDialog):
+    """A string can be enteres, which is directly passed to ogr to open a
+    datasource.
+    """
+    def __init__(self, parent, session):
+        """Initialize the dialog.
+        """
+        wxDialog.__init__(self, parent, -1, "Enter string for OGRConnection",
+                          style = wxDIALOG_MODAL|wxCAPTION)
+        self.session = session
+
+        # Sizer for the entire dialog
+        top = wxBoxSizer(wxVERTICAL)
+
+        # The list box with the drivers
+        box = wxBoxSizer(wxHORIZONTAL)#wxBox(self, -1, _("OGRConnection")),
+                            #       wxHORIZONTAL)
+        box.Add(wxStaticText(self, -1, _("URL:")), 0,
+                wxALL|wxALIGN_CENTER_VERTICAL, 4)
+        self.text_string = wxTextCtrl(self, -1, "")
+        box.Add(self.text_string, 0, wxEXPAND, 0)
+        top.Add(box, 0, wxEXPAND)
+
+        # The standard button box at the bottom of the dialog
+        buttons = wxFlexGridSizer(1, 2, 0, 0)
+        ok_button = wxButton(self, ID_DBCHOOSE_OK, _("OK"))
+        EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+        buttons.Add(ok_button, 0, wxALL|wxALIGN_RIGHT, 4)
+        cancel_button = wxButton(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+        EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+        buttons.Add(cancel_button, 0, wxALL, 4)
+        top.Add(buttons, 1, wxALL|wxALIGN_CENTER_HORIZONTAL, 4)
+
+        # Autosizing
+        self.SetAutoLayout(1)
+        self.SetSizer(top)
+        top.Fit(self)
+        top.SetSizeHints(self)
+        self.Layout()
+
+    def RunDialog(self):
+        """Run dialog
+        """
+        self.ShowModal()
+        self.Destroy()
+        return self.result
+
+    def end_dialog(self, result):
+        """Close dialog
+        """
+        self.result = result
+        if result is not None:
+            self.EndModal(wxID_OK)
+        else:
+            self.EndModal(wxID_CANCEL)
+        self.Show(False)
+
+    def OnOK(self, event):
+        """Dialog closed with OK
+        """
+        result = {}
+        result["string"] = getattr(self, "text_string").GetValue()
+        self.end_dialog(result)
+
+    def OnCancel(self, event):
+        """Dialog closed with Cancel.
+        """
+        self.end_dialog(None)
+
+    def GetDatasourceName(self):
+        """Return the string to be used for opening the database
+        """
+        return self.result["string"]
 

Index: ogrshapes.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrshapes.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- ogrshapes.py	8 Feb 2005 09:52:56 -0000	1.5
+++ ogrshapes.py	4 Mar 2005 15:07:59 -0000	1.6
@@ -17,17 +17,15 @@
     ogr = None
 
 import os
-import weakref
-from math import ceil, log
 
 from Thuban import _
 from Thuban.Model import table
+from Thuban.Model import transientdb
+from Thuban.Model.transientdb import  TransientDatabase
 
 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
 from Thuban.Model.data import RAW_PYTHON, RAW_SHAPEFILE, RAW_WKT
 
-SHAPETYPE_UNKNOWN = ogr.wkbUnknown
-
 def has_ogr_support():
     """Return whether this Thuban instance supports ogr file formats
 
@@ -37,53 +35,102 @@
     return ogr is not None
 
 if ogr is not None:
-    # mapping from ogr-lib shapetype and table constants to our constants
+    SHAPETYPE_UNKNOWN = ogr.wkbUnknown
+    SHAPETYPE_GEOMCOLL = ogr.wkbGeometryCollection
+    SHAPETYPE_NONE = ogr.wkbNone
+
+    # mapping from ogr-lib shapetypes and table constants to our constants
     ogrlib_shapetypes = {ogr.wkbPolygon: SHAPETYPE_POLYGON,
                 ogr.wkbLineString: SHAPETYPE_ARC,
                 ogr.wkbPoint: SHAPETYPE_POINT,
-                ogr.wkbUnknown: SHAPETYPE_UNKNOWN}
+                ogr.wkbUnknown: SHAPETYPE_UNKNOWN,
+                ogr.wkbNone: SHAPETYPE_NONE,
+                ogr.wkbGeometryCollection: SHAPETYPE_GEOMCOLL}
 
     fieldtype_map = {ogr.OFTString: table.FIELDTYPE_STRING,
                 ogr.OFTInteger: table.FIELDTYPE_INT,
                 ogr.OFTReal: table.FIELDTYPE_DOUBLE}
 
+else:
+    ogrlib_shapetypes = {}
+    fieldtype_map = {}
+    SHAPETYPE_UNKNOWN = 0
+    SHAPETYPE_GEOMCOLL = 7
+    SHAPETYPE_NONE = 100
+
 
 class OGRShape:
+    """Represent one shape of an OGRShapeStore
+    """
 
-    """Represent one shape of an OGRShapeStore"""
+    def __init__(self, shapestore, shape):
+        """Initialize the shape object.
 
-    def __init__(self, ogrlayer, shapeid):
-        self.ogrlayer = ogrlayer
-        self.feature = self.ogrlayer.GetFeature(shapeid)
-        self.shapeid = shapeid
+        shapestore should be an instance of OGRShapeStore,
+        shape should be an instance of an OGRFeature.
+        """
+        self.ogrlayer = shapestore.ogrlayer
+        id_column = shapestore.Id_column()
+        self.feature = shape
+        if id_column is None:
+            self.shapeid = self.feature.GetFID()
+        else:
+            self.shapeid = self.feature.GetField(id_column)
         self.geom = self.feature.GetGeometryRef()
-        self.shapetype = self.geom.GetGeometryType()
+        if self.geom:
+            self.shapetype = self.geom.GetGeometryType()
+            self.bbox = self._compute_bbox()
+            self.points = self._points()
+        else:
+            self.shapetype = ogr.wkbNone
+            self.bbox = None
+            self.points = [[]]
+        try:
+            self.shapetype = ogrlib_shapetypes[self.shapetype]
+        except:
+            self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
 
-    def compute_bbox(self):
+        self.geoms = self._geoms()
+
+    def _geoms(self):
+        """Return a list of geometry objects.
+
+        If the shape is a geometry collection, all contained geometry
+        objects are stored to the list as OGRGeometry objects.
         """
-        Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+        geoms = []
+        if self.shapetype == SHAPETYPE_GEOMCOLL:
+            for i in range(self.geom.GetGeometryCount()):
+                geoms.append(OGRGeometry(self, self.geom, i))
+        return geoms
+
+    def _compute_bbox(self):
+        """
+        Compute the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
         """
         minx, maxx, miny, maxy = self.geom.GetEnvelope()
         return (minx, miny, maxx, maxy)
 
+    def compute_bbox(self):
+        """
+        Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+        """
+        return self.bbox
+
     def ShapeID(self):
+        """Return the feature id of this shape.
+        """
         return self.shapeid
 
     def Points(self):
-        """Return the coordinates of the shape as a list of lists of pairs"""
-        shape = []
-        #spatialFilter = self.ogrlayer.GetSpatialFilter()
-
-        #if spatialFilter is not None:
-        #self.ogrlayer.SetSpatialFilter(None)
-            #feature = self.ogrlayer.GetFeature(self.shapeid)
-            #self.ogrlayer.SetSpatialFilter(spatialFilter)
-        #else:
-        #feature = self.ogrlayer.GetFeature(self.shapeid)
+        """Return the coordinates of the shape as a list of lists of pairs
+        """
+        return self.points
 
-        #if feature is None:
-         #   return shape.append([])
-        #geom = feature.GetGeometryRef()
+    def _points(self):
+        """Get the coordinates of the shape as a list of lists of pairs
+        """
+        shape = []
 
         if self.geom is None:
             return shape.append([])
@@ -107,7 +154,7 @@
                     y = geometry.GetY(point)
                     points.append((x, y))
                 shape.append(points)
-            # if geometry object is of type multipolygon
+            # if geometry object is of type multipolygon or geometry collection
             else:
                 for j in range(geometry.GetGeometryCount()):
                     points = []
@@ -120,46 +167,99 @@
         return shape
 
     def RawData(self):
-        """Return the shape id to use with the shapestore"""
+        """Return the shape id to use with the shapestore
+        """
         return self.shapeid
 
     def OGRLayer(self):
-        """Return the ogrlayer object"""
+        """Return the ogrlayer object
+        """
         return self.ogrlayer
 
     def ShapeType(self):
+        """Return the shapetype of this shape (may differ from the layer's
+        shapetype)
+        """
         return self.shapetype
 
+    def GetGeoms(self):
+        """Return the list of geometries of this feature.
 
-class OGRShapeStore:
+        If this feature is a geometry collection, all contained geometries
+        are given. Else the returned list is empty.
+        """
+        return self.geoms
 
-    """Corresponds to an OGRLayer object, containing features/shapes and 
-       providing all methods Thuban needs.
+    def GetGeom(self, index):
+        """Return the OGRGeometry object at the specified index.
+
+        This is not none only if the shape is a geometry collection.
+        """
+        if index < len(self.geoms):
+            return self.geoms[index]
+        else:
+            return None
+
+
+class OGRGeometry:
+    """This class represents a geometry belonging to a specified feature.
     """
 
-    def __init__(self, filename, layername, id_column = None):
-        # Make the filename absolute. The filename will be
-        # interpreted relative to that anyway, but when saving a
-        # session we need to compare absolute paths and it's usually
-        # safer to always work with absolute paths.
+    def __init__(self, shape, geom, index):
+        """Initialize the geometry object.
 
-        self.filename = filename
+        shape should be an OGRShape, which this geometry belongs to.
+        geom is the base geometry, index is the ReferenceID.
+        """
+        self.shape = shape
+        self.index = index
+
+        self.geom = geom.GetGeometryRef(index)
+        try:
+            self.shapetype = ogrlib_shapetypes[self.geom.GetGeometryType()]
+        except:
+            self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+
+    def ShapeType(self):
+        """Return the shapetype of this geometry object."""
+        return self.shapetype
+
+
+class OGRShapeStore:
+    """Corresponds to an OGRLayer object, containing features/shapes and
+       providing the same methods like ShapefileStore.
+    """
+
+    def __init__(self, session, filename, layername, id_column = None):
+        """Initialize the shapestore.
+
+        All required information is loaded from the datasource.
+        """
+        # if id_column is None, data is loaded from file, so we need path
+        # if id_column is not None, data is loaded from database
+        if id_column is None:
+            self.filename = os.path.abspath(filename)
+        else:
+            self.filename = filename
         self.layername = layername
 
         self.ogrdatasource = ogr.Open(filename)
         self.ogrlayer = (self.ogrdatasource).GetLayerByName(layername)
 
-        driver = self.ogrdatasource.GetDriver().GetName()
-        if driver == 'PostgreSQL':
-            self.id_column = 'gid'
+        if id_column is not None:
+            self.id_column = id_column
         else:
-            self.id_column = 'fid'
+            self.id_column = None
 
-        self.table = OGRTable(self.ogrdatasource, self.ogrlayer, self.id_column)
+        self.table = OGRTable(session, self.ogrdatasource, self.ogrlayer,
+                                self.id_column)
 
         self._open_ogrlayer(layername)
 
     def _open_ogrlayer(self, layername):
+        """Get all required information from the datasource.
+        """
         self.numshapes = self.ogrlayer.GetFeatureCount()
         self.shapetype = self.ogrlayer.GetLayerDefn().GetGeomType()
 
@@ -169,38 +269,73 @@
         else:
             self.bbox = None
 
-        if self.shapetype is not ogr.wkbUnknown:
+        try:
             self.shapetype = ogrlib_shapetypes[self.shapetype]
-        #else:
-            # this should be ogr.wkbUnknown, but Thuban does not know how
-            # to handle an unknown shapetype (e.g. Session Tree)
-            #self.shapetype = ogrlib_shapetypes[ogr.wkbPoint]
+        except:
+            # if shapetype is not contained in ogrlib_shapetypes
+            # treat it like SHAPETYPE_UNKNOWN
+            self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+        self.shapes = self.shapes()
+
+    def shapes(self):
+        """Return a collection of all features as OGRShape objects.
+        """
+        shapes = {}
+        self.ogrlayer.ResetReading()
+        if self.id_column is None:
+            nextFeature = self.ogrlayer.GetNextFeature()
+            while nextFeature is not None:
+                fid = nextFeature.GetFID()
+                shape = OGRShape(self, nextFeature)
+                shapes[shape.ShapeID()] = shape
+                nextFeature = self.ogrlayer.GetNextFeature()
+        else:
+            lay = self.ogrdatasource.ExecuteSQL("SELECT %s, * from %s" 
+                                    % (self.id_column, self.layername))
+            if lay is not None:
+                lay.ResetReading()
+                nextFeature = lay.GetNextFeature()
+                while nextFeature is not None:
+                    fid = nextFeature.GetField(0)
+                    shape = OGRShape(self, nextFeature)
+                    shapes[shape.ShapeID()] = shape
+                    nextFeature = lay.GetNextFeature()
+                self.ogrdatasource.ReleaseResultSet(lay)
+        return shapes
 
     def OGRLayer(self):
-        """Return the OGRLayer object"""
+        """Return the OGRLayer object
+        """
         return self.ogrlayer
 
     def FileName(self):
-        """Return the filename used to open the file"""
+        """Return the filename used to open the file
+        """
         return self.filename
 
     def FileType(self):
-        """Return the filetype. This is always the string 'ogr-file'"""
-        return "ogr-file"
+        """Return the filetype. This is depending on the driver used to open
+        the file.
+        """
+        return self.ogrdatasource.GetDriver().GetName()
 
     def ShapeType(self):
         """Return the type of the shapes in the shapestore.
 
-        This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
+        This is either SHAPETYPE_POINT, SHAPETYPE_ARC, SHAPETYPE_POLYGON,
+        SHAEPTYPE_GEOMCOLL, SHAPETYPE_NONE or SHAPETYPE_UNKNOWN.
         """
         return self.shapetype
 
     def RawShapeFormat(self):
-        """Return the raw data format of the shape data, i.e. RAW_PYTHON"""
+        """Return the raw data format of the shape data, i.e. RAW_PYTHON
+        """
         return RAW_PYTHON
 
     def NumShapes(self):
-        """Return the number of shapes in the shape store"""
+        """Return the number of shapes in the shape store
+        """
         return self.numshapes
 
     def BoundingBox(self):
@@ -214,53 +349,61 @@
         The bbox parameter should be the bounding box as a tuple in the
         form (minx, miny, maxx, maxy) in the coordinate system of the
         shape store.
-
-        The method GetFID() returns feature IDs starting from 0.
         """
-        # Bind a few globals to locals to make it a bit faster
-        cls = OGRShape
-        ogrlayer = self.ogrlayer
-
         left, bottom, right, top = bbox
+
         # create a geometry which can be passed to the layer as spatial filter
         bboxpolygon = ogr.CreateGeometryFromWkt(
                       ('Polygon((%s %s, %s %s, %s %s,%s %s, %s %s))'
-                                 %(left, bottom, left, top, right, top, 
+                                 %(left, bottom, left, top, right, top,
                                   right, bottom, left, bottom)))
 
-        if ogrlayer.GetSpatialRef():
-            bboxpolygon.AssignSpatialReference(ogrlayer.GetSpatialRef())
+        if self.ogrlayer.GetSpatialRef():
+            bboxpolygon.AssignSpatialReference(self.ogrlayer.GetSpatialRef())
 
-        ogrlayer.ResetReading()
+        self.ogrlayer.ResetReading()
         #ogrlayer.SetSpatialFilterRect(left, bottom, right, top)
-        ogrlayer.SetSpatialFilter(bboxpolygon)
+        self.ogrlayer.SetSpatialFilter(bboxpolygon)
 
-        numFeatures = ogrlayer.GetFeatureCount()
+        numFeatures = self.ogrlayer.GetFeatureCount()
+        # if no features are in bbox, return all features as shapesInRegion
+        # (PostGIS sometimes returns no features even if they are within 
+        #  the bounding box)
+        if numFeatures == 0:
+            self.ogrlayer.SetSpatialFilter(None)
+            numFeatures = self.ogrlayer.GetFeatureCount()
         for feature in range(numFeatures):
-            nextFeature = ogrlayer.GetNextFeature()
-            yield cls(ogrlayer, nextFeature.GetFID())
+            nextFeature = self.ogrlayer.GetNextFeature()
+            if self.id_column is None:
+                yield self.shapes[nextFeature.GetFID()]
+            else:
+                yield self.shapes[nextFeature.GetField(self.id_column)]
 
-        ogrlayer.SetSpatialFilter(None)
+        self.ogrlayer.SetSpatialFilter(None)
         bboxpolygon.Destroy()
 
     def AllShapes(self):
-        """Return an iterable over the shapes in the shape store."""
-        self.ogrlayer.ResetReading()
-        nextFeature = self.ogrlayer.GetNextFeature()
-        while nextFeature is not None:
-            yield OGRShape(self.ogrlayer, nextFeature.GetFID())
-            nextFeature = self.ogrlayer.GetNextFeature()
+        """Return an iterable over the shapes in the shape store.
+        """
+        for id in range(len(self.shapes)):
+            yield self.shapes[id]
 
-    def Shape(self, index):
-        """Return the shape with index index"""
-        return OGRShape(self.ogrlayer, index)
+    def Shape(self, fid):
+        """Return the shape with fid = fid
+        """
+        if fid in self.table.ids.keys():
+            return self.shapes[fid]
+        else:
+            return None
 
     def Table(self):
-        """Return the table containing the attribute data"""
+        """Return the table containing the attribute data
+        """
         return self.table
 
     def Dependencies(self):
-        """Return the empty tuple."""
+        """Return the empty tuple.
+        """
         return ()
 
     def OrigShapeStore(self):
@@ -268,24 +411,25 @@
         return None
 
     def Id_column(self):
-        """Return the id_column."""
+        """Return the id_column.
+        """
         return self.id_column
 
-class OGRTable:
-
-    """A Table for an ogr file
+class OGRTable(transientdb.AutoTransientTable):
+    """A Table for an ogr datasource.
     """
 
-    def __init__(self, ds, layer, id_column):
+    def __init__(self, session, ds, layer, id_column):
         """Initialize the OGRTable.
 
-        ds should be an instance of OGRDatasource.
-        layer should be an instance of OGRLayer.
+        session   - should be the current session.
+        ds        - should be an instance of OGRDatasource.
+        layer     - should be an instance of OGRLayer.
+        id_column - should be the name of the column used as ID column
         """
-
         self.datasource = ds
         self.layer = layer
-        self.tablename = layer.GetName()
+        self.tablename = self.layer.GetName()
         self.id_column = id_column
 
         # Map column names and indices to column objects.
@@ -295,12 +439,20 @@
         self._map_ords_and_ids()
 
         self._fetch_table_information()
+        self._fetch_table_content()
+
+        transientdb.AutoTransientTable.__init__(self, session.TransientDB(),
+                                                self)
 
     def _fetch_table_information(self):
-        """Internal: Update information about the table"""
+        """Internal: Update information about the table
+        """
         self.columns = []
 
         layerdefn = self.layer.GetLayerDefn()
+        # if FID column is of interest
+        #col = OGRColumn("FID", table.FIELDTYPE_INT, layerdefn.GetFieldCount())
+        #self.columns.append(col)
         for i in range(layerdefn.GetFieldCount()):
             fielddef = layerdefn.GetFieldDefn(i)
             fieldname = fielddef.GetName()
@@ -314,86 +466,108 @@
             self.column_map[col.name] = col
             self.column_map[col.index] = col
 
+    def _fetch_table_content(self):
+        """Internal: Update information contained in the table
+        """
+        self.content = []
+        layerdefn = self.layer.GetLayerDefn()
+
+        self.layer.ResetReading()
+        for i in range(self.layer.GetFeatureCount()):
+            nextFeature = self.layer.GetNextFeature()
+            row = []
+            for j in range(layerdefn.GetFieldCount()):
+                row.append(nextFeature.GetField(j))
+            # if FID should be listed in the table
+            #if self.id_column is None:
+            #    row.append(nextFeature.GetFID())
+            #else:
+            #    row.append(nextFeature.GetField(self.id_column))
+            self.content.append(row)
+
     def _map_ords_and_ids(self):
+        """Create collections which map ordinals to ids and verse visa.
+        """
         self.ordinals = {}
         self.ids = {}
 
-        lay = self.datasource.ExecuteSQL(
-                "SELECT %s from %s"
-                %(self.id_column, self.tablename))
-        lay.ResetReading()
-        nextFeature = lay.GetNextFeature()
+        if self.id_column is not None:
+            lay = self.datasource.ExecuteSQL("SELECT %s from %s"
+                    %(self.id_column, self.tablename))
+            lay.ResetReading()
+            nextFeature = lay.GetNextFeature()
+        else:
+            self.layer.ResetReading()
+            nextFeature = self.layer.GetNextFeature()
+
         ord = 0
         while nextFeature is not None:
-            id = nextFeature.GetFID()
+            if self.id_column is not None:
+                id = nextFeature.GetField(self.id_column)
+                nextFeature = lay.GetNextFeature()
+            else:
+                id = nextFeature.GetFID()
+                nextFeature = self.layer.GetNextFeature()
             self.ordinals[ord] = id
             self.ids[id] = ord
-            nextFeature = lay.GetNextFeature()
             ord = ord + 1
-        self.datasource.ReleaseResultSet(lay)
+        if self.id_column is not None:
+            self.datasource.ReleaseResultSet(lay)
 
     def TableName(self):
-        """Return the name of the table, which is the name of the layer"""
+        """Return the name of the table, which is the name of the layer
+        """
         return self.tablename
 
     def Title(self):
         """Return the title of the table.
-
-        The title is currently
         """
         return self.tablename
 
     def Dependencies(self):
-        """Return an empty tuple."""
+        """Return an empty tuple.
+        """
         return ()
 
     def NumColumns(self):
-        """Return the number of columns."""
+        """Return the number of columns.
+        """
         return len(self.columns)
 
     def Columns(self):
-        """Return all columns."""
+        """Return all columns.
+        """
         return self.columns
 
     def Column(self, col):
-        """Return the column col. col can be either a string or an integer."""
+        """Return the column col. col can be either a string or an integer.
+        """
         return self.column_map[col]
 
     def HasColumn(self, col):
-        """Return if column col exists. col can be either a string or an 
+        """Return if column col exists. col can be either a string or an
         integer.
         """
         return self.column_map.has_key(col)
 
     def NumRows(self):
-        """Return the number of rows in the table, which equals the number of 
+        """Return the number of rows in the table, which equals the number of
         features in the layer.
         """
-        return self.layer.GetFeatureCount()
+        return len(self.ids)
 
     def RowIdToOrdinal(self, gid):
-        """Return the row ordinal given its id"""
+        """Return the row ordinal given its id
+        """
         if gid < 0:
             return gid
         else:
             ord = self.ids[gid]
             return ord
-#        lay = self.datasource.ExecuteSQL(
- #               "SELECT COUNT(%s) From %s where FID < %s"
-  #              %(self.id_column, self.tablename, gid))
-   #     ord = lay.GetFeature(0).GetField(0)
-    #    self.datasource.ReleaseResultSet(lay)
- #       return ord
 
     def RowOrdinalToId(self, num):
-        """Return the rowid for given its ordinal"""
-#        lay = self.datasource.ExecuteSQL(
- #               "SELECT FID From %s"
-  #              %(self.tablename))
-   #     for i in range(num):
-    #        lay.GetNextFeature()
-     #   id = lay.GetNextFeature().GetField(0)
-      #  self.datasource.ReleaseResultSet(lay)
+        """Return the rowid for given its ordinal
+        """
         if num >= 0:
             id = self.ordinals[num]
             return id
@@ -401,32 +575,31 @@
             return num
 
     def ReadRowAsDict(self, row, row_is_ordinal = 0):
-        """Return a dictionary which contains all the fields."""
-        if row_is_ordinal == 1:
-            rowId = self.RowOrdinalToId(row)
+        """Return a dictionary which contains all the fields.
+        """
+        if row_is_ordinal == 0:
+            rowId = self.RowIdToOrdinal(row)
         else:
             rowId = row
-        layerdef = self.layer.GetLayerDefn()
-        feature = self.layer.GetFeature(rowId)
         result = {}
-        for i in range(len(self.columns)):
-            fielddef = layerdef.GetFieldDefn(i)
-            if feature is not None:
-                result[self.columns[i].name] = feature.GetField(i)
-            else:
-                result[fielddef.GetName()] = None
+        for i in range(self.NumColumns()):
+            result[self.Column(i).name] = self.content[rowId][i]
         return result
 
     def ReadValue(self, row, col, row_is_ordinal = 0):
-        """Return the requested value."""
-        if col is None:
-            return None
+        """Return the requested value.
+        """
+        if row_is_ordinal == 0:
+            rowId = self.RowIdToOrdinal(row)
         else:
-            feature = self.layer.GetFeature(row)
-        return feature.GetField(col)
+            rowId = row
+        colIndex = self.column_map[col].index
+        return self.content[rowId][colIndex]
 
     def ValueRange(self, col):
-        """Return the value range of the given column (given as string)."""
+        """Return the value range of the given column (given as string).
+        """
+
         result = self.datasource.ExecuteSQL("SELECT min(%s), max(%s) FROM %s"
                 %(col, col, self.layer.GetName()))
         result.ResetReading()
@@ -456,7 +629,9 @@
         return values
 
     def SimpleQuery(self, left, comparison, right):
-        """Return the FIDs resulting from the given query."""
+        """Return the FIDs resulting from the given query.
+        """
+
         if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
             raise ValueError("Comparison operator %r not allowed" %comparison)
 
@@ -468,9 +643,13 @@
         else:
             right_template = right
 
-        query = ("SELECT %s FROM %s WHERE '%s' %s %s ORDER BY FID"
-                % (self.id_column, self.tablename,left.name, comparison, 
-                   right_template))
+        if self.id_column is None:
+            id = "FID"
+        else:
+            id = self.id_column
+        query = ("SELECT %s FROM %s WHERE %s %s %s ORDER BY %s"
+                % (id, self.tablename,left.name, comparison,
+                   right_template, id))
 
         lay = self.datasource.ExecuteSQL(query)
         result = []
@@ -484,12 +663,12 @@
         return result
 
     def Id_column(self):
-        """Return the id_column."""
+        """Return the id_column.
+        """
         return self.id_column
 
 
 class OGRColumn:
-
     """Column description for a table for an ogr file
     """
 

Index: ogrstart.py
===================================================================
RCS file: /thubanrepository/thuban/Extensions/ogr/ogrstart.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- ogrstart.py	8 Feb 2005 09:52:56 -0000	1.4
+++ ogrstart.py	4 Mar 2005 15:07:59 -0000	1.5
@@ -10,9 +10,7 @@
 # $Id$
 
 # Needed wx-toolkit classes
-#from wxPython.wx import *
-from wxPython.wx import wxFileDialog, wxOPEN, wxMULTIPLE, wxID_OK, \
-        wxOK, wxICON_HAND
+from wxPython.wx import wxFileDialog, wxOPEN, wxMULTIPLE, wxID_OK
 
 # We need os.path
 import os
@@ -21,13 +19,13 @@
 from Thuban import _
 
 from Thuban.Model.layer import Layer
-from Thuban.UI.dbdialog import DBDialog
 
 # Import ogr related classes
 from Extensions.ogr import ogrshapes, ogrdialog
 from Extensions.ogr.ogrdialog import ChooseOGRDBTableDialog
 
 from Thuban.UI.menu import Menu
+from Thuban.UI.mainwindow import _has_dbconnections, _has_gdal_support
 
 def open_with_ogr(context):
     '''Open a file supported by ogr.
@@ -37,9 +35,13 @@
 
     # Get the file to be opened
     dlg = wxFileDialog(canvas, _("Select a data file"),
-                           ".", "",
-                           _("Shape/GML files (*.shp/*.gml)") + "|*.shp;*.gml|" +
-                           _("All Files (*.*)") + "|*.*",
+                           context.application.Path("data"), "",
+                           _("Shapefiles (*.shp)") + "|*.shp|" +
+                           _("GML files (*.gml)") + "|*.gml|" +
+                           _("MapInfo files (*.tab)") + "|*.tab|" +
+                           _("DGN files (*.dgn)") + "|*.dgn|" +
+                           _("CSV files (*.csv)") + "|*.csv|" +
+                           _("All Files (*.*)") + "|*.*|",
                            wxOPEN | wxMULTIPLE)
 
     if dlg.ShowModal() == wxID_OK:
@@ -50,22 +52,23 @@
             layerDlg = ogrdialog.ChooseLayer(canvas, filename)
             if layerDlg.ShowModal() == wxID_OK:
                 layername = layerDlg.GetLayer()
-            try:
-                session = context.application.Session()
-                store = ogrshapes.OGRShapeStore(filename, layername)
-                session.AddShapeStore(store)
-            except:
-                # the layer couldn't be opened
-                context.mainwindow.RunMessageBox(("Add Layer"),
+                try:
+                    session = context.application.Session()
+                    store = OpenFileShapestore(session, filename, layername)
+                    session.AddShapeStore(store)
+                except:
+                    # the layer couldn't be opened
+                    context.mainwindow.RunMessageBox(("Add Layer"),
                                 ("Can't open the file '%s'.")%filename)
-            else:
-                layer = Layer(title, store)
-                map.AddLayer(layer)
-                if not has_layers:
-                    # if we're adding a layer to an empty map, fit the
-                    # new map to the window
-                    canvas.FitMapToWindow()
-                context.application.SetPath("data",filename)
+                else:
+                    if store is not None:
+                        layer = Layer(title, store)
+                        map.AddLayer(layer)
+                        if not has_layers:
+                            # if we're adding a layer to an empty map, fit the
+                            # new map to the window
+                            canvas.FitMapToWindow()
+                    context.application.SetPath("data",filename)
         dlg.Destroy()
 
 def select_file_format(context):
@@ -81,7 +84,7 @@
     dlg = ogrdialog.ChooseFileFormat(canvas, session)
 
     if dlg.ShowModal() == wxID_OK:
-        context.mainwindow.RunMessageBox("dialog auf", "dialog auf")
+        pass
     dlg.Destroy()
 
 def open_db(context):
@@ -91,17 +94,14 @@
     canvas = context.mainwindow.canvas
     map = canvas.Map()
 
-    session = context.application.Session() 
+    session = context.application.Session()
     dlg = ChooseOGRDBTableDialog(canvas, session)
 
     if dlg.ShowModal() == wxID_OK:
-        dbconn, dbtable = dlg.GetTable()
+        dbconn, connString, dbtable, id_column = dlg.GetTable()
         try:
-            # Choose the correct Interface for the database type
-            filename = ('PG: host=%s user=%s dbname=%s port=%s' 
-                        %(dbconn.host, dbconn.user, dbconn.dbname, dbconn.port))
-
-            store = ogrshapes.OGRShapeStore(filename, dbtable)
+            store = OpenDBShapestore(session, dbconn, dbtable, id_column,
+                                            None)
             session.AddShapeStore(store)
 
             layer = Layer(dbtable, store)
@@ -117,7 +117,77 @@
                                % dbtable)
     dlg.Destroy()
 
+def open_OGRConnection(context):
+    """Open a datasource with an OGRConnection string."""
+    canvas = context.mainwindow.canvas
+    map = canvas.Map()
 
+    session = context.application.Session()
+    dlg = ogrdialog.OGRConnectionDialog(canvas, session)
+
+    if dlg.ShowModal() == wxID_OK:
+        dsname = dlg.GetDatasourceName()
+
+        layerDlg = ogrdialog.ChooseLayer(canvas, dsname)
+        if layerDlg.ShowModal() == wxID_OK:
+            layername = layerDlg.GetLayer()
+            try:
+                store = ogrshapes.OGRShapeStore(session, dsname, layername)
+                session.AddShapeStore(store)
+            except:
+                # the layer couldn't be opened
+                context.mainwindow.RunMessageBox(("Add Layer"),
+                            ("Can't open the file '%s'.") % dsname)
+            else:
+                layer = Layer(dsname, store)
+                has_layers = map.HasLayers()
+                map.AddLayer(layer)
+                if not has_layers:
+                    # if we're adding a layer to an empty map, fit the
+                    # new map to the window
+                    canvas.FitMapToWindow()
+    dlg.Destroy()
+
+def OpenFileShapestore(session, filename, layername):
+    """Open a datasource and add the required layer.
+    """
+    try:
+        store = ogrshapes.OGRShapeStore(session, filename, layername)
+        return store
+    except:
+        # Some error occured while initializing the layer
+        context.mainwindow.RunMessageBox(_("Open datasource"),
+                           _("Can't open the datasource '%s'")
+                           % filename)
+    else:
+        return null
+
+def OpenDBShapestore(session, dbconn, layername, id_column, geo_column):
+    """Open a datasource and add the required layer.
+
+    dbconn     - shold be a DBConnection
+    layername  - the name of the table which should opened as layer
+    id_column  - the column name which should be used as ID column
+    geo_column - always None for ogr
+    """
+    try:
+        filename = "PG: dbname=%s" %dbconn.dbname
+        if dbconn.host is not "":
+            filename = filename + " host=%s" % dbconn.host
+        if dbconn.user is not "":
+            filename = filename + " user=%s" % dbconn.user
+        if dbconn.password is not "":
+            filename = filename + " password=%s" % dbconn.password
+        if dbconn.port is not "":
+            filename = filename + " port=%s" % dbconn.port
+        store = ogrshapes.OGRShapeStore(session, filename, layername,
+                                        id_column = id_column)
+        return store
+    except:
+        # Some error occured while initializing the layer
+        context.mainwindow.RunMessageBox(_("Open datasource"),
+                           _("Can't open the datasource '%s'")
+                           % filename)
 
 # Thuban has named commands which can be registered in the central
 # instance registry.
@@ -128,28 +198,37 @@
 from Thuban.UI.mainwindow import main_menu
 
 
-# find the map menu (create it a new if not found)
+# find the map menu (create a new if not found)
 map_menu = main_menu.FindOrInsertMenu('map', _('Map'))
 ogr_menu = Menu("ogr", _("Open layer via OGR"),[])
 
+ogrsupport = ogrshapes.has_ogr_support()
 
 # create new commands and register them
 registry.Add(Command('open_ogr_files', 'Open an ogr-file', open_with_ogr,
+                     sensitive = _has_gdal_support,
                      helptext = 'Open a file supported from ogr'))
 
-registry.Add(Command('select_file_format', 'Select a file format',
-                     select_file_format, 
-                     helptext = "Select a file format supported from ogr"))
+#registry.Add(Command('select_file_format', 'Select a file format',
+#                     select_file_format, 
+#                     helptext = "Select a file format supported from ogr"))
 
 registry.Add(Command('open_db', 'Open a layer from a database',
                      open_db,
+                     sensitive = _has_dbconnections,
                      helptext = "Open a layer from a database, e.g. PostGIS"))
 
+registry.Add(Command('open_OGRConnection',
+                     ("Open a datasource with an OGRConnection string"),
+                     open_OGRConnection,
+                     sensitive = _has_gdal_support, helptext = 
+                     "Open a datasource with an OGRConnection string"))
+
 # finally bind the new command with an entry in the extensions menu
 ogr_menu.InsertItem("open_ogr_files")
-ogr_menu.InsertItem('select_file_format')
+#ogr_menu.InsertItem('select_file_format')
 ogr_menu.InsertItem('open_db')
+ogr_menu.InsertItem('open_OGRConnection')
 
 # Add ogr menu to map menu
 map_menu.InsertItem(ogr_menu, after = "rasterlayer_add")
-





More information about the Thuban-devel mailing list

This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)