Subversion Repositories basico

Rev

Rev 369 | Rev 384 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
353 t00mlabs 1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
"""
356 t00mlabs 4
# File: wdg_visor_attachments.py
353 t00mlabs 5
# Author: Tomás Vírseda
6
# License: GPL v3
7
# Description: Attachments Visor
8
"""
9
 
10
import os
11
from os.path import sep as SEP
12
from html import escape
13
import glob
14
import json
15
import html
368 t00mlabs 16
import shutil
353 t00mlabs 17
import gi
18
gi.require_version('Gdk', '3.0')
19
gi.require_version('Gtk', '3.0')
20
from gi.repository import Gdk
21
from gi.repository import Gio
22
from gi.repository import Gtk
23
from gi.repository.GdkPixbuf import Pixbuf
24
from gi.repository import Pango
25
 
26
from basico.core.mod_env import LPATH, ATYPES
27
from basico.core.mod_wdg import BasicoWidget
28
from basico.widgets.wdg_cols import CollectionsMgtView
29
from basico.widgets.wdg_import import ImportWidget
30
 
31
 
32
# ~ total, used, free = shutil.disk_usage('/home/t00m/.basico/opt/webdrivers/geckodriver')
33
# ~ ft = float(ceil(total/(1024*1024*1024)))
34
# ~ ff = float(ceil(free/(1024*1024*1024)))
35
# ~ pf = (ft-ff)*100/ft
36
 
37
# ~ ft = int(ceil(total/(1024*1024*1024)))
38
# ~ ff = int(ceil(free/(1024*1024*1024)))
39
# ~ pf = (ft-ff)*100/ft
40
 
41
class AttachmentsVisor(BasicoWidget, Gtk.VBox):
42
    def __init__(self, app):
43
        super().__init__(app, __class__.__name__)
44
        Gtk.HBox.__init__(self, app)
45
        self.set_homogeneous(False)
46
        self.bag = []
47
        self.get_services()
48
        self.setup_visor()
49
        self.icons = {}
50
        self.icons['type'] = {}
51
        for atype in ATYPES:
52
            self.icons['type'][atype.lower()] = self.srvicm.get_pixbuf_icon('basico-attachment-type-%s' % atype.lower())
53
        self.log.debug("Attachments Visor initialized")
362 t00mlabs 54
        self.populate()
353 t00mlabs 55
 
56
 
57
    def get_services(self):
58
        self.srvgui = self.get_service("GUI")
59
        self.srvclb = self.get_service('Callbacks')
60
        self.srvsap = self.get_service('SAP')
61
        self.srvicm = self.get_service('IM')
62
        self.srvstg = self.get_service('Settings')
63
        self.srvdtb = self.get_service('DB')
64
        self.srvuif = self.get_service("UIF")
65
        self.srvutl = self.get_service("Utils")
355 t00mlabs 66
        self.srvatc = self.get_service('Attachment')
369 t00mlabs 67
        self.srvant = self.get_service('Annotation')
353 t00mlabs 68
 
383 t00mlabs 69
 
353 t00mlabs 70
    def get_treeview(self):
71
        return self.treeview
72
 
73
 
74
    def sort_by_timestamp(self):
368 t00mlabs 75
        self.sorted_model.set_sort_column_id(7, Gtk.SortType.DESCENDING)
353 t00mlabs 76
 
77
 
78
    def setup_visor(self):
79
        scr = Gtk.ScrolledWindow()
80
        scr.set_hexpand(True)
81
        scr.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
82
        scr.set_shadow_type(Gtk.ShadowType.NONE)
83
        self.treeview = Gtk.TreeView()
84
        scr.add(self.treeview)
85
        scr.set_hexpand(True)
86
        self.pack_start(scr, True, True, 0)
87
 
88
        hbox = Gtk.HBox()
89
        pgb = self.srvgui.add_widget('gtk_progressbar_diskusage', Gtk.ProgressBar())
90
        fraction = self.srvutl.get_disk_usage_fraction(LPATH['DB'])
