diff src/tools/xml_tools.py @ 1105:018bdd687747

core (XMLUI): Dialogs are now managemed in XMLUI: - currents dialogs are available: - Message: a classical informational/error message, usually a popup that user has to close after reading - Note: more discreet message, usually a notification with a timeout (user don't need to close manually) - Confirm: a Ok/Cancel or Yes/No dialog - File: a dialog to get a file or dir path - dialog_opt parameter is used to customise dialogs - submit_id is used in a similar way as for forms
author Goffi <goffi@goffi.org>
date Mon, 11 Aug 2014 19:10:24 +0200
parents 2cb30f46e560
children 7fcafc3206b1
line wrap: on
line diff
--- a/src/tools/xml_tools.py	Mon Aug 11 19:10:24 2014 +0200
+++ b/src/tools/xml_tools.py	Mon Aug 11 19:10:24 2014 +0200
@@ -18,6 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from sat.core.i18n import _
+from sat.core.constants import Const as C
 from sat.core.log import getLogger
 log = getLogger(__name__)
 from xml.dom import minidom, NotFoundErr
@@ -740,8 +741,8 @@
 
         @param xmlui
         @param options (list[string, tuple]): each option can be given as:
-                                              - a string if the label and the value are the same
-                                              - a couple if the label and the value differ
+            - a string if the label and the value are the same
+            - a couple if the label and the value differ
         @param selected (list[string]): list of the selected values
         @param style (string)
         @param name (string)
@@ -772,35 +773,108 @@
             OptionElement(self, option, value in selected)
 
 
+## Dialog Elements ##
+
+
+class DialogElement(Element):
+    """Main dialog element """
+    type = 'dialog'
+
+    def __init__(self, parent, type_, level=None):
+        if not isinstance(parent, TopElement):
+            raise exceptions.DataError(_("DialogElement must be a direct child of TopElement"))
+        super(DialogElement, self).__init__(parent.xmlui, parent)
+        self.elem.setAttribute(C.XMLUI_DATA_TYPE, type_)
+        self.elem.setAttribute(C.XMLUI_DATA_LVL, level or C.XMLUI_DATA_LVL_DEFAULT)
+
+
+class MessageElement(Element):
+    """Element with the instruction message"""
+    type = C.XMLUI_DATA_MESS
+
+    def __init__(self, parent, message):
+        if not isinstance(parent, DialogElement):
+            raise exceptions.DataError(_("MessageElement must be a direct child of DialogElement"))
+        super(MessageElement, self).__init__(parent.xmlui, parent)
+        message_txt = self.xmlui.doc.createTextNode(message)
+        self.elem.appendChild(message_txt)
+
+
+class ButtonsElement(Element):
+    """Buttons element which indicate which set to use"""
+    type = 'buttons'
+
+    def __init__(self, parent, set_):
+        if not isinstance(parent, DialogElement):
+            raise exceptions.DataError(_("ButtonsElement must be a direct child of DialogElement"))
+        super(ButtonsElement, self).__init__(parent.xmlui, parent)
+        self.elem.setAttribute('set', set_)
+
+
+class FileElement(Element):
+    """File element used for FileDialog"""
+    type = 'file'
+
+    def __init__(self, parent, type_):
+        if not isinstance(parent, DialogElement):
+            raise exceptions.DataError(_("FileElement must be a direct child of DialogElement"))
+        super(FileElement, self).__init__(parent.xmlui, parent)
+        self.elem.setAttribute('type', type_)
+
+
 ## XMLUI main class
 
 
 class XMLUI(object):
     """This class is used to create a user interface (form/window/parameters/etc) using SàT XML"""
 
-    def __init__(self, panel_type="window", container="vertical", title=None, submit_id=None, session_id=None):
+    def __init__(self, panel_type="window", container="vertical", dialog_opt=None, title=None, submit_id=None, session_id=None):
         """Init SàT XML Panel
+
         @param panel_type: one of
-            - window (new window)
-            - popup
-            - form (formulaire, depend of the frontend, usually a panel with cancel/submit buttons)
-            - param (parameters, presentation depend of the frontend)
+            - C.XMLUI_WINDOW (new window)
+            - C.XMLUI_POPUP
+            - C.XMLUI_FORM (formulaire, depend of the frontend, usually a panel with cancel/submit buttons)
+            - C.XMLUI_PARAM (parameters, presentation depend of the frontend)
+            - C.XMLUI_DIALOG (one common dialog, presentation depend of frontend)
         @param container: disposition of elements, one of:
             - vertical: elements are disposed up to bottom
             - horizontal: elements are disposed left to right
             - pairs: elements come on two aligned columns
               (usually one for a label, the next for the element)
             - tabs: elemens are in categories with tabs (notebook)
+        @param dialog_opt: only used if panel_type == C.XMLUI_DIALOG. Dictionnary (string/string) where key can be:
+            - C.XMLUI_DATA_TYPE: type of dialog, value can be:
+                - C.XMLUI_DIALOG_MESSAGE (default): an information/error message. Action of user is necessary to close the dialog. Usually the frontend display a classic popup
+                - C.XMLUI_DIALOG_NOTE: like a C.XMLUI_DIALOG_MESSAGE, but action of user is not necessary to close, at frontend choice (it can be closed after a timeout). Usually the frontend display as a timed out notification
+                - C.XMLUI_DIALOG_CONFIRM: dialog with 2 choices (usualy "Ok"/"Cancel").
+                    returned data can contain:
+                        - "answer": "true" if answer is "ok", "yes" or equivalent, "false" else
+                - C.XLMUI_DIALOG_FILE: a file selection dialog
+                    returned data can contain:
+                        - "cancelled": "true" if dialog has been cancelled, not present or "false" else
+                        - "path": path of the choosed file/dir
+            - C.XMLUI_DATA_MESS: message shown in dialog
+            - C.XMLUI_DATA_LVL: one of:
+                - C.XMLUI_DATA_LVL_INFO (default): normal message
+                - C.XMLUI_DATA_LVL_WARNING: attention of user is important
+                - C.XMLUI_DATA_LVL_ERROR: something went wrong
+            - C.XMLUI_DATA_BTNS_SET: one of:
+                - C.XMLUI_DATA_BTNS_SET_OKCANCEL (default): classical "OK" and "Cancel" set
+                - C.XMLUI_DATA_BTNS_SET_YESNO: a translated "yes" for OK, and "no" for Cancel
         @param title: title or default if None
-        @param submit_id: callback id to call for panel_type we can submit (form, param)
+        @param submit_id: callback id to call for panel_type we can submit (form, param, dialog)
+        @param session_id: use to keep a session attached to the dialog, must be returned by frontends
         """
         self._introspect()
-        if panel_type not in ['window', 'form', 'param', 'popup']:
+        if panel_type not in [C.XMLUI_WINDOW, C.XMLUI_FORM, C.XMLUI_PARAM, C.XMLUI_POPUP, C.XMLUI_DIALOG]:
             raise exceptions.DataError(_("Unknown panel type [%s]") % panel_type)
-        if panel_type == 'form' and submit_id is None:
+        if panel_type == C.XMLUI_FORM and submit_id is None:
             raise exceptions.DataError(_("form XMLUI need a submit_id"))
         if not isinstance(container, basestring):
             raise exceptions.DataError(_("container argument must be a string"))
+        if dialog_opt is not None and panel_type != C.XMLUI_DIALOG:
+            raise exceptions.DataError(_("dialog_opt can only be used with dialog panels"))
         self.type = panel_type
         impl = minidom.getDOMImplementation()
 
@@ -811,6 +885,11 @@
             top_element.setAttribute("title", title)
         self.submit_id = submit_id
         self.session_id = session_id
+        if panel_type == C.XMLUI_DIALOG:
+            if dialog_opt is None:
+                dialog_opt = {}
+            self._createDialog(dialog_opt)
+            return
         self.main_container  = self._createContainer(container, TopElement(self))
         self.current_container = self.main_container
 
@@ -836,6 +915,8 @@
 
     def __getattr__(self, name):
         if name.startswith("add") and name not in ('addWidget',): # addWidgetName(...) create an instance of WidgetName
+            if self.type == C.XMLUI_DIALOG:
+                raise exceptions.InternalError(_("addXXX can't be used with dialogs"))
             class_name = name[3:]+"Widget"
             if class_name in globals():
                 cls = globals()[class_name]
@@ -886,6 +967,29 @@
         else:
             raise exceptions.DataError("session_id can't be empty")
 
+    def _createDialog(self, dialog_opt):
+        dialog_type = dialog_opt.setdefault(C.XMLUI_DATA_TYPE, C.XMLUI_DIALOG_MESSAGE)
+        if dialog_type in [C.XMLUI_DIALOG_CONFIRM, C.XMLUI_DIALOG_FILE] and self.submit_id is None:
+            raise exceptions.InternalError(_("Submit ID must be filled for this kind of dialog"))
+        top_element = TopElement(self)
+        level = dialog_opt.get(C.XMLUI_DATA_LVL)
+        dialog_elt = DialogElement(top_element, dialog_type, level)
+
+        try:
+            MessageElement(dialog_elt, dialog_opt[C.XMLUI_DATA_MESS])
+        except KeyError:
+            pass
+
+        try:
+            ButtonsElement(dialog_elt, dialog_opt[C.XMLUI_DATA_BTNS_SET])
+        except KeyError:
+            pass
+
+        try:
+            FileElement(dialog_elt, dialog_opt[C.XMLUI_DATA_FILETYPE])
+        except KeyError:
+            pass
+
     def _createContainer(self, container, parent=None, **kwargs):
         """Create a container element
         @param type: container type (cf init doc)