Source code for sibl_gui.components.addons.loaderScript.loaderScript

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
**loaderScript.py**

**Platform:**
	Windows, Linux, Mac Os X.

**Description:**
	Defines the :class:`LoaderScript` Component Interface class.

**Others:**

"""

#**********************************************************************************************************************
#***	Future imports.
#**********************************************************************************************************************
from __future__ import unicode_literals

#**********************************************************************************************************************
#***	External imports.
#**********************************************************************************************************************
import os
import platform
import re
import socket
from PyQt4.QtCore import Qt

#**********************************************************************************************************************
#***	Internal imports.
#**********************************************************************************************************************
import foundations.common
import foundations.exceptions
import foundations.namespace
import foundations.parsers
import foundations.strings
import foundations.verbose
import sibl_gui.exceptions
import umbra.exceptions
from foundations.io import File
from manager.qwidgetComponent import QWidgetComponentFactory
from umbra.globals.constants import Constants

#**********************************************************************************************************************
#***	Module attributes.
#**********************************************************************************************************************
__author__ = "Thomas Mansencal"
__copyright__ = "Copyright (C) 2008 - 2014 - Thomas Mansencal"
__license__ = "GPL V3.0 - http://www.gnu.org/licenses/"
__maintainer__ = "Thomas Mansencal"
__email__ = "thomas.mansencal@gmail.com"
__status__ = "Production"

__all__ = ["LOGGER", "COMPONENT_FILE", "LoaderScript"]

LOGGER = foundations.verbose.installLogger()

COMPONENT_FILE = os.path.join(os.path.dirname(__file__), "ui", "Loader_Script.ui")

#**********************************************************************************************************************
#***	Module classes and definitions.
#**********************************************************************************************************************
[docs]class LoaderScript(QWidgetComponentFactory(uiFile=COMPONENT_FILE)): """ | Defines the :mod:`sibl_gui.components.addons.loaderScript.loaderScript` Component Interface class. | It provides the glue between the Ibl Sets, the Templates and the 3d package. A typical operation is the following: - Retrieve both Ibl Set and Template files. - Parse Ibl Set and Template files. - Retrieve override keys defined by the user and / or another Component. - Generate the Loader Script. - Write the Loader Script. - Establish a connection with the 3d package and trigger the Loader Script execution. """ def __init__(self, parent=None, name=None, *args, **kwargs): """ Initializes the class. :param parent: Object parent. :type parent: QObject :param name: Component name. :type name: unicode :param \*args: Arguments. :type \*args: \* :param \*\*kwargs: Keywords arguments. :type \*\*kwargs: \*\* """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) super(LoaderScript, self).__init__(parent, name, *args, **kwargs) # --- Setting class attributes. --- self.deactivatable = True self.__dockArea = 2 self.__engine = None self.__iblSetsOutliner = None self.__templatesOutliner = None self.__tcpClientUi = None self.__ioDirectory = "loaderScripts/" self.__bindingIdentifierPattern = "@[a-zA-Z0-9_]*" self.__templateScriptSection = "Script" self.__templateIblSetAttributesSection = "Ibl Set Attributes" self.__templateRemoteConnectionSection = "Remote Connection" self.__win32ExecutionMethod = "ExecuteSIBLLoaderScript" self.__overrideKeys = {} self.__defaultStringSeparator = "|" self.__unnamedLightName = "Unnamed_Light" #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def dockArea(self): """ Property for **self.__dockArea** attribute. :return: self.__dockArea. :rtype: int """ return self.__dockArea @dockArea.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def dockArea(self, value): """ Setter for **self.__dockArea** attribute. :param value: Attribute value. :type value: int """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "dockArea")) @dockArea.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def dockArea(self): """ Deleter for **self.__dockArea** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "dockArea"))
@property def engine(self): """ Property for **self.__engine** attribute. :return: self.__engine. :rtype: QObject """ return self.__engine @engine.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def engine(self, value): """ Setter for **self.__engine** attribute. :param value: Attribute value. :type value: QObject """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "engine")) @engine.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def engine(self): """ Deleter for **self.__engine** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "engine"))
@property def iblSetsOutliner(self): """ Property for **self.__iblSetsOutliner** attribute. :return: self.__iblSetsOutliner. :rtype: QWidget """ return self.__iblSetsOutliner @iblSetsOutliner.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def iblSetsOutliner(self, value): """ Setter for **self.__iblSetsOutliner** attribute. :param value: Attribute value. :type value: QWidget """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "iblSetsOutliner")) @iblSetsOutliner.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def iblSetsOutliner(self): """ Deleter for **self.__iblSetsOutliner** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "iblSetsOutliner"))
@property def templatesOutliner(self): """ Property for **self.__templatesOutliner** attribute. :return: self.__templatesOutliner. :rtype: QWidget """ return self.__templatesOutliner @templatesOutliner.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def templatesOutliner(self, value): """ Setter for **self.__templatesOutliner** attribute. :param value: Attribute value. :type value: QWidget """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "templatesOutliner")) @templatesOutliner.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def templatesOutliner(self): """ Deleter for **self.__templatesOutliner** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "templatesOutliner"))
@property def tcpClientUi(self): """ Property for **self.__tcpClientUi** attribute. :return: self.__tcpClientUi. :rtype: QWidget """ return self.__tcpClientUi @tcpClientUi.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def tcpClientUi(self, value): """ Setter for **self.__tcpClientUi** attribute. :param value: Attribute value. :type value: QWidget """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "tcpClientUi")) @tcpClientUi.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def tcpClientUi(self): """ Deleter for **self.__tcpClientUi** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "tcpClientUi"))
@property def ioDirectory(self): """ Property for **self.__ioDirectory** attribute. :return: self.__ioDirectory. :rtype: unicode """ return self.__ioDirectory @ioDirectory.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def ioDirectory(self, value): """ Setter for **self.__ioDirectory** attribute. :param value: Attribute value. :type value: unicode """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "ioDirectory")) @ioDirectory.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def ioDirectory(self): """ Deleter for **self.__ioDirectory** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "ioDirectory"))
@property def bindingIdentifierPattern(self): """ Property for **self.__bindingIdentifierPattern** attribute. :return: self.__bindingIdentifierPattern. :rtype: unicode """ return self.__bindingIdentifierPattern @bindingIdentifierPattern.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def bindingIdentifierPattern(self, value): """ Setter for **self.__bindingIdentifierPattern** attribute. :param value: Attribute value. :type value: unicode """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "bindingIdentifierPattern")) @bindingIdentifierPattern.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def bindingIdentifierPattern(self): """ Deleter for **self.__bindingIdentifierPattern** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "bindingIdentifierPattern"))
@property def templateScriptSection(self): """ Property for **self.__templateScriptSection** attribute. :return: self.__templateScriptSection. :rtype: unicode """ return self.__templateScriptSection @templateScriptSection.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def templateScriptSection(self, value): """ Setter for **self.__templateScriptSection** attribute. :param value: Attribute value. :type value: unicode """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "templateScriptSection")) @templateScriptSection.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def templateScriptSection(self): """ Deleter for **self.__templateScriptSection** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "templateScriptSection"))
@property def templateIblSetAttributesSection(self): """ Property for **self.__templateIblSetAttributesSection** attribute. :return: self.__templateIblSetAttributesSection. :rtype: unicode """ return self.__templateIblSetAttributesSection @templateIblSetAttributesSection.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def templateIblSetAttributesSection(self, value): """ Setter for **self.__templateIblSetAttributesSection** attribute. :param value: Attribute value. :type value: unicode """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "templateIblSetAttributesSection")) @templateIblSetAttributesSection.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def templateIblSetAttributesSection(self): """ Deleter for **self.__templateIblSetAttributesSection** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "templateIblSetAttributesSection"))
@property def templateRemoteConnectionSection(self): """ Property for **self.__templateRemoteConnectionSection** attribute. :return: self.__templateRemoteConnectionSection. :rtype: unicode """ return self.__templateRemoteConnectionSection @templateRemoteConnectionSection.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def templateRemoteConnectionSection(self, value): """ Setter for **self.__templateRemoteConnectionSection** attribute. :param value: Attribute value. :type value: unicode """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "templateRemoteConnectionSection")) @templateRemoteConnectionSection.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def templateRemoteConnectionSection(self): """ Deleter for **self.__templateRemoteConnectionSection** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "templateRemoteConnectionSection"))
@property def overrideKeys(self): """ Property for **self.__overrideKeys** attribute. :return: self.__overrideKeys. :rtype: dict """ return self.__overrideKeys @overrideKeys.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError) def overrideKeys(self, value): """ Setter for **self.__overrideKeys** attribute. :param value: Attribute value. :type value: dict """ if value is not None: assert type(value) is dict, "'{0}' attribute: '{1}' type is not 'dict'!".format("overrideKeys", value) for key, element in value.iteritems(): assert type(key) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "overrideKeys", key) assert type(element) is foundations.parsers.AttributeCompound, \ "'{0}' attribute: '{1}' type is not 'foundations.parsers.AttributeCompound'!".format( "overrideKeys", element) self.__overrideKeys = value @overrideKeys.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def overrideKeys(self): """ Deleter for **self.__overrideKeys** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "overrideKeys"))
@property def defaultStringSeparator(self): """ Property for **self.__defaultStringSeparator** attribute. :return: self.__defaultStringSeparator. :rtype: unicode """ return self.__defaultStringSeparator @defaultStringSeparator.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError) def defaultStringSeparator(self, value): """ Setter for **self.__defaultStringSeparator** attribute. :param value: Attribute value. :type value: unicode """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "defaultStringSeparator", value) assert len(value) == 1, "'{0}' attribute: '{1}' has multiples characters!".format( "defaultStringSeparator", value) assert not re.search(r"\w", value), "'{0}' attribute: '{1}' is an alphanumeric character!".format( "defaultStringSeparator", value) self.__defaultStringSeparator = value @defaultStringSeparator.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def defaultStringSeparator(self): """ Deleter for **self.__defaultStringSeparator** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "defaultStringSeparator"))
@property def unnamedLightName(self): """ Property for **self.__unnamedLightName** attribute. :return: self.__unnamedLightName. :rtype: unicode """ return self.__unnamedLightName @unnamedLightName.setter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError) def unnamedLightName(self, value): """ Setter for **self.__unnamedLightName** attribute. :param value: Attribute value. :type value: unicode """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "unnamedLightName", value) self.__unnamedLightName = value @unnamedLightName.deleter # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def unnamedLightName(self): """ Deleter for **self.__unnamedLightName** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "unnamedLightName")) #****************************************************************************************************************** #*** Class methods. #******************************************************************************************************************
[docs] def activate(self, engine): """ Activates the Component. :param engine: Engine to attach the Component to. :type engine: QObject :return: Method success. :rtype: bool """ LOGGER.debug("> Activating '{0}' Component.".format(self.__class__.__name__)) self.__engine = engine self.__iblSetsOutliner = self.__engine.componentsManager["core.iblSetsOutliner"] self.__templatesOutliner = self.__engine.componentsManager["core.templatesOutliner"] self.__tcpClientUi = self.__engine.componentsManager["addons.tcpClientUi"] self.__ioDirectory = os.path.join(self.__engine.userApplicationDataDirectory, Constants.ioDirectory, self.__ioDirectory) not foundations.common.pathExists(self.__ioDirectory) and os.makedirs(self.__ioDirectory) self.activated = True return True
[docs] def deactivate(self): """ Deactivates the Component. :return: Method success. :rtype: bool """ LOGGER.debug("> Deactivating '{0}' Component.".format(self.__class__.__name__)) self.__engine = None self.__iblSetsOutliner = None self.__templatesOutliner = None self.__tcpClientUi = None self.__ioDirectory = os.path.basename(os.path.abspath(self.__ioDirectory)) self.activated = False return True
[docs] def initializeUi(self): """ Initializes the Component ui. :return: Method success. :rtype: bool """ LOGGER.debug("> Initializing '{0}' Component ui.".format(self.__class__.__name__)) if platform.system() in ("Darwin", "Linux"): self.Options_groupBox.hide() # Signals / Slots. self.Output_Loader_Script_pushButton.clicked.connect(self.__Output_Loader_Script_pushButton__clicked) self.Send_To_Software_pushButton.clicked.connect(self.__Send_To_Software_pushButton__clicked) self.__templatesOutliner.view.selectionModel().selectionChanged.connect( self.__templatesOutliner_view_selectionModel__selectionChanged) self.initializedUi = True return True
[docs] def uninitializeUi(self): """ Uninitializes the Component ui. :return: Method success. :rtype: bool """ LOGGER.debug("> Uninitializing '{0}' Component ui.".format(self.__class__.__name__)) # Signals / Slots. self.Output_Loader_Script_pushButton.clicked.disconnect(self.__Output_Loader_Script_pushButton__clicked) self.Send_To_Software_pushButton.clicked.disconnect(self.__Send_To_Software_pushButton__clicked) self.__templatesOutliner.view.selectionModel().selectionChanged.disconnect( self.__templatesOutliner_view_selectionModel__selectionChanged) self.initializedUi = False return True
[docs] def addWidget(self): """ Adds the Component Widget to the engine. :return: Method success. :rtype: bool """ LOGGER.debug("> Adding '{0}' Component Widget.".format(self.__class__.__name__)) self.__engine.addDockWidget(Qt.DockWidgetArea(self.__dockArea), self) return True
[docs] def removeWidget(self): """ Removes the Component Widget from the engine. :return: Method success. :rtype: bool """ LOGGER.debug("> Removing '{0}' Component Widget.".format(self.__class__.__name__)) self.__engine.removeDockWidget(self) self.setParent(None) return True
def __Output_Loader_Script_pushButton__clicked(self, checked): """ Defines the slot triggered by **Output_Loader_Script_pushButton** Widget when clicked. :param checked: Checked state. :type checked: bool """ self.outputLoaderScriptUi() def __Send_To_Software_pushButton__clicked(self, checked): """ Defines the slot triggered by **Send_To_Software_pushButton** Widget when clicked. :param checked: Checked state. :type checked: bool """ self.sendLoaderScriptToSoftwareUi() def __templatesOutliner_view_selectionModel__selectionChanged(self, selectedItems, deselectedItems): """ Defines the slot triggered by **templatesOutliner.view** Model when selection changed :param selectedItems: Selected items. :type selectedItems: QItemSelection :param deselectedItems: Deselected items. :type deselectedItems: QItemSelection """ selectedTemplates = self.__templatesOutliner.getSelectedTemplates() template = foundations.common.getFirstItem(selectedTemplates) if not (template and foundations.common.pathExists(template.path)): return LOGGER.debug("> Parsing '{0}' Template for '{1}' section.".format(template.name, self.__templateRemoteConnectionSection)) templateSectionsFileParser = foundations.parsers.SectionsFileParser(template.path) templateSectionsFileParser.parse(rawSections=(self.__templateScriptSection)) if not self.__templateRemoteConnectionSection in templateSectionsFileParser.sections: return LOGGER.debug("> {0}' section found.".format(self.__templateRemoteConnectionSection)) connectionType = foundations.parsers.getAttributeCompound("ConnectionType", templateSectionsFileParser.getValue("ConnectionType", self.__templateRemoteConnectionSection)) if connectionType.value == "Socket": LOGGER.debug("> Remote connection type: 'Socket'.") self.__tcpClientUi.address = foundations.parsers.getAttributeCompound("DefaultAddress", templateSectionsFileParser.getValue("DefaultAddress", self.__templateRemoteConnectionSection)).value self.__tcpClientUi.port = int(foundations.parsers.getAttributeCompound("DefaultPort", templateSectionsFileParser.getValue("DefaultPort", self.__templateRemoteConnectionSection)).value) elif connectionType.value == "Win32": LOGGER.debug("> Remote connection: 'Win32'.") # Oncilla: Statement commented by auto-documentation process: # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(umbra.exceptions.notifyExceptionHandler, # Oncilla: Statement commented by auto-documentation process: foundations.exceptions.FileExistsError, # Oncilla: Statement commented by auto-documentation process: Exception)
[docs] def outputLoaderScriptUi(self): """ Outputs the Loader Script. :return: Method success. :rtype: bool :note: May require user interaction. """ LOGGER.debug("> Initializing Loader Script output.") selectedTemplates = self.__templatesOutliner.getSelectedTemplates() if selectedTemplates and len(selectedTemplates) != 1: self.__engine.notificationsManager.warnify( "{0} | Multiple selected Templates, '{1}' will be used!".format(self.__class__.__name__, foundations.common.getFirstItem(selectedTemplates).name)) template = foundations.common.getFirstItem(selectedTemplates) if not template: raise foundations.exceptions.UserError( "{0} | In order to output the Loader Script, you need to select a Template!".format(self.__class__.__name__)) if not foundations.common.pathExists(template.path): raise foundations.exceptions.FileExistsError("{0} | '{1}' Template file doesn't exists!".format( self.__class__.__name__, template.name)) selectedIblSets = self.__iblSetsOutliner.getSelectedIblSets() if selectedIblSets and len(selectedIblSets) != 1: self.__engine.notificationsManager.warnify( "{0} | Multiple selected Ibl Sets, '{1}' will be used!".format(self.__class__.__name__, foundations.common.getFirstItem(selectedIblSets).name)) iblSet = foundations.common.getFirstItem(selectedIblSets) if not iblSet: raise foundations.exceptions.UserError( "{0} | In order to output the Loader Script, you need to select an Ibl Set!".format(self.__class__.__name__)) if not foundations.common.pathExists(iblSet.path): raise foundations.exceptions.FileExistsError("{0} | '{1}' Ibl Set file doesn't exists!".format( self.__class__.__name__, iblSet.title)) if self.outputLoaderScript(template, iblSet): self.__engine.notificationsManager.notify( "{0} | '{1}' output done!".format(self.__class__.__name__, template.outputScript)) return True else: raise Exception("{0} | Exception raised: '{1}' output failed!".format(self.__class__.__name__, template.outputScript)) # Oncilla: Statement commented by auto-documentation process: # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(umbra.exceptions.notifyExceptionHandler, Exception)
[docs] def sendLoaderScriptToSoftwareUi(self): """ Sends the Loader Script to associated 3d package. :return: Method success. :rtype: bool :note: May require user interaction. """ if not self.outputLoaderScriptUi(): return False selectedTemplates = self.__templatesOutliner.getSelectedTemplates() template = foundations.common.getFirstItem(selectedTemplates) if not template: return False loaderScriptPath = foundations.strings.getNormalizedPath(os.path.join(self.__ioDirectory, template.outputScript)) if self.Convert_To_Posix_Paths_checkBox.isChecked(): loaderScriptPath = foundations.strings.toPosixPath(loaderScriptPath) if self.sendLoaderScriptToSoftware(template, loaderScriptPath): return True else: raise Exception("{0} | Exception raised while sending Loader Script!".format(self.__class__.__name__)) # Oncilla: Statement commented by auto-documentation process: # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(umbra.exceptions.notifyExceptionHandler, # Oncilla: Statement commented by auto-documentation process: foundations.exceptions.DirectoryExistsError)
[docs] def outputLoaderScript(self, template, iblSet): """ Outputs the Loader Script. :param template: Template. :type template: Template :param iblSet: Ibl Set. :type iblSet: IblSet :return: Loader Script file. :rtype: unicode """ self.__overrideKeys = self.getDefaultOverrideKeys() for component in self.__engine.componentsManager.listComponents(): profile = self.__engine.componentsManager.components[component] interface = self.__engine.componentsManager.getInterface(component) if interface.activated and profile.name != self.name: hasattr(interface, "getOverrideKeys") and interface.getOverrideKeys() if self.__engine.parameters.loaderScriptsOutputDirectory: if foundations.common.pathExists(self.__engine.parameters.loaderScriptsOutputDirectory): loaderScript = File(os.path.join(self.__engine.parameters.loaderScriptsOutputDirectory, template.outputScript)) else: raise foundations.exceptions.DirectoryExistsError( "{0} | '{1}' loader Script output directory doesn't exists!".format( self.__class__.__name__, self.__engine.parameters.loaderScriptsOutputDirectory)) else: loaderScript = File(os.path.join(self.__ioDirectory, template.outputScript)) LOGGER.debug("> Loader Script output file path: '{0}'.".format(loaderScript.path)) loaderScript.content = self.getLoaderScript(template.path, iblSet.path, self.__overrideKeys) if loaderScript.content and loaderScript.write(): return loaderScript.path # Oncilla: Statement commented by auto-documentation process: # Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(umbra.exceptions.notifyExceptionHandler, # Oncilla: Statement commented by auto-documentation process: sibl_gui.exceptions.SocketConnectionError, # Oncilla: Statement commented by auto-documentation process: sibl_gui.exceptions.Win32OLEServerConnectionError)
[docs] def sendLoaderScriptToSoftware(self, template, loaderScriptPath): """ Sends the Loader Script to associated 3d package. :param template: Template. :type template: Template :param loaderScriptPath: Loader Script path. :type loaderScriptPath: unicode :return: Method success. :rtype: bool """ LOGGER.info("{0} | Starting remote connection!".format(self.__class__.__name__)) templateSectionsFileParser = foundations.parsers.SectionsFileParser(template.path) templateSectionsFileParser.parse(rawSections=(self.__templateScriptSection)) connectionType = foundations.parsers.getAttributeCompound("ConnectionType", templateSectionsFileParser.getValue("ConnectionType", self.__templateRemoteConnectionSection)) if connectionType.value == "Socket": try: connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connection.settimeout(2.5) connection.connect((foundations.strings.toString(self.__tcpClientUi.address), self.__tcpClientUi.port)) socketCommand = foundations.parsers.getAttributeCompound("ExecutionCommand", templateSectionsFileParser.getValue("ExecutionCommand", self.__templateRemoteConnectionSection)).value.replace("$loaderScriptPath", loaderScriptPath) LOGGER.debug("> Current socket command: '%s'.", socketCommand) connection.send(socketCommand) self.__engine.notificationsManager.notify( "{0} | Socket connection command dispatched!".format(self.__class__.__name__)) dataBack = connection.recv(4096) LOGGER.debug("> Received from connection: '{0}'.".format(dataBack)) connection.close() LOGGER.info("{0} | Closing remote connection!".format(self.__class__.__name__)) except socket.timeout as error: LOGGER.info("{0} | Closing remote connection on timeout!".format(self.__class__.__name__)) except Exception as error: raise sibl_gui.exceptions.SocketConnectionError( "{0} | Socket connection error: '{1}'!".format(self.__class__.__name__, error)) elif connectionType.value == "Win32": if platform.system() == "Windows" or platform.system() == "Microsoft": try: import win32com.client connection = win32com.client.Dispatch(foundations.parsers.getAttributeCompound("TargetApplication", templateSectionsFileParser.getValue("TargetApplication", self.__templateRemoteConnectionSection)).value) connection._FlagAsMethod(self.__win32ExecutionMethod) connectionCommand = foundations.parsers.getAttributeCompound("ExecutionCommand", templateSectionsFileParser.getValue("ExecutionCommand", self.__templateRemoteConnectionSection)).value.replace("$loaderScriptPath", loaderScriptPath) LOGGER.debug("> Current connection command: '%s'.", connectionCommand) getattr(connection, self.__win32ExecutionMethod)(connectionCommand) self.__engine.notificationsManager.notify( "{0} | Win32 connection command dispatched!".format(self.__class__.__name__)) except Exception as error: raise sibl_gui.exceptions.Win32OLEServerConnectionError( "{0} | Win32 OLE server connection error: '{1}'!".format(self.__class__.__name__, error)) return True
[docs] def getDefaultOverrideKeys(self): """ Gets default override keys. :return: Override keys. :rtype: dict """ LOGGER.debug("> Constructing default override keys.") overrideKeys = {} selectedTemplates = self.__templatesOutliner.getSelectedTemplates() template = foundations.common.getFirstItem(selectedTemplates) if template: LOGGER.debug("> Adding '{0}' override key with value: '{1}'.".format("Template|Path", template.path)) overrideKeys["Template|Path"] = foundations.parsers.getAttributeCompound("Template|Path", template.path) selectedIblSets = self.__iblSetsOutliner.getSelectedIblSets() iblSet = foundations.common.getFirstItem(selectedIblSets) if iblSet: LOGGER.debug("> Adding '{0}' override key with value: '{1}'.".format("Ibl Set|Path", iblSet.path)) overrideKeys["Ibl Set|Path"] = iblSet.path and foundations.parsers.getAttributeCompound("Ibl Set|Path", foundations.strings.getNormalizedPath(iblSet.path)) LOGGER.debug("> Adding '{0}' override key with value: '{1}'.".format("Background|BGfile", iblSet.backgroundImage)) overrideKeys["Background|BGfile"] = iblSet.backgroundImage and foundations.parsers.getAttributeCompound( "Background|BGfile", foundations.strings.getNormalizedPath( iblSet.backgroundImage)) LOGGER.debug("> Adding '{0}' override key with value: '{1}'.".format("Enviroment|EVfile", iblSet.lightingImage)) overrideKeys["Enviroment|EVfile"] = iblSet.lightingImage and foundations.parsers.getAttributeCompound( "Enviroment|EVfile", foundations.strings.getNormalizedPath( iblSet.lightingImage)) LOGGER.debug("> Adding '{0}' override key with value: '{1}'.".format("Reflection|REFfile", iblSet.reflectionImage)) overrideKeys["Reflection|REFfile"] = iblSet.reflectionImage and foundations.parsers.getAttributeCompound( "Reflection|REFfile", foundations.strings.getNormalizedPath( iblSet.reflectionImage)) return overrideKeys
[docs] def getLoaderScript(self, template, iblSet, overrideKeys): """ Builds a Loader Script. :param template: Template path. :type template: unicode :param iblSet: Ibl Set path. :type iblSet: unicode :param overrideKeys: Override keys. :type overrideKeys: dict :return: Loader Script. :rtype: list """ LOGGER.debug("> Parsing Template file: '{0}'.".format(template)) templateSectionsFileParser = foundations.parsers.SectionsFileParser(template) templateSectionsFileParser.parse(rawSections=(self.__templateScriptSection)) templateSections = dict.copy(templateSectionsFileParser.sections) for attribute, value in dict.copy(templateSections[self.__templateIblSetAttributesSection]).iteritems(): templateSections[self.__templateIblSetAttributesSection][foundations.namespace.removeNamespace(attribute, rootOnly=True)] = value del templateSections[self.__templateIblSetAttributesSection][attribute] LOGGER.debug("> Binding Templates file attributes.") bindedAttributes = dict(((attribute, foundations.parsers.getAttributeCompound(attribute, value)) for section in templateSections if section not in (self.__templateScriptSection) for attribute, value in templateSections[section].iteritems())) LOGGER.debug("> Parsing Ibl Set file: '{0}'.".format(iblSet)) iblSetSectionsFileParser = foundations.parsers.SectionsFileParser(iblSet) iblSetSectionsFileParser.parse() iblSetSections = dict.copy(iblSetSectionsFileParser.sections) LOGGER.debug("> Flattening Ibl Set file attributes.") flattenedIblAttributes = dict(((attribute, foundations.parsers.getAttributeCompound(attribute, value)) for section in iblSetSections for attribute, value in iblSetSections[section].iteritems())) for attribute in flattenedIblAttributes: if attribute in bindedAttributes: bindedAttributes[attribute].value = flattenedIblAttributes[attribute].value if "Lights|DynamicLights" in bindedAttributes: LOGGER.debug("> Building '{0}' custom attribute.".format("Lights|DynamicLights")) dynamicLights = [] for section in iblSetSections: if re.search(r"Light\d+", section): dynamicLights.append(section) lightName = iblSetSectionsFileParser.getValue("LIGHTname", section) dynamicLights.append(lightName and lightName or self.__unnamedLightName) lightColorTokens = iblSetSectionsFileParser.getValue("LIGHTcolor", section).split(",") for color in lightColorTokens: dynamicLights.append(color) dynamicLights.append(iblSetSectionsFileParser.getValue("LIGHTmulti", section)) dynamicLights.append(iblSetSectionsFileParser.getValue("LIGHTu", section)) dynamicLights.append(iblSetSectionsFileParser.getValue("LIGHTv", section)) LOGGER.debug("> Adding '{0}' custom attribute with value: '{1}'.".format("Lights|DynamicLights", ", ".join(dynamicLights))) bindedAttributes["Lights|DynamicLights"].value = self.__defaultStringSeparator.join(dynamicLights) LOGGER.debug("> Updating attributes with override keys.") for attribute in overrideKeys: if attribute in bindedAttributes: bindedAttributes[attribute].value = overrideKeys[attribute] and overrideKeys[attribute].value or None LOGGER.debug("> Updating Loader Script content.") loaderScript = templateSectionsFileParser.sections[ self.__templateScriptSection][templateSectionsFileParser.rawSectionContentIdentifier] boundLoaderScript = [] for line in loaderScript: bindingParameters = re.findall(r"{0}".format(self.__bindingIdentifierPattern), line) if bindingParameters: for parameter in bindingParameters: for attribute in bindedAttributes.itervalues(): if not parameter == attribute.link: continue LOGGER.debug("> Updating Loader Script parameter '{0}' with value: '{1}'.".format(parameter, attribute.value)) line = line.replace(parameter, attribute.value if attribute.value else "-1") boundLoaderScript.append(line) return boundLoaderScript