diff cagou/core/cagou_main.py @ 220:24f8ab7c08be

core: implemented showDialog so message/dialogs from QuickFrontend are displayed
author Goffi <goffi@goffi.org>
date Tue, 26 Jun 2018 07:11:16 +0200
parents c5c1dd7f88e1
children e702228b655a
line wrap: on
line diff
--- a/cagou/core/cagou_main.py	Sun Jun 24 22:26:15 2018 +0200
+++ b/cagou/core/cagou_main.py	Tue Jun 26 07:11:16 2018 +0200
@@ -50,7 +50,8 @@
 from kivy.uix.label import Label
 from kivy.uix.boxlayout import BoxLayout
 from kivy.uix.floatlayout import FloatLayout
-from kivy.uix.screenmanager import ScreenManager, Screen, FallOutTransition, RiseInTransition
+from kivy.uix.screenmanager import (ScreenManager, Screen,
+                                    FallOutTransition, RiseInTransition)
 from kivy.uix.dropdown import DropDown
 from kivy.core.window import Window
 from kivy.animation import Animation
@@ -59,6 +60,7 @@
 from . import widgets_handler
 from .common import IconButton
 from . import menu
+from . import dialog
 from importlib import import_module
 import os.path
 import glob
@@ -99,13 +101,15 @@
 class Note(Label):
     title = properties.StringProperty()
     message = properties.StringProperty()
-    level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT, options=list(C.XMLUI_DATA_LVLS))
+    level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT,
+                                      options=list(C.XMLUI_DATA_LVLS))
 
 
 class NoteDrop(Label):
     title = properties.StringProperty()
     message = properties.StringProperty()
-    level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT, options=list(C.XMLUI_DATA_LVLS))
+    level = properties.OptionProperty(C.XMLUI_DATA_LVL_DEFAULT,
+                                      options=list(C.XMLUI_DATA_LVLS))
 
 
 class NotesDrop(DropDown):
@@ -137,6 +141,11 @@
         self.notes_drop = NotesDrop(self.notes)
 
     def addNotif(self, callback, *args, **kwargs):
+        """add a notification with a callback attached
+
+        when notification is pressed, callback is called
+        @param *args, **kwargs: arguments of callback
+        """
         self.notifs_icon.addNotif(callback, *args, **kwargs)
 
     def addNote(self, title, message, level):
@@ -149,6 +158,10 @@
     def addNotifUI(self, ui):
         self.notifs_icon.addNotif(ui.show, force=True)
 
+    def addNotifWidget(self, widget):
+        app = App.get_running_app()
+        self.notifs_icon.addNotif(app.host.showExtraUI, widget=widget)
+
     def _displayNextNote(self, dummy=None):
         screen = Screen()
         try:
@@ -229,6 +242,9 @@
     def addNotifUI(self, ui):
         self.head_widget.addNotifUI(ui)
 
+    def addNotifWidget(self, widget):
+        self.head_widget.addNotifWidget(widget)
+
 
 class CagouApp(App):
     """Kivy App for Cagou"""
@@ -269,8 +285,9 @@
 
     def on_start(self):
         if sys.platform == "android":
-            # XXX: we use memory map instead of bridge because if we try to call a bridge method
-            #      in on_pause method, the call data  is not written before the actual pause
+            # XXX: we use memory map instead of bridge because if we
+            #      try to call a bridge method in on_pause method, the call data
+            #      is not written before the actual pause
             # we create a memory map on .cagou_status file with a 1 byte status
             # status is:
             # R => running
@@ -280,7 +297,8 @@
             self.cagou_status_fd = open('.cagou_status', 'wb+')
             self.cagou_status_fd.write('R')
             self.cagou_status_fd.flush()
-            self.cagou_status = mmap.mmap(self.cagou_status_fd.fileno(), 1, prot=mmap.PROT_WRITE)
+            self.cagou_status = mmap.mmap(self.cagou_status_fd.fileno(), 1,
+                                          prot=mmap.PROT_WRITE)
 
     def on_pause(self):
         self.cagou_status[0] = 'P'
@@ -347,19 +365,25 @@
             sys.exit(3)
         else:
             log.debug(u"Loading {} bridge".format(bridge_name))
