Subversion Repositories basico

Rev

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

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

from os.path import sep as SEP
from cgi import escape
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Pango

from .env import ROOT, USER_DIR, APP, LPATH, GPATH, FILE
from .service import Service


class Statusbar(Gtk.HBox, Service):
    def __init__(self, app):
        Gtk.HBox.__init__(self)
        self.app = app
        self.get_services()
        self.setup()

    def setup(self):
        vbox = Gtk.VBox()
        hbox = Gtk.HBox()

        # Status bar
        #~ separator = Gtk.Separator(orientation = Gtk.Orientation.HORIZONTAL)
        #~ vbox.pack_start(separator, True, False, 3)
        viewport = Gtk.Viewport()
        viewport.set_shadow_type(Gtk.ShadowType.IN)
        self.statusbar = self.gui.add_widget('gtk_label_statusbar', Gtk.Label())
        self.statusbar.set_property('margin-left', 6)
        self.statusbar.set_property('margin-right', 6)
        self.statusbar.set_property('margin-top', 6)
        self.statusbar.set_property('margin-bottom', 6)
        self.statusbar.set_xalign(0.0)
        self.message("<b>Welcome to Basico</b>")
        viewport.add(self.statusbar)
        hbox.pack_start(viewport, True, True, 0)

        # Progressbar
        #~ self.progressbar = Gtk.ProgressBar()
        #~ hbox.pack_start(self.progressbar, False, False, 0)

        vbox.pack_start(hbox, True, False, 0)
        self.add(vbox)


    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")


    def message(self, message):
        self.statusbar.set_markup(message)



class ListReview(Gtk.ScrolledWindow, Service):
    def __init__(self, app):
        Gtk.ScrolledWindow.__init__(self)
        self.app = app

        self.get_services()

        self.setup()


    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")


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

        # Setup model
        self.model = Gtk.ListStore(
            str,        # SAP Note ID
            str,        # Title
            str         # RC
        )
        self.treeview.set_model(self.model)

        # Setup columns
        # SAP Note Id
        self.renderer_sid = Gtk.CellRendererText()
        self.column_sid = Gtk.TreeViewColumn('SAP Note', self.renderer_sid, markup=0)
        self.column_sid.set_visible(True)
        self.column_sid.set_expand(False)
        self.column_sid.set_clickable(False)
        self.column_sid.set_sort_indicator(False)
        self.treeview.append_column(self.column_sid)

        # SAP Note Title
        self.renderer_title = Gtk.CellRendererText()
        self.column_title = Gtk.TreeViewColumn('Title', self.renderer_title, markup=1)
        self.column_title.set_visible(True)
        self.column_title.set_expand(True)
        self.column_title.set_clickable(False)
        self.column_title.set_sort_indicator(False)
        self.treeview.append_column(self.column_title)

        # SAP Note RC
        self.renderer_rc = Gtk.CellRendererText()
        self.column_rc = Gtk.TreeViewColumn('RC', self.renderer_rc, markup=2)
        self.column_rc.set_visible(False)
        self.column_rc.set_expand(False)
        self.column_rc.set_clickable(False)
        self.column_rc.set_sort_indicator(False)
        self.treeview.append_column(self.column_rc)

        # TreeView common
        self.treeview.set_can_focus(False)
        self.treeview.set_headers_visible(True)
        self.treeview.set_enable_search(False)
        self.treeview.set_hover_selection(False)
        self.treeview.set_grid_lines(Gtk.TreeViewGridLines.HORIZONTAL)
        self.treeview.modify_font(Pango.FontDescription('Monospace 10'))

        # Selection
        self.selection = self.treeview.get_selection()
        self.selection.set_mode(Gtk.SelectionMode.NONE)

        # ~ viewport.add(self.treeview)
        # ~ scrolledwindow.add(viewport)
        # ~ vbox.pack_start(scrolledwindow, True, True, 0)
        # ~ self.add(vbox)
        self.show_all()

    def update(self, sid, value):
        pass



