# Copyright (c) 2011-2014, B.I.Stepanov Institute of Physics, National Academy
# of Sciences of Belarus.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program 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 General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from common.utils import gui

__all__ = ['StatusLabelWidget']

# *****************************************************************************
class StatusLabelWidget(QWidget):
    """A rich text label with an icon for various information messages."""

    # ---- Public methods -----------------------------------------------------
    def __init__(self, parent = None):

        QWidget.__init__(self, parent)

        layout = QHBoxLayout()

        self.iconLabel = QLabel()
        # Align the icon with the top of a potentially multiline message.
        self.iconLabel.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        layout.addWidget(self.iconLabel)

        self.messageLabel = QLabel()
        self.messageLabel.setTextFormat(Qt.RichText)
        # Allow the use of very long messages if such a need arises (at the
        # cost of messing up the vertical layout, though).
        self.messageLabel.setWordWrap(True)
        # Set the label stretch factor to 1 to prevent its horizontal shrinkage.
        layout.addWidget(self.messageLabel, 1)

        layout.addStretch()

        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

    def disableWordWrapping(self):
        """Disable word wrapping for the label text (by default, word wrapping
        is enabled)."""

        self.messageLabel.setWordWrap(False)

    def clear(self):
        self.iconLabel.clear()
        self.messageLabel.clear()

    def setCompleted(self, message):
        self.setIconAndText(gui.loadIcon('completed'), message)

    def setInfo(self, message):
        self.setIconAndText(gui.loadIcon('info'), message)

    def setWarning(self, message):
        self.setIconAndText(gui.loadIcon('warning'), message)

    def setError(self, message):
        self.setIconAndText(gui.loadIcon('error'), message)

    def setProgress(self, message, requestRepaint = False):
        """Set a progress status message and then call 'repaintParentWindow'
        method if 'requestRepaint' is set to 'True'."""

        self.setIconAndText(gui.loadIcon('progress'), message)

        if requestRepaint:
            self.repaintParentWindow()

    def setStatusMessage(self, statusMessage):
        """Set icon and text according to a 'StatusMessage' instance, as
        returned by 'StatusSignalingWidget's 'getStatusMessage' method."""

        if statusMessage is None:
            self.clear()
            return

        status = statusMessage.getStatus()
        text = statusMessage.getText()

        if status == 'completed':
            self.setCompleted(text)
        if status == 'info':
            self.setInfo(text)
        elif status == 'warning':
            self.setWarning(text)
        elif status == 'error':
            self.setError(text)
        elif status == 'progress':
            self.setProgress(text)
        else:
            assert False

    def setMostSevereStatusMessage(self, statusMessageList):
        """Same as 'setStatusMessage', but take a list of 'StatusMessage'
        instances and select the most relevant message out of it.

        The most relevant message is the first message in the list with the
        greatest status severity."""

        # The least severe of the admissible status messages is 'None'.
        mostSevereMessage = None
        greatestSeverity = None

        for message in statusMessageList:

            if message is not None and (greatestSeverity is None or
                message.getSeverity() > greatestSeverity):

                mostSevereMessage = message
                greatestSeverity = message.getSeverity()

        self.setStatusMessage(mostSevereMessage)

    def repaintParentWindow(self):
        """Update this widget's layout and repaint the window it is contained
        in, so that any changes made to the displayed message would be
        immediately visible to the user.

        This is useful in combination with 'setProgress' when an action that
        may take noticeable amount of time is about to start in the main
        application thread. This may also be used as a handler for
        'StatusSignalingWidget's 'repaintRequested' signal."""

        parent = self.window()

        # Redo the layout, as the number of label text lines may have changed.
        # For some reason, this won't work as expected if only 'self's (or only
        # 'parent's) layout is activated. When both these layouts are
        # activated, this seems to work just fine.
        self.layout().activate()
        parent.layout().activate()

        # Repaint the window.
        parent.repaint()

    # ---- Private methods ----------------------------------------------------
    def setIconAndText(self, icon, message):
        iconHeight = QFontMetrics(self.messageLabel.font()).height()
        self.iconLabel.setPixmap(icon.pixmap(iconHeight))

        self.messageLabel.setText(message)
