Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Tools/BlenderExport/ogrepkg/base.py @ 6

Last change on this file since 6 was 6, checked in by anonymous, 17 years ago

=…

File size: 11.4 KB
Line 
1"""Helper functions and classes.
2
3   @author Michael Reimpell
4"""
5# Copyright (C) 2005  Michael Reimpell
6#
7# This library is free software; you can redistribute it and/or
8# modify it under the terms of the GNU Lesser General Public
9# License as published by the Free Software Foundation; either
10# version 2.1 of the License, or (at your option) any later version.
11#
12# This library is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15# Lesser General Public License for more details.
16#
17# You should have received a copy of the GNU Lesser General Public
18# License along with this library; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21# epydoc doc format
22__docformat__ = "javadoc en"
23
24import sys
25import os
26import string
27import pickle
28import Blender
29
30def indent(indent):
31        """Indentation.
32       
33           @param indent Level of indentation.
34           @return String.
35        """
36        return "        "*indent
37       
38class Singleton:
39        """Ensure that a class has at most one instance.
40       
41        @cvar instances Existing instances.
42        """
43        instances = {}
44        def __init__(self):
45                """Constructor.
46                """
47                assert self.__class__ not in Singleton.instances.keys(), \
48                        "Class \"%s\" is a singleton." % self.__class__
49                Singleton.instances[self.__class__] = self
50                return
51        # @classmethod
52        def getSingleton(singletonClass):
53                """Returns singleton instance.
54                """
55                instance = None
56                if Singleton.instances.has_key(singletonClass):
57                        instance = Singleton.instances[singletonClass]
58                else:
59                        instance = singletonClass()
60                return instance
61        getSingleton = classmethod(getSingleton)
62
63class Model:
64        """Model interface.
65        """
66        def __init__(self):
67                self.viewList = []
68                return
69        def addView(self, view):
70                self.viewList.append(view)
71                return
72        def removeView(self, view):
73                if view in self.viewList:
74                        self.viewList.remove(view)
75                return
76        # protected
77        def _notify(self):
78                """Notify views.
79                """
80                for view in self.viewList:
81                        view.update()
82                return
83
84class View:
85        """View interface.
86        """
87        def __init__(self, model):
88                self.attachModel(model)
89                return
90        def __del__(self):
91                self.detachModel()
92                return
93        def attachModel(self, model):
94                self.model = model
95                self.model.addView(self)
96                return
97        def detachModel(self):
98                self.model.removeView(self)
99                return
100        def update(self):
101                return
102
103class Log(Singleton, Model):
104        """Logs messages and status.
105       
106           Logs messages as a list of strings and keeps track of the status.
107           Possible status values are info, warning and error.
108           
109           @cvar INFO info status
110           @cvar WARNING warning status
111           @cvar ERROR error status
112        """
113        INFO, WARNING, ERROR = range(3)
114        def __init__(self):
115                """Constructor.
116                """
117                Singleton.__init__(self)
118                Model.__init__(self)
119                self.clear()
120                return
121        def clear(self):
122                """Clears the log.
123                """
124                self.messageList = []
125                self.status = Log.INFO
126                return
127        def logInfo(self, message):
128                """Logs an info message.
129               
130                   @param message message string
131                """
132                self.messageList.append((Log.INFO, message))
133                self._notify()
134                return         
135        def logWarning(self, message):
136                """Logs a warning message.
137               
138                   The status is set to <code>Log.WARNING</code> if it is not already <code>Log.ERROR</code>.
139                   
140                   @param message message string
141                """
142                self.messageList.append((Log.WARNING, "Warning: "+message))
143                if not self.status == Log.ERROR:
144                        self.status = Log.WARNING
145                self._notify()
146                return
147        def logError(self, message):
148                """Logs an error message.
149               
150                   The status is set to <code>Log.ERROR</code>.
151                   
152                   @param message message string
153                """
154                self.messageList.append((Log.ERROR, "Error: "+message))
155                self.status = Log.ERROR
156                self._notify()
157                return
158        def getStatus(self):
159                """Gets the current status.
160               
161                   The status can be
162                   <ul>
163                   <li><code>Log.INFO</code>
164                   <li><code>Log.WARNING</code>
165                   <li><code>Log.ERROR</code>
166                   </ul>
167                   
168                   @return status
169                """
170                return self.status
171        def getMessageList(self):
172                """Returns the list of log messages.
173               
174                   @return list of tuples (status, message)
175                """
176                return self.messageList
177
178class PackageSettings(Singleton):
179        """Manages package configuration.
180        """
181        def __init__(self):
182                Singleton.__init__(self)
183                self.dict = {'objectDict':{}}
184                self.textName = 'OgrePackage.cfg'
185                return
186        def save(self):
187                """Save to Blender text 'OgrePackage.cfg'.
188                """
189                # remove old configuration text
190                if self.textName in [text.getName() for text in Blender.Text.Get()]:
191                        oldSettingsText = Blender.Text.Get(self.textName)
192                        oldSettingsText.setName('OgrePackage.old')
193                        Blender.Text.unlink(oldSettingsText)
194                # write new configuration text
195                settingsText = Blender.Text.New(self.textName)
196                settingsText.write('OGRE Package settings file.\n\nThis file is automatically created. Please don\'t edit this file directly.\n\n')
197                try:
198                        # pickle
199                        settingsText.write(pickle.dumps(self.dict))
200                except (pickle.PickleError):
201                        Log.getSingleton().logError('Couldn\'t pickle package settings!')
202                return
203        def clearNoneExistingObjects(self):
204                """Maintainance method.
205               
206                   As settigns are shared among the package, they get never deleted automatically.
207                   All settings that are loaded are saved again. Therefore it is advisable to clear
208                   the object settings for deleted objects from time to time. Applications that use
209                   the package are responsible to maintain their settings.
210                """
211                existingNameList = [object.getName() for object in Blender.Object.Get()]
212                for name in self.dict['objectDict'].keys():
213                        if name not in existingNameList:
214                                del self.dict['objectDict'][name]
215                return
216        def setSetting(self, key, value):
217                """Saves a setting to the package dict.
218               
219                   Note: 'objectDict' is a reserved key.
220                """
221                self.dict[key] = value
222                return
223        def getSetting(self, key):
224                value = None
225                if self.dict.has_key(key):
226                        value = self.dict[key]
227                return value
228        def setObjectSetting(self, objectName, key, value):
229                if self.dict['objectDict'].has_key(objectName):
230                        self.dict['objectDict'][objectName][key] = value
231                else:
232                        self.dict['objectDict'][objectName] = {key:value}
233                return
234        def getObjectSetting(self, objectName, key):
235                value = None
236                if self.dict['objectDict'].has_key(objectName):
237                        if self.dict['objectDict'][objectName].has_key(key):
238                                value = self.dict['objectDict'][objectName][key]
239                return value   
240        def load(self):
241                """Load from Blender text 'OgrePackage.cfg'.
242                """
243                if self.textName in [text.getName() for text in Blender.Text.Get()]:
244                        settingsText = Blender.Text.Get(self.textName)
245                        # compose string from text and unpickle
246                        try:
247                                # unpickle
248                                self.dict = pickle.loads(string.join(settingsText.asLines()[4:],'\n'))
249                        except (pickle.PickleError):
250                                Log.getSingleton().logError('Couldn\'t unpickle package settings!')
251                                self.dict = {'objectDict':{}}
252                return
253
254class OgreXMLConverter(Singleton):
255        def __init__(self):
256                Singleton.__init__(self)
257                self.converter = None
258                self.converterArgs = ''
259                # get binary location from Blender's registry
260                registryDict = Blender.Registry.GetKey('OgrePackage', True)
261                if registryDict:
262                        if registryDict.has_key('OgreXMLConverter'):
263                                self.converter = registryDict['OgreXMLConverter']
264                # additional converter arguments
265                converterArgs = PackageSettings.getSingleton().getSetting('OgreXMLConverterArgs')
266                if converterArgs:
267                        self.converterArgs = converterArgs
268                else:
269                        self.converterArgs = ''
270                return
271        def setAdditionalArguments(self, arguments):
272                self.converterArgs = arguments
273                PackageSettings.getSingleton().setSetting('OgreXMLConverterArgs', self.converterArgs)
274                return
275        def getAdditionalArguments(self):
276                return self.converterArgs
277        def getConverter(self):
278                return self.converter
279        def setConverter(self, converter):
280                """Sets converter executable.
281                   
282                   Also saves converter location in Blender's registry. If <code>None</code>
283                   is passed, the converter is searched in $PATH.
284                   
285                   @param converter Location of OgreXMLConverter.
286                """
287                self.converter = converter
288                # update registry
289                registryDict = Blender.Registry.GetKey('OgrePackage', True)
290                if converter is None:
291                        # remove registry entry
292                        if registryDict and registryDict.has_key('OgreXMLConverter'):
293                                del registryDict['OgreXMLConverter']
294                                Blender.Registry.SetKey('OgrePackage', registryDict, True)
295                else:
296                        # set registry entry
297                        if registryDict is None:
298                                registryDict = {}
299                        registryDict['OgreXMLConverter'] = self.converter
300                        Blender.Registry.SetKey('OgrePackage', registryDict, True)
301                return
302        def findConverter(self):
303                """Find converter in path.
304               
305                   @return converter location or <code>None</code> if converter is not found.
306                """
307                converter = None
308                path = os.environ.get('PATH')
309                if path:
310                        pathList = string.split(path, ':')
311                        found = False
312                        i = 0
313                        while not found and (i < len(pathList)):
314                                if os.path.exists(os.path.join(pathList[i], 'OgreXMLConverter')):
315                                        converter = os.path.join(pathList[i], 'OgreXMLConverter')
316                                        found = True
317                                i += 1
318                return converter
319        def convert(self, filename, arguments=''):
320                """Converts given file with the OgreXMLConverter.
321               
322                   @param filename The xml filename to pass to the converter.
323                   @param arguments Additional arguments to pass to the converter.
324                """
325                converter = None
326                if self.converter:
327                        converter = self.converter
328                elif self.findConverter():
329                        converter = 'OgreXMLConverter'
330                if converter:
331                        dir = os.path.dirname(filename)
332                        # ensure proper encoding of filenames
333                        encodedDir = os.path.normpath(dir)
334                        encodedFilename = os.path.normpath(filename)
335                        encodedConverter = os.path.normpath(converter)
336                        # call the converter
337                        commandLine = '"' + encodedConverter + '" -log "' \
338                                 + os.path.join(encodedDir, 'OgreXMLConverter.log') \
339                                 + '" ' + self.converterArgs + ' ' + arguments \
340                                 + ' "' + encodedFilename + '"'
341                        if os.name == "nt":
342                                # workaround for popen windows bug
343                                commandLine = '"' + commandLine + '"'
344                        Log.getSingleton().logInfo("Running OgreXMLConverter: " + commandLine)
345                        xmlConverter = os.popen(commandLine, 'r')
346                        for line in xmlConverter:
347                                Log.getSingleton().logInfo("OgreXMLConverter: " + line)
348                        xmlConverter.close()
349                return
350
351class ConvertibleXMLFile:
352        """
353        """
354        def __init__(self, filename):
355                self.filename = filename
356                self.converterOptionDict = {}
357                self.fileObject = open(self.filename, "w")
358                return
359        def write(self, str):
360                self.fileObject.write(str)
361                return
362        def close(self):
363                self.fileObject.close()
364                return
365        def addConverterOption(self, option, value=''):
366                self.converterOptionDict[option] = value
367                return
368        def convert(self):
369                arguments = ''
370                for (key, value) in self.converterOptionDict.iteritems():
371                        arguments += ' ' + key + ' ' + value
372                OgreXMLConverter.getSingleton().convert(self.filename, arguments)
373                return
374
375class PathName:
376        """Splits a pathname independent of the underlying os.
377       
378           Blender saves pathnames in the os specific manner. Using os.path may result in problems
379           when the export is done on a different os than the creation of the .blend file.         
380        """
381        def __init__(self, pathName):
382                self.pathName = pathName
383                return
384        def dirname(self):
385                return os.path.dirname(self.pathName) 
386        def basename(self):
387                baseName = os.path.basename(self.pathName)
388                # split from non-os directories
389                # \\
390                baseName = baseName.split('\\').pop()
391                # /
392                baseName = baseName.split('/').pop()
393                if (baseName != baseName.replace(' ','_')):
394                        # replace whitespace with underscore
395                        Log.getSingleton().logWarning("Whitespaces in filename \"%s\" replaced with underscores." % baseName)
396                        baseName = baseName.replace(' ','_')
397                return baseName
398        def path(self):
399                return self.pathName
Note: See TracBrowser for help on using the repository browser.