~gtg-user/gtg/port-to-gtk3

« back to all changes in this revision

Viewing changes to GTG/gtk/editor/editor.py

  • Committer: Izidor Matušov
  • Date: 2012-12-14 13:53:48 UTC
  • mfrom: (1240.1.17 trunk)
  • Revision ID: izidor.matusov@gmail.com-20121214135348-q7wn21y464xb1q2x
Merging trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
 
28
28
from gi.repository import Gtk, Gdk, Pango
29
29
 
30
 
from GTG                     import _, ngettext
31
 
from GTG.gtk.editor          import GnomeConfig
 
30
from GTG import _, ngettext
 
31
from GTG.gtk.editor import GnomeConfig
32
32
from GTG.gtk.editor.taskview import TaskView
33
33
from GTG.core.plugins.engine import PluginEngine
34
 
from GTG.core.plugins.api    import PluginAPI
35
 
from GTG.core.task           import Task
36
 
from GTG.tools.dates         import Date
 
34
from GTG.core.plugins.api import PluginAPI
 
35
from GTG.core.task import Task
 
36
from GTG.tools.dates import Date
37
37
from GTG.gtk.editor.calendar import GTGCalendar
38
38
 
 
39
 
39
40
class TaskEditor(object):
40
41
 
41
 
    def __init__(self, 
42
 
                 requester, 
43
 
                 vmanager, 
44
 
                 task, 
 
42
    def __init__(self,
 
43
                 requester,
 
44
                 vmanager,
 
45
                 task,
45
46
                 taskconfig = None,
46
47
                 thisisnew = False,
47
48
                 clipboard = None):
98
99
                self.on_move,
99
100
        }
100
101
        self.builder.connect_signals(dic)
101
 
        self.window         = self.builder.get_object("TaskEditor")
 
102
        self.window = self.builder.get_object("TaskEditor")
102
103
        #Removing the Normal textview to replace it by our own
103
104
        #So don't try to change anything with GtkBuilder, this is a home-made widget
104
105
        textview = self.builder.get_object("textview")
105
106
        scrolled = self.builder.get_object("scrolledtask")
106
107
        scrolled.remove(textview)
107
 
        self.textview   = TaskView(self.req, self.clipboard)
 
108
        self.textview = TaskView(self.req, self.clipboard)
108
109
        self.textview.show()
109
110
        self.textview.set_subtask_callback(self.new_subtask)
110
111
        self.textview.open_task_callback(self.vmanager.open_task)
113
114
        scrolled.add(self.textview)
114
115
        conf_font_value = self.browser_config.get("font_name")
115
116
        if conf_font_value!= "":
116
 
            self.textview.modify_font(Pango.FontDescription(conf_font_value)) 
 
117
            self.textview.modify_font(Pango.FontDescription(conf_font_value))
117
118
        #Voila! it's done
118
 
        self.calendar       = GTGCalendar(self.builder)
 
119
        self.calendar = GTGCalendar(self.builder)
119
120
        self.duedate_widget = self.builder.get_object("duedate_entry")
120
121
        self.startdate_widget = self.builder.get_object("startdate_entry")
121
122
        self.closeddate_widget = self.builder.get_object("closeddate_entry")
122
 
        self.dayleft_label  = self.builder.get_object("dayleft")
 
123
        self.dayleft_label = self.builder.get_object("dayleft")
123
124
        self.tasksidebar = self.builder.get_object("tasksidebar")
124
125
        # Define accelerator keys
125
126
        self.init_accelerators()
176
177
            if tid in self.config:
177
178
                if "position" in self.config[tid]:
178
179
                    pos = self.config[tid]["position"]
179
 
                    self.move(pos[0],pos[1])
180
 
                    #print "restoring position %s %s" %(pos[0],pos[1])
 
180
                    self.move(pos[0], pos[1])
 
181
                    #print "restoring position %s %s" %(pos[0], pos[1])
181
182
                if "size" in self.config[tid]:
182
183
                    size = self.config[tid]["size"]
183
184
                    #print "size %s - %s" %(str(size[0]), str(size[1]))
184
 
                    #this eval(str()) is a ugly (!) hack to accept both int and str
 
185
                    #this eval(str()) is a ugly (!) hack to accept both int and
 
186
                    #str
185
187
                    #FIXME: Fix this!
