Пример #1
0
    def setValue(self, value):
        """
		Verändert den Wert der Eigenschaft.
		"""

        if self.__value != value:
            self.__value = value
            Debug.debug("Ändere Eigenschaft {} zu {}".format(self.name, self.__value), level=3)
            self.valueChanged.emit(self.__value)
            self.traitChanged.emit(self)
Пример #2
0
    def setValue(self, value):
        """
		Verändert den Wert der Eigenschaft.
		"""

        if self.__value != value:
            self.__value = value
            Debug.debug("Ändere Eigenschaft {} zu {}".format(
                self.name, self.__value),
                        level=3)
            self.valueChanged.emit(self.__value)
            self.traitChanged.emit(self)
    def read(self):
        """
		Diese Methode startet den Lesevorgang.

		Es wird kontrolliert, ob es sich um eine Zuässige Template-Datei für dieses Programm handelt

		\exception ErrXmlTooOldVersion Die XML-Datei hat die falsche Version.

		\exception ErrXmlOldVersion Die XML-Datei hat die falsche Version.

		\exception ErrXmlParsing Beim Parsen der XML-Datei ist ein Fehler aufgetreten.
		"""

        #dbgStart = Debug.timehook()
        for item in self.__templateFiles:
            Debug.debug("Reading from file \"{}\".".format(item), level=2)
            file_content = None
            with open(item, mode="rb") as fi:
                file_content = fi.read()

            ## Erzeuge eine temporäre Datei, mit der etree umgehen kann und schreibe den Inhalt aus der Qt-Resource in selbige hinein.
            file_like = tempfile.SpooledTemporaryFile()
            ## Dank dieser Einstellung kann ich zlib verwenden um Dateien zu dekomprimieren, welche mittels des gzip-Moduls komprimiert wurden.
            decompressed_object = zlib.decompressobj(16 + zlib.MAX_WBITS)
            file_like.write(decompressed_object.decompress(file_content))
            file_like.seek(0)

            xml_content = etree.parse(file_like)
            file_like.close()

            xml_root_element = xml_content.getroot()

            version_source = xml_root_element.attrib["version"]
            required_source = False
            if "required" in xml_root_element.attrib:
                required_source = xml_root_element.attrib["required"].lower(
                ) == "true"
            #Debug.debug(versionSource)

            try:
                self.checkXmlVersion(xml_root_element.tag,
                                     version_source,
                                     item,
                                     required=required_source)
            except ErrXmlOldVersion as e:
                text_description = self.tr(
                    "{} Loading of template will be continued but errors may occur."
                    .format(str(e)))
                self.exception_raised.emit(text_description, "warning")

            result = self.readSpecies(xml_content)
            self.readTemplate(xml_content, result[0], result[1])
Пример #4
0
	def checkXmlVersion(self, name, version, filename=None, required=False ):
		"""
		Überprüft die Version der XML-Datei. Damit ist die SoulCreator-Version gemeint.

		\param required Für den Betrieb des Programms erfordelriche Dateien sorgen dafür, daß das Programm einen entsprechend ernsten Fehler ausgibt.
		"""

		Debug.debug( "Version of file \"{name_file}\": {name} {version}".format(
			name_file=filename,
			name=name,
			version=version,
		), level=3 )

		if name == Config.PROGRAM_NAME:
			if version == Config.version():
				return
			else:
				# Unterschiede in der Minor-Version sind ignorierbar, Unterschiede in der Major-Version allerdings nicht.
				version_split = version.split(".")
				version_split = [ int(item) for item in version_split ]

				if filename is not None:
					filename = os.path.basename(filename)
				if version_split[0] < Config.PROGRAM_VERSION["major"]:
					raise Error.ErrXmlVersion(
						"XML-file \"{filename}\" was created with {program_name} {file_version} and is incompatible with {program_name} {program_version}.\nLoading of file aborted.".format(
							filename=filename,
							file_version=version,
							program_name=Config.PROGRAM_NAME,
							program_version=Config.version()
						),
						got=version,
						critical=required
					)
				else:
					raise Error.ErrXmlOldVersion(
						"XML-file \"{filename}\" was created with {program_name} {file_version} and may be compatible with {program_name} {program_version}.".format(
							filename=filename,
							file_version=version,
							program_name=Config.PROGRAM_NAME,
							program_version=Config.version()
						),
						got=version,
						critical=required
					)
		else:
			raise Error.ErrXmlVersion(
				got="{} {}".format(name, version),
				expected="{} {}".format(Config.PROGRAM_NAME, Config.version()),
				critical=required
			)