91
        text = self.srvutl.get_disk_usage_human(LPATH['DB'])
92
        pgb.set_fraction(fraction)
93
        pgb.set_text(text)
94
        pgb.set_show_text(True)
95
        hbox.pack_start(pgb, True, True, 0)
96
        self.pack_start(hbox, False, False, 0)
383 t00mlabs 97
 
353 t00mlabs 98
        # Setup model
99
        self.model = Gtk.TreeStore(
356 t00mlabs 100
            str,        # TID (Attachment ID)
353 t00mlabs 101
            Pixbuf,     # Icon
356 t00mlabs 102
            str,        # SAP Note
358 t00mlabs 103
            str,        # Document Type
356 t00mlabs 104
            str,        # Title
105
            str,        # Description
106
            str,        # Added
107
            str,        # Added (timestamp)
108
            str,        # Size
109
            int,        # Size (int)
383 t00mlabs 110
            str,        # Mimetype
353 t00mlabs 111
        )
112
 
113
        # Setup columns
114
        def get_column_header_widget(title, icon_name=None, width=24, height=24):
115
            hbox = Gtk.HBox()
116
            icon = self.srvicm.get_new_image_icon(icon_name, width, height)
117
            label = Gtk.Label()
118
            label.set_markup("<b>%s</b>" % title)
119
            # ~ label.modify_font(Pango.FontDescription('Monospace 10'))
120
            hbox.pack_start(icon, False, False, 3)
121
            hbox.pack_start(label, True, True, 3)
122
            hbox.show_all()
123
            return hbox
124
 
356 t00mlabs 125
        # TID (Attachment ID)
353 t00mlabs 126
        self.renderer_key = Gtk.CellRendererText()
356 t00mlabs 127
        self.column_key = Gtk.TreeViewColumn('TID', self.renderer_key, text=0)
353 t00mlabs 128
        self.column_key.set_visible(False)
129
        self.column_key.set_expand(False)
356 t00mlabs 130
        # ~ self.column_key.set_clickable(False)
131
        # ~ self.column_key.set_sort_indicator(False)
353 t00mlabs 132
        self.treeview.append_column(self.column_key)
133
 
134
        # Icon
135
        self.renderer_icon = Gtk.CellRendererPixbuf()
136
        self.renderer_icon.set_alignment(0.0, 0.5)
137
        self.column_icon = Gtk.TreeViewColumn('', self.renderer_icon, pixbuf=1)
356 t00mlabs 138
        # ~ widget = get_column_header_widget('', 'basico-attachment')
139
        # ~ self.column_icon.set_widget(widget)
353 t00mlabs 140
        self.column_icon.set_visible(True)
141
        self.column_icon.set_expand(False)
359 t00mlabs 142
        self.column_icon.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
143
        self.column_icon.set_expand(False)
144
        self.column_icon.set_clickable(True)
145
        self.column_icon.set_sort_indicator(True)
146
        self.column_icon.set_sort_column_id(10)
353 t00mlabs 147
        self.treeview.append_column(self.column_icon)
148
 
358 t00mlabs 149
        # Document Type
150
        self.renderer_doctype = Gtk.CellRendererText()
151
        self.renderer_doctype.set_property('background', '#FFEEAF')
359 t00mlabs 152
        self.column_doctype = Gtk.TreeViewColumn('Document type', self.renderer_doctype, markup=2)
153
        self.column_doctype.set_visible(False)
358 t00mlabs 154
        self.column_doctype.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
155
        self.column_doctype.set_expand(False)
156
        self.column_doctype.set_clickable(True)
157
        self.column_doctype.set_sort_indicator(True)
359 t00mlabs 158
        self.column_doctype.set_sort_column_id(2)
358 t00mlabs 159
        self.treeview.append_column(self.column_doctype)
359 t00mlabs 160
 
161
        # Description
162
        self.renderer_description = Gtk.CellRendererText()
163
        self.renderer_description.set_property('background', '#E3E3F0')
