Merge lp:~rick-rickspencer3/quidgets/precise into lp:quidgets

Proposed by Rick Spencer on 2012-03-06
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
Reviewer Review Type Date Requested Status
Michael Terry (community) 2012-03-06 Approve on 2012-03-13
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.
Michael Terry (mterry) wrote :

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 `GtkCellRendererToggle' 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.

review: Needs Fixing
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

Subscribers

People subscribed via source and target branches