Subversion Repositories basico

Compare Revisions

Ignore whitespace Rev 373 → Rev 374

/branches/BR-0.4/basico/basico.py
29,8 → 29,8
from basico.services.srv_attachment import Attachment
from basico.services.srv_notify import Notification
from basico.services.srv_asciidoctor import Asciidoctor
from basico.widgets.wdg_splash import Splash
 
 
#DOC: http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk
signal.signal(signal.SIGINT, signal.SIG_DFL)
 
42,11 → 42,21
"""
Basico class
"""
 
self.setup_splash()
self.setup_environment()
self.setup_logging()
self.setup_services()
 
 
def get_splash(self):
return self.splash
 
 
def setup_splash(self):
self.splash = Splash(title="Basico\n0.4", font='Roboto Slab 18', font_weight='bold', font_color="#FFFFFF", background_image=FILE['SPLASH'])
self.splash.start()
 
def setup_environment(self):
"""
Setup Basico environment
53,7 → 63,7
"""
# Add webdriver path to System PATH
os.environ["PATH"] += os.pathsep + LPATH['DRIVERS']
 
# Create local paths if they do not exist
for entry in LPATH:
if not os.path.exists(LPATH[entry]):
68,8 → 78,8
if os.path.exists(FILE['LOG']):
with open(FILE['LOG'], 'w') as flog:
pass
#Initialize logging
 
#Initialize logging
self.log = get_logger(__class__.__name__)
self.log.info("Basico %s started", APP['version'])
self.log.debug("Global path: %s", GPATH['ROOT'])
82,7 → 92,7
"""
Setup Basico Services
"""
 