Пример #5
0
	def readCharacterIdentity(self, tree):
		"""
		Lese die Identitäten des Charkaters aus.

		\note Derzeit gibt es nur eine. forenames="" surname="" honorname="" nickname="" supername="" gender="Male"
		"""

		identity = tree.find("identities/identity")
		if identity is not None:
			self.__character.identity.forenames = self.getElementAttribute(identity, "forenames").split(" ")
			self.__character.identity.surname = self.getElementAttribute(identity, "surname")
			self.__character.identity.honorname = self.getElementAttribute(identity, "honorname")
			self.__character.identity.nickname = self.getElementAttribute(identity, "nickname")
			self.__character.identity.supername = self.getElementAttribute(identity, "supername")
			self.__character.identity.gender = self.getElementAttribute(identity, "gender")
		else:
			Debug.debug( "No identity of the character found.", level=3 )
	def read(self):
		"""
		Diese Methode startet den Lesevorgang.

		Es wird kontrolliert, ob es sich um eine Zuässige Template-Datei für dieses Programm handelt

		\exception ErrXmlTooOldVersion Die XML-Datei hat die falsche Version.

		\exception ErrXmlOldVersion Die XML-Datei hat die falsche Version.

		\exception ErrXmlParsing Beim Parsen der XML-Datei ist ein Fehler aufgetreten.
		"""

		#dbgStart = Debug.timehook()
		for item in self.__templateFiles:
			Debug.debug( "Reading from file \"{}\".".format(item), level=2 )
			file_content = None
			with open(item, mode="rb") as fi:
				file_content = fi.read()

			## Erzeuge eine temporäre Datei, mit der etree umgehen kann und schreibe den Inhalt aus der Qt-Resource in selbige hinein.
			file_like = tempfile.SpooledTemporaryFile()
			## Dank dieser Einstellung kann ich zlib verwenden um Dateien zu dekomprimieren, welche mittels des gzip-Moduls komprimiert wurden.
			decompressed_object = zlib.decompressobj(16 + zlib.MAX_WBITS)
			file_like.write(decompressed_object.decompress(file_content))
			file_like.seek(0)

			xml_content = etree.parse(file_like)
			file_like.close()

			xml_root_element = xml_content.getroot()

			version_source = xml_root_element.attrib["version"]
			required_source = False
			if "required" in xml_root_element.attrib:
				required_source = xml_root_element.attrib["required"].lower() == "true"
			#Debug.debug(versionSource)

			try:
				self.checkXmlVersion( xml_root_element.tag, version_source, item, required=required_source )
			except ErrXmlOldVersion as e:
				text_description = self.tr( "{} Loading of template will be continued but errors may occur.".format( str( e ) ) )
				self.exception_raised.emit( text_description, "warning" )

			result = self.readSpecies(xml_content)
			self.readTemplate(xml_content, result[0], result[1])
