Subversion Repositories basico

Rev

Rev 276 | Rev 278 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
# File: srv_cb.py
# Author: Tomás Vírseda
# License: GPL v3
# Description: UI and related callbacks service
"""


import os
import json
import time
from concurrent.futures import ThreadPoolExecutor as Executor

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

from basico.core.mod_srv import Service
from basico.core.mod_env import FILE, LPATH
from basico.widgets.wdg_visor_sapnotes import SAPNotesVisor
from basico.widgets.wdg_visor_toolbar import VisorToolbar
from basico.widgets.wdg_cols import CollectionsMgtView
from basico.widgets.wdg_settingsview import SettingsView

# PROPKEYS = CSV headers. SAP Note metadata
PROPKEYS = ['id', 'title', 'type', 'componentkey',
            'componenttxt', 'category', 'priority', 'releaseon',
            'language', 'version']

# Extend PROPKEYS with custom basico metadata
PROPKEYS.extend (['Bookmark'])

class Callback(Service):
    def initialize(self):
        self.get_services()

    def get_services(self):
        self.srvstg = self.app.get_service('Settings')
        self.srvdtb = self.app.get_service('DB')
        self.srvgui = self.app.get_service('GUI')
        self.srvuif = self.app.get_service("UIF")
        self.srvsap = self.app.get_service('SAP')
        self.srvicm = self.app.get_service('IM')
        self.srvutl = self.app.get_service('Utils')
        self.srvant = self.app.get_service('Annotation')
        self.srvbnr = self.get_service('BNR')


    def gui_visor_switch_page(self, notebook, page, page_num):
        # 0|1|(2) -> SAP Notes Visor | Annotations Visor | (Help)
        self.srvgui.set_key_value('current_visor_tab', page_num)
        notebook_viewmenu = self.srvgui.get_widget('gtk_notebook_menuview')

        if page_num == 0:
            self.srvuif.set_widget_visibility('gtk_button_menu_views', True)
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
            visor = self.srvgui.get_widget('visor_sapnotes')
            visible_filter = visor.get_visible_filter()
            visor.update_total_sapnotes_count(len(visible_filter))
            notebook_viewmenu.set_current_page(0)
        elif page_num == 1:
            self.srvuif.set_widget_visibility('gtk_button_menu_views', False)
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
            visor = self.srvgui.get_widget('visor_annotations')
            visor.update_total_annotations_count()
            notebook_viewmenu.set_current_page(1)


    def gui_show_visor_sapnotes(self):
        notebook = self.srvgui.get_widget('gtk_notebook_visor')
        notebook.set_current_page(0)


    def gui_show_visor_annotations(self):
        notebook = self.srvgui.get_widget('gtk_notebook_visor')
        notebook.set_current_page(1)


    def action_search(self, entry):
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
        visor_annotations = self.srvgui.get_widget('visor_annotations')
        term = entry.get_text()
        page = self.srvgui.get_key_value('current_visor_tab')
        completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
        completion_model = completion.get_model()
        completion_model.clear()

        if page == 0:
            bag = self.srvdtb.search(term)
            visor_sapnotes.populate_sapnotes(bag)
        elif page == 1:
            annotations = self.srvant.search_term(term)
            visor_annotations.populate_annotations(annotations)

        ebuffer = entry.get_buffer()
        ebuffer.delete_text(0, -1)


    def sapnote_browse(self, button, sid):
        self.debug("Browsing SAP Note %d" % int(sid))
        SAP_NOTE_URL = self.srvstg.get('SAP', 'SAP_NOTE_URL')
        url = SAP_NOTE_URL % sid
        self.srvutl.browse(url)
        # ~ popover = self.srvgui.get_widget('poprowsid')
        # ~ popover.hide()


    def sapnote_delete(self, button, lsid):
        visor = self.srvgui.get_widget('visor_sapnotes')
        viewmenu = self.srvgui.get_widget('viewmenu')
        model = visor.get_sorted_model()
        bag = []

        def get_selected_sapnotes(model, path, itr):
            checked = model.get(itr, 2)[0]
            if checked:
                sid = model.get(itr, 0)[0]
                bag.append(sid)

        model.foreach(get_selected_sapnotes)
        bag.sort()
        if len(bag) > 0:
            answer = self.srvuif.warning_message(button, 'Deleting SAP Notes', 'Are you sure?', bag)
            if answer is True:
                for sid in bag:
                    self.srvdtb.delete(sid)
                visor.reload()
            else:
                self.debug("Nothing deleted")


    def gui_hide_popover(self, popover):
        popover.hide()


    def gui_show_filechooser_restore(self, *args):
        window = self.srvgui.get_window()
        dialog = Gtk.FileChooserDialog("Please choose a backup file", window,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_current_folder(LPATH['BACKUP'])
        # ~ extra_widget = dialog.get_extra_widget()
        filter_zip = Gtk.FileFilter()
        filter_zip.set_name("Basico backup files")
        filter_zip.add_pattern("*.zip")
        dialog.add_filter(filter_zip)
        # ~ extra_widget.grab_focus()

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            backup = dialog.get_filename()
            sncount, ancount = self.srvbnr.test(backup)
            question = "Restoring backup %s" % os.path.basename(backup)
            message = "%s contains:\n\n%6d SAP Notes\n%6d annotations\n\n" % (os.path.basename(backup), sncount, ancount)
            message += "Do you still want to restore this backup?\n"
            message += "Previous database will be deleted (merge operation is not supported yet)"
            wdialog = self.srvuif.warning_message_default(question, message)
            response = wdialog.run()
            if response == Gtk.ResponseType.YES:
                answer = True
            elif response == Gtk.ResponseType.NO:
                self.srvbnr.restore(backup)
            self.debug("Answer: %s" % answer)
            wdialog.destroy()
        elif response == Gtk.ResponseType.CANCEL:
            self.debug("Aborting restore.")

        dialog.destroy()


    def gui_show_about(self, *args):
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
        self.debug(notebook_menuview)
        about = self.srvgui.get_widget('widget_about')
        stack = self.srvgui.get_widget('gtk_stack_main')

        stack.set_visible_child_name('about')
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
        self.srvuif.set_widget_visibility('gtk_label_total_notes', False)
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)

        notebook_menuview.hide()
        self.gui_annotation_widget_hide()
        about.grab_focus()


    def gui_show_log(self, *args):
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
        logviewer = self.srvgui.get_widget('widget_logviewer')
        stack = self.srvgui.get_widget('gtk_stack_main')

        logviewer.update()
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
        stack.set_visible_child_name('log')
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)

        notebook_menuview.hide()
        self.gui_annotation_widget_hide()
        logviewer.grab_focus()


    def gui_show_settings(self, button):
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
        stack = self.srvgui.get_widget('gtk_stack_main')
        view_settings = self.srvgui.get_widget('widget_settings')

        stack.set_visible_child_name('settings')
        view_settings.update()
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
        self.srvuif.set_widget_visibility('gtk_label_total_notes', False)
        self.srvuif.set_widget_visibility('gtk_button_dashboard', True)

        notebook_menuview.hide()
        self.gui_annotation_widget_hide()
        view_settings.grab_focus()


    def gui_show_dashboard(self, *args):
        stack = self.srvgui.get_widget('gtk_stack_main')
        notebook_menuview = self.srvgui.get_widget('gtk_notebook_menuview')
        viewmenu = self.srvgui.get_widget('viewmenu')
        current_view = viewmenu.get_view()

        notebook_menuview.show_all()
        stack.set_visible_child_name('visor')
        self.gui_hide_popover(self.srvgui.get_widget('gtk_popover_button_menu_system'))
        self.srvuif.set_widget_visibility('gtk_button_dashboard', False)

        if current_view == 'annotation':
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)
        else:
            self.srvuif.set_widget_visibility('gtk_label_total_notes', True)


    def gui_toggle_help_visor(self, *args):
        button = self.srvgui.get_widget('gtk_togglebutton_help')
        notebook = self.srvgui.get_widget('gtk_notebook_visor')

        if button.get_active():
            self.srvuif.set_widget_visibility('gtk_notebook_help_page', True)
            notebook.set_current_page(2)
        else:
            self.srvuif.set_widget_visibility('gtk_notebook_help_page', False)
            notebook.set_current_page(0)

    def gui_lauch_help_visor(self, *args):
        self.srvutl.browse("file://%s" % FILE['HELP_INDEX'])

    def gui_annotation_widget_show(self, widget, sid='0000000000', action='create'):
        widget_annotation = self.srvgui.get_widget('widget_annotation')
        widget = self.srvgui.get_widget('gtk_label_annotation_sid')


        if action == 'create':
            self.gui_annotation_widget_clear()
            aid = self.srvant.gen_aid(sid)
        elif action == 'edit':
            aid = sid

        widget_annotation.set_metadata_to_widget(aid, action)
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', True)
        widget.grab_focus()


    def gui_show_popover(self, button, popover):
        if popover.get_visible():
            popover.hide()
        else:
            popover.show_all()


    def switch_bookmark_current_set(self, button, popover):
        visor = self.srvgui.get_widget('visor_sapnotes')
        bag = visor.get_bag()
        try:
            for sid in bag:
                metadata = self.srvdtb.get_sapnote_metadata(sid)
                bookmark = metadata['bookmark']
                if bookmark:
                    self.sapnote_unbookmark([sid])
                else:
                    self.sapnote_bookmark([sid])
            popover.hide()
        except:
            self.debug("Could not bookmark SAP Note %s" % sid)
        visor.populate_sapnotes()


    def switch_bookmark(self, button, lsid, popover):
        visor = self.srvgui.get_widget('visor_sapnotes')
        try:
            for sid in lsid:
                metadata = self.srvdtb.get_sapnote_metadata(sid)
                bookmark = metadata['bookmark']
                if bookmark:
                    self.sapnote_unbookmark([sid])
                else:
                    self.sapnote_bookmark([sid])
            popover.hide()
        except:
            self.debug("Could not bookmark SAP Note %s" % sid)
        visor.populate_sapnotes()

    def sapnote_bookmark(self, lsid):
        self.srvdtb.set_bookmark(lsid)


    def sapnote_unbookmark(self, lsid):
        self.srvdtb.set_no_bookmark(lsid)


    def sapnote_import_from_launchpad(self, *args):
        db = self.get_service('DB')
        webdriver = self.get_service('Driver')
        textview = self.srvgui.get_widget('gtk_textview_download_launchpad')
        visor = self.srvgui.get_widget('visor_sapnotes')

        bag = []
        all_notes = []
        sapnotes = []

        dlbuffer = textview.get_buffer()
        istart, iend = dlbuffer.get_bounds()
        text = dlbuffer.get_text(istart, iend, False)
        lines = text.replace(' ', ',')
        lines = lines.replace('\n', ',')
        for sid in lines.split(','):
            sid = sid.strip()
            if len(sid) > 0:
                sapnotes.append(sid)
        for sid in sapnotes:
            is_valid = self.srvdtb.is_valid(sid)
            is_saved = self.srvdtb.get_sapnote_metadata(sid)
            if is_valid and not is_saved:
                bag.append(sid)
            if is_valid:
                all_notes.append(sid)
        lbag = list(bag)
        lbag.sort()

        if len(bag)> 0:
            driver = webdriver.open()

        winroot = self.srvgui.get_widget('gtk_app_window_main')
        self.debug("%d SAP Notes to be downloaded: %s" % (len(bag), ', '.join(list(bag))))

        result = {}

        self.srvsap.start_fetching(len(bag))
        dlbag = []

        # FIXME: max_workers = 1 = Threads disabled
        # Indeed, I think this is the best option right now.
        with Executor(max_workers=1) as exe:
            jobs = []
            for sapnote in lbag:
                job = exe.submit(self.srvsap.fetch, driver, sapnote)
                jobs.append(job)

            for job in jobs:
                rc, sapnote = job.result()
                self.debug("\tRC SAP Note %s: %s" % (sapnote, rc))
                result[sapnote] = rc
                if rc:
                    sid = "0"*(10 - len(sapnote)) + sapnote
                    dlbag.append(sid)
                time.sleep(0.2)

        dlbuffer.set_text('')
        popover = self.srvgui.get_widget('gtk_popover_toolbutton_import')
        self.gui_hide_popover(popover)
        if len(bag) > 0:
            webdriver.close(driver)

        self.srvsap.stop_fetching()
        db.save_notes()
        db.build_stats()
        self.debug("Collection completed.")
        # ~ self.gui_display_visor
        # ~ viewmenu = self.srvgui.get_widget('viewmenu')
        # ~ viewmenu.row_changed(None)
        visor.populate_sapnotes(all_notes)
        self.gui_show_visor_sapnotes()
        return result


    def expand_menuview(self):
        viewmenu = self.srvgui.get_widget('viewmenu')
        viewmenu.expand_all()


    def gui_viewmenu_filter(self, *args):
        entry = self.srvgui.get_widget('gtk_entry_filter_view')
        filter = entry.get_text()
        viewmenu = self.srvgui.get_widget('viewmenu')
        selection = viewmenu.get_selection()

        def gui_iterate_over_data(model, path, itr):
            rowkey = model.get(itr, 0)[0]
            rowtype, rowval = rowkey.split('@')
            dsc = model.get(itr, 3)[0]
            contents = model.get(itr, 3)[0]
            cleanstr = contents.replace('<b>', '')
            cleanstr = cleanstr.replace('</b>', '')
            model.set(itr, 3, '%s' % cleanstr)
            viewmenu.collapse_row(path)

            if len(filter) > 0:
                if filter.upper() in rowval.upper() or filter.upper() in dsc.upper():
                    viewmenu.expand_to_path (path)
                    selection.select_path(path)
                    model.set(itr, 3, '<b>%s</b>' % contents)
            else:
                return

        model = viewmenu.get_model()
        model.foreach(gui_iterate_over_data)


    def gui_filter_visor(self, entry):
        page = self.srvgui.get_key_value('current_visor_tab')
        if page == 0:
            visor = self.srvgui.get_widget('visor_sapnotes')
            visible_filter = visor.get_visible_filter()
            visible_filter.refilter()
            visor.update_total_sapnotes_count(len(visible_filter))
        elif page == 1:
            visor = self.srvgui.get_widget('visor_annotations')
            visible_filter = visor.get_visible_filter()
            visible_filter.refilter()
            visor.update_total_annotations_count()


    def gui_filter_visor_annotations(self, entry):
        visor = self.srvgui.get_widget('visor_annotations')
        self.debug(visor)
        visible_filter = visor.get_visible_filter()
        visible_filter.refilter()
        visor.update_total_sapnotes_count(len(visible_filter))


    def gui_refresh_view(self, button, view=None):
        window = self.srvgui.get_widget('gtk_app_window_main')
        viewmenu = self.srvgui.get_widget('viewmenu')
        if view is None:
            view = viewmenu.get_view()

        if view is not None:
            viewlabel = self.srvgui.get_widget('gtk_label_current_view')
            name = "<b>%-10s</b>" % view.capitalize()
            viewlabel.set_markup(name)
        viewmenu.set_view(view)
        popover = self.srvgui.get_widget('gtk_popover_button_menu_views')
        popover.hide()
        self.gui_show_visor_sapnotes()


    def gui_toggle_menu_view(self, obj):
        paned = self.srvgui.get_widget('gtk_vbox_container_menu_view')
        button = self.srvgui.get_widget('gtk_toogletoolbutton_menu_view')
        self.debug("menuview_togglebutton(%s)(%s)" % (button, type(button)))
        if isinstance(obj, Gtk.ToggleToolButton):
            if button.get_active():
                paned.show_all()
            else:
                paned.hide()
        elif isinstance(obj, bool):
            if obj == True:
                # ~ paned.show_all()
                button.set_active(True)
            else:
                # ~ paned.hide()
                button.set_active(False)


    def gui_toggle_fullscreen(self, button):
        icon_container = self.srvgui.get_widget('gtk_box_container_icon_fullscreen')
        icon_fullscreen = self.srvicm.get_new_image_icon('basico-fullscreen', 24, 24)
        icon_unfullscreen = self.srvicm.get_new_image_icon('basico-unfullscreen', 24, 24)
        active = button.get_active()
        ui = self.srvgui.get_window()
        window = ui.get_window()
        if active:
            self.srvgui.swap_widget(icon_container, icon_unfullscreen)
            window.fullscreen()
        else:
            self.srvgui.swap_widget(icon_container, icon_fullscreen)
            window.unfullscreen()


    def action_annotation_edit(self, aid):
        self.gui_annotation_widget_show(None, aid, 'edit')


    def action_annotation_duplicate(self, *args):
        self.debug("ACTION-DUPLICATE: %s" % args)


    def action_annotation_delete(self, *args):
        statusbar = self.srvgui.get_widget('widget_statusbar')
        visor = self.srvgui.get_widget('visor_annotations')
        widget_annotation = self.srvgui.get_widget('widget_annotation')
        aid = widget_annotation.get_aid_from_widget()
        self.srvant.delete(aid)
        self.gui_annotation_widget_clear()
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
        visor.populate_annotations()


    def action_annotation_accept(self, button, sid):
        statusbar = self.srvgui.get_widget('widget_statusbar')
        widget_annotation = self.srvgui.get_widget('widget_annotation')
        visor = self.srvgui.get_widget('visor_annotations')
        viewmenu = self.srvgui.get_widget('viewmenu')

        aid = widget_annotation.get_aid_from_widget()

        annotation = widget_annotation.get_metadata_from_widget()

        if self.srvant.is_valid(aid):
            self.srvant.update(annotation)
            # ~ self.info("Updated annotation: %s" % aid)
        else:
            self.srvant.create(annotation)
            # ~ self.info('New annotation created (%s) and linked to SAP Note %010d' % (aid, int(sid)))
        visor.populate_annotations()
        self.gui_annotation_widget_clear()
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)


    def action_annotation_cancel(self, *args):
        statusbar = self.srvgui.get_widget('widget_statusbar')
        self.gui_annotation_widget_clear()
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
        self.info('Annotation canceled')


    def gui_annotation_widget_clear(self):
        a_wdg_timestamp = self.srvgui.get_widget('gtk_label_human_timestamp')
        a_wdg_title = self.srvgui.get_widget('gtk_entry_annotation_title')
        a_wdg_type = self.srvgui.get_widget('gtk_combobox_annotation_type')
        a_wdg_text = self.srvgui.get_widget('gtk_textview_annotation_text')
        a_wdg_link = self.srvgui.get_widget('gtk_entry_annotation_link')
        a_wdg_link_button = self.srvgui.get_widget('gtk_link_button_annotation_link')
        a_wdg_link_type = self.srvgui.get_widget('gtk_combobox_annotation_link_type')

        a_wdg_timestamp.set_text('')
        a_wdg_title.set_text('')
        textbuffer = a_wdg_text.get_buffer()
        textbuffer.set_text('')
        a_wdg_link.set_text('')
        a_wdg_link_button.set_uri('')
        self.gui_annotation_widget_hide()


    def gui_annotation_widget_hide(self):
        self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)