# Source code for taurus.qt.qtgui.input.choicedlg

    #!/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 package provides a dialog for graphically choosing a Taurus class
    """

    from taurus.external.qt import Qt

    __docformat__ = "restructuredtext"

    class GraphicalChoiceDlg(Qt.QDialog):
        """
        A generic dialog for choosing among a set of choices which are presented as
        an array of, each with a given pixmap.

        The :meth:`getChoice` static method is provided for convenience so that the
        dialog can be invoked wit a single line::

            chosen,ok = GraphicalChoiceDlg.getChoice(
                parent, title, msg, choices, pixmaps, size, defpixmap,
                horizontalScrollBarPolicy, verticalScrollBarPolicy
                )
        """

        def __init__(
            self,
            parent=None,
            designMode=False,
            choices=None,
            pixmaps=None,
            iconSize=128,
            defaultPixmap=None,
            horizontalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
            verticalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
        ):
            Qt.QDialog.__init__(self, parent)
            self._chosen = None
            self.setLayout(Qt.QVBoxLayout())
            self.label = Qt.QLabel("Click on your choice:")
            self.layout().addWidget(self.label)
            self._iconsArea = GraphicalChoiceWidget(
                parent=parent,
                designMode=designMode,
                choices=choices,
                pixmaps=pixmaps,
                iconSize=iconSize,
                defaultPixmap=defaultPixmap,
                horizontalScrollBarPolicy=horizontalScrollBarPolicy,
                verticalScrollBarPolicy=verticalScrollBarPolicy,
            )
            self.layout().addWidget(self._iconsArea)
            self._iconsArea.choiceMade.connect(self.onChoiceMade)

        def setHorizontalScrollBarPolicy(self, policy):
            """sets horizontal scrollbar policy of scrollArea"""
            return self._iconsArea.setHorizontalScrollBarPolicy(policy)

        def setVerticalScrollBarPolicy(self, policy):
            """sets vertical scrollbar policy of scrollArea"""
            return self._iconsArea.setVerticalScrollBarPolicy(policy)

        def setMessage(self, msg):
            """sets the text which is shown to the user in the dialog"""
            self.label.setText(msg)

        def onChoiceMade(self, chosen):
            """slot called when the user chooses an option"""
            self.accept()

        def getChosen(self):
            """
            returns the choice
            :return:
            :rtype: str
            """
            return self._iconsArea.getChosen()

        @staticmethod
        def getChoice(
            parent=None,
            title="",
            msg="",
            choices=None,
            pixmaps=None,
            iconSize=128,
            defaultPixmap=None,
            horizontalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
            verticalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
        ):
            """
            Static method which launches a GraphicalChoiceDlg with the given
            options and returns the result

            :param parent: The parent of the dialog (it will be centered on it)
            :type parent: QWidget
            :param title: the text which is displayed in the title bar of the
                dialog
            :type title: str
            :param msg: the text which is shown to the user in the dialog, above
                the choices.
            :type msg: str
            :param choices: a list of lists of strings to be used as choices names.
                The (possibly sparse) 2D array defined by the nested lists will be
                used to present the choices in a grid. The choice names will be
                used as keys for pixmaps
            :type choices: list<list>
            :param pixmaps: dictionary mapping the choices text to corresponding
                pixmap. If no valid pixmap is provided for a given choice, the
                defaultPixmap will be used
            :type pixmaps: dict<str,QPixmap>
            :param iconSize: size of the icons to be displayed (128px by default)
            :type iconSize: int
            :param defaultPixmap: Default Pixmap to use if none passed for a given
                choice. No Pixmap will be used if None passed.
            :type defaultPixmap: QPixmap
            :param horizontalScrollBarPolicy: defines the mode of the horizontal
                scroll bar. The default mode is ScrollBarAsNeeded.
            :type horizontalScrollBarPolicy: enum Qt.ScrollBarPolicy
            :param verticalScrollBarPolicy: defines the mode of the vertical scroll
                bar. The default mode is ScrollBarAsNeeded
            :type verticalScrollBarPolicy: enum Qt.ScrollBarPolicy
            :return: A tuple containing choice,ok. choice is the name of the chosen
                option. ok is true if the user pressed OK and false if the user
                pressed Cancel.
            :rtype: tuple<str,bool>
            """
            dlg = GraphicalChoiceDlg(
                parent=parent,
                choices=choices,
                pixmaps=pixmaps,
                iconSize=iconSize,
                defaultPixmap=defaultPixmap,
                horizontalScrollBarPolicy=horizontalScrollBarPolicy,
                verticalScrollBarPolicy=verticalScrollBarPolicy,
            )
            dlg.setWindowTitle(title)
            dlg.setMessage(msg)
            dlg.exec_()
            return dlg.getChosen(), (dlg.result() == dlg.Accepted)

    class GraphicalChoiceWidget(Qt.QScrollArea):
        """A widget that presents a 2D grid of buttons"""

        choiceMade = Qt.pyqtSignal("QString")

        def __init__(
            self,
            parent=None,
            designMode=False,
            choices=None,
            pixmaps=None,
            iconSize=128,
            defaultPixmap=None,
            horizontalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
            verticalScrollBarPolicy=Qt.Qt.ScrollBarAsNeeded,
        ):
            Qt.QScrollArea.__init__(self, parent)

            self._chosen = None
            self._iconSize = iconSize
            if defaultPixmap is None:
                defaultPixmap = Qt.QPixmap()
            self._defaultPixmap = defaultPixmap

            self.setFrameShape(Qt.QFrame.NoFrame)
            self.setWidgetResizable(True)
            self.setHorizontalScrollBarPolicy(horizontalScrollBarPolicy)
            self.setVerticalScrollBarPolicy(verticalScrollBarPolicy)

            w = Qt.QWidget()
            self.gridLayout = Qt.QGridLayout()
            w.setLayout(self.gridLayout)
            self.setWidget(w)

            if choices is not None:
                self.setChoices(choices, pixmaps)
            elif designMode:
                from taurus.qt.qtgui.icon import getCachedPixmap

                pm = getCachedPixmap("logos:taurus.png")
                self.setChoices(
                    [["choice1", "choice2"], ["choice3", "choice4"]],
                    dict(choice1=pm, choice2=pm, choice3=pm, choice4=pm),
                )

        def setChoices(self, choices, pixmaps=None):
            """
            sets the available options

            :param choices: a list of lists of strings to be used as choices names.
                The (possibly sparse) 2D array defined by the nested lists will be
                used to present the choices in a grid. The choice names will be
                used as keys for pixmaps
            :type choices: list<list>
            :param pixmaps: dictionary mapping the choices text to corresponding
                pixmap. If no valid pixmap is provided for a given choice, a
                default pixmap will be used
            :type pixmaps: dict<str,QPixmap>
            """
            if pixmaps is None:
                pixmaps = {}
            for i, rowlist in enumerate(choices):
                for j, choice in enumerate(rowlist):
                    self.setChoice(
                        i, j, str(choice), pixmap=pixmaps.get(choice, None)
                    )

        def setChoice(self, row, col, text, pixmap=None, tooltip=None):
            """
            sets the option for a given row,column coordinate in the grid

            :param row: row in the grid for this option
            :type row: int
            :param col: column in the grid for this option
            :type col: int
            :param text: name for this option
            :type text: str
            :param pixmap: If no valid pixmap is provided for a given choice, the
                default one will be used
            :type pixmap: QPixmap or None
            :param tooltip: tooltip for this option (if None given, the `text` is
                used)
            :type tooltip: str
            """
            if not pixmap or pixmap is None or pixmap.isNull():
                pixmap = self._defaultPixmap
            if tooltip is None:
                tooltip = text
            button = Qt.QToolButton()
            button.setText(text)
            button.setIcon(Qt.QIcon(pixmap))
            button.setIconSize(Qt.QSize(self._iconSize, self._iconSize))
            button.setToolTip(tooltip)
            button.clicked.connect(self.onClick)
            self.gridLayout.addWidget(button, row, col, Qt.Qt.AlignCenter)
            # -------------------------------------------------------
            # Work around for https://bugs.kde.org/show_bug.cgi?id=345023
            # TODO: make better solution for this
            button._id = text  # <-- ugly monkey-patch!

            # -------------------------------------------------------

        def onClick(self):
            """slot called when a button is clicked"""
            # -------------------------------------------------------
            # Work around for https://bugs.kde.org/show_bug.cgi?id=345023
            # TODO: make better solution for this
            # self._chosen = str(self.sender().text())  # <- fails due to added "&"
            self._chosen = self.sender()._id  # <-- this was monkey-patched
            # -------------------------------------------------------
            self.choiceMade.emit(self._chosen)

        def getChosen(self):
            """
            returns the choice
            :return:
            :rtype: str
            """
            return self._chosen

        @classmethod
        def getQtDesignerPluginInfo(cls):
            """Returns pertinent information in order to be able to build a valid
            QtDesigner widget plugin

            The dictionary returned by this method should contain *at least* the
            following keys and values:
            - 'module' : a string representing the full python module name (ex.:
            'taurus.qt.qtgui.base')
            - 'icon' : a string representing valid resource icon (ex.:
            'designer:combobox.png')
            - 'container' : a bool telling if this widget is a container widget or
            not.

            This default implementation returns the following dictionary::

                { 'group'     : 'Taurus Widgets',
                  'icon'      : 'logos:taurus.png',
                  'container' : False }

            :return: a map with pertinent designer information
            :rtype: dict
            """
            return {
                "module": "taurus.qt.qtgui.input",
                "group": "Taurus Input",
                "icon": "logos:taurus.png",
                "container": False,
            }

    def testWidget():
        import sys
        from taurus.qt.qtgui.application import TaurusApplication

        app = TaurusApplication(sys.argv, cmd_line_parser=None)
        w = GraphicalChoiceWidget(None, True)
        w.show()
        sys.exit(app.exec_())

    def main():
        import sys
        from taurus.qt.qtgui.icon import getCachedPixmap
        from taurus.qt.qtgui.application import TaurusApplication

        app = TaurusApplication(sys.argv, cmd_line_parser=None)

        pixmaps = {}
        choices = [["TaurusForm", "TaurusTrend"], ["TaurusPlot", "Qub"]]
        for row in choices:
            for k in row:
                pixmaps[k] = getCachedPixmap("snapshot:%s.png" % k)

        print(
            GraphicalChoiceDlg.getChoice(
                parent=None,
                title="Panel chooser",
                msg="Choose the type of Panel:",
                choices=choices,
                pixmaps=pixmaps,
            )
        )

        sys.exit(app.exec_())

    if __name__ == "__main__":
        main()
        # testWidget()