Пример #7
0
	def read( self, file_name ):
		"""
		Startet den Lesevorgang.

		\note Diese Funktion kann sowohl normale xml-Dateien als auch mittels gzip komprimierte xml-Dateien laden.
		"""

		Debug.debug( "Loading Character out of {}.".format(file_name) )

		## Mittels lxml kann diese Funktion normale XML-Dateien und offenbar auch mittels gzip komprimierte XML-Dateien laden.
		## Das normale ElementTree-Modul kann das aber nicht.
		xml_content = None
		try:
			xml_content = etree.parse(file_name)
		except etree.ParseError:
			## Möglicherweise eine komprimierte Datei und lxml wurde nicht verwendet?
			xml_content = etree.parse(gzip.GzipFile(file_name))
		xmlRootElement = xml_content.getroot()

		versionSource = xmlRootElement.attrib["version"]

		try:
			self.checkXmlVersion( xmlRootElement.tag, versionSource, file_name )
		except ErrXmlOldVersion as e:
			text_description = self.tr( "{} Loading will be continued but errors may occur.".format( str( e ) ) )
			self.exception_raised.emit( text_description, "warning" )

		## Die Daten müssen zuerst geladen werden, damit schon beim Laden die Unterschiedung zwischen Kindern und Erwachsenen erfolgen kann.
		self.readDates(xml_content)
		self.readCharacterInfo(xml_content)
		self.readCharacterIdentity(xml_content)
		self.readDerangements(xml_content)
		self.readTraits(xml_content)
		self.readItems(xml_content)
		self.readSpeciesSpecials(xml_content)
		self.readPicture(xml_content)
Пример #8
0
def _do_connect(trait, storage, character):
	"""
	Durchsucht alle existierenden Eigenschaften und kontrolliert, ob sie als Voraussetzung für <trait> in Frage kommen.
	"""

	trait_prerequisites = trait.prerequisitesText
	Debug.debug(
		"Voraussetzungen von {trait}: {prerequisite}".format(trait=trait.name, prerequisite=trait_prerequisites),
		level=4,
	)
	stop_loop = False
	for prerequisite_typ in storage.traits.keys():
		## Angabe in den Ressourcen: <typ>.<trait>[.<specialty>]
		typ_resource = "{}.".format(prerequisite_typ)
		## Ist eine Eigenschaft diesen Typs eine Voraussetzung der Eigenschaft?
		if typ_resource in trait_prerequisites:
			#Debug.debug("{trait} hat {typ} als Voraussetzung!".format(trait=trait.name, typ=item))
			for prerequisite_category in storage.categories(prerequisite_typ):
				for prerequisite_trait in character.traits[prerequisite_typ][prerequisite_category].values():
					## Überprüfen ob die Eigenschaft im Anforderungstext des Merits vorkommt.
					trait_resource = "{}.{}".format(prerequisite_typ, prerequisite_trait.identifier)
					if trait_resource in trait_prerequisites:
						# Überprüfen ob diese Eigenschaft tatsächlich in den Voraussetzungen enthalten ist. Bei dieser Überprüfung ist es wichtig, auf den ganuen Namen zu prüfen: "Status" != "Status: Camarilla"
						# Diese Überprüfung wird aber nur durchgeführt, wenn die Chance besteht, daß dieser String identisch ist.
						match_list = re.findall(r"(\w+\.[\w]+[:\s]*[\w]+)(?=[\s]*[><=.]+)", trait_prerequisites, re.UNICODE)
						if trait_resource in match_list:
							stop_loop = _create_connection( trait, prerequisite_trait, trait_prerequisites, trait_resource )
							if stop_loop:
								return
	if not stop_loop:
		## Es kann auch die Supereigenschaft als Voraussetzung vorkommen ...
		if Config.POWERSTAT_IDENTIFIER in trait_prerequisites:
			character.powerstatChanged.connect(trait.checkPrerequisites)
		## ... oder die Moral
		if Config.MORALITY_IDENTIFIER in trait_prerequisites:
			character.moralityChanged.connect(trait.checkPrerequisites)