# Declare and register services
self.services = {}
try:
151,6 → 161,7
(if any) to finalize them properly.
"""
 
self.splash.show()
# Deregister all services loaded starting by the GUI service
self.deregister_service('GUI')
for name in self.services:
160,6 → 171,7
except Exception as error:
self.log.error(error)
raise
self.splash.destroy()
self.log.info("Basico %s finished", APP['version'])
 
 
/branches/BR-0.4/basico/core/mod_env.py
64,6 → 64,7
GPATH['DOC'] = GPATH['SHARE'] + 'docs' + SEP
GPATH['RES'] = GPATH['DATA'] + 'res' + SEP
GPATH['CSS'] = GPATH['RES'] + 'css' + SEP
GPATH['SPLASH'] = GPATH['RES'] + 'splash' + SEP
GPATH['SELENIUM'] = GPATH['RES'] + 'selenium' + SEP
GPATH['DRIVERS'] = GPATH['SELENIUM'] + 'drivers' + SEP
GPATH['HELP'] = GPATH['DATA'] + 'help' + SEP
80,6 → 81,7
FILE['EVENTS'] = LPATH['LOG'] + 'events.log'
FILE['CREDITS'] = GPATH['DOC'] + 'CREDITS'
FILE['HELP_INDEX'] = GPATH['HELP_HTML'] + 'index.html'
FILE['SPLASH'] = GPATH['SPLASH'] + 'basico-splash-400x250.png'
 
# Annotations
ATYPES = ['Bookmark', 'Email', 'Fixme', 'Incident', 'Meeting', 'Note', 'Procedure', 'Snippet', 'Template', 'Todo']
/branches/BR-0.4/basico/core/mod_srv.py
32,6 → 32,7
 
self.started = False
 
 
def is_started(self):
"""Return True or False if service is running / not running
"""
123,3 → 124,7
def get_config(self):
self.srvstg = self.get_service('Settings')
return self.srvstg.load()
 
 
def get_splash(self):
return self.app.get_splash()
/branches/BR-0.4/basico/core/mod_wdg.py
29,6 → 29,7
 
self.log = get_logger(logname)
self.init_section(logname)
self.log.debug("Loading widget: %s", logname)
 
 
def get_traceback(self):
/branches/BR-0.4/basico/core/mod_win.py
47,18 → 47,18
self.srvgui.add_widget('uiapp', uiapp)
self.app = self.srvgui.get_app()
self.setup_window(uiapp)
self.setup_widgets()
self.setup_widgets()
self.run()
 
 
def get_services(self):
self.srvbnr = self.controller.get_service("BNR")
# ~ self.srvbnr = self.controller.get_service("BNR")
self.srvgui = self.controller.get_service("GUI")
self.srvdtb = self.controller.get_service("DB")
# ~ self.srvdtb = self.controller.get_service("DB")
self.srvuif = self.controller.get_service("UIF")
self.srvicm = self.controller.get_service('IM')
self.srvclb = self.controller.get_service('Callbacks')
self.srvant = self.controller.get_service('Annotation')
# ~ self.srvant = self.controller.get_service('Annotation')
 
 
def setup_controller(self, uiapp):
68,7 → 68,7
def get_signal(self, signal):
return self.signals[key]
 
 
def setup_window(self, uiapp):
Gtk.Window.__init__(self, title=APP['name'], application=uiapp)
icon = self.srvicm.get_icon('basico-component', 48, 48)
90,12 → 90,12
css_provider.load_from_path(FILE['CSS'])
context = Gtk.StyleContext()
context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
 
self.maximize ()
self.setup_headerbar()
self.show_all()
 
 
def setup_headerbar(self):
hb = self.srvgui.add_widget('gtk_headerbar_container', Gtk.HeaderBar())
hb.set_show_close_button(True)
254,7 → 254,7
button_restore.connect('clicked', self.srvclb.gui_database_restore)
# ~ button_cache = self.srvuif.create_button('basico-restore', 48, 48, '<b>Restore from cache</b>')
# ~ button_cache.connect('clicked', self.srvbnr.restore_from_cache)
 
box_bnr.pack_start(button_restore, False, False, 0)
# ~ box_bnr.pack_start(button_cache, False, False, 0)
 
298,7 → 298,7
## left pane
paned.add1(notebook_menuview)
notebook_menuview.show_all()
 
## Right pane
 
vpaned = self.srvgui.add_widget('gtk_vpaned_visor', Gtk.VPaned())
305,7 → 305,7
vpaned.set_property('margin-bottom', 6)
vpaned.set_wide_handle(True)
vpaned.set_position(0)
 
box = Gtk.VBox()
box.set_hexpand(True)
 
335,12 → 335,12
## Annotation widget (down)
boxannotations = self.srvgui.add_widget('gtk_vbox_container_annotations', Gtk.VBox())
self.srvuif.set_widget_visibility('gtk_vbox_container_annotations', False)
widget_annotation = self.srvgui.add_widget('widget_annotation', AnnotationWidget(self.controller))
widget_annotation = self.srvgui.add_widget('widget_annotation', AnnotationWidget(self.controller))
boxannotations.add(widget_annotation) # <--
 
vpaned.add1(box)
vpaned.add2(boxannotations)
 
paned.add2(vpaned)
mainbox.pack_start(paned, True, True, 0)
 
404,7 → 404,7
# ~ visor_annotations_page.set_hexpand(True)
# ~ tab_widget = self.srvuif.create_notebook_tab_label('basico-annotation', '<b>Annotations</b>')
# ~ notebook.append_page(visor_annotations_page, tab_widget)
 
# ~ if self.srvuif.webkit_support():
# ~ visor_help_page = self.srvgui.add_widget('gtk_notebook_help_page', self.setup_tab_help_visor())
# ~ visor_help_page.set_hexpand(True)
504,8 → 504,8
visor_attachments.show_all()
box.show_all()
return box
 
 
def setup_tab_menuview_sapnotes(self):
## Left view - SAP Notes Menu view
box = self.srvgui.add_widget('gtk_vbox_container_menu_view', Gtk.VBox())
636,7 → 636,7
 
separator = Gtk.Separator()
vbox_main.pack_start(separator, False, False, 6)
 
# Categories
button = self.srvgui.add_widget('gtk_togglebutton_categories', Gtk.ToggleButton())
button.set_relief(Gtk.ReliefStyle.NONE)
661,7 → 661,7
 
revealer.add(vbox_revealer)
vbox_main.pack_start(revealer, False, False, 6)
 
# Types
button = self.srvgui.add_widget('gtk_togglebutton_types', Gtk.ToggleButton())
button.set_relief(Gtk.ReliefStyle.NONE)
710,8 → 710,8
def setup_tab_menuview_annotations_preview(self):
vbox_main = Gtk.VBox()
return vbox_main
 
 
def setup_stack_about(self):
box = Gtk.VBox()
box.set_hexpand(True)
740,7 → 740,7
 
 
# ~ def setup_stack_annotation(self):
# ~ return self.srvgui.add_widget('widget_annotation', AnnotationWidget(self.controller))
# ~ return self.srvgui.add_widget('widget_annotation', AnnotationWidget(self.controller))
 
 
def run(self):
/branches/BR-0.4/basico/data/res/splash/basico-splash-400x250.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/BR-0.4/basico/data/res/splash/basico-splash-400x250.png
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: branches/BR-0.4/basico/services/srv_database.py
===================================================================
--- branches/BR-0.4/basico/services/srv_database.py (revision 373)
+++ branches/BR-0.4/basico/services/srv_database.py (revision 374)
@@ -46,8 +46,8 @@
except:
settings[self.section]['DBSAP'] = FILE['DBSAP']
self.srvstg.save(settings)
-
+
def get_services(self):
self.srvclt = self.get_service('Collections')
@@ -192,8 +192,8 @@
n += 1
self.save_notes()
return n
-
+
def get_notes(self):
'''
Return all sapnotes
@@ -380,7 +380,7 @@
continue
if cid not in new_cols:
new_cols.append(cid)
- self.log.info("\tCollection: %s", self.srvclt.get_name_by_cid(cid))
+ self.log.info("\tCollection: %s", self.srvclt.get_name_by_cid(cid))
else:
current_collections = self.sapnotes[sid]['collections']
current_collections.extend(collections)
@@ -390,13 +390,13 @@
continue
if cid not in bag:
bag.append(cid)
- self.log.info("\tCollection: %s", self.srvclt.get_name_by_cid(cid))
+ self.log.info("\tCollection: %s", self.srvclt.get_name_by_cid(cid))
self.sapnotes[sid]['collections'] = bag
self.save_notes()
except:
self.log.error(error)
-
+
def delete(self, sid):
sid = self.normalize_sid(sid)
deleted = False
/branches/BR-0.4/basico/services/srv_gui.py
16,6 → 16,7
from basico.core.mod_srv import Service
from basico.core.mod_win import GtkAppWindow
from basico.core.mod_log import get_logger
# ~ from basico.widgets.wdg_splash import Splash
 
 
class UIApp(Gtk.Application):
45,12 → 46,18
self.my_app_settings = "Primary application instance."
self.window = self.srvgui.add_widget('gtk_app_window_main', GtkAppWindow(self))
self.window.connect("delete-event", self.srvgui.quit)
# ~ db = self.app.get_service('DB')
# ~ gui = self.app.get_service('GUI')
# ~ db.load_notes()
# ~ visor_sapnotes = gui.get_widget('visor_sapnotes')
# ~ visor_sapnotes.populate()
self.log.debug("New Basico instance created")
self.srvuif.statusbar_msg("Welcome to Basico", True)
else:
self.log.debug("Basico is already running!")
splash = self.app.get_splash()
splash.hide()
 
 
def get_services(self):
"""
Missing method docstring (missing-docstring)
88,7 → 95,8
"""
Setup GUI Service
"""
self.srvsap = self.get_service('SAP')
pass
# ~ self.srvsap = self.get_service('SAP')
 
 
def run(self):
95,10 → 103,12
"""
Let GUI service start
"""
GObject.threads_init()
# ~ GObject.threads_init()
self.uiapp = UIApp(self.app)
self.log.debug("Setting up GUI")
window = self.get_window()
# ~ splash = self.app.get_splash()
# ~ splash.start()
self.uiapp.run()
 
 
178,8 → 188,8
return self.signals[signal_name]
except KeyError:
return None
 
 
def add_widget(self, name, obj=None):
"""
Add widget to cache
/branches/BR-0.4/basico/services/srv_uif.py
25,7 → 25,7
self.srvgui = self.get_service('GUI')
self.srvclb = self.get_service('Callbacks')
self.srvicm = self.get_service('IM')
self.srvdtb = self.get_service('DB')
# ~ self.srvdtb = self.get_service('DB')
self.srvant = self.get_service('Annotation')
self.srvutl = self.get_service('Utils')
self.srvntf = self.get_service('Notify')
69,13 → 69,13
return dialog
 
 
def statusbar_msg(self, message, important=False):
def statusbar_msg(self, message, important=False):
statusbar = self.srvgui.get_widget('widget_statusbar')
htimestamp = self.srvutl.get_human_date_from_timestamp()
msg = htimestamp + '\t-\t' + message
if statusbar is not None:
# Maybe the widget hasn't been created yet
statusbar.message(msg)
statusbar.message(msg)
if important:
self.srvntf.show(htimestamp, message)
 
164,6 → 164,7
 
 
def warning_message_delete_sapnotes(self, widget, question, explanation, bag):
self.srvdtb = self.get_service('DB')
window = self.srvgui.get_widget('gtk_app_window_main')
icon = self.srvicm.get_new_image_icon('basico-delete', 96, 96)
icon.show_all()
252,6 → 253,7
 
 
def action_collection_copy_to_clipboard(self, button):
self.srvdtb = self.get_service('DB')
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
 
314,4 → 316,4
dialog.destroy()
return folder
 
 
/branches/BR-0.4/basico/services/srv_utils.py
7,7 → 7,7
# Description: Generic functions service
"""
 
