Merge lp:~rick-rickspencer3/quidgets/precise into lp:quidgets
- precise
- Merge into trunk
Proposed by
Rick Spencer
Status: | Merged |
---|---|
Merged at revision: | 166 |
Proposed branch: | lp:~rick-rickspencer3/quidgets/precise |
Merge into: | lp:quidgets |
Diff against target: |
4084 lines (+997/-2064) 14 files modified
quickly/widgets/asynch_task_progressbox.py (+0/-310) quickly/widgets/conventions.py (+0/-2) quickly/widgets/couch_grid.py (+0/-458) quickly/widgets/dictionary_grid.py (+32/-32) quickly/widgets/grid_column.py (+54/-59) quickly/widgets/grid_filter.py (+692/-698) quickly/widgets/media_player_box.py (+61/-58) quickly/widgets/press_and_hold_button.py (+45/-8) quickly/widgets/tests/test_asycnh_task_progress_box.py (+0/-51) quickly/widgets/tests/test_couch_grid.py (+0/-284) quickly/widgets/tests/test_dictionary_grid.py (+7/-8) quickly/widgets/text_editor.py (+34/-31) quickly/widgets/url_fetch_progressbox.py (+39/-35) quickly/widgets/web_cam_box.py (+33/-30) |
To merge this branch: | bzr merge lp:~rick-rickspencer3/quidgets/precise |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Terry (community) | Approve | ||
Review via email: mp+96077@code.launchpad.net |
Commit message
Migrated quickly widgets to GObeject Introspection, so they will work with new Quickly projects.
Description of the change
1. deleted couchgrid, since DesktopCouch is no longer recommended (there is currently no upgrade path for apps that used CouchGrid in the past)
2. update all other quidgets to use GOI.
3. ensured all tests ran and passed.
To post a comment you must log in.
Revision history for this message
Michael Terry (mterry) wrote : | # |
Looked into that warning, and it's harmless. Just comes from CheckColumns using the generic GridColumn intializer.
I pushed after porting the GStreamer code to use python-gi so that the gobject module doesn't get imported that way.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file 'quickly/widgets/asynch_task_progressbox.py' |
2 | --- quickly/widgets/asynch_task_progressbox.py 2010-09-11 19:59:30 +0000 |
3 | +++ quickly/widgets/asynch_task_progressbox.py 1970-01-01 00:00:00 +0000 |
4 | @@ -1,310 +0,0 @@ |
5 | -### BEGIN LICENSE |
6 | -# Copyright (C) 2010 Rick Spencer rick.spencer@canonical.com |
7 | -#This program is free software: you can redistribute it and/or modify it |
8 | -#under the terms of the GNU General Public License version 3, as published |
9 | -#by the Free Software Foundation. |
10 | -# |
11 | -#This program is distributed in the hope that it will be useful, but |
12 | -#WITHOUT ANY WARRANTY; without even the implied warranties of |
13 | -#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
14 | -#PURPOSE. See the GNU General Public License for more details. |
15 | -# |
16 | -#You should have received a copy of the GNU General Public License along |
17 | -#with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | -### END LICENSE |
19 | - |
20 | -try: |
21 | - import pygtk |
22 | - pygtk.require("2.0") |
23 | - import gtk |
24 | - import threading |
25 | - import time |
26 | - import gobject |
27 | - import gettext |
28 | - from gettext import gettext as _ |
29 | - gettext.textdomain('quickly-widgets') |
30 | - |
31 | -except: |
32 | - print "couldn't load depencies" |
33 | - |
34 | -class AsynchTaskProgressBox( gtk.HBox ): |
35 | - """AsynchTaskProgressBox: encapsulates a pulstating progressbar, a cancel |
36 | - button, and a long running task. Use an AsynchTaskProgressBox when you want |
37 | - a window to perform a long running task in the background without freezing |
38 | - the UI for the user. |
39 | - |
40 | - """ |
41 | - |
42 | - def __init__(self, run_function, params = None, cancelable = True): |
43 | - """Create an AsycnTaskProgressBox |
44 | - |
45 | - Keyword arguments: |
46 | - run_function -- the function to run asynchronously |
47 | - params -- optional dictionary of parameters to be pass into run_function |
48 | - cancelable -- optional value to determine whether to show cancel button. Defaults to True. |
49 | - Do not use a value with the key of 'kill' in the params dictionary |
50 | - |
51 | - """ |
52 | - |
53 | - gtk.HBox.__init__( self, False, 2 ) |
54 | - |
55 | - self.progressbar = gtk.ProgressBar() |
56 | - self.progressbar.show() |
57 | - self.pack_start(self.progressbar, True) |
58 | - |
59 | - self.cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL) |
60 | - if cancelable: |
61 | - self.cancel_button.show() |
62 | - if params is None: |
63 | - params = {} |
64 | - params["update_progress_function"] = self.update |
65 | - self.cancel_button.set_sensitive(False) |
66 | - self.cancel_button.connect("clicked",self.__stop_clicked) |
67 | - self.pack_end(self.cancel_button, False) |
68 | - |
69 | - self.run_function = run_function |
70 | - self.pulse_thread = None |
71 | - self.work_thread = None |
72 | - self.params = params |
73 | - |
74 | - self.connect("destroy", self.__destroy) |
75 | - |
76 | - __gsignals__ = {'complete' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
77 | - (gobject.TYPE_PYOBJECT,)), |
78 | - 'cancelrequested' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
79 | - (gobject.TYPE_PYOBJECT,)) |
80 | - } |
81 | - |
82 | - def start(self, caption = "Working"): |
83 | - """executes run_function asynchronously and starts pulsating the progressbar |
84 | - Keyword arguments: |
85 | - caption -- optional text to display in the progressbar |
86 | - """ |
87 | - #Throw an exception if the user tries to start an operating thread |
88 | - if self.pulse_thread != None: |
89 | - raise RuntimeError("AsynchTaskProgressBox already started.") |
90 | - |
91 | - #Create and start a thread to run the users task |
92 | - #pass in a callback and the user's params |
93 | - self.work_thread = KillableThread(self.run_function, self.__on_complete, self.params) |
94 | - self.work_thread.start() |
95 | - |
96 | - #create a thread to display the user feedback |
97 | - self.pulse_thread = PulseThread(self.progressbar, caption) |
98 | - self.pulse_thread.start() |
99 | - |
100 | - #enable the button so the user can try to kill the task |
101 | - self.cancel_button.set_sensitive( True ) |
102 | - |
103 | - def update(self, fraction = None, displaytext = "Working"): |
104 | - """updates the progress bar with a given percentage and/or changes the |
105 | - caption. |
106 | - Keyword arguments: |
107 | - fraction -- the current percentage complete |
108 | - displaytext -- the new caption to display""" |
109 | - if self.pulse_thread != None: |
110 | - self.pulse_thread.update(fraction, displaytext) |
111 | - |
112 | - #call back function for after run_function returns |
113 | - def __on_complete( self, data ): |
114 | - self.emit("complete", data) |
115 | - self.kill() |
116 | - |
117 | - #call back function for cancel button |
118 | - def __stop_clicked( self, widget, data = None ): |
119 | - self.cancel() |
120 | - |
121 | - def cancel(self): |
122 | - self.kill() |
123 | - #emit the cancelrequested event |
124 | - #note that this only signals that the kill function was called |
125 | - #the thread may or may not have actually stopped |
126 | - self.emit("cancelrequested", self) |
127 | - |
128 | - def kill( self ): |
129 | - """ |
130 | - Stops pulstating the progressbar if the progressbar is working. |
131 | - Sets the value of 'kill' to True in the run_function. |
132 | - |
133 | - """ |
134 | - |
135 | - #stop the pulse_thread and remove a reference to it if there is one |
136 | - if self.pulse_thread != None: |
137 | - self.pulse_thread.kill() |
138 | - self.pulse_thread = None |
139 | - |
140 | - #disable the cancel button since the task is about to be told to stop |
141 | - gobject.idle_add(self.__disable_cancel_button) |
142 | - |
143 | - #tell the users function tostop if it's thread exists |
144 | - if self.work_thread != None: |
145 | - self.work_thread.kill() |
146 | - |
147 | - #called when the widget is destroyed, attempts to clean up |
148 | - #the work thread and the pulse thread |
149 | - def __destroy(self, widget, data = None): |
150 | - if self.work_thread != None: |
151 | - self.work_thread.kill() |
152 | - if self.pulse_thread != None: |
153 | - self.pulse_thread.kill() |
154 | - |
155 | - def __disable_cancel_button(self): |
156 | - gtk.gdk.threads_enter() |
157 | - self.cancel_button.set_sensitive( False ) |
158 | - gtk.gdk.threads_leave() |
159 | - |
160 | -class PulseThread ( threading.Thread ): |
161 | - """Class for use by AsynchTaskProgressBox. Not for general use. |
162 | - |
163 | - """ |
164 | - def __init__(self,progressbar,displaytext = _("Working")): |
165 | - threading.Thread.__init__(self) |
166 | - self.displaytext = displaytext |
167 | - self.setDaemon(False) |
168 | - self.progressbar = progressbar |
169 | - self.__kill = False |
170 | - self.fraction = float(0) |
171 | - |
172 | - def kill(self): |
173 | - self.__kill = True |
174 | - |
175 | - def update(self, fraction, displaytext): |
176 | - self.displaytext = displaytext |
177 | - self.fraction = fraction |
178 | - |
179 | - #As a subclass of Thread, this function runs when start() is called |
180 | - #It will cause the progressbar to pulse, showing that a task is running |
181 | - def run ( self ): |
182 | - self.progressbar.set_text(self.displaytext) |
183 | - #keep running until the __kill flag is set to True |
184 | - while not self.__kill: |
185 | - time.sleep(.1) |
186 | - #get ahold of the UI thread and command the progress bar to pulse |
187 | - gtk.gdk.threads_enter() |
188 | - if self.fraction == 0: |
189 | - self.progressbar.pulse() |
190 | - else: |
191 | - self.progressbar.set_fraction(self.fraction) |
192 | - self.progressbar.set_text(self.displaytext) |
193 | - gtk.gdk.threads_leave() |
194 | - #before exiting, reset the progressbar to show that no task is running |
195 | - gtk.gdk.threads_enter() |
196 | - self.progressbar.set_fraction(0) |
197 | - self.progressbar.set_text("") |
198 | - gtk.gdk.threads_leave() |
199 | - |
200 | -class KillableThread( threading.Thread ): |
201 | - """Class for use by AsynchTaskProgressBox. Not for general use. |
202 | - |
203 | - """ |
204 | - def __init__(self,run_function, on_complete, params = None): |
205 | - threading.Thread.__init__(self) |
206 | - self.setDaemon(False) |
207 | - self.run_function = run_function |
208 | - self.params = params |
209 | - self.on_complete = on_complete |
210 | - |
211 | - #As a subclass of Thread, this function runs when start() is called |
212 | - #It will run the user's function on this thread |
213 | - def run( self ): |
214 | - #set up params and include the kill flag |
215 | - if self.params == None: |
216 | - self.params = {} |
217 | - self.params["kill"] = False |
218 | - #tell the function to run |
219 | - data = self.run_function(self.params) |
220 | - #return any data from the function so it can be sent in the complete signal |
221 | - self.on_complete(data) |
222 | - |
223 | - #Tell the user's function that it should stop |
224 | - #Note the user's function may not check this |
225 | - def kill( self ): |
226 | - self.params["kill"] = True |
227 | - |
228 | -class TestWindow(gtk.Window): |
229 | - """For testing and demonstrating AsycnTaskProgressBox. |
230 | - |
231 | - """ |
232 | - def __init__(self): |
233 | - #create a window a VBox to hold the controls |
234 | - gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) |
235 | - self.set_title("AsynchTaskProgressBox Test Window") |
236 | - windowbox = gtk.VBox(False, 2) |
237 | - windowbox.show() |
238 | - self.add(windowbox) |
239 | - |
240 | - #create params for use by the function that should run asynchronously |
241 | - params = {"start": 100, "stop": 110} |
242 | - |
243 | - #pass in the function and the params, then add to the window |
244 | - self.thread_progressbox = AsynchTaskProgressBox(self.asynch_function, params) |
245 | - self.thread_progressbox.show() |
246 | - windowbox.add(self.thread_progressbox) |
247 | - |
248 | - #start the task, and set the text for the progressbar to "Testing" |
249 | - #This will start the function and start the progressbar pulsating |
250 | - self.thread_progressbox.start("Testing") |
251 | - |
252 | - #connect to the complete event to respond when the task is complete |
253 | - self.thread_progressbox.connect("complete",self.complete_function) |
254 | - |
255 | - #connect to the cancel requested event for demonstration purposes |
256 | - self.thread_progressbox.connect("cancelrequested", self.canceled_function) |
257 | - |
258 | - #create a button for starting the task and add it to the window |
259 | - start_button = gtk.Button(stock=gtk.STOCK_EXECUTE) |
260 | - start_button.show() |
261 | - windowbox.add(start_button) |
262 | - start_button.connect("clicked",self.start_clicked) |
263 | - self.show() |
264 | - |
265 | - #finish wiring up the window |
266 | - self.connect("destroy", self.destroy) |
267 | - |
268 | - #start up gtk.main in a threaded environment |
269 | - gtk.gdk.threads_init() |
270 | - gtk.gdk.threads_enter() |
271 | - gtk.main() |
272 | - gtk.gdk.threads_leave() |
273 | - |
274 | - #called when the window is destroyed |
275 | - def destroy(self, widget, data = None): |
276 | - gtk.main_quit() |
277 | - |
278 | - #start the AsynchTaskProgressBox when the button is clicked |
279 | - def start_clicked(self, widget, data = None): |
280 | - self.thread_progressbox.start("Testing") |
281 | - |
282 | - #The function to run asynchronously |
283 | - def asynch_function( self, params ): |
284 | - # do something interminate and cpu intensive at startup |
285 | - print "starting..." |
286 | - time.sleep(2) |
287 | - #pull values from the params that were set above |
288 | - total = float(abs(params["stop"]-params["start"])) |
289 | - for x in range(params["start"],params["stop"]): |
290 | - #check if to see if the user has told the task to stop |
291 | - if params["kill"] == True: |
292 | - #return a string if the user stopped the task |
293 | - return "stopped at " + str(x) |
294 | - else: |
295 | - #if the user did not try to stop the task, go ahead and do something |
296 | - print x |
297 | - fraction=abs(x-params["start"])/total |
298 | - # call the update_progress_function function with the current percentage and caption |
299 | - params["update_progress_function"](fraction=fraction, displaytext=str(x)) |
300 | - #this is a processor intensive task, so |
301 | - #sleep the loop to keep the UI from bogging down |
302 | - time.sleep(.5) |
303 | - #if the loop completes, return a string |
304 | - return "counted all" |
305 | - |
306 | - #called when the task completes |
307 | - def complete_function(self, widget, data = None): |
308 | - print "returned " + str(data) |
309 | - |
310 | - def canceled_function(self, widget, data=None): |
311 | - print "cancel requested" |
312 | -if __name__== "__main__": |
313 | - test = TestWindow() |
314 | - |
315 | |
316 | === modified file 'quickly/widgets/conventions.py' |
317 | --- quickly/widgets/conventions.py 2010-11-21 19:20:40 +0000 |
318 | +++ quickly/widgets/conventions.py 2012-03-06 08:52:21 +0000 |
319 | @@ -13,8 +13,6 @@ |
320 | #with this program. If not, see <http://www.gnu.org/licenses/>. |
321 | ### END LICENSE |
322 | |
323 | -import gtk |
324 | -import gobject |
325 | from grid_column import StringColumn, CurrencyColumn, CheckColumn |
326 | from grid_column import IntegerColumn, TagsColumn, DateColumn |
327 | |
328 | |
329 | === removed file 'quickly/widgets/couch_grid.py' |
330 | --- quickly/widgets/couch_grid.py 2011-08-19 17:22:14 +0000 |
331 | +++ quickly/widgets/couch_grid.py 1970-01-01 00:00:00 +0000 |
332 | @@ -1,458 +0,0 @@ |
333 | -# -*- coding: utf-8 -*- |
334 | -### BEGIN LICENSE |
335 | -# Copyright (C) 2010 Rick Spencer rick.spencer@canonical.com |
336 | -#This program is free software: you can redistribute it and/or modify it |
337 | -#under the terms of the GNU General Public License version 3, as published |
338 | -#by the Free Software Foundation. |
339 | -# |
340 | -#This program is distributed in the hope that it will be useful, but |
341 | -#WITHOUT ANY WARRANTY; without even the implied warranties of |
342 | -#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
343 | -#PURPOSE. See the GNU General Public License for more details. |
344 | -# |
345 | -#You should have received a copy of the GNU General Public License along |
346 | -#with this program. If not, see <http://www.gnu.org/licenses/>. |
347 | -### END LICENSE |
348 | - |
349 | -"""A Treeview for Desktop CouchDB |
350 | -Displays and persists data in desktopcouch, handles presentation |
351 | -of the UI in a Gtk.TreeView, as well handles persistence to a backend |
352 | -desktopcouch database. |
353 | - |
354 | -Using |
355 | -#define the database and record type |
356 | -database = "couch_widget_test" |
357 | -record_type="test_record_type" |
358 | - |
359 | -#create a dictionary if you don't already have one |
360 | -dicts = [{"test?":True,"price":100,"foo count":100,"Key4":"1004"}, |
361 | - {"test?":True,"price":100,"foo count":100,"Key4":"1004"}, |
362 | - {"test?":True,"price":100,"foo count":100,"Key4":"1004"}] |
363 | - |
364 | -#create the CouchGrid |
365 | -cg = CouchGrid(database, record_type=record_type, dictionaries=dicts) |
366 | - |
367 | -Configuring |
368 | -#Define columns to display |
369 | -keys=["price","test?"] |
370 | -cg = CouchGrid(database, record_type=record_type, dictionaries=dicts,keys=keys) |
371 | - |
372 | -#Define column types to use |
373 | -hints = {"price": StringColumn} |
374 | -cg = CouchGrid(database, record_type=record_type, dictionaries=dicts,keys=keys, type_hints = hints) |
375 | - |
376 | -#A CouchGrid is a Dictionary Grid whcih is a TreeView, |
377 | -#so you can use DicationaryGrid and TreeView members |
378 | -cg.editable = True |
379 | -cg.get_column(0).set_title("Price") |
380 | - |
381 | -Extending |
382 | -To change the way CouchGrid persists data, change _refresh_treeview to |
383 | -handle persistence of data if needed, calling DictionaryGrid._populate_treeivew |
384 | -to handle the UI. You should do the same with append_row. |
385 | - |
386 | -You may also want to override _edited and _edited_toggled to handle persistence |
387 | -when the UI is changed. |
388 | - |
389 | -It is only useful to extend CouchGrid if you are using desktopcouch for |
390 | -persistence. Otherwise, derive from DictionaryGrid. |
391 | - |
392 | -""" |
393 | - |
394 | -import gtk |
395 | -import gobject |
396 | -from desktopcouch.records.server import CouchDatabase |
397 | -from desktopcouch.records.record import Record |
398 | -from quickly.widgets.dictionary_grid import DictionaryGrid |
399 | -from quickly.widgets.grid_column import CheckColumn |
400 | - |
401 | -class CouchGrid(DictionaryGrid): |
402 | - def __init__( |
403 | - self, database_name, record_type=None, dictionaries=None, editable=False, keys=None, type_hints=None, uri=None): |
404 | - """Create a new Couchwidget |
405 | - arguments: |
406 | - database_name - specify the name of the database in the desktop |
407 | - couchdb to use. If the specified database does not exist, it |
408 | - will be created. |
409 | - |
410 | - optional arguments: |
411 | - record_type - a string to specify the record_type to use in |
412 | - retrieving and creating records. Note that if no records exist |
413 | - in the CouchDB then the keys argument must also be used or |
414 | - a RuntimeError will result. |
415 | - |
416 | - dictionaries - a list of dictionaries to initialize in the |
417 | - grid. If these haven't been added to desktopcouch, the will |
418 | - be automatically persisted and updated using the recored_type |
419 | - specified. Any previously saved data of the same record_type will |
420 | - also be displayed. |
421 | - |
422 | - keys - a list of strings specifying keys to use in |
423 | - the columns of the CouchGrid. The keys will also be used for the |
424 | - column titles and keys in desktop couch. |
425 | - |
426 | - If a record does not contain a value for a specified key |
427 | - the CouchGrid will simply display an empty cell of the |
428 | - appropriate type. If the widget is set to editable, |
429 | - the user will be able to add values to the database. |
430 | - |
431 | - The types for the columns will be inferred by the key based on |
432 | - some conventions. the key "id" is assumed to be an integer, as |
433 | - is any key ending in " count". A key ending in "?" is assumed |
434 | - to be a Boolean displayed with a checkbox. The key "price" is |
435 | - assumed to be currency, as is any key ending in "count". There |
436 | - may be others. Defaults can be overridden using type-hints. All |
437 | - other keys will be assumed to be strings. |
438 | - |
439 | - type-hints - a dictionary containing keys specificed for the |
440 | - TreeView and GridColumns. Used to override types inferred |
441 | - by convention, or for changing the type of a column from |
442 | - the default of a string to something else. |
443 | - |
444 | - uri - A uri for the DesktopCouch. This is only used to |
445 | - choose a Couch database running remotely. The default is |
446 | - to use the local desktopcouch database. |
447 | - |
448 | - """ |
449 | - |
450 | - if type(database_name) is not type(str()): |
451 | - raise TypeError("database_name is required and must be a string") |
452 | - |
453 | - #set up the database before trying to use it |
454 | - self.uri = uri |
455 | - self._record_type = None |
456 | - self._db = None |
457 | - if record_type is not None: |
458 | - self._record_type = record_type |
459 | - |
460 | - #QUESTION: What is the purpose of this? |
461 | - #if dictionaries is not None and keys is None: |
462 | - # DictionaryGrid.__init__(self, None, editable, keys, type_hints) |
463 | - #else: |
464 | - # DictionaryGrid.__init__(self, None, editable, keys, type_hints) |
465 | - |
466 | - # Have to leave it in for now. But this is certainly a bug. |
467 | - # Note: adding dicts to a CG adds to empty cols in the model between the key values and the couch dict. |
468 | - if dictionaries is not None and keys is None: |
469 | - DictionaryGrid.__init__(self, None, editable, keys, type_hints) |
470 | - else: |
471 | - DictionaryGrid.__init__(self, None, editable, keys, type_hints) |
472 | - |
473 | - |
474 | - """ |
475 | - if dictionaries is not None and keys is not None: |
476 | - DictionaryGrid.__init__(self, dictionaries, editable, keys, type_hints) |
477 | - elif keys is None: |
478 | - DictionaryGrid.__init__(self, dictionaries, editable, None, type_hints) |
479 | - elif dictionaries is None: |
480 | - DictionaryGrid.__init__(self, None, editable, keys, type_hints) |
481 | - """ |
482 | - |
483 | - |
484 | - if self.uri: |
485 | - self._db = CouchDatabase(database_name, create=True, uri=self.uri) |
486 | - else: |
487 | - self._db = CouchDatabase(database_name, create=True) |
488 | - |
489 | - if dictionaries is not None: |
490 | - for d in dictionaries: |
491 | - self._persist_dict_to_couch(d) |
492 | - |
493 | - self._refresh_treeview() |
494 | - |
495 | - @property |
496 | - def database(self): |
497 | - """database - gets an instance to the CouchDB. |
498 | - Set to a string to change the database. |
499 | - |
500 | - """ |
501 | - return self._db |
502 | - |
503 | - @database.setter |
504 | - def database(self, db_name): |
505 | - if self.uri: |
506 | - self._db = CouchDatabase(db_name, create=True, uri=self.uri) |
507 | - else: |
508 | - self._db = CouchDatabase(db_name, create=True) |
509 | - if self.record_type != None: |
510 | - self._refresh_treeview()#first time treeview is reset |
511 | - |
512 | - @property |
513 | - def record_type(self): |
514 | - """record_type - a string specifying the record type of |
515 | - the documents to retrieve from the CouchDB. |
516 | - |
517 | - Will cause the TreeView to refresh when set. |
518 | - """ |
519 | - return self._record_type |
520 | - |
521 | - @record_type.setter |
522 | - def record_type(self, record_type): |
523 | - |
524 | - #store the record type string |
525 | - self._record_type = record_type |
526 | - self._refresh_treeview() |
527 | - |
528 | - @property |
529 | - def selected_record_ids(self): |
530 | - """ selected_record_ids - a list of document ids that are |
531 | - selected in the CouchGrid. Throws an IndexError if |
532 | - a specified id is not found in the list when setting |
533 | - this property. |
534 | - |
535 | - This property is read/write |
536 | - |
537 | - """ |
538 | - ids = [] |
539 | - for row in self.selected_rows: |
540 | - id_ = None |
541 | - |
542 | - if "__desktopcouch_id" in row: |
543 | - id_ = row["__desktopcouch_id"] |
544 | - ids.append(id_) |
545 | - return ids |
546 | - |
547 | - @selected_record_ids.setter |
548 | - def selected_record_ids(self, indexes): |
549 | - rows = [] #a list of rows to select |
550 | - for id in indexes: |
551 | - id_found = False #track if the id was found |
552 | - |
553 | - for i,r in enumerate(self.list_store): |
554 | - dictionary = r[len(self.keys)] #this dictionary always last column |
555 | - if "__desktopcouch_id" in dictionary: |
556 | - if dictionary["__desktopcouch_id"] == id: |
557 | - id_found = True #id was good |
558 | - if r not in rows: #don't have duplicates to select |
559 | - rows.append(i) |
560 | - if not id_found: #stop if a requested id was not in the list |
561 | - raise IndexError("id %s not found" %id) |
562 | - |
563 | - #select the requested ids |
564 | - selection = self.get_selection() |
565 | - selection.unselect_all() |
566 | - for r in rows: |
567 | - selection.select_path(r) |
568 | - |
569 | - def remove_selected_rows(self, delete=False): |
570 | - rows_to_delete = self.selected_rows |
571 | - if delete: |
572 | - for r in rows_to_delete: |
573 | - self.database.delete_record(r["__desktopcouch_id"]) |
574 | - DictionaryGrid.remove_selected_rows(self) |
575 | - |
576 | - def _refresh_treeview(self): |
577 | - """ |
578 | - _refresh_treeview: internal function to handle rebuilding |
579 | - the gtk.TreeView along with columns and cell renderers. extends |
580 | - DictionaryGrid._refresh_treeview by retrieving stored desktopcouch |
581 | - records before calling DictionaryGrid._refresh_treeview. |
582 | - |
583 | - _refresh_treeview is not typically called directly, |
584 | - but may be useful to override in subclasses. |
585 | - |
586 | - """ |
587 | - |
588 | - #if the database is not set up, just return |
589 | - if self._db is None or self._record_type is None: |
590 | - return |
591 | - |
592 | - #if keys aren't set, infer them from the collection |
593 | - if len(self._dictionaries) > 0 and self.keys is None: |
594 | - self._infer_keys_from_dictionaries() |
595 | - |
596 | - #retrieve the docs for the record_type, if any |
597 | - results = self._db.get_records( |
598 | - record_type=self._record_type,create_view=True) |
599 | - |
600 | - |
601 | - #if there are no rows and no keys set, there is no |
602 | - #way to build the grid, just raise an error |
603 | - if len(results) == 0 and self._keys is None: |
604 | - raise RuntimeError("Cannot infer columns for CouchGrid") |
605 | - |
606 | - dicts = [] |
607 | - for r in results: |
608 | - d = r.value |
609 | - |
610 | - #hmmm, maybe make these so they get hidden rather than delete them |
611 | - #hide the desktopcouch variabls |
612 | - for key in d: |
613 | - if key.startswith("_") and not key.startswith("__desktopcouch"): |
614 | - d["__desktopcouch" + key] = d[key] |
615 | - del(d[key]) |
616 | - |
617 | - d["__record_type"] = d["record_type"] |
618 | - del(d["record_type"]) |
619 | - dicts.append(d) |
620 | - |
621 | - self._dictionaries = dicts |
622 | - DictionaryGrid._refresh_treeview(self) |
623 | - |
624 | - |
625 | - # CheckColumn is special because it is a one-shot change. A StringColumn |
626 | - # should not be saved for each keystroke, but CheckColumn should. |
627 | - for c in self.get_columns(): |
628 | - if type(c) == CheckColumn: |
629 | - c.renderer.connect("toggled",self._edited_toggled, c) |
630 | - else: |
631 | - c.renderer.connect("edited",self._edited, c) |
632 | - |
633 | - def append_row(self, dictionary): |
634 | - """append_row: add a row to the TreeView and to DesktopCouch. |
635 | - If keys are already set up only the the keys in the dictionary |
636 | - matching the keys used for columns will be displayed, though |
637 | - all the key value pairs will be saved to the DesktopCouch. |
638 | - If no keys are set up, and this is the first row, keys will be |
639 | - inferred from the dictionary keys. |
640 | - |
641 | - arguments: |
642 | - dictionary - a dictionary to add to the Treeview and to DesktopCouch |
643 | - |
644 | - """ |
645 | - |
646 | - if dictionary is None: |
647 | - dictionary = {} |
648 | - |
649 | - #Here we add rows to desktopcouch if needed |
650 | - if "__desktopcouch_id" not in dictionary: |
651 | - self._persist_dict_to_couch(dictionary) |
652 | - DictionaryGrid.append_row(self,dictionary) |
653 | - |
654 | - def _persist_dict_to_couch(self,dictionary): |
655 | - """ _persist_dict_to_couch - internal implementation. may be useful |
656 | - a subclass of CouchGrid, but not normally called directly. |
657 | - |
658 | - """ |
659 | - |
660 | - dictionary["record_type"] = self.record_type |
661 | - rec = Record(dictionary) |
662 | - #meh, best not to save an empty row |
663 | - # Perhaps we should raise an exception if not? |
664 | - if len(dictionary) > 1: |
665 | - doc_id = self._db.put_record(rec) |
666 | - dictionary["__desktopcouch_id"] = doc_id |
667 | - dictionary["__record_type"] = self.record_type |
668 | - del(dictionary["record_type"]) |
669 | - |
670 | - |
671 | - def _edited_toggled(self, cell, path, col): |
672 | - """ _edited_toggled - internal signal handler. |
673 | - Updates the database if a cell in the Treeview |
674 | - has been edited special cased for CheckColumns. |
675 | - |
676 | - """ |
677 | - |
678 | - iter = self.list_store.get_iter(path) |
679 | - key = col.key |
680 | - active = not cell.get_active() |
681 | - self._edited(cell, path, active, col) |
682 | - |
683 | - def _edited(self, cell, path, new_val, col): |
684 | - """ _edited - internal signal handler. |
685 | - Updates the database if a cell in the Treeview |
686 | - has been edited. |
687 | - |
688 | - """ |
689 | - iter = self.list_store.get_iter(path) |
690 | - key = col.key |
691 | - dictionary = self.list_store.get_value(iter,len(self.keys)) |
692 | - |
693 | - if "__desktopcouch_id" not in dictionary: #the row has not been stored |
694 | - #create a document |
695 | - dictionary["record_type"] = self.record_type |
696 | - rec = Record(dictionary) |
697 | - doc_id = self._db.put_record(rec) |
698 | - dictionary["__desktopcouch_id"] = doc_id |
699 | - self.list_store.set_value(iter, len(self.keys), dictionary) |
700 | - |
701 | - else: #it has been saved |
702 | - #get the record id from the dictionary |
703 | - #then update the datbase with the change |
704 | - id = dictionary["__desktopcouch_id"] |
705 | - key = col.key |
706 | - self._db.update_fields(id,{key:new_val}) |
707 | - |
708 | -def __show_selected(widget, row, widgets): |
709 | - """Test function for selection properties of CouchGrid""" |
710 | - tv, cg = widgets |
711 | - disp = "Rows:\n" |
712 | - for r in cg.selected_rows: |
713 | - disp += str(r) + "\n" |
714 | - |
715 | - disp += "\n\n_Ids:\n" |
716 | - for r in cg.selected_record_ids: |
717 | - disp += str(r) + "\n" |
718 | - |
719 | - tv.get_buffer().set_text(disp) |
720 | - |
721 | -def __select_ids(widget, widgets): |
722 | - """Test function for selecting ids.""" |
723 | - entry, cg, lbl = widgets |
724 | - cg.selected_record_ids = entry.get_text().split(",") |
725 | - |
726 | -if __name__ == "__main__": |
727 | - """creates a test CouchGrid if called directly""" |
728 | - |
729 | - from quickly.widgets.grid_column import StringColumn |
730 | - |
731 | - #create and show a test window and container |
732 | - win = gtk.Window(gtk.WINDOW_TOPLEVEL) |
733 | - win.set_title("CouchGrid Test Window") |
734 | - win.connect("destroy",gtk.main_quit) |
735 | - win.show() |
736 | - vbox = gtk.VBox(False, False) |
737 | - vbox.show() |
738 | - win.add(vbox) |
739 | - |
740 | - #create a test widget with test database values |
741 | - dicts = [{"test?":True,"price":100,"foo count":100,"Key4":"1004"}, |
742 | - {"test?":True,"price":100,"foo count":100,"Key4":"1004"}, |
743 | - {"test?":True,"price":100,"foo count":100,"Key4":"1004"}] |
744 | - |
745 | - #create some settings |
746 | - database = "couch_widget_test" |
747 | - record_type="test_record_type" |
748 | - keys=["price","test?"] |
749 | - hints = {"price": StringColumn} |
750 | - |
751 | - #create it and part a bit |
752 | - cg = CouchGrid(database, record_type=record_type, dictionaries=dicts,keys=keys, type_hints = hints) |
753 | - cg.editable = True |
754 | - cg.get_column(0).set_title("Price") |
755 | - |
756 | - #finish out and run the test UI |
757 | - cg.show() |
758 | - vbox.pack_start(cg, False, True) |
759 | - hbox = gtk.HBox(False, 5) |
760 | - hbox.show() |
761 | - tv = gtk.TextView() |
762 | - tv.show() |
763 | - tv.set_wrap_mode(gtk.WRAP_CHAR) |
764 | - tv.set_size_request(300,-1) |
765 | - cg.connect("selection-changed",__show_selected, (tv,cg)) |
766 | - |
767 | - id_vbox = gtk.VBox(False, 5) |
768 | - id_vbox.show() |
769 | - |
770 | - fb_lbl = gtk.Label("paste ids into the edit box to select them") |
771 | - fb_lbl.show() |
772 | - |
773 | - entry = gtk.Entry() |
774 | - entry.show() |
775 | - |
776 | - btn = gtk.Button("select ids") |
777 | - btn.show() |
778 | - btn.connect("clicked", __select_ids, (entry,cg, fb_lbl)) |
779 | - |
780 | - id_vbox.pack_start(fb_lbl, False, False) |
781 | - id_vbox.pack_start(entry, False, False) |
782 | - id_vbox.pack_end(btn, False, False) |
783 | - |
784 | - hbox.pack_start(tv, False, False) |
785 | - vbox.pack_end(hbox, False, False) |
786 | - hbox.pack_end(id_vbox, False, False) |
787 | - |
788 | - #run the test app |
789 | - gtk.main() |
790 | - |
791 | |
792 | === modified file 'quickly/widgets/dictionary_grid.py' |
793 | --- quickly/widgets/dictionary_grid.py 2011-09-04 23:58:24 +0000 |
794 | +++ quickly/widgets/dictionary_grid.py 2012-03-06 08:52:21 +0000 |
795 | @@ -14,10 +14,10 @@ |
796 | #You should have received a copy of the GNU General Public License along |
797 | #with this program. If not, see <http://www.gnu.org/licenses/>. |
798 | ### END LICENSE |
799 | -"""A gtk.TreeView for Dictionaries |
800 | -Displays and persists data in a gtk.TreeView. Handles the |
801 | -set up of the gtk.TreeView, gtk.ListModel, gtk.TreeViewColumns, |
802 | -and gtk.CellRenderers. |
803 | +"""A Gtk.TreeView for Dictionaries |
804 | +Displays and persists data in a Gtk.TreeView. Handles the |
805 | +set up of the Gtk.TreeView, Gtk.ListModel, Gtk.TreeViewColumns, |
806 | +and Gtk.CellRenderers. |
807 | |
808 | Using |
809 | #create a dictionary if you don't already have one |
810 | @@ -40,7 +40,7 @@ |
811 | hints = {"price": StringColumn} |
812 | dg = CouchGrid(dictionaries=dicts,keys=keys, type_hints = hints) |
813 | |
814 | -#A CouchGrid is gtk.TreeView, so you can use gtk.TreeView members |
815 | +#A CouchGrid is Gtk.TreeView, so you can use Gtk.TreeView members |
816 | dg.get_column(0).set_title("Price") |
817 | |
818 | #Use the selection-changed signal and read from the DictionaryGrid |
819 | @@ -67,13 +67,13 @@ |
820 | |
821 | """ |
822 | |
823 | -import gtk |
824 | -import gobject |
825 | +from gi.repository import GObject |
826 | +from gi.repository import Gtk |
827 | import conventions |
828 | -from quickly.widgets.grid_column import StringColumn |
829 | +from grid_column import StringColumn |
830 | from grid_column import CheckColumn |
831 | |
832 | -class DictionaryGrid(gtk.TreeView): |
833 | +class DictionaryGrid(Gtk.TreeView): |
834 | __gtype_name__ = "DictionaryGrid" |
835 | |
836 | def __init__(self, dictionaries=None, editable = False, keys=None, type_hints=None): |
837 | @@ -102,7 +102,7 @@ |
838 | |
839 | """ |
840 | |
841 | - gtk.TreeView.__init__(self) |
842 | + Gtk.TreeView.__init__(self) |
843 | self.list_store = None |
844 | self.unfiltered_store = None |
845 | self._keys = keys |
846 | @@ -115,7 +115,7 @@ |
847 | self._type_hints = {} |
848 | else: |
849 | self._type_hints = type_hints |
850 | - self.get_selection().set_mode(gtk.SELECTION_MULTIPLE) |
851 | + self.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) |
852 | self._refresh_treeview() |
853 | |
854 | #signal handlers to track selection in the treeview |
855 | @@ -193,7 +193,7 @@ |
856 | # themselves, but for now this works. |
857 | |
858 | for column in self.get_columns(): |
859 | - column.set_editable(editable) |
860 | + column.set_editable(editable) |
861 | self._editable = editable |
862 | |
863 | @property |
864 | @@ -251,7 +251,7 @@ |
865 | def _refresh_treeview(self): |
866 | """ |
867 | _refresh_treeview: internal function to handle rebuilding |
868 | - the gtk.TreeView along with columns and cell renderers.. |
869 | + the Gtk.TreeView along with columns and cell renderers.. |
870 | |
871 | _refresh_treeview is not typically called directly, |
872 | but may be useful to override in subclasses. |
873 | @@ -350,7 +350,7 @@ |
874 | """ |
875 | remove_selected_rows: removes the rows currently selected |
876 | in the TreeView UI from the TreeView as well as the backing |
877 | - gtk.ListStore. |
878 | + Gtk.ListStore. |
879 | |
880 | """ |
881 | |
882 | @@ -361,11 +361,11 @@ |
883 | return |
884 | |
885 | #store the last selected row to reselect after removal |
886 | - next_to_select = rows[-1][0] + 1 - len(rows) |
887 | + next_to_select = rows[-1].get_indices()[0] + 1 - len(rows) |
888 | |
889 | #loop through and remove |
890 | |
891 | - if type(model) is not gtk.ListStore: |
892 | + if type(model) is not Gtk.ListStore: |
893 | iters = [model.get_model().get_iter(path) for path in rows] |
894 | store_iters = [] |
895 | |
896 | @@ -431,8 +431,8 @@ |
897 | |
898 | #create the liststore with the designated types |
899 | #the last column is always for storing the backing dict |
900 | - col_types.append(gobject.TYPE_PYOBJECT) |
901 | - self.list_store = gtk.ListStore(*col_types) |
902 | + col_types.append(GObject.TYPE_PYOBJECT) |
903 | + self.list_store = Gtk.ListStore(*col_types) |
904 | |
905 | for c in self.get_columns(): |
906 | self.__last_sorted_col = None |
907 | @@ -459,11 +459,11 @@ |
908 | self.__last_sorted_col.set_sort_indicator(False) |
909 | self.__last_sorted_col = column |
910 | |
911 | - __gsignals__ = {'cell-edited' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
912 | - (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), |
913 | + __gsignals__ = {'cell-edited' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
914 | + (GObject.TYPE_PYOBJECT,GObject.TYPE_PYOBJECT,GObject.TYPE_PYOBJECT,GObject.TYPE_PYOBJECT,GObject.TYPE_PYOBJECT)), |
915 | |
916 | - 'selection-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
917 | - (gobject.TYPE_PYOBJECT,)) |
918 | + 'selection-changed' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
919 | + (GObject.TYPE_PYOBJECT,)) |
920 | } |
921 | |
922 | def __show_selected(widget, selected_rows, data=None): |
923 | @@ -488,14 +488,14 @@ |
924 | {"key?": True, "price":33.00,"tags" : "ccc ddd eee","_foo":"bar","bing count":15}, |
925 | {"ID": 3, "tags" : "ddd eee fff","_foo":"bar"}, |
926 | {"ID": 4, "price":5.00,"_foo":"bar"}] |
927 | - #create and show a test window |
928 | - win = gtk.Window(gtk.WINDOW_TOPLEVEL) |
929 | + #create and show a test windowp |
930 | + win = Gtk.Window() |
931 | win.set_title("DictionaryGrid Test Window") |
932 | - win.connect("destroy",gtk.main_quit) |
933 | + win.connect("destroy",Gtk.main_quit) |
934 | win.show() |
935 | |
936 | #create a top level container |
937 | - vbox = gtk.VBox(False, False) |
938 | + vbox = Gtk.VBox(False, False) |
939 | vbox.show() |
940 | win.add(vbox) |
941 | |
942 | @@ -507,19 +507,19 @@ |
943 | |
944 | #show the control, add it to the window, and run the main loop |
945 | grid.show() |
946 | - vbox.pack_start(grid, False, True) |
947 | + vbox.pack_start(grid, False, False, 0) |
948 | |
949 | #create a test display area |
950 | - hbox = gtk.HBox(False, 5) |
951 | + hbox = Gtk.HBox(False, 5) |
952 | hbox.show() |
953 | - tv = gtk.TextView() |
954 | + tv = Gtk.TextView() |
955 | tv.show() |
956 | grid.connect("selection-changed",__show_selected, tv) |
957 | grid.connect("cell-edited",__on_edited, tv) |
958 | |
959 | - hbox.pack_start(tv, False, False) |
960 | - vbox.pack_end(hbox, False, False) |
961 | + hbox.pack_start(tv, False, False, 0) |
962 | + vbox.pack_end(hbox, False, False, 0) |
963 | |
964 | #run the test app |
965 | - gtk.main() |
966 | + Gtk.main() |
967 | |
968 | |
969 | === modified file 'quickly/widgets/grid_column.py' |
970 | --- quickly/widgets/grid_column.py 2011-09-04 23:58:24 +0000 |
971 | +++ quickly/widgets/grid_column.py 2012-03-06 08:52:21 +0000 |
972 | @@ -23,8 +23,8 @@ |
973 | to control the type of column used for a key in a dictionary. |
974 | |
975 | Customizing |
976 | -The column types in this module are all descendants of gtk.TreeView, so |
977 | -you can use all of the gtk.TreeView methods and properties to control |
978 | +The column types in this module are all descendants of Gtk.TreeView, so |
979 | +you can use all of the Gtk.TreeView methods and properties to control |
980 | how a grid column looks or works. |
981 | |
982 | #Find a grid column and change the title |
983 | @@ -34,7 +34,7 @@ |
984 | |
985 | Extending |
986 | To display data in a column with a string, such as to display words and |
987 | -numbers, you should extend StringColumn. Otherwise, extend gtk.TreeView |
988 | +numbers, you should extend StringColumn. Otherwise, extend Gtk.TreeView |
989 | directly. In either case, you will need to implement a set of functions. |
990 | |
991 | A Grid Column must track two different data, a "real" value, which is tracked |
992 | @@ -56,7 +56,7 @@ |
993 | a row does not contain a key, value pair for the specified column. For example |
994 | StringColumn returns an empty string ("") |
995 | |
996 | -A new column type will often require a specially configured gtk.CellRenderer. |
997 | +A new column type will often require a specially configured Gtk.CellRenderer. |
998 | If you are deriving from StringColumn, but are using a custom renderer, |
999 | you need to override the _initialize_renderer method, and set the |
1000 | columns renderer property to the renderer. You should also connect the |
1001 | @@ -68,8 +68,8 @@ |
1002 | _initialize_renderer: |
1003 | |
1004 | def _initialize_renderer( self, editable, index ): |
1005 | - self.renderer = gtk.CellRendererSpin() |
1006 | - adj = gtk.Adjustment(0,-10000000000,10000000000,1) |
1007 | + self.renderer = Gtk.CellRendererSpin() |
1008 | + adj = Gtk.Adjustment(0,-10000000000,10000000000,1) |
1009 | self.renderer.set_property("adjustment", adj) |
1010 | self.renderer.set_property("editable", editable) |
1011 | self.renderer.set_property("digits",2) |
1012 | @@ -89,26 +89,20 @@ |
1013 | """ |
1014 | |
1015 | |
1016 | - |
1017 | import sys |
1018 | import datetime |
1019 | import gettext |
1020 | from gettext import gettext as _ |
1021 | gettext.textdomain('quickly-widgets') |
1022 | |
1023 | -try: |
1024 | - import pygtk |
1025 | - pygtk.require("2.0") |
1026 | - import gtk |
1027 | - import gobject |
1028 | - import grid_filter |
1029 | - |
1030 | - |
1031 | -except Exception, inst: |
1032 | - print "some dependencies for GridFilter are not available" |
1033 | - raise inst |
1034 | - |
1035 | -class GridColumn( gtk.TreeViewColumn ): |
1036 | +import grid_filter |
1037 | + |
1038 | +from gi.repository import GObject |
1039 | +from gi.repository import Gtk |
1040 | +from gi.repository import Gdk |
1041 | + |
1042 | + |
1043 | +class GridColumn( Gtk.TreeViewColumn ): |
1044 | """GridColumn - Base class that provides features that is important |
1045 | to all columns used in a DictionaryGrid or decendants. Currently |
1046 | it's useful only to StringColumn and CheckColumn, but should make it |
1047 | @@ -116,7 +110,7 @@ |
1048 | """ |
1049 | |
1050 | def __init__(self, key, index, dictionary_index, renderer, editable=True, format_function = None ): |
1051 | - gtk.TreeViewColumn.__init__(self, key, renderer, text=index) |
1052 | + Gtk.TreeViewColumn.__init__(self, key, renderer, text=index) |
1053 | |
1054 | self.set_clickable(True) |
1055 | self.set_resizable(True) |
1056 | @@ -124,6 +118,7 @@ |
1057 | self.index = index |
1058 | self.key = key |
1059 | self.dictionary_index = dictionary_index |
1060 | + # Why should list_store be set to None? |
1061 | self.list_store = None |
1062 | |
1063 | |
1064 | @@ -135,21 +130,22 @@ |
1065 | |
1066 | rows = [tuple(r) + (i,) for i, r in enumerate(self.list_store)] |
1067 | |
1068 | - # I NEED TO HAVE A LOOK AT THIS IF-BLOCK. At least, it needs a comment. |
1069 | - if sort_order == gtk.SORT_ASCENDING: |
1070 | - sort_order = gtk.SORT_DESCENDING |
1071 | + # Sort opposite of last time |
1072 | + if sort_order == Gtk.SortType.ASCENDING: |
1073 | + sort_order = Gtk.SortType.DESCENDING |
1074 | else: |
1075 | - sort_order = gtk.SORT_ASCENDING |
1076 | + sort_order = Gtk.SortType.ASCENDING |
1077 | |
1078 | self.set_sort_order(sort_order) |
1079 | self.set_sort_indicator(True) |
1080 | |
1081 | - if sort_order == gtk.SORT_ASCENDING: |
1082 | + if sort_order == Gtk.SortType.ASCENDING: |
1083 | rows.sort(self._sort_ascending) |
1084 | else: |
1085 | rows.sort(self._sort_descending) |
1086 | |
1087 | - self.list_store.reorder([r[-1] for r in rows]) |
1088 | + # Where does self.list_store come from? |
1089 | + self.list_store.set_sort_column_id(self.index, sort_order) |
1090 | |
1091 | def set_editable(self, editable): |
1092 | self.renderer.set_property("editable", editable) |
1093 | @@ -164,7 +160,7 @@ |
1094 | |
1095 | """ |
1096 | |
1097 | - column_type = gobject.TYPE_STRING |
1098 | + column_type = GObject.TYPE_STRING |
1099 | __sort_order = None |
1100 | default_filter = grid_filter.StringFilterBox |
1101 | def __init__(self, key, index, dictionary_index, editable=True, format_function = None ): |
1102 | @@ -247,7 +243,7 @@ |
1103 | cell_renderer - a reference to the specific cell_renderer that is |
1104 | formatting the string |
1105 | |
1106 | - tree_model - the gtk.ListStore that is the backing data for the |
1107 | + tree_model - the Gtk.ListStore that is the backing data for the |
1108 | DictionaryGrid that contains the column. |
1109 | |
1110 | iter - an iterator that references the row of the the DictionaryGrid |
1111 | @@ -274,8 +270,7 @@ |
1112 | |
1113 | """ |
1114 | |
1115 | - self.renderer = gtk.CellRendererText() |
1116 | - self.renderer.mode = gtk.CELL_RENDERER_MODE_EDITABLE |
1117 | + self.renderer = Gtk.CellRendererText() |
1118 | self.renderer.set_property("editable", editable) |
1119 | self.renderer.connect("edited", self._cell_edited) |
1120 | |
1121 | @@ -340,14 +335,14 @@ |
1122 | return "" |
1123 | |
1124 | class CurrencyColumn( StringColumn ): |
1125 | - """CurrencyColumn - display data in currency format. Uses a gtk.Spinner |
1126 | + """CurrencyColumn - display data in currency format. Uses a Gtk.Spinner |
1127 | to display data and support editing if enabled. Store real values as float. |
1128 | |
1129 | Inherits from StringColumn. |
1130 | |
1131 | """ |
1132 | |
1133 | - column_type = gobject.TYPE_STRING |
1134 | + column_type = GObject.TYPE_STRING |
1135 | default_filter = grid_filter.NumericFilterBox |
1136 | def __init__(self, key, index,dictionary_index, editable=True ): |
1137 | """Creates a CurrencyColumn |
1138 | @@ -380,8 +375,8 @@ |
1139 | |
1140 | """ |
1141 | |
1142 | - self.renderer = gtk.CellRendererSpin() |
1143 | - adj = gtk.Adjustment(0,-10000000000,10000000000,1) |
1144 | + self.renderer = Gtk.CellRendererSpin() |
1145 | + adj = Gtk.Adjustment(0,-10000000000,10000000000,1) |
1146 | self.renderer.set_property("adjustment", adj) |
1147 | self.renderer.set_property("editable", editable) |
1148 | self.renderer.set_property("digits",2) |
1149 | @@ -494,19 +489,19 @@ |
1150 | |
1151 | """ |
1152 | |
1153 | - column_type = gobject.TYPE_STRING |
1154 | + column_type = GObject.TYPE_STRING |
1155 | default_filter = grid_filter.TagsFilterBox |
1156 | |
1157 | |
1158 | class IntegerColumn( StringColumn ): |
1159 | - """IntegerColumn - display data in Integer format. Uses a gtk.Spinner |
1160 | + """IntegerColumn - display data in Integer format. Uses a Gtk.Spinner |
1161 | to display data and support editing if enabled. Store real values as int. |
1162 | |
1163 | Inherits from StringColumn. |
1164 | |
1165 | """ |
1166 | |
1167 | - column_type = gobject.TYPE_STRING |
1168 | + column_type = GObject.TYPE_STRING |
1169 | default_filter = grid_filter.IntegerFilterBox |
1170 | |
1171 | def __init__(self, key, index, dictionary_index, editable=True ): |
1172 | @@ -529,8 +524,8 @@ |
1173 | StringColumn.__init__( self, key, index, dictionary_index, editable) |
1174 | |
1175 | def _initialize_renderer( self, editable, index ): |
1176 | - self.renderer = gtk.CellRendererSpin() |
1177 | - adj = gtk.Adjustment(0,-10000000000,10000000000,1) |
1178 | + self.renderer = Gtk.CellRendererSpin() |
1179 | + adj = Gtk.Adjustment(0,-10000000000,10000000000,1) |
1180 | self.renderer.set_property("adjustment", adj) |
1181 | self.renderer.set_property("editable", editable) |
1182 | self.renderer.connect("edited", self._cell_edited) |
1183 | @@ -640,11 +635,11 @@ |
1184 | class CheckColumn( GridColumn ): |
1185 | """CheckColumn - display data as checkboxes. Store real values as bool. |
1186 | |
1187 | - Inherits from gtk.TreeViewColumn. |
1188 | + Inherits from Gtk.TreeViewColumn. |
1189 | |
1190 | """ |
1191 | |
1192 | - column_type = gobject.TYPE_INT |
1193 | + column_type = GObject.TYPE_INT |
1194 | default_filter = grid_filter.CheckFilterBox |
1195 | |
1196 | def __init__(self, key, index, dictionary_index, editable=True, format_function = None ): |
1197 | @@ -684,7 +679,7 @@ |
1198 | y = y[self.index] |
1199 | return x - y |
1200 | |
1201 | - def _on_format(self,column, cell_renderer, tree_model, iter): |
1202 | + def _on_format(self,column, cell_renderer, tree_model, iter, format_function): |
1203 | cell_val = tree_model.get_value(iter, self.index) |
1204 | cell_renderer.set_property('inconsistent', False) |
1205 | if cell_val == 1: |
1206 | @@ -698,9 +693,9 @@ |
1207 | self.extra_format_function() |
1208 | |
1209 | def _initialize_renderer( self, editable, index ): |
1210 | - self.renderer = gtk.CellRendererToggle() |
1211 | + self.renderer = Gtk.CellRendererToggle() |
1212 | self.renderer.set_property("activatable", editable) |
1213 | - col = gtk.TreeViewColumn(self.key, self.renderer, active=index) |
1214 | + col = Gtk.TreeViewColumn(self.key, self.renderer, active=index) |
1215 | self.renderer.connect("toggled", self.toggled) |
1216 | |
1217 | def toggled(self, cell, path, data=None): |
1218 | @@ -772,14 +767,14 @@ |
1219 | return bool(val) |
1220 | |
1221 | class DateColumn( StringColumn ): |
1222 | - """DateColumn - display data in date format. Uses a gtk.Calendar |
1223 | + """DateColumn - display data in date format. Uses a Gtk.Calendar |
1224 | to display data and support editing if enabled. Store real values as tuple. |
1225 | |
1226 | Inherits from StringColumn. |
1227 | |
1228 | """ |
1229 | |
1230 | - column_type = gobject.TYPE_STRING |
1231 | + column_type = GObject.TYPE_STRING |
1232 | default_filter = grid_filter.DateFilterBox |
1233 | |
1234 | def __init__(self, key, index,dictionary_index, editable=True ): |
1235 | @@ -816,27 +811,27 @@ |
1236 | self.renderer.set_property('editable',self._editable) |
1237 | self.renderer.connect("edited", self._cell_edited) |
1238 | |
1239 | -class CellRendererDate(gtk.CellRendererText): |
1240 | +class CellRendererDate(Gtk.CellRendererText): |
1241 | def __init__(self): |
1242 | - gtk.CellRendererText.__init__(self) |
1243 | + Gtk.CellRendererText.__init__(self) |
1244 | self.date_format = '%Y-%m-%d' |
1245 | |
1246 | self.calendar_window = None |
1247 | self.calendar = None |
1248 | |
1249 | def _create_calendar(self, treeview): |
1250 | - self.calendar_window = gtk.Dialog(parent=treeview.get_toplevel()) |
1251 | + self.calendar_window = Gtk.Dialog(parent=treeview.get_toplevel()) |
1252 | self.calendar_window.action_area.hide() |
1253 | self.calendar_window.set_decorated(False) |
1254 | self.calendar_window.set_property('skip-taskbar-hint', True) |
1255 | |
1256 | - self.calendar = gtk.Calendar() |
1257 | - self.calendar.display_options(gtk.CALENDAR_SHOW_DAY_NAMES | gtk.CALENDAR_SHOW_HEADING) |
1258 | + self.calendar = Gtk.Calendar() |
1259 | + self.calendar.display_options(Gtk.CalendarDisplayOptions.SHOW_DAY_NAMES | Gtk.CalendarDisplayOptions.SHOW_HEADING) |
1260 | self.calendar.connect('day-selected-double-click', self._day_selected, None) |
1261 | self.calendar.connect('key-press-event', self._day_selected) |
1262 | self.calendar.connect('focus-out-event', self._selection_cancelled) |
1263 | self.calendar_window.set_transient_for(None) # cancel the modality of dialog |
1264 | - self.calendar_window.vbox.pack_start(self.calendar) |
1265 | + self.calendar_window.vbox.pack_start(self.calendar, True, True, 0) |
1266 | |
1267 | # necessary for getting the (width, height) of calendar_window |
1268 | self.calendar.show() |
1269 | @@ -871,20 +866,20 @@ |
1270 | |
1271 | response = self.calendar_window.run() |
1272 | self.calendar_window.hide() |
1273 | - if response == gtk.RESPONSE_OK: |
1274 | + if response == Gtk.ResponseType.OK: |
1275 | (year, month, day) = self.calendar.get_date() |
1276 | - date = datetime.date(year, month + 1, day).strftime(self.date_format) # gtk.Calendar's month starts from zero |
1277 | + date = datetime.date(year, month + 1, day).strftime(self.date_format) # Gtk.Calendar's month starts from zero |
1278 | self.emit('edited', path, date) |
1279 | |
1280 | - return None # don't return any editable, our gtk.Dialog did the work already |
1281 | + return None # don't return any editable, our Gtk.Dialog did the work already |
1282 | |
1283 | def _day_selected(self, calendar, event): |
1284 | # event == None for day selected via doubleclick |
1285 | - if not event or event.type == gtk.gdk.KEY_PRESS and gtk.gdk.keyval_name(event.keyval) == 'Return': |
1286 | - self.calendar_window.response(gtk.RESPONSE_OK) |
1287 | + if not event or event.type == Gdk.EventType.KEY_PRESS and Gdk.keyval_name(event.keyval) == 'Return': |
1288 | + self.calendar_window.response(Gtk.ResponseType.OK) |
1289 | return True |
1290 | |
1291 | def _selection_cancelled(self, calendar, event): |
1292 | - self.calendar_window.response(gtk.RESPONSE_CANCEL) |
1293 | + self.calendar_window.response(Gtk.ResponseType.CANCEL) |
1294 | return True |
1295 | |
1296 | |
1297 | === modified file 'quickly/widgets/grid_filter.py' |
1298 | --- quickly/widgets/grid_filter.py 2010-12-18 16:06:52 +0000 |
1299 | +++ quickly/widgets/grid_filter.py 2012-03-06 08:52:21 +0000 |
1300 | @@ -15,12 +15,12 @@ |
1301 | ### END LICENSE |
1302 | |
1303 | """Widgets and Objects for filtering a DictionaryGrid |
1304 | -GridFilter is as gtk.VBox that provides filtering UI for a |
1305 | +GridFilter is as Gtk.VBox that provides filtering UI for a |
1306 | DictionaryGrid. Provides multiple filters, and choosing |
1307 | between "And" and "Or" filtering. Provides default filters appropriate |
1308 | for each column. |
1309 | |
1310 | -GridFilter row is a gtk.HBox that is a container for displaying FilterCombos. |
1311 | +GridFilter row is a Gtk.HBox that is a container for displaying FilterCombos. |
1312 | |
1313 | FilterCombos display a filter and handle filtering of rows to |
1314 | display and hide in the associated DictionaryGrid. The GridColumns |
1315 | @@ -60,374 +60,370 @@ |
1316 | self.append("starts with",lambda x,y: x.startswith(y)) |
1317 | self.append("ends with",lambda x,y: x.endswith(y)) |
1318 | |
1319 | -Filter UI could be created to use widgets other than gtk.Combo so long as |
1320 | -the widget has a get_model function that returns a gtk.ListStore with |
1321 | +Filter UI could be created to use widgets other than Gtk.Combo so long as |
1322 | +the widget has a get_model function that returns a Gtk.ListStore with |
1323 | filtering functions stored as the last value (column) in the liststore. |
1324 | |
1325 | """ |
1326 | |
1327 | + |
1328 | import sys |
1329 | import datetime |
1330 | import gettext |
1331 | from gettext import gettext as _ |
1332 | gettext.textdomain('quickly-widgets') |
1333 | |
1334 | -try: |
1335 | - import pygtk |
1336 | - pygtk.require("2.0") |
1337 | - import gtk |
1338 | - import gobject |
1339 | - |
1340 | -except Exception, inst: |
1341 | - print "some dependencies for GridFilter are not available" |
1342 | - raise inst |
1343 | - |
1344 | -class GridFilter( gtk.VBox ): |
1345 | - """GridFilter: A widget that provides a user interface for filtering a |
1346 | - treeview. A GridFilter hosts one ore more GridRows, which in turn host |
1347 | - an active filter. |
1348 | - |
1349 | - """ |
1350 | - def __init__(self, grid, filter_hints={} ): |
1351 | - """Create a GridFilter for filtering an associated treeview. |
1352 | - This class is used by BugsPane. |
1353 | - |
1354 | - arguments: |
1355 | - grid - A DictionaryGrid to filter |
1356 | - |
1357 | - options arguments: |
1358 | - filter_hints - a dictionary of column keys to FilterCombo types to |
1359 | - provide custom filtering. |
1360 | - |
1361 | - """ |
1362 | - |
1363 | - gtk.VBox.__init__( self, False, 10 ) |
1364 | - self.grid = grid |
1365 | - self.store = grid.get_model() |
1366 | - self.filter_hints = filter_hints |
1367 | - |
1368 | - #create the and/or radio buttons |
1369 | - radio_box = gtk.HBox(False,2) |
1370 | - radio_box.show() |
1371 | - self.pack_start(radio_box, False, False) |
1372 | - self.and_button = gtk.RadioButton(None,_("M_atch All of the following"), True) |
1373 | - self.and_button.show() |
1374 | - self.and_button.connect("toggled",self.__filter_changed) |
1375 | - radio_box.pack_start(self.and_button, False, False) |
1376 | - or_button = gtk.RadioButton(self.and_button,_("Match any _of the following"), True) |
1377 | - or_button.show() |
1378 | - radio_box.pack_start(or_button, False, False) |
1379 | - self.rows = [] |
1380 | - self._add_row(self) |
1381 | - |
1382 | - def _add_row(self, widget, data=None): |
1383 | - """_add_row: internal signal handler that receives a request |
1384 | - from a FilterRow to add a new row. Sets up and adds the row to the GridFilter. |
1385 | - |
1386 | - Do not call directly |
1387 | - """ |
1388 | - |
1389 | - #TODO: I suppose this is leaking references to filter rows |
1390 | - row = FilterRow(self.grid, len(self.rows) > 0, self.filter_hints ) |
1391 | - row.connect('add_row_requested',self._add_row) |
1392 | - row.connect('remove_row_requested',self._remove_row) |
1393 | - row.connect('refilter_requested',self.__filter_changed) |
1394 | - row.show() |
1395 | - self.rows.append(row) |
1396 | - self.pack_start(row, False, False) |
1397 | - |
1398 | - def _remove_row(self, widget, data=None): |
1399 | - """_remove_row: internal signal handler that receives a |
1400 | - request from a FilterRow to remove itself from the GridFilter. |
1401 | - |
1402 | - Do not call directly |
1403 | - """ |
1404 | - |
1405 | - self.rows.remove(widget) |
1406 | - self.remove(widget) |
1407 | - self.__filter_changed(self) |
1408 | - |
1409 | - def __filter_changed(self,widget, data=None): |
1410 | - """__filter_changed: internal signal handler that handles |
1411 | - requests to reapply the fitlers in the GridFilter's FilterRows. |
1412 | - |
1413 | - """ |
1414 | - |
1415 | - filt = self.store.filter_new() |
1416 | - sort_mod = gtk.TreeModelSort(filt) |
1417 | - filt.set_visible_func(self.__filter_func, data ) |
1418 | - filt.refilter() |
1419 | - self.grid.set_model(sort_mod) |
1420 | - |
1421 | - def __filter_func(self, model, iter, data): |
1422 | - """filter_func: called for each row in the treeview model in response to |
1423 | - a __filter_changed signal. Determines for each row whether it should be |
1424 | - visible based on the FilterRows in the GridFilter. |
1425 | - |
1426 | - |
1427 | - Do not call directly |
1428 | - """ |
1429 | - #determine whether this is an "and" or an "or" filter |
1430 | - match_all = self.and_button.get_active() |
1431 | - |
1432 | - for r in self.rows: |
1433 | - rez = r.is_match(iter.copy(),model) #check the result of each filter |
1434 | - if match_all: #if it's an "and" filter |
1435 | - if not rez: #and if the filter does not match |
1436 | - return False #then the row should not be visible |
1437 | - else: #but if it's an "or" filter |
1438 | - if rez: #and it is a match |
1439 | - return True #return that the row should be visible |
1440 | - return match_all #all filters match an "and" or none matched an "or" |
1441 | - |
1442 | -class FilterRow( gtk.HBox): |
1443 | - """FilterRow: A widget that displays a single filter in a GridFilter. |
1444 | - Typically, this class will not be used directly, but only via a GridFilter. |
1445 | - |
1446 | - """ |
1447 | - wait_for_input = False |
1448 | - |
1449 | - def __init__(self, grid, removable=True, filter_hints={}): |
1450 | - """Create a FilterRow to be used in a GridFilter. |
1451 | - A FitlerRow is comprised of a combo that lists the treeview headings. |
1452 | - The combo stores the string to display for the heading, as well as |
1453 | - the widget that is used to filter each heading. When the user changes |
1454 | - the value in the dropdown, the FilterRow retrieves the correct filter from |
1455 | - the combo, and displays that filter to the user. |
1456 | - |
1457 | - The FilterRow also handles offering UI for the user to add and remove |
1458 | - FilterRows for the GridFilter containing it. |
1459 | +from gi.repository import GObject |
1460 | +from gi.repository import Gtk |
1461 | + |
1462 | +class GridFilter( Gtk.VBox ): |
1463 | + """GridFilter: A widget that provides a user interface for filtering a |
1464 | + treeview. A GridFilter hosts one ore more GridRows, which in turn host |
1465 | + an active filter. |
1466 | + """ |
1467 | + |
1468 | + def __init__(self, grid, filter_hints={} ): |
1469 | + """Create a GridFilter for filtering an associated treeview. |
1470 | + This class is used by BugsPane. |
1471 | + |
1472 | + arguments: |
1473 | + grid - A DictionaryGrid to filter |
1474 | + |
1475 | + options arguments: |
1476 | + filter_hints - a dictionary of column keys to FilterCombo types to |
1477 | + provide custom filtering. |
1478 | + |
1479 | + """ |
1480 | + |
1481 | + Gtk.VBox.__init__( self, False, 10 ) |
1482 | + self.grid = grid |
1483 | + self.store = grid.get_model() |
1484 | + self.filter_hints = filter_hints |
1485 | + |
1486 | + #create the and/or radio buttons |
1487 | + radio_box = Gtk.HBox(False,2) |
1488 | + radio_box.show() |
1489 | + self.pack_start(radio_box, False, False, 0) |
1490 | + self.and_button = Gtk.RadioButton.new_with_label_from_widget(None,_("M_atch All of the following")) |
1491 | + self.and_button.show() |
1492 | + self.and_button.connect("toggled",self.__filter_changed) |
1493 | + radio_box.pack_start(self.and_button, False, False, 0) |
1494 | + or_button = Gtk.RadioButton.new_with_label_from_widget(self.and_button,_("Match any _of the following")) |
1495 | + or_button.show() |
1496 | + radio_box.pack_start(or_button, False, False, 0) |
1497 | + self.rows = [] |
1498 | + self._add_row(self) |
1499 | + |
1500 | + def _add_row(self, widget, data=None): |
1501 | + """_add_row: internal signal handler that receives a request |
1502 | + from a FilterRow to add a new row. Sets up and adds the row to the GridFilter. |
1503 | + |
1504 | + Do not call directly |
1505 | + """ |
1506 | + |
1507 | + #TODO: I suppose this is leaking references to filter rows |
1508 | + row = FilterRow(self.grid, len(self.rows) > 0, self.filter_hints ) |
1509 | + row.connect('add_row_requested',self._add_row) |
1510 | + row.connect('remove_row_requested',self._remove_row) |
1511 | + row.connect('refilter_requested',self.__filter_changed) |
1512 | + row.show() |
1513 | + self.rows.append(row) |
1514 | + self.pack_start(row, False, False, 0) |
1515 | + |
1516 | + def _remove_row(self, widget, data=None): |
1517 | + """_remove_row: internal signal handler that receives a |
1518 | + request from a FilterRow to remove itself from the GridFilter. |
1519 | + |
1520 | + Do not call directly |
1521 | + """ |
1522 | + |
1523 | + self.rows.remove(widget) |
1524 | + self.remove(widget) |
1525 | + self.__filter_changed(self) |
1526 | + |
1527 | + def __filter_changed(self,widget, data=None): |
1528 | + """__filter_changed: internal signal handler that handles |
1529 | + requests to reapply the fitlers in the GridFilter's FilterRows. |
1530 | + |
1531 | + """ |
1532 | + |
1533 | + filt = self.store.filter_new() |
1534 | + sort_mod = Gtk.TreeModelSort(model=filt) |
1535 | + filt.set_visible_func(self.__filter_func, data ) |
1536 | + filt.refilter() |
1537 | + self.grid.set_model(sort_mod) |
1538 | + |
1539 | + def __filter_func(self, model, iter, data): |
1540 | + """filter_func: called for each row in the treeview model in response to |
1541 | + a __filter_changed signal. Determines for each row whether it should be |
1542 | + visible based on the FilterRows in the GridFilter. |
1543 | + |
1544 | + |
1545 | + Do not call directly |
1546 | + """ |
1547 | + #determine whether this is an "and" or an "or" filter |
1548 | + match_all = self.and_button.get_active() |
1549 | + |
1550 | + for r in self.rows: |
1551 | + rez = r.is_match(iter.copy(),model) #check the result of each filter |
1552 | + if match_all: #if it's an "and" filter |
1553 | + if not rez: #and if the filter does not match |
1554 | + return False #then the row should not be visible |
1555 | + else: #but if it's an "or" filter |
1556 | + if rez: #and it is a match |
1557 | + return True #return that the row should be visible |
1558 | + return match_all #all filters match an "and" or none matched an "or" |
1559 | + |
1560 | +class FilterRow( Gtk.HBox): |
1561 | + """FilterRow: A widget that displays a single filter in a GridFilter. |
1562 | + Typically, this class will not be used directly, but only via a GridFilter. |
1563 | + |
1564 | + """ |
1565 | + wait_for_input = False |
1566 | + |
1567 | + def __init__(self, grid, removable=True, filter_hints={}): |
1568 | + """Create a FilterRow to be used in a GridFilter. |
1569 | + A FitlerRow is comprised of a combo that lists the treeview headings. |
1570 | + The combo stores the string to display for the heading, as well as |
1571 | + the widget that is used to filter each heading. When the user changes |
1572 | + the value in the dropdown, the FilterRow retrieves the correct filter from |
1573 | + the combo, and displays that filter to the user. |
1574 | + |
1575 | + The FilterRow also handles offering UI for the user to add and remove |
1576 | + FilterRows for the GridFilter containing it. |
1577 | |
1578 | - grid - |
1579 | - |
1580 | - keyword arguments: |
1581 | - removable - True if the row should be able to be removed from the GridFilter |
1582 | - Typicall False for the first row. |
1583 | - |
1584 | - filter_hints - a dictionary of keys mapped to custom filters to apply to the |
1585 | - column designated by the key |
1586 | - |
1587 | - """ |
1588 | - |
1589 | - gtk.HBox.__init__( self, False, 10 ) |
1590 | - self.store = grid.get_model() |
1591 | - self.grid = grid |
1592 | - |
1593 | - heading_combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT,gobject.TYPE_INT) |
1594 | - |
1595 | - #apply default combos |
1596 | - for i, k in enumerate(self.grid.keys): |
1597 | - if k in filter_hints: |
1598 | - filt_combo = filter_hints[k] |
1599 | - else: |
1600 | - filt_combo = grid.get_columns()[i].default_filter() |
1601 | + grid - |
1602 | + |
1603 | + keyword arguments: |
1604 | + removable - True if the row should be able to be removed from the GridFilter |
1605 | + Typicall False for the first row. |
1606 | + |
1607 | + filter_hints - a dictionary of keys mapped to custom filters to apply to the |
1608 | + column designated by the key |
1609 | + |
1610 | + """ |
1611 | + |
1612 | + Gtk.HBox.__init__( self, False, 10 ) |
1613 | + self.store = grid.get_model() |
1614 | + self.grid = grid |
1615 | + |
1616 | + heading_combo_store = Gtk.ListStore(GObject.TYPE_STRING,GObject.TYPE_PYOBJECT,GObject.TYPE_INT) |
1617 | + |
1618 | + |
1619 | + #apply default combos |
1620 | + for i, k in enumerate(self.grid.keys): |
1621 | + if k in filter_hints: |
1622 | + filt_combo = filter_hints[k] |
1623 | + else: |
1624 | + filt_combo = grid.get_columns()[i].default_filter() |
1625 | |
1626 | - column_title = grid.get_columns()[i].get_title() |
1627 | - heading_combo_store.append([column_title,filt_combo,i]) |
1628 | - |
1629 | - filt_combo.connect("changed",self.__filter_changed) |
1630 | - filt_combo.show() |
1631 | - |
1632 | - self.column_combo = gtk.ComboBox(heading_combo_store) |
1633 | - cell = gtk.CellRendererText() |
1634 | - self.column_combo.pack_start(cell, True) |
1635 | - self.column_combo.add_attribute(cell, 'text', 0) |
1636 | - |
1637 | - self.filter_space = gtk.HBox(False,1) |
1638 | - self.filter_space.show() |
1639 | - |
1640 | - self.column_combo.show() |
1641 | - vb = gtk.VBox(False, 5) |
1642 | - vb.show() |
1643 | - vb.pack_start(self.column_combo, True, False) |
1644 | - self.pack_start(vb,False, False) |
1645 | - self.column_combo.connect("changed",self.__column_changed) |
1646 | - self.column_combo.set_active(0) |
1647 | - |
1648 | - self.pack_start(self.filter_space, False, False) |
1649 | - |
1650 | - button_box = gtk.HBox(False,2) |
1651 | - button_box.show() |
1652 | - self.pack_start(button_box,False,False) |
1653 | - |
1654 | - #add a button that can create a new row in the grid filter |
1655 | - add_button = gtk.Button(stock = gtk.STOCK_ADD) |
1656 | - add_button.show() |
1657 | - vb2 = gtk.VBox(False, 5) |
1658 | - vb2.show() |
1659 | - vb2.pack_start(add_button, True, False) |
1660 | - button_box.pack_start(vb2, False, False) |
1661 | - add_button.connect("clicked",lambda x: self.emit('add_row_requested',self) ) |
1662 | - |
1663 | - #add a button to remove the row if applicable |
1664 | - if removable: |
1665 | - rm_button = gtk.Button(stock = gtk.STOCK_REMOVE) |
1666 | - rm_button.show() |
1667 | - vb3 = gtk.VBox(False, 5) |
1668 | - vb3.show() |
1669 | - vb3.pack_start(rm_button, True, False) |
1670 | - rm_button.connect('clicked', lambda x: self.emit("remove_row_requested",self) ) |
1671 | - button_box.pack_start(vb3) |
1672 | - |
1673 | - __gsignals__ = {'add_row_requested' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
1674 | - (gobject.TYPE_PYOBJECT,)), |
1675 | - 'remove_row_requested' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
1676 | - (gobject.TYPE_PYOBJECT,)), |
1677 | - 'refilter_requested' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
1678 | - (gobject.TYPE_PYOBJECT,)) |
1679 | - } |
1680 | - |
1681 | - def __column_changed(self, widget, data = None): |
1682 | - """column_changed: internal signal handler for the user changing |
1683 | - the combo for the column that they wish to apply the filter to. |
1684 | - removes the other filter widgets and replaces them widgets stored in |
1685 | - the filter widget. |
1686 | - |
1687 | - """ |
1688 | - |
1689 | - if len(self.filter_space.get_children()) > 0: |
1690 | - self.filter_space.remove(self.filter_space.get_children()[0]) |
1691 | - iter = widget.get_model().get_iter(widget.get_active()) |
1692 | - filter_box = widget.get_model().get_value(iter,1) |
1693 | - self.filter_space.pack_start(filter_box, False, False) |
1694 | - |
1695 | - def __filter_changed(self,widget, data=None): |
1696 | - """filter_changed: internal signal handler called when the FilterRow has changed. |
1697 | - Used to tell the GridFilter to refilter. Only emits if the filter is |
1698 | - active (a heading is selected in the combo and the user has entered |
1699 | - text in the filter. |
1700 | - |
1701 | - """ |
1702 | + column_title = grid.get_columns()[i].get_title() |
1703 | + heading_combo_store.append([column_title,filt_combo,i]) |
1704 | + |
1705 | + filt_combo.connect("changed",self.__filter_changed) |
1706 | + filt_combo.show() |
1707 | + |
1708 | + self.column_combo = Gtk.ComboBox.new_with_model(heading_combo_store) |
1709 | + cell = Gtk.CellRendererText() |
1710 | + self.column_combo.pack_start(cell, True) |
1711 | + self.column_combo.add_attribute(cell, 'text', 0) |
1712 | + |
1713 | + self.filter_space = Gtk.HBox(False,1) |
1714 | + self.filter_space.show() |
1715 | + |
1716 | + self.column_combo.show() |
1717 | + vb = Gtk.VBox(False, 5) |
1718 | + vb.show() |
1719 | + vb.pack_start(self.column_combo, True, False, 0) |
1720 | + self.pack_start(vb,False, False, 0) |
1721 | + self.column_combo.connect("changed",self.__column_changed) |
1722 | + self.column_combo.set_active(0) |
1723 | + |
1724 | + self.pack_start(self.filter_space, False, False, 0) |
1725 | + |
1726 | + button_box = Gtk.HBox(False,2) |
1727 | + button_box.show() |
1728 | + self.pack_start(button_box,False,False, 0) |
1729 | + |
1730 | + #add a button that can create a new row in the grid filter |
1731 | + add_button = Gtk.Button(stock = Gtk.STOCK_ADD) |
1732 | + add_button.show() |
1733 | + vb2 = Gtk.VBox(False, 5) |
1734 | + vb2.show() |
1735 | + vb2.pack_start(add_button, True, False, 0) |
1736 | + button_box.pack_start(vb2, False, False, 0) |
1737 | + add_button.connect("clicked",lambda x: self.emit('add_row_requested',self) ) |
1738 | + |
1739 | + #add a button to remove the row if applicable |
1740 | + if removable: |
1741 | + rm_button = Gtk.Button(stock = Gtk.STOCK_REMOVE) |
1742 | + rm_button.show() |
1743 | + vb3 = Gtk.VBox(False, 5) |
1744 | + vb3.show() |
1745 | + vb3.pack_start(rm_button, True, False, 0) |
1746 | + rm_button.connect('clicked', lambda x: self.emit("remove_row_requested",self) ) |
1747 | + button_box.pack_start(vb3, True, True, 0) |
1748 | + |
1749 | + __gsignals__ = {'add_row_requested' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
1750 | + (GObject.TYPE_PYOBJECT,)), |
1751 | + 'remove_row_requested' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
1752 | + (GObject.TYPE_PYOBJECT,)), |
1753 | + 'refilter_requested' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
1754 | + (GObject.TYPE_PYOBJECT,)) |
1755 | + } |
1756 | + |
1757 | + |
1758 | + def __column_changed(self, widget, data = None): |
1759 | + """column_changed: internal signal handler for the user changing |
1760 | + the combo for the column that they wish to apply the filter to. |
1761 | + removes the other filter widgets and replaces them widgets stored in |
1762 | + the filter widget. |
1763 | + |
1764 | + """ |
1765 | + |
1766 | + if len(self.filter_space.get_children()) > 0: |
1767 | + self.filter_space.remove(self.filter_space.get_children()[0]) |
1768 | + iter = widget.get_model().get_iter(widget.get_active()) |
1769 | + filter_box = widget.get_model().get_value(iter,1) |
1770 | + self.filter_space.pack_start(filter_box, False, False, 0) |
1771 | + |
1772 | + def __filter_changed(self,widget, data=None): |
1773 | + """filter_changed: internal signal handler called when the FilterRow has changed. |
1774 | + Used to tell the GridFilter to refilter. Only emits if the filter is |
1775 | + active (a heading is selected in the combo and the user has entered |
1776 | + text in the filter. |
1777 | + |
1778 | + """ |
1779 | |
1780 | - #if not self.wait_for_input: |
1781 | - #if self.__get_current_filter_combo().get_active > -1: |
1782 | - self.emit('refilter_requested',self) |
1783 | - |
1784 | - def __get_current_filter_combo(self): |
1785 | - """get_current_filter_combo: internal function that retrieves |
1786 | - the combobox stored for the filter for the user selected treeview column. |
1787 | - |
1788 | - """ |
1789 | - iter = self.column_combo.get_model().get_iter(self.column_combo.get_active()) |
1790 | - return self.column_combo.get_model().get_value(iter,1) |
1791 | - |
1792 | - def is_match(self, store_iter, model): |
1793 | - """is_match: returns true if the filter set in the FilterRow matches |
1794 | - the value specified in the column and row. Used to determine whether |
1795 | - to hide or show a row. |
1796 | - |
1797 | - Typically called for each treeview row and each FilterRow in response |
1798 | - to a change in one of the FilterRows. |
1799 | - |
1800 | - arguments: |
1801 | - store_iter: the iter pointing the the row in the treeview to test |
1802 | - model: the treeview model containing the rows being tested |
1803 | - |
1804 | - """ |
1805 | - col_iter = self.column_combo.get_model().get_iter(self.column_combo.get_active()) |
1806 | - filter_widget = self.column_combo.get_model().get_value(col_iter,1) |
1807 | - treeview_col = self.column_combo.get_model().get_value(col_iter,2) |
1808 | - |
1809 | - orig_val = model.get_value(store_iter.copy(), treeview_col) |
1810 | - return filter_widget.filter(orig_val) |
1811 | - |
1812 | -class BlankFilterBox( gtk.HBox): |
1813 | - """BlankFilterBox provides a base class for FilterCombos, as |
1814 | - well as an empty combo that can be used without subclassing |
1815 | - by calling BlankFilterBox.append |
1816 | - |
1817 | - """ |
1818 | - __gsignals__ = {'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
1819 | - (gobject.TYPE_PYOBJECT,)), |
1820 | - } |
1821 | - |
1822 | - |
1823 | - def __init__(self): |
1824 | - """create a BlankFilterBox |
1825 | - |
1826 | - """ |
1827 | - |
1828 | - gtk.HBox.__init__(self,False) |
1829 | - self.__combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) |
1830 | - self.combo = gtk.ComboBox(self.__combo_store) |
1831 | - cell = gtk.CellRendererText() |
1832 | - self.combo.pack_start(cell, True) |
1833 | - self.combo.add_attribute(cell, 'text', 0) |
1834 | - self.combo.show() |
1835 | - self.combo.connect("changed",self.__changed) |
1836 | - self.entry = gtk.Entry() |
1837 | - self.entry.show() |
1838 | - self.entry.connect("changed",self.__changed) |
1839 | - self.pack_start(self.combo, False, False) |
1840 | - self.pack_start(self.entry) |
1841 | - |
1842 | - def filter(self, orig_val): |
1843 | - if self.combo.get_active() == -1: |
1844 | - return True |
1845 | - filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
1846 | - filt_func = self.combo.get_model().get_value(filt_iter,1) |
1847 | - target_val = self.entry.get_text() |
1848 | - return filt_func(orig_val, self.entry.get_text()) |
1849 | - |
1850 | - def __changed(self, widget, data=None): |
1851 | - self.emit("changed",data) |
1852 | - |
1853 | - def append(self, text, func): |
1854 | - """append: adds a row to the FilterCombo that includes a |
1855 | - string to display in the combo, and a function to determine |
1856 | - if a row should displayed or hidden by the filter. |
1857 | - |
1858 | - func should take a value indicated by text, and a value entered by |
1859 | - the user in the supplied gtk.TextEntry, and return True if the |
1860 | - row should be displayed or False if it should be hidden. |
1861 | + #if not self.wait_for_input: |
1862 | + #if self.__get_current_filter_combo().get_active > -1: |
1863 | + self.emit('refilter_requested',self) |
1864 | + |
1865 | + def __get_current_filter_combo(self): |
1866 | + """get_current_filter_combo: internal function that retrieves |
1867 | + the combobox stored for the filter for the user selected treeview column. |
1868 | + |
1869 | + """ |
1870 | + iter = self.column_combo.get_model().get_iter(self.column_combo.get_active()) |
1871 | + return self.column_combo.get_model().get_value(iter,1) |
1872 | + |
1873 | + def is_match(self, store_iter, model): |
1874 | + """is_match: returns true if the filter set in the FilterRow matches |
1875 | + the value specified in the column and row. Used to determine whether |
1876 | + to hide or show a row. |
1877 | + |
1878 | + Typically called for each treeview row and each FilterRow in response |
1879 | + to a change in one of the FilterRows. |
1880 | + |
1881 | + arguments: |
1882 | + store_iter: the iter pointing the the row in the treeview to test |
1883 | + model: the treeview model containing the rows being tested |
1884 | + |
1885 | + """ |
1886 | + col_iter = self.column_combo.get_model().get_iter(self.column_combo.get_active()) |
1887 | + filter_widget = self.column_combo.get_model().get_value(col_iter,1) |
1888 | + treeview_col = self.column_combo.get_model().get_value(col_iter,2) |
1889 | + |
1890 | + orig_val = model.get_value(store_iter.copy(), treeview_col) |
1891 | + return filter_widget.filter(orig_val) |
1892 | + |
1893 | +class BlankFilterBox( Gtk.HBox): |
1894 | + """BlankFilterBox provides a base class for FilterCombos, as |
1895 | + well as an empty combo that can be used without subclassing |
1896 | + by calling BlankFilterBox.append |
1897 | |
1898 | """ |
1899 | - |
1900 | - self.__combo_store.append([text, func]) |
1901 | + __gsignals__ = {'changed' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
1902 | + (GObject.TYPE_PYOBJECT,)), |
1903 | + } |
1904 | + |
1905 | + |
1906 | + def __init__(self): |
1907 | + """create a BlankFilterBox |
1908 | + |
1909 | + """ |
1910 | + |
1911 | + Gtk.HBox.__init__(self,False) |
1912 | + self.__combo_store = Gtk.ListStore(GObject.TYPE_STRING,GObject.TYPE_PYOBJECT) |
1913 | + self.combo = Gtk.ComboBox.new_with_model(self.__combo_store) |
1914 | + cell = Gtk.CellRendererText() |
1915 | + self.combo.pack_start(cell, True) |
1916 | + self.combo.add_attribute(cell, 'text', 0) |
1917 | + self.combo.show() |
1918 | + self.combo.connect("changed",self.__changed) |
1919 | + self.entry = Gtk.Entry() |
1920 | + self.entry.show() |
1921 | + self.entry.connect("changed",self.__changed) |
1922 | + self.pack_start(self.combo, False, False, 0) |
1923 | + self.pack_start(self.entry, True, True, 0) |
1924 | + |
1925 | + def filter(self, orig_val): |
1926 | + if self.combo.get_active() == -1: |
1927 | + return True |
1928 | + filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
1929 | + filt_func = self.combo.get_model().get_value(filt_iter,1) |
1930 | + target_val = self.entry.get_text() |
1931 | + return filt_func(orig_val, self.entry.get_text()) |
1932 | + |
1933 | + def __changed(self, widget, data=None): |
1934 | + self.emit("changed",data) |
1935 | + |
1936 | + def append(self, text, func): |
1937 | + """append: adds a row to the FilterCombo that includes a |
1938 | + string to display in the combo, and a function to determine |
1939 | + if a row should displayed or hidden by the filter. |
1940 | + |
1941 | + func should take a value indicated by text, and a value entered by |
1942 | + the user in the supplied Gtk.TextEntry, and return True if the |
1943 | + row should be displayed or False if it should be hidden. |
1944 | + |
1945 | + """ |
1946 | + |
1947 | + self.__combo_store.append([text, func]) |
1948 | |
1949 | class StringFilterBox( BlankFilterBox ): |
1950 | - """StringFilterBox: A default string filter class for use in a FilterRow. |
1951 | + """StringFilterBox: A default string filter class for use in a FilterRow. |
1952 | |
1953 | Lets the user specify if the row should be displayed based on |
1954 | containing, not containing, starting with, or ending with a user specified |
1955 | string. |
1956 | |
1957 | - |
1958 | """ |
1959 | - def __init__(self): |
1960 | - """create a StringFilterBox. |
1961 | - |
1962 | - """ |
1963 | - |
1964 | - BlankFilterBox.__init__(self) |
1965 | - self.append(_("contains"),self.contains) |
1966 | - self.append(_("does not contain"),self.not_contains) |
1967 | - self.append(_("starts with"),self.starts_with) |
1968 | - self.append(_("ends with"),self.ends_with) |
1969 | - |
1970 | - def contains(self, orig_val, target_val): |
1971 | - if len(self.entry.get_text()) == 0 or orig_val is None: |
1972 | - return True |
1973 | - return orig_val.find(target_val) > -1 |
1974 | - |
1975 | - def not_contains(self, orig_val, target_val): |
1976 | - if len(target_val) == 0 or orig_val is None: |
1977 | - return True |
1978 | - return orig_val.find(target_val) == -1 |
1979 | - |
1980 | - def starts_with(self, orig_val, target_val): |
1981 | - if len(target_val) == 0 or orig_val is None: |
1982 | - return True |
1983 | - return orig_val.startswith(target_val) |
1984 | - |
1985 | - def ends_with(self, orig_val, target_val): |
1986 | - if len(target_val) == 0 or orig_val is None: |
1987 | - return True |
1988 | - return orig_val.endswith(target_val) |
1989 | + |
1990 | + def __init__(self): |
1991 | + """create a StringFilterBox. |
1992 | + |
1993 | + """ |
1994 | + |
1995 | + BlankFilterBox.__init__(self) |
1996 | + self.append(_("contains"),self.contains) |
1997 | + self.append(_("does not contain"),self.not_contains) |
1998 | + self.append(_("starts with"),self.starts_with) |
1999 | + self.append(_("ends with"),self.ends_with) |
2000 | + |
2001 | + def contains(self, orig_val, target_val): |
2002 | + if len(self.entry.get_text()) == 0 or orig_val is None: |
2003 | + return True |
2004 | + return orig_val.find(target_val) > -1 |
2005 | + |
2006 | + def not_contains(self, orig_val, target_val): |
2007 | + if len(target_val) == 0 or orig_val is None: |
2008 | + return True |
2009 | + return orig_val.find(target_val) == -1 |
2010 | + |
2011 | + def starts_with(self, orig_val, target_val): |
2012 | + if len(target_val) == 0 or orig_val is None: |
2013 | + return True |
2014 | + return orig_val.startswith(target_val) |
2015 | + |
2016 | + def ends_with(self, orig_val, target_val): |
2017 | + if len(target_val) == 0 or orig_val is None: |
2018 | + return True |
2019 | + return orig_val.endswith(target_val) |
2020 | |
2021 | |
2022 | class TagsFilterBox( BlankFilterBox ): |
2023 | - """TagsFilterBox: A default tag filter class for use in a FilterRow. |
2024 | + """TagsFilterBox: A default tag filter class for use in a FilterRow. |
2025 | |
2026 | Lets the user specify if the row should be displayed based on |
2027 | containing a one tag or all tags. Assumes tags are seperated by |
2028 | @@ -435,382 +431,382 @@ |
2029 | |
2030 | """ |
2031 | |
2032 | - def __init__(self): |
2033 | - BlankFilterBox.__init__(self) |
2034 | - self.append(_("has any of these tags"), self._filter_any) |
2035 | - self.append(_("has all of these tags"), self._filter_all) |
2036 | - self.append(_("does not have one of these tags"), self._filter_not) |
2037 | - self.append(_("does not have any of these tags"), self._filter_not_all) |
2038 | - |
2039 | - def _filter_any(self, orig_val, target_val): |
2040 | - """ |
2041 | - _filter_any: filter function that hides rows |
2042 | - if none of the tags supplied in "bugs_tags_s" are found |
2043 | - in the gtk.TextEntry. |
2044 | - |
2045 | - Do not call directly |
2046 | - |
2047 | - """ |
2048 | - |
2049 | - if len(target_val) == 0: |
2050 | - return True |
2051 | - |
2052 | - tags_on_bug = orig_val.split() |
2053 | - tags_in_filter = target_val.split() |
2054 | - |
2055 | - for tag in tags_in_filter: |
2056 | - if tag in tags_on_bug: |
2057 | - return True |
2058 | - return False |
2059 | - |
2060 | - def _filter_all(self, orig_val, target_val): |
2061 | - """ |
2062 | - _filter_any: filter function that hides rows |
2063 | - if not all of the tags supplied in "bugs_tags_s" are found |
2064 | - in the gtk.TextEntry. |
2065 | - |
2066 | - Do not call directly |
2067 | - |
2068 | - """ |
2069 | - if len(target_val) == 0: |
2070 | - return True |
2071 | - |
2072 | - tags_on_bug = orig_val.split() |
2073 | - tags_in_filter = self.entry.get_text().split() |
2074 | - |
2075 | - for tag in tags_in_filter: |
2076 | - if tag not in tags_on_bug: |
2077 | - return False |
2078 | - return True |
2079 | - |
2080 | - def _filter_not(self, orig_val, target_val): |
2081 | - """ |
2082 | - _filter_not: filter function that hides rows |
2083 | - if one of the tags supplied in "bugs_tags_s" are found |
2084 | - in the gtk.TextEntry. |
2085 | - |
2086 | - Do not call directly |
2087 | - |
2088 | - """ |
2089 | - if len(target_val) == 0: |
2090 | - return True |
2091 | - |
2092 | - tags_on_bug = orig_val.split() |
2093 | - tags_in_filter = target_val.split() |
2094 | + def __init__(self): |
2095 | + BlankFilterBox.__init__(self) |
2096 | + self.append(_("has any of these tags"), self._filter_any) |
2097 | + self.append(_("has all of these tags"), self._filter_all) |
2098 | + self.append(_("does not have one of these tags"), self._filter_not) |
2099 | + self.append(_("does not have any of these tags"), self._filter_not_all) |
2100 | + |
2101 | + def _filter_any(self, orig_val, target_val): |
2102 | + """ |
2103 | + _filter_any: filter function that hides rows |
2104 | + if none of the tags supplied in "bugs_tags_s" are found |
2105 | + in the Gtk.TextEntry. |
2106 | + |
2107 | + Do not call directly |
2108 | + |
2109 | + """ |
2110 | + |
2111 | + if len(target_val) == 0: |
2112 | + return True |
2113 | + |
2114 | + tags_on_bug = orig_val.split() |
2115 | + tags_in_filter = target_val.split() |
2116 | + |
2117 | + for tag in tags_in_filter: |
2118 | + if tag in tags_on_bug: |
2119 | + return True |
2120 | + return False |
2121 | + |
2122 | + def _filter_all(self, orig_val, target_val): |
2123 | + """ |
2124 | + _filter_any: filter function that hides rows |
2125 | + if not all of the tags supplied in "bugs_tags_s" are found |
2126 | + in the Gtk.TextEntry. |
2127 | + |
2128 | + Do not call directly |
2129 | + |
2130 | + """ |
2131 | + if len(target_val) == 0: |
2132 | + return True |
2133 | + |
2134 | + tags_on_bug = orig_val.split() |
2135 | + tags_in_filter = self.entry.get_text().split() |
2136 | + |
2137 | + for tag in tags_in_filter: |
2138 | + if tag not in tags_on_bug: |
2139 | + return False |
2140 | + return True |
2141 | + |
2142 | + def _filter_not(self, orig_val, target_val): |
2143 | + """ |
2144 | + _filter_not: filter function that hides rows |
2145 | + if one of the tags supplied in "bugs_tags_s" are found |
2146 | + in the Gtk.TextEntry. |
2147 | + |
2148 | + Do not call directly |
2149 | + |
2150 | + """ |
2151 | + if len(target_val) == 0: |
2152 | + return True |
2153 | + |
2154 | + tags_on_bug = orig_val.split() |
2155 | + tags_in_filter = target_val.split() |
2156 | |
2157 | - for tag in tags_in_filter: |
2158 | - if tag not in tags_on_bug: |
2159 | - return True |
2160 | - return False |
2161 | - |
2162 | - def _filter_not_all(self, orig_val, target_val): |
2163 | - """ |
2164 | - _filter_not all: filter function that hides rows |
2165 | - if all of the tags supplied in "bugs_tags_s" are found |
2166 | - in the gtk.TextEntry. |
2167 | - |
2168 | - Do not call directly |
2169 | - |
2170 | - """ |
2171 | - if len(self.entry.get_text()) == 0: |
2172 | - return True |
2173 | - |
2174 | - tags_on_bug = orig_val.split() |
2175 | - tags_in_filter = target_val.split() |
2176 | - |
2177 | - for tag in tags_in_filter: |
2178 | - if tag in tags_on_bug: |
2179 | - return False |
2180 | - return True |
2181 | - |
2182 | -class IntegerFilterBox( gtk.HBox ): |
2183 | - """ |
2184 | - |
2185 | - """ |
2186 | - __gsignals__ = {'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
2187 | - (gobject.TYPE_PYOBJECT,)), |
2188 | - } |
2189 | - |
2190 | - def __init__(self): |
2191 | - gtk.HBox.__init__(self, False, 10) |
2192 | - self.__combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) |
2193 | - self.combo = gtk.ComboBox(self.__combo_store) |
2194 | - cell = gtk.CellRendererText() |
2195 | - self.combo.pack_start(cell, True) |
2196 | - self.combo.add_attribute(cell, 'text', 0) |
2197 | - self.combo.show() |
2198 | - self.combo.connect("changed",self.__changed) |
2199 | - adj = gtk.Adjustment(0,-1000000000,1000000000,1) |
2200 | - |
2201 | - self.spinner = gtk.SpinButton(adj,1,0) |
2202 | - self.spinner.set_activates_default(True) |
2203 | - self.spinner.show() |
2204 | - self.spinner.set_numeric(True) |
2205 | - |
2206 | - self.spinner.connect("value-changed",self.__changed) |
2207 | - self.pack_start(self.combo, False, False) |
2208 | - self.pack_start(self.spinner) |
2209 | - |
2210 | - self.__combo_store.append(["=",self._equals]) |
2211 | - self.__combo_store.append(["<",self._less_than]) |
2212 | - self.__combo_store.append([">",self._greater_than]) |
2213 | - self.__combo_store.append(["<=",self._less_than_equals]) |
2214 | - self.__combo_store.append([">=",self._greater_than_equals]) |
2215 | - |
2216 | - def __changed(self, widget, data=None): |
2217 | - self.emit("changed",data) |
2218 | - |
2219 | - def filter(self, orig_val): |
2220 | - if self.combo.get_active() == -1: |
2221 | - return True |
2222 | - |
2223 | - filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2224 | - filt_func = self.combo.get_model().get_value(filt_iter,1) |
2225 | - |
2226 | - try: |
2227 | - target_val = int(self.spinner.get_value_as_int()) |
2228 | - |
2229 | - |
2230 | - except Exception, inst: |
2231 | - print inst |
2232 | - return False |
2233 | - |
2234 | - return filt_func(orig_val, target_val) |
2235 | - |
2236 | - def _equals(self, orig_val, target_val): |
2237 | - if orig_val == "": |
2238 | - return False |
2239 | - return int(orig_val) == target_val |
2240 | - |
2241 | - def _less_than(self, orig_val, target_val): |
2242 | - if orig_val == "": |
2243 | - return False |
2244 | - return int(orig_val) < target_val |
2245 | - |
2246 | - def _greater_than(self, orig_val, target_val): |
2247 | - if orig_val == "": |
2248 | - return False |
2249 | - return int(orig_val) > target_val |
2250 | - |
2251 | - def _less_than_equals(self, orig_val, target_val): |
2252 | - if orig_val == "": |
2253 | - return False |
2254 | - return int(orig_val) <= target_val |
2255 | - |
2256 | - def _greater_than_equals(self, orig_val, target_val): |
2257 | - if orig_val == "": |
2258 | - return False |
2259 | - return int(orig_val) >= target_val |
2260 | - |
2261 | -class DateFilterBox( gtk.HBox ): |
2262 | - """DateFilterCombo: A default date filter class for use in a FilterRow. |
2263 | + for tag in tags_in_filter: |
2264 | + if tag not in tags_on_bug: |
2265 | + return True |
2266 | + return False |
2267 | + |
2268 | + def _filter_not_all(self, orig_val, target_val): |
2269 | + """ |
2270 | + _filter_not all: filter function that hides rows |
2271 | + if all of the tags supplied in "bugs_tags_s" are found |
2272 | + in the Gtk.TextEntry. |
2273 | + |
2274 | + Do not call directly |
2275 | + |
2276 | + """ |
2277 | + if len(self.entry.get_text()) == 0: |
2278 | + return True |
2279 | + |
2280 | + tags_on_bug = orig_val.split() |
2281 | + tags_in_filter = target_val.split() |
2282 | + |
2283 | + for tag in tags_in_filter: |
2284 | + if tag in tags_on_bug: |
2285 | + return False |
2286 | + return True |
2287 | + |
2288 | +class IntegerFilterBox( Gtk.HBox ): |
2289 | + """ |
2290 | + |
2291 | + """ |
2292 | + __gsignals__ = {'changed' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
2293 | + (GObject.TYPE_PYOBJECT,)), |
2294 | + } |
2295 | + |
2296 | + def __init__(self): |
2297 | + Gtk.HBox.__init__(self, False, 10) |
2298 | + self.__combo_store = Gtk.ListStore(GObject.TYPE_STRING,GObject.TYPE_PYOBJECT) |
2299 | + self.combo = Gtk.ComboBox.new_with_model(self.__combo_store) |
2300 | + cell = Gtk.CellRendererText() |
2301 | + self.combo.pack_start(cell, True) |
2302 | + self.combo.add_attribute(cell, 'text', 0) |
2303 | + self.combo.show() |
2304 | + self.combo.connect("changed",self.__changed) |
2305 | + adj = Gtk.Adjustment(0,-1000000000,1000000000,1) |
2306 | + |
2307 | + self.spinner = Gtk.SpinButton.new(adj,1,0) |
2308 | + self.spinner.set_activates_default(True) |
2309 | + self.spinner.show() |
2310 | + self.spinner.set_numeric(True) |
2311 | + |
2312 | + self.spinner.connect("value-changed",self.__changed) |
2313 | + self.pack_start(self.combo, False, False, 0) |
2314 | + self.pack_start(self.spinner, True, True, 0) |
2315 | + |
2316 | + self.__combo_store.append(["=",self._equals]) |
2317 | + self.__combo_store.append(["<",self._less_than]) |
2318 | + self.__combo_store.append([">",self._greater_than]) |
2319 | + self.__combo_store.append(["<=",self._less_than_equals]) |
2320 | + self.__combo_store.append([">=",self._greater_than_equals]) |
2321 | + |
2322 | + def __changed(self, widget, data=None): |
2323 | + self.emit("changed",data) |
2324 | + |
2325 | + def filter(self, orig_val): |
2326 | + if self.combo.get_active() == -1: |
2327 | + return True |
2328 | + |
2329 | + filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2330 | + filt_func = self.combo.get_model().get_value(filt_iter,1) |
2331 | + |
2332 | + try: |
2333 | + target_val = int(self.spinner.get_value_as_int()) |
2334 | + except Exception, inst: |
2335 | + print inst |
2336 | + return False |
2337 | + |
2338 | + return filt_func(orig_val, target_val) |
2339 | + |
2340 | + def _equals(self, orig_val, target_val): |
2341 | + if orig_val == "": |
2342 | + return False |
2343 | + return int(orig_val) == target_val |
2344 | + |
2345 | + def _less_than(self, orig_val, target_val): |
2346 | + if orig_val == "": |
2347 | + return False |
2348 | + return int(orig_val) < target_val |
2349 | + |
2350 | + def _greater_than(self, orig_val, target_val): |
2351 | + if orig_val == "": |
2352 | + return False |
2353 | + return int(orig_val) > target_val |
2354 | + |
2355 | + def _less_than_equals(self, orig_val, target_val): |
2356 | + if orig_val == "": |
2357 | + return False |
2358 | + return int(orig_val) <= target_val |
2359 | + |
2360 | + def _greater_than_equals(self, orig_val, target_val): |
2361 | + if orig_val == "": |
2362 | + return False |
2363 | + return int(orig_val) >= target_val |
2364 | + |
2365 | +class DateFilterBox( Gtk.HBox ): |
2366 | + """DateFilterCombo: A default date filter class for use in a FilterRow. |
2367 | |
2368 | Lets the user specify if the row should be displayed based on |
2369 | the settings in a date widget. |
2370 | |
2371 | - """ |
2372 | - __gsignals__ = {'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
2373 | - (gobject.TYPE_PYOBJECT,)), |
2374 | - } |
2375 | + """ |
2376 | + __gsignals__ = {'changed' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
2377 | + (GObject.TYPE_PYOBJECT,)), |
2378 | + } |
2379 | |
2380 | - def __init__(self): |
2381 | - """create a CheckFilterCombo |
2382 | + def __init__(self): |
2383 | + """create a CheckFilterCombo |
2384 | |
2385 | - """ |
2386 | - gtk.HBox.__init__(self, False, 10) |
2387 | - |
2388 | - self.__combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) |
2389 | - self.combo = gtk.ComboBox(self.__combo_store) |
2390 | - cell = gtk.CellRendererText() |
2391 | - self.combo.pack_start(cell, False) |
2392 | - self.combo.add_attribute(cell, 'text', 0) |
2393 | - self.combo.show() |
2394 | - self.combo.connect("changed",self.__changed) |
2395 | - |
2396 | - self.__combo_store.append([ _("before"),self.before ]) |
2397 | - self.__combo_store.append([ _("on or before"),self.on_before ]) |
2398 | - self.__combo_store.append([ _("on"), self.on_date ]) |
2399 | - self.__combo_store.append([ _("on or after"),self.on_after ]) |
2400 | - self.__combo_store.append([ _("after"),self.after ]) |
2401 | - |
2402 | - self.calendar = gtk.Calendar() |
2403 | - self.calendar.show() |
2404 | - self.calendar.connect("day-selected", self.__changed) |
2405 | - vb = gtk.VBox(False, 5) |
2406 | - vb.show() |
2407 | - vb.pack_start(self.combo, True, False) |
2408 | - self.pack_start(vb, False, False) |
2409 | - self.pack_start(self.calendar, False, False) |
2410 | - |
2411 | - def before(self, orig_val): |
2412 | - stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2413 | - if stored_date is None: |
2414 | - return False |
2415 | - return stored_date < target_date |
2416 | - |
2417 | - def on_before(self, orig_val): |
2418 | - stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2419 | - if stored_date is None: |
2420 | - return False |
2421 | - return stored_date <= target_date |
2422 | - |
2423 | - def on_date(self, orig_val): |
2424 | - stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2425 | - if stored_date is None: |
2426 | - return False |
2427 | - return stored_date == target_date |
2428 | - |
2429 | - def on_after(self, orig_val): |
2430 | - stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2431 | - if stored_date is None: |
2432 | - return False |
2433 | - return stored_date >= target_date |
2434 | - |
2435 | - def after(self, orig_val): |
2436 | - stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2437 | - if stored_date is None: |
2438 | - return False |
2439 | - return stored_date > target_date |
2440 | - |
2441 | - def __get_dates(self, orig_val, target_date): |
2442 | - target_date = self.calendar.get_date() |
2443 | - target_date = datetime.date(int(target_date[0]),int(target_date[1] + 1),int(target_date[2])) |
2444 | - if orig_val is not None and len(orig_val) > 0: |
2445 | - p = orig_val.split("-") |
2446 | - stored_date = datetime.date(int(p[0]),int(p[1]),int(p[2])) |
2447 | - else: |
2448 | - stored_date = None |
2449 | - return (stored_date, target_date) |
2450 | - |
2451 | - def filter(self, orig_val): |
2452 | - if self.combo.get_active() == -1: |
2453 | - return True |
2454 | - |
2455 | - filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2456 | - filt_func = self.combo.get_model().get_value(filt_iter,1) |
2457 | - return filt_func(orig_val) |
2458 | - |
2459 | - def __changed(self, widget, data=None): |
2460 | - self.emit("changed",data) |
2461 | - |
2462 | - |
2463 | -class CheckFilterBox( gtk.HBox ): |
2464 | - """CheckFilterCombo: A default checkbox filter class for use in a FilterRow. |
2465 | + """ |
2466 | + Gtk.HBox.__init__(self, False, 10) |
2467 | + |
2468 | + self.__combo_store = Gtk.ListStore(GObject.TYPE_STRING,GObject.TYPE_PYOBJECT) |
2469 | + self.combo = Gtk.ComboBox.new_with_model(self.__combo_store) |
2470 | + cell = Gtk.CellRendererText() |
2471 | + self.combo.pack_start(cell, False) |
2472 | + self.combo.add_attribute(cell, 'text', 0) |
2473 | + self.combo.show() |
2474 | + self.combo.connect("changed",self.__changed) |
2475 | + |
2476 | + self.__combo_store.append([ _("before"),self.before ]) |
2477 | + self.__combo_store.append([ _("on or before"),self.on_before ]) |
2478 | + self.__combo_store.append([ _("on"), self.on_date ]) |
2479 | + self.__combo_store.append([ _("on or after"),self.on_after ]) |
2480 | + self.__combo_store.append([ _("after"),self.after ]) |
2481 | + |
2482 | + self.calendar = Gtk.Calendar() |
2483 | + self.calendar.show() |
2484 | + self.calendar.connect("day-selected", self.__changed) |
2485 | + vb = Gtk.VBox(False, 5) |
2486 | + vb.show() |
2487 | + vb.pack_start(self.combo, True, False, 0) |
2488 | + self.pack_start(vb, False, False, 0) |
2489 | + self.pack_start(self.calendar, False, False, 0) |
2490 | + |
2491 | + def before(self, orig_val): |
2492 | + stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2493 | + if stored_date is None: |
2494 | + return False |
2495 | + return stored_date < target_date |
2496 | + |
2497 | + def on_before(self, orig_val): |
2498 | + stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2499 | + if stored_date is None: |
2500 | + return False |
2501 | + return stored_date <= target_date |
2502 | + |
2503 | + def on_date(self, orig_val): |
2504 | + stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2505 | + if stored_date is None: |
2506 | + return False |
2507 | + return stored_date == target_date |
2508 | + |
2509 | + def on_after(self, orig_val): |
2510 | + stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2511 | + if stored_date is None: |
2512 | + return False |
2513 | + return stored_date >= target_date |
2514 | + |
2515 | + def after(self, orig_val): |
2516 | + stored_date, target_date = self.__get_dates(orig_val, self.calendar.get_date()) |
2517 | + if stored_date is None: |
2518 | + return False |
2519 | + return stored_date > target_date |
2520 | + |
2521 | + def __get_dates(self, orig_val, target_date): |
2522 | + target_date = self.calendar.get_date() |
2523 | + target_date = datetime.date(int(target_date[0]),int(target_date[1] + 1),int(target_date[2])) |
2524 | + if orig_val is not None and len(orig_val) > 0: |
2525 | + p = orig_val.split("-") |
2526 | + stored_date = datetime.date(int(p[0]),int(p[1]),int(p[2])) |
2527 | + else: |
2528 | + stored_date = None |
2529 | + return (stored_date, target_date) |
2530 | + |
2531 | + def filter(self, orig_val): |
2532 | + if self.combo.get_active() == -1: |
2533 | + return True |
2534 | + |
2535 | + filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2536 | + filt_func = self.combo.get_model().get_value(filt_iter,1) |
2537 | + return filt_func(orig_val) |
2538 | + |
2539 | + def __changed(self, widget, data=None): |
2540 | + self.emit("changed",data) |
2541 | + |
2542 | +class CheckFilterBox( Gtk.HBox ): |
2543 | + """CheckFilterCombo: A default checkbox filter class for use in a FilterRow. |
2544 | |
2545 | Lets the user specify if the row should be displayed based on |
2546 | whether a Checkbox is active, inactive, or not set. |
2547 | |
2548 | - """ |
2549 | - __gsignals__ = {'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
2550 | - (gobject.TYPE_PYOBJECT,)), |
2551 | - } |
2552 | + """ |
2553 | + __gsignals__ = {'changed' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, |
2554 | + (GObject.TYPE_PYOBJECT,)), |
2555 | + } |
2556 | |
2557 | - def __init__(self): |
2558 | - """create a CheckFilterCombo |
2559 | + def __init__(self): |
2560 | + """create a CheckFilterCombo |
2561 | |
2562 | - """ |
2563 | - gtk.HBox.__init__(self, False, 10) |
2564 | - |
2565 | - self.__combo_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) |
2566 | - self.combo = gtk.ComboBox(self.__combo_store) |
2567 | - cell = gtk.CellRendererText() |
2568 | - self.combo.pack_start(cell, True) |
2569 | - self.combo.add_attribute(cell, 'text', 0) |
2570 | - self.combo.show() |
2571 | - self.combo.connect("changed",self.__changed) |
2572 | - |
2573 | - self.__combo_store.append([ _("checked"),self.filter_checked ]) |
2574 | - self.__combo_store.append([ _("not Checked"),self.filter_not_checked ]) |
2575 | - self.__combo_store.append([ _("unset"), self.filter_unset ]) |
2576 | - |
2577 | - self.pack_start(self.combo, False, False) |
2578 | - |
2579 | - def filter(self, orig_val): |
2580 | - if self.combo.get_active() == -1: |
2581 | - return True |
2582 | - |
2583 | - filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2584 | - filt_func = self.combo.get_model().get_value(filt_iter,1) |
2585 | - return filt_func(orig_val) |
2586 | - |
2587 | - def filter_checked(self, orig_val): |
2588 | - return orig_val == 1 |
2589 | - |
2590 | - def filter_not_checked(self, orig_val): |
2591 | - return orig_val == 0 |
2592 | - |
2593 | - def filter_unset(self, orig_val): |
2594 | - return orig_val == -1 |
2595 | - |
2596 | - def __changed(self, widget, data=None): |
2597 | - self.emit("changed",data) |
2598 | + """ |
2599 | + Gtk.HBox.__init__(self, False, 10) |
2600 | + |
2601 | + self.__combo_store = Gtk.ListStore(GObject.TYPE_STRING,GObject.TYPE_PYOBJECT) |
2602 | + self.combo = Gtk.ComboBox.new_with_model(self.__combo_store) |
2603 | + cell = Gtk.CellRendererText() |
2604 | + self.combo.pack_start(cell, True) |
2605 | + self.combo.add_attribute(cell, 'text', 0) |
2606 | + self.combo.show() |
2607 | + self.combo.connect("changed",self.__changed) |
2608 | + |
2609 | + self.__combo_store.append([ _("checked"),self.filter_checked ]) |
2610 | + self.__combo_store.append([ _("not Checked"),self.filter_not_checked ]) |
2611 | + self.__combo_store.append([ _("unset"), self.filter_unset ]) |
2612 | + |
2613 | + self.pack_start(self.combo, False, False, 0) |
2614 | + |
2615 | + def filter(self, orig_val): |
2616 | + if self.combo.get_active() == -1: |
2617 | + return True |
2618 | + |
2619 | + filt_iter = self.combo.get_model().get_iter(self.combo.get_active()) |
2620 | + filt_func = self.combo.get_model().get_value(filt_iter,1) |
2621 | + return filt_func(orig_val) |
2622 | + |
2623 | + def filter_checked(self, orig_val): |
2624 | + return orig_val == 1 |
2625 | + |
2626 | + def filter_not_checked(self, orig_val): |
2627 | + return orig_val == 0 |
2628 | + |
2629 | + def filter_unset(self, orig_val): |
2630 | + return orig_val == -1 |
2631 | + |
2632 | + def __changed(self, widget, data=None): |
2633 | + self.emit("changed",data) |
2634 | |
2635 | |
2636 | class NumericFilterBox( BlankFilterBox ): |
2637 | - """NumericFilterCombo: A default number filter class for use in a FilterRow. |
2638 | + """NumericFilterCombo: A default number filter class for use in a FilterRow. |
2639 | |
2640 | Lets the user specify if the row should be displayed based on numeric |
2641 | relationships to a number specified by the user. |
2642 | |
2643 | - """ |
2644 | - |
2645 | - |
2646 | - def __init__(self): |
2647 | - """create a NumericFilterCombo |
2648 | - |
2649 | - """ |
2650 | - BlankFilterBox.__init__( self ) |
2651 | - self.append("=",self._equals ) |
2652 | - self.append("<",self._less_than ) |
2653 | - self.append(">",self._greater_than ) |
2654 | - self.append("<=",self._less_than_equals) |
2655 | - self.append(">=",self._greater_than_equals ) |
2656 | - |
2657 | - def _equals(self, orig_val): |
2658 | - try: |
2659 | - return float(orig_val) == float(self.entry.get_text()) |
2660 | - except: |
2661 | - return True |
2662 | - |
2663 | - def _less_than(self, orig_val): |
2664 | - try: |
2665 | - return float(orig_val) < float(self.entry.get_text()) |
2666 | - except: |
2667 | - return True |
2668 | - |
2669 | - def _greater_than(self, orig_val): |
2670 | - try: |
2671 | - return float(orig_val) > float(self.entry.get_text()) |
2672 | - except: |
2673 | - return True |
2674 | - |
2675 | - def _less_than_equals(self, orig_val): |
2676 | - try: |
2677 | - return float(orig_val) <= float(self.entry.get_text()) |
2678 | - except: |
2679 | - return True |
2680 | - |
2681 | - def _greater_than_equals(self, orig_val): |
2682 | - try: |
2683 | - return float(orig_val) >= float(self.entry.get_text()) |
2684 | - except: |
2685 | - return True |
2686 | + """ |
2687 | + |
2688 | + |
2689 | + def __init__(self): |
2690 | + """create a NumericFilterCombo |
2691 | + |
2692 | + """ |
2693 | + BlankFilterBox.__init__( self ) |
2694 | + self.append("=",self._equals ) |
2695 | + self.append("<",self._less_than ) |
2696 | + self.append(">",self._greater_than ) |
2697 | + self.append("<=",self._less_than_equals) |
2698 | + self.append(">=",self._greater_than_equals ) |
2699 | + |
2700 | + def _equals(self, orig_val): |
2701 | + try: |
2702 | + return float(orig_val) == float(self.entry.get_text()) |
2703 | + except: |
2704 | + return True |
2705 | + |
2706 | + def _less_than(self, orig_val): |
2707 | + try: |
2708 | + return float(orig_val) < float(self.entry.get_text()) |
2709 | + except: |
2710 | + return True |
2711 | + |
2712 | + def _greater_than(self, orig_val): |
2713 | + try: |
2714 | + return float(orig_val) > float(self.entry.get_text()) |
2715 | + except: |
2716 | + return True |
2717 | + |
2718 | + def _less_than_equals(self, orig_val): |
2719 | + try: |
2720 | + return float(orig_val) <= float(self.entry.get_text()) |
2721 | + except: |
2722 | + return True |
2723 | + |
2724 | + def _greater_than_equals(self, orig_val): |
2725 | + try: |
2726 | + return float(orig_val) >= float(self.entry.get_text()) |
2727 | + except: |
2728 | + return True |
2729 | + |
2730 | + |
2731 | +# Test case begins here. |
2732 | |
2733 | def __delete_test(button, grid): |
2734 | grid.remove_selected_rows(delete=True) |
2735 | |
2736 | if __name__ == "__main__": |
2737 | - """creates a test CouchGrid if called directly""" |
2738 | - from couch_grid import CouchGrid |
2739 | + """creates a test DictionaryGrid and GridFilter if called directly""" |
2740 | + from dictionary_grid import DictionaryGrid |
2741 | |
2742 | #create and show a test window |
2743 | - win = gtk.Window(gtk.WINDOW_TOPLEVEL) |
2744 | - win.set_title("DictionaryGrid Test Window") |
2745 | - win.connect("destroy",gtk.main_quit) |
2746 | + win = Gtk.Window.new(Gtk.WindowType.TOPLEVEL) |
2747 | + win.set_title("CouchGrid Test Window") |
2748 | + win.connect("destroy",Gtk.main_quit) |
2749 | win.show() |
2750 | |
2751 | #create a top level container |
2752 | - vbox = gtk.VBox(False, 10) |
2753 | + vbox = Gtk.VBox(False, 10) |
2754 | vbox.show() |
2755 | win.add(vbox) |
2756 | |
2757 | @@ -821,9 +817,7 @@ |
2758 | {"ID": 3, "key?": False, "tags": "ddd eee fff", "string":"dddddddd","date":"2010-10-01"}, |
2759 | {"ID": 4, "key?": True, "tags": "eee fff ggg", "string":"eeeeeeee","date":"2010-11-01"}] |
2760 | |
2761 | - database_name = "couch_widget_test" |
2762 | - record_type = "couch_grid_filter_test" |
2763 | - grid = CouchGrid(database_name, record_type=record_type, dictionaries=dicts, editable=True) |
2764 | + grid = DictionaryGrid(dictionaries=dicts, editable=True) |
2765 | grid.columns["tags"].set_title("modified title") |
2766 | grid.show() |
2767 | |
2768 | @@ -831,15 +825,15 @@ |
2769 | hints = {} |
2770 | filt = GridFilter(grid,hints) |
2771 | filt.show() |
2772 | - vbox.pack_start(filt, False, False) |
2773 | - vbox.pack_end(grid, True, True) |
2774 | + vbox.pack_start(filt, False, False, 0) |
2775 | + vbox.pack_end(grid, True, True, 0) |
2776 | |
2777 | - delete_button = gtk.Button("Delete Selected") |
2778 | + delete_button = Gtk.Button("Delete Selected") |
2779 | delete_button.connect("clicked",__delete_test,grid) |
2780 | delete_button.show() |
2781 | |
2782 | |
2783 | - vbox.pack_start(delete_button,False, False) |
2784 | - gtk.main() |
2785 | + vbox.pack_start(delete_button,False, False, 0) |
2786 | + Gtk.main() |
2787 | |
2788 | |
2789 | |
2790 | === modified file 'quickly/widgets/media_player_box.py' |
2791 | --- quickly/widgets/media_player_box.py 2011-01-17 03:40:02 +0000 |
2792 | +++ quickly/widgets/media_player_box.py 2012-03-06 08:52:21 +0000 |
2793 | @@ -50,14 +50,14 @@ |
2794 | #You can add Widgets to the MediaPlayerBox simply by packing them in |
2795 | player.pack_start(my_widget, False, False) |
2796 | |
2797 | -#You can get a reference to the controls, which are a gtk.Toolbar |
2798 | -mybutton = gtk.ToolButton() |
2799 | +#You can get a reference to the controls, which are a Gtk.Toolbar |
2800 | +mybutton = Gtk.ToolButton() |
2801 | player.controls.insert(mybutton, 0) |
2802 | |
2803 | #You can access the playbutton, slider, or time label directly as well |
2804 | -player.play_button.hide()#a gtk.ToggleToolButton |
2805 | -player.slider.hide()#a gtk.HScale |
2806 | -player.time_label.hide()#a gtk.Label |
2807 | +player.play_button.hide()#a Gtk.ToggleToolButton |
2808 | +player.slider.hide()#a Gtk.HScale |
2809 | +player.time_label.hide()#a Gtk.Label |
2810 | |
2811 | #If you want access to all the gstreamer knobs and dials, you can just |
2812 | #get a reference to the playbin (see gstreamer documentation for details. |
2813 | @@ -67,13 +67,13 @@ |
2814 | player.playbin.emit(signal_name) |
2815 | |
2816 | Extending |
2817 | -A WebCamBox is gtk.VBox |
2818 | -A WebCamBox is a gtk.VBox that contains a gtk.DrawingArea for displaying |
2819 | +A WebCamBox is Gtk.VBox |
2820 | +A WebCamBox is a Gtk.VBox that contains a Gtk.DrawingArea for displaying |
2821 | video output, and a thin wrapper around a playbin, which is a gstreamer |
2822 | pipleine sublcass that provides all the media playing functionality. |
2823 | |
2824 | To add GUI elements simple, create them and pack them into MediaPlayerBox, since |
2825 | -it's just a gtk.VBox |
2826 | +it's just a Gtk.VBox |
2827 | |
2828 | Similarly, to add to or change the media player functionality, modify properties on |
2829 | the playbin. You may also want to overide _on_message and/or _on_sync_message |
2830 | @@ -81,18 +81,21 @@ |
2831 | |
2832 | """ |
2833 | |
2834 | + |
2835 | import sys |
2836 | import os |
2837 | -import gtk |
2838 | +from gi.repository import Gtk |
2839 | +from gi.repository import Gdk |
2840 | +from gi.repository import GdkX11 |
2841 | +from gi.repository import GObject |
2842 | import gst |
2843 | import datetime |
2844 | -import gobject |
2845 | |
2846 | import gettext |
2847 | from gettext import gettext as _ |
2848 | gettext.textdomain('quickly-widgets') |
2849 | |
2850 | -class MediaPlayerBox(gtk.VBox): |
2851 | +class MediaPlayerBox(Gtk.VBox): |
2852 | """MediaPlayerBox - A VBox that tries to play the media file as defined by it's URU property. |
2853 | It works for video and sound files. |
2854 | |
2855 | @@ -102,13 +105,13 @@ |
2856 | """Creates a MediaPlayerBox, Note that this does not start media. |
2857 | For that, set the uri property and then call play(). |
2858 | |
2859 | - This function has no arguments |
2860 | + This function has no argumentsf |
2861 | |
2862 | """ |
2863 | - gtk.VBox.__init__(self, False, 5) |
2864 | - self.video_window = gtk.DrawingArea() |
2865 | + Gtk.VBox.__init__(self, False, 5) |
2866 | + self.video_window = Gtk.DrawingArea() |
2867 | self.video_window.connect("realize",self.__on_video_window_realized) |
2868 | -# self.pack_start(self.video_window, True, True) |
2869 | +# self.pack_start(self.video_window, True, True, 0) |
2870 | self.video_window.show() |
2871 | self.connect("destroy", self.on_destroy) |
2872 | |
2873 | @@ -121,21 +124,21 @@ |
2874 | self.__uri = "" |
2875 | self.realized = False |
2876 | |
2877 | - self.controls = gtk.Toolbar() |
2878 | + self.controls = Gtk.Toolbar() |
2879 | if show_controls: |
2880 | self.controls.show() |
2881 | - self.pack_start(self.controls, False, False) |
2882 | - self.pack_start(self.video_window, True, True) |
2883 | + self.pack_start(self.controls, False, False, 0) |
2884 | + self.pack_start(self.video_window, True, True, 0) |
2885 | |
2886 | - self.play_button = gtk.ToggleToolButton() |
2887 | - self.play_button.set_stock_id(gtk.STOCK_MEDIA_PLAY) |
2888 | + self.play_button = Gtk.ToggleToolButton() |
2889 | + self.play_button.set_stock_id(Gtk.STOCK_MEDIA_PLAY) |
2890 | self.play_button.show() |
2891 | self._play_button_toggled_handler = self.play_button.connect("toggled",self._play_button_toggled) |
2892 | self.controls.add(self.play_button) |
2893 | |
2894 | - item = gtk.ToolItem() |
2895 | + item = Gtk.ToolItem() |
2896 | item.show() |
2897 | - self.slider = gtk.HScale() |
2898 | + self.slider = Gtk.HScale() |
2899 | self.slider_changed_handler = None |
2900 | self.slider.set_draw_value(False) |
2901 | self.slider.set_increments(10,60) |
2902 | @@ -145,9 +148,9 @@ |
2903 | item.add(self.slider) |
2904 | self.controls.insert(item, -1) |
2905 | |
2906 | - item2 = gtk.ToolItem() |
2907 | + item2 = Gtk.ToolItem() |
2908 | item2.show() |
2909 | - self.time_label = gtk.Label("") |
2910 | + self.time_label = Gtk.Label("") |
2911 | self.time_label.show() |
2912 | item2.add(self.time_label) |
2913 | self.controls.insert(item2, -1) |
2914 | @@ -175,7 +178,7 @@ |
2915 | self.slider.set_sensitive(True) |
2916 | self._reformat_slider() |
2917 | self._start_slider_updates() |
2918 | - self.play_button.set_stock_id(gtk.STOCK_MEDIA_PAUSE) |
2919 | + self.play_button.set_stock_id(Gtk.STOCK_MEDIA_PAUSE) |
2920 | self._set_play_button_active(True) |
2921 | |
2922 | def pause(self): |
2923 | @@ -186,11 +189,12 @@ |
2924 | This function has no arguments |
2925 | |
2926 | """ |
2927 | + |
2928 | self.playbin.set_state(gst.STATE_PAUSED) |
2929 | self.slider.set_sensitive(True) |
2930 | self._reformat_slider() |
2931 | self.slider.set_sensitive(True) |
2932 | - self.play_button.set_stock_id(gtk.STOCK_MEDIA_PLAY) |
2933 | + self.play_button.set_stock_id(Gtk.STOCK_MEDIA_PLAY) |
2934 | self._set_play_button_active(False) |
2935 | |
2936 | def stop(self): |
2937 | @@ -203,7 +207,7 @@ |
2938 | |
2939 | self.playbin.set_state(gst.STATE_NULL) |
2940 | self.slider.set_sensitive(False) |
2941 | - self.play_button.set_stock_id(gtk.STOCK_MEDIA_PLAY) |
2942 | + self.play_button.set_stock_id(Gtk.STOCK_MEDIA_PLAY) |
2943 | self._set_play_button_active(False) |
2944 | self.slider.set_value(0) |
2945 | |
2946 | @@ -305,7 +309,7 @@ |
2947 | if self.playbin.get_state()[1] == gst.STATE_NULL: |
2948 | self.slider.set_range(0, 0) |
2949 | else: |
2950 | - gobject.idle_add(self._set_slider_range) |
2951 | + GObject.idle_add(self._set_slider_range) |
2952 | |
2953 | def _set_slider_range(self): |
2954 | dur = self.duration |
2955 | @@ -313,16 +317,16 @@ |
2956 | return True |
2957 | else: |
2958 | self._duration_time_str = self._formatted_time(dur) |
2959 | - gtk.gdk.threads_enter() |
2960 | + Gdk.threads_enter() |
2961 | self.slider.set_range(0, dur) |
2962 | - gtk.gdk.threads_leave() |
2963 | + Gdk.threads_leave() |
2964 | return False |
2965 | |
2966 | def _start_slider_updates(self): |
2967 | if self.playbin.get_state()[1] == gst.STATE_NULL: |
2968 | self.slide.set_value(0) |
2969 | else: |
2970 | - gobject.timeout_add(1000, self._set_slider_position) |
2971 | + GObject.timeout_add(1000, self._set_slider_position) |
2972 | |
2973 | def _set_slider_position(self): |
2974 | if self._slider_changed_handler is not None: |
2975 | @@ -395,7 +399,7 @@ |
2976 | if message_name == "prepare-xwindow-id": |
2977 | imagesink = message.src |
2978 | imagesink.set_property("force-aspect-ratio", True) |
2979 | - imagesink.set_xwindow_id(self.video_window.window.xid) |
2980 | + imagesink.set_xwindow_id(self.video_window.get_window().get_xid()) |
2981 | |
2982 | def __on_video_window_realized(self, widget, data=None): |
2983 | """__on_video_window_realized - internal signal handler, used |
2984 | @@ -407,16 +411,16 @@ |
2985 | self._set_video_window_id() |
2986 | |
2987 | def _set_video_window_id(self): |
2988 | - if not self.realized and self.video_window.window is not None: |
2989 | - x = self.video_window.window.xid |
2990 | + if not self.realized and self.video_window.get_window() is not None: |
2991 | + x = self.video_window.get_window().get_xid() |
2992 | self.realized = True |
2993 | |
2994 | def on_destroy(self, widget, data=None): |
2995 | #clean up the camera before exiting |
2996 | self.playbin.set_state(gst.STATE_NULL) |
2997 | |
2998 | - __gsignals__ = {'end-of-file' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
2999 | - (gobject.TYPE_PYOBJECT,)), |
3000 | + __gsignals__ = {'end-of-file' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
3001 | + (GObject.TYPE_PYOBJECT,)), |
3002 | } |
3003 | |
3004 | def __seek_func(sender, mb): |
3005 | @@ -445,16 +449,15 @@ |
3006 | |
3007 | if __name__ == "__main__": |
3008 | """creates a test WebCamBox""" |
3009 | - import quickly.prompts |
3010 | |
3011 | #create and show a test window |
3012 | - win = gtk.Window(gtk.WINDOW_TOPLEVEL) |
3013 | + win = Gtk.Window() |
3014 | win.set_title("WebCam Test Window") |
3015 | - win.connect("destroy",gtk.main_quit) |
3016 | + win.connect("destroy",Gtk.main_quit) |
3017 | win.show() |
3018 | |
3019 | #create a top level container |
3020 | - vbox = gtk.VBox(False, 10) |
3021 | + vbox = Gtk.VBox(False, 10) |
3022 | vbox.show() |
3023 | win.add(vbox) |
3024 | |
3025 | @@ -464,47 +467,47 @@ |
3026 | vbox.add(mb) |
3027 | mb.show() |
3028 | |
3029 | - uri_entry = gtk.Entry() |
3030 | + uri_entry = Gtk.Entry() |
3031 | |
3032 | - play_butt = gtk.Button("Play") |
3033 | - pause_butt = gtk.Button("Pause") |
3034 | - stop_butt = gtk.Button("Stop") |
3035 | - seek_butt = gtk.Button("Seek") |
3036 | - controls_butt = gtk.ToggleButton("Controls") |
3037 | - time_label = gtk.Label("") |
3038 | + play_butt = Gtk.Button("Play") |
3039 | + pause_butt = Gtk.Button("Pause") |
3040 | + stop_butt = Gtk.Button("Stop") |
3041 | + seek_butt = Gtk.Button("Seek") |
3042 | + controls_butt = Gtk.ToggleButton("Controls") |
3043 | + time_label = Gtk.Label("") |
3044 | |
3045 | play_butt.connect("clicked", lambda x:mb.play()) |
3046 | play_butt.show() |
3047 | - mb.pack_end(play_butt, False) |
3048 | + mb.pack_end(play_butt, False, False, 0) |
3049 | |
3050 | uri_entry.connect("activate", __set_uri, (mb, uri_entry)) |
3051 | uri_entry.set_text("file:///home/rick/Videos/VID00110.AVI") |
3052 | uri_entry.show() |
3053 | - mb.pack_end(uri_entry, False) |
3054 | + mb.pack_end(uri_entry, False, False, 0) |
3055 | |
3056 | pause_butt.connect("clicked", lambda x:mb.pause()) |
3057 | pause_butt.show() |
3058 | - mb.pack_end(pause_butt, False) |
3059 | + mb.pack_end(pause_butt, False, False, 0) |
3060 | |
3061 | stop_butt.connect("clicked", lambda x:mb.stop()) |
3062 | stop_butt.show() |
3063 | - mb.pack_end(stop_butt, False) |
3064 | + mb.pack_end(stop_butt, False, False, 0) |
3065 | |
3066 | seek_butt.connect("clicked", __seek_func, mb) |
3067 | seek_butt.show() |
3068 | - mb.pack_end(seek_butt, False) |
3069 | + mb.pack_end(seek_butt, False, False, 0) |
3070 | |
3071 | controls_butt.connect("clicked", __controls_func, mb) |
3072 | controls_butt.show() |
3073 | - mb.pack_end(controls_butt, False) |
3074 | + mb.pack_end(controls_butt, False, False, 0) |
3075 | |
3076 | mb.connect("end-of-file", __on_media_ended) |
3077 | |
3078 | time_label.show() |
3079 | - mb.pack_end(time_label, False) |
3080 | - |
3081 | - gobject.timeout_add(1000, __seek_time, (mb, time_label)) |
3082 | - |
3083 | - gtk.main() |
3084 | + mb.pack_end(time_label, False, False, 0) |
3085 | + |
3086 | + GObject.timeout_add(1000, __seek_time, (mb, time_label)) |
3087 | + |
3088 | + Gtk.main() |
3089 | |
3090 | |
3091 | |
3092 | === modified file 'quickly/widgets/press_and_hold_button.py' |
3093 | --- quickly/widgets/press_and_hold_button.py 2011-01-17 20:27:12 +0000 |
3094 | +++ quickly/widgets/press_and_hold_button.py 2012-03-06 08:52:21 +0000 |
3095 | @@ -34,14 +34,14 @@ |
3096 | pah.set_labe("Press and Hold") |
3097 | |
3098 | Extending |
3099 | -A PressAndHoldButton is gtk.Button |
3100 | +A PressAndHoldButton is Gtk.Button |
3101 | |
3102 | """ |
3103 | |
3104 | -import gobject |
3105 | -import gtk |
3106 | +from gi.repository import GObject |
3107 | +from gi.repository import Gtk |
3108 | |
3109 | -class PressAndHoldButton(gtk.Button): |
3110 | +class PressAndHoldButton(Gtk.Button): |
3111 | def __init__(self): |
3112 | """Create a PressAndHoldButton |
3113 | |
3114 | @@ -51,7 +51,7 @@ |
3115 | |
3116 | """ |
3117 | |
3118 | - gtk.Button.__init__(self) |
3119 | + Gtk.Button.__init__(self) |
3120 | self.timeout = 250 |
3121 | self.connect("pressed",self.__pressed) |
3122 | self.connect("released",self.__released) |
3123 | @@ -60,7 +60,7 @@ |
3124 | def __pressed(self, widget, data=None): |
3125 | self.__continue_ticking = True |
3126 | widget.emit("tick",self) |
3127 | - gobject.timeout_add(self.timeout, self.__tick) |
3128 | + GObject.timeout_add(self.timeout, self.__tick) |
3129 | |
3130 | def __released(self, widget, data=None): |
3131 | self.__continue_ticking = False |
3132 | @@ -70,7 +70,44 @@ |
3133 | self.emit("tick",self) |
3134 | return self.__continue_ticking |
3135 | |
3136 | - __gsignals__ = {'tick' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
3137 | - (gobject.TYPE_PYOBJECT,)), |
3138 | + __gsignals__ = {'tick' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
3139 | + (GObject.TYPE_PYOBJECT,)), |
3140 | } |
3141 | |
3142 | +def __test_tick(sender, widget, label): |
3143 | + """internal method for testing. |
3144 | + Do not use. |
3145 | + """ |
3146 | + |
3147 | + label.set_text(str(int(label.get_text()) + 1)) |
3148 | + |
3149 | + |
3150 | + |
3151 | +if __name__ == "__main__": |
3152 | + """creates a test PressAndHoldButton""" |
3153 | + |
3154 | + #create and show a test window |
3155 | + win = Gtk.Window() |
3156 | + win.set_title("Press and Hold Test Window") |
3157 | + win.connect("destroy",Gtk.main_quit) |
3158 | + win.show() |
3159 | + |
3160 | + #create a top level container |
3161 | + vbox = Gtk.VBox(False, 10) |
3162 | + vbox.show() |
3163 | + win.add(vbox) |
3164 | + |
3165 | + button = PressAndHoldButton() |
3166 | + button.set_label("Press and hold") |
3167 | + button.show() |
3168 | + vbox.pack_start(button, False, False, 5) |
3169 | + |
3170 | + label = Gtk.Label("0") |
3171 | + label.show() |
3172 | + vbox.pack_end(label, False, False, 5) |
3173 | + |
3174 | + button.timeout = 10 |
3175 | + |
3176 | + button.connect("tick",__test_tick, label) |
3177 | + |
3178 | + Gtk.main() |
3179 | |
3180 | === removed file 'quickly/widgets/tests/test_asycnh_task_progress_box.py' |
3181 | --- quickly/widgets/tests/test_asycnh_task_progress_box.py 2010-03-30 23:38:02 +0000 |
3182 | +++ quickly/widgets/tests/test_asycnh_task_progress_box.py 1970-01-01 00:00:00 +0000 |
3183 | @@ -1,51 +0,0 @@ |
3184 | -### BEGIN LICENSE |
3185 | -# Copyright (C) 2010 Rick Spencer rick.spencer@canonical.com |
3186 | -#This program is free software: you can redistribute it and/or modify it |
3187 | -#under the terms of the GNU General Public License version 3, as published |
3188 | -#by the Free Software Foundation. |
3189 | -# |
3190 | -#This program is distributed in the hope that it will be useful, but |
3191 | -#WITHOUT ANY WARRANTY; without even the implied warranties of |
3192 | -#MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3193 | -#PURPOSE. See the GNU General Public License for more details. |
3194 | -# |
3195 | -#You should have received a copy of the GNU General Public License along |
3196 | -#with this program. If not, see <http://www.gnu.org/licenses/>. |
3197 | -### END LICENSE |
3198 | - |
3199 | -"""Tests for the AsyncTaskProgressBox""" |
3200 | - |
3201 | -from testtools import TestCase |
3202 | -from quickly.widgets.asynch_task_progressbox import AsynchTaskProgressBox |
3203 | - |
3204 | -class TestAsynchTaskProgessBox(TestCase): |
3205 | - """Test the CouchGrid functionality""" |
3206 | - |
3207 | - def setUp(self): |
3208 | - TestCase.setUp(self) |
3209 | - |
3210 | - def tearDown(self): |
3211 | - TestCase.tearDown(self) |
3212 | - |
3213 | - def test_constructions(self): |
3214 | - """Test a simple creating An AsynchTaskProgressBox """ |
3215 | - box = AsynchTaskProgressBox(self.asynch_function) |
3216 | - self.assertEqual((box != None), True) |
3217 | - |
3218 | - #A function to run asynchronously |
3219 | - def asynch_function( self, params ): |
3220 | - #pull values from the params that were set above |
3221 | - for x in range(params["start"],params["stop"]): |
3222 | - #check if to see if the user has told the task to stop |
3223 | - if params["kill"] == True: |
3224 | - #return a string if the user stopped the task |
3225 | - return "stopped at " + str(x) |
3226 | - else: |
3227 | - #if the user did not try to stop the task, go ahead and do something |
3228 | - print x |
3229 | - #this is a processor intensive task, so |
3230 | - #sleep the loop to keep the UI from bogging down |
3231 | - time.sleep(.5) |
3232 | - #if the loop completes, return a string |
3233 | - return "counted all" |
3234 | - |
3235 | |
3236 | === removed file 'quickly/widgets/tests/test_couch_grid.py' |
3237 | --- quickly/widgets/tests/test_couch_grid.py 2010-09-02 01:03:54 +0000 |
3238 | +++ quickly/widgets/tests/test_couch_grid.py 1970-01-01 00:00:00 +0000 |
3239 | @@ -1,284 +0,0 @@ |
3240 | -# Copyright 2009 Canonical Ltd. |
3241 | -# |
3242 | -# This file is part of desktopcouch. |
3243 | -# |
3244 | -# desktopcouch is free software: you can redistribute it and/or modify |
3245 | -# it under the terms of the GNU Lesser General Public License version 3 |
3246 | -# as published by the Free Software Foundation. |
3247 | -# |
3248 | -# desktopcouch is distributed in the hope that it will be useful, |
3249 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3250 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3251 | -# GNU Lesser General Public License for more details. |
3252 | -# |
3253 | -# You should have received a copy of the GNU Lesser General Public License |
3254 | -# along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
3255 | -# |
3256 | -# Authors: Rick Spencer <rick.spencer@canonical.com> |
3257 | - |
3258 | -"""Tests for the CouchGrid object""" |
3259 | - |
3260 | -from testtools import TestCase |
3261 | - |
3262 | -from desktopcouch.records.record import Record |
3263 | -from desktopcouch.records.server import CouchDatabase |
3264 | -from quickly.widgets.couch_grid import CouchGrid |
3265 | - |
3266 | - |
3267 | -class TestCouchGrid(TestCase): |
3268 | - """Test the CouchGrid functionality""" |
3269 | - |
3270 | - def setUp(self): |
3271 | - TestCase.setUp(self) |
3272 | - self.dbname = self._testMethodName |
3273 | - self.db = CouchDatabase(self.dbname, create=True) |
3274 | - self.record_type = "test_record_type" |
3275 | - |
3276 | - def tearDown(self): |
3277 | - """tear down each test""" |
3278 | - TestCase.tearDown(self) |
3279 | - #delete the database |
3280 | - del self.db._server[self.dbname] |
3281 | - |
3282 | - def test_constructor_guarded(self): |
3283 | - """Ensure that CouchGrid cannot be constructed without a |
3284 | - database name. |
3285 | - """ |
3286 | - try: |
3287 | - cw = CouchGrid(None) |
3288 | - except TypeError, inst: |
3289 | - self.assertEqual( |
3290 | - inst.args[0],"database_name is required and must be a string") |
3291 | - |
3292 | - def test_new_rows_with_headings(self): |
3293 | - """Test a simple creating a CouchGrid """ |
3294 | - |
3295 | - #create a test widget with test database values |
3296 | - cw = CouchGrid(self.dbname) |
3297 | - |
3298 | - #allow editing |
3299 | - cw.editable = True |
3300 | - |
3301 | - #create headers/keys |
3302 | - cw.keys = ["Key1", "Key2", "Key3", "Key4"] |
3303 | - |
3304 | - #set the record_type for the TreeView |
3305 | - #it will not populate without this value being set |
3306 | - cw.record_type = self.record_type |
3307 | - |
3308 | - #create a row with all four columns set |
3309 | - cw.append_row({"Key1":"val1", "Key2":"val2", "Key2":"val3", "Key4":"val4"}) |
3310 | - |
3311 | - #create a row with only the second column set |
3312 | - cw.append_row({"Key1":"", "Key2":"val2"}) |
3313 | - |
3314 | - #create an empty row (which will not be saved until the user edits it) |
3315 | - cw.append_row({}) |
3316 | - |
3317 | - #if this all worked, there should be three rows in the model |
3318 | - model = cw.get_model() |
3319 | - self.assertEqual(len(model), 3) |
3320 | - |
3321 | - def test_headings_no_stored_records(self): |
3322 | - record_type = "a_new_record_type" |
3323 | - dicts = [{"key1":"val1"},{"key1":"val2"}] |
3324 | - cw = CouchGrid(self.dbname, record_type=record_type,dictionaries=dicts) |
3325 | - self.assertEqual(len(cw.get_model()),2) |
3326 | - self.assertEqual(cw.get_model().get_n_columns(),2) |
3327 | - |
3328 | - def test_no_headings_or_stored_records(self): |
3329 | - """test when there is no defined headings and no stored records |
3330 | - to infer headings from. Should raise a proper exception. |
3331 | - """ |
3332 | - |
3333 | - try: |
3334 | - #create a test widget with test database values |
3335 | - cw = CouchGrid(self.dbname) |
3336 | - |
3337 | - #set the record_type for the TreeView |
3338 | - #it will not populate without this value being set |
3339 | - cw.record_type = self.record_type |
3340 | - |
3341 | - #create a row with all four columns set |
3342 | - cw.append_row(["val1", "val2", "val3", "val4"]) |
3343 | - |
3344 | - #create a row with only the second column set |
3345 | - cw.append_row(["", "val2"]) |
3346 | - |
3347 | - #create an empty row (which will not be saved until the |
3348 | - #user edits it) |
3349 | - cw.append_row([]) |
3350 | - |
3351 | - #if this all worked, there should be three rows in the model |
3352 | - model = cw.get_model() |
3353 | - |
3354 | - #should be catching the following exception |
3355 | - except RuntimeError, inst: |
3356 | - self.assertEquals( |
3357 | - inst.args[0].find("Cannot infer columns for CouchGrid"),0) |
3358 | - |
3359 | - |
3360 | - def test_all_from_database(self): |
3361 | - #create some records |
3362 | - db = CouchDatabase(self.dbname, create=True) |
3363 | - db.put_record(Record({ |
3364 | - "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
3365 | - "record_type": self.record_type})) |
3366 | - db.put_record(Record({ |
3367 | - "key1_1": "val2_1", "key1_2": "val2_2", "key1_3": "val2_3", |
3368 | - "record_type": self.record_type})) |
3369 | - |
3370 | - #build the CouchGrid |
3371 | - cw = CouchGrid(self.dbname) |
3372 | - cw.record_type = self.record_type |
3373 | - #make sure there are three columns and two rows |
3374 | - self.assertEqual(cw.get_model().get_n_columns(),4) |
3375 | - self.assertEqual(len(cw.get_model()),2) |
3376 | - |
3377 | - def test_delete_selected_rows(self): |
3378 | - #create some records |
3379 | - db = CouchDatabase(self.dbname, create=True) |
3380 | - ids = [] |
3381 | - for i in xrange(0,10): |
3382 | - ids.append( db.put_record(Record({ |
3383 | - "key1_1": "val1_%s" % str(i), "iter_count": i, |
3384 | - "record_type": self.record_type}))) |
3385 | - |
3386 | - #build the CouchGrid |
3387 | - cw = CouchGrid(self.dbname, record_type = self.record_type) |
3388 | - cw.selected_record_ids = [ids[0],ids[5],ids[9]] |
3389 | - cw.remove_selected_rows(delete=True) |
3390 | - self.assertEqual(self.db.get_record(ids[0]) is None,True) |
3391 | - self.assertEqual(self.db.get_record(ids[5]) is None,True) |
3392 | - self.assertEqual(self.db.get_record(ids[9]) is None,True) |
3393 | - |
3394 | - self.assertEqual(self.db.get_record(ids[1]) is not None,True) |
3395 | - self.assertEqual(self.db.get_record(ids[2]) is not None,True) |
3396 | - self.assertEqual(self.db.get_record(ids[3]) is not None,True) |
3397 | - self.assertEqual(self.db.get_record(ids[4]) is not None,True) |
3398 | - self.assertEqual(self.db.get_record(ids[6]) is not None,True) |
3399 | - self.assertEqual(self.db.get_record(ids[7]) is not None,True) |
3400 | - self.assertEqual(self.db.get_record(ids[8]) is not None,True) |
3401 | - |
3402 | - def test_dont_delete_selected_rows(self): |
3403 | - #create some records |
3404 | - db = CouchDatabase(self.dbname, create=True) |
3405 | - ids = [] |
3406 | - for i in xrange(0,10): |
3407 | - ids.append( db.put_record(Record({ |
3408 | - "key1_1": "val1_%s" % str(i), "iter_count": i, |
3409 | - "record_type": self.record_type}))) |
3410 | - |
3411 | - #build the CouchGrid |
3412 | - cw = CouchGrid(self.dbname, record_type = self.record_type) |
3413 | - cw.selected_record_ids = [ids[0],ids[5],ids[9]] |
3414 | - cw.remove_selected_rows(delete=False) |
3415 | - cw.selected_record_ids = [ids[1],ids[4],ids[8]] |
3416 | - cw.remove_selected_rows() |
3417 | - self.assertEqual(self.db.get_record(ids[0]) is not None,True) |
3418 | - self.assertEqual(self.db.get_record(ids[5]) is not None,True) |
3419 | - self.assertEqual(self.db.get_record(ids[9]) is not None,True) |
3420 | - |
3421 | - self.assertEqual(self.db.get_record(ids[1]) is not None,True) |
3422 | - self.assertEqual(self.db.get_record(ids[2]) is not None,True) |
3423 | - self.assertEqual(self.db.get_record(ids[3]) is not None,True) |
3424 | - self.assertEqual(self.db.get_record(ids[4]) is not None,True) |
3425 | - self.assertEqual(self.db.get_record(ids[6]) is not None,True) |
3426 | - self.assertEqual(self.db.get_record(ids[7]) is not None,True) |
3427 | - self.assertEqual(self.db.get_record(ids[8]) is not None,True) |
3428 | - |
3429 | - |
3430 | - |
3431 | - def test_selected_id_property(self): |
3432 | - #create some records |
3433 | - db = CouchDatabase(self.dbname, create=True) |
3434 | - id1 = db.put_record(Record({ |
3435 | - "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
3436 | - "record_type": self.record_type})) |
3437 | - id2 = db.put_record(Record({ |
3438 | - "key1_1": "val2_1", "key1_2": "val2_2", "key1_3": "val2_3", |
3439 | - "record_type": self.record_type})) |
3440 | - |
3441 | - #build the CouchGrid |
3442 | - cw = CouchGrid(self.dbname) |
3443 | - cw.record_type = self.record_type |
3444 | - |
3445 | - #make sure the record ids are selected properly |
3446 | - cw.selected_record_ids = [id1] |
3447 | - self.assertEqual(cw.selected_record_ids[0], id1) |
3448 | - cw.selected_record_ids = [id2] |
3449 | - self.assertEqual(cw.selected_record_ids[0], id2) |
3450 | - |
3451 | - def test_single_col_from_database(self): |
3452 | - #create some records |
3453 | - self.db.put_record(Record({ |
3454 | - "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
3455 | - "record_type": self.record_type})) |
3456 | - self.db.put_record(Record({ |
3457 | - "key1_1": "val2_1", "key1_2": "val2_2", "key1_3": "val2_3", |
3458 | - "record_type": self.record_type})) |
3459 | - #build the CouchGrid |
3460 | - cw = CouchGrid(self.dbname) |
3461 | - cw.keys = ["key1_1"] |
3462 | - cw.record_type = self.record_type |
3463 | - #make sure there are three columns and two rows |
3464 | - self.assertEqual(cw.get_model().get_n_columns(),2) |
3465 | - self.assertEqual(len(cw.get_model()),2) |
3466 | - |
3467 | - def test_optional_record_type_arg(self): |
3468 | - """Test a simple creating a CouchGrid """ |
3469 | - #create some records |
3470 | - self.db.put_record(Record({ |
3471 | - "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
3472 | - "record_type": self.record_type})) |
3473 | - self.db.put_record(Record({ |
3474 | - "key1_1": "val1_1", "key1_2": "val2_2", "key1_3": "val2_3", |
3475 | - "record_type": self.record_type})) |
3476 | - |
3477 | - #create a test widget with test database values |
3478 | - cw = CouchGrid(self.dbname, record_type=self.record_type) |
3479 | - |
3480 | - #make sure there are three columns and two rows |
3481 | - self.assertEqual(cw.get_model().get_n_columns(),4) |
3482 | - self.assertEqual(len(cw.get_model()),2) |
3483 | - |
3484 | - def test_optional_args_no_stored_records(self): |
3485 | - """Test a simple creating a CouchGrid """ |
3486 | - |
3487 | - #create a test widget with test database values |
3488 | - cw = CouchGrid( |
3489 | - self.dbname, record_type=self.record_type, |
3490 | - keys=["Key1", "Key2", "Key3", "Key4"]) |
3491 | - |
3492 | - #create a row with all four columns set |
3493 | - cw.append_row({"Key1":"val1", "Key2":"val2", "Key2":"val3", "Key4":"val4"}) |
3494 | - |
3495 | - #create a row with only the second column set |
3496 | - cw.append_row({"Key1":"", "Key2":"val2"}) |
3497 | - |
3498 | - #create an empty row (which will not be saved until the user edits it) |
3499 | - cw.append_row({}) |
3500 | - |
3501 | - #if this all worked, there should be three rows in the model |
3502 | - model = cw.get_model() |
3503 | - self.assertEqual(len(model), 3) |
3504 | - |
3505 | - def test_programatically_add_row(self): |
3506 | - """test appending different sized rows programatically""" |
3507 | - #create some records |
3508 | - self.db.put_record(Record({ |
3509 | - "key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3", |
3510 | - "record_type": self.record_type})) |
3511 | - self.db.put_record(Record({ |
3512 | - "key1_1": "val2_1", "key1_2": "val2_2", "key1_3": "val2_3", |
3513 | - "record_type": self.record_type})) |
3514 | - |
3515 | - #create a test widget with test database values |
3516 | - cw = CouchGrid(self.dbname, record_type=self.record_type) |
3517 | - |
3518 | - #allow editing |
3519 | - cw.append_row({"key1_1":"boo", "key1_2":"ray"}) |
3520 | - |
3521 | - #make sure there are three columns and two rows |
3522 | - self.assertEqual(cw.get_model().get_n_columns(),4) |
3523 | - self.assertEqual(len(cw.get_model()),3) |
3524 | |
3525 | === modified file 'quickly/widgets/tests/test_dictionary_grid.py' |
3526 | --- quickly/widgets/tests/test_dictionary_grid.py 2011-09-05 06:23:54 +0000 |
3527 | +++ quickly/widgets/tests/test_dictionary_grid.py 2012-03-06 08:52:21 +0000 |
3528 | @@ -18,7 +18,7 @@ |
3529 | |
3530 | from testtools import TestCase |
3531 | from quickly.widgets.dictionary_grid import DictionaryGrid |
3532 | -import gobject |
3533 | +from gi.repository import GObject |
3534 | from quickly.widgets.grid_column import StringColumn, IntegerColumn, CurrencyColumn,CheckColumn, DateColumn |
3535 | |
3536 | class TestDictionaryGrid(TestCase): |
3537 | @@ -42,7 +42,6 @@ |
3538 | grid.append_row({"key1":"val11","key2":"val12"}) |
3539 | self.assertEqual(len(grid.get_model()),1) |
3540 | |
3541 | - |
3542 | def test_constructor_with_dicts(self): |
3543 | """test creating a grid with dictionaries in the contructor""" |
3544 | dicts = [{"key1_1": "val1_1", "key1_2": "val1_2", "key1_3": "val1_3"}, |
3545 | @@ -184,13 +183,13 @@ |
3546 | key = c.key |
3547 | col_type = c.column_type |
3548 | if key == "id": |
3549 | - self.assertEqual(col_type,gobject.TYPE_STRING) |
3550 | + self.assertEqual(col_type,GObject.TYPE_STRING) |
3551 | elif key == "price": |
3552 | - self.assertEqual(col_type,gobject.TYPE_STRING) |
3553 | + self.assertEqual(col_type,GObject.TYPE_STRING) |
3554 | elif key == "bool?": |
3555 | - self.assertEqual(col_type,gobject.TYPE_STRING) |
3556 | + self.assertEqual(col_type,GObject.TYPE_STRING) |
3557 | elif key == "foo": |
3558 | - self.assertEqual(col_type,gobject.TYPE_INT) |
3559 | + self.assertEqual(col_type,GObject.TYPE_INT) |
3560 | else: |
3561 | self.assertEqual("Extra key Found",False) |
3562 | |
3563 | @@ -253,9 +252,9 @@ |
3564 | dicts = [{"price":"100.00","id":"50","bool?":"Yes"}] |
3565 | grid = DictionaryGrid(dicts, keys) |
3566 | grid.editable = False |
3567 | - ed1 = grid.columns["price"].get_cell_renderers()[0].get_property("editable") |
3568 | + ed1 = grid.columns["price"].get_cells()[0].get_property("editable") |
3569 | self.assertTrue(not ed1) |
3570 | - ed2 = grid.columns["bool?"].get_cell_renderers()[0].get_property("activatable") |
3571 | + ed2 = grid.columns["bool?"].get_cells()[0].get_property("activatable") |
3572 | self.assertTrue(not ed2) |
3573 | |
3574 | def test_set_a_column_title(self): |
3575 | |
3576 | === modified file 'quickly/widgets/text_editor.py' |
3577 | --- quickly/widgets/text_editor.py 2011-02-03 16:28:49 +0000 |
3578 | +++ quickly/widgets/text_editor.py 2012-03-06 08:52:21 +0000 |
3579 | @@ -35,25 +35,26 @@ |
3580 | |
3581 | Configuring |
3582 | #Configure as a TextView |
3583 | -self.editor.set_wrap_mode(gtk.WRAP_CHAR) |
3584 | +self.editor.set_wrap_mode(Gtk.WRAP_CHAR) |
3585 | |
3586 | -#Access the gtk.TextBuffer if needed |
3587 | +#Access the Gtk.TextBuffer if needed |
3588 | buffer = self.editor.get_buffer() |
3589 | |
3590 | Extending |
3591 | -A TextEditor is gtk.TextView |
3592 | +A TextEditor is Gtk.TextView |
3593 | |
3594 | """ |
3595 | |
3596 | + |
3597 | try: |
3598 | - import pygtk |
3599 | - pygtk.require("2.0") |
3600 | - import gtk |
3601 | + from gi.repository import Gtk |
3602 | + from gi.repository import Gdk |
3603 | import re |
3604 | except: |
3605 | print "couldn't load depencies" |
3606 | |
3607 | -class TextEditor( gtk.TextView ): |
3608 | + |
3609 | +class TextEditor( Gtk.TextView ): |
3610 | """TextEditor encapsulates management of TextBuffer and TextIter for |
3611 | common functionality, such as cut, copy, paste, undo, redo, and |
3612 | highlighting of text. |
3613 | @@ -65,10 +66,10 @@ |
3614 | |
3615 | """ |
3616 | |
3617 | - gtk.TextView.__init__( self) |
3618 | + Gtk.TextView.__init__(self) |
3619 | self.undo_max = None |
3620 | self._highlight_strings = [] |
3621 | - found_tag = gtk.TextTag("highlight") |
3622 | + found_tag = Gtk.TextTag(name="highlight") |
3623 | found_tag.set_property("background","yellow") |
3624 | self.get_buffer().get_tag_table().add(found_tag) |
3625 | |
3626 | @@ -77,7 +78,8 @@ |
3627 | self.change_event = self.get_buffer().connect("changed",self._on_text_changed) |
3628 | self._auto_bullet = None |
3629 | self.auto_bullets = False |
3630 | - self.clipboard = gtk.Clipboard() |
3631 | + display = self.get_display() |
3632 | + self.clipboard = Gtk.Clipboard.get_for_display(display, Gdk.SELECTION_CLIPBOARD) |
3633 | |
3634 | self.undos = [] |
3635 | self.redos = [] |
3636 | @@ -92,7 +94,7 @@ |
3637 | """ |
3638 | start_iter = self.get_buffer().get_iter_at_offset(0) |
3639 | end_iter = self.get_buffer().get_iter_at_offset(-1) |
3640 | - return self.get_buffer().get_text(start_iter,end_iter) |
3641 | + return self.get_buffer().get_text(start_iter,end_iter, False) |
3642 | |
3643 | @text.setter |
3644 | def text(self, text): |
3645 | @@ -179,6 +181,7 @@ |
3646 | |
3647 | |
3648 | self._highlight_strings = [] |
3649 | + |
3650 | self._highlight() |
3651 | |
3652 | def _highlight(self): |
3653 | @@ -189,7 +192,7 @@ |
3654 | |
3655 | start_iter = self.get_buffer().get_iter_at_offset(0) |
3656 | end_iter = self.get_buffer().get_iter_at_offset(-1) |
3657 | - text = self.get_buffer().get_text(start_iter,end_iter) |
3658 | + text = self.get_buffer().get_text(start_iter,end_iter, False) |
3659 | self.get_buffer().remove_all_tags(start_iter, end_iter) |
3660 | for s in self._highlight_strings: |
3661 | hits = [match.start() for match in re.finditer(re.escape(s), text)] |
3662 | @@ -213,7 +216,7 @@ |
3663 | handler. |
3664 | |
3665 | """ |
3666 | - |
3667 | + |
3668 | self.get_buffer().copy_clipboard(self.clipboard) |
3669 | |
3670 | def paste(self, widget=None, data=None): |
3671 | @@ -306,7 +309,7 @@ |
3672 | cur_line = iter.get_line() |
3673 | prev_line_iter = self.get_buffer().get_iter_at_line(cur_line) |
3674 | pl_offset = prev_line_iter.get_offset() |
3675 | - pl_text = self.get_buffer().get_text(prev_line_iter, iter) |
3676 | + pl_text = self.get_buffer().get_text(prev_line_iter, iter, False) |
3677 | if pl_text.strip().find("*") == 0: |
3678 | ws = "" |
3679 | if not pl_text.startswith("*"): |
3680 | @@ -320,7 +323,7 @@ |
3681 | """ |
3682 | |
3683 | self._highlight() |
3684 | - text = self.get_buffer().get_text(start_iter,end_iter) |
3685 | + text = self.get_buffer().get_text(start_iter,end_iter, False) |
3686 | cmd = {"action":"insert","offset":start_iter.get_offset(),"text":text} |
3687 | self._add_undo(cmd) |
3688 | |
3689 | @@ -335,25 +338,25 @@ |
3690 | del(self.undos[0]) |
3691 | self.undos.append(cmd) |
3692 | |
3693 | -class TestWindow(gtk.Window): |
3694 | +class TestWindow(Gtk.Window): |
3695 | """For testing and demonstrating AsycnTaskProgressBox. |
3696 | |
3697 | """ |
3698 | def __init__(self): |
3699 | #create a window a VBox to hold the controls |
3700 | - gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) |
3701 | + Gtk.Window.__init__(self) |
3702 | self.set_title("TextEditor Test Window") |
3703 | - windowbox = gtk.VBox(False, 2) |
3704 | + windowbox = Gtk.VBox(False, 2) |
3705 | windowbox.show() |
3706 | self.add(windowbox) |
3707 | self.editor = TextEditor() |
3708 | self.editor.show() |
3709 | - windowbox.pack_end(self.editor) |
3710 | + windowbox.pack_end(self.editor, True, True, 0) |
3711 | self.set_size_request(200,200) |
3712 | self.show() |
3713 | self.maximize() |
3714 | |
3715 | - self.connect("destroy", gtk.main_quit) |
3716 | + self.connect("destroy", Gtk.main_quit) |
3717 | self.editor.text = "this is some inserted text" |
3718 | self.editor.append("\nLine 3") |
3719 | self.editor.prepend("Line1\n") |
3720 | @@ -364,35 +367,35 @@ |
3721 | self.editor.add_highlight("some") |
3722 | self.editor.undo_max = 100 |
3723 | self.editor.auto_bullets = True |
3724 | - cut_button = gtk.Button("Cut") |
3725 | + cut_button = Gtk.Button("Cut") |
3726 | cut_button.connect("clicked",self.editor.cut) |
3727 | cut_button.show() |
3728 | - windowbox.pack_start(cut_button, False) |
3729 | + windowbox.pack_start(cut_button, False, False, 0) |
3730 | |
3731 | - copy_button = gtk.Button("Copy") |
3732 | + copy_button = Gtk.Button("Copy") |
3733 | copy_button.connect("clicked",self.editor.copy) |
3734 | copy_button.show() |
3735 | - windowbox.pack_start(copy_button, False) |
3736 | + windowbox.pack_start(copy_button, False, False, 0) |
3737 | |
3738 | - paste_button = gtk.Button("Paste") |
3739 | + paste_button = Gtk.Button("Paste") |
3740 | paste_button.connect("clicked",self.editor.paste) |
3741 | paste_button.show() |
3742 | - windowbox.pack_start(paste_button, False) |
3743 | + windowbox.pack_start(paste_button, False, False, 0) |
3744 | |
3745 | - undo_button = gtk.Button("Undo") |
3746 | + undo_button = Gtk.Button("Undo") |
3747 | undo_button.connect("clicked",self.editor.undo) |
3748 | undo_button.show() |
3749 | - windowbox.pack_start(undo_button, False) |
3750 | + windowbox.pack_start(undo_button, False, False, 0) |
3751 | |
3752 | - redo_button = gtk.Button("Redo") |
3753 | + redo_button = Gtk.Button("Redo") |
3754 | redo_button.connect("clicked",self.editor.redo) |
3755 | redo_button.show() |
3756 | - windowbox.pack_start(redo_button, False) |
3757 | + windowbox.pack_start(redo_button, False, False, 0) |
3758 | |
3759 | print self.editor.text |
3760 | |
3761 | |
3762 | if __name__== "__main__": |
3763 | test = TestWindow() |
3764 | - gtk.main() |
3765 | + Gtk.main() |
3766 | |
3767 | |
3768 | === modified file 'quickly/widgets/url_fetch_progressbox.py' |
3769 | --- quickly/widgets/url_fetch_progressbox.py 2011-09-05 06:19:23 +0000 |
3770 | +++ quickly/widgets/url_fetch_progressbox.py 2012-03-06 08:52:21 +0000 |
3771 | @@ -1,5 +1,6 @@ |
3772 | ### BEGIN LICENSE |
3773 | # Copyright (C) 2010 Stuart Langridge stuart.langridge@canonical.com |
3774 | +# Copyright (C) 2012 Rick Spencer rick.spencer@canonical.com |
3775 | #This program is free software: you can redistribute it and/or modify it |
3776 | #under the terms of the GNU General Public License version 3, as published |
3777 | #by the Free Software Foundation. |
3778 | @@ -14,18 +15,18 @@ |
3779 | ### END LICENSE |
3780 | |
3781 | try: |
3782 | - import pygtk |
3783 | - pygtk.require("2.0") |
3784 | - import gtk, gobject, gio |
3785 | + from gi.repository import GObject |
3786 | + from gi.repository import Gtk |
3787 | + from gi.repository import Gio |
3788 | + from gi.repository import GLib |
3789 | import gettext |
3790 | from gettext import gettext as _ |
3791 | gettext.textdomain('quickly-widgets') |
3792 | - import glib |
3793 | except: |
3794 | print "couldn't load dependencies" |
3795 | |
3796 | |
3797 | -class UrlFetchProgressBox(gtk.HBox): |
3798 | +class UrlFetchProgressBox(Gtk.HBox): |
3799 | """UrlFetchProgressBox: encapsulates a pulsating progressbar, a cancel |
3800 | button, and a URL that needs fetching. Use a UrlFetchProgressBox when you |
3801 | need to fetch a URL; the box will show while the URL is being fetched |
3802 | @@ -37,10 +38,10 @@ |
3803 | Cancelling fires the "downloaded" signal with a value of None. |
3804 | """ |
3805 | |
3806 | - __gsignals__ = {'downloaded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
3807 | - (gobject.TYPE_PYOBJECT,)), |
3808 | - 'download-error' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
3809 | - (gobject.TYPE_PYOBJECT,))} |
3810 | + __gsignals__ = {'downloaded' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
3811 | + (GObject.TYPE_PYOBJECT,)), |
3812 | + 'download-error' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
3813 | + (GObject.TYPE_PYOBJECT,))} |
3814 | |
3815 | def __init__(self, url, destroy_after_fetching=True, cancelable=True): |
3816 | """Create an UrlFetchProgressBox |
3817 | @@ -51,39 +52,37 @@ |
3818 | is fetched? Defaults to True. |
3819 | cancelable -- whether to show cancel button. Defaults to True. |
3820 | """ |
3821 | - gtk.HBox.__init__( self, False, 2) |
3822 | - self.progressbar = gtk.ProgressBar() |
3823 | - gobject.timeout_add(10, self.__tick) |
3824 | + Gtk.HBox.__init__( self, False, 2) |
3825 | + self.progressbar = Gtk.ProgressBar() |
3826 | + GObject.timeout_add(10, self.__tick) |
3827 | self.running = True |
3828 | parts = [x for x in url.split("/") if x] |
3829 | self.progressbar.set_text(_("Downloading %s") % parts[-1]) |
3830 | self.progressbar.show() |
3831 | - self.pack_start(self.progressbar, True) |
3832 | + self.pack_start(self.progressbar, True, True, 0) |
3833 | self.destroy_after_fetching = destroy_after_fetching |
3834 | - self.cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL) |
3835 | + self.cancel_button = Gtk.Button(stock=Gtk.STOCK_CANCEL) |
3836 | if cancelable: |
3837 | self.cancel_button.show() |
3838 | self.cancel_button.set_sensitive(False) |
3839 | self.cancel_button.connect("clicked",self.__cancel) |
3840 | - self.pack_end(self.cancel_button, False) |
3841 | + self.pack_end(self.cancel_button, False, False, 0) |
3842 | self.cancel_button.set_sensitive(True) |
3843 | - self.__canceller = gio.Cancellable() |
3844 | - self.stream = gio.File(url) |
3845 | - self.stream.load_contents_async(self.__download_finished, cancellable=self.__canceller) |
3846 | + self.__canceller = Gio.Cancellable() |
3847 | + self.stream = Gio.file_new_for_uri(url) |
3848 | + self.stream.load_contents_async(self.__canceller, self.__download_finished, None) |
3849 | |
3850 | + |
3851 | def __tick(self): |
3852 | self.progressbar.pulse() |
3853 | return self.running |
3854 | |
3855 | - def __download_finished(self, gdaemonfile, result): |
3856 | + def __download_finished(self, gdaemonfile, result, data=None): |
3857 | try: |
3858 | - content = self.stream.load_contents_finish(result)[0] |
3859 | - except gio.Error, e: |
3860 | - if e.code == 19: |
3861 | - self.emit("downloaded", None) |
3862 | - else: |
3863 | - self.emit("download-error",e) |
3864 | - except glib.GError, e: |
3865 | + #GIO documentation says that the file is [0] in the tuple |
3866 | + #but it is realy [1] |
3867 | + content = self.stream.load_contents_finish(result)[1] |
3868 | + except Exception, e: |
3869 | self.emit("download-error",e) |
3870 | else: |
3871 | self.emit("downloaded", content) |
3872 | @@ -97,29 +96,34 @@ |
3873 | self.running = False |
3874 | if self.destroy_after_fetching: self.destroy() |
3875 | |
3876 | -class TestWindow(gtk.Window): |
3877 | +class TestWindow(Gtk.Window): |
3878 | def __init__(self): |
3879 | - gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) |
3880 | + Gtk.Window.__init__(self) |
3881 | self.set_title("UrlFetchProgressBox test") |
3882 | - self.vbox = gtk.VBox() |
3883 | - btn = gtk.Button(stock=gtk.STOCK_EXECUTE) |
3884 | + self.vbox = Gtk.VBox() |
3885 | + btn = Gtk.Button(stock=Gtk.STOCK_EXECUTE) |
3886 | btn.connect("clicked", self.start_download) |
3887 | - self.vbox.pack_end(btn) |
3888 | + self.vbox.pack_end(btn, True, True, 0) |
3889 | self.add(self.vbox) |
3890 | self.set_size_request(300,200) |
3891 | - self.connect("destroy", gtk.main_quit) |
3892 | + self.connect("destroy", Gtk.main_quit) |
3893 | |
3894 | def start_download(self, btn): |
3895 | prog = UrlFetchProgressBox("http://www.ubuntu.com/desktop/get-ubuntu/download") |
3896 | + |
3897 | prog.connect("downloaded", self.downloaded) |
3898 | - self.vbox.pack_start(prog, expand=False) |
3899 | + prog.connect("download-error", self.errored) |
3900 | + self.vbox.pack_start(prog, False, False, 0) |
3901 | prog.show() |
3902 | - |
3903 | + |
3904 | + def errored(self, widget, e): |
3905 | + print "encountered error: %s " % e.message |
3906 | + |
3907 | def downloaded(self, widget, content): |
3908 | print "downloaded %s bytes of content" % len(content) |
3909 | |
3910 | if __name__ == "__main__": |
3911 | w = TestWindow() |
3912 | w.show_all() |
3913 | - gtk.main() |
3914 | + Gtk.main() |
3915 | |
3916 | |
3917 | === modified file 'quickly/widgets/web_cam_box.py' |
3918 | --- quickly/widgets/web_cam_box.py 2011-01-04 03:19:55 +0000 |
3919 | +++ quickly/widgets/web_cam_box.py 2012-03-06 08:52:21 +0000 |
3920 | @@ -53,13 +53,13 @@ |
3921 | cam.pack_start(my_widget, False, False) |
3922 | |
3923 | Extending |
3924 | -A WebCamBox is gtk.VBox |
3925 | -A WebCamBox is a gtk.VBox that contains a gtk.DrawingArea for displaying |
3926 | +A WebCamBox is Gtk.VBox |
3927 | +A WebCamBox is a Gtk.VBox that contains a Gtk.DrawingArea for displaying |
3928 | webcam output, and a thin wrapper around a camerabin, which is a gstreamer |
3929 | pipleine sublcass that provides all the camera functionality. |
3930 | |
3931 | To add GUI elements simple, create them and pack them into WebCamBox, since |
3932 | -it's just a gtk.VBox |
3933 | +it's just a Gtk.VBox |
3934 | |
3935 | Similarly, to add to or change the web cam functionality, modify properties on |
3936 | the camerabin. You may also want to overide _on_message and/or _on_sync_message |
3937 | @@ -67,18 +67,20 @@ |
3938 | |
3939 | """ |
3940 | |
3941 | +from gi.repository import Gtk |
3942 | +from gi.repository import GdkX11 |
3943 | +from gi.repository import GObject |
3944 | + |
3945 | import sys |
3946 | import os |
3947 | -import gtk |
3948 | import gst |
3949 | import datetime |
3950 | -import gobject |
3951 | |
3952 | import gettext |
3953 | from gettext import gettext as _ |
3954 | gettext.textdomain('quickly-widgets') |
3955 | |
3956 | -class WebCamBox(gtk.VBox): |
3957 | +class WebCamBox(Gtk.VBox): |
3958 | """WebCamBox - A VBox that tries to turn on and display the default webcam for the |
3959 | computer on which it is running. It is also capable of saving an image |
3960 | from the webcam to the user's Picture directory. |
3961 | @@ -92,10 +94,10 @@ |
3962 | This function has no arguments |
3963 | |
3964 | """ |
3965 | - gtk.VBox.__init__(self, False, 5) |
3966 | - self.video_window = gtk.DrawingArea() |
3967 | + Gtk.VBox.__init__(self, False, 5) |
3968 | + self.video_window = Gtk.DrawingArea() |
3969 | self.video_window.connect("realize",self.__on_video_window_realized) |
3970 | - self.pack_start(self.video_window, True, True) |
3971 | + self.pack_start(self.video_window, True, True, 0) |
3972 | self.video_window.show() |
3973 | self.connect("destroy", self.on_destroy) |
3974 | |
3975 | @@ -105,7 +107,7 @@ |
3976 | bus.enable_sync_message_emission() |
3977 | bus.connect("message", self._on_message) |
3978 | bus.connect("sync-message::element", self._on_sync_message) |
3979 | - self.camerabin.set_property("image-encoder",gst.element_factory_make("pngenc", "png_encoder")) |
3980 | + #self.camerabin.set_property("image-encoder",gst.element_factory_make("pngenc", "png_encoder")) |
3981 | self.filename_prefix = "" |
3982 | self.realized = False |
3983 | |
3984 | @@ -155,7 +157,7 @@ |
3985 | """ |
3986 | |
3987 | stamp = str(datetime.datetime.now()) |
3988 | - extension = ".png" |
3989 | + extension = ".jpg" |
3990 | directory = os.environ["HOME"] + _("/Pictures/") |
3991 | self.filename = directory + self.filename_prefix + stamp + extension |
3992 | self.camerabin.set_property("filename", self.filename) |
3993 | @@ -217,7 +219,7 @@ |
3994 | if message_name == "prepare-xwindow-id": |
3995 | imagesink = message.src |
3996 | imagesink.set_property("force-aspect-ratio", True) |
3997 | - imagesink.set_xwindow_id(self.video_window.window.xid) |
3998 | + imagesink.set_xwindow_id(self.video_window.get_window().get_xid()) |
3999 | |
4000 | def __on_video_window_realized(self, widget, data=None): |
4001 | """__on_video_window_realized - internal signal handler, used |
4002 | @@ -229,16 +231,16 @@ |
4003 | self._set_video_window_id() |
4004 | |
4005 | def _set_video_window_id(self): |
4006 | - if not self.realized and self.video_window.window is not None: |
4007 | - x = self.video_window.window.xid |
4008 | + if not self.realized and self.video_window.get_window() is not None: |
4009 | + x = self.video_window.get_window().get_xid() |
4010 | self.realized = True |
4011 | |
4012 | def on_destroy(self, widget, data=None): |
4013 | #clean up the camera before exiting |
4014 | self.camerabin.set_state(gst.STATE_NULL) |
4015 | |
4016 | - __gsignals__ = {'image-captured' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
4017 | - (gobject.TYPE_PYOBJECT,)), |
4018 | + __gsignals__ = {'image-captured' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, |
4019 | + (GObject.TYPE_PYOBJECT,)), |
4020 | } |
4021 | |
4022 | def __image_captured(widget, data=None): |
4023 | @@ -247,20 +249,21 @@ |
4024 | |
4025 | """ |
4026 | |
4027 | - quickly.prompts.info("WebCam Test",data) |
4028 | + #quickly.prompts.info("WebCam Test",data) |
4029 | + print data |
4030 | |
4031 | if __name__ == "__main__": |
4032 | """creates a test WebCamBox""" |
4033 | - import quickly.prompts |
4034 | + #import quickly.prompts |
4035 | |
4036 | #create and show a test window |
4037 | - win = gtk.Window(gtk.WINDOW_TOPLEVEL) |
4038 | + win = Gtk.Window() |
4039 | win.set_title("WebCam Test Window") |
4040 | - win.connect("destroy",gtk.main_quit) |
4041 | + win.connect("destroy",Gtk.main_quit) |
4042 | win.show() |
4043 | |
4044 | #create a top level container |
4045 | - vbox = gtk.VBox(False, 10) |
4046 | + vbox = Gtk.VBox(False, 10) |
4047 | vbox.show() |
4048 | win.add(vbox) |
4049 | |
4050 | @@ -271,27 +274,27 @@ |
4051 | mb.play() |
4052 | |
4053 | mb.connect("image-captured", __image_captured) |
4054 | - play_butt = gtk.Button("Play") |
4055 | - pause_butt = gtk.Button("Pause") |
4056 | - stop_butt = gtk.Button("Stop") |
4057 | - pic_butt = gtk.Button("Picture") |
4058 | + play_butt = Gtk.Button("Play") |
4059 | + pause_butt = Gtk.Button("Pause") |
4060 | + stop_butt = Gtk.Button("Stop") |
4061 | + pic_butt = Gtk.Button("Picture") |
4062 | |
4063 | play_butt.connect("clicked", lambda x:mb.play()) |
4064 | play_butt.show() |
4065 | - mb.pack_end(play_butt, False) |
4066 | + mb.pack_end(play_butt, False, False, 0) |
4067 | |
4068 | pause_butt.connect("clicked", lambda x:mb.pause()) |
4069 | pause_butt.show() |
4070 | - mb.pack_end(pause_butt, False) |
4071 | + mb.pack_end(pause_butt, False, False, 0) |
4072 | |
4073 | stop_butt.connect("clicked", lambda x:mb.stop()) |
4074 | stop_butt.show() |
4075 | - mb.pack_end(stop_butt, False) |
4076 | + mb.pack_end(stop_butt, False, False, 0) |
4077 | |
4078 | pic_butt.connect("clicked", lambda x:mb.take_picture()) |
4079 | pic_butt.show() |
4080 | - mb.pack_end(pic_butt, False) |
4081 | + mb.pack_end(pic_butt, False, False, 0) |
4082 | |
4083 | - gtk.main() |
4084 | + Gtk.main() |
4085 | |
4086 |
Seems fine, but running the tests on the new code gives me several errors like:
Gtk-WARNING **: Cannot connect attribute `text' for cell renderer class `GtkCellRendere rToggle' since attribute does not exist
Is that expected? Aside from that, this is approved. So if you fix that or it's innocuous, push away.