class LogViewer(Gtk.ScrolledWindow, Service):
    def __init__(self, app):
        Gtk.ScrolledWindow.__init__(self)
        self.app = app
        self.log = app.log
        self.get_services()
        self.setup()
        self.update()


    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")


    def setup(self):
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.set_shadow_type(Gtk.ShadowType.IN)
        self.set_hexpand(True)
        self.set_vexpand(True)
        self.logviewer = self.gui.add_widget('gtk_textview_logviewer', Gtk.TextView())
        self.logviewer.modify_font(Pango.FontDescription('Monospace 10'))
        buffer_logviewer = self.logviewer.get_buffer()
        self.add(self.logviewer)
        self.show_all()


    def update(self):
        logviewer = self.gui.get_widget('gtk_textview_logviewer')
        buffer_logviewer = logviewer.get_buffer()
        log = open(FILE['LOG'], 'r').read()
        buffer_logviewer.set_text(log)
        istart, iend = buffer_logviewer.get_bounds()
        buffer_logviewer.place_cursor(iend)



class SettingsView(Gtk.ScrolledWindow, Service):
    def __init__(self, app):
        Gtk.ScrolledWindow.__init__(self)
        Service.__init__(self)
        self.app = app
        self.log = app.log
        self.get_services()
        self.setup()

    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")


    def setup(self):
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.set_shadow_type(Gtk.ShadowType.IN)
        self.set_hexpand(True)
        self.set_vexpand(True)
        viewport = Gtk.Viewport()
        self.treeview = Gtk.TreeView()
        viewport.add(self.treeview)
        self.add(viewport)

        # Setup model
        self.model = Gtk.TreeStore(
            str,        # Primary key: SECTION-KEY-VALUE
            str,        # Key
            str,        # Value
        )

        # Setup columns
        # Primary key: SECTION-KEY-VALUE
        self.renderer_pkey = Gtk.CellRendererText()
        self.column_pkey = Gtk.TreeViewColumn('Primary Key', self.renderer_pkey, text=0)
        self.column_pkey.set_visible(False)
        self.column_pkey.set_expand(False)
        self.column_pkey.set_clickable(False)
        self.column_pkey.set_sort_indicator(False)
        self.treeview.append_column(self.column_pkey)

        # Key
        self.renderer_key = Gtk.CellRendererText()
        self.column_key = Gtk.TreeViewColumn('Key', self.renderer_key, markup=1)
        self.column_key.set_visible(True)
        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)

        # Value
        self.renderer_value = Gtk.CellRendererText()
        self.column_value = Gtk.TreeViewColumn('Value', self.renderer_value, markup=2)
        self.column_value.set_visible(True)
        self.column_value.set_expand(True)
        self.column_value.set_clickable(False)
        self.column_value.set_sort_indicator(False)
        self.treeview.append_column(self.column_value)

        # TreeView common
        self.sorted_model = Gtk.TreeModelSort(model=self.model)
        self.sorted_model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        self.treeview.set_model(self.sorted_model)

        self.treeview.set_can_focus(False)
        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.HORIZONTAL)
        # ~ self.treeview.modify_font(Pango.FontDescription('Monospace 10'))

        # Selection
        self.selection = self.treeview.get_selection()
        self.selection.set_mode(Gtk.SelectionMode.SINGLE)

        self.show_all()


    def update(self):
        from cgi import escape
        self.model.clear()
        self.settings = self.app.get_service('Settings')
        config = self.settings.load()
        sdict = {}

        # ENVIRONMENT NODE
        root = self.model.append(None, ['root', '<big><b>Environment</b></big>', ''])


        self.model.append(root, ['', '<span color="blue">App System Dir</span>', ROOT])

        pid = self.model.append(root, ['', '<b>APP</b>', ''])
        for key in APP:
            value = APP[key]
            if isinstance(value, list):
                value = ('\n'.join(value))
            value = escape(value)
            self.model.append(pid, ['APP-%s' % key, '<span color="blue">%s</span>' % key, value])
        pid = self.model.append(root, ['', '<b>LPATH</b>', ''])
        for key in LPATH:
            self.model.append(pid, ['LPATH-%s' % key, '<span color="blue">%s</span>' % key, LPATH[key]])
        pid = self.model.append(root, ['', '<b>GPATH</b>', ''])
        for key in GPATH:
            self.model.append(pid, ['GPATH-%s' % key, '<span color="blue">%s</span>' % key, GPATH[key]])
        pid = self.model.append(root, ['', '<b>FILE</b>', ''])
        for key in FILE:
            self.model.append(pid, ['FILE-%s' % key, '<span color="blue">%s</span>' % key, FILE[key]])

        # SETTINGS NODE
        root = self.model.append(None, ['root', '<big><b>Settings</b></big>', ''])

        def get_pid(key):
            try:
                pid = sdict[key]
            except:
                pid = self.model.append(root, [key, '<b>%s</b>' % key, ''])
                sdict[key] = pid
            return pid

        for skey in config.keys():
            pid = get_pid(skey)
            for key in config[skey]:
                value = str(config[skey][key])
                pkey = '%s-%s-%s' % (skey, key, value)
                self.model.append(pid, [pkey, '<span color="blue">%s</span>' % key, value])


        # WIDGETS NODE
        root = self.model.append(None, ['root', '<big><b>Runtime Objects</b></big>', ''])

        wdgdict = {}
        widgets = self.gui.get_widgets()
        for name in widgets:
            objname = escape(str(widgets[name]))
            pobj = gobject = objname[4:objname.find(' ')]
            gobj_left = gobject[:gobject.find('.')]
            gobj_right = gobject[gobject.find('.')+1:]
            pobj = gobject[:gobject.find('.')]
            try:
                ppid_left = wdgdict[gobj_left]
            except:
                ppid_left = self.model.append(root, [gobj_left, '<b>%s</b>' % gobj_left, ''])
                wdgdict[gobj_left] = ppid_left


            try:
                ppid_right = wdgdict[gobj_right]
            except:
                ppid_right = self.model.append(ppid_left, [gobj_right, '<b>%s</b>' % gobj_right, ''])
                wdgdict[gobj_right] = ppid_right

            self.model.append(ppid_right, [gobject, name, ''])