164
        self.column_description = Gtk.TreeViewColumn('Description', self.renderer_description, markup=3)
165
        # ~ widget = get_column_header_widget('Description', 'basico-component')
166
        # ~ self.column_description.set_widget(widget)
167
        self.column_description.set_visible(True)
168
        self.column_description.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
169
        self.column_description.set_expand(False)
170
        self.column_description.set_clickable(True)
171
        self.column_description.set_sort_indicator(True)
172
        self.column_description.set_sort_column_id(3)
173
        self.treeview.append_column(self.column_description)
383 t00mlabs 174
 
356 t00mlabs 175
        # Attachment Title
353 t00mlabs 176
        self.renderer_title = Gtk.CellRendererText()
177
        self.renderer_title.set_property('background', '#FFFEEA')
178
        self.renderer_title.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE)
358 t00mlabs 179
        self.column_title = Gtk.TreeViewColumn('Title', self.renderer_title, markup=4)
356 t00mlabs 180
        # ~ widget = get_column_header_widget('Title', 'basico-tag')
181
        # ~ self.column_title.set_widget(widget)
353 t00mlabs 182
        self.column_title.set_visible(True)
183
        self.column_title.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
184
        self.column_title.set_expand(True)
185
        self.column_title.set_clickable(True)
186
        self.column_title.set_sort_indicator(True)
358 t00mlabs 187
        self.column_title.set_sort_column_id(4)
353 t00mlabs 188
        self.treeview.append_column(self.column_title)
189
 
359 t00mlabs 190
        # SAP Note Id
191
        self.renderer_sid = Gtk.CellRendererText()
192
        self.renderer_sid.set_property('xalign', 1.0)
193
        self.renderer_sid.set_property('height', 36)
194
        self.renderer_sid.set_property('background', '#F0E3E3')
195
        self.column_sid = Gtk.TreeViewColumn('SAP Note', self.renderer_sid, markup=5)
196
        # ~ widget = get_column_header_widget('SAP Note', 'basico-sid')
197
        # ~ self.column_sid.set_widget(widget)
198
        self.column_sid.set_visible(True)
199
        self.column_sid.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
200
        self.column_sid.set_expand(False)
201
        self.column_sid.set_clickable(True)
202
        self.column_sid.set_sort_indicator(True)
203
        self.column_sid.set_sort_column_id(5)
204
        self.treeview.append_column(self.column_sid)
383 t00mlabs 205
 
356 t00mlabs 206
        # Added
358 t00mlabs 207
        self.renderer_added = Gtk.CellRendererText()
208
        self.renderer_added.set_property('background', '#E3F1E3')
209
        self.column_added = Gtk.TreeViewColumn('Added', self.renderer_added, markup=6)
210
        # ~ widget = get_column_header_widget('Added', 'basico-category')
211
        # ~ self.column_added.set_widget(widget)
212
        self.column_added.set_visible(True)
213
        self.column_added.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
214
        self.column_added.set_expand(False)
215
        self.column_added.set_clickable(True)
216
        self.column_added.set_sort_indicator(True)
217
        self.column_added.set_sort_column_id(7)
218
        self.treeview.append_column(self.column_added)
353 t00mlabs 219
 
356 t00mlabs 220
        # Added (timestamp)
358 t00mlabs 221
        self.renderer_addedts = Gtk.CellRendererText()
222
        self.column_addedts = Gtk.TreeViewColumn('Added', self.renderer_addedts, text=7)
223
        self.column_addedts.set_visible(False)
224
        self.treeview.append_column(self.column_addedts)
353 t00mlabs 225
 
356 t00mlabs 226
        # Size
358 t00mlabs 227
        self.renderer_size = Gtk.CellRendererText()
228
        self.renderer_size.set_property('background', '#e4f1f1')
229
        self.column_size = Gtk.TreeViewColumn('Size', self.renderer_size, markup=8)
230
        self.column_size.set_visible(True)