import os
import os
import re
import sys
import json
41,9 → 41,10
"""
Missing method docstring (missing-docstring)
"""
self.srvdtb = self.get_service('DB')
# ~ self.srvdtb = self.get_service('DB')
pass
 
 
def get_file_metadata(self, path):
self.log.debug("Getting metadata from: %s", path)
metadata = {}
93,8 → 94,8
title = '%s.%s' % (basename, extension)
self.log.debug("\tTitle: %s", title)
return title
 
 
def get_file_mimetype(self, path):
mimetype, val = Gio.content_type_guess('filename=%s' % path, data=None)
return mimetype
157,13 → 158,13
elif integer_bytes > 1024*1024*1024 and integer_bytes < (1024*1024*1024*1024):
return "%d Gb" % self.get_gigabytes(integer_bytes)
 
 
def get_disk_usage_human(self, path):
"""
Get disk usage as a fraction for using with Gtk.Progressbar)
Some bytes borrowed from:
https://github.com/juancarlospaco/anglerfish/blob/master/anglerfish/bytes2human.py
"""
"""
total, used, free = self.get_disk_usage(path)
tgb = self.get_gigabytes(total)
ugb = self.get_gigabytes(used)
195,13 → 196,13
"""
if timestamp is None:
timestamp = self.timestamp()
 
