<commit_before>##########################################################################
#  
#  Copyright (c) 2012, 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 <NAME> 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 os
import re
import weakref
import threading

import IECore

import Gaffer
import GafferUI

class BrowserEditor( GafferUI.EditorWidget ) :

	def __init__( self, scriptNode=None, **kw ) :
	
		self.__column = GafferUI.ListContainer( borderWidth = 8, spacing = 6 )
		
		GafferUI.EditorWidget.__init__( self, self.__column, scriptNode, **kw )
		
		with self.__column :
		
			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 6 ) :
			
				GafferUI.Label( "Location" )
			
				modeMenu = GafferUI.SelectionMenu()
				for mode in self.__modes :
					modeMenu.addItem( mode[0] )
				self.__modeChangedConnection = modeMenu.currentIndexChangedSignal().connect( Gaffer.WeakMethod( self.__modeChanged ) )
		
			self.__pathChooser = GafferUI.PathChooserWidget( Gaffer.DictPath( {}, "/" ), previewTypes=GafferUI.PathPreviewWidget.types() )
			self.__pathChooser.pathWidget().setVisible( False )
		
		self.__modeInstances = {}
		self.__currentModeInstance = None
		self.__modeChanged( modeMenu )
	
	## Returns the PathChooserWidget which forms the majority of this ui.
	def pathChooser( self ) :
	
		return self.__pathChooser
	
	def __repr__( self ) :

		return "GafferUI.BrowserEditor()"
		
	def __modeChanged( self, modeMenu ) :
	
		label = modeMenu.getCurrentItem()
		if label not in self.__modeInstances :
			for mode in self.__modes :
				if mode[0] == label :
					self.__modeInstances[label] = mode[1]( self )
					break

		if self.__currentModeInstance is not None :
			self.__currentModeInstance.disconnect()
		
		self.__currentModeInstance = self.__modeInstances[label]
		self.__currentModeInstance.connect()
		
	class Mode( object ) :
	
		def __init__( self, browser ) :
		
			self.__browser = weakref.ref( browser ) # avoid circular references
			self.__directoryPath = None
			self.__displayMode = None
			
			# create the op matcher on a separate thread, as it may take a while to trawl
			# through all the available ops.
			self.__opMatcher = None
			threading.Thread( target = self.__createOpMatcher ).start()
			
		def browser( self ) :
		
			return self.__browser()
		
		def connect( self ) :
		
			if self.__directoryPath is None :
				self.__directoryPath = self._initialPath()
				self.__displayMode = self._initialDisplayMode()
				self.__columns = self._initialColumns()
				
			# we need a little bit of jiggery pokery, because the PathChooserWidget edits
			# the main path as a leaf path, and we're more interested in setting the current
			# directory.
			pathElements = self.__directoryPath[:]
			self.browser().pathChooser().setPath( self.__directoryPath )
			self.browser().pathChooser().directoryPathWidget().getPath()[:] = pathElements
			
			self.browser().pathChooser().pathListingWidget().setDisplayMode( self.__displayMode )
			self.browser().pathChooser().pathListingWidget().setColumns( self.__columns )
			
			self.__contextMenuConnection = self.browser().pathChooser().pathListingWidget().contextMenuSignal().connect( Gaffer.WeakMethod( self.__contextMenu ) )
						
		def disconnect( self ) :
	
			self.__directoryPath[:] = self.browser().pathChooser().directoryPathWidget().getPath()[:]
			self.__displayMode = self.browser().pathChooser().pathListingWidget().getDisplayMode()
	
			self.__contextMenuConnection = None
	
		## Must be implemented by derived classes to return the initial directory path to be viewed.
		def _initialPath( self ) :
		
			raise NotImplementedError
		
		## May be reimplemented by derived classes to change the initial display mode of the path listing
		def _initialDisplayMode( self ) :
		
			return GafferUI.PathListingWidget.DisplayMode.List
		
		## Must be reimplemented by derived classes to specify the columns to be displayed in the PathListingWidget.
		def _initialColumns( self ) :
		
			raise NotImplementedError
			
		def __contextMenu( self, pathListing ) :
		
			menuDefinition = IECore.MenuDefinition()
		
			if self.__opMatcher is not None :
			
				selectedPaths = pathListing.getSelectedPaths()
				if len( selectedPaths ) == 1 :
					parameterValue = selectedPaths[0]
				else :
					parameterValue = selectedPaths
			
				ops = self.__opMatcher.matches( parameterValue )
				for op, parameter in ops :
				
					menuDefinition.append( "/Actions/%s (%s)" % ( op.typeName(), parameter.name ), { "command" : self.__opDialogueCommand( op ) } )
					
			else :
			
				menuDefinition.append( "/Loading actions...", { "active" : False } )
					
			self.__menu = GafferUI.Menu( menuDefinition )
			if len( menuDefinition.items() ) :
				self.__menu.popup( parent = pathListing.ancestor( GafferUI.Window ) )
			
			return True
		
		def __createOpMatcher( self ) :
		
			self.__opMatcher = Gaffer.OpMatcher.defaultInstance()
			
		def __opDialogueCommand( self, op ) :
		
			def showDialogue( menu ) :
			
				dialogue = GafferUI.OpDialogue( op )
				dialogue.waitForResult( parentWindow = menu.ancestor( GafferUI.Window ) )
				
			return showDialogue<commit_msg>Deferring matching of ops until submenu is opened.<commit_after>##########################################################################
#  
#  Copyright (c) 2012, 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 <NAME> 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 os
import re
import weakref
import threading

import IECore

import Gaffer
import GafferUI