231
        self.column_size.set_expand(False)
232
        self.column_size.set_clickable(True)
233
        self.column_size.set_sort_indicator(True)
234
        self.column_size.set_sort_column_id(9)
235
        self.treeview.append_column(self.column_size)
353 t00mlabs 236
 
356 t00mlabs 237
        # Size (int)
238
        self.renderer_sizeint = Gtk.CellRendererText()
239
        self.renderer_sizeint.set_property('background', '#FFE6D1')
358 t00mlabs 240
        self.column_sizeint = Gtk.TreeViewColumn('SizeInt', self.renderer_sizeint, text=9)
356 t00mlabs 241
        self.column_sizeint.set_visible(False)
242
        self.column_sizeint.set_clickable(True)
243
        self.column_sizeint.set_sort_indicator(True)
358 t00mlabs 244
        self.column_sizeint.set_sort_column_id(9)
356 t00mlabs 245
        self.treeview.append_column(self.column_sizeint)
353 t00mlabs 246
 
356 t00mlabs 247
        # Mimetype
353 t00mlabs 248
        self.renderer_annotation = Gtk.CellRendererText()
358 t00mlabs 249
        self.column_annotation = Gtk.TreeViewColumn('Mimetype', self.renderer_annotation, markup=10)
353 t00mlabs 250
        self.column_annotation.set_visible(False)
251
        self.treeview.append_column(self.column_annotation)
383 t00mlabs 252
 
353 t00mlabs 253
        # Treeview properties
254
        self.treeview.set_can_focus(False)
255
        self.treeview.set_enable_tree_lines(True)
256
        self.treeview.set_headers_visible(True)
257
        self.treeview.set_enable_search(True)
258
        self.treeview.set_hover_selection(False)
259
        self.treeview.set_grid_lines(Gtk.TreeViewGridLines.NONE)
260
        self.treeview.set_enable_tree_lines(True)
261
        self.treeview.set_level_indentation(10)
368 t00mlabs 262
        self.treeview.connect('button_press_event', self.row_right_click)
383 t00mlabs 263
 
353 t00mlabs 264
        # DOC: In order to have a Gtk.Widged with sorting and filtering
265
        # capabilities, you have to filter the model first, and use this
266
        # new model to create the sorted model. Then, attach the sorted
267
        # model to the treeview...
268
 
269
        # Treeview filtering:
270
        self.visible_filter = self.model.filter_new()
271
        self.visible_filter.set_visible_func(self.visible_function)
272
 
273
        # TreeView sorting
274
        self.sorted_model = Gtk.TreeModelSort(model=self.visible_filter)
275
        self.sorted_model.set_sort_func(0, self.sort_function, None)
276
 
277
        # Selection
278
        self.selection = self.treeview.get_selection()
279
        self.selection.set_mode(Gtk.SelectionMode.SINGLE)
356 t00mlabs 280
        # ~ self.selection.connect('changed', self.row_changed)
353 t00mlabs 281
 
282
        # Set model (filtered and sorted)
283
        self.sorted_model.set_sort_column_id(9, Gtk.SortType.ASCENDING)
284
        self.treeview.set_model(self.sorted_model)
285
 
286
        self.show_all()
287
 
288
 
289
    def sort_function(self, model, row1, row2, user_data):
290
        sort_column = 0
291
 
292
        value1 = model.get_value(row1, sort_column)
293
        value2 = model.get_value(row2, sort_column)
294
 
295
        if value1 < value2:
296
            return -1
297
        elif value1 == value2:
298
            return 0
299
        else:
300
            return 1
301
 
302
 
303
    def always_visible(self, model, itr, data):
304
        return False
305
 
306
 
307
    def visible_function(self, model, itr, data):
308
        entry = self.srvgui.get_widget('gtk_entry_filter_visor')
309
        text = self.srvutl.clean_html(entry.get_text())
310
        title = model.get(itr, 4)[0]
311
        match = text.upper() in title.upper()
312
 
313
        return match
314
 
315
 
