#!/usr/bin/env python2.6 # -*- coding: utf-8 -*- import sys import os from subprocess import Popen, PIPE, call import optparse import re content_header = """#!/usr/bin/env python # -*- coding: utf-8 -*- # Author: Jens Kasten # Date: 20110802 # import os import sys import gettext try: from PyQt4 import QtCore, QtGui except ImportError, e: print str(e) sys.exit() locale_app = sys.argv[0] if locale_app.endswith('.py'): locale_app = locale_app[2:len(locale_app)-3] else: locale_app = locale_app[2:] t = gettext.translation(locale_app, "/usr/share/locale", fallback=True) _ = t.ugettext """ content_footer = """ if __name__ == "__main__": app = QtGui.QApplication(sys.argv) f = MyMainWindow() f.show() sys.exit(app.exec_()) """ class QtMakeFile(object): def __init__(self): # some defaults self.config = { 'ui': {'dir-name': 'ui', 'file-names': [], }, 'py': {'dir-name': 'py', 'file-names': [], }, 'lib': {'dir-name': 'lib', 'file-names': [], }, 'tr': {'dir-name': 'tr', 'file-names': [], }, 'mo': {'dir-name': 'mo'} } self.languages_to_translate = ['de_DE', 'fr', 'en'] def list_files(self, file_type): """Method for listing all files in given directory. """ dir_name = self.config[file_type]['dir-name'] assert os.path.isdir(dir_name), "Directory '%s' does not exists" % dir_name result = [] files = os.listdir(dir_name) assert len(files) > 0, "Found no file in %s" % dir_name for file in files: if not file.endswith('.swp') or not file.startswith('.'): result.append(file) assert len(result) > 0, "Found no file with thats end on %s" % file_type self.config[file_type]['file-names'] = result def get_qt_names(self): """Extract the class name and widget name from given ui file.""" for ui_file in self.config['ui']['file-names']: qt_names = {} fd = open(os.path.join(self.config['ui']['dir-name'], ui_file)) lines = fd.readlines() for line in lines: class_name = re.match(r"^.*(.*).*$", line) if class_name: qt_names['class-name'] = class_name.group(1) if "class-name" in qt_names: widget_name = re.match(r'.*class="Q(.*)" name="%s".*' % qt_names['class-name'], line) if widget_name: qt_names['widget-name'] = widget_name.group(1) break fd.close() assert len(qt_names) > 0, "Found nothing in %s" % ui_file self.config['ui'][ui_file] = {} if ui_file.startswith('main_'): exe = ui_file.replace('main_', '').replace('.ui', '') self.config['ui']['exe'] = exe self.config['lib']['class-name'] = qt_names['class-name'] self.config['lib']['widget-name'] = qt_names['widget-name'] for key, value in qt_names.iteritems(): self.config['ui'][ui_file][key] = value def generate_py_files(self): """Create the python classes from ui files. It's using the pyuic4 tool. """ for _file in self.config['ui']['file-names']: ui_file = os.path.join(self.config['ui']['dir-name'], _file) py_file = os.path.join(self.config['py']['dir-name'], _file.replace('.ui', '.py')) if os.path.isfile(py_file): os.remove(py_file) cmd = ['pyuic4', ui_file, '-o', py_file] try: call(cmd) except OSError, e: print str(e) def generate_executable(self, content_header, content_footer): """Write all data to a single file.""" try: assert 'exe' in self.config['ui'], "No main file for first window exists" exe = self.config['ui']['exe'] if os.path.isfile(exe): os.remove(exe) fd = open(exe, "a+") # starts with the header fd.write(content_header) # write all autogenerated python class for py_file in self.config['py']['file-names']: fd_py = open(os.path.join(self.config['py']['dir-name'], py_file)) for line in fd_py.readlines(): # do a simple check thats comments not write if not line.startswith('#'): if not line.startswith('from'): # replace the qt4-designer behavio line = line.replace('("_{', '(_("') line = line.replace('}")', '"))') fd.write(line) fd_py.close() for lib_file in self.config['lib']['file-names']: fd_lib = open(os.path.join(self.config['lib']['dir-name'], lib_file)) for line in fd_lib.readlines(): line = line.replace("{{class-name}}", self.config['lib']['class-name']) line = line.replace("{{widget-name}}", self.config['lib']['widget-name']) fd.write(line) fd_lib.close() fd.write(content_footer) fd.close() os.chmod(exe, 0755) except OSError, e: print str(e) except Exception, e: print str(e) def generate_translation(self): # create pot file in_put = self.config['ui']['exe'] out_put = ".".join([self.config['ui']['exe'], 'pot']) out_put_dir = self.config['tr']['dir-name'] cmd = ['xgettext', '-p', out_put_dir, '-o', out_put, in_put, '-L', 'python', '--from-code', 'utf-8'] retcode = call(cmd) # create po files in_put = os.path.join(out_put_dir, out_put) for lang in self.languages_to_translate: po_put = ".".join([lang, 'po']) po_put = os.path.join(out_put_dir, po_put) cmd = ['msginit', '-l', lang, '-i', in_put, '-o', po_put] retcode = call(cmd) def generate_mo_files(self): out_put_dir = self.config['tr']['dir-name'] mo_dir = self.config['mo']['dir-name'] for lang in self.languages_to_translate: po_put = ".".join([lang, 'po']) po_put = os.path.join(out_put_dir, po_put) mo_put = ".".join([self.config['ui']['exe'], 'mo']) mo_out = os.path.join(mo_dir, lang, 'LC_MESSAGES') if not os.path.isdir(mo_out): os.system('mkdir -pv %s' % mo_out) mo_put = os.path.join(mo_out, mo_put) cmd = ['msgfmt', '-o', mo_put, po_put] call(cmd) def run(self): # first add all files form Qt4-Designer self.list_files(self.config['ui']['dir-name']) # add own python file self.list_files(self.config['lib']['dir-name']) # search for first window, based on class mit name main self.get_qt_names() # lets generate py classes which pyuic4 self.generate_py_files() # add py files self.list_files(self.config['py']['dir-name']) # build single python file which include all self.generate_executable(content_header, content_footer) # build the translation file self.generate_translation() def main(): parser = optparse.OptionParser("usage: %prog [-h|--help|options]") parser.add_option("-U", "--ui-dir", dest="ui_dir", type="string", help="Directory where the Qt4-Designer ui files are placed. \ If nothing given assumed directory 'ui'.") parser.add_option("-P", "--py-dir", dest="py_dir", type="string", help="Directory where the pyuic4 write his output. \ If nothing given assumed directory 'py'.") parser.add_option("-L", "--lib-dir", dest="lib_dir", type="string", help="Directory where the own python file is placed. \ If nothing given assumed directory 'lib'.") parser.add_option("-T", "--tr-dir", dest="tr_dir", type="string", help="Directory where the translation files are placed. \ If nothing given assumed directory 'tr'.") parser.add_option("-M", "--input-for-mo", dest="mo", type="string", help="Create mo files, need the executable name as argument.") (options, args) = parser.parse_args() qt = QtMakeFile() if options.ui_dir: assert os.path.isdir(options.ui_dir), "No ui directory" qt.config['ui']['dir-name'] = options.ui_dir if options.py_dir: assert os.path.isdir(options.py_dir), "No py directory" qt.config['py']['dir-name'] = options.py_dir if options.lib_dir: assert os.path.isdir(options.lib_dir), "No lib directory" qt.config['lib']['dir-name'] = options.lib_dir if options.tr_dir: assert os.path.isdir(options.tr_dir), "No tr directory" qt.config['tr']['dir-name'] = options.tr_dir if options.mo: qt.config['ui']['exe'] = options.mo qt.generate_mo_files() else: qt.run() if __name__ == "__main__": main()