~cosmin.lupu/+junk/penguintv

« back to all changes in this revision

Viewing changes to penguintv/SynchronizeDialog.py

  • Committer: cosmin.lupu at gmail
  • Date: 2010-04-27 16:47:43 UTC
  • Revision ID: cosmin.lupu@gmail.com-20100427164743-ds8xrqonipp5ovdf
initial packaging

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#(c) 2006 Owen Williams
 
2
#see LICENSE
 
3
 
 
4
import ptv_sync
 
5
import ptvDB
 
6
import gtk.glade
 
7
import gobject
 
8
import utils
 
9
 
 
10
import logging
 
11
 
 
12
import os, os.path
 
13
if utils.HAS_LUCENE:
 
14
        import PyLucene
 
15
        threadclass = PyLucene.PythonThread
 
16
else:
 
17
        import threading
 
18
        threadclass = threading.Thread
 
19
 
 
20
class SynchronizeDialog:
 
21
        def __init__(self, gladefile, app):
 
22
                self._app = app
 
23
                self._xml = gtk.glade.XML(gladefile, 'synchronize_window','penguintv')
 
24
                self._dialog = self._xml.get_widget("synchronize_window")
 
25
                self._preview_dialog = self._xml.get_widget("sync_preview_window")
 
26
                for key in dir(self.__class__):
 
27
                        if key[:3] == 'on_':
 
28
                                self._xml.signal_connect(key, getattr(self,key))
 
29
                                
 
30
                self._audio_check = self._xml.get_widget("audio_check")
 
31
                self._delete_check = self._xml.get_widget("delete_check")
 
32
                self._move_check = self._xml.get_widget("move_check")
 
33
                self._destination_entry = self._xml.get_widget("dest_entry")
 
34
                
 
35
                self._delete_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_delete', False))
 
36
                self._move_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_move', False))
 
37
                self._audio_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_audio_only', False))
 
38
                self._dest_dir = self._app.db.get_setting(ptvDB.STRING, '/apps/penguintv/sync_dest_dir', "")
 
39
                self._destination_entry.set_text(self._dest_dir)
 
40
                self._cancel = False
 
41
                
 
42
                
 
43
                if utils.HAS_GCONF:
 
44
                        try:
 
45
                                import gconf
 
46
                        except:
 
47
                                from gnome import gconf
 
48
                        self._conf = gconf.client_get_default()
 
49
                        self._conf.add_dir('/apps/penguintv',gconf.CLIENT_PRELOAD_NONE)
 
50
                        self._conf.notify_add('/apps/penguintv/sync_delete',self.set_sync_delete)
 
51
                        self._conf.notify_add('/apps/penguintv/sync_move',self.set_sync_move)
 
52
                        self._conf.notify_add('/apps/penguintv/sync_audio_only',self.set_audio_only)
 
53
                        self._conf.notify_add('/apps/penguintv/sync_dest_dir',self.set_dest_dir)
 
54
                
 
55
                self._progress_dialog = SynchronizeDialog.SyncProgress(gtk.glade.XML(gladefile, 'sync_progress_window','penguintv'), self._cancel_cb)
 
56
                self._preview_dialog = SynchronizeDialog.SyncPreview(gtk.glade.XML(gladefile, 'sync_preview_window','penguintv'), self._cancel_cb, self._sync_cb)
 
57
                
 
58
        def Show(self):
 
59
                self._dialog.show()
 
60
                                
 
61
        def run(self):
 
62
                self._destination_entry.grab_focus()
 
63
                return self._dialog.run()
 
64
                
 
65
        def _check_dest_dir(self, dir_to_check):
 
66
                try:
 
67
                        stat = os.stat(dir_to_check)
 
68
                        if not os.path.isdir(dir_to_check):
 
69
                                return False                            
 
70
                        self._app.db.set_setting(ptvDB.STRING, '/apps/penguintv/sync_dest_dir',dir_to_check)
 
71
                        logging.debug("sync destination OK: %s" % dir_to_check)
 
72
                        return True
 
73
                except Exception, e:
 
74
                        logging.warning("sync destination FAIL: %s \n %s" % (dir_to_check, str(e)))
 
75
                        return False
 
76
                
 
77
        def _cancel_cb(self):
 
78
                self._cancel = True
 
79
                #hide preview just in case, but don't hide progress because we want to see that it's cancelling
 
80
                self._preview_dialog.hide()
 
81
                
 
82
        def _sync_cb(self):
 
83
                self._preview_dialog.hide()
 
84
                self.on_sync_button_clicked(None)
 
85
                
 
86
        def on_browse_button_clicked(self, event):
 