Пример #9
0
def checkPrerequisites(trait, storage, character):
	if not isinstance(trait, BasicTrait):
		Debug.debug("Error!")
	else:
		if trait.hasPrerequisites and trait.prerequisiteTraits:
			## Angabe in den Ressourcen: <typ>.<trait>[.<specialty>] >|<|== ? and|or ...
			## Diese werden aufgeteilt in [[ <typ>, <trait>, <specialty> ] >|<|== ? and|or ... ]
			traitPrerequisites = trait.prerequisitesText
			#Debug.debug("{trait} hat Voraussetzungen? {truth}".format(trait=trait.name, truth=trait.hasPrerequisites))
			for item in trait.prerequisiteTraits:
				# Überprüfen, ob die Eigenschaft im Anforderungstext des Merits vorkommt.
				literalReference = "ptr{}".format(id(item))
				if literalReference in traitPrerequisites:
					## Spezialisierungen
					literalReferencePlusSpecial = "{}.".format(literalReference)
					if literalReferencePlusSpecial in traitPrerequisites:
						idx = traitPrerequisites.index(literalReferencePlusSpecial)
						#traitWithSpecial = re.search(r"\w+\.{1}(\w+)", traitPrerequisites[idx:])
						#special = traitWithSpecial.group(1)
						specialties = re.findall(r"\w+\.{1}(\w+)", traitPrerequisites[idx:])
						for special in specialties:
							if special in item.specialties:
								traitPrerequisites = traitPrerequisites.replace(".{}".format(special), "")
							else:
								traitPrerequisites = traitPrerequisites.replace("{}.{}".format(literalReference, special), "0")
					traitPrerequisites = traitPrerequisites.replace(literalReference, str(item.value))
			# Es kann auch die Supereigenschaft als Voraussetzung vorkommen ...
			if Config.POWERSTAT_IDENTIFIER in traitPrerequisites:
				traitPrerequisites = traitPrerequisites.replace(Config.POWERSTAT_IDENTIFIER, str(character.powerstat))
			# ... oder die Moral
			if Config.MORALITY_IDENTIFIER in traitPrerequisites:
				traitPrerequisites = traitPrerequisites.replace(Config.MORALITY_IDENTIFIER, str(character.morality))

			# Die Voraussetzungen sollten jetzt nurnoch aus Zahlen und logischen Operatoren bestehen.
			## eval() is dangerous
			## Aber ast.literal_eval() erlaubt nicht das Auswerten von "a < b" etc.
			## Es werden ausschließlich Zahlen, Klammern "(" und ")" und die Zeichen "<" "<=" ">" ">=" "==" und "!=" sowie den logischen Verknüpfungen "and" und "or" erlaubt.
			#traitPrerequisites = "1 < 2 and 2 < 3"
			if re.match( r"^(\(*\d+\s*[<>=!]+\s*\d+\)*\s*(and|or)?\s*)+$", traitPrerequisites ):
				try:
					result = eval(traitPrerequisites)
					#Debug.debug("Eigenschaft {} ({} = {})".format(trait.name, traitPrerequisites, result))
				except (NameError, SyntaxError):
					Debug.debug("Error bei {}: {}".format(trait.name, traitPrerequisites))
					result = False
			else:
				raise ValueError("Only digits, spaces and the symbols \"<\", \">\", \"=\", \"!\", \"(\" and \")\" are allowed at this point.")

			Debug.debug( "Eigenschaft \"{}\" wird verfügbar? {}!".format(trait.name, result), level=4 )
			trait.setAvailable(result)
	def writeFile(self, tree, file_name):
		"""
		Schreibt den Elementbaum in eine Datei.

		Die Charaktere können als komprimierte Datei gespeichert werden, wenn dies in den Einstellungen so festgelegt wird.
		"""

		_character_data = None
		if lxmlLoadad:
			Debug.debug( "Using the advanced lxml-module to write the XML-tree." )
			_character_data = etree.tostring(tree, pretty_print=True, encoding="UTF-8", xml_declaration=True)
		else:
			Debug.debug( "Using the basic xml.etree.ElementTree-module to write the XML-tree." )
			_character_data = etree.tostring(tree, encoding="unicode")

		## In die Datei schreiben.
		if Config.compress_saves:
			Debug.debug( "Writing character into {} (compressed).".format(file_name) )
			with gzip.open(file_name, "w") as file_object:
				file_object.write(bytes(_character_data, "UTF-8"))
		else:
			Debug.debug( "Writing character into {} (uncompressed).".format(file_name) )
			with open(file_name, "w") as file_object:
				file_object.write(_character_data)
