Subversion Repositories basico

Rev

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

Rev Author Line No. Line
340 t00mlabs 1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
"""
4
# File: srv_cb.py
5
# Author: Tomás Vírseda
6
# License: GPL v3
7
# Description: UI and related callbacks service
8
"""
9
 
10
import os
11
import json
12
import time
13
from concurrent.futures import ThreadPoolExecutor as Executor
14
 
15
import gi
16
gi.require_version('Gtk', '3.0')
17
from gi.repository import Gtk
18
from gi.repository import Gdk
19
 
20
from basico.core.mod_srv import Service
21
from basico.core.mod_env import FILE, LPATH, ATYPES, APP
22
from basico.widgets.wdg_visor_sapnotes import SAPNotesVisor
23
from basico.widgets.wdg_visor_toolbar import VisorToolbar
24
from basico.widgets.wdg_cols import CollectionsMgtView
25
from basico.widgets.wdg_settingsview import SettingsView
26
 
27
# PROPKEYS = CSV headers. SAP Note metadata
28
PROPKEYS = ['id', 'title', 'type', 'componentkey',
29
            'componenttxt', 'category', 'priority', 'releasedon',
30
            'language', 'version']
31
 
32
# Extend PROPKEYS with custom basico metadata
33
PROPKEYS.extend (['Bookmark'])
34
 
35
class Callback(Service):
36
    def initialize(self):
37
        self.get_services()
38
 
39
    def get_services(self):
40
        self.srvstg = self.get_service('Settings')
41
        self.srvdtb = self.get_service('DB')
42
        self.srvgui = self.get_service('GUI')
43
        self.srvuif = self.get_service("UIF")
44
        self.srvsap = self.get_service('SAP')
45
        self.srvicm = self.get_service('IM')
46
        self.srvutl = self.get_service('Utils')
47
        self.srvant = self.get_service('Annotation')
48
        self.srvbnr = self.get_service('BNR')
49
        self.srvclt = self.get_service('Collections')
356 t00mlabs 50
        self.srvatc = self.get_service('Attachment')
340 t00mlabs 51
 
52
 
53
    def gui_visor_switch_page(self, notebook, page, page_num):
54
        # 0|1|(2) -> SAP Notes Visor | Annotations Visor | (Help)
55
        self.srvgui.set_key_value('current_visor_tab', page_num)
56
        notebook_viewmenu = self.srvgui.get_widget('gtk_notebook_menuview')
57
        paned = self.srvgui.get_widget('gtk_hpaned')
58
 
59
        if page_num == 0:
60
            self.srvuif.set_widget_visibility('gtk_button_menu_views', True)
61
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
62
            visor = self.srvgui.get_widget('visor_sapnotes')
63
            visible_filter = visor.get_visible_filter()
64
            visor.update_total_sapnotes_count()
65
            paned.set_position(400)
66
            notebook_viewmenu.set_current_page(0)
67
        elif page_num == 1:
68
            self.srvuif.set_widget_visibility('gtk_button_menu_views', False)
69
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
70
            visor = self.srvgui.get_widget('visor_annotations')
71
            visor.populate_annotations()
349 t00mlabs 72
            paned.set_position(400)
340 t00mlabs 73
            notebook_viewmenu.set_current_page(1)
74
 
75
 
76
    def gui_show_visor_sapnotes(self):
77
        notebook = self.srvgui.get_widget('gtk_notebook_visor')
78
        notebook.set_current_page(0)
79
 
80
 
81
    def gui_show_visor_annotations(self):
82
        notebook = self.srvgui.get_widget('gtk_notebook_visor')
83
        notebook.set_current_page(1)
84
 
85
 
86
    def action_search(self, entry):
87
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
88
        visor_annotations = self.srvgui.get_widget('visor_annotations')
89
        term = entry.get_text()
90
        page = self.srvgui.get_key_value('current_visor_tab')
91
        completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
92
        completion_model = completion.get_model()
93
        completion_model.clear()
94
 
95
        if page == 0:
96
            bag = self.srvdtb.search(term)
97
            visor_sapnotes.populate_sapnotes(bag)
98
            ebuffer = entry.get_buffer()
99
            ebuffer.delete_text(0, -1)
100
            msg = "Found %d SAP Notes for term '%s'" % (len(bag), term)
101
            self.log.info(msg)
102
            self.srvuif.statusbar_msg(msg)
103
        elif page == 1:
104
            annotations = self.srvant.search_term(term)
105
            visor_annotations.populate_annotations(annotations)
106
            msg = "Found %d annotations for term '%s'" % (len(annotations), term)
107
            self.log.info(msg)
108
            self.srvuif.statusbar_msg(msg)
109
 
110
 
111
 
112
    def sapnote_browse(self, button, sid):
113
        self.log.info("Browsing SAP Note %d" % int(sid))
114
        SAP_NOTE_URL = self.srvstg.get('SAP', 'SAP_NOTE_URL')
115
        url = SAP_NOTE_URL % sid
116
        self.srvutl.browse(url)
117
 
118
 
119
    def sapnote_download_pdf(self, button, sid):
120
        self.log.info("Browsing PDF for SAP Note %d" % int(sid))
121
        SAP_NOTE_URL_PDF = self.srvstg.get('SAP', 'SAP_NOTE_URL_PDF')
122
        url = SAP_NOTE_URL_PDF % sid
123
        self.srvutl.browse(url)
124
 
125
 
126
    def sapnote_delete(self, button, sid):