-        super(Cagou, self).__init__(bridge_factory=bridge_module.Bridge, xmlui=xmlui, check_options=quick_utils.check_options, connect_bridge=False)
+        super(Cagou, self).__init__(bridge_factory=bridge_module.Bridge,
+                                    xmlui=xmlui,
+                                    check_options=quick_utils.check_options,
+                                    connect_bridge=False)
         self._import_kv()
         self.app = CagouApp()
         self.app.host = self
-        self.media_dir = self.app.media_dir = config.getConfig(main_config, '', 'media_dir')
-        self.downloads_dir = self.app.downloads_dir = config.getConfig(main_config, '', 'downloads_dir')
+        self.media_dir = self.app.media_dir = config.getConfig(main_config, '',
+                                                               'media_dir')
+        self.downloads_dir = self.app.downloads_dir = config.getConfig(main_config, '',
+                                                                       'downloads_dir')
         if not os.path.exists(self.downloads_dir):
             try:
                 os.makedirs(self.downloads_dir)
             except OSError as e:
                 log.warnings(_(u"Can't create downloads dir: {reason}").format(reason=e))
         self.app.default_avatar = os.path.join(self.media_dir, "misc/default_avatar.png")
-        self.app.icon = os.path.join(self.media_dir, "icons/muchoslava/png/cagou_profil_bleu_96.png")
+        self.app.icon = os.path.join(self.media_dir,
+                                     "icons/muchoslava/png/cagou_profil_bleu_96.png")
         self._plg_wids = []  # main widgets plugins
         self._plg_wids_transfer = []  # transfer widgets plugins
         self._import_plugins()
@@ -423,7 +447,10 @@
         @param profiles(iterable): list of profiles
         """
         main_cls = plugin_info['main']
-        return self.widgets.getOrCreateWidget(main_cls, target, on_new_widget=None, profiles=iter(self.profiles))
+        return self.widgets.getOrCreateWidget(main_cls,
+                                              target,
+                                              on_new_widget=None,
+                                              profiles=iter(self.profiles))
 
     def _defaultFactoryTransfer(self, plugin_info, callback, cancel_cb, profiles):
         """default factory used to create transfer widgets instances
@@ -463,9 +490,12 @@
         self.default_wid = None
         plugins_path = os.path.dirname(cagou.plugins.__file__)
         plugin_glob = u"plugin*." + C.PLUGIN_EXT
-        plug_lst = [os.path.splitext(p)[0] for p in map(os.path.basename, glob.glob(os.path.join(plugins_path, plugin_glob)))]
+        plug_lst = [os.path.splitext(p)[0] for p in
+                    map(os.path.basename, glob.glob(os.path.join(plugins_path,
+                                                                 plugin_glob)))]
 
-        imported_names_main = set()  # used to avoid loading 2 times plugin with same import name
+        imported_names_main = set()  # used to avoid loading 2 times
+                                     # plugin with same import name
         imported_names_transfer = set()
         for plug in plug_lst:
             plugin_path = 'cagou.plugins.' + plug
@@ -485,7 +515,8 @@
                 imported_names = imported_names_transfer
                 default_factory = self._defaultFactoryTransfer
             else:
-                log.error(u"unknown plugin type {type_} for plugin {file_}, skipping".format(
+                log.error(u"unknown plugin type {type_} for plugin {file_}, skipping"
+                    .format(
                     type_ = plugin_type,
                     file_ = plug
                     ))
@@ -503,18 +534,22 @@
 
             if 'platforms' in plugin_info:
                 if sys.platform not in plugin_info['platforms']:
-                    log.info(u"{plugin_file} is not used on this platform, skipping".format(**plugin_info))
+                    log.info(u"{plugin_file} is not used on this platform, skipping"
+                             .format(**plugin_info))
                     continue
 
             # import name is used to differentiate plugins
             if 'import_name' not in plugin_info:
                 plugin_info['import_name'] = plug
             if plugin_info['import_name'] in imported_names:
-                log.warning(_(u"there is already a plugin named {}, ignoring new one").format(plugin_info['import_name']))
+                log.warning(_(u"there is already a plugin named {}, "
+                              u"ignoring new one").format(plugin_info['import_name']))
                 continue
             if plugin_info['import_name'] == C.WID_SELECTOR:
                 if plugin_type != C.PLUG_TYPE_WID:
-                    log.error(u"{import_name} import name can only be used with {type_} type, skipping {name}".format(type_=C.PLUG_TYPE_WID, **plugin_info))
+                    log.error(u"{import_name} import name can only be used with {type_} "
+                              u"type, skipping {name}".format(type_=C.PLUG_TYPE_WID,
+                                                              **plugin_info))
                     continue
                 # if WidgetSelector exists, it will be our default widget
                 self.default_wid = plugin_info
@@ -634,7 +669,8 @@
                     break
 
         if to_change is None:
-            raise exceptions.InternalError(u"no CagouWidget found when trying to switch widget")
+            raise exceptions.InternalError(u"no CagouWidget found when "
+                                           u"trying to switch widget")
 
         wrapper = to_change.parent
         while wrapper is not None and not(isinstance(wrapper, widgets_handler.WHWrapper)):
@@ -677,7 +713,11 @@
         if widget.parent is None:
             return widget
         targets = list(widget.targets)
-        w = self.widgets.getOrCreateWidget(widget.__class__, targets[0], on_new_widget=None, on_existing_widget=C.WIDGET_RECREATE, profiles=widget.profiles)
+        w = self.widgets.getOrCreateWidget(widget.__class__,
+                                           targets[0],
+                                           on_new_widget=None,
+                                           on_existing_widget=C.WIDGET_RECREATE,
+                                           profiles=widget.profiles)
         for t in targets[1:]:
             w.addTarget(t)
         return w
@@ -687,7 +727,9 @@
     def _menusGetCb(self, backend_menus):
         main_menu = self.app.root.root_menus
         self.menus.addMenus(backend_menus)
-        self.menus.addMenu(C.MENU_GLOBAL, (_(u"Help"), _(u"About")), callback=main_menu.onAbout)
+        self.menus.addMenu(C.MENU_GLOBAL,
+                           (_(u"Help"), _(u"About")),
+                           callback=main_menu.onAbout)
         main_menu.update(C.MENU_GLOBAL)
 
     ## bridge handlers ##
@@ -706,9 +748,11 @@
         self.bridge.menusGet("", C.NO_SECURITY_LIMIT, callback=self._menusGetCb)
 
     def setPresenceStatus(self, show='', status=None, profile=C.PROF_KEY_NONE):
-        log.info(u"Profile presence status set to {show}/{status}".format(show=show, status=status))
+        log.info(u"Profile presence status set to {show}/{status}".format(show=show,
+                                                                          status=status))
 
-    def errback(self, failure_, title=_('error'), message=_(u'error while processing: {msg}')):
+    def errback(self, failure_, title=_('error'),
+                message=_(u'error while processing: {msg}')):
         self.addNote(title, message.format(msg=failure_), level=C.XMLUI_DATA_LVL_WARNING)
 
     def addNote(self, title, message, level=C.XMLUI_DATA_LVL_INFO):
@@ -722,6 +766,13 @@
         """
         self.app.root.addNotifUI(ui)
 
+    def addNotifWidget(self, widget):
+        """add a notification with a Kivy widget attached
+
+        @param widget(kivy.uix.Widget): widget to attach to notification
+        """
+        self.app.root.addNotifWidget(widget)
+
     def showUI(self, ui):
         """show a XMLUI"""
         self.app.root.changeWidget(ui, "xmlui")
@@ -738,10 +789,31 @@
     def getDefaultAvatar(self, entity=None):
         return self.app.default_avatar
 
+    def _dialog_cb(self, cb, *args, **kwargs):
+        """generic dialog callback
+
+        close dialog then call the callback with given arguments
+        """
+        def callback():
+            self.closeUI()
+            cb(*args, **kwargs)
+        return callback
+
     def showDialog(self, message, title, type="info", answer_cb=None, answer_data=None):
-        # TODO
-        log.info(u"FIXME: showDialog not implemented")
-        log.info(u"message: {} -- {}".format(title, message))
+        if type in ('info', 'warning', 'error'):
+            self.addNote(title, message, type)
+        elif type == "yes/no":
+            wid = dialog.ConfirmDialog(title=title, message=message,
+                                       yes_cb=self._dialog_cb(answer_cb,
+                                                              True,
+                                                              answer_data),
+                                       no_cb=self._dialog_cb(answer_cb,
+                                                             False,
+                                                             answer_data)
+                                       )
+            self.addNotifWidget(wid)
+        else:
+            log.warning(_(u"unknown dialog type: {dialog_type}").format(dialog_type=type))
 
 
     def desktop_notif(self, message, title=u'', duration=5000):