Subversion Repositories basico

Rev

Rev 380 | Rev 384 | 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_uif.py
5
# Author: Tomás Vírseda
6
# License: GPL v3
7
# Description: Generic UI functions service
8
"""
9
 
10
from html import escape
11
from gi.repository import Gdk
12
from gi.repository import Gtk
13
from gi.repository import Gio
14
from gi.repository import Pango
15
from gi.repository.GdkPixbuf import Pixbuf
16
 
17
from basico.core.mod_srv import Service
18
 
19
class UIFuncs(Service):
20
    def initialize(self):
21
        self.get_services()
22
 
23
 
24
    def get_services(self):
25
        self.srvgui = self.get_service('GUI')
26
        self.srvclb = self.get_service('Callbacks')
27
        self.srvicm = self.get_service('IM')
374 t00mlabs 28
        # ~ self.srvdtb = self.get_service('DB')
340 t00mlabs 29
        self.srvant = self.get_service('Annotation')
30
        self.srvutl = self.get_service('Utils')
31
        self.srvntf = self.get_service('Notify')
32
 
33
 
34
    def get_gtk_version(self):
35
        return Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()
36
 
37
 
38
    def check_gtk_version(self):
39
        vmajor, vminor, vmicro =  self.get_gtk_version()
40
        self.log.debug("GTK+ Version: %d.%d.%d" % (vmajor, vminor, vmicro))
41
 
42
        if vmajor == 3 and vminor >= 18:
43
            return True
44
        else:
45
            self.log.error("Please, install a modern version of GTK+ (>= 3.18)")
46
            return False
47
 
48
    def get_window_parent(self):
49
        return self.srvgui.get_window()
50
 
51
 
52
    def message_dialog_error(self, head, body):
53
        parent = self.get_window_parent()
54
        dialog = Gtk.MessageDialog(parent, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, "%s" % head)
55
        dialog.format_secondary_markup("%s" % body)
56
        return dialog
57
 
58
    def message_dialog_info(self, head, body):
59
        parent = self.get_window_parent()
60
        dialog = Gtk.MessageDialog(parent, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, "%s" % head)
61
        dialog.format_secondary_markup("%s" % body)
62
        return dialog
63
 
64
 
65
    def message_dialog_question(self, head, body):
66
        parent = self.get_window_parent()
67
        dialog = Gtk.MessageDialog(parent, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, head)
68
        dialog.format_secondary_markup("%s" % body)
69
        return dialog
70
 
71
 
374 t00mlabs 72
    def statusbar_msg(self, message, important=False):
340 t00mlabs 73
        statusbar = self.srvgui.get_widget('widget_statusbar')
74
        htimestamp = self.srvutl.get_human_date_from_timestamp()
75
        msg = htimestamp + '\t-\t' + message
76
        if statusbar is not None:
77
            # Maybe the widget hasn't been created yet
374 t00mlabs 78
            statusbar.message(msg)
340 t00mlabs 79
        if important:
80
            self.srvntf.show(htimestamp, message)
81
 
82
 
83
    def create_menuview_button(self, view):
84
        hbox = Gtk.Box(spacing = 0, orientation="horizontal")
85
        icon = self.srvicm.get_pixbuf_icon('basico-%s' % view, 24, 24)
86
        image = Gtk.Image()
87
        image.set_from_pixbuf(icon)
88
        label = Gtk.Label("View by %s" % view)
89
        hbox.pack_start(image, False, False, 3)
90
        hbox.pack_start(label, False, False, 3)
91
        button = Gtk.Button()
92
        button.add(hbox)
93
        button.set_relief(Gtk.ReliefStyle.NONE)
94
        button.connect('clicked', self.srvclb.gui_refresh_view, '%s' % view)
95
 
96
        return button
97
 
98
    def create_notebook_tab_label(self, iconname, title):
99
        hbox = Gtk.HBox()
100
        icon = self.srvicm.get_new_image_icon(iconname)
101
        label = Gtk.Label()
102
        label.set_markup(title)
103
        hbox.pack_start(icon, False, False, 3)
104
        hbox.pack_start(label, False, False, 0)
105
        hbox.show_all()
106
 
107
        return hbox
108
 
109
 
110
    def create_button(self, icon_name=None, icon_width=32, icon_heigth=32, title=''):
111
        button = Gtk.Button()
112
        button.set_relief(Gtk.ReliefStyle.NONE)
113
        hbox = Gtk.HBox()
114
        icon = self.srvicm.get_new_image_icon(icon_name, icon_width, icon_heigth)
115
        label = Gtk.Label()
116
        label.set_markup(title)
117
        label.set_xalign(0.0)
118
        hbox.pack_start(icon, False, False, 6)
119
        hbox.pack_start(label, True, True, 0)
120
        button.add(hbox)
121
 
122
        return button
123
 
124
 
125
    def warning_message_delete_annotations(self, widget, question, explanation, bag):
126
        window = self.srvgui.get_widget('gtk_app_window_main')
127
        icon = self.srvicm.get_new_image_icon('basico-delete', 96, 96)
128
        icon.show_all()
129
        dialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.QUESTION,
130
            Gtk.ButtonsType.YES_NO, question)
131
        dialog.set_size_request(600, 380);
132
        content_area = dialog.get_content_area()
133
        vbox = Gtk.VBox()
134
        label = Gtk.Label()
135
        label.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE)
136
        label.set_property('selectable', True)
137
        label.set_xalign(0.0)
138
        label.grab_focus()
139
        msg = '\t<b>This is the list of annotations to be deleted:</b>'
140
        vbox.pack_start(label, False, False, 0)
141
        scr = Gtk.ScrolledWindow()
142
        scr.set_shadow_type(Gtk.ShadowType.NONE)
143
        scr.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
144
 
145
        msg += '\n\n'
146
        for aid in bag:
147
            msg += '\t%s\t\n' % self.srvant.get_title(aid)
148
        msg += '\n'
149
        label.set_markup(msg)
150
 
151
        vbox.pack_start(scr, True, True, 0)
152
        content_area.pack_start(vbox, True, True, 0)
153
        content_area.show_all()
154
        dialog.set_image(icon)
155
        dialog.format_secondary_text(explanation)
156
        response = dialog.run()
157
        if response == Gtk.ResponseType.YES:
158
            answer = True
159
        else:
160
            answer = False
161
        dialog.destroy()
162
 
163
        return answer
164
 
165
 
166
    def warning_message_delete_sapnotes(self, widget, question, explanation, bag):
374 t00mlabs 167
        self.srvdtb = self.get_service('DB')
340 t00mlabs 168
        window = self.srvgui.get_widget('gtk_app_window_main')
169
        icon = self.srvicm.get_new_image_icon('basico-delete', 96, 96)
170
        icon.show_all()
171
        dialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.QUESTION,
172
            Gtk.ButtonsType.YES_NO, question)
173
        dialog.set_size_request(800, 600);
174
        content_area = dialog.get_content_area()
175
        vbox = Gtk.VBox()
383 t00mlabs 176
        # ~ label = Gtk.Label()
177
        # ~ label.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE)
178
        # ~ label.set_property('selectable', True)
179
        # ~ label.set_xalign(0.0)
180
        # ~ label.grab_focus()
181
        # ~ msg = '\t<b>You are about to delete %d SAP Notes:</b>' % len(bag)
182
        # ~ scr = Gtk.ScrolledWindow()
183
        # ~ scr.set_shadow_type(Gtk.ShadowType.NONE)
184
        # ~ scr.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
340 t00mlabs 185
 
383 t00mlabs 186
        # ~ msg += '\n\n'
187
        # ~ for sid in bag:
188
            # ~ msg += '\t%010d - %s\t\n' % (int(sid), escape(self.srvdtb.get_title(sid)))
189
        # ~ msg += '\n'
190
        # ~ label.set_markup(msg)
191
        # ~ scr.add(label)
192
        sapnotesbox = self.sapnotebox(bag)
193
        vbox.pack_start(sapnotesbox, True, True, 0)
340 t00mlabs 194
        content_area.pack_start(vbox, True, True, 0)
195
        content_area.show_all()
196
        dialog.set_image(icon)
197
        dialog.format_secondary_text(explanation)
198
        response = dialog.run()
199
        if response == Gtk.ResponseType.YES:
200
            answer = True
201
        else:
202
            answer = False
203
        dialog.destroy()
204
 
205
        return answer
206
 
207
 
208
    def set_widget_visibility(self, widget_name, visibility):
209
        widget = self.srvgui.get_widget(widget_name)
210
        if visibility:
211
            widget.set_no_show_all(False)
212
            widget.show_all()
213
        else:
214
            widget.set_no_show_all(True)
215
            widget.hide()
216
 
217
 
218
    def get_combobox_text(self, combobox, col):
219
        treeiter = combobox.get_active_iter()
220
        model = combobox.get_model()
221
        return model[treeiter][col]
222
 
223
 
224
    def set_combobox_active(self, combobox, value):
225
        model = combobox.get_model()
226
        for treeiter in model:
227
            self.log.debug (model[treeiter][0])
228
 
229
 
230
    def get_textview_text(self, textview):
231
        textbuffer = textview.get_buffer()
232
        istart, iend = textbuffer.get_bounds()
233
        return textbuffer.get_text(istart, iend, False)
234
 
235
 
236
    def set_textview_text(self, textview, text):
237
        textbuffer = textview.get_buffer()
238
        textbuffer.set_text(text)
239
 
240
    def dialog_info(self, title, message):
241
        window = self.srvgui.get_window()
242
        dialog = Gtk.MessageDialog(window, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, title)
243
        dialog.format_secondary_text(message)
244
        dialog.run()
245
        dialog.destroy()
246
 
247
 
248
    def grab_focus(self):
380 t00mlabs 249
        try:
250
            popover = self.srvgui.get_key_value('LAST_POPOVER')
251
            popover.popdown()
252
        except:
253
            pass
340 t00mlabs 254
 
255
 
256
    def action_collection_copy_to_clipboard(self, button):
374 t00mlabs 257
        self.srvdtb = self.get_service('DB')
340 t00mlabs 258
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
259
        visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
260
 
261
        bag = visor_sapnotes.get_filtered_bag()
262
        text = ''
263
        for sid in bag:
264
            metadata = self.srvdtb.get_sapnote_metadata(sid)
265
            text += "SAP Note %s: %s - Component: %s\n" % (str(int(sid)), metadata['title'], metadata['componentkey'])
266
        clipboard.set_text(text, -1)
267
 
268
        msg = "%d SAP Notes copied to the clipboard" % (len(bag))
368 t00mlabs 269
        self.statusbar_msg(msg)
340 t00mlabs 270
        self.log.debug(msg)
271
 
272
 
273
    def copy_text_to_clipboard(self, text):
274
        clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
275
        clipboard.set_text(text, -1)
368 t00mlabs 276
        msg = "Copied '%s' to clipboard" % text
277
        self.statusbar_msg(msg)
340 t00mlabs 278
 
364 t00mlabs 279
 
280
    def get_toolbar_separator(self, draw=False, expand=False):
281
        tool = Gtk.SeparatorToolItem.new()
282
        tool.set_draw(draw)
283
        tool.set_expand(expand)
284
        return tool
367 t00mlabs 285
 
286
 
287
    def tree_path_to_row(self, path):
288
        """