adate = self.get_datetime(timestamp)
return "%s" % adate.strftime("%Y/%m/%d %H:%M")
 
 
def get_excel_date(self, timestamp):
timestamp = timestamp.replace('-', '/')
timestamp = timestamp.replace('-', '/')
timestamp = timestamp.replace('T', ' ')
adate = datetime.strptime(timestamp, "%Y/%m/%d %H:%M:%S")
excel_date = "%s" % adate.strftime("%d/%m/%Y")
/branches/BR-0.4/basico/widgets/wdg_cols.py
20,10 → 20,10
"""
Missing class docstring (missing-docstring)
"""
def __init__(self, app, sid, overwrite=False):
def __init__(self, app, sid, overwrite=False):
super().__init__(app, __class__.__name__)
Gtk.VBox.__init__(self)
self.sid = sid
self.sid = sid
self.current_cid = None
self.overwrite = overwrite
self.log.debug("CollectionsMgtView widget overwrite mode is %s", overwrite)
61,7 → 61,7
if self.sid == '0000000000':
title.set_markup('<big><b>Manage collections</b></big>')
elif self.sid == 'view':
title.set_markup('<big><b>Manage collections for this view</b></big>')
title.set_markup('<big><b>Manage collections for this view</b></big>')
else:
title.set_markup('<big><b>Collections for SAP Note %s</b></big>' % str(int(self.sid)))
title.set_xalign(0.0)
172,7 → 172,7
self.trv_signal_changed = self.selection.connect('changed', self.row_changed)
 