Пример #11
0
    def __init__(self, fileName=None, exportPath=None, parent=None):
        debug_timing_start = Debug.timehook()

        super(MainWindow, self).__init__(parent)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        QCoreApplication.setOrganizationName(Config.ORGANIZATION)
        QCoreApplication.setApplicationName(Config.PROGRAM_NAME)
        QCoreApplication.setApplicationVersion(Config.version())

        #Debug.debug(QApplication.style())

        self.setWindowTitle("")
        self.setWindowIcon(QIcon(":/icons/images/WoD.png"))

        self.__storage = StorageTemplate(self)
        self.storeTemplateData()
        self.__character = StorageCharacter(self.__storage)
        ## Später sollte ich mich für einen entscheiden!!
        self.__readCharacter = ReadXmlCharacter(self.__character)
        self.__writeCharacter = WriteXmlCharacter(self.__character)

        self.ui.pushButton_next.clicked.connect(
            self.ui.selectWidget_select.selectNext)
        self.ui.pushButton_previous.clicked.connect(
            self.ui.selectWidget_select.selectPrevious)
        self.ui.selectWidget_select.currentRowChanged.connect(
            self.ui.stackedWidget_traits.setCurrentIndex)
        self.ui.selectWidget_select.currentRowChanged.connect(
            self.setTabButtonState)
        #self.ui.selectWidget_select.currentRowChanged.connect(self.pageChanged.emit)
        self.__character.speciesChanged.connect(
            self.ui.selectWidget_select.changeIcons)

        self.__readCharacter.exception_raised.connect(
            self.showExceptionMessage)

        # Laden der Konfiguration
        self.readSettings()

        self.populateUi()

        Debug.timesince(debug_timing_start,
                        "Time neccessary to populate the UI.")

        debug_timing_between_start = Debug.timehook()

        self.activate()

        Debug.timesince(debug_timing_between_start,
                        "Time neccessary to activate the UI.")

        debug_timing_between_start = Debug.timehook()

        self.ui.selectWidget_select.currentRowChanged.connect(
            self.showCreationPoints)

        self.ui.actionSettings.triggered.connect(self.showSettingsDialog)
        self.ui.actionNew.triggered.connect(self.newCharacter)
        self.ui.actionOpen.triggered.connect(self.openCharacter)
        self.ui.actionSave.triggered.connect(self.saveCharacter)
        self.ui.actionExport.triggered.connect(self.exportCharacter)
        self.ui.actionPrint.triggered.connect(self.printCharacter)
        self.ui.actionAbout.triggered.connect(self.aboutApp)

        self.reset()
        Debug.timesince(debug_timing_between_start,
                        "Time neccessary to set all initial values.")

        debug_timing_between_start = Debug.timehook()

        ## Wird ein Dateiname angegeben, soll dieser sofort geladen werden.
        if fileName:
            if os.path.exists(fileName):
                if GlobalState.is_verbose:
                    print("Opening file {}.".format(fileName))
                self.openCharacter(fileName)
            elif fileName.lower() in [
                    species.lower()
                    for species in self.__storage.species.keys()
            ]:
                if GlobalState.is_verbose:
                    print(
                        "Empty Charactersheet of species {} will be created.".
                        format(fileName.lower()))
                self.__character.species = fileName[0].upper(
                ) + fileName[1:].lower()
                self.__character.setModified(False)
            else:
                Shell.print_warning(
                    "A file named \"{}\" does not exist.".format(fileName))

            Debug.timesince(debug_timing_between_start,
                            "Time neccessary to load a file at startup.")

        if exportPath:
            if GlobalState.is_verbose:
                print("Creating PDF {}".format(exportPath[0]))
            # exportPath ist eine Liste mit einem einzigen Element als Inhalt (argparse)
            self.__createPdf(exportPath[0])
            # Damit das Programm ordentlich geschlossen werden kann, muß auf das Starten der Event-Loop gewartet werden. dies geht am einfachsten mit einem QTimer.
            QTimer.singleShot(0, self.close)

        Debug.timesince(
            debug_timing_start,
            "The full time span neccessary to prepare the application for user input."
        )