186
 
                    self.window.resize(eval(str(size[0])),eval(str(size[1])))
 
188
                    self.window.resize(eval(str(size[0])), eval(str(size[1])))
187
189
 
188
190
        self.textview.set_editable(True)
189
191
        self.window.show()
208
210
 
209
211
        # Ctrl-Shift-N creates a new subtask
210
212
        insert_subtask = self.builder.get_object("insert_subtask")
211
 
        key, mod       = Gtk.accelerator_parse("<Control><Shift>n")
212
 
        insert_subtask.add_accelerator('clicked', agr, key, mod, Gtk.AccelFlags.VISIBLE)
 
213
        key, mod = Gtk.accelerator_parse("<Control><Shift>n")
 
214
        insert_subtask.add_accelerator('clicked', agr, key, mod,
 
215
            Gtk.AccelFlags.VISIBLE)
213
216
 
214
217
        # Ctrl-D marks task as done
215
218
        mark_as_done_editor = self.builder.get_object('mark_as_done_editor')
216
219
        key, mod = Gtk.accelerator_parse('<Control>d')
217
 
        mark_as_done_editor.add_accelerator('clicked', agr, key, mod, Gtk.AccelFlags.VISIBLE)
 
220
        mark_as_done_editor.add_accelerator('clicked', agr, key, mod,
 
221
            Gtk.AccelFlags.VISIBLE)
218
222
 
219
223
        # Ctrl-I marks task as dismissed
220
224
        dismiss_editor = self.builder.get_object('dismiss_editor')
221
225
        key, mod = Gtk.accelerator_parse('<Control>i')
222
 
        dismiss_editor.add_accelerator('clicked', agr, key, mod, Gtk.AccelFlags.VISIBLE)
 
226
        dismiss_editor.add_accelerator('clicked', agr, key, mod,
 
227
            Gtk.AccelFlags.VISIBLE)
223
228
 
224
229
    #Can be called at any time to reflect the status of the Task
225
230
    #Refresh should never interfere with the TaskView.
231
236
        if self.window == None:
232
237
            return
233
238
        to_save = False
234
 
        #title of the window 
 
239
        #title of the window
235
240
        if title:
236
241
            self.window.set_title(title)
237
242
            to_save = True
238
243
        else:
239
244
            self.window.set_title(self.task.get_title())
240
245
 
241
 
        status = self.task.get_status() 
 
246
        status = self.task.get_status()
 
247
        dismiss_tooltip = GnomeConfig.MARK_UNDISMISS_TOOLTIP
242
248
        if status == Task.STA_DISMISSED:
243
249
            self.donebutton.set_label(GnomeConfig.MARK_DONE)
244
250
            self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP)
245
251
            self.donebutton.set_icon_name("gtg-task-done")
246
252
            self.dismissbutton.set_label(GnomeConfig.MARK_UNDISMISS)
247
 
            self.dismissbutton.set_tooltip_text(GnomeConfig.MARK_UNDISMISS_TOOLTIP)
 
253
            self.dismissbutton.set_tooltip_text(dismiss_tooltip)
248
254
            self.dismissbutton.set_icon_name("gtg-task-undismiss")
249
255
        elif status == Task.STA_DONE:
250
256
            self.donebutton.set_label(GnomeConfig.MARK_UNDONE)
251
257
            self.donebutton.set_tooltip_text(GnomeConfig.MARK_UNDONE_TOOLTIP)
252
258
            self.donebutton.set_icon_name("gtg-task-undone")
253
259
            self.dismissbutton.set_label(GnomeConfig.MARK_DISMISS)
254
 
            self.dismissbutton.set_tooltip_text(GnomeConfig.MARK_DISMISS_TOOLTIP)
 
260
            self.dismissbutton.set_tooltip_text(dismiss_tooltip)
255
261
            self.dismissbutton.set_icon_name("gtg-task-dismiss")
256
262
        else:
257
263
            self.donebutton.set_label(GnomeConfig.MARK_DONE)
258
264
            self.donebutton.set_tooltip_text(GnomeConfig.MARK_DONE_TOOLTIP)
259
265
            self.donebutton.set_icon_name("gtg-task-done")
260
266
            self.dismissbutton.set_label(GnomeConfig.MARK_DISMISS)