127
        visor = self.srvgui.get_widget('visor_sapnotes')
128
        viewmenu = self.srvgui.get_widget('viewmenu')
129
 
130
        answer = self.srvuif.warning_message_delete_sapnotes(button, 'Deleting SAP Notes', 'Are you sure?', [sid])
131
        if answer is True:
132
            self.srvdtb.delete(sid)
133
            self.srvuif.statusbar_msg("SAP Note %s deleted" % sid, True)
134
            visor.reload()
135
        else:
136
            self.log.info("SAP Note %s not deletd", sid)
137
 
138
 
139
    def sapnote_delete_view(self, button):
140
        visor = self.srvgui.get_widget('visor_sapnotes')
141
        viewmenu = self.srvgui.get_widget('viewmenu')
142
 
143
        bag = visor.get_filtered_bag()
144
        answer = self.srvuif.warning_message_delete_sapnotes(button, 'Deleting SAP Notes', 'Are you sure?', bag)
145
        if answer is True:
146
            for sid in bag:
147
                self.srvdtb.delete(sid)
148
            visor.reload()
149
            msg = "Deleted %d SAP Notes" % len(bag)
150
            self.log.info(msg)
151
            self.srvuif.statusbar_msg(msg, True)
152
        else:
153
            msg = "None of the %d SAP Notes has been deleted" % len(bag)
154
            self.log.info(msg)
155
            self.srvuif.statusbar_msg(msg, True)
156
        visor.reload()
157
        viewmenu.populate()
158
 
159
    def gui_hide_popover(self, popover):
160
        popover.hide()
161
 
162
 
163
    def gui_database_backup(self, *args):
164
        window = self.srvgui.get_window()
165
        question = "Backup database"
166
        message = "\nShould this backup include all your annotations?"
167
        wdialog = self.srvuif.message_dialog_question(question, message)
168
        res_bck_annot = wdialog.run()
169
        wdialog.destroy()
170
 
171
        dialog = Gtk.FileChooserDialog("Please choose target folder and backup name (without extension)", window,
172
            Gtk.FileChooserAction.SAVE,
173
            ("Cancel", Gtk.ResponseType.CANCEL,
174
            "Select", Gtk.ResponseType.OK))
175
        TIMESTAMP = self.srvutl.timestamp()
176
        TARGET_FILE = 'basico-%s' % TIMESTAMP
177
        dialog.set_filename(LPATH['BACKUP'])
178
        dialog.set_current_folder_uri(LPATH['BACKUP'])
179
        dialog.set_current_name(TARGET_FILE)
180
        dialog.set_default_size(800, 400)
181
        res_bck_file = dialog.run()
182
        self.log.debug("Backup file: %s", dialog.get_filename())
183
 
184
        if res_bck_file == Gtk.ResponseType.OK:
185
            backup_filename = dialog.get_filename()
186
            if res_bck_annot == Gtk.ResponseType.YES:
187
                bckname = self.srvbnr.backup(backup_filename, backup_annotations=True)
188
                msg = "Database with annotations backed up successfully to: %s" % bckname
189
                dialog.destroy()
190
            else:
191
                bckname = self.srvbnr.backup(backup_filename, backup_annotations=False)
192
                msg = "Database without annotations backed up successfully to: %s" % bckname
193
            self.log.info(msg)
194
            self.srvuif.statusbar_msg(msg, True)
195
            self.srvuif.copy_text_to_clipboard(bckname)
196
 
197
        else:
198
            self.srvuif.statusbar_msg("Backup aborted by user", True)
199
            self.log.info("Backup aborted")
200
        self.srvuif.grab_focus()
201
 
202
 
203
    def gui_database_restore(self, *args):
204
        visor_annotations = self.srvgui.get_widget('visor_annotations')
205
        window = self.srvgui.get_window()
