├── AUTHORS ├── CMakeLists.txt ├── LICENSE-rcc ├── LICENSE-uic ├── README.md ├── cmake_uninstall.cmake ├── pylupdate ├── CMakeLists.txt ├── fetchtr.cpp ├── main.cpp ├── merge.cpp ├── metatranslator.cpp ├── metatranslator.h ├── numberh.cpp ├── proparser.cpp ├── proparser.h ├── pyside2-lupdate.1 ├── sametexth.cpp ├── simtexth.cpp ├── simtexth.h ├── translator.cpp └── translator.h ├── pyrcc ├── CMakeLists.txt ├── main.cpp ├── pyside2-rcc.1 ├── rcc.cpp └── rcc.h ├── pyside2-uic ├── pyside2uic ├── Compiler │ ├── __init__.py │ ├── compiler.py │ ├── indenter.py │ ├── misc.py │ ├── proxy_type.py │ ├── qobjectcreator.py │ └── qtproxies.py ├── __init__.py.in ├── driver.py ├── exceptions.py ├── icon_cache.py ├── objcreator.py ├── port_v2 │ ├── __init__.py │ ├── as_string.py │ ├── ascii_upper.py │ ├── invoke.py │ ├── load_plugin.py │ ├── proxy_base.py │ └── string_io.py ├── port_v3 │ ├── __init__.py │ ├── as_string.py │ ├── ascii_upper.py │ ├── invoke.py │ ├── load_plugin.py │ ├── proxy_base.py │ └── string_io.py ├── properties.py ├── pyside2-uic.1 ├── uiparser.py └── widget-plugins │ ├── qtdeclarative.py │ └── qtwebkit.py └── tests ├── CMakeLists.txt ├── qwizard_test.ui └── rcc ├── CMakeLists.txt ├── document-print-preview.png ├── example.qrc ├── image.qrc ├── manychars.txt ├── rcc_image_test.py ├── rcc_test.py ├── run_test.sh ├── shining.txt └── words.txt /AUTHORS: -------------------------------------------------------------------------------- 1 | This is a fork of pyuic from PyQt4. 2 | 3 | Authors 4 | - PySide developers 5 | 6 | PyQt4 pyuic authors 7 | - Torsten Marek 8 | - Phil Thompson 9 | 10 | PyQt4 pyrcc4 authors 11 | - Trolltech 12 | - Phil Thompson 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(pyside2-tools) 3 | 4 | find_package(Shiboken2 2.0.0 REQUIRED) 5 | find_package(Qt5 REQUIRED Core) 6 | find_package(PySide2 2.0.0 REQUIRED) 7 | 8 | set(pyside2_tools_MAJOR_VERSION "2") 9 | set(pyside2_tools_MINOR_VERSION "0") 10 | set(pyside2_tools_MICRO_VERSION "0") 11 | set(pyside2_tools_VERSION "${pyside2_tools_MAJOR_VERSION}.${pyside2_tools_MINOR_VERSION}.${pyside2_tools_MICRO_VERSION}") 12 | 13 | configure_file("pyside2uic/__init__.py.in" "${CMAKE_CURRENT_BINARY_DIR}/pyside2uic/__init__.py" @ONLY) 14 | 15 | option(BUILD_TESTS "Build tests." TRUE) 16 | 17 | if(CMAKE_HOST_APPLE) 18 | set(OSX_USE_LIBCPP "OFF" CACHE BOOL "Explicitly link the libc++ standard library (useful for osx deployment targets lower than 10.9.") 19 | if(OSX_USE_LIBCPP) 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 21 | endif() 22 | endif() 23 | 24 | # UIC stuff 25 | if (NOT SITE_PACKAGE) 26 | execute_process( 27 | COMMAND ${SHIBOKEN_PYTHON_INTERPRETER} -c "if True: 28 | from distutils import sysconfig 29 | from os.path import sep 30 | print(sysconfig.get_python_lib(1, 0, prefix='${CMAKE_INSTALL_PREFIX}').replace(sep, '/')) 31 | " 32 | OUTPUT_VARIABLE SITE_PACKAGE 33 | OUTPUT_STRIP_TRAILING_WHITESPACE) 34 | if (NOT SITE_PACKAGE) 35 | message(FATAL_ERROR "Could not detect Python module installation directory.") 36 | endif() 37 | endif() 38 | 39 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pyside2-uic 40 | DESTINATION bin 41 | PERMISSIONS 42 | OWNER_EXECUTE OWNER_WRITE OWNER_READ 43 | GROUP_EXECUTE GROUP_READ 44 | WORLD_EXECUTE WORLD_READ) 45 | 46 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pyside2uic/__init__.py" 47 | DESTINATION "${SITE_PACKAGE}/pyside2uic") 48 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pyside2uic 49 | DESTINATION ${SITE_PACKAGE} 50 | PATTERN "*.in" EXCLUDE 51 | PATTERN "*pyside2uic/*.1" EXCLUDE 52 | PATTERN "*pyside2uic/__init__.py" EXCLUDE 53 | PATTERN "*pyside2uic\\__init__.py" EXCLUDE) 54 | 55 | # Man pages for pyside2-uic 56 | if (NOT win32) 57 | file(GLOB manpages "${CMAKE_CURRENT_SOURCE_DIR}/pyside2uic/*.1") 58 | install(FILES ${manpages} DESTINATION share/man/man1) 59 | endif() 60 | 61 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" 62 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 63 | IMMEDIATE @ONLY) 64 | 65 | add_custom_target(uninstall "${CMAKE_COMMAND}" 66 | -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") 67 | 68 | set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${pyside2_tools_VERSION}) 69 | add_custom_target(dist 70 | COMMAND mkdir -p "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}" && 71 | git log > "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}/ChangeLog" && 72 | git archive --prefix=${ARCHIVE_NAME}/ HEAD --format=tar --output="${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && 73 | tar -C "${CMAKE_BINARY_DIR}" --owner=root --group=root -r "${ARCHIVE_NAME}/ChangeLog" -f "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && 74 | bzip2 -f9 "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && 75 | echo "Source package created at ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2.\n" 76 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) 77 | 78 | set(PYSIDE2RCC_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/pyrcc/pyside2-rcc) 79 | add_subdirectory(pyrcc) 80 | add_subdirectory(pylupdate) 81 | 82 | if (BUILD_TESTS) 83 | enable_testing() 84 | add_subdirectory(tests) 85 | endif () 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tools 2 | ===== 3 | 4 | PySide development tools (pyuic and pyrcc) 5 | 6 | This repository is the tools for PySide2. If you would like to install PySide2, please go to [pyside2-setup](https://github.com/PySide/pyside2-setup) for instructions. 7 | 8 | Resources: 9 | 10 | * [PySide2-setup](https://github.com/PySide/pyside2-setup) 11 | The container-project with the setup.py script. It contains the following sub-projects: 12 | * [PySide2 Wiki](https://github.com/PySide/pyside2/wiki) 13 | Developer information 14 | * [PySide2](https://github.com/PySide/pyside2) 15 | The PySide2 project 16 | * [Shiboken2](https://github.com/PySide/shiboken2) 17 | The Shiboken2 project 18 | * [PySide2-tools](https://github.com/PySide/pyside2-examples) 19 | The PySide2-tools project 20 | * [PySide2-examples](https://github.com/PySide/pyside2-examples) 21 | The PySide2 example scripts 22 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake: -------------------------------------------------------------------------------- 1 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 3 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | STRING(REGEX REPLACE "\n" ";" files "${files}") 7 | FOREACH(file ${files}) 8 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 9 | IF(EXISTS "$ENV{DESTDIR}${file}") 10 | EXEC_PROGRAM( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | IF(NOT "${rm_retval}" STREQUAL 0) 16 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 17 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 18 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 19 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 20 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 21 | ENDFOREACH(file) 22 | -------------------------------------------------------------------------------- /pylupdate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(lupdate_SRC 3 | fetchtr.cpp 4 | main.cpp 5 | merge.cpp 6 | metatranslator.cpp 7 | numberh.cpp 8 | proparser.cpp 9 | sametexth.cpp 10 | simtexth.cpp 11 | translator.cpp 12 | ) 13 | 14 | find_package(Qt5Core) 15 | find_package(Qt5Gui) 16 | find_package(Qt5Xml) 17 | find_package(Qt5Widgets) 18 | 19 | set(lupdate_MOC_HEADERS translator.h) 20 | qt5_wrap_cpp(lupdate_MOC_OUTFILES ${lupdate_MOC_HEADERS}) 21 | 22 | add_executable(pyside2-lupdate ${lupdate_SRC} ${lupdate_MOC_OUTFILES}) 23 | include_directories(pyside2-lupdate 24 | ${CMAKE_CURRENT_SOURCE_DIR} 25 | ${Qt5Xml_INCLUDE_DIRS} 26 | ${Qt5Core_INCLUDE_DIRS} 27 | ${Qt5Gui_INCLUDE_DIRS} 28 | ${Qt5Widgets_INCLUDE_DIRS} 29 | ) 30 | 31 | target_link_libraries(pyside2-lupdate 32 | ${Qt5Core_LIBRARIES} 33 | ${Qt5Xml_LIBRARIES} 34 | ${Qt5Gui_LIBRARIES} 35 | ${Qt5Widgets_LIBRARIES} 36 | ) 37 | 38 | install(TARGETS pyside2-lupdate RUNTIME DESTINATION bin) 39 | 40 | # Man pages 41 | if (NOT win32) 42 | file(GLOB manpages "${CMAKE_CURRENT_SOURCE_DIR}/*.1") 43 | install(FILES ${manpages} DESTINATION share/man/man1) 44 | endif() 45 | -------------------------------------------------------------------------------- /pylupdate/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2002-2007 Detlev Offenbach 6 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 7 | * 8 | * Contact: PySide team 9 | * 10 | * This program is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License 12 | * version 2 as published by the Free Software Foundation. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | * 02110-1301 USA 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | // defined in fetchtr.cpp 41 | extern void fetchtr_py( const char *fileName, MetaTranslator *tor, 42 | const char *defaultContext, bool mustExist, const QByteArray &codecForSource ); 43 | extern void fetchtr_ui( const char *fileName, MetaTranslator *tor, 44 | const char *defaultContext, bool mustExist ); 45 | 46 | 47 | 48 | // defined in merge.cpp 49 | extern void merge( const MetaTranslator *tor, const MetaTranslator *virginTor, MetaTranslator *out, 50 | bool verbose, bool noObsolete ); 51 | 52 | typedef QList TML; 53 | 54 | static void printUsage() 55 | { 56 | fprintf( stderr, "Usage:\n" 57 | " pyside2-lupdate [options] project-file\n" 58 | " pyside2-lupdate [options] source-files -ts ts-files\n" 59 | "Options:\n" 60 | " -help Display this information and exit\n" 61 | " -noobsolete\n" 62 | " Drop all obsolete strings\n" 63 | " -verbose\n" 64 | " Explain what is being done\n" 65 | " -version\n" 66 | " Display the version of pyside2-lupdate and exit\n" ); 67 | } 68 | 69 | static void updateTsFiles( const MetaTranslator& fetchedTor, 70 | const QStringList& tsFileNames, const QString& codecForTr, 71 | bool noObsolete, bool verbose ) 72 | { 73 | QStringList::ConstIterator t = tsFileNames.begin(); 74 | QDir dir; 75 | while ( t != tsFileNames.end() ) { 76 | QString fn = dir.relativeFilePath(*t); 77 | MetaTranslator tor; 78 | MetaTranslator out; 79 | tor.load( *t ); 80 | if ( !codecForTr.isEmpty() ) 81 | tor.setCodec( codecForTr.toLatin1() ); 82 | if ( verbose ) 83 | fprintf( stderr, "Updating '%s'...\n", fn.toLatin1().constData() ); 84 | 85 | merge( &tor, &fetchedTor, &out, verbose, noObsolete ); 86 | if ( noObsolete ) 87 | out.stripObsoleteMessages(); 88 | out.stripEmptyContexts(); 89 | if ( !out.save(*t) ) { 90 | #if defined(_MSC_VER) && _MSC_VER >= 1400 91 | char buf[100]; 92 | strerror_s(buf, sizeof(buf), errno); 93 | fprintf( stderr, "pyside2-lupdate error: Cannot save '%s': %s\n", 94 | fn.toLatin1().constData(), buf ); 95 | #else 96 | fprintf( stderr, "pyside2-lupdate error: Cannot save '%s': %s\n", 97 | fn.toLatin1().constData(), strerror(errno) ); 98 | #endif 99 | } 100 | ++t; 101 | } 102 | } 103 | 104 | int main( int argc, char **argv ) 105 | { 106 | QString defaultContext = "@default"; 107 | MetaTranslator fetchedTor; 108 | QByteArray codecForTr; 109 | QByteArray codecForSource; 110 | QStringList tsFileNames; 111 | QStringList uiFileNames; 112 | 113 | bool verbose = false; 114 | bool noObsolete = false; 115 | bool metSomething = false; 116 | int numFiles = 0; 117 | bool standardSyntax = true; 118 | bool metTsFlag = false; 119 | 120 | int i; 121 | 122 | for ( i = 1; i < argc; i++ ) { 123 | if ( qstrcmp(argv[i], "-ts") == 0 ) 124 | standardSyntax = false; 125 | } 126 | 127 | for ( i = 1; i < argc; i++ ) { 128 | if ( qstrcmp(argv[i], "-help") == 0 ) { 129 | printUsage(); 130 | return 0; 131 | } else if ( qstrcmp(argv[i], "-noobsolete") == 0 ) { 132 | noObsolete = true; 133 | continue; 134 | } else if ( qstrcmp(argv[i], "-verbose") == 0 ) { 135 | verbose = true; 136 | continue; 137 | } else if ( qstrcmp(argv[i], "-version") == 0 ) { 138 | fprintf( stderr, "pyside2-lupdate version %s\n", QT_VERSION_STR ); 139 | return 0; 140 | } else if ( qstrcmp(argv[i], "-ts") == 0 ) { 141 | metTsFlag = true; 142 | continue; 143 | } 144 | 145 | numFiles++; 146 | 147 | QString fullText; 148 | 149 | if ( !metTsFlag ) { 150 | QFile f( argv[i] ); 151 | if ( !f.open(QIODevice::ReadOnly) ) { 152 | #if defined(_MSC_VER) && _MSC_VER >= 1400 153 | char buf[100]; 154 | strerror_s(buf, sizeof(buf), errno); 155 | fprintf( stderr, "pyside2-lupdate error: Cannot open file '%s': %s\n", 156 | argv[i], buf ); 157 | #else 158 | fprintf( stderr, "pyside2-lupdate error: Cannot open file '%s': %s\n", 159 | argv[i], strerror(errno) ); 160 | #endif 161 | return 1; 162 | } 163 | 164 | QTextStream t( &f ); 165 | fullText = t.readAll(); 166 | f.close(); 167 | } 168 | 169 | QString oldDir = QDir::currentPath(); 170 | QDir::setCurrent( QFileInfo(argv[i]).path() ); 171 | 172 | if ( standardSyntax ) { 173 | fetchedTor = MetaTranslator(); 174 | codecForTr.clear(); 175 | codecForSource.clear(); 176 | tsFileNames.clear(); 177 | uiFileNames.clear(); 178 | 179 | QMap tagMap = proFileTagMap( fullText ); 180 | QMap::Iterator it; 181 | 182 | for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { 183 | QStringList toks = it.value().split(' '); 184 | QStringList::Iterator t; 185 | 186 | for ( t = toks.begin(); t != toks.end(); ++t ) { 187 | if ( it.key() == "SOURCES" ) { 188 | fetchtr_py( (*t).toUtf8(), &fetchedTor, defaultContext.toUtf8(), true, codecForSource ); 189 | metSomething = true; 190 | } else if ( it.key() == "TRANSLATIONS" ) { 191 | tsFileNames.append( *t ); 192 | metSomething = true; 193 | } else if ( it.key() == "CODEC" || 194 | it.key() == "DEFAULTCODEC" || 195 | it.key() == "CODECFORTR" ) { 196 | codecForTr = (*t).toLatin1(); 197 | fetchedTor.setCodecForTr(codecForTr); 198 | } else if ( it.key() == "CODECFORSRC" ) { 199 | codecForSource = (*t).toLatin1(); 200 | } else if ( it.key() == "FORMS" ) { 201 | fetchtr_ui( (*t).toUtf8(), &fetchedTor, defaultContext.toUtf8(), true); 202 | } 203 | } 204 | } 205 | 206 | updateTsFiles( fetchedTor, tsFileNames, codecForTr, noObsolete, verbose ); 207 | 208 | if ( !metSomething ) { 209 | fprintf( stderr, 210 | "pyside2-lupdate warning: File '%s' does not look like a" 211 | " project file\n", 212 | argv[i] ); 213 | } else if ( tsFileNames.isEmpty() ) { 214 | fprintf( stderr, 215 | "pyside2-lupdate warning: Met no 'TRANSLATIONS' entry in" 216 | " project file '%s'\n", 217 | argv[i] ); 218 | } 219 | } else { 220 | if ( metTsFlag ) { 221 | if ( QString(argv[i]).toLower().endsWith(".ts") ) { 222 | QFileInfo fi( argv[i] ); 223 | if ( !fi.exists() || fi.isWritable() ) { 224 | tsFileNames.append( argv[i] ); 225 | } else { 226 | fprintf( stderr, 227 | "pyside2-lupdate warning: For some reason, I cannot" 228 | " save '%s'\n", 229 | argv[i] ); 230 | } 231 | } else { 232 | fprintf( stderr, 233 | "pyside2-lupdate error: File '%s' lacks .ts extension\n", 234 | argv[i] ); 235 | } 236 | } else { 237 | QFileInfo fi(argv[i]); 238 | if ( fi.suffix() == "py" || fi.suffix() == "pyw" ) { 239 | fetchtr_py( fi.fileName().toUtf8(), &fetchedTor, defaultContext.toUtf8(), true, codecForSource ); 240 | } else { 241 | fetchtr_ui( fi.fileName().toUtf8(), &fetchedTor, defaultContext.toUtf8(), true); 242 | } 243 | } 244 | } 245 | QDir::setCurrent( oldDir ); 246 | } 247 | 248 | if ( !standardSyntax ) 249 | updateTsFiles( fetchedTor, tsFileNames, codecForTr, noObsolete, verbose ); 250 | 251 | if ( numFiles == 0 ) { 252 | printUsage(); 253 | return 1; 254 | } 255 | return 0; 256 | } 257 | -------------------------------------------------------------------------------- /pylupdate/merge.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2006 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | 26 | #include "metatranslator.h" 27 | #include "simtexth.h" 28 | #include 29 | 30 | // defined in numberh.cpp 31 | extern int applyNumberHeuristic( MetaTranslator *tor ); 32 | // defined in sametexth.cpp 33 | extern int applySameTextHeuristic( MetaTranslator *tor ); 34 | 35 | typedef QList TML; 36 | 37 | /* 38 | Merges two MetaTranslator objects into the first one. The first one 39 | is a set of source texts and translations for a previous version of 40 | the internationalized program; the second one is a set of fresh 41 | source texts newly extracted from the source code, without any 42 | translation yet. 43 | */ 44 | 45 | void merge( const MetaTranslator *tor, const MetaTranslator *virginTor, MetaTranslator *outTor, bool verbose, bool noObsolete ) 46 | { 47 | int known = 0; 48 | int neww = 0; 49 | int obsoleted = 0; 50 | int UntranslatedObsoleted = 0; 51 | int similarTextHeuristicCount = 0; 52 | TML all = tor->messages(); 53 | TML::Iterator it; 54 | outTor->setLanguageCode(tor->languageCode()); 55 | 56 | /* 57 | The types of all the messages from the vernacular translator 58 | are updated according to the virgin translator. 59 | */ 60 | for ( it = all.begin(); it != all.end(); ++it ) { 61 | MetaTranslatorMessage::Type newType = MetaTranslatorMessage::Finished; 62 | MetaTranslatorMessage m = *it; 63 | 64 | // skip context comment 65 | if ( !QByteArray(m.sourceText()).isEmpty() ) { 66 | MetaTranslatorMessage mv = virginTor->find(m.context(), m.sourceText(), m.comment()); 67 | if ( mv.isNull() ) { 68 | mv = virginTor->find(m.context(), m.comment(), m.fileName(), m.lineNumber()); 69 | if ( mv.isNull() ) { 70 | // did not find it in the virgin, mark it as obsolete 71 | newType = MetaTranslatorMessage::Obsolete; 72 | if ( m.type() != MetaTranslatorMessage::Obsolete ) 73 | obsoleted++; 74 | } else { 75 | // Do not just accept it if its on the same line number, but different source text. 76 | // Also check if the texts are more or less similar before we consider them to represent the same message... 77 | // ### The QString() cast is evil 78 | if (getSimilarityScore(QString(m.sourceText()), mv.sourceText()) >= textSimilarityThreshold) { 79 | // It is just slightly modified, assume that it is the same string 80 | m = MetaTranslatorMessage(m.context(), mv.sourceText(), m.comment(), m.fileName(), m.lineNumber(), m.translations()); 81 | m.setPlural(mv.isPlural()); 82 | 83 | // Mark it as unfinished. (Since the source text was changed it might require re-translating...) 84 | newType = MetaTranslatorMessage::Unfinished; 85 | ++similarTextHeuristicCount; 86 | } else { 87 | // The virgin and vernacular sourceTexts are so different that we could not find it. 88 | newType = MetaTranslatorMessage::Obsolete; 89 | if ( m.type() != MetaTranslatorMessage::Obsolete ) 90 | obsoleted++; 91 | } 92 | neww++; 93 | } 94 | } else { 95 | switch ( m.type() ) { 96 | case MetaTranslatorMessage::Finished: 97 | default: 98 | if (m.isPlural() == mv.isPlural()) { 99 | newType = MetaTranslatorMessage::Finished; 100 | } else { 101 | newType = MetaTranslatorMessage::Unfinished; 102 | } 103 | known++; 104 | break; 105 | case MetaTranslatorMessage::Unfinished: 106 | newType = MetaTranslatorMessage::Unfinished; 107 | known++; 108 | break; 109 | case MetaTranslatorMessage::Obsolete: 110 | newType = MetaTranslatorMessage::Unfinished; 111 | neww++; 112 | } 113 | 114 | // Always get the filename and linenumber info from the virgin Translator, in case it has changed location. 115 | // This should also enable us to read a file that does not have the element. 116 | m.setFileName(mv.fileName()); 117 | m.setLineNumber(mv.lineNumber()); 118 | m.setPlural(mv.isPlural()); // ### why not use operator=? 119 | } 120 | 121 | if (newType == MetaTranslatorMessage::Obsolete && !m.isTranslated()) { 122 | ++UntranslatedObsoleted; 123 | } 124 | 125 | m.setType(newType); 126 | outTor->insert(m); 127 | } 128 | } 129 | 130 | /* 131 | Messages found only in the virgin translator are added to the 132 | vernacular translator. Among these are all the context comments. 133 | */ 134 | all = virginTor->messages(); 135 | 136 | for ( it = all.begin(); it != all.end(); ++it ) { 137 | MetaTranslatorMessage mv = *it; 138 | bool found = tor->contains(mv.context(), mv.sourceText(), mv.comment()); 139 | if (!found) { 140 | MetaTranslatorMessage m = tor->find(mv.context(), mv.comment(), mv.fileName(), mv.lineNumber()); 141 | if (!m.isNull()) { 142 | if (getSimilarityScore(QString(m.sourceText()), mv.sourceText()) >= textSimilarityThreshold) { 143 | found = true; 144 | } 145 | } else { 146 | found = false; 147 | } 148 | } 149 | if ( !found ) { 150 | outTor->insert( mv ); 151 | if ( !QByteArray(mv.sourceText()).isEmpty() ) 152 | neww++; 153 | } 154 | } 155 | 156 | /* 157 | The same-text heuristic handles cases where a message has an 158 | obsolete counterpart with a different context or comment. 159 | */ 160 | int sameTextHeuristicCount = applySameTextHeuristic( outTor ); 161 | 162 | /* 163 | The number heuristic handles cases where a message has an 164 | obsolete counterpart with mostly numbers differing in the 165 | source text. 166 | */ 167 | int sameNumberHeuristicCount = applyNumberHeuristic( outTor ); 168 | 169 | if ( verbose ) { 170 | int totalFound = neww + known; 171 | fprintf( stderr, " Found %d source text%s (%d new and %d already existing)\n", 172 | totalFound, totalFound == 1 ? "" : "s", neww, known); 173 | 174 | if (obsoleted) { 175 | if (noObsolete) { 176 | fprintf( stderr, " Removed %d obsolete entr%s\n", 177 | obsoleted, obsoleted == 1 ? "y" : "ies" ); 178 | } else { 179 | int total = obsoleted - UntranslatedObsoleted; 180 | fprintf( stderr, " Kept %d obsolete translation%s\n", 181 | total, total == 1 ? "" : "s" ); 182 | 183 | fprintf( stderr, " Removed %d obsolete untranslated entr%s\n", 184 | UntranslatedObsoleted, UntranslatedObsoleted == 1 ? "y" : "ies" ); 185 | 186 | } 187 | } 188 | 189 | if (sameNumberHeuristicCount) 190 | fprintf( stderr, " Number heuristic provided %d translation%s\n", 191 | sameNumberHeuristicCount, sameNumberHeuristicCount == 1 ? "" : "s" ); 192 | if (sameTextHeuristicCount) 193 | fprintf( stderr, " Same-text heuristic provided %d translation%s\n", 194 | sameTextHeuristicCount, sameTextHeuristicCount == 1 ? "" : "s" ); 195 | if (similarTextHeuristicCount) 196 | fprintf( stderr, " Similar-text heuristic provided %d translation%s\n", 197 | similarTextHeuristicCount, similarTextHeuristicCount == 1 ? "" : "s" ); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /pylupdate/metatranslator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2002-2007 Detlev Offenbach 6 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 7 | * 8 | * Contact: PySide team 9 | * 10 | * This program is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License 12 | * version 2 as published by the Free Software Foundation. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | * 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifndef METATRANSLATOR_H 27 | #define METATRANSLATOR_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | QT_FORWARD_DECLARE_CLASS(QTextCodec) 37 | 38 | class MetaTranslatorMessage : public TranslatorMessage 39 | { 40 | public: 41 | enum Type { Unfinished, Finished, Obsolete }; 42 | 43 | MetaTranslatorMessage(); 44 | MetaTranslatorMessage( const char *context, const char *sourceText, 45 | const char *comment, 46 | const QString &fileName, int lineNumber, 47 | const QStringList& translations = QStringList(), 48 | bool utf8 = false, Type type = Unfinished, 49 | bool plural = false ); 50 | MetaTranslatorMessage( const MetaTranslatorMessage& m ); 51 | 52 | MetaTranslatorMessage& operator=( const MetaTranslatorMessage& m ); 53 | 54 | void setType( Type nt ) { ty = nt; } 55 | Type type() const { return ty; } 56 | bool utf8() const { return utfeight; } 57 | bool isPlural() const { return m_plural; } 58 | void setPlural(bool isplural) { m_plural = isplural; } 59 | 60 | bool operator==( const MetaTranslatorMessage& m ) const; 61 | bool operator!=( const MetaTranslatorMessage& m ) const 62 | { return !operator==( m ); } 63 | bool operator<( const MetaTranslatorMessage& m ) const; 64 | bool operator<=( const MetaTranslatorMessage& m ) 65 | { return !operator>( m ); } 66 | bool operator>( const MetaTranslatorMessage& m ) const 67 | { return this->operator<( m ); } 68 | bool operator>=( const MetaTranslatorMessage& m ) const 69 | { return !operator<( m ); } 70 | 71 | private: 72 | bool utfeight; 73 | Type ty; 74 | bool m_plural; 75 | }; 76 | 77 | class MetaTranslator 78 | { 79 | public: 80 | MetaTranslator(); 81 | MetaTranslator( const MetaTranslator& tor ); 82 | 83 | MetaTranslator& operator=( const MetaTranslator& tor ); 84 | 85 | void clear(); 86 | bool load( const QString& filename ); 87 | bool save( const QString& filename ) const; 88 | bool release( const QString& filename, bool verbose = false, 89 | bool ignoreUnfinished = false, 90 | Translator::SaveMode mode = Translator::Stripped ) const; 91 | 92 | bool contains( const char *context, const char *sourceText, 93 | const char *comment ) const; 94 | 95 | MetaTranslatorMessage find( const char *context, const char *sourceText, 96 | const char *comment ) const; 97 | MetaTranslatorMessage find(const char *context, const char *comment, 98 | const QString &fileName, int lineNumber) const; 99 | 100 | void insert( const MetaTranslatorMessage& m ); 101 | 102 | void stripObsoleteMessages(); 103 | void stripEmptyContexts(); 104 | 105 | void setCodec( const char *name ); // kill me 106 | void setCodecForTr( const char *name ) { setCodec(name); } 107 | QTextCodec *codecForTr() const { return codec; } 108 | QString toUnicode( const char *str, bool utf8 ) const; 109 | 110 | QString languageCode() const; 111 | static void languageAndCountry(const QString &languageCode, QLocale::Language *lang, QLocale::Country *country); 112 | void setLanguageCode(const QString &languageCode); 113 | QList messages() const; 114 | QList translatedMessages() const; 115 | static int grammaticalNumerus(QLocale::Language language, QLocale::Country country); 116 | static QStringList normalizedTranslations(const MetaTranslatorMessage& m, 117 | QLocale::Language lang, QLocale::Country country); 118 | 119 | private: 120 | void makeFileNamesAbsolute(const QDir &oldPath); 121 | 122 | typedef QMap TMM; 123 | typedef QMap TMMInv; 124 | 125 | TMM mm; 126 | QByteArray codecName; 127 | QTextCodec *codec; 128 | QString m_language; // A string beginning with a 2 or 3 letter language code (ISO 639-1 or ISO-639-2), 129 | // followed by the optional country variant to distinguist between country-specific variations 130 | // of the language. The language code and country code are always separated by '_' 131 | // Note that the language part can also be a 3-letter ISO 639-2 code. 132 | // Legal examples: 133 | // 'pt' portuguese, assumes portuguese from portugal 134 | // 'pt_BR' Brazilian portuguese (ISO 639-1 language code) 135 | // 'por_BR' Brazilian portuguese (ISO 639-2 language code) 136 | }; 137 | 138 | /* 139 | This is a quick hack. The proper way to handle this would be 140 | to extend MetaTranslator's interface. 141 | */ 142 | #define ContextComment "QT_LINGUIST_INTERNAL_CONTEXT_COMMENT" 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /pylupdate/numberh.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2006 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include "metatranslator.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | typedef QMap TMM; 34 | typedef QList TML; 35 | 36 | static bool isDigitFriendly( int c ) 37 | { 38 | return ispunct((uchar)c) || isspace((uchar)c); 39 | } 40 | 41 | static int numberLength( const char *s ) 42 | { 43 | int i = 0; 44 | 45 | if ( isdigit((uchar)s[0]) ) { 46 | do { 47 | i++; 48 | } while (isdigit((uchar)s[i]) || 49 | (isDigitFriendly(s[i]) && 50 | (isdigit((uchar)s[i + 1]) || 51 | (isDigitFriendly(s[i + 1]) && isdigit((uchar)s[i + 2]))))); 52 | } 53 | return i; 54 | } 55 | 56 | /* 57 | Returns a version of 'key' where all numbers have been replaced by zeroes. If 58 | there were none, returns "". 59 | */ 60 | static QByteArray zeroKey( const char *key ) 61 | { 62 | QByteArray zeroed; 63 | zeroed.resize( int(strlen(key)) + 1 ); 64 | char *z = zeroed.data(); 65 | int i = 0, j = 0; 66 | int len; 67 | bool metSomething = false; 68 | 69 | while ( key[i] != '\0' ) { 70 | len = numberLength( key + i ); 71 | if ( len > 0 ) { 72 | i += len; 73 | z[j++] = '0'; 74 | metSomething = true; 75 | } else { 76 | z[j++] = key[i++]; 77 | } 78 | } 79 | z[j] = '\0'; 80 | 81 | if ( metSomething ) 82 | return zeroed; 83 | else 84 | return ""; 85 | } 86 | 87 | static QString translationAttempt( const QString& oldTranslation, 88 | const char *oldSource, 89 | const char *newSource ) 90 | { 91 | int p = zeroKey( oldSource ).count( '0' ); 92 | int oldSourceLen = qstrlen( oldSource ); 93 | QString attempt; 94 | QStringList oldNumbers; 95 | QStringList newNumbers; 96 | QVector met( p ); 97 | QVector matchedYet( p ); 98 | int i, j; 99 | int k = 0, ell, best; 100 | int m, n; 101 | int pass; 102 | 103 | /* 104 | This algorithm is hard to follow, so we'll consider an example 105 | all along: oldTranslation is "XeT 3.0", oldSource is "TeX 3.0" 106 | and newSource is "XeT 3.1". 107 | 108 | First, we set up two tables: oldNumbers and newNumbers. In our 109 | example, oldNumber[0] is "3.0" and newNumber[0] is "3.1". 110 | */ 111 | for ( i = 0, j = 0; i < oldSourceLen; i++, j++ ) { 112 | m = numberLength( oldSource + i ); 113 | n = numberLength( newSource + j ); 114 | if ( m > 0 ) { 115 | oldNumbers.append( QByteArray(oldSource + i, m + 1) ); 116 | newNumbers.append( QByteArray(newSource + j, n + 1) ); 117 | i += m; 118 | j += n; 119 | met[k] = false; 120 | matchedYet[k] = 0; 121 | k++; 122 | } 123 | } 124 | 125 | /* 126 | We now go over the old translation, "XeT 3.0", one letter at a 127 | time, looking for numbers found in oldNumbers. Whenever such a 128 | number is met, it is replaced with its newNumber equivalent. In 129 | our example, the "3.0" of "XeT 3.0" becomes "3.1". 130 | */ 131 | for ( i = 0; i < (int) oldTranslation.length(); i++ ) { 132 | attempt += oldTranslation[i]; 133 | for ( k = 0; k < p; k++ ) { 134 | if ( oldTranslation[i] == oldNumbers[k][matchedYet[k]] ) 135 | matchedYet[k]++; 136 | else 137 | matchedYet[k] = 0; 138 | } 139 | 140 | /* 141 | Let's find out if the last character ended a match. We make 142 | two passes over the data. In the first pass, we try to 143 | match only numbers that weren't matched yet; if that fails, 144 | the second pass does the trick. This is useful in some 145 | suspicious cases, flagged below. 146 | */ 147 | for ( pass = 0; pass < 2; pass++ ) { 148 | best = p; // an impossible value 149 | for ( k = 0; k < p; k++ ) { 150 | if ( (!met[k] || pass > 0) && 151 | matchedYet[k] == (int) oldNumbers[k].length() && 152 | numberLength(oldTranslation.toLatin1().constData() + (i + 1) - 153 | matchedYet[k]) == matchedYet[k] ) { 154 | // the longer the better 155 | if ( best == p || matchedYet[k] > matchedYet[best] ) 156 | best = k; 157 | } 158 | } 159 | if ( best != p ) { 160 | attempt.truncate( attempt.length() - matchedYet[best] ); 161 | attempt += newNumbers[best]; 162 | met[best] = true; 163 | for ( k = 0; k < p; k++ ) 164 | matchedYet[k] = 0; 165 | break; 166 | } 167 | } 168 | } 169 | 170 | /* 171 | We flag two kinds of suspicious cases. They are identified as 172 | such with comments such as "{2000?}" at the end. 173 | 174 | Example of the first kind: old source text "TeX 3.0" translated 175 | as "XeT 2.0" is flagged "TeX 2.0 {3.0?}", no matter what the 176 | new text is. 177 | */ 178 | for ( k = 0; k < p; k++ ) { 179 | if ( !met[k] ) 180 | attempt += QString( " {" ) + newNumbers[k] + QString( "?}" ); 181 | } 182 | 183 | /* 184 | Example of the second kind: "1 of 1" translated as "1 af 1", 185 | with new source text "1 of 2", generates "1 af 2 {1 or 2?}" 186 | because it's not clear which of "1 af 2" and "2 af 1" is right. 187 | */ 188 | for ( k = 0; k < p; k++ ) { 189 | for ( ell = 0; ell < p; ell++ ) { 190 | if ( k != ell && oldNumbers[k] == oldNumbers[ell] && 191 | newNumbers[k] < newNumbers[ell] ) 192 | attempt += QString( " {" ) + newNumbers[k] + QString( " or " ) + 193 | newNumbers[ell] + QString( "?}" ); 194 | } 195 | } 196 | return attempt; 197 | } 198 | 199 | /* 200 | Augments a MetaTranslator with translations easily derived from 201 | similar existing (probably obsolete) translations. 202 | 203 | For example, if "TeX 3.0" is translated as "XeT 3.0" and "TeX 3.1" 204 | has no translation, "XeT 3.1" is added to the translator and is 205 | marked Unfinished. 206 | 207 | Returns the number of additional messages that this heuristic translated. 208 | */ 209 | int applyNumberHeuristic( MetaTranslator *tor ) 210 | { 211 | TMM translated, untranslated; 212 | TMM::Iterator t, u; 213 | TML all = tor->messages(); 214 | TML::Iterator it; 215 | int inserted = 0; 216 | 217 | for ( it = all.begin(); it != all.end(); ++it ) { 218 | bool hasTranslation = (*it).isTranslated(); 219 | if ( (*it).type() == MetaTranslatorMessage::Unfinished ) { 220 | if ( !hasTranslation ) 221 | untranslated.insert(QByteArray((*it).context()) + "\n" + (*it).sourceText() + "\n" 222 | + (*it).comment(), *it); 223 | } else if ( hasTranslation && (*it).translations().count() == 1 ) { 224 | translated.insert( zeroKey((*it).sourceText()), *it ); 225 | } 226 | } 227 | 228 | for ( u = untranslated.begin(); u != untranslated.end(); ++u ) { 229 | t = translated.find( zeroKey((*u).sourceText()) ); 230 | if ( t != translated.end() && !t.key().isEmpty() && 231 | qstrcmp((*t).sourceText(), (*u).sourceText()) != 0 ) { 232 | MetaTranslatorMessage m( *u ); 233 | m.setTranslation(translationAttempt((*t).translation(), (*t).sourceText(), 234 | (*u).sourceText())); 235 | tor->insert( m ); 236 | inserted++; 237 | } 238 | } 239 | return inserted; 240 | } 241 | -------------------------------------------------------------------------------- /pylupdate/proparser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include "proparser.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifdef Q_OS_UNIX 35 | #include 36 | #endif 37 | 38 | #ifdef Q_OS_WIN32 39 | #define QT_POPEN _popen 40 | #else 41 | #define QT_POPEN popen 42 | #endif 43 | 44 | QString loadFile( const QString &fileName ) 45 | { 46 | QFile file( fileName ); 47 | if ( !file.open(QIODevice::ReadOnly) ) { 48 | fprintf( stderr, "error: Cannot load '%s': %s\n", 49 | file.fileName().toLatin1().constData(), 50 | file.errorString().toLatin1().constData() ); 51 | return QString(); 52 | } 53 | 54 | QTextStream in( &file ); 55 | return in.readAll(); 56 | } 57 | 58 | QMap proFileTagMap( const QString& text ) 59 | { 60 | QString t = text; 61 | 62 | QMap tagMap; 63 | bool stillProcess = true; // If include() has a $$tag then we need to reprocess 64 | 65 | while (stillProcess) { 66 | /* 67 | Strip any commments before we try to include. We 68 | still need to do it after we include to make sure the 69 | included file does not have comments 70 | */ 71 | t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") ); 72 | 73 | /* 74 | Process include() commands. 75 | $$PWD is a special case so we have to change it while 76 | we know where the included file is. 77 | */ 78 | QRegExp callToInclude("include\\s*\\(\\s*([^()\\s]+)\\s*\\)"); 79 | int i = 0; 80 | while ( (i = callToInclude.indexIn(t, i)) != -1 ) { 81 | bool doneWithVar = false; 82 | QString fileName = callToInclude.cap(1); 83 | QString after = fileName.replace("$$PWD", QDir::currentPath()); 84 | if (!tagMap.isEmpty() && after.contains("$$")) { 85 | QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" ); 86 | int ii = 0; 87 | while ((ii = after.indexOf(var, ii)) != -1) { 88 | if (tagMap.contains(var.cap(1))) { 89 | after.replace(ii, var.cap(0).length(), tagMap[var.cap(1)]); 90 | } else { // Couldn't find it 91 | doneWithVar = true; 92 | break; 93 | } 94 | } 95 | 96 | } 97 | if (doneWithVar || !after.contains("$$")) { 98 | after = loadFile(after); 99 | QFileInfo fi(callToInclude.cap(1)); 100 | after.replace("$$PWD", fi.path()); 101 | t.replace( i, callToInclude.matchedLength(), after ); 102 | } 103 | i += after.length(); 104 | } 105 | 106 | /* 107 | Strip comments, merge lines ending with backslash, add 108 | spaces around '=' and '+=', replace '\n' with ';', and 109 | simplify white spaces. 110 | */ 111 | t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") ); 112 | t.replace( QRegExp(QString("\\\\[^\n\\S]*\n")), QString(" ") ); 113 | t.replace( "=", QString(" = ") ); 114 | t.replace( "+ =", QString(" += ") ); 115 | t.replace( "\n", QString(";") ); 116 | t.replace( "\r", QString("") ); // remove carriage return 117 | t = t.simplified(); 118 | 119 | /* 120 | Populate tagMap with 'key = value' entries. 121 | */ 122 | QStringList lines = t.split(';', QString::SkipEmptyParts); 123 | QStringList::Iterator line; 124 | for ( line = lines.begin(); line != lines.end(); ++line ) { 125 | QStringList toks = (*line).split(' ', QString::SkipEmptyParts); 126 | 127 | if ( toks.count() >= 3 && 128 | (toks[1] == QString("=") || toks[1] == QString("+=") || 129 | toks[1] == QString("*=")) ) { 130 | QString tag = toks.first(); 131 | int k = tag.lastIndexOf( QChar(':') ); // as in 'unix:' 132 | if ( k != -1 ) 133 | tag = tag.mid( k + 1 ); 134 | toks.erase( toks.begin() ); 135 | 136 | QString action = toks.first(); 137 | toks.erase( toks.begin() ); 138 | 139 | if ( tagMap.contains(tag) ) { 140 | if ( action == QString("=") ) 141 | tagMap.insert( tag, toks.join(" ") ); 142 | else 143 | tagMap[tag] += QChar( ' ' ) + toks.join( " " ); 144 | } else { 145 | tagMap[tag] = toks.join( " " ); 146 | } 147 | } 148 | } 149 | /* 150 | Expand $$variables within the 'value' part of a 'key = value' 151 | pair. 152 | */ 153 | QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" ); 154 | QMap::Iterator it; 155 | for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { 156 | int i = 0; 157 | while ( (i = var.indexIn((*it), i)) != -1 ) { 158 | int len = var.matchedLength(); 159 | QString invocation = var.cap(1); 160 | QString after; 161 | 162 | if ( invocation == "system" ) { 163 | // skip system(); it will be handled in the next pass 164 | ++i; 165 | } else { 166 | if ( tagMap.contains(invocation) ) 167 | after = tagMap[invocation]; 168 | else if (invocation.toLower() == "pwd") 169 | after = QDir::currentPath(); 170 | (*it).replace( i, len, after ); 171 | i += after.length(); 172 | } 173 | } 174 | } 175 | 176 | /* 177 | Execute system() calls. 178 | */ 179 | QRegExp callToSystem( "\\$\\$system\\s*\\(([^()]*)\\)" ); 180 | for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { 181 | int i = 0; 182 | while ( (i = callToSystem.indexIn((*it), i)) != -1 ) { 183 | /* 184 | This code is stolen from qmake's project.cpp file. 185 | Ideally we would use the same parser, so we wouldn't 186 | have this code duplication. 187 | */ 188 | QString after; 189 | char buff[256]; 190 | FILE *proc = QT_POPEN( callToSystem.cap(1).toLatin1().constData(), "r" ); 191 | while ( proc && !feof(proc) ) { 192 | int read_in = int(fread( buff, 1, 255, proc )); 193 | if ( !read_in ) 194 | break; 195 | for ( int i = 0; i < read_in; i++ ) { 196 | if ( buff[i] == '\n' || buff[i] == '\t' ) 197 | buff[i] = ' '; 198 | } 199 | buff[read_in] = '\0'; 200 | after += buff; 201 | } 202 | (*it).replace( i, callToSystem.matchedLength(), after ); 203 | i += after.length(); 204 | } 205 | } 206 | stillProcess = callToInclude.indexIn(t) != -1; 207 | } 208 | return tagMap; 209 | } 210 | -------------------------------------------------------------------------------- /pylupdate/proparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2002-2007 Detlev Offenbach 6 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 7 | * 8 | * Contact: PySide team 9 | * 10 | * This program is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License 12 | * version 2 as published by the Free Software Foundation. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | * 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifndef PROPARSER_H 27 | #define PROPARSER_H 28 | 29 | #include 30 | #include 31 | 32 | QMap proFileTagMap( const QString& text ); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /pylupdate/pyside2-lupdate.1: -------------------------------------------------------------------------------- 1 | .TH PYSIDE-LUPDATE "1" "December 2010" "pyside2-lupdate" "User Commands" 2 | .SH NAME 3 | pyside2\-lupdate \- extracts translatable messages from Qt UI files and Python source code. 4 | .SH DESCRIPTION 5 | .SS "Usage:" 6 | .IP 7 | pyside2\-lupdate [options] project\-file 8 | .IP 9 | pyside2\-lupdate [options] source\-files \-ts ts\-files 10 | .SS "Options:" 11 | .TP 12 | \fB\-noobsolete 13 | Drop all obsolete strings 14 | .TP 15 | \fB\-verbose 16 | Explain what is being done 17 | .TP 18 | \fB\-version 19 | Display the version of pyside2-lupdate and exit 20 | .TP 21 | \fB\-help 22 | Display this information and exit 23 | .SH COPYRIGHT 24 | Copyright \(co 2010 Nokia Corporation and/or its subsidiary(\fB\-ies\fR) 25 | .SH AUTHOR 26 | .PP 27 | This manpage was written by Marcelo Lira , on the 29. December 2010. 28 | -------------------------------------------------------------------------------- /pylupdate/sametexth.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2006 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include "metatranslator.h" 26 | 27 | #include 28 | #include 29 | 30 | typedef QMap TMM; 31 | typedef QList TML; 32 | 33 | /* 34 | Augments a MetaTranslator with trivially derived translations. 35 | 36 | For example, if "Enabled:" is consistendly translated as "Eingeschaltet:" no 37 | matter the context or the comment, "Eingeschaltet:" is added as the 38 | translation of any untranslated "Enabled:" text and is marked Unfinished. 39 | 40 | Returns the number of additional messages that this heuristic translated. 41 | */ 42 | 43 | int applySameTextHeuristic( MetaTranslator *tor ) 44 | { 45 | TMM translated; 46 | TMM avoid; 47 | TMM::Iterator t; 48 | TML untranslated; 49 | TML::Iterator u; 50 | TML all = tor->messages(); 51 | TML::Iterator it; 52 | int inserted = 0; 53 | 54 | for ( it = all.begin(); it != all.end(); ++it ) { 55 | if ( (*it).type() == MetaTranslatorMessage::Unfinished ) { 56 | if ( !(*it).isTranslated() ) 57 | untranslated.append( *it ); 58 | } else { 59 | QByteArray key = (*it).sourceText(); 60 | t = translated.find( key ); 61 | if ( t != translated.end() ) { 62 | /* 63 | The same source text is translated at least two 64 | different ways. Do nothing then. 65 | */ 66 | if ( (*t).translations() != (*it).translations() ) { 67 | translated.remove( key ); 68 | avoid.insert( key, *it ); 69 | } 70 | } else if ( !avoid.contains(key) && (*it).isTranslated() ) { 71 | translated.insert( key, *it ); 72 | } 73 | } 74 | } 75 | 76 | for ( u = untranslated.begin(); u != untranslated.end(); ++u ) { 77 | QByteArray key = (*u).sourceText(); 78 | t = translated.find( key ); 79 | if ( t != translated.end() ) { 80 | MetaTranslatorMessage m( *u ); 81 | m.setTranslations( (*t).translations() ); 82 | tor->insert( m ); 83 | inserted++; 84 | } 85 | } 86 | return inserted; 87 | } 88 | -------------------------------------------------------------------------------- /pylupdate/simtexth.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2006 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include "simtexth.h" 26 | #include "metatranslator.h" 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | typedef QList TML; 34 | 35 | /* 36 | How similar are two texts? The approach used here relies on co-occurrence 37 | matrices and is very efficient. 38 | 39 | Let's see with an example: how similar are "here" and "hither"? The 40 | co-occurrence matrix M for "here" is M[h,e] = 1, M[e,r] = 1, M[r,e] = 1, and 0 41 | elsewhere; the matrix N for "hither" is N[h,i] = 1, N[i,t] = 1, ..., 42 | N[h,e] = 1, N[e,r] = 1, and 0 elsewhere. The union U of both matrices is the 43 | matrix U[i,j] = max { M[i,j], N[i,j] }, and the intersection V is 44 | V[i,j] = min { M[i,j], N[i,j] }. The score for a pair of texts is 45 | 46 | score = (sum of V[i,j] over all i, j) / (sum of U[i,j] over all i, j), 47 | 48 | a formula suggested by Arnt Gulbrandsen. Here we have 49 | 50 | score = 2 / 6, 51 | 52 | or one third. 53 | 54 | The implementation differs from this in a few details. Most importantly, 55 | repetitions are ignored; for input "xxx", M[x,x] equals 1, not 2. 56 | */ 57 | 58 | /* 59 | Every character is assigned to one of 20 buckets so that the co-occurrence 60 | matrix requires only 20 * 20 = 400 bits, not 256 * 256 = 65536 bits or even 61 | more if we want the whole Unicode. Which character falls in which bucket is 62 | arbitrary. 63 | 64 | The second half of the table is a replica of the first half, because of 65 | laziness. 66 | */ 67 | static const int indexOf[256] = { 68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | // ! " # $ % & ' ( ) * + , - . / 71 | 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, 72 | // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 73 | 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, 74 | // @ A B C D E F G H I J K L M N O 75 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 76 | // P Q R S T U V W X Y Z [ \ ] ^ _ 77 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, 78 | // ` a b c d e f g h i j k l m n o 79 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 80 | // p q r s t u v w x y z { | } ~ 81 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, 82 | 83 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85 | 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, 86 | 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, 87 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 88 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, 89 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 90 | 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0 91 | }; 92 | 93 | /* 94 | The entry bitCount[i] (for i between 0 and 255) is the number of bits used to 95 | represent i in binary. 96 | */ 97 | static const int bitCount[256] = { 98 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 99 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 100 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 101 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 102 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 103 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 104 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 105 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 106 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 107 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 108 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 109 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 110 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 111 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 112 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 113 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 114 | }; 115 | 116 | struct CoMatrix 117 | { 118 | /* 119 | The matrix has 20 * 20 = 400 entries. This requires 50 bytes, or 13 120 | words. Some operations are performed on words for more efficiency. 121 | */ 122 | union { 123 | quint8 b[52]; 124 | quint32 w[13]; 125 | }; 126 | 127 | CoMatrix() { memset( b, 0, 52 ); } 128 | CoMatrix( const char *text ) { 129 | char c = '\0', d; 130 | memset( b, 0, 52 ); 131 | /* 132 | The Knuth books are not in the office only for show; they help make 133 | loops 30% faster and 20% as readable. 134 | */ 135 | while ( (d = *text) != '\0' ) { 136 | setCoocc( c, d ); 137 | if ( (c = *++text) != '\0' ) { 138 | setCoocc( d, c ); 139 | text++; 140 | } 141 | } 142 | } 143 | 144 | void setCoocc( char c, char d ) { 145 | int k = indexOf[(uchar) c] + 20 * indexOf[(uchar) d]; 146 | b[k >> 3] |= k & 0x7; 147 | } 148 | 149 | int worth() const { 150 | int w = 0; 151 | for ( int i = 0; i < 50; i++ ) 152 | w += bitCount[b[i]]; 153 | return w; 154 | } 155 | }; 156 | 157 | static inline CoMatrix reunion( const CoMatrix& m, const CoMatrix& n ) 158 | { 159 | CoMatrix p; 160 | for ( int i = 0; i < 13; i++ ) 161 | p.w[i] = m.w[i] | n.w[i]; 162 | return p; 163 | } 164 | 165 | static inline CoMatrix intersection( const CoMatrix& m, const CoMatrix& n ) 166 | { 167 | CoMatrix p; 168 | for ( int i = 0; i < 13; i++ ) 169 | p.w[i] = m.w[i] & n.w[i]; 170 | return p; 171 | } 172 | 173 | StringSimilarityMatcher::StringSimilarityMatcher(const QString &stringToMatch) 174 | { 175 | m_cm = new CoMatrix( stringToMatch.toLatin1().constData() ); 176 | m_length = stringToMatch.length(); 177 | } 178 | 179 | int StringSimilarityMatcher::getSimilarityScore(const QString &strCandidate) 180 | { 181 | CoMatrix cmTarget( strCandidate.toLatin1().constData() ); 182 | int targetLen = strCandidate.length(); 183 | int delta = qAbs( m_length - targetLen ); 184 | 185 | int score = ( (intersection(*m_cm, cmTarget).worth() + 1) << 10 ) / 186 | ( reunion(*m_cm, cmTarget).worth() + (delta << 1) + 1 ); 187 | 188 | return score; 189 | } 190 | 191 | StringSimilarityMatcher::~StringSimilarityMatcher() 192 | { 193 | delete m_cm; 194 | } 195 | 196 | /** 197 | * Checks how similar two strings are. 198 | * The return value is the score, and a higher score is more similar than one with a low score. 199 | * Linguist considers a score over 190 to be a good match. 200 | * \sa StringSimilarityMatcher 201 | */ 202 | int getSimilarityScore(const QString &str1, const char* str2) 203 | { 204 | CoMatrix cmTarget( str2 ); 205 | int targetLen = qstrlen( str2 ); 206 | CoMatrix cm( str1.toLatin1().constData() ); 207 | int delta = qAbs( (int) str1.length() - targetLen ); 208 | 209 | int score = ( (intersection(cm, cmTarget).worth() + 1) << 10 ) / 210 | ( reunion(cm, cmTarget).worth() + (delta << 1) + 1 ); 211 | 212 | return score; 213 | } 214 | 215 | CandidateList similarTextHeuristicCandidates( const MetaTranslator *tor, 216 | const char *text, 217 | int maxCandidates ) 218 | { 219 | QList scores; 220 | CandidateList candidates; 221 | 222 | TML all = tor->translatedMessages(); 223 | 224 | foreach ( MetaTranslatorMessage mtm, all ) { 225 | if ( mtm.type() == MetaTranslatorMessage::Unfinished || 226 | mtm.translation().isEmpty() ) 227 | continue; 228 | 229 | QString s = tor->toUnicode( mtm.sourceText(), mtm.utf8() ); 230 | int score = getSimilarityScore(s, text); 231 | 232 | if ( (int) candidates.count() == maxCandidates && 233 | score > scores[maxCandidates - 1] ) 234 | candidates.removeAt( candidates.size()-1 ); 235 | if ( (int) candidates.count() < maxCandidates && score >= textSimilarityThreshold ) { 236 | Candidate cand( s, mtm.translation() ); 237 | 238 | int i; 239 | for ( i = 0; i < (int) candidates.size(); i++ ) { 240 | if ( score >= scores.at(i) ) { 241 | if ( score == scores.at(i) ) { 242 | if ( candidates.at(i) == cand ) 243 | goto continue_outer_loop; 244 | } else { 245 | break; 246 | } 247 | } 248 | } 249 | scores.insert( i, score ); 250 | candidates.insert( i, cand ); 251 | } 252 | continue_outer_loop: 253 | ; 254 | } 255 | return candidates; 256 | } 257 | -------------------------------------------------------------------------------- /pylupdate/simtexth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2006 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef SIMTEXTH_H 26 | #define SIMTEXTH_H 27 | 28 | const int textSimilarityThreshold = 190; 29 | 30 | #include 31 | #include 32 | 33 | class MetaTranslator; 34 | 35 | struct Candidate { 36 | QString source; 37 | QString target; 38 | 39 | Candidate() { } 40 | Candidate( const QString& source0, const QString& target0 ) 41 | : source( source0 ), target( target0 ) { } 42 | }; 43 | 44 | inline bool operator==( const Candidate& c, const Candidate& d ) { 45 | return c.target == d.target && c.source == d.source; 46 | } 47 | inline bool operator!=( const Candidate& c, const Candidate& d ) { 48 | return !operator==( c, d ); 49 | } 50 | 51 | typedef QList CandidateList; 52 | 53 | struct CoMatrix; 54 | /** 55 | * This class is more efficient for searching through a large array of candidate strings, since we only 56 | * have to construct the CoMatrix for the \a stringToMatch once, 57 | * after that we just call getSimilarityScore(strCandidate). 58 | * \sa getSimilarityScore 59 | */ 60 | class StringSimilarityMatcher { 61 | public: 62 | StringSimilarityMatcher(const QString &stringToMatch); 63 | ~StringSimilarityMatcher(); 64 | int getSimilarityScore(const QString &strCandidate); 65 | 66 | private: 67 | CoMatrix *m_cm; 68 | int m_length; 69 | }; 70 | 71 | int getSimilarityScore(const QString &str1, const char* str2); 72 | 73 | CandidateList similarTextHeuristicCandidates( const MetaTranslator *tor, 74 | const char *text, 75 | int maxCandidates ); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /pylupdate/translator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2002-2007 Detlev Offenbach 6 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 7 | * 8 | * Contact: PySide team 9 | * 10 | * This program is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License 12 | * version 2 as published by the Free Software Foundation. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | * 02110-1301 USA 23 | * 24 | */ 25 | 26 | #ifndef TRANSLATOR_H 27 | #define TRANSLATOR_H 28 | 29 | #include "QtCore/qobject.h" 30 | #include "QtCore/qbytearray.h" 31 | #include "QtCore/qstringlist.h" 32 | #include "QtCore/qlocale.h" 33 | #include 34 | 35 | class TranslatorPrivate; 36 | 37 | class TranslatorMessage 38 | { 39 | public: 40 | TranslatorMessage(); 41 | TranslatorMessage(const char * context, const char * sourceText, 42 | const char * comment, 43 | const QString &fileName, 44 | int lineNumber, 45 | const QStringList& translations = QStringList()); 46 | TranslatorMessage(const TranslatorMessage & m); 47 | 48 | TranslatorMessage & operator=(const TranslatorMessage & m); 49 | 50 | uint hash() const { return h; } 51 | const char *context() const { return cx.isNull() ? 0 : cx.constData(); } 52 | const char *sourceText() const { return st.isNull() ? 0 : st.constData(); } 53 | const char *comment() const { return cm.isNull() ? 0 : cm.constData(); } 54 | 55 | inline void setTranslations(const QStringList &translations); 56 | QStringList translations() const { return m_translations; } 57 | void setTranslation(const QString &translation) { m_translations = QStringList(translation); } 58 | QString translation() const { return m_translations.value(0); } 59 | bool isTranslated() const { return m_translations.count() > 1 || !m_translations.value(0).isEmpty(); } 60 | 61 | enum Prefix { NoPrefix, Hash, HashContext, HashContextSourceText, 62 | HashContextSourceTextComment }; 63 | void write(QDataStream & s, bool strip = false, 64 | Prefix prefix = HashContextSourceTextComment) const; 65 | Prefix commonPrefix(const TranslatorMessage&) const; 66 | 67 | bool operator==(const TranslatorMessage& m) const; 68 | bool operator!=(const TranslatorMessage& m) const 69 | { return !operator==(m); } 70 | bool operator<(const TranslatorMessage& m) const; 71 | bool operator<=(const TranslatorMessage& m) const 72 | { return !m.operator<(*this); } 73 | bool operator>(const TranslatorMessage& m) const 74 | { return m.operator<(*this); } 75 | bool operator>=(const TranslatorMessage& m) const 76 | { return !operator<(m); } 77 | 78 | QString fileName(void) const { return m_fileName; } 79 | void setFileName(const QString &fileName) { m_fileName = fileName; } 80 | int lineNumber(void) const { return m_lineNumber; } 81 | void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; } 82 | bool isNull() const { return st.isNull() && m_lineNumber == -1 && m_translations.isEmpty(); } 83 | 84 | private: 85 | uint h; 86 | QByteArray cx; 87 | QByteArray st; 88 | QByteArray cm; 89 | QStringList m_translations; 90 | QString m_fileName; 91 | int m_lineNumber; 92 | 93 | enum Tag { Tag_End = 1, Tag_SourceText16, Tag_Translation, Tag_Context16, 94 | Tag_Hash, Tag_SourceText, Tag_Context, Tag_Comment, 95 | Tag_Obsolete1 }; 96 | }; 97 | 98 | QT_BEGIN_NAMESPACE 99 | Q_DECLARE_TYPEINFO(TranslatorMessage, Q_MOVABLE_TYPE); 100 | QT_END_NAMESPACE 101 | 102 | inline void TranslatorMessage::setTranslations(const QStringList &translations) 103 | { m_translations = translations; } 104 | 105 | class Translator : public QTranslator 106 | { 107 | Q_OBJECT 108 | public: 109 | explicit Translator(QObject *parent = 0); 110 | ~Translator(); 111 | 112 | virtual TranslatorMessage findMessage(const char *context, const char *sourceText, 113 | const char *comment = 0, 114 | const QString &fileName = 0, int lineNumber = -1) const; 115 | virtual QString translate(const char *context, const char *sourceText, 116 | const char *comment = 0) const 117 | { return findMessage(context, sourceText, comment).translation(); } 118 | 119 | bool load(const QString & filename, 120 | const QString & directory = QString(), 121 | const QString & search_delimiters = QString(), 122 | const QString & suffix = QString()); 123 | bool load(const uchar *data, int len); 124 | 125 | void clear(); 126 | 127 | enum SaveMode { Everything, Stripped }; 128 | 129 | bool save(const QString & filename, SaveMode mode = Everything); 130 | 131 | void insert(const TranslatorMessage&); 132 | inline void insert(const char *context, const char *sourceText, const QString &fileName, int lineNo, const QStringList &translations) { 133 | insert(TranslatorMessage(context, sourceText, "", fileName, lineNo, translations)); 134 | } 135 | void remove(const TranslatorMessage&); 136 | inline void remove(const char *context, const char *sourceText) { 137 | remove(TranslatorMessage(context, sourceText, "", QLatin1String(""), -1)); 138 | } 139 | bool contains(const char *context, const char *sourceText, const char * comment = 0) const; 140 | bool contains(const char *context, const char *comment, const QString &fileName, int lineNumber) const; 141 | 142 | void squeeze(SaveMode = Everything); 143 | void unsqueeze(); 144 | 145 | QList messages() const; 146 | 147 | bool isEmpty() const; 148 | 149 | private: 150 | Q_DISABLE_COPY(Translator) 151 | TranslatorPrivate *d; 152 | }; 153 | 154 | static const char * const japaneseStyleForms[] = { "Unique Form", 0 }; 155 | static const char * const englishStyleForms[] = { "Singular", "Plural", 0 }; 156 | static const char * const frenchStyleForms[] = { "Singular", "Plural", 0 }; 157 | static const char * const latvianForms[] = { "Singular", "Plural", "Nullar", 0 }; 158 | static const char * const irishStyleForms[] = { "Singular", "Dual", "Plural", 0 }; 159 | static const char * const czechForms[] = { "Singular", "Dual", "Plural", 0 }; 160 | static const char * const slovakForms[] = { "Singular", "Dual", "Plural", 0 }; 161 | static const char * const macedonianForms[] = { "Singular", "Dual", "Plural", 0 }; 162 | static const char * const lithuanianForms[] = { "Singular", "Dual", "Plural", 0 }; 163 | static const char * const russianStyleForms[] = { "Singular", "Dual", "Plural", 0 }; 164 | static const char * const polishForms[] = { "Singular", "Paucal", "Plural", 0 }; 165 | static const char * const romanianForms[] = 166 | { "Singular", "Plural Form for 2 to 19", "Plural", 0 }; 167 | static const char * const slovenianForms[] = { "Singular", "Dual", "Trial", "Plural", 0 }; 168 | static const char * const malteseForms[] = 169 | { "Singular", "Plural Form for 2 to 10", "Plural Form for 11 to 19", "Plural", 0 }; 170 | static const char * const welshForms[] = 171 | { "Nullar", "Singular", "Dual", "Sexal", "Plural", 0 }; 172 | static const char * const arabicForms[] = 173 | { "Nullar", "Singular", "Dual", "Minority Plural", "Plural", "Plural Form for 100, 200, ...", 0 }; 174 | 175 | #define EOL QLocale::C 176 | 177 | static const QLocale::Language japaneseStyleLanguages[] = { 178 | QLocale::Afan, 179 | QLocale::Armenian, 180 | QLocale::Bhutani, 181 | QLocale::Bislama, 182 | QLocale::Burmese, 183 | QLocale::Chinese, 184 | QLocale::Fijian, 185 | QLocale::Guarani, 186 | QLocale::Hungarian, 187 | QLocale::Indonesian, 188 | QLocale::Japanese, 189 | QLocale::Javanese, 190 | QLocale::Korean, 191 | QLocale::Malay, 192 | QLocale::NauruLanguage, 193 | QLocale::Persian, 194 | QLocale::Sundanese, 195 | QLocale::Thai, 196 | QLocale::Tibetan, 197 | QLocale::Vietnamese, 198 | QLocale::Yoruba, 199 | QLocale::Zhuang, 200 | EOL 201 | }; 202 | 203 | static const QLocale::Language englishStyleLanguages[] = { 204 | QLocale::Abkhazian, 205 | QLocale::Afar, 206 | QLocale::Afrikaans, 207 | QLocale::Albanian, 208 | QLocale::Amharic, 209 | QLocale::Assamese, 210 | QLocale::Aymara, 211 | QLocale::Azerbaijani, 212 | QLocale::Bashkir, 213 | QLocale::Basque, 214 | QLocale::Bengali, 215 | QLocale::Bihari, 216 | // Missing: Bokmal, 217 | QLocale::Bulgarian, 218 | QLocale::Cambodian, 219 | QLocale::Catalan, 220 | QLocale::Cornish, 221 | QLocale::Corsican, 222 | QLocale::Danish, 223 | QLocale::Dutch, 224 | QLocale::English, 225 | QLocale::Esperanto, 226 | QLocale::Estonian, 227 | QLocale::Faroese, 228 | QLocale::Finnish, 229 | // Missing: Friulian, 230 | QLocale::Frisian, 231 | QLocale::Galician, 232 | QLocale::Georgian, 233 | QLocale::German, 234 | QLocale::Greek, 235 | QLocale::Greenlandic, 236 | QLocale::Gujarati, 237 | QLocale::Hausa, 238 | QLocale::Hebrew, 239 | QLocale::Hindi, 240 | QLocale::Icelandic, 241 | QLocale::Interlingua, 242 | QLocale::Interlingue, 243 | QLocale::Italian, 244 | QLocale::Kannada, 245 | QLocale::Kashmiri, 246 | QLocale::Kazakh, 247 | QLocale::Kinyarwanda, 248 | QLocale::Kirghiz, 249 | QLocale::Kurdish, 250 | QLocale::Kurundi, 251 | QLocale::Lao, 252 | QLocale::Latin, 253 | // Missing: Letzeburgesch, 254 | QLocale::Lingala, 255 | QLocale::Malagasy, 256 | QLocale::Malayalam, 257 | QLocale::Marathi, 258 | QLocale::Mongolian, 259 | // Missing: Nahuatl, 260 | QLocale::Nepali, 261 | QLocale::NorthernSotho, 262 | QLocale::Norwegian, 263 | QLocale::NorwegianNynorsk, 264 | QLocale::Occitan, 265 | QLocale::Oriya, 266 | QLocale::Pashto, 267 | QLocale::Portuguese, 268 | QLocale::Punjabi, 269 | QLocale::Quechua, 270 | QLocale::RhaetoRomance, 271 | QLocale::SouthernSotho, 272 | QLocale::Tswana, 273 | QLocale::Shona, 274 | QLocale::Sindhi, 275 | QLocale::Sinhala, 276 | QLocale::Swati, 277 | QLocale::Somali, 278 | QLocale::Spanish, 279 | QLocale::Swahili, 280 | QLocale::Swedish, 281 | QLocale::Tagalog, 282 | QLocale::Tajik, 283 | QLocale::Tamil, 284 | QLocale::Tatar, 285 | QLocale::Telugu, 286 | QLocale::Tongan, 287 | QLocale::Tsonga, 288 | QLocale::Turkish, 289 | QLocale::Turkmen, 290 | QLocale::Twi, 291 | QLocale::Uigur, 292 | QLocale::Uzbek, 293 | QLocale::Volapuk, 294 | QLocale::Wolof, 295 | QLocale::Xhosa, 296 | QLocale::Yiddish, 297 | QLocale::Zulu, 298 | EOL 299 | }; 300 | static const QLocale::Language frenchStyleLanguages[] = { 301 | // keep synchronized with frenchStyleCountries 302 | QLocale::Breton, 303 | QLocale::French, 304 | QLocale::Portuguese, 305 | // Missing: Filipino, 306 | QLocale::Tigrinya, 307 | // Missing: Walloon 308 | EOL 309 | }; 310 | static const QLocale::Language latvianLanguage[] = { QLocale::Latvian, EOL }; 311 | static const QLocale::Language irishStyleLanguages[] = { 312 | QLocale::Divehi, 313 | QLocale::Gaelic, 314 | QLocale::Inuktitut, 315 | QLocale::Inupiak, 316 | QLocale::Irish, 317 | QLocale::Manx, 318 | QLocale::Maori, 319 | // Missing: Sami, 320 | QLocale::Samoan, 321 | QLocale::Sanskrit, 322 | EOL 323 | }; 324 | static const QLocale::Language czechLanguage[] = { QLocale::Czech, EOL }; 325 | static const QLocale::Language slovakLanguage[] = { QLocale::Slovak, EOL }; 326 | static const QLocale::Language macedonianLanguage[] = { QLocale::Macedonian, EOL }; 327 | static const QLocale::Language lithuanianLanguage[] = { QLocale::Lithuanian, EOL }; 328 | static const QLocale::Language russianStyleLanguages[] = { 329 | QLocale::Bosnian, 330 | QLocale::Byelorussian, 331 | QLocale::Croatian, 332 | QLocale::Russian, 333 | QLocale::Serbian, 334 | QLocale::SerboCroatian, 335 | QLocale::Ukrainian, 336 | EOL 337 | }; 338 | static const QLocale::Language polishLanguage[] = { QLocale::Polish, EOL }; 339 | static const QLocale::Language romanianLanguages[] = { 340 | QLocale::Moldavian, 341 | QLocale::Romanian, 342 | EOL 343 | }; 344 | static const QLocale::Language slovenianLanguage[] = { QLocale::Slovenian, EOL }; 345 | static const QLocale::Language malteseLanguage[] = { QLocale::Maltese, EOL }; 346 | static const QLocale::Language welshLanguage[] = { QLocale::Welsh, EOL }; 347 | static const QLocale::Language arabicLanguage[] = { QLocale::Arabic, EOL }; 348 | 349 | static const QLocale::Country frenchStyleCountries[] = { 350 | // keep synchronized with frenchStyleLanguages 351 | QLocale::AnyCountry, 352 | QLocale::AnyCountry, 353 | QLocale::Brazil, 354 | QLocale::AnyCountry 355 | }; 356 | 357 | struct NumerusTableEntry { 358 | const char * const *forms; 359 | const QLocale::Language *languages; 360 | const QLocale::Country *countries; 361 | }; 362 | 363 | static const NumerusTableEntry numerusTable[] = { 364 | { japaneseStyleForms, japaneseStyleLanguages, 0 }, 365 | { englishStyleForms, englishStyleLanguages, 0 }, 366 | { frenchStyleForms, frenchStyleLanguages, frenchStyleCountries }, 367 | { latvianForms, latvianLanguage, 0 }, 368 | { irishStyleForms, irishStyleLanguages, 0 }, 369 | { czechForms, czechLanguage, 0 }, 370 | { slovakForms, slovakLanguage, 0 }, 371 | { macedonianForms, macedonianLanguage, 0 }, 372 | { lithuanianForms, lithuanianLanguage, 0 }, 373 | { russianStyleForms, russianStyleLanguages, 0 }, 374 | { polishForms, polishLanguage, 0 }, 375 | { romanianForms, romanianLanguages, 0 }, 376 | { slovenianForms, slovenianLanguage, 0 }, 377 | { malteseForms, malteseLanguage, 0 }, 378 | { welshForms, welshLanguage, 0 }, 379 | { arabicForms, arabicLanguage, 0 } 380 | }; 381 | 382 | static const int NumerusTableSize = sizeof(numerusTable) / sizeof(numerusTable[0]); 383 | 384 | bool getNumerusInfo(QLocale::Language language, QLocale::Country country, 385 | QStringList *forms); 386 | 387 | #endif // TRANSLATOR_H 388 | -------------------------------------------------------------------------------- /pyrcc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Qt5Xml) 2 | 3 | add_executable(pyside2-rcc main.cpp rcc.cpp) 4 | include_directories(pyside2-rcc 5 | ${Qt5Xml_INCLUDE_DIRS} 6 | ${Qt5Core_INCLUDE_DIRS}) 7 | 8 | target_link_libraries(pyside2-rcc 9 | ${Qt5Core_LIBRARIES} 10 | ${Qt5Xml_LIBRARIES}) 11 | 12 | install(TARGETS pyside2-rcc RUNTIME DESTINATION bin) 13 | 14 | # Man pages 15 | if (NOT win32) 16 | file(GLOB manpages "${CMAKE_CURRENT_SOURCE_DIR}/*.1") 17 | install(FILES ${manpages} DESTINATION share/man/man1) 18 | endif() 19 | -------------------------------------------------------------------------------- /pyrcc/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2016 The Qt Company Ltd. 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "rcc.h" 36 | 37 | // Some static globals 38 | static QString initName; 39 | static bool verbose = false; 40 | static int py_version = 3; 41 | static int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT; 42 | static int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT; 43 | static QString resourceRoot; 44 | 45 | bool processResourceFile(const QStringList &filenamesIn, const QString &filenameOut, bool list) 46 | { 47 | if (verbose) 48 | fprintf(stderr, "PySide2 resource compiler\n"); 49 | 50 | //setup 51 | RCCResourceLibrary library; 52 | library.setInputFiles(filenamesIn); 53 | library.setInitName(initName); 54 | library.setVerbose(verbose); 55 | library.setPythonVersion(py_version); 56 | library.setCompressLevel(compressLevel); 57 | library.setCompressThreshold(compressThreshold); 58 | library.setResourceRoot(resourceRoot); 59 | if(!library.readFiles()) 60 | return false; 61 | 62 | //open output 63 | FILE *out_fd = stdout; 64 | if (!filenameOut.isEmpty() && filenameOut != QLatin1String("-")) { 65 | #if defined(_MSC_VER) && _MSC_VER >= 1400 66 | if (fopen_s(&out_fd, filenameOut.toLocal8Bit().constData(), "w")) { 67 | #else 68 | out_fd = fopen(filenameOut.toLocal8Bit().constData(), "w"); 69 | if(!out_fd) { 70 | #endif 71 | fprintf(stderr, "Unable to open %s for writing\n", filenameOut.toLatin1().constData()); 72 | return false; 73 | } 74 | } 75 | 76 | //do the task 77 | bool ret = true; 78 | if(list) { 79 | const QStringList data = library.dataFiles(); 80 | for(int i = 0; i < data.size(); ++i) 81 | fprintf(out_fd, "%s\n", QDir::cleanPath(data.at(i)).toLatin1().constData()); 82 | } else { 83 | ret = library.output(out_fd); 84 | } 85 | if(out_fd != stdout) 86 | fclose(out_fd); 87 | 88 | //done 89 | return ret; 90 | } 91 | 92 | int showHelp(const char *argv0, const QString &error) 93 | { 94 | fprintf(stderr, "PySide2 resource compiler\n"); 95 | if (!error.isEmpty()) 96 | fprintf(stderr, "%s: %s\n", argv0, error.toLatin1().constData()); 97 | fprintf(stderr, "Usage: %s [options] \n\n" 98 | "Options:\n" 99 | " -o file Write output to file rather than stdout\n" 100 | " -py2 Generate code for any Python v2.x version\n" 101 | " -py3 Generate code for any Python v3.x version (default)\n" 102 | " -name name Create an external initialization function with name\n" 103 | " -threshold level Threshold to consider compressing files\n" 104 | " -compress level Compress input files by level\n" 105 | " -root path Prefix resource access path with root path\n" 106 | " -no-compress Disable all compression\n" 107 | " -version Display version\n" 108 | " -help Display this information\n", 109 | argv0); 110 | return 1; 111 | } 112 | 113 | int main(int argc, char *argv[]) 114 | { 115 | QString outFilename; 116 | bool helpRequested = false, list = false; 117 | QStringList files; 118 | 119 | //parse options 120 | QString errorMsg; 121 | for (int i = 1; i < argc && errorMsg.isEmpty(); i++) { 122 | if (argv[i][0] == '-') { // option 123 | QByteArray opt = argv[i] + 1; 124 | if (opt == "o") { 125 | if (!(i < argc-1)) { 126 | errorMsg = QLatin1String("Missing output name"); 127 | break; 128 | } 129 | outFilename = argv[++i]; 130 | } else if(opt == "name") { 131 | if (!(i < argc-1)) { 132 | errorMsg = QLatin1String("Missing target name"); 133 | break; 134 | } 135 | initName = argv[++i]; 136 | } else if(opt == "root") { 137 | if (!(i < argc-1)) { 138 | errorMsg = QLatin1String("Missing root path"); 139 | break; 140 | } 141 | resourceRoot = QDir::cleanPath(argv[++i]); 142 | if(resourceRoot.isEmpty() || resourceRoot[0] != '/') 143 | errorMsg = QLatin1String("Root must start with a /"); 144 | } else if(opt == "compress") { 145 | if (!(i < argc-1)) { 146 | errorMsg = QLatin1String("Missing compression level"); 147 | break; 148 | } 149 | compressLevel = QString(argv[++i]).toInt(); 150 | } else if(opt == "threshold") { 151 | if (!(i < argc-1)) { 152 | errorMsg = QLatin1String("Missing compression threshold"); 153 | break; 154 | } 155 | compressThreshold = QString(argv[++i]).toInt(); 156 | } else if(opt == "verbose") { 157 | verbose = true; 158 | } else if(opt == "py2") { 159 | py_version = 2; 160 | } else if(opt == "py3") { 161 | py_version = 3; 162 | } else if(opt == "list") { 163 | list = true; 164 | } else if(opt == "version") { 165 | fprintf(stderr, "Resource Compiler for Qt version %s\n", QT_VERSION_STR); 166 | return 1; 167 | } else if(opt == "help" || opt == "h") { 168 | helpRequested = true; 169 | } else if(opt == "no-compress") { 170 | compressLevel = -2; 171 | } else { 172 | errorMsg = QString(QLatin1String("Unknown option: '%1'")).arg(argv[i]); 173 | } 174 | } else { 175 | if(!QFile::exists(argv[i])) { 176 | qWarning("%s: File does not exist '%s'", argv[0], argv[i]); 177 | return 1; 178 | } 179 | files.append(argv[i]); 180 | } 181 | } 182 | 183 | if (!files.size() || !errorMsg.isEmpty() || helpRequested) 184 | return showHelp(argv[0], errorMsg); 185 | return int(!processResourceFile(files, outFilename, list)); 186 | } 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /pyrcc/pyside2-rcc.1: -------------------------------------------------------------------------------- 1 | .TH PYSIDE\-RCC "1" "December 2010" "pyside2\-rcc" "User Commands" 2 | .SH NAME 3 | pyside2\-rcc \- PySide2 resource compiler 4 | .SH DESCRIPTION 5 | .SS "Usage:" 6 | .IP 7 | pyside2\-rcc [options] 8 | .SS "Options:" 9 | .TP 10 | \fB\-o\fR file 11 | Write output to file rather than stdout 12 | .TP 13 | \fB\-py2\fR 14 | Generate code for any Python v2.x version (default) 15 | .TP 16 | \fB\-py3\fR 17 | Generate code for any Python v3.x version 18 | .TP 19 | \fB\-name\fR name 20 | Create an external initialization function with name 21 | .TP 22 | \fB\-threshold\fR level 23 | Threshold to consider compressing files 24 | .TP 25 | \fB\-compress\fR level 26 | Compress input files by level 27 | .TP 28 | \fB\-root\fR path 29 | Prefix resource access path with root path 30 | .TP 31 | \fB\-no\-compress 32 | Disable all compression 33 | .TP 34 | \fB\-version 35 | Display version 36 | .TP 37 | \fB\-help 38 | Display this information 39 | .SH COPYRIGHT 40 | Copyright \(co 2010 Nokia Corporation and/or its subsidiary(\fB\-ies\fR) 41 | .SH AUTHOR 42 | .PP 43 | This manpage was written by Marcelo Lira , on the 29. December 2010. 44 | -------------------------------------------------------------------------------- /pyrcc/rcc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the PySide Tools project. 3 | * 4 | * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. 5 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 6 | * 7 | * Contact: PySide team 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | * 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef RCC_H 26 | #define RCC_H 27 | 28 | #define TAG_RCC "RCC" 29 | #define TAG_RESOURCE "qresource" 30 | #define TAG_FILE "file" 31 | 32 | #define ATTRIBUTE_LANG "lang" 33 | #define ATTRIBUTE_PREFIX "prefix" 34 | #define ATTRIBUTE_ALIAS "alias" 35 | #define ATTRIBUTE_THRESHOLD "threshold" 36 | #define ATTRIBUTE_COMPRESS "compress" 37 | 38 | 39 | #define CONSTANT_HEADER_SIZE 8 40 | #define CONSTANT_COMPRESSLEVEL_DEFAULT 0 41 | #define CONSTANT_COMPRESSTHRESHOLD_DEFAULT 70 42 | 43 | struct RCCFileInfo; 44 | 45 | class RCCResourceLibrary 46 | { 47 | public: 48 | inline RCCResourceLibrary(); 49 | ~RCCResourceLibrary(); 50 | 51 | bool output(FILE *out); 52 | 53 | bool readFiles(); 54 | 55 | inline void setInputFiles(QStringList files) { mFileNames = files; } 56 | inline QStringList inputFiles() const { return mFileNames; } 57 | 58 | QStringList dataFiles() const; 59 | 60 | inline void setVerbose(bool b) { mVerbose = b; } 61 | inline bool verbose() const { return mVerbose; } 62 | 63 | inline void setPythonVersion(int v) { mPrefix = (v == 2 ? "" : "b"); } 64 | 65 | inline void setInitName(const QString &n) { mInitName = n; } 66 | inline QString initName() const { return mInitName; } 67 | 68 | inline void setCompressLevel(int c) { mCompressLevel = c; } 69 | inline int compressLevel() const { return mCompressLevel; } 70 | 71 | inline void setCompressThreshold(int t) { mCompressThreshold = t; } 72 | inline int compressThreshold() const { return mCompressThreshold; } 73 | 74 | inline void setResourceRoot(QString str) { mResourceRoot = str; } 75 | inline QString resourceRoot() const { return mResourceRoot; } 76 | 77 | private: 78 | RCCFileInfo *root; 79 | bool addFile(const QString &alias, const RCCFileInfo &file); 80 | bool interpretResourceFile(QIODevice *inputDevice, QString file, QString currentPath = QString()); 81 | 82 | bool writeHeader(FILE *out); 83 | bool writeDataBlobs(FILE *out); 84 | bool writeDataNames(FILE *out); 85 | bool writeDataStructure(FILE *out); 86 | bool writeInitializer(FILE *out); 87 | 88 | QStringList mFileNames; 89 | QString mResourceRoot, mInitName; 90 | bool mVerbose; 91 | int mCompressLevel; 92 | int mCompressThreshold; 93 | int mTreeOffset, mNamesOffset, mDataOffset; 94 | const char *mPrefix; 95 | }; 96 | 97 | inline RCCResourceLibrary::RCCResourceLibrary() 98 | { 99 | root = 0; 100 | mVerbose = false; 101 | mCompressLevel = -1; 102 | mCompressThreshold = 70; 103 | mTreeOffset = mNamesOffset = mDataOffset = 0; 104 | } 105 | 106 | struct RCCFileInfo 107 | { 108 | enum Flags 109 | { 110 | NoFlags = 0x00, 111 | Compressed = 0x01, 112 | Directory = 0x02 113 | }; 114 | 115 | inline RCCFileInfo(QString name = QString(), QFileInfo fileInfo = QFileInfo(), 116 | QLocale locale = QLocale(), uint flags = NoFlags, 117 | int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT, int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT); 118 | ~RCCFileInfo() { qDeleteAll(children); } 119 | inline QString resourceName() { 120 | QString resource = name; 121 | for(RCCFileInfo *p = parent; p; p = p->parent) 122 | resource = resource.prepend(p->name + "/"); 123 | return ":" + resource; 124 | } 125 | 126 | int flags; 127 | QString name; 128 | QLocale locale; 129 | QFileInfo fileInfo; 130 | RCCFileInfo *parent; 131 | QHash children; 132 | int mCompressLevel; 133 | int mCompressThreshold; 134 | 135 | qint64 nameOffset, dataOffset, childOffset; 136 | qint64 writeDataBlob(FILE *out, qint64 offset); 137 | qint64 writeDataName(FILE *out, qint64 offset); 138 | bool writeDataInfo(FILE *out); 139 | }; 140 | 141 | inline RCCFileInfo::RCCFileInfo(QString name, QFileInfo fileInfo, QLocale locale, uint flags, 142 | int compressLevel, int compressThreshold) 143 | { 144 | this->name = name; 145 | this->fileInfo = fileInfo; 146 | this->locale = locale; 147 | this->flags = flags; 148 | this->parent = 0; 149 | this->nameOffset = this->dataOffset = this->childOffset = 0; 150 | this->mCompressLevel = compressLevel; 151 | this->mCompressThreshold = compressThreshold; 152 | } 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /pyside2-uic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This file is part of the PySide project. 3 | # 4 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 5 | # Copyright (C) 2010 Riverbank Computing Limited. 6 | # Copyright (C) 2009 Torsten Marek 7 | # 8 | # Contact: PySide team 9 | # 10 | # This program is free software; you can redistribute it and/or 11 | # modify it under the terms of the GNU General Public License 12 | # version 2 as published by the Free Software Foundation. 13 | # 14 | # This program is distributed in the hope that it will be useful, but 15 | # WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | # General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | # 02110-1301 USA 23 | 24 | import sys 25 | import optparse 26 | 27 | from PySide2 import QtCore 28 | from pyside2uic.driver import Driver 29 | from PySide2 import __version__ as PySideVersion 30 | from pyside2uic import __version__ as PySideUicVersion 31 | 32 | Version = "PySide2 User Interface Compiler version %s, running on PySide2 %s." % (PySideUicVersion, PySideVersion) 33 | 34 | def main(): 35 | if sys.hexversion >= 0x03000000: 36 | from pyside2uic.port_v3.invoke import invoke 37 | else: 38 | from pyside2uic.port_v2.invoke import invoke 39 | 40 | parser = optparse.OptionParser(usage="pyside2-uic [options] ", 41 | version=Version) 42 | parser.add_option("-p", "--preview", dest="preview", action="store_true", 43 | default=False, 44 | help="show a preview of the UI instead of generating code") 45 | parser.add_option("-o", "--output", dest="output", default="-", metavar="FILE", 46 | help="write generated code to FILE instead of stdout") 47 | parser.add_option("-x", "--execute", dest="execute", action="store_true", 48 | default=False, 49 | help="generate extra code to test and display the class") 50 | parser.add_option("-d", "--debug", dest="debug", action="store_true", 51 | default=False, help="show debug output") 52 | parser.add_option("-i", "--indent", dest="indent", action="store", type="int", 53 | default=4, metavar="N", 54 | help="set indent width to N spaces, tab if N is 0 (default: 4)") 55 | 56 | g = optparse.OptionGroup(parser, title="Code generation options") 57 | g.add_option("--from-imports", dest="from_imports", action="store_true", 58 | default=False, help="generate imports relative to '.'") 59 | parser.add_option_group(g) 60 | 61 | opts, args = parser.parse_args() 62 | 63 | if len(args) != 1: 64 | sys.stderr.write("Error: one input ui-file must be specified\n") 65 | sys.exit(1) 66 | 67 | sys.exit(invoke(Driver(opts, args[0]))) 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2009 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/compiler.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | import sys 24 | 25 | from pyside2uic.properties import Properties 26 | from pyside2uic.uiparser import UIParser 27 | from pyside2uic.Compiler import qtproxies 28 | from pyside2uic.Compiler.indenter import createCodeIndenter, getIndenter, \ 29 | write_code 30 | from pyside2uic.Compiler.qobjectcreator import CompilerCreatorPolicy 31 | from pyside2uic.Compiler.misc import write_import 32 | 33 | 34 | class UICompiler(UIParser): 35 | def __init__(self): 36 | UIParser.__init__(self, qtproxies.QtCore, qtproxies.QtGui, qtproxies.QtWidgets, 37 | CompilerCreatorPolicy()) 38 | 39 | def reset(self): 40 | qtproxies.i18n_strings = [] 41 | UIParser.reset(self) 42 | 43 | def setContext(self, context): 44 | qtproxies.i18n_context = context 45 | 46 | def createToplevelWidget(self, classname, widgetname): 47 | indenter = getIndenter() 48 | indenter.level = 0 49 | 50 | indenter.write("from PySide2 import QtCore, QtGui, QtWidgets") 51 | indenter.write("") 52 | 53 | indenter.write("class Ui_%s(object):" % self.uiname) 54 | indenter.indent() 55 | indenter.write("def setupUi(self, %s):" % widgetname) 56 | indenter.indent() 57 | w = self.factory.createQObject(classname, widgetname, (), 58 | is_attribute = False, 59 | no_instantiation = True) 60 | w.baseclass = classname 61 | w.uiclass = "Ui_%s" % self.uiname 62 | return w 63 | 64 | def setDelayedProps(self): 65 | write_code("") 66 | write_code("self.retranslateUi(%s)" % self.toplevelWidget) 67 | UIParser.setDelayedProps(self) 68 | 69 | def finalize(self): 70 | indenter = getIndenter() 71 | indenter.level = 1 72 | indenter.write("") 73 | indenter.write("def retranslateUi(self, %s):" % self.toplevelWidget) 74 | indenter.indent() 75 | 76 | if qtproxies.i18n_strings: 77 | for s in qtproxies.i18n_strings: 78 | indenter.write(s) 79 | else: 80 | indenter.write("pass") 81 | 82 | indenter.dedent() 83 | indenter.dedent() 84 | 85 | # Make a copy of the resource modules to import because the parser will 86 | # reset() before returning. 87 | self._resources = self.resources 88 | 89 | def compileUi(self, input_stream, output_stream, from_imports): 90 | createCodeIndenter(output_stream) 91 | w = self.parse(input_stream) 92 | 93 | indenter = getIndenter() 94 | indenter.write("") 95 | 96 | self.factory._cpolicy._writeOutImports() 97 | 98 | for res in self._resources: 99 | write_import(res, from_imports) 100 | 101 | return {"widgetname": str(w), 102 | "uiclass" : w.uiclass, 103 | "baseclass" : w.baseclass} 104 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/indenter.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2009 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | indentwidth = 4 24 | 25 | _indenter = None 26 | 27 | class _IndentedCodeWriter(object): 28 | def __init__(self, output): 29 | self.level = 0 30 | self.output = output 31 | 32 | def indent(self): 33 | self.level += 1 34 | 35 | def dedent(self): 36 | self.level -= 1 37 | 38 | def write(self, line): 39 | if line.strip(): 40 | if indentwidth > 0: 41 | indent = " " * indentwidth 42 | line = line.replace("\t", indent) 43 | else: 44 | indent = "\t" 45 | 46 | self.output.write("%s%s\n" % (indent * self.level, line)) 47 | else: 48 | self.output.write("\n") 49 | 50 | 51 | def createCodeIndenter(output): 52 | global _indenter 53 | _indenter = _IndentedCodeWriter(output) 54 | 55 | def getIndenter(): 56 | return _indenter 57 | 58 | def write_code(string): 59 | _indenter.write(string) 60 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/misc.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | 24 | from pyside2uic.Compiler.indenter import write_code 25 | 26 | 27 | def write_import(module_name, from_imports): 28 | if from_imports: 29 | write_code("from . import %s" % module_name) 30 | else: 31 | write_code("import %s" % module_name) 32 | 33 | 34 | def moduleMember(module, name): 35 | if module: 36 | return "%s.%s" % (module, name) 37 | 38 | return name 39 | 40 | 41 | class Literal(object): 42 | """Literal(string) -> new literal 43 | 44 | string will not be quoted when put into an argument list""" 45 | def __init__(self, string): 46 | self.string = string 47 | 48 | def __str__(self): 49 | return self.string 50 | 51 | def __or__(self, r_op): 52 | return Literal("%s|%s" % (self, r_op)) 53 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/proxy_type.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.Compiler.misc import Literal, moduleMember 24 | 25 | 26 | class ProxyType(type): 27 | def __init__(*args): 28 | type.__init__(*args) 29 | for cls in args[0].__dict__.values(): 30 | if type(cls) is ProxyType: 31 | cls.module = args[0].__name__ 32 | 33 | if not hasattr(args[0], "module"): 34 | args[0].module = "" 35 | 36 | def __getattribute__(cls, name): 37 | try: 38 | return type.__getattribute__(cls, name) 39 | except AttributeError: 40 | # Handle internal (ie. non-PySide) attributes as normal. 41 | if name == "module": 42 | raise 43 | 44 | # Avoid a circular import. 45 | from pyside2uic.Compiler.qtproxies import LiteralProxyClass 46 | 47 | return type(name, (LiteralProxyClass, ), 48 | {"module": moduleMember(type.__getattribute__(cls, "module"), 49 | type.__getattribute__(cls, "__name__"))}) 50 | 51 | def __str__(cls): 52 | return moduleMember(type.__getattribute__(cls, "module"), 53 | type.__getattribute__(cls, "__name__")) 54 | 55 | def __or__(self, r_op): 56 | return Literal("%s|%s" % (self, r_op)) 57 | 58 | def __eq__(self, other): 59 | return str(self) == str(other) 60 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/qobjectcreator.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | 24 | import logging 25 | 26 | try: 27 | set() 28 | except NameError: 29 | from sets import Set as set 30 | 31 | from pyside2uic.Compiler.indenter import write_code 32 | from pyside2uic.Compiler.qtproxies import (QtWidgets, QtGui, Literal, 33 | strict_getattr) 34 | 35 | 36 | logger = logging.getLogger(__name__) 37 | DEBUG = logger.debug 38 | 39 | 40 | class _QtGuiWrapper(object): 41 | def search(clsname): 42 | try: 43 | return strict_getattr(QtGui, clsname) 44 | except AttributeError: 45 | return None 46 | 47 | search = staticmethod(search) 48 | 49 | 50 | class _QtWidgetsWrapper(object): 51 | def search(clsname): 52 | try: 53 | return strict_getattr(QtWidgets, clsname) 54 | except AttributeError: 55 | return None 56 | 57 | search = staticmethod(search) 58 | 59 | 60 | class _ModuleWrapper(object): 61 | def __init__(self, name, classes): 62 | if "." in name: 63 | idx = name.rfind(".") 64 | self._package = name[:idx] 65 | self._module = name[idx + 1:] 66 | else: 67 | self._package = None 68 | self._module = name 69 | 70 | self._classes = set(classes) 71 | self._used = False 72 | 73 | def search(self, cls): 74 | if cls in self._classes: 75 | self._used = True 76 | return type(cls, (QtWidgets.QWidget,), {"module": self._module}) 77 | else: 78 | return None 79 | 80 | def _writeImportCode(self): 81 | if self._used: 82 | if self._package is None: 83 | write_code("import %s" % self._module) 84 | else: 85 | write_code("from %s import %s" % (self._package, self._module)) 86 | 87 | 88 | class _CustomWidgetLoader(object): 89 | def __init__(self): 90 | self._widgets = {} 91 | self._usedWidgets = set() 92 | 93 | def addCustomWidget(self, widgetClass, baseClass, module): 94 | assert widgetClass not in self._widgets 95 | self._widgets[widgetClass] = (baseClass, module) 96 | 97 | 98 | def _resolveBaseclass(self, baseClass): 99 | try: 100 | for x in range(0, 10): 101 | try: return strict_getattr(QtWidgets, baseClass) 102 | except AttributeError: pass 103 | 104 | baseClass = self._widgets[baseClass][0] 105 | else: 106 | raise ValueError("baseclass resolve took too long, check custom widgets") 107 | 108 | except KeyError: 109 | raise ValueError("unknown baseclass %s" % baseClass) 110 | 111 | 112 | def search(self, cls): 113 | try: 114 | self._usedWidgets.add(cls) 115 | baseClass = self._resolveBaseclass(self._widgets[cls][0]) 116 | DEBUG("resolved baseclass of %s: %s" % (cls, baseClass)) 117 | 118 | return type(cls, (baseClass,), 119 | {"module" : ""}) 120 | 121 | except KeyError: 122 | return None 123 | 124 | def _writeImportCode(self): 125 | imports = {} 126 | for widget in self._usedWidgets: 127 | _, module = self._widgets[widget] 128 | imports.setdefault(module, []).append(widget) 129 | 130 | for module, classes in imports.items(): 131 | write_code("from %s import %s" % (module, ", ".join(classes))) 132 | 133 | 134 | class CompilerCreatorPolicy(object): 135 | def __init__(self): 136 | self._modules = [] 137 | 138 | def createQtGuiWrapper(self): 139 | return _QtGuiWrapper 140 | 141 | def createQtWidgetsWrapper(self): 142 | return _QtWidgetsWrapper 143 | 144 | def createModuleWrapper(self, name, classes): 145 | mw = _ModuleWrapper(name, classes) 146 | self._modules.append(mw) 147 | return mw 148 | 149 | def createCustomWidgetLoader(self): 150 | cw = _CustomWidgetLoader() 151 | self._modules.append(cw) 152 | return cw 153 | 154 | def instantiate(self, clsObject, objectname, ctor_args, is_attribute=True, no_instantiation=False): 155 | return clsObject(objectname, is_attribute, ctor_args, no_instantiation) 156 | 157 | def invoke(self, rname, method, args): 158 | return method(rname, *args) 159 | 160 | def getSlot(self, object, slotname): 161 | return Literal("%s.%s" % (object, slotname)) 162 | 163 | def _writeOutImports(self): 164 | for module in self._modules: 165 | module._writeImportCode() 166 | -------------------------------------------------------------------------------- /pyside2uic/Compiler/qtproxies.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | 24 | import sys 25 | import re 26 | 27 | from pyside2uic.Compiler.indenter import write_code 28 | from pyside2uic.Compiler.misc import Literal, moduleMember 29 | 30 | if sys.hexversion >= 0x03000000: 31 | from pyside2uic.port_v3.proxy_base import ProxyBase 32 | from pyside2uic.port_v3.as_string import as_string 33 | else: 34 | from pyside2uic.port_v2.proxy_base import ProxyBase 35 | from pyside2uic.port_v2.as_string import as_string 36 | 37 | i18n_strings = [] 38 | i18n_context = "" 39 | 40 | def i18n_print(string): 41 | i18n_strings.append(string) 42 | 43 | def i18n_void_func(name): 44 | def _printer(self, *args): 45 | i18n_print("%s.%s(%s)" % (self, name, ", ".join(map(as_string, args)))) 46 | return _printer 47 | 48 | def i18n_func(name): 49 | def _printer(self, rname, *args): 50 | i18n_print("%s = %s.%s(%s)" % (rname, self, name, ", ".join(map(as_string, args)))) 51 | return Literal(rname) 52 | 53 | return _printer 54 | 55 | def strict_getattr(module, clsname): 56 | cls = getattr(module, clsname) 57 | if issubclass(cls, LiteralProxyClass): 58 | raise AttributeError(cls) 59 | else: 60 | return cls 61 | 62 | 63 | class i18n_string(object): 64 | def __init__(self, string, disambig): 65 | self.string = string 66 | self.disambig = disambig 67 | 68 | def __str__(self): 69 | if self.disambig is None: 70 | disambig = "None" 71 | else: 72 | disambig = as_string(self.disambig, encode=False) 73 | 74 | return 'QtWidgets.QApplication.translate("%s", %s, %s, -1)' % (i18n_context, as_string(self.string, encode=False), disambig) 75 | 76 | 77 | # Classes with this flag will be handled as literal values. If functions are 78 | # called on these classes, the literal value changes. 79 | # Example: 80 | # the code 81 | # >>> QSize(9,10).expandedTo(...) 82 | # will print just that code. 83 | AS_ARGUMENT = 2 84 | 85 | # ATTENTION: currently, classes can either be literal or normal. If a class 86 | # should need both kinds of behaviour, the code has to be changed. 87 | 88 | class ProxyClassMember(object): 89 | def __init__(self, proxy, function_name, flags): 90 | self.proxy = proxy 91 | self.function_name = function_name 92 | self.flags = flags 93 | 94 | def __str__(self): 95 | return "%s.%s" % (self.proxy, self.function_name) 96 | 97 | def __call__(self, *args): 98 | func_call = "%s.%s(%s)" % (self.proxy, 99 | self.function_name, 100 | ", ".join(map(as_string, args))) 101 | if self.flags & AS_ARGUMENT: 102 | self.proxy._uic_name = func_call 103 | return self.proxy 104 | else: 105 | needs_translation = False 106 | for arg in args: 107 | if isinstance(arg, i18n_string): 108 | needs_translation = True 109 | if needs_translation: 110 | i18n_print(func_call) 111 | else: 112 | write_code(func_call) 113 | 114 | 115 | class ProxyClass(ProxyBase): 116 | flags = 0 117 | 118 | def __init__(self, objectname, is_attribute, args=(), noInstantiation=False): 119 | if objectname: 120 | if is_attribute: 121 | objectname = "self." + objectname 122 | 123 | self._uic_name = objectname 124 | else: 125 | self._uic_name = "Unnamed" 126 | 127 | if not noInstantiation: 128 | funcall = "%s(%s)" % \ 129 | (moduleMember(self.module, self.__class__.__name__), 130 | ", ".join(map(str, args))) 131 | 132 | if objectname: 133 | funcall = "%s = %s" % (objectname, funcall) 134 | 135 | write_code(funcall) 136 | 137 | def __str__(self): 138 | return self._uic_name 139 | 140 | def __getattribute__(self, attribute): 141 | try: 142 | return object.__getattribute__(self, attribute) 143 | except AttributeError: 144 | return ProxyClassMember(self, attribute, self.flags) 145 | 146 | 147 | class LiteralProxyClass(ProxyClass): 148 | """LiteralObject(*args) -> new literal class 149 | 150 | a literal class can be used as argument in a function call 151 | 152 | >>> class Foo(LiteralProxyClass): pass 153 | >>> str(Foo(1,2,3)) == "Foo(1,2,3)" 154 | """ 155 | flags = AS_ARGUMENT 156 | def __init__(self, *args): 157 | self._uic_name = "%s(%s)" % \ 158 | (moduleMember(self.module, self.__class__.__name__), 159 | ", ".join(map(as_string, args))) 160 | 161 | 162 | class ProxyNamespace(ProxyBase): 163 | pass 164 | 165 | 166 | # These are all the Qt classes used by pyuic4 in their namespaces. If a class 167 | # is missing, the compiler will fail, normally with an AttributeError. 168 | # 169 | # For adding new classes: 170 | # - utility classes used as literal values do not need to be listed 171 | # because they are created on the fly as subclasses of LiteralProxyClass 172 | # - classes which are *not* QWidgets inherit from ProxyClass and they 173 | # have to be listed explicitly in the correct namespace. These classes 174 | # are created via a ProxyQObjectCreator 175 | # - new QWidget-derived classes have to inherit from qtproxies.QWidget 176 | # If the widget does not need any special methods, it can be listed 177 | # in _qwidgets 178 | 179 | class QtCore(ProxyNamespace): 180 | class Qt(ProxyNamespace): 181 | pass 182 | 183 | ## connectSlotsByName and connect have to be handled as class methods, 184 | ## otherwise they would be created as LiteralProxyClasses and never be 185 | ## printed 186 | class QMetaObject(ProxyClass): 187 | def connectSlotsByName(cls, *args): 188 | ProxyClassMember(cls, "connectSlotsByName", 0)(*args) 189 | connectSlotsByName = classmethod(connectSlotsByName) 190 | 191 | 192 | class QObject(ProxyClass): 193 | def metaObject(self): 194 | class _FakeMetaObject(object): 195 | def className(*args): 196 | return self.__class__.__name__ 197 | return _FakeMetaObject() 198 | 199 | def objectName(self): 200 | return self._uic_name.split(".")[-1] 201 | 202 | def connect(cls, *args): 203 | # Handle slots that have names corresponding to Python keywords. 204 | slot_name = str(args[-1]) 205 | if slot_name.endswith('.raise'): 206 | args = list(args[:-1]) 207 | args.append(Literal(slot_name + '_')) 208 | 209 | ProxyClassMember(cls, "connect", 0)(*args) 210 | connect = classmethod(connect) 211 | 212 | class QtGui(ProxyNamespace): 213 | class QIcon(ProxyClass): pass 214 | class QConicalGradient(ProxyClass): pass 215 | class QLinearGradient(ProxyClass): pass 216 | class QRadialGradient(ProxyClass): pass 217 | class QBrush(ProxyClass): pass 218 | class QPainter(ProxyClass): pass 219 | class QPalette(ProxyClass): pass 220 | class QFont(ProxyClass): pass 221 | 222 | # These sub-class QWidget but aren't themselves sub-classed. 223 | _qwidgets = ("QCalendarWidget", "QDialogButtonBox", "QDockWidget", "QGroupBox", 224 | "QLineEdit", "QMainWindow", "QMenuBar", "QProgressBar", "QStatusBar", 225 | "QToolBar", "QWizardPage") 226 | 227 | class QtWidgets(ProxyNamespace): 228 | class QApplication(QtCore.QObject): 229 | def translate(uiname, text, disambig, encoding): 230 | return i18n_string(text or "", disambig) 231 | translate = staticmethod(translate) 232 | 233 | class QSpacerItem(ProxyClass): pass 234 | class QSizePolicy(ProxyClass): pass 235 | ## QActions inherit from QObject for the metaobject stuff 236 | ## and the hierarchy has to be correct since we have a 237 | ## isinstance(x, QtWidgets.QLayout) call in the ui parser 238 | class QAction(QtCore.QObject): pass 239 | class QActionGroup(QtCore.QObject): pass 240 | class QButtonGroup(QtCore.QObject): pass 241 | class QLayout(QtCore.QObject): 242 | def setMargin(self, v): 243 | ProxyClassMember(self, "setContentsMargins", 0)(v, v, v, v); 244 | 245 | class QGridLayout(QLayout): pass 246 | class QBoxLayout(QLayout): pass 247 | class QHBoxLayout(QBoxLayout): pass 248 | class QVBoxLayout(QBoxLayout): pass 249 | class QFormLayout(QLayout): pass 250 | 251 | class QWidget(QtCore.QObject): 252 | def font(self): 253 | return Literal("%s.font()" % self) 254 | 255 | def minimumSizeHint(self): 256 | return Literal("%s.minimumSizeHint()" % self) 257 | 258 | def sizePolicy(self): 259 | sp = LiteralProxyClass() 260 | sp._uic_name = "%s.sizePolicy()" % self 261 | return sp 262 | 263 | class QDialog(QWidget): pass 264 | class QWizard(QDialog): pass 265 | 266 | class QAbstractSlider(QWidget): pass 267 | class QDial(QAbstractSlider): pass 268 | class QScrollBar(QAbstractSlider): pass 269 | class QSlider(QAbstractSlider): pass 270 | 271 | class QMenu(QWidget): 272 | def menuAction(self): 273 | return Literal("%s.menuAction()" % self) 274 | 275 | class QTabWidget(QWidget): 276 | def addTab(self, *args): 277 | text = args[-1] 278 | 279 | if isinstance(text, i18n_string): 280 | i18n_print("%s.setTabText(%s.indexOf(%s), %s)" % \ 281 | (self._uic_name, self._uic_name, args[0], text)) 282 | args = args[:-1] + ("", ) 283 | 284 | ProxyClassMember(self, "addTab", 0)(*args) 285 | 286 | def indexOf(self, page): 287 | return Literal("%s.indexOf(%s)" % (self, page)) 288 | 289 | class QComboBox(QWidget): pass 290 | class QFontComboBox(QComboBox): pass 291 | 292 | class QAbstractSpinBox(QWidget): pass 293 | class QDoubleSpinBox(QAbstractSpinBox): pass 294 | class QSpinBox(QAbstractSpinBox): pass 295 | 296 | class QDateTimeEdit(QAbstractSpinBox): pass 297 | class QDateEdit(QDateTimeEdit): pass 298 | class QTimeEdit(QDateTimeEdit): pass 299 | 300 | class QFrame(QWidget): pass 301 | class QLabel(QFrame): pass 302 | class QLCDNumber(QFrame): pass 303 | class QSplitter(QFrame): pass 304 | class QStackedWidget(QFrame): pass 305 | 306 | class QToolBox(QFrame): 307 | def addItem(self, *args): 308 | text = args[-1] 309 | 310 | if isinstance(text, i18n_string): 311 | i18n_print("%s.setItemText(%s.indexOf(%s), %s)" % \ 312 | (self._uic_name, self._uic_name, args[0], text)) 313 | args = args[:-1] + ("", ) 314 | 315 | ProxyClassMember(self, "addItem", 0)(*args) 316 | 317 | def indexOf(self, page): 318 | return Literal("%s.indexOf(%s)" % (self, page)) 319 | 320 | def layout(self): 321 | return QtWidgets.QLayout("%s.layout()" % self, 322 | False, (), noInstantiation=True) 323 | 324 | class QAbstractScrollArea(QFrame): pass 325 | class QGraphicsView(QAbstractScrollArea): pass 326 | class QMdiArea(QAbstractScrollArea): pass 327 | class QPlainTextEdit(QAbstractScrollArea): pass 328 | class QScrollArea(QAbstractScrollArea): pass 329 | 330 | class QTextEdit(QAbstractScrollArea): pass 331 | class QTextBrowser(QTextEdit): pass 332 | 333 | class QAbstractItemView(QAbstractScrollArea): pass 334 | class QColumnView(QAbstractItemView): pass 335 | class QHeaderView(QAbstractItemView): pass 336 | class QListView(QAbstractItemView): pass 337 | 338 | class QTableView(QAbstractItemView): 339 | def horizontalHeader(self): 340 | return QtWidgets.QHeaderView("%s.horizontalHeader()" % self, 341 | False, (), noInstantiation=True) 342 | 343 | def verticalHeader(self): 344 | return QtWidgets.QHeaderView("%s.verticalHeader()" % self, 345 | False, (), noInstantiation=True) 346 | 347 | class QTreeView(QAbstractItemView): 348 | def header(self): 349 | return QtWidgets.QHeaderView("%s.header()" % self, 350 | False, (), noInstantiation=True) 351 | 352 | class QListWidgetItem(ProxyClass): pass 353 | 354 | class QListWidget(QListView): 355 | isSortingEnabled = i18n_func("isSortingEnabled") 356 | setSortingEnabled = i18n_void_func("setSortingEnabled") 357 | 358 | def item(self, row): 359 | return QtWidgets.QListWidgetItem("%s.item(%i)" % (self, row), False, 360 | (), noInstantiation=True) 361 | 362 | class QTableWidgetItem(ProxyClass): pass 363 | 364 | class QTableWidget(QTableView): 365 | isSortingEnabled = i18n_func("isSortingEnabled") 366 | setSortingEnabled = i18n_void_func("setSortingEnabled") 367 | 368 | def item(self, row, col): 369 | return QtWidgets.QTableWidgetItem("%s.item(%i, %i)" % (self, row, col), 370 | False, (), noInstantiation=True) 371 | 372 | def horizontalHeaderItem(self, col): 373 | return QtWidgets.QTableWidgetItem("%s.horizontalHeaderItem(%i)" % (self, col), 374 | False, (), noInstantiation=True) 375 | 376 | def verticalHeaderItem(self, row): 377 | return QtWidgets.QTableWidgetItem("%s.verticalHeaderItem(%i)" % (self, row), 378 | False, (), noInstantiation=True) 379 | 380 | class QTreeWidgetItem(ProxyClass): 381 | def child(self, index): 382 | return QtWidgets.QTreeWidgetItem("%s.child(%i)" % (self, index), 383 | False, (), noInstantiation=True) 384 | 385 | class QTreeWidget(QTreeView): 386 | isSortingEnabled = i18n_func("isSortingEnabled") 387 | setSortingEnabled = i18n_void_func("setSortingEnabled") 388 | 389 | def headerItem(self): 390 | return QtWidgets.QWidget("%s.headerItem()" % self, False, (), 391 | noInstantiation=True) 392 | 393 | def topLevelItem(self, index): 394 | return QtWidgets.QTreeWidgetItem("%s.topLevelItem(%i)" % (self, index), 395 | False, (), noInstantiation=True) 396 | 397 | class QAbstractButton(QWidget): pass 398 | class QCheckBox(QAbstractButton): pass 399 | class QRadioButton(QAbstractButton): pass 400 | class QToolButton(QAbstractButton): pass 401 | 402 | class QPushButton(QAbstractButton): pass 403 | class QCommandLinkButton(QPushButton): pass 404 | 405 | # Add all remaining classes. 406 | for _class in _qwidgets: 407 | if _class not in locals(): 408 | locals()[_class] = type(_class, (QWidget, ), {}) 409 | -------------------------------------------------------------------------------- /pyside2uic/__init__.py.in: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | __all__ = ("compileUi", "compileUiDir", "widgetPluginPath") 24 | 25 | __version__ = "@pyside_tools_VERSION@" 26 | 27 | from pyside2uic.Compiler import indenter, compiler 28 | 29 | _header = """# -*- coding: utf-8 -*- 30 | 31 | # Form implementation generated from reading ui file '%s' 32 | # 33 | # Created: %s 34 | # by: pyside2-uic %s running on PySide2 %s 35 | # 36 | # WARNING! All changes made in this file will be lost! 37 | 38 | """ 39 | 40 | _display_code = """ 41 | if __name__ == "__main__": 42 | \timport sys 43 | \tapp = QtWidgets.QApplication(sys.argv) 44 | \t%(widgetname)s = QtWidgets.%(baseclass)s() 45 | \tui = %(uiclass)s() 46 | \tui.setupUi(%(widgetname)s) 47 | \t%(widgetname)s.show() 48 | \tsys.exit(app.exec_()) 49 | """ 50 | 51 | 52 | def compileUiDir(dir, recurse=False, map=None, **compileUi_args): 53 | """compileUiDir(dir, recurse=False, map=None, **compileUi_args) 54 | 55 | Creates Python modules from Qt Designer .ui files in a directory or 56 | directory tree. 57 | 58 | dir is the name of the directory to scan for files whose name ends with 59 | '.ui'. By default the generated Python module is created in the same 60 | directory ending with '.py'. 61 | recurse is set if any sub-directories should be scanned. The default is 62 | False. 63 | map is an optional callable that is passed the name of the directory 64 | containing the '.ui' file and the name of the Python module that will be 65 | created. The callable should return a tuple of the name of the directory 66 | in which the Python module will be created and the (possibly modified) 67 | name of the module. The default is None. 68 | compileUi_args are any additional keyword arguments that are passed to 69 | the compileUi() function that is called to create each Python module. 70 | """ 71 | 72 | import os 73 | 74 | # Compile a single .ui file. 75 | def compile_ui(ui_dir, ui_file): 76 | # Ignore if it doesn't seem to be a .ui file. 77 | if ui_file.endswith('.ui'): 78 | py_dir = ui_dir 79 | py_file = ui_file[:-3] + '.py' 80 | 81 | # Allow the caller to change the name of the .py file or generate 82 | # it in a different directory. 83 | if map is not None: 84 | py_dir, py_file = map(py_dir, py_file) 85 | 86 | # Make sure the destination directory exists. 87 | try: 88 | os.makedirs(py_dir) 89 | except: 90 | pass 91 | 92 | ui_path = os.path.join(ui_dir, ui_file) 93 | py_path = os.path.join(py_dir, py_file) 94 | 95 | ui_file = open(ui_path, 'r') 96 | py_file = open(py_path, 'w') 97 | 98 | try: 99 | compileUi(ui_file, py_file, **compileUi_args) 100 | finally: 101 | ui_file.close() 102 | py_file.close() 103 | 104 | if recurse: 105 | for root, _, files in os.walk(dir): 106 | for ui in files: 107 | compile_ui(root, ui) 108 | else: 109 | for ui in os.listdir(dir): 110 | if os.path.isfile(os.path.join(dir, ui)): 111 | compile_ui(dir, ui) 112 | 113 | 114 | def compileUi(uifile, pyfile, execute=False, indent=4, from_imports=False): 115 | """compileUi(uifile, pyfile, execute=False, indent=4, from_imports=False) 116 | 117 | Creates a Python module from a Qt Designer .ui file. 118 | 119 | uifile is a file name or file-like object containing the .ui file. 120 | pyfile is the file-like object to which the Python code will be written to. 121 | execute is optionally set to generate extra Python code that allows the 122 | code to be run as a standalone application. The default is False. 123 | indent is the optional indentation width using spaces. If it is 0 then a 124 | tab is used. The default is 4. 125 | from_imports is optionally set to generate import statements that are 126 | relative to '.'. 127 | """ 128 | 129 | from time import ctime 130 | import PySide2 131 | 132 | try: 133 | uifname = uifile.name 134 | except AttributeError: 135 | uifname = uifile 136 | 137 | indenter.indentwidth = indent 138 | 139 | global PySideToolsVersion 140 | pyfile.write(_header % (uifname, ctime(), __version__, PySide2.__version__)) 141 | 142 | winfo = compiler.UICompiler().compileUi(uifile, pyfile, from_imports) 143 | 144 | if execute: 145 | indenter.write_code(_display_code % winfo) 146 | 147 | 148 | # The list of directories that are searched for widget plugins. 149 | from pyside2uic.objcreator import widgetPluginPath 150 | -------------------------------------------------------------------------------- /pyside2uic/driver.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | 24 | import sys 25 | import logging 26 | 27 | from pyside2uic import compileUi 28 | 29 | 30 | class Driver(object): 31 | """ This encapsulates access to the pyuic functionality so that it can be 32 | called by code that is Python v2/v3 specific. 33 | """ 34 | 35 | LOGGER_NAME = 'PySide2.uic' 36 | 37 | def __init__(self, opts, ui_file): 38 | """ Initialise the object. opts is the parsed options. ui_file is the 39 | name of the .ui file. 40 | """ 41 | 42 | if opts.debug: 43 | logger = logging.getLogger(self.LOGGER_NAME) 44 | handler = logging.StreamHandler() 45 | handler.setFormatter(logging.Formatter("%(name)s: %(message)s")) 46 | logger.addHandler(handler) 47 | logger.setLevel(logging.DEBUG) 48 | 49 | self._opts = opts 50 | self._ui_file = ui_file 51 | 52 | def invoke(self): 53 | """ Invoke the action as specified by the parsed options. Returns 0 if 54 | there was no error. 55 | """ 56 | 57 | if self._opts.preview: 58 | return self._preview() 59 | 60 | self._generate() 61 | 62 | return 0 63 | 64 | def _preview(self): 65 | """ Preview the .ui file. Return the exit status to be passed back to 66 | the parent process. 67 | """ 68 | 69 | from PySide2 import QtUiTools 70 | from PySide2 import QtGui 71 | from PySide2 import QtWidgets 72 | 73 | app = QtWidgets.QApplication([self._ui_file]) 74 | widget = QtUiTools.QUiLoader().load(self._ui_file) 75 | widget.show() 76 | 77 | return app.exec_() 78 | 79 | def _generate(self): 80 | """ Generate the Python code. """ 81 | 82 | if sys.hexversion >= 0x03000000: 83 | if self._opts.output == '-': 84 | from io import TextIOWrapper 85 | 86 | pyfile = TextIOWrapper(sys.stdout.buffer, encoding='utf8') 87 | else: 88 | pyfile = open(self._opts.output, 'wt', encoding='utf8') 89 | else: 90 | if self._opts.output == '-': 91 | pyfile = sys.stdout 92 | else: 93 | pyfile = open(self._opts.output, 'wt') 94 | 95 | compileUi(self._ui_file, pyfile, self._opts.execute, self._opts.indent, self._opts.from_imports) 96 | 97 | def on_IOError(self, e): 98 | """ Handle an IOError exception. """ 99 | 100 | sys.stderr.write("Error: %s: \"%s\"\n" % (e.strerror, e.filename)) 101 | 102 | def on_SyntaxError(self, e): 103 | """ Handle a SyntaxError exception. """ 104 | 105 | sys.stderr.write("Error in input file: %s\n" % e) 106 | 107 | def on_NoSuchWidgetError(self, e): 108 | """ Handle a NoSuchWidgetError exception. """ 109 | 110 | if e.args[0].startswith("Q3"): 111 | sys.stderr.write("Error: Q3Support widgets are not supported by PySide2.\n") 112 | else: 113 | sys.stderr.write(str(e) + "\n") 114 | 115 | def on_Exception(self, e): 116 | """ Handle a generic exception. """ 117 | 118 | if logging.getLogger(self.LOGGER_NAME).level == logging.DEBUG: 119 | import traceback 120 | 121 | traceback.print_exception(*sys.exc_info()) 122 | else: 123 | from PySide2 import QtCore 124 | 125 | sys.stderr.write("""An unexpected error occurred. 126 | Check that you are using the latest version of PySide2 and report the error to 127 | http://bugs.openbossa.org, including the ui file used to trigger the error. 128 | """) 129 | -------------------------------------------------------------------------------- /pyside2uic/exceptions.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2009 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | class NoSuchWidgetError(Exception): 24 | def __str__(self): 25 | return "Unknown Qt widget: %s" % (self.args[0],) 26 | 27 | class UnsupportedPropertyError(Exception): 28 | pass 29 | 30 | class WidgetPluginError(Exception): 31 | pass 32 | -------------------------------------------------------------------------------- /pyside2uic/icon_cache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This file is part of the PySide project. 3 | # 4 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 5 | # Copyright (C) 2010 Riverbank Computing Limited. 6 | # Copyright (C) 2009 Torsten Marek 7 | # 8 | # Contact: PySide team 9 | # 10 | # This program is free software; you can redistribute it and/or 11 | # modify it under the terms of the GNU General Public License 12 | # version 2 as published by the Free Software Foundation. 13 | # 14 | # This program is distributed in the hope that it will be useful, but 15 | # WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | # General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 | # 02110-1301 USA 23 | 24 | 25 | import os.path 26 | 27 | 28 | class IconCache(object): 29 | """Maintain a cache of icons. If an icon is used more than once by a GUI 30 | then ensure that only one copy is created. 31 | """ 32 | 33 | def __init__(self, object_factory, qtgui_module): 34 | """Initialise the cache.""" 35 | 36 | self._object_factory = object_factory 37 | self._qtgui_module = qtgui_module 38 | self._base_dir = '' 39 | self._cache = [] 40 | 41 | def set_base_dir(self, base_dir): 42 | """ Set the base directory to be used for all relative filenames. """ 43 | 44 | self._base_dir = base_dir 45 | 46 | def get_icon(self, iconset): 47 | """Return an icon described by the given iconset tag.""" 48 | 49 | iset = _IconSet(iconset, self._base_dir) 50 | 51 | try: 52 | idx = self._cache.index(iset) 53 | except ValueError: 54 | idx = -1 55 | 56 | if idx >= 0: 57 | # Return the icon from the cache. 58 | iset = self._cache[idx] 59 | else: 60 | # Follow uic's naming convention. 61 | name = 'icon' 62 | idx = len(self._cache) 63 | 64 | if idx > 0: 65 | name += str(idx) 66 | 67 | icon = self._object_factory.createQObject("QIcon", name, (), 68 | is_attribute=False) 69 | iset.set_icon(icon, self._qtgui_module) 70 | self._cache.append(iset) 71 | 72 | return iset.icon 73 | 74 | 75 | class _IconSet(object): 76 | """An icon set, ie. the mode and state and the pixmap used for each.""" 77 | 78 | def __init__(self, iconset, base_dir): 79 | """Initialise the icon set from an XML tag.""" 80 | 81 | # Set the pre-Qt v4.4 fallback (ie. with no roles). 82 | self._fallback = self._file_name(iconset.text, base_dir) 83 | self._use_fallback = True 84 | 85 | # Parse the icon set. 86 | self._roles = {} 87 | 88 | for i in iconset: 89 | file_name = i.text 90 | if file_name is not None: 91 | file_name = self._file_name(file_name, base_dir) 92 | 93 | self._roles[i.tag] = file_name 94 | self._use_fallback = False 95 | 96 | # There is no real icon yet. 97 | self.icon = None 98 | 99 | @staticmethod 100 | def _file_name(fname, base_dir): 101 | """ Convert a relative filename if we have a base directory. """ 102 | 103 | fname = fname.replace("\\", "\\\\") 104 | 105 | if base_dir != '' and fname[0] != ':' and not os.path.isabs(fname): 106 | fname = os.path.join(base_dir, fname) 107 | 108 | return fname 109 | 110 | def set_icon(self, icon, qtgui_module): 111 | """Save the icon and set its attributes.""" 112 | 113 | if self._use_fallback: 114 | icon.addFile(self._fallback) 115 | else: 116 | for role, pixmap in self._roles.items(): 117 | if role.endswith("off"): 118 | mode = role[:-3] 119 | state = qtgui_module.QIcon.Off 120 | elif role.endswith("on"): 121 | mode = role[:-2] 122 | state = qtgui_module.QIcon.On 123 | else: 124 | continue 125 | 126 | mode = getattr(qtgui_module.QIcon, mode.title()) 127 | 128 | if pixmap: 129 | icon.addPixmap(qtgui_module.QPixmap(pixmap), mode, state) 130 | else: 131 | icon.addPixmap(qtgui_module.QPixmap(), mode, state) 132 | 133 | self.icon = icon 134 | 135 | def __eq__(self, other): 136 | """Compare two icon sets for equality.""" 137 | 138 | if not isinstance(other, type(self)): 139 | return NotImplemented 140 | 141 | if self._use_fallback: 142 | if other._use_fallback: 143 | return self._fallback == other._fallback 144 | 145 | return False 146 | 147 | if other._use_fallback: 148 | return False 149 | 150 | return self._roles == other._roles 151 | -------------------------------------------------------------------------------- /pyside2uic/objcreator.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | import sys 24 | import os.path 25 | 26 | from pyside2uic.exceptions import NoSuchWidgetError, WidgetPluginError 27 | 28 | if sys.hexversion >= 0x03000000: 29 | from pyside2uic.port_v3.load_plugin import load_plugin 30 | else: 31 | from pyside2uic.port_v2.load_plugin import load_plugin 32 | 33 | 34 | # The list of directories that are searched for widget plugins. This is 35 | # exposed as part of the API. 36 | widgetPluginPath = [os.path.join(os.path.dirname(__file__), 'widget-plugins')] 37 | 38 | 39 | MATCH = True 40 | NO_MATCH = False 41 | MODULE = 0 42 | CW_FILTER = 1 43 | 44 | 45 | class QObjectCreator(object): 46 | def __init__(self, creatorPolicy): 47 | self._cpolicy = creatorPolicy 48 | 49 | self._cwFilters = [] 50 | self._modules = [self._cpolicy.createQtWidgetsWrapper(), 51 | self._cpolicy.createQtGuiWrapper()] 52 | 53 | # Get the optional plugins. 54 | for plugindir in widgetPluginPath: 55 | try: 56 | plugins = os.listdir(plugindir) 57 | except: 58 | plugins = [] 59 | 60 | for filename in plugins: 61 | if not filename.endswith('.py') or filename == '__init__.py': 62 | continue 63 | 64 | filename = os.path.join(plugindir, filename) 65 | 66 | plugin_globals = { 67 | "MODULE": MODULE, 68 | "CW_FILTER": CW_FILTER, 69 | "MATCH": MATCH, 70 | "NO_MATCH": NO_MATCH} 71 | 72 | plugin_locals = {} 73 | 74 | if load_plugin(open(filename), plugin_globals, plugin_locals): 75 | pluginType = plugin_locals["pluginType"] 76 | if pluginType == MODULE: 77 | modinfo = plugin_locals["moduleInformation"]() 78 | self._modules.append(self._cpolicy.createModuleWrapper(*modinfo)) 79 | elif pluginType == CW_FILTER: 80 | self._cwFilters.append(plugin_locals["getFilter"]()) 81 | else: 82 | raise WidgetPluginError("Unknown plugin type of %s" % filename) 83 | 84 | self._customWidgets = self._cpolicy.createCustomWidgetLoader() 85 | self._modules.append(self._customWidgets) 86 | 87 | def createQObject(self, classname, *args, **kwargs): 88 | classType = self.findQObjectType(classname) 89 | if classType: 90 | return self._cpolicy.instantiate(classType, *args, **kwargs) 91 | raise NoSuchWidgetError(classname) 92 | 93 | def invoke(self, rname, method, args=()): 94 | return self._cpolicy.invoke(rname, method, args) 95 | 96 | def findQObjectType(self, classname): 97 | for module in self._modules: 98 | w = module.search(classname) 99 | if w is not None: 100 | return w 101 | return None 102 | 103 | def getSlot(self, obj, slotname): 104 | return self._cpolicy.getSlot(obj, slotname) 105 | 106 | def addCustomWidget(self, widgetClass, baseClass, module): 107 | for cwFilter in self._cwFilters: 108 | match, result = cwFilter(widgetClass, baseClass, module) 109 | if match: 110 | widgetClass, baseClass, module = result 111 | break 112 | 113 | self._customWidgets.addCustomWidget(widgetClass, baseClass, module) 114 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/as_string.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | import re 23 | 24 | 25 | def as_string(obj, encode=True): 26 | if isinstance(obj, basestring): 27 | s = '"' + _escape(obj.encode('UTF-8')) + '"' 28 | return s 29 | 30 | return str(obj) 31 | 32 | 33 | _esc_regex = re.compile(r"(\"|\'|\\)") 34 | 35 | def _escape(text): 36 | # This escapes any escaped single or double quote or backslash. 37 | x = _esc_regex.sub(r"\\\1", text) 38 | 39 | # This replaces any '\n' with an escaped version and a real line break. 40 | return re.sub(r'\n', r'\\n"\n"', x) 41 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/ascii_upper.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | import string 23 | 24 | 25 | # A translation table for converting ASCII lower case to upper case. 26 | _ascii_trans_table = string.maketrans(string.ascii_lowercase, 27 | string.ascii_uppercase) 28 | 29 | 30 | # Convert a string to ASCII upper case irrespective of the current locale. 31 | def ascii_upper(s): 32 | return s.translate(_ascii_trans_table) 33 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/invoke.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.exceptions import NoSuchWidgetError 24 | 25 | 26 | def invoke(driver): 27 | """ Invoke the given command line driver. Return the exit status to be 28 | passed back to the parent process. 29 | """ 30 | 31 | exit_status = 1 32 | 33 | try: 34 | exit_status = driver.invoke() 35 | 36 | except IOError, e: 37 | driver.on_IOError(e) 38 | 39 | except SyntaxError, e: 40 | driver.on_SyntaxError(e) 41 | 42 | except NoSuchWidgetError, e: 43 | driver.on_NoSuchWidgetError(e) 44 | 45 | except Exception, e: 46 | driver.on_Exception(e) 47 | 48 | return exit_status 49 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/load_plugin.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.exceptions import WidgetPluginError 24 | 25 | 26 | def load_plugin(plugin, plugin_globals, plugin_locals): 27 | """ Load the given plugin (which is an open file). Return True if the 28 | plugin was loaded, or False if it wanted to be ignored. Raise an exception 29 | if there was an error. 30 | """ 31 | 32 | try: 33 | exec(plugin.read(), plugin_globals, plugin_locals) 34 | except ImportError: 35 | return False 36 | except Exception, e: 37 | raise WidgetPluginError("%s: %s" % (e.__class__, str(e))) 38 | 39 | return True 40 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/proxy_base.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.Compiler.proxy_type import ProxyType 24 | 25 | 26 | class ProxyBase(object): 27 | __metaclass__ = ProxyType 28 | -------------------------------------------------------------------------------- /pyside2uic/port_v2/string_io.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | 23 | # Import the StringIO object. 24 | try: 25 | from cStringIO import StringIO 26 | except ImportError: 27 | from StringIO import StringIO 28 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/as_string.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | import re 23 | 24 | 25 | def as_string(obj, encode=True): 26 | if isinstance(obj, str): 27 | s = '"' + _escape(obj) + '"' 28 | 29 | return s 30 | 31 | return str(obj) 32 | 33 | 34 | _esc_regex = re.compile(r"(\"|\'|\\)") 35 | 36 | def _escape(text): 37 | # This escapes any escaped single or double quote or backslash. 38 | x = _esc_regex.sub(r"\\\1", text) 39 | 40 | # This replaces any '\n' with an escaped version and a real line break. 41 | return re.sub(r'\n', r'\\n"\n"', x) 42 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/ascii_upper.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | 23 | # A translation table for converting ASCII lower case to upper case. 24 | _ascii_trans_table = bytes.maketrans(b'abcdefghijklmnopqrstuvwxyz', 25 | b'ABCDEFGHIJKLMNOPQRSTUVWXYZ') 26 | 27 | 28 | # Convert a string to ASCII upper case irrespective of the current locale. 29 | def ascii_upper(s): 30 | return s.translate(_ascii_trans_table) 31 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/invoke.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.exceptions import NoSuchWidgetError 24 | 25 | 26 | def invoke(driver): 27 | """ Invoke the given command line driver. Return the exit status to be 28 | passed back to the parent process. 29 | """ 30 | 31 | exit_status = 1 32 | 33 | try: 34 | exit_status = driver.invoke() 35 | 36 | except IOError as e: 37 | driver.on_IOError(e) 38 | 39 | except SyntaxError as e: 40 | driver.on_SyntaxError(e) 41 | 42 | except NoSuchWidgetError as e: 43 | driver.on_NoSuchWidgetError(e) 44 | 45 | except Exception as e: 46 | driver.on_Exception(e) 47 | 48 | return exit_status 49 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/load_plugin.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.exceptions import WidgetPluginError 24 | 25 | 26 | def load_plugin(plugin, plugin_globals, plugin_locals): 27 | """ Load the given plugin (which is an open file). Return True if the 28 | plugin was loaded, or False if it wanted to be ignored. Raise an exception 29 | if there was an error. 30 | """ 31 | 32 | try: 33 | exec(plugin.read(), plugin_globals, plugin_locals) 34 | except ImportError: 35 | return False 36 | except Exception as e: 37 | raise WidgetPluginError("%s: %s" % (e.__class__, str(e))) 38 | 39 | return True 40 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/proxy_base.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | from pyside2uic.Compiler.proxy_type import ProxyType 24 | 25 | 26 | class ProxyBase(metaclass=ProxyType): 27 | pass 28 | -------------------------------------------------------------------------------- /pyside2uic/port_v3/string_io.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | 23 | # Import the StringIO object. 24 | from io import StringIO 25 | -------------------------------------------------------------------------------- /pyside2uic/properties.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | import logging 24 | import os.path 25 | import sys 26 | 27 | from pyside2uic.exceptions import UnsupportedPropertyError 28 | from pyside2uic.icon_cache import IconCache 29 | 30 | if sys.hexversion >= 0x03000000: 31 | from pyside2uic.port_v3.ascii_upper import ascii_upper 32 | else: 33 | from pyside2uic.port_v2.ascii_upper import ascii_upper 34 | 35 | logger = logging.getLogger(__name__) 36 | DEBUG = logger.debug 37 | 38 | QtCore = None 39 | QtGui = None 40 | QtWidgets = None 41 | 42 | 43 | def int_list(prop): 44 | return [int(child.text) for child in prop] 45 | 46 | def float_list(prop): 47 | return [float(child.text) for child in prop] 48 | 49 | bool_ = lambda v: v == "true" 50 | 51 | def needsWidget(func): 52 | func.needsWidget = True 53 | return func 54 | 55 | 56 | class Properties(object): 57 | def __init__(self, factory, QtCore_mod, QtGui_mod, QtWidgets_mod): 58 | global QtGui, QtCore, QtWidgets 59 | QtWidgets = QtWidgets_mod 60 | QtGui = QtGui_mod 61 | QtCore = QtCore_mod 62 | self.factory = factory 63 | 64 | self._base_dir = '' 65 | 66 | self.reset() 67 | 68 | def set_base_dir(self, base_dir): 69 | """ Set the base directory to be used for all relative filenames. """ 70 | 71 | self._base_dir = base_dir 72 | self.icon_cache.set_base_dir(base_dir) 73 | 74 | def reset(self): 75 | self.buddies = [] 76 | self.delayed_props = [] 77 | self.icon_cache = IconCache(self.factory, QtGui) 78 | 79 | def _pyEnumMember(self, cpp_name): 80 | try: 81 | prefix, membername = cpp_name.split("::") 82 | except ValueError: 83 | prefix = "Qt" 84 | membername = cpp_name 85 | 86 | if prefix == "Qt": 87 | return getattr(QtCore.Qt, membername) 88 | 89 | scope = self.factory.findQObjectType(prefix) 90 | if scope is None: 91 | raise AttributeError("unknown enum %s" % cpp_name) 92 | 93 | return getattr(scope, membername) 94 | 95 | def _set(self, prop): 96 | expr = [self._pyEnumMember(v) for v in prop.text.split('|')] 97 | 98 | value = expr[0] 99 | for v in expr[1:]: 100 | value |= v 101 | 102 | return value 103 | 104 | def _enum(self, prop): 105 | return self._pyEnumMember(prop.text) 106 | 107 | def _number(self, prop): 108 | return int(prop.text) 109 | 110 | _uInt = _longLong = _uLongLong = _number 111 | 112 | def _double(self, prop): 113 | return float(prop.text) 114 | 115 | def _bool(self, prop): 116 | return prop.text == 'true' 117 | 118 | def _stringlist(self, prop): 119 | return [self._string(p, notr='true') for p in prop] 120 | 121 | def _string(self, prop, notr=None): 122 | text = prop.text 123 | 124 | if text is None: 125 | return "" 126 | 127 | if prop.get('notr', notr) == 'true': 128 | return text 129 | 130 | return QtWidgets.QApplication.translate(self.uiname, text, 131 | prop.get('comment'), -1) 132 | 133 | _char = _string 134 | 135 | def _cstring(self, prop): 136 | return str(prop.text) 137 | 138 | def _color(self, prop): 139 | args = int_list(prop) 140 | 141 | # Handle the optional alpha component. 142 | alpha = int(prop.get("alpha", "255")) 143 | 144 | if alpha != 255: 145 | args.append(alpha) 146 | 147 | return QtGui.QColor(*args) 148 | 149 | def _point(self, prop): 150 | return QtCore.QPoint(*int_list(prop)) 151 | 152 | def _pointf(self, prop): 153 | return QtCore.QPointF(*float_list(prop)) 154 | 155 | def _rect(self, prop): 156 | return QtCore.QRect(*int_list(prop)) 157 | 158 | def _rectf(self, prop): 159 | return QtCore.QRectF(*float_list(prop)) 160 | 161 | def _size(self, prop): 162 | return QtCore.QSize(*int_list(prop)) 163 | 164 | def _sizef(self, prop): 165 | return QtCore.QSizeF(*float_list(prop)) 166 | 167 | def _pixmap(self, prop): 168 | if prop.text: 169 | fname = prop.text.replace("\\", "\\\\") 170 | if self._base_dir != '' and fname[0] != ':' and not os.path.isabs(fname): 171 | fname = os.path.join(self._base_dir, fname) 172 | 173 | return QtGui.QPixmap(fname) 174 | 175 | # Don't bother to set the property if the pixmap is empty. 176 | return None 177 | 178 | def _iconset(self, prop): 179 | return self.icon_cache.get_icon(prop) 180 | 181 | def _url(self, prop): 182 | return QtCore.QUrl(prop[0].text) 183 | 184 | def _locale(self, prop): 185 | lang = getattr(QtCore.QLocale, prop.attrib['language']) 186 | country = getattr(QtCore.QLocale, prop.attrib['country']) 187 | return QtCore.QLocale(lang, country) 188 | 189 | def _cursor(self, prop): 190 | return QtGui.QCursor(QtCore.Qt.CursorShape(int(prop.text))) 191 | 192 | def _date(self, prop): 193 | return QtCore.QDate(*int_list(prop)) 194 | 195 | def _datetime(self, prop): 196 | args = int_list(prop) 197 | return QtCore.QDateTime(QtCore.QDate(*args[-3:]), QtCore.QTime(*args[:-3])) 198 | 199 | def _time(self, prop): 200 | return QtCore.QTime(*int_list(prop)) 201 | 202 | def _gradient(self, prop): 203 | name = 'gradient' 204 | 205 | # Create the specific gradient. 206 | gtype = prop.get('type', '') 207 | 208 | if gtype == 'LinearGradient': 209 | startx = float(prop.get('startx')) 210 | starty = float(prop.get('starty')) 211 | endx = float(prop.get('endx')) 212 | endy = float(prop.get('endy')) 213 | gradient = self.factory.createQObject('QLinearGradient', name, 214 | (startx, starty, endx, endy), is_attribute=False) 215 | 216 | elif gtype == 'ConicalGradient': 217 | centralx = float(prop.get('centralx')) 218 | centraly = float(prop.get('centraly')) 219 | angle = float(prop.get('angle')) 220 | gradient = self.factory.createQObject('QConicalGradient', name, 221 | (centralx, centraly, angle), is_attribute=False) 222 | 223 | elif gtype == 'RadialGradient': 224 | centralx = float(prop.get('centralx')) 225 | centraly = float(prop.get('centraly')) 226 | radius = float(prop.get('radius')) 227 | focalx = float(prop.get('focalx')) 228 | focaly = float(prop.get('focaly')) 229 | gradient = self.factory.createQObject('QRadialGradient', name, 230 | (centralx, centraly, radius, focalx, focaly), 231 | is_attribute=False) 232 | 233 | else: 234 | raise UnsupportedPropertyError(prop.tag) 235 | 236 | # Set the common values. 237 | spread = prop.get('spread') 238 | if spread: 239 | gradient.setSpread(getattr(QtGui.QGradient, spread)) 240 | 241 | cmode = prop.get('coordinatemode') 242 | if cmode: 243 | gradient.setCoordinateMode(getattr(QtGui.QGradient, cmode)) 244 | 245 | # Get the gradient stops. 246 | for gstop in prop: 247 | if gstop.tag != 'gradientstop': 248 | raise UnsupportedPropertyError(gstop.tag) 249 | 250 | position = float(gstop.get('position')) 251 | color = self._color(gstop[0]) 252 | 253 | gradient.setColorAt(position, color) 254 | 255 | return name 256 | 257 | def _palette(self, prop): 258 | palette = self.factory.createQObject("QPalette", "palette", (), 259 | is_attribute=False) 260 | 261 | for palette_elem in prop: 262 | sub_palette = getattr(QtGui.QPalette, palette_elem.tag.title()) 263 | for role, color in enumerate(palette_elem): 264 | if color.tag == 'color': 265 | # Handle simple colour descriptions where the role is 266 | # implied by the colour's position. 267 | palette.setColor(sub_palette, 268 | QtGui.QPalette.ColorRole(role), self._color(color)) 269 | elif color.tag == 'colorrole': 270 | role = getattr(QtGui.QPalette, color.get('role')) 271 | brush = self._brush(color[0]) 272 | palette.setBrush(sub_palette, role, brush) 273 | else: 274 | raise UnsupportedPropertyError(color.tag) 275 | 276 | return palette 277 | 278 | def _brush(self, prop): 279 | brushstyle = prop.get('brushstyle') 280 | 281 | if brushstyle in ('LinearGradientPattern', 'ConicalGradientPattern', 'RadialGradientPattern'): 282 | gradient = self._gradient(prop[0]) 283 | brush = self.factory.createQObject("QBrush", "brush", (gradient, ), 284 | is_attribute=False) 285 | else: 286 | color = self._color(prop[0]) 287 | brush = self.factory.createQObject("QBrush", "brush", (color, ), 288 | is_attribute=False) 289 | 290 | brushstyle = getattr(QtCore.Qt, brushstyle) 291 | brush.setStyle(brushstyle) 292 | 293 | return brush 294 | 295 | #@needsWidget 296 | def _sizepolicy(self, prop, widget): 297 | values = [int(child.text) for child in prop] 298 | 299 | if len(values) == 2: 300 | # Qt v4.3.0 and later. 301 | horstretch, verstretch = values 302 | hsizetype = getattr(QtWidgets.QSizePolicy, prop.get('hsizetype')) 303 | vsizetype = getattr(QtWidgets.QSizePolicy, prop.get('vsizetype')) 304 | else: 305 | hsizetype, vsizetype, horstretch, verstretch = values 306 | hsizetype = QtWidgets.QSizePolicy.Policy(hsizetype) 307 | vsizetype = QtWidgets.QSizePolicy.Policy(vsizetype) 308 | 309 | sizePolicy = self.factory.createQObject("QSizePolicy", "sizePolicy", 310 | (hsizetype, vsizetype), is_attribute=False) 311 | sizePolicy.setHorizontalStretch(horstretch) 312 | sizePolicy.setVerticalStretch(verstretch) 313 | sizePolicy.setHeightForWidth(widget.sizePolicy().hasHeightForWidth()) 314 | return sizePolicy 315 | _sizepolicy = needsWidget(_sizepolicy) 316 | 317 | # font needs special handling/conversion of all child elements. 318 | _font_attributes = (("Family", str), 319 | ("PointSize", int), 320 | ("Weight", int), 321 | ("Italic", bool_), 322 | ("Underline", bool_), 323 | ("StrikeOut", bool_), 324 | ("Bold", bool_)) 325 | 326 | def _font(self, prop): 327 | newfont = self.factory.createQObject("QFont", "font", (), 328 | is_attribute = False) 329 | for attr, converter in self._font_attributes: 330 | v = prop.findtext("./%s" % (attr.lower(),)) 331 | if v is None: 332 | continue 333 | 334 | getattr(newfont, "set%s" % (attr,))(converter(v)) 335 | return newfont 336 | 337 | def _cursorShape(self, prop): 338 | return getattr(QtCore.Qt, prop.text) 339 | 340 | def convert(self, prop, widget=None): 341 | try: 342 | func = getattr(self, "_" + prop[0].tag) 343 | except AttributeError: 344 | raise UnsupportedPropertyError(prop[0].tag) 345 | else: 346 | args = {} 347 | if getattr(func, "needsWidget", False): 348 | assert widget is not None 349 | args["widget"] = widget 350 | 351 | return func(prop[0], **args) 352 | 353 | 354 | def _getChild(self, elem_tag, elem, name, default=None): 355 | for prop in elem.findall(elem_tag): 356 | if prop.attrib["name"] == name: 357 | return self.convert(prop) 358 | else: 359 | return default 360 | 361 | def getProperty(self, elem, name, default=None): 362 | return self._getChild("property", elem, name, default) 363 | 364 | def getAttribute(self, elem, name, default=None): 365 | return self._getChild("attribute", elem, name, default) 366 | 367 | def setProperties(self, widget, elem): 368 | try: 369 | self.wclass = elem.attrib["class"] 370 | except KeyError: 371 | pass 372 | for prop in elem.findall("property"): 373 | prop_name = prop.attrib["name"] 374 | DEBUG("setting property %s" % (prop_name,)) 375 | 376 | try: 377 | stdset = bool(int(prop.attrib["stdset"])) 378 | except KeyError: 379 | stdset = True 380 | 381 | if not stdset: 382 | self._setViaSetProperty(widget, prop) 383 | elif hasattr(self, prop_name): 384 | getattr(self, prop_name)(widget, prop) 385 | else: 386 | prop_value = self.convert(prop, widget) 387 | if prop_value is not None: 388 | getattr(widget, "set%s%s" % (ascii_upper(prop_name[0]), prop_name[1:]))(prop_value) 389 | 390 | # SPECIAL PROPERTIES 391 | # If a property has a well-known value type but needs special, 392 | # context-dependent handling, the default behaviour can be overridden here. 393 | 394 | # Delayed properties will be set after the whole widget tree has been 395 | # populated. 396 | def _delayed_property(self, widget, prop): 397 | prop_value = self.convert(prop) 398 | if prop_value is not None: 399 | prop_name = prop.attrib["name"] 400 | self.delayed_props.append((widget, False, 401 | 'set%s%s' % (ascii_upper(prop_name[0]), prop_name[1:]), 402 | prop_value)) 403 | 404 | # These properties will be set with a widget.setProperty call rather than 405 | # calling the set function. 406 | def _setViaSetProperty(self, widget, prop): 407 | prop_value = self.convert(prop) 408 | if prop_value is not None: 409 | widget.setProperty(prop.attrib["name"], prop_value) 410 | 411 | # Ignore the property. 412 | def _ignore(self, widget, prop): 413 | pass 414 | 415 | # Define properties that use the canned handlers. 416 | currentIndex = _delayed_property 417 | currentRow = _delayed_property 418 | 419 | showDropIndicator = _setViaSetProperty 420 | intValue = _setViaSetProperty 421 | value = _setViaSetProperty 422 | 423 | objectName = _ignore 424 | leftMargin = _ignore 425 | topMargin = _ignore 426 | rightMargin = _ignore 427 | bottomMargin = _ignore 428 | horizontalSpacing = _ignore 429 | verticalSpacing = _ignore 430 | 431 | # tabSpacing is actually the spacing property of the widget's layout. 432 | def tabSpacing(self, widget, prop): 433 | prop_value = self.convert(prop) 434 | if prop_value is not None: 435 | self.delayed_props.append((widget, True, 'setSpacing', prop_value)) 436 | 437 | # buddy setting has to be done after the whole widget tree has been 438 | # populated. We can't use delay here because we cannot get the actual 439 | # buddy yet. 440 | def buddy(self, widget, prop): 441 | buddy_name = prop[0].text 442 | if buddy_name: 443 | self.buddies.append((widget, buddy_name)) 444 | 445 | # geometry is handled specially if set on the toplevel widget. 446 | def geometry(self, widget, prop): 447 | if widget.objectName() == self.uiname: 448 | geom = int_list(prop[0]) 449 | widget.resize(geom[2], geom[3]) 450 | else: 451 | widget.setGeometry(self._rect(prop[0])) 452 | 453 | def orientation(self, widget, prop): 454 | # If the class is a QFrame, it's a line. 455 | if widget.metaObject().className() == "QFrame": 456 | widget.setFrameShape( 457 | {"Qt::Horizontal": QtWidgets.QFrame.HLine, 458 | "Qt::Vertical" : QtWidgets.QFrame.VLine}[prop[0].text]) 459 | 460 | # In Qt Designer, lines appear to be sunken, QFormBuilder loads 461 | # them as such, uic generates plain lines. We stick to the look in 462 | # Qt Designer. 463 | widget.setFrameShadow(QtWidgets.QFrame.Sunken) 464 | else: 465 | widget.setOrientation(self._enum(prop[0])) 466 | 467 | # The isWrapping attribute of QListView is named inconsistently, it should 468 | # be wrapping. 469 | def isWrapping(self, widget, prop): 470 | widget.setWrapping(self.convert(prop)) 471 | 472 | # This is a pseudo-property injected to deal with setContentsMargin() 473 | # introduced in Qt v4.3. 474 | def pyuicContentsMargins(self, widget, prop): 475 | widget.setContentsMargins(*int_list(prop)) 476 | 477 | # This is a pseudo-property injected to deal with setHorizontalSpacing() 478 | # and setVerticalSpacing() introduced in Qt v4.3. 479 | def pyuicSpacing(self, widget, prop): 480 | horiz, vert = int_list(prop) 481 | 482 | if horiz == vert: 483 | widget.setSpacing(horiz) 484 | else: 485 | if horiz >= 0: 486 | widget.setHorizontalSpacing(horiz) 487 | 488 | if vert >= 0: 489 | widget.setVerticalSpacing(vert) 490 | -------------------------------------------------------------------------------- /pyside2uic/pyside2-uic.1: -------------------------------------------------------------------------------- 1 | .TH PYSIDE-UIC "1" "December 2010" "pyside2-uic" "User Commands" 2 | .SH NAME 3 | pyside2\-uic \- DESCRIPTION... 4 | .SH DESCRIPTION 5 | .SS "Usage:" 6 | .IP 7 | pyside2\-uic [options] 8 | .SS "Options:" 9 | .TP 10 | \fB\-\-version 11 | show program's version number and exit 12 | .TP 13 | .BI \-h\fB \fR,\fB \-\-help 14 | show this help message and exit 15 | .TP 16 | .BI \-o FILE \fR, \-\-output=\fIFILE 17 | write generated code to FILE instead of stdout 18 | .TP 19 | .BI \-x \fR, \-\-execute 20 | generate extra code to test and display the class 21 | .TP 22 | .BI \-d \fR, \-\-debug 23 | show debug output 24 | .TP 25 | .BI \-i N\fR, \-\-ident=N 26 | set indent width to N spaces, tab if N is 0 (default: 4) 27 | .SH COPYRIGHT 28 | Copyright \(co 2010 Nokia Corporation and/or its subsidiary(\fB\-ies\fR) 29 | .SH AUTHOR 30 | .PP 31 | This manpage was written by Marcelo Lira , on the 29. December 2010. 32 | -------------------------------------------------------------------------------- /pyside2uic/widget-plugins/qtdeclarative.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2010 Riverbank Computing Limited. 5 | # 6 | # Contact: PySide team 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # version 2 as published by the Free Software Foundation. 11 | # 12 | # This program is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 | # 02110-1301 USA 21 | 22 | # If pluginType is MODULE, the plugin loader will call moduleInformation. The 23 | # variable MODULE is inserted into the local namespace by the plugin loader. 24 | pluginType = MODULE 25 | 26 | 27 | # moduleInformation() must return a tuple (module, widget_list). If "module" 28 | # is "A" and any widget from this module is used, the code generator will write 29 | # "import A". If "module" is "A[.B].C", the code generator will write 30 | # "from A[.B] import C". Each entry in "widget_list" must be unique. 31 | def moduleInformation(): 32 | return "PySide2.QtDeclarative", ("QDeclarativeView", ) 33 | -------------------------------------------------------------------------------- /pyside2uic/widget-plugins/qtwebkit.py: -------------------------------------------------------------------------------- 1 | # This file is part of the PySide project. 2 | # 3 | # Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 4 | # Copyright (C) 2009 Riverbank Computing Limited. 5 | # Copyright (C) 2009 Torsten Marek 6 | # 7 | # Contact: PySide team 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # version 2 as published by the Free Software Foundation. 12 | # 13 | # This program is distributed in the hope that it will be useful, but 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 | # 02110-1301 USA 22 | 23 | 24 | # If pluginType is MODULE, the plugin loader will call moduleInformation. The 25 | # variable MODULE is inserted into the local namespace by the plugin loader. 26 | pluginType = MODULE 27 | 28 | 29 | # moduleInformation() must return a tuple (module, widget_list). If "module" 30 | # is "A" and any widget from this module is used, the code generator will write 31 | # "import A". If "module" is "A[.B].C", the code generator will write 32 | # "from A[.B] import C". Each entry in "widget_list" must be unique. 33 | def moduleInformation(): 34 | return "PySide2.QtWebKit", ("QWebView", ) 35 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Shiboken2 2.0.0 REQUIRED) 2 | add_subdirectory(rcc) 3 | add_test(QWizard ${SHIBOKEN_PYTHON_INTERPRETER} ${CMAKE_SOURCE_DIR}/pyside2-uic "${CMAKE_CURRENT_SOURCE_DIR}/qwizard_test.ui") 4 | set_tests_properties(QWizard PROPERTIES 5 | ENVIRONMENT "PYTHONPATH=$ENV{PYTHONPATH}:${CMAKE_SOURCE_DIR}:${CMAKE_CURRENT_SOURCE_DIR}") 6 | -------------------------------------------------------------------------------- /tests/qwizard_test.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Wizard 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Wizard 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 72 29 | 30 | 31 | 32 | Hello 33 | 34 | 35 | Qt::PlainText 36 | 37 | 38 | true 39 | 40 | 41 | Qt::AlignCenter 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | http://test.qml 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | QDeclarativeView 61 | QGraphicsView 62 |
QtDeclarative/QDeclarativeView
63 |
64 |
65 | 66 | 67 |
68 | -------------------------------------------------------------------------------- /tests/rcc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(ADD_RCC_TEST name pyfile qrcfile) 2 | add_test(${name} ${CMAKE_CURRENT_SOURCE_DIR}/run_test.sh 3 | ${PYSIDERCC_EXECUTABLE} 4 | ${CMAKE_CURRENT_SOURCE_DIR}/${pyfile} 5 | ${CMAKE_CURRENT_SOURCE_DIR}/${qrcfile} 6 | ${CMAKE_CURRENT_SOURCE_DIR}) 7 | endmacro() 8 | 9 | add_rcc_test(RccTest rcc_test.py example.qrc) 10 | add_rcc_test(RccImageTest rcc_image_test.py image.qrc) 11 | -------------------------------------------------------------------------------- /tests/rcc/document-print-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyside/pyside2-tools/f68388cf547c0d63a5d4a145f65aa9fa90529d52/tests/rcc/document-print-preview.png -------------------------------------------------------------------------------- /tests/rcc/example.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | words.txt 4 | shining.txt 5 | manychars.txt 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/rcc/image.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | document-print-preview.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/rcc/manychars.txt: -------------------------------------------------------------------------------- 1 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 2 | -------------------------------------------------------------------------------- /tests/rcc/rcc_image_test.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | 4 | from PySide2.QtWidgets import QApplication 5 | from PySide2.QtGui import QPixmap 6 | 7 | import image_rc 8 | 9 | class TestRccImage(unittest.TestCase): 10 | def testImage(self): 11 | app = QApplication([]) 12 | image = QPixmap(":image") 13 | self.assertFalse(image.isNull()) 14 | 15 | if __name__ == '__main__': 16 | unittest.main() 17 | -------------------------------------------------------------------------------- /tests/rcc/rcc_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | from PySide2.QtCore import QFile 4 | import example_rc 5 | 6 | class TestRccSimple(unittest.TestCase): 7 | 8 | def setUp(self): 9 | self.testdir = os.path.dirname(__file__) 10 | 11 | def testSimple(self): 12 | handle = QFile(":words.txt") 13 | handle.open(QFile.ReadOnly) 14 | original = open(os.path.join(self.testdir, "words.txt"), "r") 15 | self.assertEqual(handle.readLine(), original.readline()) 16 | 17 | def testAlias(self): 18 | handle = QFile(":jack") 19 | handle.open(QFile.ReadOnly) 20 | original = open(os.path.join(self.testdir, "shining.txt"), "r") 21 | self.assertEqual(handle.readLine(), original.readline()) 22 | 23 | def testHuge(self): 24 | handle = QFile(":manychars.txt") 25 | handle.open(QFile.ReadOnly) 26 | original = open(os.path.join(self.testdir, "manychars.txt"), "r") 27 | self.assertEqual(handle.readLine(), original.readline()) 28 | 29 | 30 | if __name__ == '__main__': 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /tests/rcc/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This is a nasty workaround of a CTest limitation 4 | # of setting the environment variables for the test. 5 | 6 | # $1: pyside2-rcc 7 | # $2: python test 8 | # $3: qrc file 9 | 10 | export PYTHONPATH=$PYTHONPATH:`pwd` 11 | $1 -o `basename $3 .qrc`_rc.py $3 12 | `pkg-config shiboken2 --variable=python_interpreter` $2 13 | -------------------------------------------------------------------------------- /tests/rcc/shining.txt: -------------------------------------------------------------------------------- 1 | All work and no play makes Jack a dull boy. 2 | -------------------------------------------------------------------------------- /tests/rcc/words.txt: -------------------------------------------------------------------------------- 1 | The Quick Brown Fox Jumps Over The Lazy Dog. 2 | --------------------------------------------------------------------------------