289
        Convert `path` to a list row integer.
290
 
291
        `path` can be either a :class:`Gtk.Treepath` instance or a string
292
        representation of it (as commonly used by various callbacks).
293
        """
294
        if path is None: return None
295
        if isinstance(path, Gtk.TreePath):
296
            return path.get_indices()[0]
297
        if isinstance(path, str):
298
            return int(path)
299
        raise TypeError("Bad type {} for path {}"
300
                        .format(repr(type(path)), repr(path)))
301
 
302
 
303
    def tree_row_to_path(self, row):
304
        """Convert list row integer to a :class:`Gtk.TreePath`."""
305
        if row is None: return None
306
        return Gtk.TreePath.new_from_string(str(row))
368 t00mlabs 307
 
308
 
309
    def select_folder(self, folder=None):
310
        window = self.srvgui.get_window()
311
        dialog = Gtk.FileChooserDialog("Please, choose a folder", window, Gtk.FileChooserAction.SELECT_FOLDER, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, "Select", Gtk.ResponseType.OK))
312
        response = dialog.run()
313
        if response == Gtk.ResponseType.OK:
314
            folder = folder = dialog.get_filename()
315
        else:
316
            folder = None
317
        dialog.destroy()
318
        return folder
319
 
374 t00mlabs 320
 
383 t00mlabs 321
    def sapnotebox(self, lsid):
322
        box = Gtk.Box()
323
        box.set_property('margin', 6)
324
        scr = Gtk.ScrolledWindow()
325
        scr.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
326
        scr.set_shadow_type(Gtk.ShadowType.IN)
327
        treeview = Gtk.TreeView()
328
        scr.add(treeview)
329
        box.pack_start(scr, True, True, 0)
330
 
331
        model = Gtk.ListStore(
332
            str,        # sid
333
            str,        # title
334
            str,        # component
335
        )
336
 
337
        # SAP Note Id
338
        renderer_sid = Gtk.CellRendererText()
339
        renderer_sid.set_property('xalign', 1.0)
340
        renderer_sid.set_property('height', 36)
341
        # ~ renderer_sid.set_property('background', '#F0E3E3')
342
        column_sid = Gtk.TreeViewColumn('SAP Note', renderer_sid, markup=0)
343
        column_sid.set_visible(True)
344
        column_sid.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
345
        column_sid.set_expand(False)
346
        column_sid.set_clickable(True)
347
        column_sid.set_sort_indicator(True)
348
        column_sid.set_sort_column_id(0)
349
        column_sid.set_sort_order(Gtk.SortType.ASCENDING)
350
        model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
351
        treeview.append_column(column_sid)
352
 
353
        # SAP Note title
354
        renderer_title = Gtk.CellRendererText()
355
        renderer_title.set_property('xalign', 0.0)
356
        renderer_title.set_property('height', 36)
357
        renderer_title.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE)
358
        # ~ renderer_title.set_property('background', '#FFFEEA')
359
        column_title = Gtk.TreeViewColumn('Title', renderer_title, markup=1)
360
        column_title.set_visible(True)
361
        column_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
362
        column_title.set_expand(True)
363
        column_title.set_clickable(True)
364
        column_title.set_sort_indicator(True)
365
        column_title.set_sort_column_id(1)
366
        column_title.set_sort_order(Gtk.SortType.ASCENDING)
367
        model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
368
        treeview.append_column(column_title)
369
 
370
        # SAP Note component
371
        renderer_component = Gtk.CellRendererText()
372
        renderer_component.set_property('xalign', 0.0)
373
        renderer_component.set_property('height', 36)
374
        # ~ renderer_component.set_property('background', '#F0E3E3')
375
        column_component = Gtk.TreeViewColumn('Component', renderer_component, markup=2)
376
        column_component.set_visible(True)
377
        column_component.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
378
        column_component.set_expand(False)
379
        column_component.set_clickable(True)
380
        column_component.set_sort_indicator(True)
381
        column_component.set_sort_column_id(1)
382
        column_component.set_sort_order(Gtk.SortType.ASCENDING)
383
        model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
384
        treeview.append_column(column_component)
385
 
386
        # Treeview properties
387
        treeview.set_can_focus(False)
388
        treeview.set_enable_tree_lines(True)
389
        treeview.set_headers_visible(True)
390
        treeview.set_enable_search(True)
391
        treeview.set_hover_selection(False)
392
        treeview.set_grid_lines(Gtk.TreeViewGridLines.NONE)
393
        treeview.set_enable_tree_lines(True)
394
        treeview.set_level_indentation(10)
395
 
396
        # TreeView sorting
397
        def sort_function(model, row1, row2, user_data):
398
            sort_column = 0
399
 
400
            value1 = model.get_value(row1, sort_column)
401
            value2 = model.get_value(row2, sort_column)
402
 
403
            if value1 < value2:
404
                return -1
405
            elif value1 == value2:
406
                return 0
407
            else:
408
                return 1
409
 
410
        self.sorted_model = Gtk.TreeModelSort(model=model)
411
        self.sorted_model.set_sort_func(0, sort_function, None)
412
 
413
        # Selection
414
        selection = treeview.get_selection()
415
        selection.set_mode(Gtk.SelectionMode.NONE)
416
 
417
        # Set model (filtered and sorted)
418
        treeview.set_model(self.sorted_model)
419
 
420
        for sid in lsid:
421
            ssid = str(int(sid))
422
            title = self.srvdtb.get_title(sid)
423
            component = self.srvdtb.get_component(sid)
424
            model.append([ssid, escape(title), component])
425
 
426
        box.show_all()
427
 
428
        return box