206
        dialog = Gtk.FileChooserDialog("Please choose a backup file", window,
207
            Gtk.FileChooserAction.OPEN,
208
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
209
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
210
        dialog.set_current_folder(LPATH['BACKUP'])
211
        filter_zip = Gtk.FileFilter()
212
        filter_zip.set_name("Basico backup files")
213
        filter_zip.add_pattern("*.bco")
214
        dialog.add_filter(filter_zip)
215
        response = dialog.run()
216
        backup = dialog.get_filename()
217
        self.log.info("You are about to restore this file: %s" % backup)
218
        dialog.destroy()
219
 
220
        if response == Gtk.ResponseType.OK:
221
            res = self.srvbnr.test(backup)
222
            if res is None:
223
                dialog = self.srvuif.message_dialog_info("Backup file corrupted?", "It wasn't possible to read all data from this file")
224
                dialog.run()
225
                self.srvuif.statusbar_msg("Backup file corrupted. It wasn't possible to read all data from this file", True)
226
                self.log.info("Backup file corrupted?")
227
            else:
228
                # Ask if the process should force an overwrite in target database
229
                question = "Should the import process overwrite data?"
230
                message = "All metadata for SAP Notes will be overwrited and annotations with the same identifier will be overwriten"
231
                wdialog = self.srvuif.message_dialog_question(question, message)
232
                response = wdialog.run()
233
                wdialog.destroy()
234
                if response == Gtk.ResponseType.YES:
235
                    overwrite = True
236
                else:
237
                    overwrite = False
238
 
239
 
240
                # Ask for final confirmation
241
                sncount, ancount, clcount = res
242
                question = "Restoring backup %s" % os.path.basename(backup)
243
                message = "\n%s contains:\n\n<b>%6d SAP Notes</b>\n<b>%6d collections</b>\n<b>%6d annotations</b>\n\n" % (os.path.basename(backup), sncount, clcount, ancount)
244
                message += "Do you still want to restore this backup?\n"
245
                wdialog = self.srvuif.message_dialog_question(question, message)
246
                response = wdialog.run()
247
                wdialog.destroy()
248
                if response == Gtk.ResponseType.YES:
249
                    self.srvbnr.restore_from_backup(backup, overwrite)
250
                    self.srvdtb.load_notes()
251
                    self.srvclt.load_collections()
252
                    visor_annotations.populate_annotations()
253
                    self.gui_refresh_view()
254
                    self.gui_show_visor_sapnotes()
255
                    self.srvuif.statusbar_msg("Backup restored successfully", True)
256
                    self.log.info("Backup restored successfully")
257
                elif response == Gtk.ResponseType.NO:
258
                    self.srvuif.statusbar_msg("Restore aborted by user", True)
259
                    self.log.info("Restore aborted")
260
        elif response == Gtk.ResponseType.CANCEL:
261
            self.srvuif.statusbar_msg("Restore aborted by user", True)
262
            self.log.info("Restore aborted")
263
 
264
        dialog.destroy()
265
        self.srvuif.grab_focus()
266
 
267
 
268
    def gui_show_about(self, *args):
269
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
270
        about = self.srvgui.get_widget('widget_about')
271
        stack = self.srvgui.get_widget('gtk_stack_main')
272
 
273
        stack.set_visible_child_name('about')
274
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
275
        self.srvuif.set_widget_visibility('gtk_label_total_notes', False)
276
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)
277
 
278
        notebook_menuview.hide()
279
        self.gui_annotation_widget_hide()
280
        about.grab_focus()
281
 
282
 
283
    def gui_show_log(self, *args):
284
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
285
        logviewer = self.srvgui.get_widget('widget_logviewer')
286
        stack = self.srvgui.get_widget('gtk_stack_main')
287
 
288
        logviewer.update()
289
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
290
        stack.set_visible_child_name('log')
291
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)
292
 
293
        notebook_menuview.hide()
294
        self.gui_annotation_widget_hide()
295
        logviewer.grab_focus()
296
        self.srvuif.statusbar_msg("Displaying application log")
297
 
298
 
299
    def gui_show_settings(self, button):
300
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
301
        stack = self.srvgui.get_widget('gtk_stack_main')
302
        view_settings = self.srvgui.get_widget('widget_settings')
303
 
304
        stack.set_visible_child_name('settings')
305
        view_settings.update()
306
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
307
        self.srvuif.set_widget_visibility('gtk_label_total_notes', False)
308
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)
309
 
310
        notebook_menuview.hide()
311
        self.gui_annotation_widget_hide()
312
        view_settings.grab_focus()
313
        self.srvuif.statusbar_msg("Displaying application settings")
314
 
315
 
316
    def gui_show_dashboard(self, *args):
317
        stack = self.srvgui.get_widget('gtk_stack_main')
318
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
319
        viewmenu = self.srvgui.get_widget('viewmenu')
320
        current_view = viewmenu.get_view()
321
 
322
        notebook_menuview.show_all()
323
        stack.set_visible_child_name('visor')
324
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
325
        self.srvuif.set_widget_visibility('gtk_button_dashboard', False)
326
 
327
        if current_view == 'annotation':
328
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
329
        else:
330
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
331
        self.srvuif.statusbar_msg("Displaying application dashboard")
332
 
333
 
334
    def gui_toggle_help_visor(self, *args):
335
        button = self.srvgui.get_widget('gtk_togglebutton_help')
336
        notebook = self.srvgui.get_widget('gtk_notebook_visor')
337
 
338
        if button.get_active():
339
            self.srvuif.set_widget_visibility('gtk_notebook_help_page', True)
340
            notebook.set_current_page(2)
341
        else:
342
            self.srvuif.set_widget_visibility('gtk_notebook_help_page', False)
343
            notebook.set_current_page(0)
344
        self.srvuif.statusbar_msg("Displaying application help")
345
 
346
 
347
    def gui_lauch_help_visor(self, *args):
348
        self.srvutl.browse("file://%s" % FILE['HELP_INDEX'])
349
 
350
 
351
    def gui_annotation_widget_show(self, widget, sid='0000000000', action='create'):
352
        widget_annotation = self.srvgui.get_widget('widget_annotation')
353 t00mlabs 353
        widget = self.srvgui.get_widget('gtk_label_timestamp_created')
340 t00mlabs 354
 
355
        if action == 'create':
356
            self.gui_annotation_widget_clear()
357
            aid = self.srvant.gen_aid(sid)
358
        elif action == 'edit':
359
            aid = sid
360
 
361 t00mlabs 361
        self.log.debug("AID: %s", aid)
340 t00mlabs 362
        widget_annotation.set_metadata_to_widget(aid, action)
363
 
364
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', True)
365
        widget.grab_focus()
366
 
367
 
368
    def gui_show_popover(self, button, popover):
369
        if popover.get_visible():
370
            popover.hide()
371
        else:
372
            popover.show_all()
373
 
374
 
375
    def switch_bookmark_current_view(self, *args):
376
        visor = self.srvgui.get_widget('visor_sapnotes')
377
        bag = visor.get_filtered_bag()
378
        try:
379
            for sid in bag:
380
                metadata = self.srvdtb.get_sapnote_metadata(sid)
381
                bookmark = metadata['bookmark']
382
                if bookmark:
383
                    self.sapnote_unbookmark([sid])
384
                else:
385
                    self.sapnote_bookmark([sid])
386
        except:
387
            self.log.error("Could not bookmark SAP Note %s" % sid)
388
            self.log.error(self.get_traceback())
389
        visor.populate_sapnotes(bag)
390
        msg = "%d SAP Notes (un)bookmarked" % len(bag)
391
        self.log.info(msg)
392
        self.srvuif.statusbar_msg(msg, True)
393
 
394
 
395
    def switch_bookmark(self, button, lsid, popover):
396
        visor = self.srvgui.get_widget('visor_sapnotes')
397
        try:
398
            for sid in lsid:
399
                metadata = self.srvdtb.get_sapnote_metadata(sid)
400
                bookmark = metadata['bookmark']
401
                if bookmark:
402
                    self.sapnote_unbookmark([sid])
403
                    self.srvuif.statusbar_msg("SAP Notes unbookmarked")
404
                else:
405
                    self.sapnote_bookmark([sid])
406
                    self.srvuif.statusbar_msg("SAP Notes bookmarked")
407
            popover.hide()
408
        except:
409
            self.log.error("Could not bookmark SAP Note %s" % sid)
410
            self.log.error(self.get_traceback())
411
        visor.populate_sapnotes()
412
 
413
 
414
    def sapnote_bookmark(self, lsid):
415
        self.srvdtb.set_bookmark(lsid)
416
 
417
 
418
    def sapnote_unbookmark(self, lsid):
419
        self.srvdtb.set_no_bookmark(lsid)
420
 
421
 
422
    def sapnote_import_from_launchpad(self, *args):
423
        db = self.get_service('DB')
424
        webdriver = self.get_service('Driver')
425
        textview = self.srvgui.get_widget('gtk_textview_download_launchpad')
426
        visor = self.srvgui.get_widget('visor_sapnotes')
427
 
428
        bag = []
429
        all_notes = []
430
        sapnotes = []
431
 
432
        dlbuffer = textview.get_buffer()
433
        istart, iend = dlbuffer.get_bounds()
434
        text = dlbuffer.get_text(istart, iend, False)
435
        lines = text.replace(' ', ',')
436
        lines = lines.replace('\n', ',')
437
        for sid in lines.split(','):
438
            sid = sid.strip()
439
            if len(sid) > 0:
440
                sapnotes.append(sid)
441
        for sid in sapnotes:
442
            is_valid = self.srvdtb.is_valid(sid)
443
            is_saved = self.srvdtb.get_sapnote_metadata(sid)
444
            if is_valid and not is_saved:
445
                bag.append(sid)
446
            if is_valid:
447
                all_notes.append(sid)
448
        lbag = list(bag)
449
        lbag.sort()
450
 
451
        if len(bag)> 0:
452
            driver = webdriver.open()
453
 
454
        winroot = self.srvgui.get_widget('gtk_app_window_main')
455
        msg = "%d SAP Notes to be downloaded: %s" % (len(bag), ', '.join(list(bag)))
456
        self.log.info(msg)
457
 
458
        result = {}
459
 
460
        self.srvsap.start_fetching(len(bag))
461
        dlbag = []
462
 
463
        # FIXME: max_workers = 1 = Threads disabled
464
        # Indeed, I think this is the best option right now.
465
        with Executor(max_workers=1) as exe:
466
            jobs = []
467
            for sapnote in lbag:
468
                job = exe.submit(self.srvsap.fetch, driver, sapnote)
469
                jobs.append(job)
470
 
471
            for job in jobs:
472
                rc, sapnote = job.result()
473
                msg = "\tRC SAP Note %s: %s" % (sapnote, rc)
474
                self.log.info(msg)
475
                result[sapnote] = rc
476
                if rc:
477
                    sid = "0"*(10 - len(sapnote)) + sapnote
478
                    dlbag.append(sid)
479
                time.sleep(0.2)
480
 
481
        dlbuffer.set_text('')
482
        popover = self.srvgui.get_widget('gtk_popover_toolbutton_import')
483
        self.gui_hide_popover(popover)
484
        if len(bag) > 0:
485
            webdriver.close(driver)
486
 
487
        self.srvsap.stop_fetching()
488
        db.save_notes()
489
        db.build_stats()
490
        self.log.info("Download completed.")
491
        self.srvuif.statusbar_msg("Download completed", True)
492
        visor.populate_sapnotes(all_notes)
493
        self.gui_show_visor_sapnotes()
494
        return result
495
 
496
 
497
    def expand_menuview(self):
498
        viewmenu = self.srvgui.get_widget('viewmenu')
499
        viewmenu.expand_all()
500
 
501
 
502
    def gui_viewmenu_filter(self, *args):
503
        entry = self.srvgui.get_widget('gtk_entry_filter_view')
504
        filter = entry.get_text()
505
        viewmenu = self.srvgui.get_widget('viewmenu')
506
        selection = viewmenu.get_selection()
507
 
508
        def gui_iterate_over_data(model, path, itr):
509
            rowkey = model.get(itr, 0)[0]
510
            rowtype, rowval = rowkey.split('@')
511
            dsc = model.get(itr, 1)[0]
512
            contents = model.get(itr, 1)[0]
513
            cleanstr = contents.replace('<b>', '')
514
            cleanstr = cleanstr.replace('</b>', '')