356 t00mlabs 316
    def update_total_attachments_count(self):
353 t00mlabs 317
        statusbar = self.srvgui.get_widget('widget_statusbar')
318
        lblnotescount = self.srvgui.get_widget('gtk_label_total_notes')
356 t00mlabs 319
        total = self.srvatc.get_total()
353 t00mlabs 320
        count = len(self.visible_filter)
356 t00mlabs 321
        lblnotescount.set_markup("<b>%d/<big>%d attachments</big></b>" % (count, total))
322
        msg = 'View populated with %d attachments' % count
353 t00mlabs 323
        self.srvuif.statusbar_msg(msg)
324
 
325
 
326
    def get_visible_filter(self):
327
        return self.visible_filter
328
 
329
 
356 t00mlabs 330
    # ~ def row_changed(self, selection):
331
        # ~ try:
332
            # ~ model, treeiter = selection.get_selected()
333
            # ~ if treeiter is not None:
334
                # ~ component = model[treeiter][5]
335
                # ~ if component == 'Annotation':
336
                    # ~ aid = model[treeiter][10]
337
                    # ~ is_valid = self.srvant.is_valid(aid)
338
                    # ~ if is_valid:
339
                        # ~ self.srvclb.action_annotation_edit(aid)
340
                # ~ else:
341
                    # ~ aid = None
342
                    # ~ self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
343
        # ~ except Exception as error:
344
            # ~ head = "Error reading annotation's contents"
345
            # ~ body = "<i>%s</i>\n\n" % error
346
            # ~ body += "As a workaround, a new file will be created"
347
            # ~ dialog = self.srvuif.message_dialog_error(head, body)
348
            # ~ self.log.debug(error)
349
            # ~ self.log.debug(self.get_traceback())
350
            # ~ dialog.run()
351
            # ~ dialog.destroy()
352
            # ~ #FIXME: create an empty file for contents
353 t00mlabs 353
 
354
 
355
    def toggle_checkbox(self, cell, path):
356
        path = self.sorted_model.convert_path_to_child_path(Gtk.TreePath(path))
357
        self.model[path][2] = not self.model[path][2]
358
 
359
 
356 t00mlabs 360
    def get_node(self, key, icon, sid, title, description, added, timestamp, size, sizeint, mimetype, doctype):
353 t00mlabs 361
        # Add completion entries
356 t00mlabs 362
        # ~ completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
363
        # ~ completion_model = completion.get_model()
364
        # ~ title = self.srvutl.clean_html(title)
365
        # ~ completion_model.append([title])
353 t00mlabs 366
 
367
        node = []
368
        node.append(key)
369
        node.append(icon)
370
        node.append(sid)
371
        node.append(title)
356 t00mlabs 372
        node.append(description)
373
        node.append(added)
374
        node.append(timestamp)
375
        node.append(size)
376
        node.append(sizeint)
377
        node.append(mimetype)
378
        node.append(doctype)
353 t00mlabs 379
        return node
380
 
381
 
356 t00mlabs 382
    def set_bag(self, attachments):
383
        self.bag = attachments
353 t00mlabs 384
 
385
 
386
    def get_bag(self):
387
        return self.bag
388
 
389
 
390
    def reload(self):
391
        bag = self.get_bag()
362 t00mlabs 392
        self.populate(bag)
353 t00mlabs 393
 
394
 
362 t00mlabs 395
    def populate(self, attachments=None):
356 t00mlabs 396
        # ~ completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
397
        # ~ completion_model = completion.get_model()
398
        # ~ completion_model.clear()
353 t00mlabs 399
 
400
        self.treeview.set_model(None)
401
        self.model.clear()
402
 
356 t00mlabs 403
        if attachments is None:
404
            attachments = self.srvatc.get_all()
353 t00mlabs 405
        else:
356 t00mlabs 406
            self.set_bag(attachments)
353 t00mlabs 407
 
408
        dcats = {}
409
        snpids = {}
410
        nodes = []