261
 
            self.dismissbutton.set_tooltip_text(GnomeConfig.MARK_DISMISS_TOOLTIP)
 
267
            self.dismissbutton.set_tooltip_text(dismiss_tooltip)
262
268
            self.dismissbutton.set_icon_name("gtg-task-dismiss")
263
269
        self.donebutton.show()
264
270
        self.tasksidebar.show()
272
278
        else:
273
279
            self.builder.get_object("label4").hide()
274
280
            self.builder.get_object("hbox4").hide()
275
 
            self.builder.get_object("label2").show() 
 
281
            self.builder.get_object("label2").show()
276
282
            self.builder.get_object("hbox1").show()
277
283
 
278
284
        #refreshing the start date field
284
290
            update_date = True
285
291
 
286
292
        if update_date:
287
 
            self.startdate_widget.set_text(str(startdate)) 
 
293
            self.startdate_widget.set_text(str(startdate))
288
294
 
289
295
        #refreshing the due date field
290
296
        duedate = self.task.get_due_date()
304
310
            self.closeddate_widget.set_text(str(closeddate))
305
311
 
306
312
        #refreshing the day left label
307
 
        #If the task is marked as done, we display the delay between the 
308
 
        #due date and the actual closing date. If the task isn't marked 
 
313
        #If the task is marked as done, we display the delay between the
 
314
        #due date and the actual closing date. If the task isn't marked
309
315
        #as done, we display the number of days left.
310
316
        if status in [Task.STA_DISMISSED, Task.STA_DONE]:
311
317
            delay = self.task.get_days_late()
314
320
            elif delay == 0:
315
321
                txt = "Completed on time"
316
322
            elif delay >= 1:
317
 
                txt = ngettext("Completed %(days)d day late", "Completed %(days)d days late", delay) % {'days': delay}
 
323
                txt = ngettext("Completed %(days)d day late",
 
324
                    "Completed %(days)d days late", delay) % {'days': delay}
318
325
            elif delay <= -1:
319
326
                abs_delay = abs(delay)
320
 
                txt = ngettext("Completed %(days)d day early", "Completed %(days)d days early", abs_delay) % {'days': abs_delay}
 
327
                txt = ngettext("Completed %(days)d day early",
 
328
                    "Completed %(days)d days early", abs_delay) % \
 
329
                    {'days': abs_delay}
321
330
        else:
322
331
            due_date = self.task.get_due_date()
323
332
            result = due_date.days_left()
324
333
            if due_date.is_fuzzy():
325
334
                txt = ""
326
335
            elif result > 0:
327
 
                txt = ngettext("Due tomorrow!", "%(days)d days left", result) % {'days': result}
 
336
                txt = ngettext("Due tomorrow!", "%(days)d days left", result) \
 
337
                    % {'days': result}
328
338
            elif result == 0:
329
339
                txt = _("Due today!")
330
340
            elif result < 0:
331
341
                abs_result = abs(result)
332
 
                txt = ngettext("Due yesterday!", "Was %(days)d days ago", abs_result) % {'days': abs_result}
 
342
                txt = ngettext("Due yesterday!", "Was %(days)d days ago",
 
343
                    abs_result) % {'days': abs_result}
333
344
 
334
345
        style_context = self.window.get_style_context()
335
346
        color = style_context.get_color(Gtk.StateFlags.INSENSITIVE).to_color()
336
 
        self.dayleft_label.set_markup("<span color='"+color.to_string()+"'>"+txt+"</span>")
 
347
        self.dayleft_label.set_markup("<span color='%s'>%s</span>" % (
 
348
            color.to_string(), txt))
337
349
 
338
350
        #Refreshing the tag list in the insert tag button
339
351
        taglist = self.req.get_used_tags()
356
368
        if to_save:
357
369
            self.light_save()
358
370
 
359
 
    def date_changed(self,widget,data):
 
371
    def date_changed(self, widget, data):
360
372
        text = widget.get_text()
361
373
        valid = True
362
374
        if not text:
428
440
        for task in all_subtasks:
429
441
            self.vmanager.close_task(task.get_id())
430
442
 
431
 
    def dismiss(self,widget): #pylint: disable-msg=W0613
 
443
    def dismiss(self, widget): #pylint: disable-msg=W0613
432
444
        stat = self.task.get_status()