515
            model.set(itr, 1, '%s' % cleanstr)
516
            viewmenu.collapse_row(path)
517
 
518
            if len(filter) > 0:
519
                if filter.upper() in rowval.upper() or filter.upper() in dsc.upper():
520
                    viewmenu.expand_to_path (path)
521
                    selection.select_path(path)
522
                    model.set(itr, 1, '<b>%s</b>' % contents)
523
            else:
524
                return
525
 
526
        model = viewmenu.get_model()
527
        model.foreach(gui_iterate_over_data)
528
 
529
 
530
    def gui_viewmenu_select_first_entry(self):
531
        viewmenu = self.srvgui.get_widget('viewmenu')
532
        selection = viewmenu.get_selection()
533
        selection.select_path("0")
534
 
535
 
536
    def gui_filter_visor(self, entry):
537
        page = self.srvgui.get_key_value('current_visor_tab')
538
        if page == 0:
539
            visor = self.srvgui.get_widget('visor_sapnotes')
540
            visible_filter = visor.get_visible_filter()
541
            visible_filter.refilter()
542
            visor.update_total_sapnotes_count()
543
        elif page == 1:
544
            visor = self.srvgui.get_widget('visor_annotations')
545
            visor.populate_annotations()
546
            visible_filter = visor.get_visible_filter()
547
            visible_filter.refilter()
548
            visor.update_total_annotations_count()
549
 
550
 
551
    def gui_refresh_view(self, button=None, view=None):
552
        window = self.srvgui.get_widget('gtk_app_window_main')
553
        viewmenu = self.srvgui.get_widget('viewmenu')
554
        if view is None:
555
            view = viewmenu.get_view()
556
 
557
        if view is not None:
558
            viewlabel = self.srvgui.get_widget('gtk_label_current_view')
559
            name = "<b>%-10s</b>" % view.capitalize()
560
            viewlabel.set_markup(name)
561
        viewmenu.set_view(view)
562
        popover = self.srvgui.get_widget('gtk_popover_button_menu_views')
563
        popover.hide()
564
        self.gui_show_visor_sapnotes()
565
 
566
 
567
    def gui_toggle_menu_view(self, obj):
568
        paned = self.srvgui.get_widget('gtk_vbox_container_menu_view')
569
        button = self.srvgui.get_widget('gtk_toogletoolbutton_menu_view')
570
        if isinstance(obj, Gtk.ToggleToolButton):
571
            if button.get_active():
572
                paned.show_all()
573
            else:
574
                paned.hide()
575
        elif isinstance(obj, bool):
576
            if obj == True:
577
                button.set_active(True)
578
            else:
579
                button.set_active(False)
580
 
581
 
582
    def gui_toggle_fullscreen(self, button):
583
        icon_container = self.srvgui.get_widget('gtk_box_container_icon_fullscreen')
584
        icon_fullscreen = self.srvicm.get_new_image_icon('basico-fullscreen', 24, 24)
585
        icon_unfullscreen = self.srvicm.get_new_image_icon('basico-unfullscreen', 24, 24)
586
        active = button.get_active()
587
        window = self.srvgui.get_window()
588
        if active:
589
            self.srvgui.swap_widget(icon_container, icon_unfullscreen)
590
            window.fullscreen()
591
        else:
592
            self.srvgui.swap_widget(icon_container, icon_fullscreen)
593
            window.unfullscreen()
594
 
595
 
596
    def action_annotation_edit(self, aid):
597
        self.gui_annotation_widget_show(None, aid, 'edit')
598
 
599
 
600
    def action_annotation_duplicate(self, *args):
601
        self.log.debug("ACTION-DUPLICATE: %s" % args)
602
 
603
 
604
    def action_annotation_delete(self, *args):
605
        visor = self.srvgui.get_widget('visor_annotations')
606
        widget_annotation = self.srvgui.get_widget('widget_annotation')
607
        aid = widget_annotation.get_aid_from_widget()
608
 
609
        answer = self.srvuif.warning_message_delete_annotations(None, 'Deleting annotations', 'Are you sure?', [aid])
610
        if answer is True:
611
            title = self.srvant.get_title(aid)
612
            self.srvant.delete(aid)
613
            self.gui_annotation_widget_clear()
614
            self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
615
            visor.populate_annotations()
616
            self.srvuif.statusbar_msg("Annotation <i>'%s'</i> deleted" % title, True)
617
        else:
618
            self.log.info("Annotation %s hasn't been deleted" % title)
619
            self.srvuif.statusbar_msg("Action canceled. Nothing deleted.", True)
620
 
621
        self.srvuif.grab_focus()
622
 
623
 
624
    def action_annotation_accept(self, button, sid):
625
        widget_annotation = self.srvgui.get_widget('widget_annotation')
626
        visor_annotations = self.srvgui.get_widget('visor_annotations')
627
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
628
        viewmenu = self.srvgui.get_widget('viewmenu')
629
 
630
        aid = widget_annotation.get_aid_from_widget()
351 t00mlabs 631
        annotation = widget_annotation.get_metadata_from_widget()
340 t00mlabs 632
 
633
        if self.srvant.is_valid(aid):
634
            self.srvant.update(annotation)
635
            title = self.srvant.get_title(aid)
636
            self.srvuif.statusbar_msg("Updated annotation: %s" % title, True)
637
        else:
638
            self.srvant.create(annotation)
639
            title = self.srvant.get_title(aid)