356 t00mlabs 411
        for fname in attachments:
353 t00mlabs 412
            try:
413
                with open(fname, 'r') as fa:
414
                    try:
356 t00mlabs 415
                        metadata = json.load(fa)
416
                        sid = self.srvatc.get_sid(metadata['TID'])
358 t00mlabs 417
                        sid = str(int(sid))
418
                        if sid == '0':
356 t00mlabs 419
                            sid = ''
383 t00mlabs 420
                        node = self.get_node(   metadata['TID'],
360 t00mlabs 421
                                                self.srvicm.find_mime_type_pixbuf(metadata['Mimetype'], 36, 36),
358 t00mlabs 422
                                                metadata['Doctype'],
359 t00mlabs 423
                                                metadata['Description'],
356 t00mlabs 424
                                                metadata['Title'],
359 t00mlabs 425
                                                sid,
356 t00mlabs 426
                                                self.srvutl.fuzzy_date_from_timestamp(metadata['Created']),
427
                                                metadata['Created'],
428
                                                str(self.srvutl.get_human_sizes(int(metadata['Size']))),
383 t00mlabs 429
                                                int(metadata['Size']),
430
                                                metadata['Mimetype'],
356 t00mlabs 431
                                            )
432
                        nodes.append(node)
353 t00mlabs 433
                    except Exception as error:
434
                        self.log.error(error)
435
                        self.log.error(self.get_traceback())
436
            except Exception as error:
437
                # Whenever an annotation is deleted, after reloading
438
                # the view, it fails. Then, skip it
356 t00mlabs 439
                self.log.error("Attachment: %s", fname)
353 t00mlabs 440
                self.log.error(error)
441
 
442
        for node in nodes:
356 t00mlabs 443
            self.model.append(None, node)
353 t00mlabs 444
 
445
        self.treeview.set_model(self.sorted_model)
446
        self.sort_by_timestamp()
356 t00mlabs 447
        self.update_total_attachments_count()
383 t00mlabs 448
        # ~ self.log.debug("Visor updated")
353 t00mlabs 449
 
450
    def show_widgets(self):
451
        self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
452
 
453
 
368 t00mlabs 454
    def row_right_click(self, treeview, event, data=None):
353 t00mlabs 455
        if event.button == 3:
456
            rect = Gdk.Rectangle()
457
            rect.x = x = int(event.x)
458
            rect.y = y = int(event.y)
459
            pthinfo = self.treeview.get_path_at_pos(x,y)
460
            if pthinfo is not None:
461
                path,col,cellx,celly = pthinfo
462
                model = treeview.get_model()
463
                treeiter = model.get_iter(path)
368 t00mlabs 464
                tid = model[treeiter][0]
353 t00mlabs 465
                toolbar = self.srvgui.get_widget('visortoolbar')
466
                popover = self.srvgui.add_widget('gtk_popover_visor_row', Gtk.Popover.new(treeview))
467
                popover.set_position(Gtk.PositionType.TOP)
468
                popover.set_pointing_to(rect)
368 t00mlabs 469
                box = self.build_popover(tid, popover)
353 t00mlabs 470
                if box is not None:
471
                    popover.add(box)
472
                    self.srvclb.gui_show_popover(None, popover)
473
 
474
 
368 t00mlabs 475
    def build_popover(self, tid, popover):
476
        sid = self.srvatc.get_sid(tid)
369 t00mlabs 477
        aid = self.srvatc.get_metadata_value(tid, 'AID')
368 t00mlabs 478
        self.log.debug("%s -> %s", tid, sid)
353 t00mlabs 479
 
480
        def get_popover_button(text, icon_name):
481
            button = Gtk.Button()
482
            button.set_relief(Gtk.ReliefStyle.NONE)
483
            hbox = Gtk.HBox()
484
            icon = self.srvicm.get_new_image_icon(icon_name, 24, 24)
485
            lbltext = Gtk.Label()
486
            lbltext.set_xalign(0.0)