433
445
        if stat == "Dismiss":
434
446
            self.task.set_status("Active")
438
450
            self.close_all_subtasks()
439
451
            self.close(None)
440
452
 
441
 
    def change_status(self,widget): #pylint: disable-msg=W0613
 
453
    def change_status(self, widget): #pylint: disable-msg=W0613
442
454
        stat = self.task.get_status()
443
455
        if stat == "Done":
444
456
            self.task.set_status("Active")
457
469
            self.vmanager.ask_delete_tasks([self.task.get_id()])
458
470
 
459
471
    #Take the title as argument and return the subtask ID
460
 
    def new_subtask(self,title=None,tid=None):
 
472
    def new_subtask(self, title=None, tid=None):
461
473
        if tid:
462
474
            self.task.add_child(tid)
463
475
        elif title:
472
484
        task_id = task.get_id()
473
485
        self.vmanager.open_task(task_id)
474
486
 
475
 
    def insert_subtask(self,widget): #pylint: disable-msg=W0613
 
487
    def insert_subtask(self, widget): #pylint: disable-msg=W0613
476
488
        self.textview.insert_newtask()
477
489
        self.textview.grab_focus()
478
490
 
479
 
    def inserttag_clicked(self,widget): #pylint: disable-msg=W0613
 
491
    def inserttag_clicked(self, widget): #pylint: disable-msg=W0613
480
492
        itera = self.textview.get_insert()
481
493
        if itera.starts_line():
482
 
            self.textview.insert_text("@",itera)
 
494
            self.textview.insert_text("@", itera)
483
495
        else:
484
 
            self.textview.insert_text(" @",itera)
 
496
            self.textview.insert_text(" @", itera)
485
497
        self.textview.grab_focus()
486
498
 
487
 
    def inserttag(self,widget,tag): #pylint: disable-msg=W0613
 
499
    def inserttag(self, widget, tag): #pylint: disable-msg=W0613
488
500
        self.textview.insert_tags([tag])
489
501
        self.textview.grab_focus()
490
502
 
491
503
    def save(self):
492
504
        self.task.set_title(self.textview.get_title())
493
 
        self.task.set_text(self.textview.get_text()) 
 
505
        self.task.set_text(self.textview.get_text())
494
506
        self.task.sync()
495
507
        if self.config != None:
496
508
            self.config.write()
509
521
        if tosave:
510
522
            self.save()
511
523
 
512
 
    #This will bring the Task Editor to front    
 
524
    #This will bring the Task Editor to front
513
525
    def present(self):
514
526
        self.window.present()
515
527
 
516
 
    def move(self,x,y):
 
528
    def move(self, x, y):
517
529
        try:
518
530
            xx=int(x)
519
531
            yy=int(y)
520
 
            self.window.move(xx,yy)
 
532
            self.window.move(xx, yy)
521
533
        except:
522
534
            pass
523
535
 
524
536
    def get_position(self):
525
537
        return self.window.get_position()
526
538
 
527
 
    def on_move(self,widget,event):
 
539
    def on_move(self, widget, event):
528
540
        #saving the position
529
541
        if self.config != None:
530
542
            tid = self.task.get_id()
535
547
            self.config[tid]["size"] = self.window.get_size()
536
548
 
537
549
    #We define dummy variable for when close is called from a callback
538
 
    def close(self,window=None,a=None,b=None,c=None): #pylint: disable-msg=W0613
 
550
    def close(self, window=None, a=None, b=None, c=None):
 
551
        #pylint: disable-msg=W0613
539
552
        #We should also destroy the whole taskeditor object.
540
553
        if self.window:
541
554
            self.window.destroy()
542
555
            self.window = None
543
556
 
544
557
    #The destroy signal is linked to the "close" button. So if we call
545
 
    #destroy in the close function, this will cause the close to be called twice
 
558
    #destroy in the close function, this will cause the close to be called
 
559
    #twice
546
560
    #To solve that, close will just call "destroy" and the destroy signal
547
561
    #Will be linked to this destruction method that will save the task
548
 
    def destruction(self,a=None):
 
562
    def destruction(self, a=None):
549
563
        #Save should be also called when buffer is modified
550
564
        self.pengine.onTaskClose(self.plugin_api)
551
565
        self.pengine.remove_api(self.plugin_api)