# Filter
# ~ self.visible_filter = self.model.filter_new()
# ~ self.visible_filter = self.sorted_model.filter_new()
# ~ self.visible_filter.set_visible_func(self.visible_function)
# ~ treeview.set_model(self.visible_filter)
 
208,7 → 208,7
self.log.debug("Collection to be linked: %s (%s)", self.srvclt.get_name_by_cid(cid), cid)
 
self.model.foreach(get_linked_collections)
 
if len(selected) == 0:
selected.append(COL_DOWNLOADED)
 
222,15 → 222,15
for sid in bag:
self.srvdtb.set_collections(sid, selected, self.overwrite)
self.srvuif.statusbar_msg("Selected collections linked to all SAP Note in this view", True)
 
visor_sapnotes = self.srvgui.get_widget('visor_sapnotes')
visor_sapnotes.populate()
viewmenu = self.srvgui.get_widget('viewmenu')
viewmenu.populate()
viewmenu.grab_focus()
 
 
 
def row_changed(self, selection):
"""
Missing method docstring (missing-docstring)
256,9 → 256,9
 
if entry is not None and isinstance(entry, Gtk.Entry):
name = entry.get_text()
res, msg = self.srvclt.create(name)
res, msg = self.srvclt.create(name)
self.srvuif.statusbar_msg(msg, True)
 
self.model.clear()
collections = self.srvclt.get_all()
if len(collections) > 0:
271,8 → 271,8
self.current_cid = None
 
self.srvuif.statusbar_msg("Collections updated")
 
 
def delete(self, button):
"""
Missing method docstring (missing-docstring)
309,6 → 309,7
text = entry.get_text()
title = model.get(itr, 2)[0]
match = text.upper() in title.upper()
self.log.debug("%s in %s is %s", text.upper(), title.upper(), match)
return match
 
 
316,8 → 317,8
entry = self.srvgui.get_widget('gtk_entry_collection_new')
filter = entry.get_text()
selection = self.treeview.get_selection()
# ~ self.visible_filter.refilter()
 
 
def gui_iterate_over_data(model, path, itr):
title = self.sorted_model.get(itr, 2)[0]
if len(filter) > 0:
339,7 → 340,7
if cid == COL_DOWNLOADED:
self.srvuif.statusbar_msg("You can't rename this collection")
return
 
name_old = self.srvclt.get_name_by_cid(cid)
iter_has_child = model.iter_has_child(treeiter)
 
/branches/BR-0.4/basico/widgets/wdg_menuview.py
678,7 → 678,7
scomp = set()
dcomp = {}
self.model.clear()
 