87
                dialog = gtk.FileChooserDialog(_('Select Destination Folder...'),None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
 
88
                                  buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
 
89
                dialog.set_default_response(gtk.RESPONSE_OK)
 
90
 
 
91
                response = dialog.run()
 
92
                if response == gtk.RESPONSE_OK:
 
93
                        self._destination_entry.set_text(dialog.get_filename())
 
94
                dialog.destroy()
 
95
        
 
96
        def on_delete_check_toggled(self, event):
 
97
                self._app.db.set_setting(ptvDB.BOOL, '/apps/penguintv/sync_delete',self._delete_check.get_active())
 
98
                
 
99
        def on_move_check_toggled(self, event):
 
100
                self._app.db.set_setting(ptvDB.BOOL, '/apps/penguintv/sync_move',self._move_check.get_active())
 
101
 
 
102
        def on_audio_check_toggled(self, event):
 
103
                self._app.db.set_setting(ptvDB.BOOL, '/apps/penguintv/sync_audio_only',self._audio_check.get_active())
 
104
        
 
105
        def on_sync_button_clicked(self, event):
 
106
                self._dest_dir = self._destination_entry.get_text()
 
107
                if not self._check_dest_dir(self._dest_dir):
 
108
                        dialog = gtk.Dialog(title=_("Destination Error"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
109
                        label = gtk.Label(_("The destination you have selected is not valid.  \nPlease select another destination and try again."))
 
110
                        dialog.vbox.pack_start(label, True, True, 0)
 
111
                        label.show()
 
112
                        response = dialog.run()
 
113
                        dialog.hide()
 
114
                        del dialog
 
115
                        return
 
116
                        
 
117
                #sync = ptv_sync.ptv_sync(self._dest_dir, self._delete_check.get_active(), self._audio_check.get_active())
 
118
                move_files = self._move_check.get_active()
 
119
                sync = SynchronizeDialog._sync_thread(self._dest_dir, 
 
120
                                                                                          self._delete_check.get_active(),
 
121
                                                                                          move_files, 
 
122
                                                                                          self._audio_check.get_active())
 
123
                self._progress_dialog.progress_bar.set_fraction(0)
 
124
                self._progress_dialog.progress_label.set_text("")
 
125
                self._progress_dialog.Show()
 
126
                self._dialog.hide()
 
127
                
 
128
                def _sync_gen():
 
129
                        while True:
 
130
                                p = sync.progress
 
131
                                t = sync.total
 
132
                                m = sync.message
 
133
                                if not self._cancel:
 
134
                                        if move_files:
 
135
                                                for m_id in sync.pop_delete_list():
 
136
                                                        self._app.delete_media(m_id)
 
137
                                        if t == -1:
 
138
                                                self._progress_dialog.progress_bar.pulse()
 
139
                                        else:
 
140
                                                self._progress_dialog.progress_bar.set_fraction(float(p)/float(t))
 
141
                                        self._progress_dialog.progress_label.set_markup("<i>"+m+"</i>")
 
142
                                else:
 
143
                                        sync.interrupt() #don't exit loop, just keep going
 
144
                                if p == t:
 
145
                                        break
 
146
                                yield True
 
147
                        if self._cancel:
 
148
                                self._progress_dialog.hide()
 
149
                        self._cancel = False
 
150
                        self._progress_dialog.hide()
 
151
                        yield False
 
152
                        
 
153
                gobject.timeout_add(100,_sync_gen().next)
 
154
                sync.start()
 
155
                
 
156
        class _sync_thread(threadclass):
 
157
                def __init__(self, dest_dir, delete=False, move=False, audio=False):
 
158
                        threadclass.__init__(self)
 
159
                        self._dest_dir = dest_dir
 
160
                        self._delete = delete
 
161
                        self._move = move
 
162
                        self._audio = audio
 
163
                        self._cancel = False
 
164
                        self._delete_list = []
 
165
                        
 
166
                        self.progress = 0
 
167
                        self.total = 100
 
168
                        self.message = ""
 
169
                        
 
170
                def interrupt(self):
 
171
                        self._cancel = True
 
172
                        
 
173
                def pop_delete_list(self):
 
174
                        retval = self._delete_list
 
175
                        self._delete_list = []
 
176
                        return retval
 
177
                        
 
178
                def run(self):
 
179
                        self._cancel = False
 
180
                        sync = ptv_sync.ptv_sync(self._dest_dir, delete=self._delete, move=self._move, audio=self._audio)
 
181
                        try:
 
182
                                for event in sync.sync_gen():
 
183
                                        if not self._cancel:
 
184
                                                self.progress = event[0]
 
185
                                                self.total    = event[1]
 
186
                                                self.message  = event[2]
 
187
                                                # Append to list of media ids to delete from app
 
188
                                                if event[3] is not None:
 
189
                                                        self._delete_list.append(event[3])
 
190
                                        else:
 
191
                                                sync.interrupt() #don't exit loop
 
192
                        except Exception, e:
 
193
                                print "error copying file:",e
 
194
                        self.progress = self.total #just make sure this is done
 
195
                        
 
196
        def on_preview_button_clicked(self, event):
 
197
                self._dest_dir = self._destination_entry.get_text()
 
198
                if not self._check_dest_dir(self._dest_dir):
 
199
                        dialog = gtk.Dialog(title=_("Destination Error"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
200
                        label = gtk.Label(_("The destination you have selected is not valid.  Please select another destination and try again."))
 
201
                        dialog.vbox.pack_start(label, True, True, 0)
 
202
                        label.show()
 
203
                        response = dialog.run()
 
204
                        dialog.hide()
 
205
                        del dialog
 
206
                        return
 
207
                sync = ptv_sync.ptv_sync(self._dest_dir, delete=self._delete_check.get_active(), 
 
208
                                                                 move=self._move_check.get_active(), 
 
209
                                                                 audio=self._audio_check.get_active(), 
 
210
                                                                 dryrun=True)
 
211
                
 
212
                self._preview_dialog.buff.set_text("")
 
213
                self._preview_dialog.Show()
 
214
                self._dialog.hide()
 
215
 
 
216
                def _sync_gen():
 
217
                        text = ""
 
218
                        last_message = ""
 
219
                        for event in sync.sync_gen():
 
220
                                if not self._cancel:
 
221
                                        #text+="\n"+event[2]
 
222
                                        #self._preview_dialog.buff.set_text(text)
 
223
                                        if last_message != event[2]:
 
224
                                                self._preview_dialog.buff.insert_at_cursor(event[2]+"\n")
 
225
                                        last_message = event[2]
 
226
                                else:
 
227
                                        sync.interrupt()
 
228
                                #else:... just yield, let the generator run its course
 
229
                                yield True
 
230
                        if self._cancel:
 
231
                                self._preview_dialog.hide()
 
232
                        self._cancel = False
 
233
                        yield False
 
234
                gobject.idle_add(_sync_gen().next)                      
 
235
                        
 
236
        def on_cancel_button_clicked(self, event):
 
237
                self.hide()
 
238
        
 
239
        def on_synchronize_window_delete_event(self, widget, event):
 
240
                return self._dialog.hide_on_delete()
 
241
                
 
242
        def hide(self):
 
243
                self._dialog.hide()
 
244
                
 
245
        def set_sync_delete(self, client, *args, **kwargs):
 
246
                self._delete_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_delete', False))
 
247
                
 
248
        def set_sync_move(self, client, *args, **kwargs):
 
249
                self._move_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_move', False))
 
250
 
 
251
        def set_audio_only(self, client, *args, **kwargs):
 
252
                self._audio_check.set_active(self._app.db.get_setting(ptvDB.BOOL, '/apps/penguintv/sync_audio_only', False))
 
253
                
 
254
        def set_dest_dir(self, client, *args, **kwargs):
 
255
                self._dest_dir = self._app.db.get_setting(ptvDB.STRING, '/apps/penguintv/sync_dest_dir', "")
 
256
                self._destination_entry.set_text(self._dest_dir)
 
257
                
 
258
        class SyncProgress:
 
259
                def __init__(self, xml, cancel_cb):
 
260
                        self._dialog = xml.get_widget('sync_progress_window')
 
261
                        self.progress_bar = xml.get_widget('sync_progressbar')
 
262
                        self.progress_bar.set_pulse_step(.05)
 
263
                        self.progress_label = xml.get_widget('progress_info_label')
 
264
                        self._cancel_cb = cancel_cb
 
265
                        for key in dir(self.__class__):
 
266
                                if key[:3] == 'on_':
 
267
                                        xml.signal_connect(key, getattr(self,key))
 
268
                                        
 
269
                def Show(self):
 
270
                        self._dialog.show_all()
 
271
                        
 
272
                def hide(self):
 
273
                        self._dialog.hide()
 
274
                        
 
275
                def on_sync_progress_window_delete_event(self, widget, event):
 
276
                        return self._dialog.hide_on_delete()
 
277
                
 
278
                def on_cancel_button_clicked(self, event):
 
279
                        self._cancel_cb()
 
280
                        self.progress_label.set_markup(_("<i>Cancelling...</i>"))
 
281
                        #self.hide() #stay up while the cancel completes
 
282
        
 
283
        class SyncPreview:
 
284
                def __init__(self, xml, cancel_cb, sync_cb):
 
285
                        self._dialog = xml.get_widget('sync_preview_window')
 
286
                        self._cancel_cb = cancel_cb
 
287
                        self._sync_cb = sync_cb
 
288
                        self.buff = gtk.TextBuffer()
 
289
                        self._sync_textview = xml.get_widget('sync_textview')
 
290
                        self._sync_textview.set_buffer(self.buff)
 
291
                        
 
292
                        for key in dir(self.__class__):
 
293
                                if key[:3] == 'on_':
 
294
                                        xml.signal_connect(key, getattr(self,key))
 
295
                        
 
296
                def Show(self):
 
297
                        self._dialog.show_all()
 
298
                        
 
299
                def hide(self):
 
300
                        self._dialog.hide()
 
301
                        
 
302
                def on_sync_preview_window_delete_event(self, widget, event):
 
303
                        return self._dialog.hide_on_delete()
 
304
                        
 
305
                def on_sync_button_clicked(self, event):
 
306
                        self._sync_cb()
 
307
                        self.hide()
 
308
                        
 
309
                def on_cancel_button_clicked(self, event):
 
310
                        self._cancel_cb()
 
311
                        self.hide()