class ImportWidget(Gtk.VBox, Service):
    def __init__(self, app):
        Gtk.VBox.__init__(self)
        Service.__init__(self)
        self.app = app
        self.log = app.log
        self.get_services()
        self.setup()

    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")
        self.cb = self.app.get_service('Callbacks')
        self.im = self.app.get_service('IM')

    def setup(self):
        # Import Header
        header = Gtk.VBox()
        hbox = Gtk.HBox()
        icon = self.im.get_new_image_icon('basico-add')
        title = Gtk.Label()
        title.set_markup('<big><b>Import SAP Notes from Launchpad</b></big>')
        title.set_xalign(0.0)
        hbox.pack_start(icon, False, False, 6)
        hbox.pack_start(title, True, True, 0)
        separator = Gtk.Separator()
        header.pack_start(hbox, False, False, 0)
        header.pack_start(separator, False, False, 3)
        self.pack_start(header, False, False, 0)

        # Import body
        vbox = Gtk.VBox()
        vbox.set_size_request(400,320)
        label = Gtk.Label()
        message = "Write down the list of SAP Notes that you want to download.\nThey can be separated by a new line or by commas."
        label.set_markup('%s' % message)
        label.set_property('margin-top', 3)
        label.set_property('margin-bottom', 3)
        label.set_justify(Gtk.Justification.LEFT)
        label.set_xalign(0.0)
        vbox.pack_start(label, False, True, 0)
        custom_scroller = Gtk.ScrolledWindow()
        custom_scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        custom_scroller.set_shadow_type(Gtk.ShadowType.IN)
        custom_scroller.set_vexpand(True)
        custom_text_view = self.gui.add_widget('gtk_textview_download_launchpad', Gtk.TextView())
        custom_text_view.set_vexpand(True)
        custom_text_buffer = Gtk.TextBuffer()
        custom_text_buffer.set_text('')
        custom_text_view.set_buffer(custom_text_buffer)
        custom_scroller.add(custom_text_view)
        vbox.pack_start(custom_scroller, True, True, 0)
        label = Gtk.Label()
        message = "<small>Please, be patient:  Firefox will be launched headless so you won't see any window.</small>"
        label.set_markup('%s' % message)
        label.set_justify(Gtk.Justification.LEFT)
        vbox.pack_end(label, False, False, 0)
        custom_button = Gtk.Button("Download")
        custom_button.connect('clicked', self.cb.sapnote_import_from_launchpad)
        vbox.pack_end(custom_button, False, False, 3)
        self.pack_start(vbox, True, True, 0)
        self.show_all()