640
            self.srvuif.statusbar_msg('New annotation created: %s' % title, True)
641
        visor_annotations.populate_annotations()
642
        visor_sapnotes.populate_sapnotes()
643
        self.gui_annotation_widget_clear()
644
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
645
        self.srvuif.grab_focus()
646
 
647
 
648
    def action_annotation_cancel(self, *args):
649
        statusbar = self.srvgui.get_widget('widget_statusbar')
650
        self.gui_annotation_widget_clear()
651
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
350 t00mlabs 652
        button = self.srvgui.get_widget('gtk_togglebutton_maximize_annotation_widget')
653
        button.set_active(False)
340 t00mlabs 654
        self.log.debug('Annotation canceled')
655
        self.srvuif.statusbar_msg("Annotation canceled")
656
        self.srvuif.grab_focus()
657
 
658
 
659
    def get_sapnotes_from_current_view(self, colname=None):
660
        viewmenu = self.srvgui.get_widget('viewmenu')
661
        view = viewmenu.get_view()
662
        rowtype = viewmenu.get_row_type()
663
        rowid = viewmenu.get_row_id()
664
 
665
        if view == 'collection':
666
            cols = self.srvclt.get_collections_by_row_title(colname)
667
            bag = []
668
            for colid in cols:
669
                bag.extend(self.srvdtb.get_notes_by_node('collection', colid))
670
        else:
671
            bag = self.srvdtb.get_notes_by_node(rowtype, rowid)
672
 
673
        return bag
674
 
675
 
676
    def action_collection_export_text_csv(self, *args):
677
        rootwin = self.srvgui.get_window()
678
        timestamp = self.srvutl.timestamp()
679
        filename = "%s%s.csv" % (LPATH['EXPORT'], timestamp)
680
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
681
 
682
        bag = visor_sapnotes.get_filtered_bag()
683
 
