75 """<b>Project Translations Browser</b>""" |
75 """<b>Project Translations Browser</b>""" |
76 """<p>This allows to easily see all translations contained in the current""" |
76 """<p>This allows to easily see all translations contained in the current""" |
77 """ project. Several actions can be executed via the context menu.</p>""" |
77 """ project. Several actions can be executed via the context menu.</p>""" |
78 )) |
78 )) |
79 |
79 |
80 self.lreleaseProc = None |
80 self.__lreleaseProcesses = [] |
|
81 self.__pylupdateProcesses = [] |
81 self.lreleaseProcRunning = False |
82 self.lreleaseProcRunning = False |
82 self.pylupdateProc = None |
|
83 self.pylupdateProcRunning = False |
83 self.pylupdateProcRunning = False |
84 self.tmpProject = [] |
84 self.__tmpProjects = [] |
85 |
85 |
86 def _createPopupMenus(self): |
86 def _createPopupMenus(self): |
87 """ |
87 """ |
88 Protected overloaded method to generate the popup menu. |
88 Protected overloaded method to generate the popup menu. |
89 """ |
89 """ |
771 else: |
771 else: |
772 pf.write('{0} {1}{2}'.format( |
772 pf.write('{0} {1}{2}'.format( |
773 list[0].replace(os.sep, '/'), "\n", "\n")) |
773 list[0].replace(os.sep, '/'), "\n", "\n")) |
774 |
774 |
775 pf.close() |
775 pf.close() |
776 self.tmpProject.append(outFile) |
776 self.__tmpProjects.append(outFile) |
777 except IOError: |
777 except IOError: |
778 E5MessageBox.critical(self, |
778 E5MessageBox.critical(self, |
779 self.trUtf8("Write temporary project file"), |
779 self.trUtf8("Write temporary project file"), |
780 self.trUtf8("<p>The temporary project file <b>{0}</b> could not" |
780 self.trUtf8("<p>The temporary project file <b>{0}</b> could not" |
781 " be written.</p>").format(outFile)) |
781 " be written.</p>").format(outFile)) |
782 self.tmpProject = [] |
782 |
783 return False |
783 if len(self.__tmpProjects) == 0: |
|
784 return False |
784 |
785 |
785 return True |
786 return True |
786 |
787 |
787 def __readStdoutLupdate(self): |
788 def __readStdoutLupdate(self): |
788 """ |
789 """ |
789 Private slot to handle the readyReadStandardOutput signal of the |
790 Private slot to handle the readyReadStandardOutput signal of the |
790 pylupdate process. |
791 pylupdate process. |
791 """ |
792 """ |
792 if self.pylupdateProc is not None: |
793 proc = self.sender() |
793 self.__readStdout(self.pylupdateProc, '{0}: '.format(self.pylupdate)) |
794 if proc is not None: |
|
795 self.__readStdout(proc, '{0}: '.format(self.pylupdate)) |
794 else: |
796 else: |
795 return |
797 return |
796 |
798 |
797 def __readStdoutLrelease(self): |
799 def __readStdoutLrelease(self): |
798 """ |
800 """ |
799 Private slot to handle the readyReadStandardOutput signal of the |
801 Private slot to handle the readyReadStandardOutput signal of the |
800 lrelease process. |
802 lrelease process. |
801 """ |
803 """ |
802 if self.lreleaseProc is not None: |
804 proc = self.sender() |
803 self.__readStdout(self.lreleaseProc, 'lrelease: ') |
805 if proc is not None: |
|
806 self.__readStdout(proc, 'lrelease: ') |
804 else: |
807 else: |
805 return |
808 return |
806 |
809 |
807 def __readStdout(self, proc, ps): |
810 def __readStdout(self, proc, ps): |
808 """ |
811 """ |
823 def __readStderrLupdate(self): |
826 def __readStderrLupdate(self): |
824 """ |
827 """ |
825 Private slot to handle the readyReadStandardError signal of the |
828 Private slot to handle the readyReadStandardError signal of the |
826 pylupdate process. |
829 pylupdate process. |
827 """ |
830 """ |
828 if self.pylupdateProc is not None: |
831 proc = self.sender() |
829 self.__readStderr(self.pylupdateProc, '{0}: '.format(self.pylupdate)) |
832 if proc is not None: |
|
833 self.__readStderr(proc, '{0}: '.format(self.pylupdate)) |
830 else: |
834 else: |
831 return |
835 return |
832 |
836 |
833 def __readStderrLrelease(self): |
837 def __readStderrLrelease(self): |
834 """ |
838 """ |
835 Private slot to handle the readyReadStandardError signal of the |
839 Private slot to handle the readyReadStandardError signal of the |
836 lrelease process. |
840 lrelease process. |
837 """ |
841 """ |
838 if self.lreleaseProc is not None: |
842 proc = self.sender() |
839 self.__readStderr(self.lreleaseProc, 'lrelease: ') |
843 if proc is not None: |
|
844 self.__readStderr(proc, 'lrelease: ') |
840 else: |
845 else: |
841 return |
846 return |
842 |
847 |
843 def __readStderr(self, proc, ps): |
848 def __readStderr(self, proc, ps): |
844 """ |
849 """ |
872 Private slot to handle the finished signal of the pylupdate process. |
877 Private slot to handle the finished signal of the pylupdate process. |
873 |
878 |
874 @param exitCode exit code of the process (integer) |
879 @param exitCode exit code of the process (integer) |
875 @param exitStatus exit status of the process (QProcess.ExitStatus) |
880 @param exitStatus exit status of the process (QProcess.ExitStatus) |
876 """ |
881 """ |
877 self.pylupdateProcRunning = False |
|
878 if exitStatus == QProcess.NormalExit and exitCode == 0: |
882 if exitStatus == QProcess.NormalExit and exitCode == 0: |
879 ui = e5App().getObject("UserInterface") |
883 ui = e5App().getObject("UserInterface") |
880 if ui.notificationsEnabled(): |
884 if ui.notificationsEnabled(): |
881 ui.showNotification(UI.PixmapCache.getPixmap("linguist48.png"), |
885 ui.showNotification(UI.PixmapCache.getPixmap("linguist48.png"), |
882 self.trUtf8("Translation file generation"), |
886 self.trUtf8("Translation file generation"), |
889 " was successful.")) |
893 " was successful.")) |
890 else: |
894 else: |
891 E5MessageBox.critical(self, |
895 E5MessageBox.critical(self, |
892 self.trUtf8("Translation file generation"), |
896 self.trUtf8("Translation file generation"), |
893 self.trUtf8("The generation of the translation files (*.ts) has failed.")) |
897 self.trUtf8("The generation of the translation files (*.ts) has failed.")) |
894 self.pylupdateProc = None |
898 |
|
899 proc = self.sender() |
|
900 for index in range(len(self.__pylupdateProcesses)): |
|
901 if proc == self.__pylupdateProcesses[index][0]: |
|
902 try: |
|
903 self.__tmpProjects.remove(self.__pylupdateProcesses[index][1]) |
|
904 os.remove(self.__pylupdateProcesses[index][1]) |
|
905 except EnvironmentError: |
|
906 pass |
|
907 del self.__pylupdateProcesses[index] |
|
908 break |
|
909 if not self.__pylupdateProcesses: |
|
910 # all done |
|
911 self.pylupdateProcRunning = False |
895 |
912 |
896 def __generateTSFile(self, noobsolete=False, generateAll=True): |
913 def __generateTSFile(self, noobsolete=False, generateAll=True): |
897 """ |
914 """ |
898 Private method used to run pylupdate/pylupdate4 to generate the .ts files. |
915 Private method used to run pylupdate/pylupdate4 to generate the .ts files. |
899 |
916 |
931 for lang in langs] |
948 for lang in langs] |
932 self.hooks["generateSelectedWithObsolete"](l) |
949 self.hooks["generateSelectedWithObsolete"](l) |
933 return |
950 return |
934 |
951 |
935 # generate a minimal temporary projectfile suitable for pylupdate |
952 # generate a minimal temporary projectfile suitable for pylupdate |
|
953 self.__tmpProjects = [] |
936 if self.project.pdata["PROGLANGUAGE"][0] in ["Python", "Python2", "Python3"]: |
954 if self.project.pdata["PROGLANGUAGE"][0] in ["Python", "Python2", "Python3"]: |
937 ok = self.__writeTempProjectFile(langs, [".py"]) |
955 ok = self.__writeTempProjectFile(langs, [".py"]) |
938 else: |
956 else: |
939 ok = False |
957 ok = False |
940 if not ok: |
958 if not ok: |
951 elif self.project.getProjectType() in ["PySide", "PySideC"]: |
969 elif self.project.getProjectType() in ["PySide", "PySideC"]: |
952 self.pylupdate = Utilities.generatePySideToolPath('pyside-lupdate') |
970 self.pylupdate = Utilities.generatePySideToolPath('pyside-lupdate') |
953 else: |
971 else: |
954 return |
972 return |
955 |
973 |
956 for tempProjectFile in self.tmpProject: |
974 self.__pylupdateProcesses = [] |
957 self.pylupdateProc = QProcess() |
975 for tempProjectFile in self.__tmpProjects[:]: |
|
976 proc = QProcess() |
958 args = [] |
977 args = [] |
959 |
978 |
960 if noobsolete: |
979 if noobsolete: |
961 args.append('-noobsolete') |
980 args.append('-noobsolete') |
962 |
981 |
963 args.append('-verbose') |
982 args.append('-verbose') |
964 path, filename = os.path.split(tempProjectFile) |
983 path, filename = os.path.split(tempProjectFile) |
965 args.append(filename) |
984 args.append(filename) |
966 self.pylupdateProc.setWorkingDirectory(os.path.join(self.project.ppath, path)) |
985 proc.setWorkingDirectory(os.path.join(self.project.ppath, path)) |
967 self.pylupdateProc.finished.connect(self.__generateTSFileDone) |
986 proc.finished.connect(self.__generateTSFileDone) |
968 self.pylupdateProc.readyReadStandardOutput.connect(self.__readStdoutLupdate) |
987 proc.readyReadStandardOutput.connect(self.__readStdoutLupdate) |
969 self.pylupdateProc.readyReadStandardError.connect(self.__readStderrLupdate) |
988 proc.readyReadStandardError.connect(self.__readStderrLupdate) |
970 |
989 |
971 self.pylupdateProc.start(self.pylupdate, args) |
990 proc.start(self.pylupdate, args) |
972 procStarted = self.pylupdateProc.waitForStarted(5000) |
991 procStarted = proc.waitForStarted() |
973 if procStarted: |
992 if procStarted: |
974 self.pylupdateProcRunning = True |
993 self.pylupdateProcRunning = True |
975 self.pylupdateProc.waitForFinished(10000) |
994 self.__pylupdateProcesses.append((proc, tempProjectFile)) |
976 else: |
995 else: |
977 E5MessageBox.critical(self, |
996 E5MessageBox.critical(self, |
978 self.trUtf8('Process Generation Error'), |
997 self.trUtf8('Process Generation Error'), |
979 self.trUtf8( |
998 self.trUtf8( |
980 'Could not start {0}.<br>' |
999 'Could not start {0}.<br>' |
981 'Ensure that it is in the search path.' |
1000 'Ensure that it is in the search path.' |
982 ).format(self.pylupdate)) |
1001 ).format(self.pylupdate)) |
983 # cleanup |
1002 # cleanup |
984 try: |
1003 try: |
985 for fn in self.tmpProject: |
1004 self.__tmpProjects.remove(tempProjectFile) |
986 os.remove(fn) |
1005 os.remove(tempProjectFile) |
987 except EnvironmentError: |
1006 except EnvironmentError: |
988 pass |
1007 pass |
989 self.tmpProject = [] |
|
990 |
1008 |
991 def __generateAll(self): |
1009 def __generateAll(self): |
992 """ |
1010 """ |
993 Private method to generate all translation files (.ts) for Qt Linguist. |
1011 Private method to generate all translation files (.ts) for Qt Linguist. |
994 |
1012 |
1052 shutil.move(qmFile, target) |
1070 shutil.move(qmFile, target) |
1053 else: |
1071 else: |
1054 E5MessageBox.critical(self, |
1072 E5MessageBox.critical(self, |
1055 self.trUtf8("Translation file release"), |
1073 self.trUtf8("Translation file release"), |
1056 self.trUtf8("The release of the translation files (*.qm) has failed.")) |
1074 self.trUtf8("The release of the translation files (*.qm) has failed.")) |
1057 self.lreleaseProc = None |
1075 |
1058 try: |
1076 proc = self.sender() |
1059 os.remove(self.tmpProject) |
1077 for index in range(len(self.__lreleaseProcesses)): |
1060 except EnvironmentError: |
1078 if proc == self.__lreleaseProcesses[index][0]: |
1061 pass |
1079 try: |
1062 self.tmpProject = None |
1080 self.__tmpProjects.remove(self.__lreleaseProcesses[index][1]) |
1063 self.project.checkLanguageFiles() |
1081 os.remove(self.__lreleaseProcesses[index][1]) |
|
1082 except EnvironmentError: |
|
1083 pass |
|
1084 del self.__lreleaseProcesses[index] |
|
1085 break |
|
1086 if not self.__lreleaseProcesses: |
|
1087 # all done |
|
1088 self.lreleaseProcRunning = False |
|
1089 self.project.checkLanguageFiles() |
1064 |
1090 |
1065 def __releaseTSFile(self, generateAll=False): |
1091 def __releaseTSFile(self, generateAll=False): |
1066 """ |
1092 """ |
1067 Private method to run lrelease to release the translation files (.qm). |
1093 Private method to run lrelease to release the translation files (.qm). |
1068 |
1094 |
1085 for lang in langs] |
1111 for lang in langs] |
1086 self.hooks["releaseSelected"](l) |
1112 self.hooks["releaseSelected"](l) |
1087 return |
1113 return |
1088 |
1114 |
1089 # generate a minimal temporary projectfile suitable for lrelease |
1115 # generate a minimal temporary projectfile suitable for lrelease |
|
1116 self.__tmpProjects = [] |
1090 if self.project.pdata["PROGLANGUAGE"][0] in ["Python", "Python2", "Python3"]: |
1117 if self.project.pdata["PROGLANGUAGE"][0] in ["Python", "Python2", "Python3"]: |
1091 ok = self.__writeTempProjectFile(langs, [".py"]) |
1118 ok = self.__writeTempProjectFile(langs, [".py"]) |
1092 else: |
1119 else: |
1093 ok = False |
1120 ok = False |
1094 if not ok: |
1121 if not ok: |
1095 return |
1122 return |
1096 |
|
1097 self.lreleaseProc = QProcess() |
|
1098 args = [] |
|
1099 |
1123 |
1100 if self.project.getProjectType() in \ |
1124 if self.project.getProjectType() in \ |
1101 ["Qt4", "Qt4C", "PyQt5", "PyQt5C", "E4Plugin", "PySide", "PySideC"]: |
1125 ["Qt4", "Qt4C", "PyQt5", "PyQt5C", "E4Plugin", "PySide", "PySideC"]: |
1102 lrelease = os.path.join( |
1126 lrelease = os.path.join( |
1103 Utilities.getQtBinariesPath(), |
1127 Utilities.getQtBinariesPath(), |
1105 else: |
1129 else: |
1106 return |
1130 return |
1107 if Utilities.isWindowsPlatform(): |
1131 if Utilities.isWindowsPlatform(): |
1108 lrelease = lrelease + '.exe' |
1132 lrelease = lrelease + '.exe' |
1109 |
1133 |
1110 args.append('-verbose') |
1134 self.__lreleaseProcesses = [] |
1111 args.append(self.tmpProject) |
1135 for tempProjectFile in self.__tmpProjects[:]: |
1112 self.lreleaseProc.setWorkingDirectory(self.project.ppath) |
1136 proc = QProcess() |
1113 self.lreleaseProc.finished.connect(self.__releaseTSFileDone) |
1137 args = [] |
1114 self.lreleaseProc.readyReadStandardOutput.connect(self.__readStdoutLrelease) |
1138 |
1115 self.lreleaseProc.readyReadStandardError.connect(self.__readStderrLrelease) |
1139 args.append('-verbose') |
1116 |
1140 path, filename = os.path.split(tempProjectFile) |
1117 self.lreleaseProc.start(lrelease, args) |
1141 args.append(filename) |
1118 procStarted = self.lreleaseProc.waitForStarted(5000) |
1142 proc.setWorkingDirectory(os.path.join(self.project.ppath, path)) |
1119 if procStarted: |
1143 proc.finished.connect(self.__releaseTSFileDone) |
1120 self.lreleaseProcRunning = True |
1144 proc.readyReadStandardOutput.connect(self.__readStdoutLrelease) |
1121 else: |
1145 proc.readyReadStandardError.connect(self.__readStderrLrelease) |
1122 E5MessageBox.critical(self, |
1146 |
1123 self.trUtf8('Process Generation Error'), |
1147 proc.start(lrelease, args) |
1124 self.trUtf8( |
1148 procStarted = proc.waitForStarted() |
1125 '<p>Could not start lrelease.<br>' |
1149 if procStarted: |
1126 'Ensure that it is available as <b>{0}</b>.</p>' |
1150 self.lreleaseProcRunning = True |
1127 ).format(lrelease)) |
1151 self.__lreleaseProcesses.append((proc, tempProjectFile)) |
|
1152 else: |
|
1153 E5MessageBox.critical(self, |
|
1154 self.trUtf8('Process Generation Error'), |
|
1155 self.trUtf8( |
|
1156 '<p>Could not start lrelease.<br>' |
|
1157 'Ensure that it is available as <b>{0}</b>.</p>' |
|
1158 ).format(lrelease)) |
|
1159 |
|
1160 # cleanup |
|
1161 try: |
|
1162 self.__tmpProjects.remove(tempProjectFile) |
|
1163 os.remove(tempProjectFile) |
|
1164 except EnvironmentError: |
|
1165 pass |
1128 |
1166 |
1129 def __releaseSelected(self): |
1167 def __releaseSelected(self): |
1130 """ |
1168 """ |
1131 Private method to release the translation files (.qm). |
1169 Private method to release the translation files (.qm). |
1132 """ |
1170 """ |