class About(Gtk.ScrolledWindow):
    def __init__(self):
        Gtk.ScrolledWindow.__init__(self)
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.set_hexpand(True)
        self.set_vexpand(True)

        viewport = Gtk.Viewport()
        widget = Gtk.VBox()
        viewport.add(widget)
        widget.set_hexpand(True)
        widget.set_vexpand(True)

        # Set logo
        label = Gtk.Label()
        # ~ label.set_markup("🙇")
        label.set_markup("")
        label.modify_font(Pango.FontDescription('Monospace 92'))
        widget.pack_start(label, False, False, 6)

        # Set App name
        label = Gtk.Label()
        label.set_markup("<b>%s %s</b>" % (APP['short'].capitalize(), APP['version']))
        label.modify_font(Pango.FontDescription('Monospace 48'))
        widget.pack_start(label, False, False, 6)

        # Set App desc
        label = Gtk.Label()
        label.set_markup("%s" % APP['name'])
        label.modify_font(Pango.FontDescription('Arial 24'))
        widget.pack_start(label, False, False, 6)

        # Set App license
        label = Gtk.Label()
        label.set_markup("<i>\n\n%s\n\n</i>" % APP['license'])
        label.modify_font(Pango.FontDescription('Monospace 10'))
        label.set_justify(Gtk.Justification.CENTER)
        label.set_line_wrap(True)
        widget.pack_start(label, False, False, 6)

        # Set Link button
        linkbutton = Gtk.LinkButton(uri="http://t00mlabs.net", label="t00mlabs.net")
        widget.pack_start(linkbutton, False, False, 6)

        # Set Copyright holders
        label = Gtk.Label()
        label.set_markup("Copyright \xa9 2016-2018 Tomás Vírseda")
        label.modify_font(Pango.FontDescription('Monospace 10'))
        label.set_justify(Gtk.Justification.CENTER)
        label.set_line_wrap(True)
        widget.pack_start(label, False, False, 6)

        # Authors
        label = Gtk.Label()
        label.set_markup("\n%s" % escape(APP['authors'][0]))
        label.modify_font(Pango.FontDescription('Monospace 10'))
        label.set_justify(Gtk.Justification.CENTER)
        label.set_line_wrap(True)
        label.set_selectable(True)
        widget.pack_start(label, False, False, 6)

        self.add(viewport)
        self.show_all()