class BrowserEditor( GafferUI.EditorWidget ) :

	def __init__( self, scriptNode=None, **kw ) :
	
		self.__column = GafferUI.ListContainer( borderWidth = 8, spacing = 6 )
		
		GafferUI.EditorWidget.__init__( self, self.__column, scriptNode, **kw )
		
		with self.__column :
		
			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 6 ) :
			
				GafferUI.Label( "Location" )
			
				modeMenu = GafferUI.SelectionMenu()
				for mode in self.__modes :
					modeMenu.addItem( mode[0] )
				self.__modeChangedConnection = modeMenu.currentIndexChangedSignal().connect( Gaffer.WeakMethod( self.__modeChanged ) )
		
			self.__pathChooser = GafferUI.PathChooserWidget( Gaffer.DictPath( {}, "/" ), previewTypes=GafferUI.PathPreviewWidget.types() )
			self.__pathChooser.pathWidget().setVisible( False )
		
		self.__modeInstances = {}
		self.__currentModeInstance = None
		self.__modeChanged( modeMenu )
	
	## Returns the PathChooserWidget which forms the majority of this ui.
	def pathChooser( self ) :
	
		return self.__pathChooser
	
	def __repr__( self ) :

		return "GafferUI.BrowserEditor()"
		
	def __modeChanged( self, modeMenu ) :
	
		label = modeMenu.getCurrentItem()
		if label not in self.__modeInstances :
			for mode in self.__modes :
				if mode[0] == label :
					self.__modeInstances[label] = mode[1]( self )
					break

		if self.__currentModeInstance is not None :
			self.__currentModeInstance.disconnect()
		
		self.__currentModeInstance = self.__modeInstances[label]
		self.__currentModeInstance.connect()
		
	class Mode( object ) :
	
		def __init__( self, browser ) :
		
			self.__browser = weakref.ref( browser ) # avoid circular references
			self.__directoryPath = None
			self.__displayMode = None
			
			# create the op matcher on a separate thread, as it may take a while to trawl
			# through all the available ops.
			self.__opMatcher = None
			threading.Thread( target = self.__createOpMatcher ).start()
			
		def browser( self ) :
		
			return self.__browser()
		
		def connect( self ) :
		
			if self.__directoryPath is None :
				self.__directoryPath = self._initialPath()
				self.__displayMode = self._initialDisplayMode()
				self.__columns = self._initialColumns()
				
			# we need a little bit of jiggery pokery, because the PathChooserWidget edits
			# the main path as a leaf path, and we're more interested in setting the current
			# directory.
			pathElements = self.__directoryPath[:]
			self.browser().pathChooser().setPath( self.__directoryPath )
			self.browser().pathChooser().directoryPathWidget().getPath()[:] = pathElements
			
			self.browser().pathChooser().pathListingWidget().setDisplayMode( self.__displayMode )
			self.browser().pathChooser().pathListingWidget().setColumns( self.__columns )
			
			self.__contextMenuConnection = self.browser().pathChooser().pathListingWidget().contextMenuSignal().connect( Gaffer.WeakMethod( self.__contextMenu ) )
						
		def disconnect( self ) :
	
			self.__directoryPath[:] = self.browser().pathChooser().directoryPathWidget().getPath()[:]
			self.__displayMode = self.browser().pathChooser().pathListingWidget().getDisplayMode()
	
			self.__contextMenuConnection = None
	
		## Must be implemented by derived classes to return the initial directory path to be viewed.
		def _initialPath( self ) :
		
			raise NotImplementedError
		
		## May be reimplemented by derived classes to change the initial display mode of the path listing
		def _initialDisplayMode( self ) :
		
			return GafferUI.PathListingWidget.DisplayMode.List
		
		## Must be reimplemented by derived classes to specify the columns to be displayed in the PathListingWidget.
		def _initialColumns( self ) :
		
			raise NotImplementedError
			
		def __contextMenu( self, pathListing ) :
		
			menuDefinition = IECore.MenuDefinition()
		
			if self.__opMatcher is not None :
			
				selectedPaths = pathListing.getSelectedPaths()
				if len( selectedPaths ) == 1 :
					parameterValue = selectedPaths[0]
				else :
					parameterValue = selectedPaths
			
				menuDefinition.append( "/Actions", { "subMenu" : IECore.curry( Gaffer.WeakMethod( self.__actionsSubMenu ), parameterValue ) } )
					
			else :
			
				menuDefinition.append( "/Loading actions...", { "active" : False } )
					
			self.__menu = GafferUI.Menu( menuDefinition )
			if len( menuDefinition.items() ) :
				self.__menu.popup( parent = pathListing.ancestor( GafferUI.Window ) )
			
			return True
		
		def __actionsSubMenu( self, parameterValue ) :
		
			menuDefinition = IECore.MenuDefinition()
				
			ops = self.__opMatcher.matches( parameterValue )
			if len( ops ) :
				for op, parameter in ops :
					menuDefinition.append( "/%s (%s)" % ( op.typeName(), parameter.name ), { "command" : self.__opDialogueCommand( op ) } )
			else :
				menuDefinition.append( "/None available", { "active" : False } )
				
			return menuDefinition
				
		def __createOpMatcher( self ) :
		
			self.__opMatcher = Gaffer.OpMatcher.defaultInstance()
			
		def __opDialogueCommand( self, op ) :
		
			def showDialogue( menu ) :
			
				dialogue = GafferUI.OpDialogue( op )
				dialogue.waitForResult( parentWindow = menu.ancestor( GafferUI.Window ) )
				
			return showDialogue
{'fraction_non_alphanumeric': 0.1050675434207705, 'fraction_numerical': 0.0017153884640125794, 'mean_word_length': 3.648504983388704, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1664275', 'n_tokens_mistral': 4567, 'n_tokens_neox': 3782, 'n_words': 1218}