Subversion Repositories basico

Rev

Rev 243 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

#!/usr/bin/python
# -*- coding: utf-8 -*-
# File: sapnoteviewvisor.py
# Author: Tomás Vírseda
# License: GPL v3
# Description: SAPNoteViewVisor widget

import os
from os.path import sep as SEP
from cgi import escape
import glob
import json

import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository.GdkPixbuf import Pixbuf
from gi.repository import Pango

from basico.core.mod_env import LPATH
from basico.widgets.wdg_cols import CollectionsMgtView
from basico.widgets.wdg_import import ImportWidget


class SAPNoteViewVisorToolbar(Gtk.HBox):
    def __init__(self, app):
        Gtk.Box.__init__(self, app)
        self.app = app
        self.get_services()
        self.set_homogeneous(False)
        self.tool_bar = Gtk.Toolbar()
        self.pack_start(self.tool_bar, False, True, 0)
        self.tool_bar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
        self.tool_bar.set_property('margin-bottom', 0)

        # Toggle Views button
        tool = self.srvgui.add_widget('gtk_toogletoolbutton_menu_view', Gtk.ToggleToolButton.new())
        tool.set_icon_name('gtk-select-color')
        tool.connect('toggled', self.srvclb.gui_toggle_menu_view)
        tool.set_active(False)
        tool.set_hexpand(False)
        self.tool_bar.insert(tool, -1)

        # View combobox button/popover
        tool = Gtk.ToolItem.new()
        lhbox = Gtk.HBox()
        menuviews = self.srvgui.add_widget('gtk_button_menu_views', Gtk.Button())
        hbox = Gtk.HBox()
        label = self.srvgui.add_widget('gtk_label_current_view', Gtk.Label())
        label.set_xalign(0.0)
        image = self.srvgui.add_widget('gtk_image_current_view', Gtk.Image())
        hbox.pack_start(image, False, False, 3)
        hbox.pack_start(label, True, True, 3)
        menuviews.add(hbox)
        lhbox.pack_start(menuviews, True, True, 3)
        lhbox.show_all()
        tool.add(lhbox)
        tool.set_expand(False)
        self.tool_bar.insert(tool, -1)

        ### Popover menuviews
        popover = self.srvgui.add_widget('gtk_popover_button_menu_views', Gtk.Popover.new(menuviews))
        menuviews.connect('clicked', self.srvclb.gui_show_popover, popover)
        box = Gtk.Box(spacing = 0, orientation="vertical")
        popover.add(box)


        box.pack_start(self.srvuif.create_menuview_button('annotation'), False, False, 0)
        separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
        box.pack_start(separator, False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('collection'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('component'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('description'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('bookmarks'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('category'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('chronologic'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('priority'), False, False, 0)
        box.pack_start(self.srvuif.create_menuview_button('type'), False, False, 0)

        # Import button
        tool = Gtk.ToolButton()
        tool.set_icon_name('basico-add')
        popover = self.srvgui.add_widget('gtk_popover_toolbutton_import', Gtk.Popover.new(tool))
        tool.connect('clicked', self.srvclb.gui_show_popover, popover)
        self.tool_bar.insert(tool, -1)

        ## Popover body
        box = Gtk.VBox(spacing = 0, orientation="vertical")
        box.set_property('margin', 3)
        widget_import = self.srvgui.add_widget('widget_import', ImportWidget(self.app))
        box.pack_start(widget_import, True, True, 6)
        popover.add(box)

        # Annotation button
        tool = Gtk.ToolButton()
        tool.set_icon_name('basico-annotation')
        popover = self.srvgui.add_widget('gtk_popover_annotation', Gtk.Popover.new(tool))
        # ~ tool.connect('clicked', self.srvclb.gui_show_popover, popover)
        tool.connect('clicked', self.srvclb.gui_annotation_widget_show)
        self.tool_bar.insert(tool, -1)

        ## Popover body
        # ~ box = Gtk.VBox(spacing = 0, orientation="vertical")
        # ~ box.set_property('margin', 3)
        # ~ widget_import = self.srvgui.add_widget('widget_annotation', AnnotationWidget(self.app))
        # ~ box.pack_start(widget_import, True, True, 6)
        # ~ popover.add(box)


        # Filter entry

        ## Completion
        self.completion = self.srvgui.add_widget('gtk_entrycompletion_visor', Gtk.EntryCompletion())
        self.completion.set_match_func(self.completion_match_func)
        self.completion_model = Gtk.ListStore(str)
        self.completion.set_model(self.completion_model)
        self.completion.set_text_column(0)

        tool = Gtk.ToolItem.new()

        hbox = Gtk.HBox()
        entry = Gtk.Entry()
        entry.set_completion(self.completion)
        entry.connect('activate', self.srvclb.gui_filter_visor)
        self.srvgui.add_widget('gtk_entry_filter_visor', entry)

        icon = self.srvicm.get_pixbuf_icon('basico-find')
        entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, icon)
        entry.set_icon_sensitive(Gtk.EntryIconPosition.PRIMARY, True)
        entry.set_icon_tooltip_markup (Gtk.EntryIconPosition.PRIMARY, "Search in the whole database")

        icon = self.srvicm.get_pixbuf_icon('basico-filter')
        entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.SECONDARY, icon)
        entry.set_icon_sensitive(Gtk.EntryIconPosition.SECONDARY, True)
        entry.set_icon_tooltip_markup (Gtk.EntryIconPosition.SECONDARY, "Click here to filter results")
        entry.set_placeholder_text("Filter results...")

        def on_icon_pressed(entry, icon_pos, event):
            if icon_pos == Gtk.EntryIconPosition.PRIMARY:
                self.srvclb.action_search(entry)
            elif icon_pos == Gtk.EntryIconPosition.SECONDARY:
                self.srvclb.gui_filter_visor(entry)

        entry.connect('changed', self.srvclb.gui_filter_visor)
        entry.connect("icon-press", on_icon_pressed)
        hbox.pack_start(entry, True, True, 0)
        tool.add(hbox)
        tool.set_expand(True)
        self.tool_bar.insert(tool, -1)

        # ~ Separator
        tool = Gtk.SeparatorToolItem.new()
        tool.set_draw(False)
        tool.set_expand(True)
        self.tool_bar.insert(tool, -1)

        # Button Total SAP Notes
        tool = Gtk.ToolItem()
        tool.set_expand(False)
        button = self.srvgui.add_widget('gtk_button_total_notes', Gtk.Button())
        button.set_relief(Gtk.ReliefStyle.NONE)

        popover = self.srvgui.add_widget('gtk_popover_button_total_notes', Gtk.Popover.new(button))
        label = self.srvgui.add_widget('gtk_label_total_notes', Gtk.Label())
        hbox = Gtk.HBox()
        hbox.pack_start(label, False, False, 0)
        button.add(hbox)
        button.connect('clicked', self.srvclb.gui_show_popover, popover)
        tool.add(button)
        self.tool_bar.insert(tool, -1)

        ## Popover body
        box = self.build_popover(popover)
        popover.add(box)

        # Fullscreen toggle button
        tool = Gtk.ToolItem()
        tool.set_expand(False)
        icon = self.srvicm.get_new_image_icon('basico-fullscreen', 24, 24)
        box = self.srvgui.add_widget('gtk_box_container_icon_fullscreen', Gtk.Box())
        box.pack_start(icon, False, False, 0)
        button = Gtk.ToggleButton()
        button.set_relief(Gtk.ReliefStyle.NONE)
        button.connect('toggled', self.srvclb.gui_toggle_fullscreen)
        button.add(box)
        tool.add(button)
        self.tool_bar.insert(tool, -1)

        # Toolbar initial settings
        self.set_visible(True)
        self.set_no_show_all(False)
        self.tool_bar.set_hexpand(True)


    def get_services(self):
        self.srvgui = self.app.get_service("GUI")
        self.srvclb = self.app.get_service('Callbacks')
        self.srvsap = self.app.get_service('SAP')
        self.srvicm = self.app.get_service('IM')
        self.srvstg = self.app.get_service('Settings')
        self.srvdtb = self.app.get_service('DB')
        self.srvuif = self.app.get_service("UIF")


    def completion_match_func(self, completion, key, iter):
        model = completion.get_model()
        text = model.get_value(iter, 0)
        if key.upper() in text.upper():
            return True
        return False



    def build_popover(self, popover):
        box = Gtk.Box(spacing = 3, orientation="vertical")
        sid = '0000000000'

        def get_popover_button(text, icon_name):
            button = Gtk.Button()
            button.set_relief(Gtk.ReliefStyle.NONE)
            hbox = Gtk.HBox()
            icon = self.srvicm.get_new_image_icon(icon_name, 24, 24)
            lbltext = Gtk.Label()
            lbltext.set_xalign(0.0)
            lbltext.set_markup('%s' % text)
            hbox.pack_start(icon, False, False, 3)
            hbox.pack_start(lbltext, True, True, 3)
            button.add(hbox)
            return button

        # Popover button "Bookmark"
        button = get_popover_button("(Un)bookmark SAP Notes", 'basico-bookmarks')
        button.connect('clicked', self.srvclb.switch_bookmark_current_set, popover)
        box.pack_start(button, False, False, 0)

        # Separator
        separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
        box.pack_start(separator, True, True, 0)

        # Popover button Collection Management
        button = get_popover_button("Manage collections", 'basico-collection')
        box.pack_start(button, False, False, 0)
        self.popcollections = self.srvgui.add_widget('gtk_popover_button_manage_collections_selected_notes', Gtk.Popover.new(button))
        self.popcollections.set_position(Gtk.PositionType.RIGHT)
        button.connect('clicked', self.srvclb.gui_show_popover, self.popcollections)
        self.popcollections.add(CollectionsMgtView(self.app, sid, self.popcollections))

        # Separator
        separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
        box.pack_start(separator, True, True, 0)


        # Popover button "Delete SAP Notes"
        button = get_popover_button("Delete SAP Notes", 'basico-delete')
        button.connect('clicked', self.srvclb.sapnote_delete, sid)
        box.pack_start(button, False, False, 0)

        return box

class SAPNoteViewVisor(Gtk.Box):
    def __init__(self, app):
        Gtk.Box.__init__(self, app)
        self.app = app
        self.bag = []
        self.get_services()
        self.setup()


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

    def get_treeview(self):
        return self.treeview


    def sort_by_timestamp(self):
        self.sorted_model.set_sort_column_id(11, Gtk.SortType.DESCENDING)


    def setup(self):
        scr = Gtk.ScrolledWindow()
        scr.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scr.set_shadow_type(Gtk.ShadowType.IN)
        viewport = Gtk.Viewport()
        self.treeview = Gtk.TreeView()
        viewport.add(self.treeview)
        scr.add(viewport)
        self.pack_start(scr, True, True, 6)

        # Setup model
        self.model = Gtk.TreeStore(
            int,        # key
            Pixbuf,     # Icon
            int,        # checkbox
            str,        # sid
            str,        # title
            str,        # component
            str,        # category
            str,        # type
            str,        # priority
            str,        # last update
            str,        # Annotation Id (extra key)
            str,        # Timestamp
        )

        # Setup columns
        def get_column_header_widget(title, icon_name=None, width=24, height=24):
            hbox = Gtk.HBox()
            icon = self.srvicm.get_new_image_icon(icon_name, width, height)
            label = Gtk.Label()
            label.set_markup("<b>%s</b>" % title)
            label.modify_font(Pango.FontDescription('Monospace 10'))
            hbox.pack_start(icon, False, False, 3)
            hbox.pack_start(label, True, True, 3)
            hbox.show_all()
            return hbox

        # SAP Note key
        self.renderer_key = Gtk.CellRendererText()
        self.renderer_key.set_property('height', 32)
        self.column_key = Gtk.TreeViewColumn('Key', self.renderer_key, text=0)
        self.column_key.set_visible(False)
        self.column_key.set_expand(False)
        self.column_key.set_clickable(False)
        self.column_key.set_sort_indicator(False)
        self.treeview.append_column(self.column_key)

        # Icon
        self.renderer_icon = Gtk.CellRendererPixbuf()
        self.renderer_icon.set_alignment(0.0, 0.5)
        self.column_icon = Gtk.TreeViewColumn('Bookmark', self.renderer_icon, pixbuf=1)
        widget = get_column_header_widget('', 'basico-bookmarks')
        self.column_icon.set_widget(widget)
        self.column_icon.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_icon.set_visible(True)
        self.column_icon.set_expand(False)
        self.column_icon.set_clickable(False)
        self.column_icon.set_sort_indicator(False)
        self.treeview.append_column(self.column_icon)

        # SAP Note Checkbox
        self.renderer_checkbox = Gtk.CellRendererToggle()
        self.renderer_checkbox.connect("toggled", self.toggle_checkbox)
        self.column_checkbox = Gtk.TreeViewColumn('', self.renderer_checkbox, active=2)
        self.column_checkbox.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_checkbox.set_visible(False)
        self.column_checkbox.set_expand(False)
        self.column_checkbox.set_clickable(True)
        self.column_checkbox.set_sort_indicator(False)
        self.column_checkbox.set_property('spacing', 50)
        self.treeview.append_column(self.column_checkbox)

        # SAP Note Id
        self.renderer_sid = Gtk.CellRendererText()
        self.renderer_sid.set_property('xalign', 1.0)
        self.renderer_sid.set_property('height', 36)
        self.renderer_sid.set_property('background', '#F0E3E3')
        self.column_sid = Gtk.TreeViewColumn('SAP Note Id', self.renderer_sid, markup=3)
        widget = get_column_header_widget('SAP Note Id', 'basico-sid')
        self.column_sid.set_widget(widget)
        self.column_sid.set_visible(True)
        self.column_sid.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_sid.set_expand(False)
        self.column_sid.set_clickable(True)
        self.column_sid.set_sort_indicator(True)
        self.column_sid.set_sort_column_id(0)
        self.column_sid.set_sort_order(Gtk.SortType.ASCENDING)
        self.model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.treeview.append_column(self.column_sid)

        # SAP Note title
        self.renderer_title = Gtk.CellRendererText()
        self.renderer_title.set_property('background', '#FFFEEA')
        self.renderer_title.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE)
        self.column_title = Gtk.TreeViewColumn('Title', self.renderer_title, markup=4)
        widget = get_column_header_widget('Title', 'basico-tag')
        self.column_title.set_widget(widget)
        self.column_title.set_visible(True)
        self.column_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_title.set_expand(True)
        self.column_title.set_clickable(True)
        self.column_title.set_sort_indicator(True)
        self.column_title.set_sort_column_id(4)
        self.treeview.append_column(self.column_title)

        # SAP Note Component
        self.renderer_component = Gtk.CellRendererText()
        self.renderer_component.set_property('background', '#E3E3F0')
        self.column_component = Gtk.TreeViewColumn('Component', self.renderer_component, markup=5)
        widget = get_column_header_widget('Component', 'basico-component')
        self.column_component.set_widget(widget)
        self.column_component.set_visible(True)
        self.column_component.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_component.set_expand(False)
        self.column_component.set_clickable(True)
        self.column_component.set_sort_indicator(True)
        self.column_component.set_sort_column_id(5)
        self.treeview.append_column(self.column_component)

        # SAP Note Category
        self.renderer_category = Gtk.CellRendererText()
        self.renderer_category.set_property('background', '#E3F1E3')
        self.column_category = Gtk.TreeViewColumn('Category', self.renderer_category, markup=6)
        widget = get_column_header_widget('Category', 'basico-category')
        self.column_category.set_widget(widget)
        self.column_category.set_visible(False)
        self.column_category.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_category.set_expand(False)
        self.column_category.set_clickable(True)
        self.column_category.set_sort_indicator(True)
        self.column_category.set_sort_column_id(6)
        self.treeview.append_column(self.column_category)

        # SAP Note Type
        self.renderer_type = Gtk.CellRendererText()
        self.renderer_type.set_property('background', '#e4f1f1')
        self.column_type = Gtk.TreeViewColumn('Type', self.renderer_type, markup=7)
        self.column_type.set_visible(True)
        self.column_type.set_expand(False)
        self.column_type.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_type.set_clickable(True)
        self.column_type.set_sort_indicator(True)
        self.column_type.set_sort_column_id(7)
        self.treeview.append_column(self.column_type)

        # SAP Note Priority
        self.renderer_priority = Gtk.CellRendererText()
        self.column_priority = Gtk.TreeViewColumn('Priority', self.renderer_priority, markup=8)
        self.column_priority.set_visible(False)
        self.column_priority.set_expand(True)
        self.column_priority.set_clickable(True)
        self.column_priority.set_sort_indicator(True)
        self.column_priority.set_sort_column_id(8)
        self.treeview.append_column(self.column_priority)

        # SAP Note UpdatedOn
        self.renderer_updated = Gtk.CellRendererText()
        self.renderer_updated.set_property('background', '#FFE6D1')
        self.column_updated = Gtk.TreeViewColumn('Updated On', self.renderer_updated, markup=9)
        self.column_updated.set_visible(True)
        self.column_updated.set_expand(False)
        self.column_updated.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_updated.set_clickable(True)
        self.column_updated.set_sort_indicator(True)
        self.column_updated.set_sort_column_id(11)
        self.treeview.append_column(self.column_updated)

        # Annotation Id
        self.renderer_annotation = Gtk.CellRendererText()
        self.column_annotation = Gtk.TreeViewColumn('Annotation Id', self.renderer_annotation, markup=10)
        self.column_annotation.set_visible(False)
        self.column_annotation.set_expand(False)
        self.column_annotation.set_clickable(False)
        self.column_annotation.set_sort_indicator(False)
        self.treeview.append_column(self.column_annotation)

        # Timestamp
        self.renderer_timestamp = Gtk.CellRendererText()
        self.column_timestamp = Gtk.TreeViewColumn('Annotation Id', self.renderer_timestamp, text=11)
        self.column_timestamp.set_visible(False)
        self.column_timestamp.set_expand(False)
        self.column_timestamp.set_clickable(False)
        self.column_timestamp.set_sort_indicator(False)
        self.treeview.append_column(self.column_timestamp)

        # Treeview properties
        self.treeview.set_can_focus(False)
        self.treeview.set_enable_tree_lines(True)
        self.treeview.set_headers_visible(True)
        self.treeview.set_enable_search(True)
        self.treeview.set_hover_selection(False)
        self.treeview.set_grid_lines(Gtk.TreeViewGridLines.NONE)
        self.treeview.set_enable_tree_lines(True)
        self.treeview.set_level_indentation(10)
        self.treeview.modify_font(Pango.FontDescription('Monospace 10'))
        self.treeview.connect('button_press_event', self.right_click)

        # DOC: In order to have a Gtk.Widged with sorting and filtering
        # capabilities, you have to filter the model first, and use this
        # new model to create the sorted model. Then, attach the sorted
        # model to the treeview...

        # Treeview filtering:
        self.visible_filter = self.model.filter_new()
        self.visible_filter.set_visible_func(self.visible_function)
        # ~ treeview.set_search_equal_func(self.search_function)
        # https://stackoverflow.com/questions/23355866/user-search-collapsed-rows-in-a-gtk-treeview

        # TreeView sorting
        self.sorted_model = Gtk.TreeModelSort(model=self.visible_filter)
        self.sorted_model.set_sort_func(0, self.sort_function, None)

        # Selection
        self.selection = self.treeview.get_selection()
        self.selection.set_mode(Gtk.SelectionMode.SINGLE)
        self.selection.connect('changed', self.row_changed)

        # Set model (filtered and sorted)
        self.treeview.set_model(self.sorted_model)

        self.show_all()


    def sort_function(self, model, row1, row2, user_data):
        sort_column = 0

        value1 = model.get_value(row1, sort_column)
        value2 = model.get_value(row2, sort_column)

        if value1 < value2:
            return -1
        elif value1 == value2:
            return 0
        else:
            return 1

    def always_visible(self, model, itr, data):
        return False

    def visible_function(self, model, itr, data):
        entry = self.srvgui.get_widget('gtk_entry_filter_visor')
        text = entry.get_text()
        sid = str(model.get(itr, 3)[0])
        if sid.startswith('<'):
            sid = sid[3:-4]
        title = model.get(itr, 4)[0]
        component = str(model.get(itr, 5)[0])
        category = model.get(itr, 6)[0]
        rtype = model.get(itr, 7)[0]
        string = ' '.join(['SAP Note %s' % sid, title, component, category, rtype])
        match = text.upper() in string.upper()
        # ~ self.debug("%s in %s? %s" % (text, string, match))

        return match


    def update_total_sapnotes_count(self, count=0):
        statusbar = self.srvgui.get_widget('widget_statusbar')
        lblnotescount = self.srvgui.get_widget('gtk_label_total_notes')
        total = self.srvdtb.get_total()

        lblnotescount.set_markup("<b>%d/<big>%d</big></b>" % (count, total))
        # ~ self.info('View populated with %d SAP Notes' % count)


    def get_visible_filter(self):
        return self.visible_filter


    def row_changed(self, selection):
        try:
            model, treeiter = selection.get_selected()
            if treeiter is not None:
                component = model[treeiter][5]
                if component == 'Annotation':
                    aid = model[treeiter][10]
                    is_valid = self.srvant.is_valid(aid)
                    if is_valid:
                        self.srvclb.action_annotation_edit(aid)
                else:
                    aid = None
                    self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
        except Exception as error:
            self.debug(error)
            self.print_traceback()


    def toggle_checkbox(self, cell, path):
        path = self.sorted_model.convert_path_to_child_path(Gtk.TreePath(path))
        self.model[path][2] = not self.model[path][2]


    def get_node(self, key, icon, checkbox, sid, title, component, category='', sntype='', priority='', updated='', aid='', timestamp=''):
        # Add completion entries
        completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
        completion_model = completion.get_model()
        completion_model.append([title])

        node = []
        node.append(key)
        node.append(icon)
        node.append(checkbox)
        node.append(sid)
        node.append(title)
        node.append(component)
        node.append(category)
        node.append(sntype)
        node.append(priority)
        node.append(updated)
        node.append(aid) # Extra key for annotations id (aid)
        node.append(timestamp)
        return node


    def get_bag(self):
        return self.bag


    def populate_sapnotes(self, bag=None, cid=None):
        icon_annotation = self.srvicm.get_pixbuf_icon('basico-annotation', 32, 32)
        icon_content = self.srvicm.get_pixbuf_icon('basico-logviewer', 32, 32)
        icon_link = self.srvicm.get_pixbuf_icon('basico-browser', 32, 32)
        icon_empty = self.srvicm.get_pixbuf_icon('basico-empty', 32, 32)
        icon_sapnote = self.srvicm.get_pixbuf_icon('basico-sapnote', 32, 32)
        icon_bookmark = self.srvicm.get_pixbuf_icon('basico-bookmarks', 32, 32)
        self.column_sid.set_visible(True)
        self.column_checkbox.set_visible(False)
        self.column_category.set_visible(False)
        self.column_component.set_visible(True)
        completion = self.srvgui.get_widget('gtk_entrycompletion_visor')
        completion_model = completion.get_model()
        completion_model.clear()

        # ~ self.srvclb.gui_show_dashboard()

        if bag is None:
            bag = self.bag
        else:
            self.bag = bag


        self.model.clear()

        for sid in self.bag:
            metadata = self.srvdtb.get_sapnote_metadata(sid)
            if metadata is not None:
                bookmark = metadata['bookmark']
                title = escape(metadata['title'])
                sid = str(int(metadata['id']))
                if bookmark:
                    icon = icon_bookmark
                    title = "<b>%s</b>" % title
                    sid = "<b>%s</b>" % sid
                else:
                    icon = icon_sapnote

                timestamp = metadata['releaseon']
                timestamp = timestamp.replace('-', '')
                timestamp = timestamp.replace(':', '')
                timestamp = timestamp.replace('T', '_')

                node = self.get_node(   int(metadata['id']),
                                        icon,
                                        bookmark,
                                        '<b>%s</b>' % sid,
                                        title,
                                        escape(metadata['componentkey']),
                                        escape(metadata['category']),
                                        escape(metadata['type']),
                                        escape(metadata['priority']),
                                        self.srvutl.fuzzy_date_from_timestamp(timestamp),
                                        '',
                                        timestamp
                                    )
                pid = self.model.append(None, node)

                # Load annotations
                files = self.srvant.get_by_sid(metadata['id'])
                for fname in files:
                    with open(fname, 'r') as fa:
                        annotation = json.load(fa)
                        # ~ self.debug("Populating annotation: %s" % annotation['aid'])
                        node = self.get_node(   0,
                                                icon_annotation,
                                                False,
                                                '',
                                                annotation['title'],
                                                annotation['component'],
                                                '',
                                                annotation['type'],
                                                '',
                                                self.srvutl.fuzzy_date_from_timestamp(annotation['timestamp']),
                                                annotation['aid'],
                                                annotation['timestamp']
                                            )
                        self.model.append(pid, node)
        self.treeview.set_model(self.sorted_model)
        self.update_total_sapnotes_count(len(self.model))
        self.show_widgets()
        stack = self.srvgui.get_widget('gtk_stack_main')
        stack.set_visible_child_name('visor')
        # ~ self.srvant.get_all()


    def populate_annotations(self, annotations=None):
        icon_annotation = self.srvicm.get_pixbuf_icon('basico-annotation', 32, 32)
        icon_content = self.srvicm.get_pixbuf_icon('basico-logviewer', 32, 32)
        icon_link = self.srvicm.get_pixbuf_icon('basico-browser', 32, 32)
        icon_empty = self.srvicm.get_pixbuf_icon('basico-empty', 32, 32)
        icon_bookmark = self.srvicm.get_pixbuf_icon('basico-bookmarks', 32, 32)
        icon_sapnote = self.srvicm.get_pixbuf_icon('basico-sapnote', 32, 32)
        self.column_sid.set_visible(False)
        self.column_checkbox.set_visible(True)
        self.column_category.set_visible(True)
        self.column_component.set_visible(False)
        # ~ self.srvclb.gui_show_dashboard()

        self.model.clear()

        if annotations is None:
            annotations = self.srvant.get_all()

        snpids = {}

        for fname in annotations:
            with open(fname, 'r') as fa:
                annotation = json.load(fa)
                sid = self.srvant.get_sid(annotation['aid'])
                node = self.get_node(   0,
                                        icon_annotation,
                                        False,
                                        str(int(sid)),
                                        annotation['title'],
                                        annotation['component'],
                                        '',
                                        annotation['type'],
                                        '',
                                        self.srvutl.fuzzy_date_from_timestamp(annotation['timestamp']),
                                        annotation['aid'],
                                        annotation['timestamp']
                                    )
                self.model.append(None, node)
        self.treeview.set_model(self.sorted_model)
        self.sort_by_timestamp()
        self.treeview.expand_all()
        self.update_total_sapnotes_count(len(self.model))
        self.show_widgets()
        stack = self.srvgui.get_widget('gtk_stack_main')
        stack.set_visible_child_name('visor')


    def show_widgets(self):
        self.srvuif.set_widget_visibility('gtk_button_total_notes', True)


    def right_click(self, treeview, event, data=None):
        if event.button == 3:
            rect = Gdk.Rectangle()
            rect.x = x = int(event.x)
            rect.y = y = int(event.y)
            pthinfo = self.treeview.get_path_at_pos(x,y)
            if pthinfo is not None:
                path,col,cellx,celly = pthinfo
                model = treeview.get_model()
                treeiter = model.get_iter(path)
                component = model[treeiter][5]
                sid = model[treeiter][0]
                sid = "0"*(10 - len(str(sid))) + str(sid)
                toolbar = self.srvgui.get_widget('visortoolbar')
                popover = self.srvgui.add_widget('gtk_popover_visor_row', Gtk.Popover.new(treeview))
                popover.set_position(Gtk.PositionType.TOP)
                popover.set_pointing_to(rect)
                box = self.build_popover(sid, popover, component)
                popover.add(box)
                self.srvclb.gui_show_popover(None, popover)


    def build_popover(self, sid, popover, component):
        box = Gtk.Box(spacing = 3, orientation="vertical")

        def get_popover_button(text, icon_name):
            button = Gtk.Button()
            button.set_relief(Gtk.ReliefStyle.NONE)
            hbox = Gtk.HBox()
            icon = self.srvicm.get_new_image_icon(icon_name, 24, 24)
            lbltext = Gtk.Label()
            lbltext.set_xalign(0.0)
            lbltext.set_markup('%s' % text)
            hbox.pack_start(icon, False, False, 3)
            hbox.pack_start(lbltext, True, True, 3)
            button.add(hbox)
            return button

        if component == 'Annotation':
            # Popover button "Delete annotation"
            button = get_popover_button("Delete annotation", 'basico-delete')
            button.show_all()
            button.connect('clicked', self.srvclb.action_annotation_delete)
            box.pack_start(button, False, False, 0)

            # Popover button "Duplicate annotation"
            button = get_popover_button("Duplicate annotation", 'basico-duplicate')
            button.show_all()
            button.connect('clicked', self.srvclb.action_annotation_duplicate)
            box.pack_start(button, False, False, 0)

        else:
            # Popover button "Add an annotation"
            button = get_popover_button("Add an annotation", 'basico-annotation')
            button.show_all()
            button.connect('clicked', self.srvclb.gui_annotation_widget_show, sid, 'create')
            box.pack_start(button, False, False, 0)

            # Popover button "Open SAP Note"
            button = get_popover_button("See SAP Note", 'basico-browse')
            button.connect('clicked', self.srvclb.sapnote_browse, sid)
            box.pack_start(button, False, False, 0)

            # Popover button "Bookmark"
            button = get_popover_button("(Un)bookmark SAP Note", 'basico-bookmarks')
            button.connect('clicked', self.srvclb.switch_bookmark, [sid], popover)
            box.pack_start(button, False, False, 0)

            # Separator
            separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
            box.pack_start(separator, True, True, 0)

            # Popover button Collection Management
            button = get_popover_button("Manage collections", 'basico-collection')
            box.pack_start(button, False, False, 0)
            self.popcollections = self.srvgui.add_widget('gtk_popover_button_manage_collections_single_note', Gtk.Popover.new(button))
            self.popcollections.set_position(Gtk.PositionType.RIGHT)
            button.connect('clicked', self.srvclb.gui_show_popover, self.popcollections)
            self.popcollections.add(CollectionsMgtView(self.app, sid, self.popcollections))

            # Separator
            separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
            box.pack_start(separator, True, True, 0)


            # Popover button "Delete SAP Note"
            button = get_popover_button("Delete SAP Note", 'basico-delete')
            button.connect('clicked', self.srvclb.sapnote_delete, sid)
            box.pack_start(button, False, False, 0)

        return box