class CollectionsMgtView(Gtk.VBox, Service):
    def __init__(self, app, sid, popover):
        Gtk.VBox.__init__(self)
        self.app = app
        self.log = app.log
        self.sid = sid
        self.popover = popover
        self.current_tid = None
        self.get_services()
        self.setup()
        self.setup_treeview()
        self.update()


    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")
        self.im = self.app.get_service("IM")
        self.uif = self.app.get_service("UIF")
        self.clts = self.app.get_service('Collections')


    def setup(self):
        # Setup Widget properties
        self.set_size_request(400, 680)
        self.set_property('margin', 3)
        self.set_hexpand(True)
        self.set_vexpand(True)

        # CollectionMgt Header
        header = Gtk.VBox()
        hbox = Gtk.HBox()
        icon = self.im.get_new_image_icon('basico-collection')
        title = Gtk.Label()
        title.set_markup('<big><b>Collections for SAP Note %s</b></big>' % str(int(self.sid)))
        title.set_xalign(0.0)
        hbox.pack_start(icon, False, False, 6)
        hbox.pack_start(title, True, True, 0)
        separator = Gtk.Separator()
        header.pack_start(hbox, False, False, 0)
        header.pack_start(separator, False, False, 3)
        self.pack_start(header, False, False, 3)

        # Entry Widget /  Delete entry button
        hbox = Gtk.HBox()
        self.entry = self.gui.add_widget('gtk_entry_collection_new', Gtk.Entry())
        self.entry.connect('activate', self.update)
        delete = self.uif.create_button('basico-delete', 24, 24, '')
        delete.connect('clicked', self.delete)
        hbox.pack_start(self.entry, True, True, 6)
        hbox.pack_start(delete, False, False, 0)
        self.pack_start(hbox, False, False, 0)

        # Collection Treeview
        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)

        # Footer
        separator = Gtk.Separator()
        self.pack_start(separator, False, False, 0)

        ## Buttons
        footer = Gtk.HBox()
        accept = self.uif.create_button('basico-check-ok', 24, 24, '<b>Apply changes</b>')
        accept.connect('clicked', self.accept)
        footer.pack_start(accept, True, False, 0)
        self.pack_start(footer, False, False, 3)


    def setup_treeview(self):
        # Setup model
        self.model = Gtk.ListStore(
            str,        # key
            int,        # checkbox
            str,        # title
        )

        # Setup columns
        # Collection key
        self.renderer_key = Gtk.CellRendererText()
        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)

        # Collection Checkbox
        self.renderer_checkbox = Gtk.CellRendererToggle()
        self.renderer_checkbox.connect("toggled", self.toggle_checkbox)
        self.column_checkbox = Gtk.TreeViewColumn('Selected', self.renderer_checkbox, active=1)
        self.column_checkbox.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self.column_checkbox.set_visible(True)
        self.column_checkbox.set_expand(False)
        self.column_checkbox.set_clickable(True)
        self.column_checkbox.set_sort_indicator(False)
        self.treeview.append_column(self.column_checkbox)

        # Collection title
        self.renderer_title = Gtk.CellRendererText()
        self.column_title = Gtk.TreeViewColumn('Collection', self.renderer_title, markup=2)
        self.column_title.set_visible(True)
        self.column_title.set_expand(True)
        self.column_title.set_clickable(True)
        self.column_title
        self.column_title.set_sort_indicator(True)
        self.model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
        self.treeview.append_column(self.column_title)

        # TreeView common
        # ~ self.sorted_model = Gtk.TreeModelSort(model=self.model)
        # ~ self.sorted_model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
        # ~ self.treeview.set_model(self.sorted_model)

        self.treeview.set_can_focus(False)
        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.HORIZONTAL)
        # ~ self.treeview.modify_font(Pango.FontDescription('Monospace 10'))

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

        self.treeview.set_model(self.model)

        self.show_all()


    def toggle_checkbox(self, cell, path):
        self.model[path][1] = not self.model[path][1]


    def accept(self, button):
        db = self.app.get_service('DB')
        selected = []
        def get_linked_collections(model, path, itr):
            tid = model.get(itr, 0)[0]
            linked = model.get(itr, 1)[0]
            if linked:
                selected.append(tid)

        self.model.foreach(get_linked_collections)
        if self.sid != '0000000000':
            db.set_collections(self.sid, selected)
        else:
            visor = self.gui.get_widget('visor')
            bag = visor.get_bag()
            for sid in bag:
                db.set_collections(sid, selected)

        self.popover.hide()


    def row_changed(self, selection):
        model, treeiter = selection.get_selected() #_rows()
        visor = self.gui.get_widget('visor')
        try:
            self.current_tid = model[treeiter][0]
            title = model[treeiter][2]
            self.entry.set_text(title)
        except TypeError:
            pass
        except Exception as error:
            self.debug("ERROR: collections->row_changed->error: %s" % error)
            raise


    def update(self, entry=None):
        db = self.app.get_service('DB')
        linked = db.get_collections(self.sid)

        if entry is not None and isinstance(entry, Gtk.Entry):
            self.clts.create(entry)

        self.model.clear()
        collections = self.clts.get_all()
        for tid in collections:
            name = collections[tid]
            if tid in linked:
                self.model.append([tid, 1, name])
            else:
                self.model.append([tid, 0, name])
        self.current_tid = None


    def delete(self, button):
        self.debug("Deleting collection with id: %s" % self.current_tid)
        res = self.clts.delete(self.current_tid)
        if res:
            self.update()