# Add Downloaded collection
cid = self.srvclt.get_cid_by_name('Downloaded')
count = len(self.srvdtb.get_notes_by_node('collection', cid))
/branches/BR-0.4/basico/widgets/wdg_splash.py
0,0 → 1,143
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
# File: setup.py
# Author: Tomás Vírseda
# License: GPL v3
# Description: setup.py tells you that the module/package you are about
# to install has been packaged and distributed with Distutils, which is
# the standard for distributing Python Modules.
#
# !!!
# Code borrowed from: https://github.com/SolydXK/solydxk-system/blob/origin/master/usr/lib/solydxk/system/splash.py
# !!!
#
"""
 
# ====================================================================
# Class to show a splash screen while application is loading
# ====================================================================
# Initiate the splash screen:
# from splash import Splash
# splash = Splash(title='Splash Screen')
# Other arguments: width, height, font, font_weight, font_color, background_color, background_image.
# width and height are ignored when background_image is used.
# background_color is ignored when background_image is provided.
# font can be the font name with size: font='Roboto Slab 18', or only the size in which it will use the system default font.
# font_weight can be ultralight, light, normal, bold, ultrabold, heavy, or a numeric weight.
#
# Start the splash screen:
# splash.start()
#
# When done:
# splash.destroy()
#
# Note: you can hide and show the splash screen when needed:
# splash.hide()
# splash.show()
# ====================================================================
 
# Make sure the right Gtk version is loaded
import gi
gi.require_version('Gtk', '3.0')
 
# from gi.repository import Gtk, GdkPixbuf, GObject, Pango, Gdk
import time
from gi.repository import Gtk, Gdk
from threading import Thread
from os.path import exists
from basico.core.mod_log import get_logger
 
 
class Splash(Thread):
def __init__(self, title, width=400, height=250, font=16, font_weight='normal', font_color='000000', background_color='ffffff', background_image=None):
Thread.__init__(self)
self.log = get_logger(__class__.__name__)
self.title = title
self.width = width
self.height = height
self.font = font
self.font_weight = font_weight
self.font_color = self.prep_hex_color(font_color)
self.background_image = '' if background_image is None else background_image
 
# Window settings
self.window = Gtk.Window(Gtk.WindowType.POPUP)
self.window.set_type_hint(Gdk.WindowTypeHint.SPLASHSCREEN)
self.window.set_position(Gtk.WindowPosition.CENTER)
self.window.set_title(self.title)
 
# Create overlay with a background image
overlay = Gtk.Overlay()
self.window.add(overlay)
if exists(self.background_image):
# Window will adjust to image size automatically
bg = Gtk.Image.new_from_file(self.background_image)
overlay.add(bg)
else:
# Set window dimensions
self.window.set_default_size(self.width, self.height)
# Set background color
self.window.override_background_color(Gtk.StateType.NORMAL,
self.hex_to_rgba(background_color, True))
 
# Add box with label
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.set_margin_top(self.height / 3)
box.set_margin_left(20)
box.set_margin_right(20)
# Add the box to a new overlay in the existing overlay
overlay.add_overlay(box)
lbl_title = Gtk.Label()
lbl_title.set_line_wrap(True)
lbl_title.set_justify(Gtk.Justification.CENTER)
# Markup format: https://developer.gnome.org/pango/stable/PangoMarkupFormat.html
lbl_title.set_markup('<span font="{}" color="#{}" weight="{}">{}</span>'.format(self.font,
self.font_color,
self.font_weight,
self.title))
box.pack_start(lbl_title, False, True, 0)
 
def run(self):
# Show the splash screen
self.window.show_all()
# Without this ugly one-liner, the window won't show
while Gtk.events_pending(): Gtk.main_iteration()
self.log.debug("Show the splash screen")
 
 
def prep_hex_color(self, hex_color):
hex_color = hex_color.strip('#')
# Fill up with last character until length is 6 characters
if len(hex_color) < 6:
hex_color = hex_color.ljust(6, hex_color[-1])
# Add alpha channel if it's not there
hex_color = hex_color.ljust(8, 'f')
return hex_color
 
def hex_to_rgba(self, hex_color, as_gdk_rgba=False):
hex_color = self.prep_hex_color(hex_color)
# Create a list with rgba values from hex_color
rgba = list(int(hex_color[i : i + 2], 16) for i in (0, 2 ,4, 6))
if as_gdk_rgba:
# Change values to float between 0 and 1 for Gdk.RGBA
for i, val in enumerate(rgba):
if val > 0:
rgba[i] = 1 / (255 / val)
# Return the Gdk.RGBA object
return Gdk.RGBA(rgba[0], rgba[1], rgba[2], rgba[3])
return rgba
 
def show(self):
self.window.show()
# ~ self.log.debug("Show the splash screen")
# ~ time.sleep(3)
 
def hide(self):
self.window.hide()
# ~ self.log.debug("Hide the splash screen")
 
def destroy(self):
while Gtk.events_pending(): Gtk.main_iteration()
self.window.destroy()
self.log.debug("Hide the splash screen")
/branches/BR-0.4/setup.py
45,6 → 45,10
'basico/data/res/css/basico.css',
'basico/data/res/css/custom-asciidoc.css',
]),
('basico/data/res/splash',
[
'basico/data/res/splash/basico-splash-400x250.png',
]),
('basico/data/tpl', ['basico/data/tpl/report.html']),
('basico/data/icons',
[