# HG changeset patch # User Goffi # Date 1407777024 -7200 # Node ID 018bdd6877478c611a1fde380774db027bafc67b # Parent 490a8a4536b6cd269b2e8fed922687efbb49a00e 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 diff -r 490a8a4536b6 -r 018bdd687747 src/tools/xml_tools.py --- 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 . 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)