##########################################################################
#
#  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import weakref

import IECore

import Gaffer
import GafferUI

QtCore = GafferUI._qtImport( "QtCore" )
QtGui = GafferUI._qtImport( "QtGui" )

## The MessageWidget class displays a log of messages in the format specified by
# IECore MessageHandlers.
class MessageWidget( GafferUI.Widget ) :

	def __init__( self, **kw ) :

		row = GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing=4 )
		GafferUI.Widget.__init__( self, row, **kw )

		with row :

			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Vertical, spacing=6 ) :

				buttonSpecs = [
					( IECore.Msg.Level.Error, "Errors. These may chill you to your very core. Click to scroll to the next one (if you can stomach it)." ),
					( IECore.Msg.Level.Warning, "Warnings. These may give you pause for thought. Click to scroll to the next thinking point." ),
					( IECore.Msg.Level.Info, "Information. You may find this edifying. Click to scroll to the next enlightening nugget." ),
					( IECore.Msg.Level.Debug, "Debug information. You may find this very dull. Click to scroll to the next item." ),
				]
				self.__levelButtons = {}
				self.__buttonClickedConnections = []
				for buttonSpec in buttonSpecs :
					button = GafferUI.Button(
						image = IECore.Msg.levelAsString( buttonSpec[0] ).lower() + "Notification.png",
						hasFrame = False,
					)
					button.__level = buttonSpec[0]
					self.__levelButtons[buttonSpec[0]] = button
					self.__buttonClickedConnections.append( button.clickedSignal().connect( Gaffer.WeakMethod( self.__buttonClicked ) ) )
					button.setVisible( False )
					button.setToolTip( buttonSpec[1] )

				GafferUI.Spacer( IECore.V2i( 10 ) )

			self.__text = GafferUI.MultiLineTextWidget( editable=False )

		self.__messageLevel = IECore.Msg.Level.Info
		self.__messageHandler = _MessageHandler( self )
		self.__messages = []
		self.__processingEvents = False

	## Returns a MessageHandler which will output to this Widget.
	## \threading It is safe to use the handler on threads other than the main thread.
	def messageHandler( self ) :

		return self.__messageHandler

	## It can be useful to forward messages captured by this widget
	# on to other message handlers - for instance to perform centralised
	# logging in addition to local display. This method returns a
	# CompoundMessageHandler which can be used for such forwarding -
	# simply add a handler with forwardingMessageHandler().addHandler().
	def forwardingMessageHandler( self ) :

		return self.__messageHandler._forwarder

	## Sets an IECore.MessageHandler.Level specifying which
	# type of messages will be visible to the user - levels above
	# that specified will be invisible. Note that the invisible
	# messages are still stored, so they can be made visible at a later
	# time by a suitable call to setMessageLevel(). This can be useful
	# for revealing debug messages only after a warning or error has
	# alerted the user to a problem.
	def setMessageLevel( self, messageLevel ) :

		assert( isinstance( messageLevel, IECore.MessageHandler.Level ) )

		if messageLevel == self.__messageLevel :