class AnnotationWidget(Gtk.VBox, Service):
    def __init__(self, app, sid='0000000000'):
        Gtk.VBox.__init__(self)
        self.app = app
        self.log = app.log
        self.sid = sid
        self.get_services()
        self.setup()
        self.setup_header()
        self.setup_body()
        self.setup_footer()



    def get_services(self):
        """Load services to be used in this class
        """

        self.gui = self.app.get_service("GUI")
        self.im = self.app.get_service("IM")
        self.uif = self.app.get_service("UIF")
        self.clts = self.app.get_service('Collections')
        self.cb = self.app.get_service('Callbacks')
        self.annot = self.app.get_service('Annotation')
        self.utils = self.app.get_service('Utils')


    def setup(self):
        # Setup Widget properties
        self.set_property('margin-left', 3)
        self.set_property('margin-right', 3)
        self.set_hexpand(True)
        self.set_vexpand(True)

        # Annotation container (body)
        self.container_body = self.gui.add_widget('gtk_vbox_annotation_container', Gtk.VBox())
        self.container_body.set_border_width(3)
        self.pack_start(self.container_body, True, True, 3)


    def setup_header(self):
        # Annotation Header
        container = self.gui.get_widget('gtk_vbox_annotation_container')
        header = Gtk.VBox()
        hbox = Gtk.HBox()
        icon = self.im.get_new_image_icon('basico-annotation')
        title = self.gui.add_widget('gtk_label_annotation_sid', Gtk.Label())
        if self.sid == '0000000000':
            title.set_markup('<big><b>Annotation</b></big>')
        else:
            title.set_markup('<big><b>Annotation for SAP Note %s</b>' % str(int(self.sid)))
        title.set_xalign(0.0)
        hbox.pack_start(icon, False, False, 6)
        hbox.pack_start(title, True, True, 0)
        separator = Gtk.Separator()
        header.pack_start(hbox, False, False, 0)
        header.pack_start(separator, False, False, 3)
        header.show_all()
        container.pack_start(header, False, False, 3)


    def setup_body(self):
        vbox = Gtk.VBox()

        # Hidden metadata
        hbox = Gtk.HBox()
        a_aid = self.gui.add_widget('gtk_label_aid', Gtk.Label())
        a_aid.set_property('xalign', 0.0)
        a_aid.set_sensitive(False)
        a_aid.set_selectable(True)
        a_aid.modify_font(Pango.FontDescription('Monospace 10'))
        # ~ a_aid.set_visible(False)
        # ~ a_aid.set_no_show_all(True)
        hbox.pack_start(a_aid, True, True, 3)
        a_timestamp = self.gui.add_widget('gtk_label_timestamp', Gtk.Label(self.utils.timestamp()))
        a_timestamp.set_sensitive(False)
        a_timestamp.set_visible(False)
        a_timestamp.set_no_show_all(True)
        hbox.pack_start(a_timestamp, True, True, 0)
        vbox.pack_start(hbox, False, False, 3)

        hbox = Gtk.HBox()
        # Title
        a_title = self.gui.add_widget('gtk_entry_annotation_title', Gtk.Entry())
        a_title.set_placeholder_text("Type a title here...")
        a_title.modify_font(Pango.FontDescription('Monospace 10'))
        hbox.pack_start(a_title, True, True, 0)

        # Type
        a_type_model = Gtk.ListStore(str)
        self.gui.add_widget('annotation_type_FIXME', a_type_model.append(['FIXME']))
        active = self.gui.add_widget('annotation_type_Note', a_type_model.append(['Note']))
        self.gui.add_widget('annotation_type_Procedure', a_type_model.append(['Procedure']))
        self.gui.add_widget('annotation_type_Snippet', a_type_model.append(['Snippet']))
        self.gui.add_widget('annotation_type_Template', a_type_model.append(['Template']))
        self.gui.add_widget('annotation_type_TODO', a_type_model.append(['TODO']))
        a_type = Gtk.ComboBox.new_with_model(a_type_model)
        a_type.set_active_iter(active)
        self.gui.add_widget('gtk_combobox_annotation_type', a_type)
        renderer_type = Gtk.CellRendererText()
        a_type.pack_start(renderer_type, True)
        a_type.add_attribute(renderer_type, "text", 0)
        hbox.pack_start(a_type, False, False, 3)
        vbox.pack_start(hbox, False, False, 0)

        # Text
        hbox = Gtk.HBox()
        scroller = Gtk.ScrolledWindow()
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scroller.set_shadow_type(Gtk.ShadowType.IN)
        scroller.set_hexpand(True)
        scroller.set_vexpand(True)
        a_text = self.gui.add_widget('gtk_textview_annotation_text', Gtk.TextView())
        a_text.modify_font(Pango.FontDescription('Monospace 10'))
        a_text.set_vexpand(True)
        a_text.set_left_margin (6)
        a_text.set_top_margin (6)
        a_text.set_right_margin (6)
        a_text.set_bottom_margin (6)
        a_textbuffer = Gtk.TextBuffer()
        a_textbuffer.set_text('')
        a_text.set_buffer(a_textbuffer)
        scroller.add(a_text)
        hbox.pack_start(scroller, True, True, 3)

        # Calendar
        calendar = self.gui.add_widget('gtk_calendar_annotation_timestamp', Gtk.Calendar())
        hbox.pack_start(calendar, False, False, 0)
        vbox.pack_start(hbox, True, True, 3)

        # Url
        hbox = Gtk.HBox()
        a_link = self.gui.add_widget('gtk_entry_annotation_link', Gtk.Entry())
        a_link.set_placeholder_text("Type a url here...")
        hbox.pack_start(a_link, True, True, 3)
        a_link_type_model = Gtk.ListStore(str)
        self.gui.add_widget('annotation_link_type_Intranet', a_link_type_model.append(['Intranet']))
        self.gui.add_widget('annotation_link_type_SAP Blog', a_link_type_model.append(['SAP Blog']))
        self.gui.add_widget('annotation_link_type_SAP Document', a_link_type_model.append(['SAP Document']))
        self.gui.add_widget('annotation_link_SAP Help', a_link_type_model.append(['SAP Help']))
        self.gui.add_widget('annotation_link_type_SAP Incident', a_link_type_model.append(['SAP Incident']))
        self.gui.add_widget('annotation_link_SAP Questions and Answers', a_link_type_model.append(['SAP Questions and Answers']))
        self.gui.add_widget('annotation_link_type_SAP Wiki', a_link_type_model.append(['SAP Wiki']))
        active = self.gui.add_widget('annotation_link_type_Website', a_link_type_model.append(['Website']))
        a_link_type = Gtk.ComboBox.new_with_model(a_link_type_model)
        a_link_type.set_active_iter(active)
        self.gui.add_widget('gtk_combobox_annotation_link_type', a_link_type)
        renderer_text = Gtk.CellRendererText()
        a_link_type.pack_start(renderer_text, True)
        a_link_type.add_attribute(renderer_text, "text", 0)
        hbox.pack_start(a_link_type, False, False, 0)
        vbox.pack_start(hbox, False, False, 3)

        self.container_body.add(vbox)


    def setup_footer(self):
        # Buttons Accept/Cancel
        hbox = Gtk.HBox()
        accept = self.gui.add_widget('gtk_button_accept_annotation', Gtk.Button('Accept'))
        accept.connect('clicked', self.cb.action_annotation_accept, self.sid)
        accept.set_property('always-show-image', True)
        icon = self.im.get_new_image_icon('basico-check-accept', 24, 24)
        accept.set_image(icon)
        cancel = self.gui.add_widget('gtk_button_cancel_annotation', Gtk.Button('Cancel'))
        cancel.connect('clicked', self.cb.action_annotation_cancel)
        cancel.set_property('always-show-image', True)
        icon = self.im.get_new_image_icon('basico-check-cancel', 24, 24)
        cancel.set_image(icon)
        hbox.pack_start(accept, True, False, 3)
        hbox.pack_start(cancel, True, False, 3)
        self.pack_start(hbox, False, False, 3)


    def set_aid(self, aid):
        a_aid = self.gui.get_widget('gtk_label_aid')
        a_aid.set_text(aid)


    def get_aid(self):
        a_aid = self.gui.get_widget('gtk_label_aid')
        return a_aid.get_text()


    def set_metadata(self, aid, action):
        self.set_aid(aid)
        sid = self.annot.get_sid(aid)
        title = self.gui.get_widget('gtk_label_annotation_sid')
        if sid == '0000000000':
            title.set_markup('<big><b>Annotation</b></big>')
        else:
            title.set_markup('<big><b>Annotation for SAP Note %s</b></big>' % str(int(sid)))

        if action == 'create':
            pass
        elif action == 'edit':
            annotation = self.annot.get_metadata(aid)
            if annotation is not None:
                ANNOTATION_FILE_CONTENT = LPATH['ANNOTATIONS'] + aid + '.adoc'
                timestamp = self.utils.get_datetime(annotation['timestamp'])
                a_wdg_aid = self.gui.get_widget('gtk_label_aid')
                a_wdg_timestamp = self.gui.get_widget('gtk_label_timestamp')
                a_wdg_title = self.gui.get_widget('gtk_entry_annotation_title')
                a_wdg_type = self.gui.get_widget('gtk_combobox_annotation_type')
                a_wdg_text = self.gui.get_widget('gtk_textview_annotation_text')
                a_wdg_link = self.gui.get_widget('gtk_entry_annotation_link')
                a_wdg_link_type = self.gui.get_widget('gtk_combobox_annotation_link_type')
                a_wdg_cal = self.gui.get_widget('gtk_calendar_annotation_timestamp')

                a_wdg_aid.set_text(annotation['aid'])
                a_wdg_timestamp.set_text(self.utils.timestamp())
                a_wdg_title.set_text(annotation['title'])
                a_wdg_type.set_active_iter(self.gui.get_widget('annotation_type_%s' % annotation['type']))
                self.uif.set_textview_text(a_wdg_text, open(ANNOTATION_FILE_CONTENT).read())
                a_wdg_link.set_text(annotation['link'])
                a_wdg_link_type.set_active_iter(self.gui.get_widget('annotation_link_type_%s' % annotation['link_type']))
                a_wdg_cal.select_month(timestamp.month-1, timestamp.year)
                a_wdg_cal.select_day(timestamp.day)


    def get_metadata(self, aid):
        annotation = {}
        a_wdg_aid = self.gui.get_widget('gtk_label_aid')
        a_wdg_timestamp = self.gui.get_widget('gtk_label_timestamp')
        a_wdg_title = self.gui.get_widget('gtk_entry_annotation_title')
        a_wdg_type = self.gui.get_widget('gtk_combobox_annotation_type')
        a_wdg_text = self.gui.get_widget('gtk_textview_annotation_text')
        a_wdg_link = self.gui.get_widget('gtk_entry_annotation_link')
        a_wdg_link_type = self.gui.get_widget('gtk_combobox_annotation_link_type')

        annotation['aid'] = a_wdg_aid.get_text()
        annotation['timestamp'] = a_wdg_timestamp.get_text()
        annotation['title'] = a_wdg_title.get_text()
        annotation['component'] = 'Annotation'
        annotation['category'] = ''
        annotation['type'] = self.uif.get_combobox_text(a_wdg_type, 0)
        annotation['content'] =  self.uif.get_textview_text(a_wdg_text)
        annotation['link'] = a_wdg_link.get_text()
        annotation['link_type'] = self.uif.get_combobox_text(a_wdg_link_type, 0)

        return annotation