Пример #12
0
	def __init__(self, fileName=None, exportPath=None, parent=None):
		debug_timing_start = Debug.timehook()

		super(MainWindow, self).__init__(parent)

		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)

		QCoreApplication.setOrganizationName( Config.ORGANIZATION )
		QCoreApplication.setApplicationName( Config.PROGRAM_NAME )
		QCoreApplication.setApplicationVersion( Config.version() )

		#Debug.debug(QApplication.style())

		self.setWindowTitle( "" )
		self.setWindowIcon( QIcon( ":/icons/images/WoD.png" ) )

		self.__storage = StorageTemplate( self )
		self.storeTemplateData()
		self.__character = StorageCharacter(self.__storage)
		## Später sollte ich mich für einen entscheiden!!
		self.__readCharacter = ReadXmlCharacter(self.__character)
		self.__writeCharacter = WriteXmlCharacter(self.__character)

		self.ui.pushButton_next.clicked.connect(self.ui.selectWidget_select.selectNext)
		self.ui.pushButton_previous.clicked.connect(self.ui.selectWidget_select.selectPrevious)
		self.ui.selectWidget_select.currentRowChanged.connect(self.ui.stackedWidget_traits.setCurrentIndex)
		self.ui.selectWidget_select.currentRowChanged.connect(self.setTabButtonState)
		#self.ui.selectWidget_select.currentRowChanged.connect(self.pageChanged.emit)
		self.__character.speciesChanged.connect(self.ui.selectWidget_select.changeIcons)

		self.__readCharacter.exception_raised.connect(self.showExceptionMessage)

		# Laden der Konfiguration
		self.readSettings()

		self.populateUi()

		Debug.timesince( debug_timing_start, "Time neccessary to populate the UI." )

		debug_timing_between_start = Debug.timehook()

		self.activate()

		Debug.timesince( debug_timing_between_start, "Time neccessary to activate the UI." )

		debug_timing_between_start = Debug.timehook()

		self.ui.selectWidget_select.currentRowChanged.connect(self.showCreationPoints)

		self.ui.actionSettings.triggered.connect(self.showSettingsDialog)
		self.ui.actionNew.triggered.connect(self.newCharacter)
		self.ui.actionOpen.triggered.connect(self.openCharacter)
		self.ui.actionSave.triggered.connect(self.saveCharacter)
		self.ui.actionExport.triggered.connect(self.exportCharacter)
		self.ui.actionPrint.triggered.connect(self.printCharacter)
		self.ui.actionAbout.triggered.connect(self.aboutApp)

		self.reset()
		Debug.timesince( debug_timing_between_start, "Time neccessary to set all initial values." )

		debug_timing_between_start = Debug.timehook()

		## Wird ein Dateiname angegeben, soll dieser sofort geladen werden.
		if fileName:
			if os.path.exists(fileName):
				if GlobalState.is_verbose:
					print("Opening file {}.".format(fileName))
				self.openCharacter(fileName)
			elif fileName.lower() in [ species.lower() for species in self.__storage.species.keys() ]:
				if GlobalState.is_verbose:
					print("Empty Charactersheet of species {} will be created.".format(fileName.lower()))
				self.__character.species = fileName[0].upper() + fileName[1:].lower()
				self.__character.setModified(False)
			else:
				Shell.print_warning("A file named \"{}\" does not exist.".format(fileName))

			Debug.timesince( debug_timing_between_start, "Time neccessary to load a file at startup." )

		if exportPath:
			if GlobalState.is_verbose:
				print("Creating PDF {}".format(exportPath[0]))
			# exportPath ist eine Liste mit einem einzigen Element als Inhalt (argparse)
			self.__createPdf(exportPath[0])
			# Damit das Programm ordentlich geschlossen werden kann, muß auf das Starten der Event-Loop gewartet werden. dies geht am einfachsten mit einem QTimer.
			QTimer.singleShot(0, self.close)

		Debug.timesince( debug_timing_start, "The full time span neccessary to prepare the application for user input." )