Package pysqlgtk :: Module models
[hide private]
[frames] | no frames]

Source Code for Module pysqlgtk.models

  1  #       This program is free software; you can redistribute it and/or modify 
  2  #       it under the terms of the GNU General Public License as published by 
  3  #       the Free Software Foundation; either version 2 of the License, or 
  4  #       (at your option) any later version. 
  5  #        
  6  #       This program is distributed in the hope that it will be useful, 
  7  #       but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  #       GNU General Public License for more details. 
 10  #        
 11  #       You should have received a copy of the GNU General Public License 
 12  #       along with this program; if not, write to the Free Software 
 13  #       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 14  #       MA 02110-1301, USA. 
 15   
 16   
 17  #!/usr/bin/python 
 18  #-*- coding: iso-8859-1 -*- 
 19  #see http://www.python.org/peps/pep-0263.html for info of type encoding 
 20   
 21  import pygtk 
 22  import gobject 
 23  pygtk.require('2.0') 
 24  import gtk 
 25  import sqlobject 
 26  from sqlobject.col import * 
 27  import ConfigParser 
 28  import widgets 
 29   
30 -def get_connstr_from_file(filename, passw=None):
31 """reads configuration settings from <i>filename</i> and returns an URI that can be passed as 32 connection string to <i>connectionForURI(connection_string)</i> from sqlobject. If the second 33 parameter <i>passw</i> is given, it will use this as password for the string even if a password 34 is found in the configuration file. If no password is found nor passed as argument, the URI will 35 be formed without password.""" 36 config_parser = ConfigParser.SafeConfigParser() 37 config_parser.read(filename) 38 dbms = config_parser.get("dbconn","dbms") 39 host = config_parser.get("dbconn","host") 40 port = config_parser.get("dbconn","port") 41 db = config_parser.get("dbconn","db") 42 user = config_parser.get("dbconn","user") 43 if passw: 44 pw = passw 45 else: 46 pw = config_parser.get("dbconn","pw") 47 48 if len(pw) > 0: 49 user ="%s:%s" %(user, pw) 50 if len(user)> 0: 51 user ="%s@" % (user,) 52 53 connstr = "%s://%s%s/%s" % (dbms,user,host,db) 54 55 return connstr
56 57
58 -def get_columntype(column):
59 coltype = gobject.TYPE_NONE 60 if type(column) is SOStringCol: 61 coltype = gobject.TYPE_STRING 62 elif type(column) is SOIntCol: 63 coltype = gobject.TYPE_INT 64 elif type(column) is SODecimalCol: 65 #in some DB like MySQL Decimals internally are treated as Strings. However, sqlobject treats it as float 66 coltype = gobject.TYPE_FLOAT 67 elif type(column) is SOFloatCol: 68 coltype = gobject.TYPE_FLOAT 69 elif type(column) is SOBoolCol: 70 coltype = gobject.TYPE_BOOLEAN 71 elif type(column) is SOCurrencyCol: 72 #Currency in sqlobject is a special type of decimal, which in turn is a float. 73 coltype = gobject.TYPE_FLOAT 74 elif type(column) is SODateTimeCol: 75 coltype = gobject.TYPE_STRING 76 elif type(column) is SODateCol: 77 coltype = gobject.TYPE_STRING 78 elif type(column) is SOTimeCol: 79 coltype = gobject.TYPE_STRING 80 elif type(column) is SOUnicodeCol: 81 coltype = gobject.TYPE_STRING 82 elif type(column) is SOPickelCol: 83 coltype = gobject.TYPE_OBJECT 84 elif type(column) is SOForeignKey: 85 coltype = gobject.TYPE_INT 86 #This should work, as this attribute returns a list... 87 elif type(column) is SOMultipleJoin: 88 coltype = gobject.TYPE_OBJECt 89 return coltype
90
91 -class SqlListModel(gtk.GenericTreeModel):
92 """a Treemodel that can be used with gtk.TreeView. This model helps combining 93 the power of SQLObject and pygtk""" 94 select_list = [] 95 select_args = None 96 sql_object = None 97 __where_clause = () # stores the last used params used in self.refresh(). If self.refresh() 98 # is called whithout params, these are used. To make a full select, call 99 # self.flush() before self.refresh(). 100
101 - def __init__(self, sql_object):
102 """The constructor takes a SQLObject Class (not an Instance!) as only argument. However, the 103 model does not contain any data yet on construction time. To fill the model with data you have 104 to call the method <i>refresh()</i>""" 105 gtk.GenericTreeModel.__init__(self) 106 self.sql_object = sql_object 107 # self.select just maps to the select method of the referrenced sql_object 108 self.select = self.sql_object.select
109
110 - def on_get_flags(self):
111 return gtk.TREE_MODEL_LIST_ONLY|gtk.TREE_MODEL_ITERS_PERSIST
112
113 - def on_get_n_columns(self):
114 "returns the number of cols of the model" 115 return len(self.sql_object.sqlmeta.columnList)
116
117 - def on_get_column_type(self, n):
118 column = self.sql_object.sqlmeta.columnList[n] 119 return get_columntype(column)
120
121 - def on_get_iter(self, path):
122 try: 123 return self.select_list[path[0]] 124 except IndexError: 125 return None
126
127 - def on_get_path(self, rowref):
128 return self.select_list.index(rowref)
129
130 - def on_get_value(self, rowref, column):
131 name = '_SO_val_'+self.sql_object.sqlmeta.columnList[column].name 132 return rowref.__dict__[name]
133
134 - def on_iter_next(self, rowref):
135 try: 136 i = self.select_list.index(rowref)+1 137 return self.select_list[i] 138 except IndexError: 139 return None
140
141 - def on_iter_children(self, rowref):
142 if rowref: 143 return None 144 else: 145 return self.select_list[0]
146
147 - def on_iter_has_child(self, rowref):
148 return False
149
150 - def on_iter_n_children(self, rowref):
151 if rowref: 152 return 0 153 else: 154 return len(self.select_list)
155
156 - def on_iter_nth_child(self, rowref, n):
157 if rowref: 158 return None 159 try: 160 return self.select_list[0] 161 except IndexError: 162 return None
163
164 - def on_iter_parent(child):
165 return None
166
167 - def get_col_by_attr(self, col_name):
168 for column in self.sql_object.sqlmeta.columnList: 169 if column.name == col_name: 170 return self.sql_object.sqlmeta.columnList.index(column)
171 172
173 - def iter_previous(self, iter):
174 """in order to be able to navigate forward and backward through the list, this method has been added 175 to complement <i>iter_next()</i>.""" 176 pathstr="0" 177 path = self.get_path(iter) 178 if path[0]>0: 179 index = path[0] 180 index = index-1 181 pathstr =str(index) 182 return self.get_iter_from_string(pathstr)
183
184 - def refresh(self, *value):
185 """fills the list with instances. Arguments are like in SQLObject.select(). 186 If no argument is given, the last used arguments are used. To make a full select, 187 call flush before refresh""" 188 if len(value)>0: 189 self.__where_clause = value 190 select_result = self.select(*value) 191 self.select_list = list(select_result)
192
193 - def flush(self):
194 """flushes the argument buffer that keeps the last used argument with refresh().""" 195 self.__where_clause = ()
196
197 - def add_row(self, **values):
198 """Creates a new SqlObject instance and appends it to the model, no matter if it complies with the 199 last used select parameters. The parameters are just the same as if for the corresponding SqlObject 200 class.""" 201 new_row = self.sql_object(**values) 202 self.select_list.append(new_row) 203 path = self.select_list.index(new_row) 204 self.row_inserted(path,self.get_iter(path))
205 206
207 - def change_row(self, iter, **values):
208 row = self.get_row(iter) 209 row.set(**values) 210 self.row_changed(self.get_path(iter),iter)
211 212
213 - def get_row(self, iter):
214 try: 215 return self.select_list[self.get_path(iter)[0]] 216 except: 217 return None
218
219 - def del_row(self, iter):
220 row = self.get_row(iter) 221 del_id = row.id 222 path = self.get_path(iter) 223 self.select_list.remove(row) 224 self.row_deleted(path) 225 self.sql_object.delete(del_id)
226 227 ###the following section contains the Controller classes 228 229 ###wreg =[(gtk.Entry,'set_text','get_text')] 230
231 -class SqlController(object):
232 """This Class controls representation and manipulation of row data (SQLObject Instance) through 233 pygtk widgets""" 234 __row = None 235 widgets = [] 236
237 - def is_dirty(self):
238 if not self.__row: 239 return False 240 is_dirty = False 241 for w in self.widgets: 242 field_name, widget = w 243 field_name = '_SO_val_'+field_name 244 if self.get_widget_value(widget) != self.__row.__dict__[field_name]: #!!! 245 is_dirty = True 246 return is_dirty
247
248 - def set_widget_value(self, widget, value):
249 """Sets the value of widget. If the widget is unknown it will try to call set_value()""" 250 if type(widget) is gtk.Entry: 251 widget.set_text(str(value)) 252 elif type(widget) is gtk.TextView: 253 buffer = widget.get_buffer() 254 buffer.set_text(str(value)) 255 elif type(widget) is gtk.FileChooser: 256 widget.set_filename(str(value)) 257 elif type(widget) is gtk.SpinButton: 258 widget.set_value(value) 259 elif type(widget) is gtk.ScaleButton: 260 widget.set_value(value) 261 else : widget.set_value(value)
262
263 - def get_widget_value(self, widget):
264 """returns the value of widget. If widget is unknown, it will try to call get_value(). 265 So, if you write your own widgets or compound widgets, all you have to do is provide a 266 method get_value() in order to be able to use it with the controller.""" 267 if type(widget) is gtk.Entry: 268 return widget.get_text() 269 elif type(widget) is gtk.TextView: 270 buffer = widget.get_buffer() 271 return buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()) 272 elif type(widget) is gtk.FileChooser: 273 return widget.get_filename() 274 elif type(widget) is gtk.SpinButton: 275 return widget.get_value() 276 elif type(widget) is gtk.ScaleButton: 277 return widget.get_value() 278 elif type(widget) is widgets.DateEntry(): 279 return widget.get_value() 280 else: 281 return widget.get_value()
282 283
284 - def reset(self):
285 """Sets the widget contents to the values of the assigned SqlObject instance. This can also be used 286 to explicitely update the widgets' contents, for example when widgets are added to the controller 287 after an SqlObject instance has been set, or simply to implement a reset button in a data form.""" 288 if self.__row: 289 for w in self.widgets: 290 field_name, widget = w 291 field_name = '_SO_val_'+field_name 292 value = self.__row.__dict__[field_name] 293 self.set_widget_value(widget, value) 294 else: 295 for w in self.widgets: 296 field_name, widget = w 297 field_name = '_SO_val_'+field_name 298 self.set_widget_value(widget, "")
299 300
301 - def set_row(self, sqlobj_instance):
302 """row is an sqlobject instance or None""" 303 if sqlobj_instance: 304 self.__row = sqlobj_instance 305 self.reset()
306
307 - def get_row(self):
308 return self.__row
309
310 - def commit(self):
311 """writes the values of the widgets to the assigned SqlObject instance fields. This implies 312 that the values are written to the database, unless lazy update is set. See SqlObject 313 documentation for more details""" 314 values = dict() 315 for w in self.widgets: 316 value = None 317 field_name, widget = w 318 value = self.get_widget_value(widget) 319 print value 320 if value: 321 values[field_name] = value 322 self.__row.set(**values)
323
324 - def add_widget(self, field_name, widget, validator=None):
325 """adds the widget to the controller. If a validator function is given, it will be connected 326 to the focus out event of the widget.""" 327 self.widgets.append((field_name, widget)) 328 if validator: 329 widget.connect("focus-out-event", validator)
330
331 - def set_editable(self,editable=True):
332 """calls set_editable of all the widgets assigned to the controller. You should provide a method 333 set_editable(True|False) with your own compound widgets. If you don't, it won't rise an an exception 334 but obviously it won't work either.""" 335 for w in self.widgets: 336 field_name, widget = w 337 if hasattr(widget, 'set_editable'): 338 widget.set_editable(editable)
339 340
341 -class SqlListController(SqlController):
342 """A controller for navigating through a SqlListModel"""
343 - def __init__(self, sql_list_model):
344 self.model = sql_list_model 345 self.iter = self.model.get_iter_first() 346 self.set_row(self.model.get_row(self.iter))
347
348 - def next(self):
349 """Sets the controller to the next SqlObject Instance in the list""" 350 if not self.iter: #case of an empty table 351 return 352 if self.is_dirty(): 353 self.commit() 354 if self.model.iter_next(self.iter): 355 self.iter = self.model.iter_next(self.iter) 356 self.set_row(self.model.get_row(self.iter))
357
358 - def previous(self):
359 if not self.iter: #case of an empty table 360 return 361 """Sets the controller to the previous SqlObject Instance in the list""" 362 if self.is_dirty(): 363 self.commit() 364 self.iter = self.model.iter_previous(self.iter) 365 self.set_row(self.model.get_row(self.iter))
366