487
            lbltext.set_markup('%s' % text)
488
            hbox.pack_start(icon, False, False, 3)
489
            hbox.pack_start(lbltext, True, True, 3)
490
            button.add(hbox)
491
            return button
492
 
368 t00mlabs 493
        box = Gtk.Box(spacing = 3, orientation="vertical")
353 t00mlabs 494
 
368 t00mlabs 495
        # ~ # Popover button "Delete annotation"
496
        # ~ button = get_popover_button("<b>Delete</b> annotation", 'basico-delete')
497
        # ~ button.show_all()
498
        # ~ button.connect('clicked', self.srvclb.action_annotation_delete)
499
        # ~ box.pack_start(button, False, False, 0)
500
 
501
        # Copy identifier to clipboard
502
        button = get_popover_button("<b>Copy identifier</b> to clipboard", 'basico-copy-paste')
503
        button.show_all()
504
        button.connect('clicked', self.srvclb.copy_text_to_clipboard, tid)
505
        box.pack_start(button, False, False, 0)
506
 
507
        if sid != '0000000000':
508
            # Jump to SAP Note
509
            button = get_popover_button("Jump to <b>SAP Note %d</b>" % int(sid), 'basico-jump-sapnote')
353 t00mlabs 510
            button.show_all()
368 t00mlabs 511
            button.connect('clicked', self.srvclb.gui_jump_to_sapnote, sid)
353 t00mlabs 512
            box.pack_start(button, False, False, 0)
369 t00mlabs 513
 
514
        if self.srvant.is_valid(aid):
515
           # Jump to Annotation
516
            aid_file = LPATH['ANNOTATIONS'] + aid + '.json'
517
            button = get_popover_button("Jump to <b>Annotation</b>", 'basico-jump-sapnote')
518
            button.show_all()
519
            button.connect('clicked', self.srvclb.gui_jump_to_annotation, aid_file)
520
            box.pack_start(button, False, False, 0)
383 t00mlabs 521
 
368 t00mlabs 522
        # Separator
523
        separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
524
        box.pack_start(separator, True, True, 0)
353 t00mlabs 525
 
368 t00mlabs 526
        # Download to PC
527
        button = get_popover_button("<b>Download attachment</b> to PC", 'basico-backup')
528
        button.show_all()
529
        button.connect('clicked', self.download, tid)
530
        box.pack_start(button, False, False, 0)
383 t00mlabs 531
 
368 t00mlabs 532
        return box
353 t00mlabs 533
 
534
 
535
    def connect_menuview_signals(self):
536
        # Categories
537
        button = self.srvgui.get_widget('gtk_togglebutton_categories')
538
        button.connect('toggled', self.set_visible_categories)
539
 
540
        for name in ['inbox', 'drafts', 'archived']:
541
            button = self.srvgui.get_widget('gtk_button_category_%s' % name)
542
            button.connect('toggled', self.set_visible_category, name)
543
 
544
        # Types
545
        button = self.srvgui.get_widget('gtk_togglebutton_types')
546
        button.connect('toggled', self.set_visible_types)
547
 
548
        for name in ATYPES:
549
            button = self.srvgui.get_widget('gtk_button_type_%s' % name.lower())
550
            button.connect('toggled', self.set_visible_annotation_type, name)
551
 
552
 
553
    def set_active_categories(self):
554
        category = self.srvgui.get_widget('gtk_togglebutton_inbox')
555
        category.set_active(True)
556
 
368 t00mlabs 557
 
558
    def download(self, widget, tid):
559
        filename = self.srvatc.get_metadata_value(tid, 'Title')
560
        target_folder = self.srvuif.select_folder()
561
        if target_folder is not None:
562
            source = LPATH['ATTACHMENTS'] + tid
563
            target = os.path.join(target_folder, filename)
564
            shutil.copy(source, target)
565
            msg = "Attachment downloaded to %s" % (target)
566
            self.log.debug(msg)
567
            self.srvuif.statusbar_msg(msg)
568