# Source code for taurus.qt.qtgui.dialog.taurusmessagebox

    #!/usr/bin/env python

    # ###########################################################################
    #
    # This file is part of Taurus
    #
    # http://taurus-scada.org
    #
    # Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
    #
    # Taurus is free software: you can redistribute it and/or modify
    # it under the terms of the GNU Lesser General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # Taurus is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU Lesser General Public License for more details.
    #
    # You should have received a copy of the GNU Lesser General Public License
    # along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
    #
    # ###########################################################################

    """This module provides a set of dialog based widgets
    """

    import sys

    from taurus.external.qt import Qt
    from taurus.core.util.excepthook import BaseExceptHook
    from taurus.core.util.log import LogExceptHook
    from taurus.core.util.wrap import wraps

    __docformat__ = "restructuredtext"

    class TaurusMessageBox(Qt.QDialog):
        """A panel intended to display a taurus error.
        Example::

            dev = taurus.Device("sys/tg_test/1")
            try:
                print(dev.read_attribute("throw_exception"))
            except PyTango.DevFailed, df:
                msgbox = TaurusMessageBox()
                msgbox.show()

        You can show the error outside the exception handling code. If you do this,
        you should keep a record of the exception information as given by
        :func:`sys.exc_info`::

            dev = taurus.Device("sys/tg_test/1")
            exc_info = None
            try:
                print(dev.read_attribute("throw_exception"))
            except PyTango.DevFailed, df:
                exc_info = sys.exc_info()

            if exc_info:
                msgbox = TaurusMessageBox(*exc_info)
                msgbox.show()
        """

        def __init__(
            self,
            err_type=None,
            err_value=None,
            err_traceback=None,
            parent=None,
            designMode=False,
        ):
            Qt.QDialog.__init__(self, parent)
            layout = Qt.QVBoxLayout()
            self.setLayout(layout)
            import taurus.qt.qtgui.panel

            MsgPanel = taurus.qt.qtgui.panel.TaurusMessagePanel
            self._panel = MsgPanel(
                err_type, err_value, err_traceback, self, designMode
            )
            layout.setContentsMargins(0, 0, 0, 0)
            layout.addWidget(self._panel)
            self.panel().buttonBox().accepted.connect(self.accept)
            self._panel.toggledDetails.connect(self._onShowDetails)

        def _onShowDetails(self, show):
            self.adjustSize()

        def panel(self):
            """Returns the :class:`taurus.qt.qtgui.panel.TaurusMessagePanel`.

            :return: the internal panel
            :rtype: taurus.qt.qtgui.panel.TaurusMessagePanel
            """
            return self._panel

        def addButton(self, button, role=Qt.QDialogButtonBox.ActionRole):
            """Adds the given button with the given to the button box

            :param button: the button to be added
            :type button: PyQt5.Qt.QPushButton
            :param role: button role
            :type role: PyQt5.Qt.QDialogButtonBox.ButtonRole
            """
            self.panel().addButton(button, role)

        def setIconPixmap(self, pixmap):
            """Sets the icon to the dialog

            :param pixmap: the icon pixmap
            :type pixmap: PyQt5.Qt.QPixmap
            """
            self._panel.setIconPixmap(pixmap)

        def setText(self, text):
            """Sets the text of the dialog

            :param text: the new text
            :type text: str
            """
            self._panel.setText(text)

        def getText(self):
            """Returns the current text of this panel

            :return: the text for this panel
            :rtype: str
            """
            return self._panel.getText()

        def setDetailedText(self, text):
            """Sets the detailed text of the dialog

            :param text: the new text
            :type text: str
            """
            self._panel.setDetailedText(text)

        def setError(self, err_type=None, err_value=None, err_traceback=None):
            """Sets the exception object.
            Example usage::

                dev = taurus.Device("sys/tg_test/1")
                exc_info = None
                msgbox = TaurusMessageBox()
                try:
                    print(dev.read_attribute("throw_exception"))
                except PyTango.DevFailed, df:
                    exc_info = sys.exc_info()

                if exc_info:
                    msgbox.setError(*exc_info)
                    msgbox.show()

            :param err_type: the exception type of the exception being handled (a
                class object)
            :type error: class object
            :param err_value: exception object
            :type err_value: object
            :param err_traceback: a traceback object which encapsulates the call
                stack at the point where the exception originally occurred
            :type err_traceback: TracebackType
            """
            self._panel.setError(err_type, err_value, err_traceback)

    _PROTECT_MESSAGE_BOX = None

    def _ProtectMessageBox(
        err_type=None, err_value=None, err_traceback=None, parent=None
    ):
        global _PROTECT_MESSAGE_BOX
        box = _PROTECT_MESSAGE_BOX
        if box is None:
            _PROTECT_MESSAGE_BOX = box = TaurusMessageBox(
                err_type=err_type,
                err_value=err_value,
                err_traceback=err_traceback,
                parent=parent,
            )
            box.panel().setCheckBoxVisible(True)
        else:
            box.setError(
                err_type=err_type, err_value=err_value, err_traceback=err_traceback
            )
        if box.panel().checkBoxState() == Qt.Qt.Checked:
            return
        return box

    def protectTaurusMessageBox(fn):
        """The idea of this function is to be used as a decorator on any method
        you which to protect against exceptions. The handle of the exception is to
        display a :class:`TaurusMessageBox` with the exception information.
        Example::

            @protectTaurusMessgeBox
            def turnBeamOn(device_name):
                d = taurus.Device(device_name)
                d.TurnOn()
        """

        @wraps(fn)
        def wrapped(*args, **kwargs):
            try:
                return fn(*args, **kwargs)
            except Exception:
                msgbox = _ProtectMessageBox(*sys.exc_info())
                if msgbox is None:
                    return
                msgbox.exec_()

        return wrapped

    class ProtectTaurusMessageBox(object):
        """The idea of this class is to be used as a decorator on any method
        you which to protect against exceptions. The handle of the exception is to
        display a :class:`TaurusMessageBox` with the exception information. The
        optional parameter title gives the window bar a customized title. The
        optional parameter msg allows you to give a customized message in the
        dialog. Example::

            @ProtectTaurusMessgeBox(title="Error trying to turn the beam on")
            def turnBeamOn(device_name):
                d = taurus.Device(device_name)
                d.TurnOn()
        """

        def __init__(self, title=None, msg=None):
            self._title = title
            self._msg = msg

        def __call__(self, fn):
            @wraps(fn)
            def wrapped(*args, **kwargs):
                try:
                    return fn(*args, **kwargs)
                except Exception:
                    msgbox = _ProtectMessageBox(*sys.exc_info())
                    if msgbox is None:
                        return
                    if self._title is not None:
                        msgbox.setWindowTitle(self._title)
                    if self._msg is not None:
                        msgbox.setText(self._msg)
                    msgbox.exec_()

            return wrapped

    class TaurusExceptHookMessageBox(BaseExceptHook):
        """A callable class that acts as an excepthook that displays an unhandled
        exception in a :class:`~taurus.qt.qtgui.dialog.TaurusMessageBox`.

        :param hook_to: callable excepthook that will be called at the end of this
            hook handling [default: None]
        :type hook_to: callable
        :param title: message box title [default: None meaning use exception value]
        :type name: str
        :param msg: message box text [default: None meaning use exception]
        """

        MSG_BOX = None

        def __init__(self, hook_to=None, title=None, msg=None):
            BaseExceptHook.__init__(self, hook_to=hook_to)
            self._title = title
            self._msg = msg

        def _getMessageBox(
            self, err_type=None, err_value=None, err_traceback=None, parent=None
        ):
            box = self.__class__.MSG_BOX

            if box is None:
                self.__class__.MSG_BOX = box = TaurusMessageBox(
                    err_type=err_type,
                    err_value=err_value,
                    err_traceback=err_traceback,
                    parent=parent,
                )
                box.panel().setCheckBoxVisible(True)
            else:
                box.setError(
                    err_type=err_type,
                    err_value=err_value,
                    err_traceback=err_traceback,
                )
            if box.panel().checkBoxState() == Qt.Qt.Checked:
                return
            return box

        def report(self, *exc_info):
            app = Qt.QApplication.instance()
            if app is None:
                LogExceptHook().report(*exc_info)
                return
            msgbox = self._getMessageBox(*exc_info)
            if msgbox is None:
                return
            if self._title is not None:
                msgbox.setWindowTitle(self._title)
            if self._msg is not None:
                msgbox.setText(self._msg)
            msgbox.exec_()

    class DemoException(Exception):
        pass

    def s1():
        return s2()

    def s2():
        return s3()

    def s3():
        raise DemoException("A demo exception occurred")

    def py_exc():
        try:
            s1()
        except Exception:
            msgbox = TaurusMessageBox(*sys.exc_info())
            msgbox.exec_()

    def tg_exc():
        import PyTango  # TODO: tango-centric

        try:
            PyTango.Except.throw_exception(
                "TangoException", "A simple tango exception", "right here"
            )
        except PyTango.DevFailed:
            msgbox = TaurusMessageBox(*sys.exc_info())
            msgbox.exec_()

    def tg_serv_exc():
        import PyTango  # TODO: tango-centric
        import taurus

        dev = taurus.Device("sys/tg_test/1")
        try:
            dev.read_attribute("throw_exception")
        except PyTango.DevFailed:
            msgbox = TaurusMessageBox(*sys.exc_info())
            msgbox.exec_()
        except Exception:
            msgbox = TaurusMessageBox(*sys.exc_info())
            msgbox.exec_()

    def py_tg_serv_exc():
        import PyTango  # TODO: tango-centric

        try:
            PyTango.Except.throw_exception(
                "TangoException", "A simple tango exception", "right here"
            )
        except PyTango.DevFailed as df1:
            try:
                import traceback
                import io

                origin = io.StringIO()
                traceback.print_stack(file=origin)
                origin.seek(0)
                origin = origin.read()
                PyTango.Except.re_throw_exception(
                    df1,
                    "PyDs_Exception",
                    "DevFailed: A simple tango " "exception",
                    origin,
                )
            except PyTango.DevFailed:
                msgbox = TaurusMessageBox(*sys.exc_info())
                msgbox.exec_()

    def demo():
        """Message dialog"""
        panel = Qt.QWidget()
        layout = Qt.QVBoxLayout()
        panel.setLayout(layout)

        m1 = Qt.QPushButton("Python exception")
        layout.addWidget(m1)
        m1.clicked.connect(py_exc)
        m2 = Qt.QPushButton("Tango exception")
        layout.addWidget(m2)
        m2.clicked.connect(tg_exc)
        layout.addWidget(m2)
        m3 = Qt.QPushButton("Tango server exception")
        layout.addWidget(m3)
        m3.clicked.connect(tg_serv_exc)
        layout.addWidget(m3)
        m4 = Qt.QPushButton("Python tango server exception")
        layout.addWidget(m4)
        m4.clicked.connect(py_tg_serv_exc)
        layout.addWidget(m4)

        panel.show()
        return panel

    def main():
        import taurus.qt.qtgui.application

        Application = taurus.qt.qtgui.application.TaurusApplication

        app = Application.instance()
        owns_app = app is None

        if owns_app:
            app = Qt.QApplication([])
            app.setApplicationName("Taurus message demo")
            app.setApplicationVersion("1.0")

        w = demo()

        if owns_app:
            sys.exit(app.exec_())
        else:
            return w

    if __name__ == "__main__":
        main()