684
        dialog = Gtk.FileChooserDialog("Save file", rootwin,
685
            Gtk.FileChooserAction.SAVE,
686
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
687
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
688
        dialog.set_filename(filename)
689
        dialog.set_current_name(os.path.basename(filename))
690
        response = dialog.run()
691
 
692
        if response == Gtk.ResponseType.OK:
693
            export_path = dialog.get_filename()
694
            res = self.srvbnr.export_to_text_csv(bag, export_path)
695
            self.log.info("%d SAP Notes exported to CSV format: %s", len(bag), export_path)
696
            self.srvuif.statusbar_msg("%d SAP Notes exported to CSV format: %s" % (len(bag), export_path), True)
697
            self.srvuif.copy_text_to_clipboard(export_path)
698
        else:
699
            self.log.info("Export canceled by user")
700
            self.srvuif.statusbar_msg("Export canceled by user", True)
701
        dialog.destroy()
702
 
703
 
704
    def action_collection_export_excel(self, *args):
705
        rootwin = self.srvgui.get_window()
706
        timestamp = self.srvutl.timestamp()
707
        filename = "%s%s.xlsx" % (LPATH['EXPORT'], timestamp)
708
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
709
 
710
        bag = visor_sapnotes.get_filtered_bag()
711
 
712
        dialog = Gtk.FileChooserDialog("Save file", rootwin,
713
            Gtk.FileChooserAction.SAVE,
714
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
715
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
716
        dialog.set_filename(filename)
717
        dialog.set_current_name(os.path.basename(filename))
718
        response = dialog.run()
719
 
720
        if response == Gtk.ResponseType.OK:
721
            export_path = dialog.get_filename()
722
            res = self.srvbnr.export_to_excel(bag, export_path)
723
            if res:
724
                self.log.info("Selected SAP Notes exported to MS Excel format (xlsx): %s" % export_path)
725
                self.srvuif.statusbar_msg("%d SAP Notes exported to MS Excel format: %s" % (len(bag), export_path), True)
726
                self.srvuif.copy_text_to_clipboard(export_path)
727
            else:
728
                self.log.error(self.get_traceback())
729
        else:
730
            self.log.info("Export canceled by user")
731
            self.srvuif.statusbar_msg("Export canceled by user", True)
732
        dialog.destroy()
733
 
734
 
735
    def action_collection_export_basico(self, *args):
736
        rootwin = self.srvgui.get_window()
737
        timestamp = self.srvutl.timestamp()
738
        filename = "%s%s.bco" % (LPATH['EXPORT'], timestamp)
739
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
740
 
741
        bag = visor_sapnotes.get_filtered_bag()
742
 
743
        dialog = Gtk.FileChooserDialog("Save file", rootwin,
744
            Gtk.FileChooserAction.SAVE,
745
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
746
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
747
        dialog.set_filename(filename)
748
        dialog.set_current_name(os.path.basename(filename))
749
        response = dialog.run()
750
 
751
        if response == Gtk.ResponseType.OK:
752
            export_path = dialog.get_filename()
753
            target = self.srvbnr.export_to_basico(bag, export_path)
754
            self.log.info("%d SAP Notes exported to Basico %s format: %s", len(bag), APP['version'], target)
755
            self.srvuif.statusbar_msg("%d SAP Notes exported to Basico %s format: %s" % (len(bag), APP['version'], target), True)
756
            self.srvuif.copy_text_to_clipboard(export_path)
757
        else:
758
            self.log.info("Export canceled by user")
759
            self.srvuif.statusbar_msg("Export canceled by user", True)
760
        dialog.destroy()
761
 
762
 
763
    def action_collection_copy_to_clipboard(self, button):
764
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
765
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
766
 
767
        bag = visor_sapnotes.get_filtered_bag()
768
        text = ''
769
        for sid in bag:
770
            metadata = self.srvdtb.get_sapnote_metadata(sid)
771
            text += "SAP Note %s: %s - Component: %s\n" % (str(int(sid)), metadata['title'], metadata['componentkey'])
772
        clipboard.set_text(text, -1)
773
 
774
        msg = "%d SAP Notes copied to the clipboard: %s" % (len(bag), ', '.join(list(bag)))
775
        self.log.info(msg)
776
        msg = "%d SAP Notes copied to the clipboard" % len(bag)
777
        self.srvuif.statusbar_msg(msg, True)
778
 
779
 
780
    def gui_annotation_widget_clear(self):
781
        a_wdg_timestamp = self.srvgui.get_widget('gtk_label_human_timestamp')
354 t00mlabs 782
        a_wdg_timestamp_created = self.srvgui.get_widget('gtk_label_timestamp_created')
340 t00mlabs 783
        a_wdg_title = self.srvgui.get_widget('gtk_entry_annotation_title')
784
        a_wdg_type = self.srvgui.get_widget('gtk_combobox_annotation_type')
785
        a_wdg_text = self.srvgui.get_widget('gtk_textview_annotation_text')
786
        a_wdg_link = self.srvgui.get_widget('gtk_entry_annotation_link')
787
        a_wdg_link_button = self.srvgui.get_widget('gtk_link_button_annotation_link')
788
        a_wdg_link_type = self.srvgui.get_widget('gtk_combobox_annotation_link_type')
789
 
790
        a_wdg_timestamp.set_text('')
354 t00mlabs 791
        a_wdg_timestamp_created.set_text('')
340 t00mlabs 792
        a_wdg_title.set_text('')
793
        textbuffer = a_wdg_text.get_buffer()
794
        textbuffer.set_text('')
795
        a_wdg_link.set_text('')
796
        a_wdg_link_button.set_uri('')
797
        self.gui_annotation_widget_hide()
798
 
799
 
800
    def gui_annotation_widget_hide(self):
801
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
802
 
803
 
804
    def gui_copy_to_clipboard_sapnote(self, widget, lsid, popover):
805
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
806
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
807
        text = ''
808
        for sid in lsid:
809
            metadata = self.srvdtb.get_sapnote_metadata(sid)
810
            text += "SAP Note %10s: %s - Component: %s\n" % (sid, metadata['title'], metadata['componentkey'])
811
        clipboard.set_text(text, -1)
812
        if popover is not None:
813
            popover.hide()
814
            self.srvuif.grab_focus()
815
 
816
 
817
    def gui_jump_to_sapnote(self, widget, sid):
818
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
819
        visor_sapnotes.populate_sapnotes([sid])
820
        self.gui_show_visor_sapnotes()
821
        self.srvuif.grab_focus()
822
        msg = "Jumping to SAP Note %s" % sid
823
        self.log.info(msg)
824
        self.srvuif.statusbar_msg(msg)
825
 
826
 
827
    def gui_link_to_sapnote(self, *args):
828
        pass
829
 
830
    def gui_switch_selection_atypes(self, switch, state):
831
        label = self.srvgui.get_widget('gtk_label_switch_select_atypes')
832
        switched = switch.get_active()
833
        switch.set_state(switched)
834
        if switched is True:
835
            label.set_text ("All selected")
836
 
837
        else:
838
            label.set_text("None selected")
839
 
840
        for name in ATYPES:
841
            button = self.srvgui.get_widget('gtk_button_type_%s' % name.lower())
842
            button.set_state(switched)
843
            button.set_active(switched)
844
 
845
 
846
    def gui_sapnotes_select_all_none(self, witch, state):
847
        visor = self.srvgui.get_widget('visor_sapnotes')
848
        model = visor.get_model()
849
 
850
        def get_selected_sapnotes(model, path, itr):
851
            component = model.get(itr, 5)
852
            if component != 'Annotation':
853
                model.set(itr, 2, state)
854
 
855
        model.foreach(get_selected_sapnotes)
348 t00mlabs 856
 
857
 
858
    def gui_maximize_annotation_window(self, *args):
352 t00mlabs 859
        vpaned = self.srvgui.get_widget('gtk_vpaned_visor')
348 t00mlabs 860
        stack_main = self.srvgui.get_widget('gtk_stack_main')
861
        toggle_button = self.srvgui.get_widget('gtk_togglebutton_maximize_annotation_widget')
862
        if toggle_button.get_active():
352 t00mlabs 863
            # ~ stack_main.hide()
864
            vpaned.set_position(0)
348 t00mlabs 865
        else:
352 t00mlabs 866
            # ~ stack_main.show_all()
361 t00mlabs 867
            vpaned.set_position(450)
356 t00mlabs 868
 
869
 
360 t00mlabs 870
    def gui_attachment_add_to_sapnote(self, button, sid):
871
        visor_attachemnts = self.srvgui.get_widget('visor_attachments')
872
        visor_annotations = self.srvgui.get_widget('visor_annotations')
873
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
874
 
875
        # Create annotation
876
        aid = self.srvant.gen_aid(sid)
877
        annotation = {}
878
        annotation["AID"] = aid
879
        annotation["Title"] = "Attachments added for SAP Note %s" % str(int(sid))
880
        annotation["Component"] = "Annotation"
881
        annotation["Type"] = "Note"
882
        annotation["Category"] = "Inbox"
883
        annotation["Priority"] = "Low"
884
        annotation["Link"] = ""
885
        annotation["LinkType"] = "Website"
886
        annotation["Origin"] = "Service-Attachment"
887
 
888
        # Get attachments from filechooser dialog
889
        attachments = self.gui_attachment_show_filechooser()
890
 
891
        # Add them to Basico database
892
        if attachments is not None:
893
            content = '== Attachments\n\n'
894
            for attachment in attachments:
895
                # only allow files (avoid directories)
896
                if os.path.isfile(attachment):
897
                    content += "* %s\n" % attachment
898
                    tid = self.srvatc.create(attachment, aid)
899
                    annotation["TID"] = tid
900
                    # ~ self.log.debug(annotation)
901
                annotation["Content"] = content
902
                self.srvant.create(annotation)
903
            visor_attachemnts.populate_attachments()
904
            visor_annotations.populate_annotations()
905
            visor_sapnotes.populate_sapnotes()
906
        else:
907
            self.log.warning("No files selected to attach")
908
 
909
 
910
    def gui_attachment_add_to_annotation(self, button):
911
        visor_attachemnts = self.srvgui.get_widget('visor_attachments')
912
        visor_annotations = self.srvgui.get_widget('visor_annotations')
356 t00mlabs 913
        aid = widget_annotation.get_aid_from_widget()
360 t00mlabs 914
 
915
        # Create annotation
916
        sid = self.srvant.get_sid(aid)
917
        new_aid = self.srvant.gen_aid(sid)
918
        annotation = {}
919
        annotation["AID"] = new_aid
920
        annotation["Title"] = "Attachments added for annotation: %s" % self.srvant.get_title(aid)
921
        annotation["Component"] = "Annotation"
922
        annotation["Type"] = "Note"
923
        annotation["Category"] = "Inbox"
924
        annotation["Priority"] = "Low"
925
        annotation["Link"] = ""
926
        annotation["LinkType"] = "Website"
927
        annotation["Origin"] = "Service-Attachment"
928
 
929
        # Get attachments from filechooser dialog
356 t00mlabs 930
        attachments = self.gui_attachment_show_filechooser()
931
 
932
        # Add them to Basico database
933
        if attachments is not None:
360 t00mlabs 934
            content = '== Attachments\n\n'
356 t00mlabs 935
            for attachment in attachments:
936
                # only allow files (avoid directories)
937
                if os.path.isfile(attachment):
360 t00mlabs 938
                    content += "* %s\n" % attachment
939
                    tid = self.srvatc.create(attachment, aid)
940
                    annotation["TID"] = tid
941
                    # ~ self.log.debug(annotation)
942
                annotation["Content"] = content
943
                self.srvant.create(annotation)
944
                self.srvant.update_timestamp(aid)
945
            visor_attachemnts.populate_attachments()
946
            visor_annotations.populate_annotations()
356 t00mlabs 947
        else:
948
            self.log.warning("No files selected to attach")
360 t00mlabs 949
 
950
 
951
    def gui_attachment_add(self, button):
952
        visor_attachemnts = self.srvgui.get_widget('visor_attachments')
953
        visor_annotations = self.srvgui.get_widget('visor_annotations')
954
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
955
 
956
        # Create annotation
957
        aid = self.srvant.gen_aid('0000000000')
958
        annotation = {}
959
        annotation["AID"] = aid
960
        annotation["Title"] = "Attachments added"
961
        annotation["Component"] = "Annotation"
962
        annotation["Type"] = "Note"
963
        annotation["Category"] = "Inbox"
964
        annotation["Priority"] = "Low"
965
        annotation["Link"] = ""
966
        annotation["LinkType"] = "Website"
967
        annotation["Origin"] = "Service-Attachment"
968
 
969
        # Get attachments from filechooser dialog
970
        attachments = self.gui_attachment_show_filechooser()
971
 
972
        # Add them to Basico database
973
        if attachments is not None:
974
            content = '== Attachments\n\n'
975
            for attachment in attachments:
976
                # only allow files (avoid directories)
977
                if os.path.isfile(attachment):
978
                    content += "* %s\n" % attachment
979
                    tid = self.srvatc.create(attachment, aid)
980
                    annotation["TID"] = tid
981
                    # ~ self.log.debug(annotation)
982
                annotation["Content"] = content
983
                self.srvant.create(annotation)
984
            visor_attachemnts.populate_attachments()
985
            visor_annotations.populate_annotations()
986
        else:
987
            self.log.warning("No files selected to attach")
356 t00mlabs 988
 
989
    def gui_attachment_show_filechooser(self):
990
        filenames = None
991
        parentwin = self.srvgui.get_window()
992
        dialog = Gtk.FileChooserDialog(title="Open file(s) ...",
993
                                       parent=parentwin,
994
                                       action=Gtk.FileChooserAction.OPEN,
995
                                       buttons=("_Cancel",
996
                                                Gtk.ResponseType.CANCEL,
997
                                        "_Open", Gtk.ResponseType.ACCEPT))
998
        dialog.set_select_multiple(True)
999
        response = dialog.run()
1000
        if response == Gtk.ResponseType.ACCEPT:
1001
            filenames = dialog.get_filenames()
1002
            i = 0
1003
            while i < len(filenames):
1004
                filename = filenames[i]
1005
                self.log.debug("%s was selected", filename)
1006
                i += 1
1007
        dialog.destroy()
1008
        return filenames
1009