diff --git a/dist/changes-4.6.0.md b/dist/changes-4.6.0.md index 9f1db648bd9..ee899662c69 100644 --- a/dist/changes-4.6.0.md +++ b/dist/changes-4.6.0.md @@ -24,8 +24,18 @@ General Editing * Added option to display annotations between lines (QTCREATORBUG-19181) +* Added shortcut setting for jumping to document start and end * Fixed that editor could jump to end of file when editing in a different split (QTCREATORBUG-19550) +* Fixed order of items in list of recent documents when documents are suspended + (QTCREATORBUG-19758) +* Fixed crash in generic highlighter (QTCREATORBUG-19916) +* Fixed issue with snippet variables on Gnome (QTCREATORBUG-19571) +* Fixed tool tips in binary editor (QTCREATORBUG-17573) + +Help + +* Improved startup performance All Projects @@ -54,12 +64,17 @@ QML Support Debugging * Split `Expressions` view from `Locals` view (QTCREATORBUG-19167) +* LLDB + * Fixed attaching to core file (QTCREATORBUG-18722) + * Fixed issue when killing LLDB from the outside (QTCREATORBUG-18723) Qt Quick Designer * Added font and text properties from Qt 5.10 * Fixed that items blurred when zooming in * Fixed crash when changing control focus policy (QTCREATORBUG-19563) +* Fixed assert in backend process with Qt 5.9.4 & 5.10.1 and later + (QTCREATORBUG-19729) Version Control Systems @@ -73,15 +88,18 @@ Version Control Systems Diff Viewer * Added folding for files and chunks +* Fixed issue with repeated stage and unstage operation Test Integration * Added grouping of test cases (QTCREATORBUG-17979) +* Fixed handling of `qCritical` output (QTCREATORBUG-19795) * Google Test * Fixed detection of crashed tests (QTCREATORBUG-19565) Model Editor +* Removed experimental state * Added support for text alignment * Added support for multi-line object names * Added support for dragging items onto model editor from more panes @@ -89,6 +107,8 @@ Model Editor * Added `Flat` visual role * Added `Add Related Elements` to diagram context menu * Added wizard for scratch models +* Moved export actions to `File` menu +* Moved zoom actions to editor tool bar * Fixed issue with selecting items (QTCREATORBUG-18368) Platform Specific @@ -98,6 +118,7 @@ Windows * Added support for the [heob](https://github.com/ssbssa/heob/releases) memory analyzer * Fixed detection of CDB in non-default installation roots +* Fixed issue with setting `PATH` versus `Path` environment variable Android diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 3ff19d57aef..2d4f46b0601 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -12,8 +12,8 @@ Nachricht konnte nicht gesendet werden - Unable to send command line arguments to the already running instance. It appears to be not responding. Do you want to start a new instance of Creator? - Die Kommandozeilenargumente konnten nicht an die laufende Instanz übermittelt werden. Sie antwortet nicht. Möchten Sie eine neue Instanz von Qt Creator starten? + Unable to send command line arguments to the already running instance. It does not appear to be responding. Do you want to start a new instance of %1? + Die Kommandozeilenargumente konnten nicht an die laufende Instanz übermittelt werden. Sie antwortet nicht. Möchten Sie eine neue Instanz von %1 starten? Could not find Core plugin in %1 @@ -1058,6 +1058,30 @@ Trotzdem fortfahren? Ctrl+L Ctrl+L + + Zoom In + Vergrößern + + + Ctrl++ + Ctrl++ + + + Zoom Out + Verkleinern + + + Ctrl+- + Ctrl+- + + + Original Size + Originalgröße + + + Meta+0 + Meta+0 + &Options... &Einstellungen... @@ -1460,14 +1484,14 @@ Trotzdem fortfahren? CppTools::Internal::CppFileSettingsWidget /************************************************************************** -** Qt Creator license header template +** %1 license header template ** Special keywords: %USER% %DATE% %YEAR% ** Environment variables: %$VARIABLE% ** To protect a percent sign, use '%%'. **************************************************************************/ /************************************************************************** -** Qt Creator license header template +** %1 license header template ** Special keywords: %USER% %DATE% %YEAR% ** Environment variables: %$VARIABLE% ** To protect a percent sign, use '%%'. @@ -1912,18 +1936,10 @@ Weiterführende Informationen befinden sich in /etc/sysctl.d/10-ptrace.conf Pat&h: &Pfad: - - <p>Specifying the module (base name of the library or executable) for function or file type breakpoints can significantly speed up debugger startup times (CDB, LLDB). - <p>Die Angabe des Moduls (Basisname der Bibliothek oder der ausführbaren Datei) für Haltepunkte des Typs Datei/Zeile oder Funktion kann die Startzeit des Debuggers erheblich reduzieren (CDB, LLDB). - &Module: &Modul: - - <p>Debugger commands to be executed when the breakpoint is hit. This feature is only available for GDB. - <p>Debugger-Kommandos, die beim Auslösen eines Haltepunkts ausgeführt werden (nur GDB). - &Commands: &Kommandos: @@ -2116,6 +2132,14 @@ Weiterführende Informationen befinden sich in /etc/sysctl.d/10-ptrace.conf Breakpoint at "%1" Haltepunkt bei "%1" + + Specifying the module (base name of the library or executable) for function or file type breakpoints can significantly speed up debugger startup times (CDB, LLDB). + Die Angabe des Moduls (Basisname der Bibliothek oder der ausführbaren Datei) für Haltepunkte des Typs Datei/Zeile oder Funktion kann die Startzeit des Debuggers erheblich reduzieren (CDB, LLDB). + + + Debugger commands to be executed when the breakpoint is hit. This feature is only available for GDB. + Debugger-Kommandos, die beim Auslösen eines Haltepunkts ausgeführt werden (nur GDB). + Function Funktion @@ -2624,7 +2648,7 @@ Sie haben die Wahl zu warten oder das Debuggen abzubrechen. Eine mögliche Ursache ist die begrenzte Pfadlänge in Core-Dateien. - Try to specify the binary in Debug > Start Debugging > Attach to Core. + Try to specify the binary in Debug > Start Debugging > Load Core File. Bitte geben Sie den Namen der ausführbaren Datei im Dialog Debuggen > Debuggen > Core-Datei auswählen an. @@ -4682,6 +4706,14 @@ Jetzt Commit ausführen? Would you like to create a local branch? Möchten Sie einen lokalen Branch erstellen? + + Nothing to recover + Nichts wiederherzustellen + + + Files recovered + Dateien wiederhergestellt + Cannot obtain log of "%1": %2 Das Log von "%1" konnte nicht erhalten werden: %2 @@ -5197,6 +5229,10 @@ Jetzt Commit ausführen? Fixup Previous Commit... Vorangehenden Commit verbessern... + + Recover Deleted Files + Gelöschte Dateien wiederherstellen + Abort Merge Merge abbrechen @@ -6903,8 +6939,8 @@ Außer: %2 Alt+Y - Filter Files - Dateien filtern + Options + Einstellungen @@ -6961,15 +6997,15 @@ Außer: %2 Current directory - Arbeitsordner + Arbeitsverzeichnis Directory - Ordner + Verzeichnis Projects Directory - Projektordner + Projektverzeichnis Save all files before build @@ -7055,14 +7091,14 @@ Außer: %2 Same Build Directory Gleiches Build-Verzeichnis - - Limit build output to - Begrenze Build-Ausgabe auf - Limit application output to Ausgabe der Anwendung begrenzen auf + + Limit build output to + Begrenze Build-Ausgabe auf + ProjectExplorer::Internal::ProjectFileWizardExtension @@ -7681,10 +7717,6 @@ Möchten Sie sie ignorieren? Duplicate File... Datei duplizieren... - - Diff Against Current File - Mit aktueller Datei vergleichen - Ctrl+T Ctrl+T @@ -10418,10 +10450,22 @@ Sie können die Änderungen in einem Stash ablegen oder zurücksetzen.Show Hidden Files Versteckte Dateien zeigen + + The file "%1" was renamed to "%2", but the following projects could not be automatically changed: %3 + Die Datei "%1" wurde in "%2" umbenannt, aber die folgenden Projekte konnten nicht automatisch geändert werden: %3 + + + Show Bread Crumbs + Breadcrumb-Navigation anzeigen + Synchronize with Editor Mit Editor synchronisieren + + The following projects failed to automatically remove the file: %1 + Die folgenden Projekte konnten die Datei nicht automatisch entfernen: %1 + Open Project in "%1" Projekt in "%1" öffnen @@ -10526,13 +10570,6 @@ Sie können die Änderungen in einem Stash ablegen oder zurücksetzen.Ausführung: <b>%1</b><br/> - - ProjectExplorer::ProjectConfiguration - - Clone of %1 - Kopie von %1 - - ProjectExplorer @@ -10623,6 +10660,14 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML. QmlDesigner::NavigatorWidget + + Navigator + Navigator + + + Project + Projekt + Navigator Title of navigator view @@ -10711,7 +10756,7 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML. Find Usages - Verwendung suchen + Verwendungen suchen QML @@ -10817,10 +10862,6 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML.qmake "%1" is not an executable. qmake "%1" ist keine ausführbare Datei. - - No qmlviewer installed. - Es ist kein qmlviewer installiert. - Desktop Qt Version is meant for the desktop @@ -10944,10 +10985,6 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML.Qt version is too old. Die Qt-Version ist zu alt. - - Device type is not desktop. - Der Gerätetyp ist nicht "Desktop". - No Qt version set in kit. Im Kit ist keine Qt-Version gesetzt. @@ -10955,19 +10992,18 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML. QmlProjectManager::QmlProjectRunConfiguration - - No qmlviewer or qmlscene found. - Es konnten weder qmlviewer noch qmlscene gefunden werden. - QML Scene QMLRunConfiguration display name. QML Scene - QML Viewer - QMLRunConfiguration display name. - QML-Betrachter + No qmlscene found. + qmlscene nicht gefunden. + + + No qmlscene binary specified for target device. + Für das Zielgerät ist keine ausführbare qmlscene-Datei angegeben. No script file to execute. @@ -10976,10 +11012,6 @@ Dies ist unabhängig vom Wert der Eigenschaft "visible" in QML. QmlProjectManager::Internal::QmlProjectRunConfigurationFactory - - QML Viewer - QML-Betrachter - QML Scene QML Scene @@ -11244,16 +11276,6 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins: ProjectExplorer::BuildConfiguration - - Build - Display name of the build build step list. Used as part of the labels in the project window. - Build - - - Clean - Display name of the clean build step list. Used as part of the labels in the project window. - Bereinigen - Build Settings Build-Einstellungen @@ -12468,17 +12490,6 @@ Flags: %3 There is no CDB executable specified. Es wurde keine ausführbare Datei für CDB angegeben. - - Internal error: The extension %1 cannot be found. -If you have updated Qt Creator via Maintenance Tool, you may need to rerun the Tool and select "Add or remove components" and then select the -Qt > Tools > Qt Creator > Qt Creator CDB Debugger Support component. -If you build Qt Creator from sources and want to use a CDB executable with another bitness than your Qt Creator build, -you will need to build a separate CDB extension with the same bitness as the CDB you want to use. - Interner Fehler: Die Erweiterung %1 wurde nicht gefunden. -Wenn Sie Qt Creator mit dem Maintenance Tool aktualisiert haben, müssen Sie dieses vielleicht erneut ausführen, "Komponenten hinzufügen oder entfernen" auswählen und die Komponente Qt > Tools > Qt Creator CDB Debugger Support auswählen. -Wenn Sie Qt Creator aus den Quelltexten erstellen und eine ausführbare CDB-Datei mit einer anderen Architektur (32 bit, 64 bit) verwenden wollen als der Qt Creator, den Sie erstellen, -müssen Sie eine separate CDB-Erweiterung mit der gleichen Architektur wie diese CDB-Datei erstellen. - Interrupting is not possible in remote sessions. Das Unterbrechen ist bei entferntem Debuggen nicht möglich. @@ -12507,6 +12518,14 @@ müssen Sie eine separate CDB-Erweiterung mit der gleichen Architektur wie diese Malformed stop response received. Es wurde eine ungültige Stop-Antwort erhalten. + + Internal error: The extension %1 cannot be found. +If you have updated %2 via Maintenance Tool, you may need to rerun the Tool and select "Add or remove components" and then select the Qt > Tools > Qt Creator CDB Debugger Support component. +If you build %2 from sources and want to use a CDB executable with another bitness than your %2 build, you will need to build a separate CDB extension with the same bitness as the CDB you want to use. + Interner Fehler: Die Erweiterung %1 wurde nicht gefunden. +Wenn Sie %2 mit dem Maintenance Tool aktualisiert haben, müssen Sie dieses vielleicht erneut ausführen, "Komponenten hinzufügen oder entfernen" auswählen und die Komponente Qt > Tools > Qt Creator CDB Debugger Support auswählen. +Wenn Sie %2 aus den Quelltexten erstellen und eine ausführbare CDB-Datei mit einer anderen Architektur (32 Bit, 64 Bit) verwenden wollen als %2, müssen Sie eine separate CDB-Erweiterung mit der gleichen Architektur wie diese CDB-Datei erstellen. + Switching to main thread... Wechsel zu Haupt-Thread... @@ -12691,6 +12710,7 @@ wenn es außerhalb von git bash aufgerufen wird. ProjectExplorer::DeployConfigurationFactory Deploy Configuration + Display name of the default deploy configuration Deployment-Konfiguration @@ -13331,7 +13351,7 @@ Sie werden möglicherweise gebeten, den Inhalt dieses Logs mitzuteilen, wenn Sie Expected integer after colon. - Nach dem Doppelpunkt wird ein Ganzzahlwert erwartet. + Nach dem Doppelpunkt wird ein ganzzahliger Wert erwartet. Expected array of strings after colon. @@ -13359,7 +13379,7 @@ Sie werden möglicherweise gebeten, den Inhalt dieses Logs mitzuteilen, wenn Sie Expected integer. - Ganzzahlwert erwartet. + Ganzzahliger Wert erwartet. Expected object literal after colon. @@ -13675,10 +13695,6 @@ konnte nicht unter Versionsverwaltung (%2) gestellt werden &Threads &Threads - - Locals and &Expressions - Lokale Variablen und &Ausdrücke - Continue Fortsetzen @@ -13807,6 +13823,14 @@ konnte nicht unter Versionsverwaltung (%2) gestellt werden Source Files Quelldateien + + Locals + Lokale Variablen + + + &Expressions + &Ausdrücke + Snapshots Snapshots @@ -14020,6 +14044,10 @@ Soll es noch einmal versucht werden? Ignore whitespace only changes. Änderungen der Leerzeichen nicht berücksichtigen. + + Reload + Neu laden + Ignore Whitespace Leerzeichen nicht berücksichtigen @@ -14120,6 +14148,34 @@ Soll es noch einmal versucht werden? Library search input hint text <Filter> + + Add New Resources... + Neue Ressourcen hinzufügen... + + + Add new resources to project. + Neue Ressourcen zum Projekt hinzufügen. + + + Add import %1 + Import %1 hinzufügen + + + Add Resources + Ressourcen hinzufügen + + + Target Directory + Zielverzeichnis + + + Failed to Add File + Datei konnte nicht hinzugefügt werden + + + Could not add %1 to project. + %1 konnte nicht zum Projekt hinzugefügt werden. + QmlDesigner::StatesEditorModel @@ -14144,8 +14200,9 @@ Soll es noch einmal versucht werden? QmlDesigner::StatesEditorView - States Editor - States-Editor + States + Der Plural von "Status" ist "Status": https://de.wiktionary.org/wiki/Status + States base state @@ -14380,7 +14437,7 @@ Lokale Commits werden nicht zum Master-Branch gepusht, bis ein normaler Commit e By default, push will fail if the target directory exists, but does not already have a control directory. This flag will allow push to proceed. - Normalerweise schlägt eine Branch-Operation fehl, wenn der Zielordner vorhanden ist und keinen Versionskontroll-Ordner hat. + Normalerweise schlägt eine push-Operation fehl, wenn das Zielverzeichnis vorhanden ist, aber keinen Versionskontroll-Ordner hat. Die Einstellung gestattet es, unter diesem Umständen fortzusetzen. @@ -16822,12 +16879,12 @@ Soll es noch einmal versucht werden? RemoteLinux::RemoteLinuxRunConfiguration %1 (on Remote Device) - %1 (auf Mobilgerät) + %1 (auf anderem Gerät) Run on Remote Device Remote Linux run configuration default display name - Auf Mobilgerät ausführen + Auf anderem Gerät ausführen @@ -16953,10 +17010,47 @@ When a problem is detected, the application is interrupted and can be debugged.< Die Speicheranalyse mit Valgrind und GDB benutzt das Programm "memcheck", um Speicherlecks zu finden. Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersucht werden. + + Heob + Heob + + + Ctrl+Alt+H + Ctrl+Alt+H + Valgrind Memory Analyzer (External Application) Speicheranalyse mit Valgrind (externe Anwendung) + + Heob: No local run configuration available. + Heob: Keine lokale Ausführungskonfiguration verfügbar. + + + Heob: No toolchain available. + Heob: Keine Toolchain verfügbar. + + + Heob: No executable set. + Heob: Keine ausführbare Datei angegeben. + + + Heob: Cannot find %1. + Heob: Kann %1 nicht finden. + + + The %1 executables must be in the appropriate location. + Die ausführbaren %1-Dateien müssen am richtigen Ort liegen. + + + Heob used with MinGW projects needs the %1 DLLs for proper stacktrace resolution. + Für MinGW-Projekte braucht Heob die %1-DLLs zur korrekten Stacktrace-Auflösung. + + + Heob: Cannot create %1 process (%2). + Avoiding "heob64.exe-Prozess" + Heob: Kann Prozess %1 nicht erzeugen (%2). + A Valgrind Memcheck analysis is still in progress. Ein Valgrind Speichertest läuft noch. @@ -16986,17 +17080,17 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Memcheck: Fehler beim Auswerten der Valgrind-Ausgabe: %1 - Memory Analyzer Tool finished, %n issues were found. + Memory Analyzer Tool finished. %n issues were found. - Das Speicheranalysewerkzeug wurde beendet; ein Problem wurde gefunden. - Das Speicheranalysewerkzeug wurde beendet; %n Probleme wurde gefunden. + Das Speicheranalysewerkzeug wurde beendet. Ein Problem wurde gefunden. + Das Speicheranalysewerkzeug wurde beendet. %n Probleme wurde gefunden. - Log file processed, %n issues were found. + Log file processed. %n issues were found. - Die Logdatei wurde verarbeitet; ein Problem wurde gefunden. - Die Logdatei wurde verarbeitet; %n Probleme wurden gefunden. + Die Logdatei wurde verarbeitet. Ein Problem wurde gefunden. + Die Logdatei wurde verarbeitet. %n Probleme wurden gefunden. @@ -17351,8 +17445,8 @@ Zusätzlich wird die Verbindung zum Gerät getestet. RemoteLinux::Internal::RemoteLinuxRunConfigurationFactory - (on Remote Generic Linux Host) - (auf entferntem generischem Linux-Host) + %1 (on Remote Generic Linux Host) + %1 (auf entferntem generischem Linux-Host) @@ -18143,17 +18237,6 @@ Außer: %3 Nach Aktualisierungen suchen - - ProjectExplorer::SettingsAccessor - - Unsupported Shared Settings File - Nicht unterstützte .shared-Einstellungsdatei - - - The version of your .shared file is not supported by %1. Do you want to try loading it anyway? - Diese Version der .shared-Datei wird nicht von %1 unterstützt. Möchten Sie sie trotzdem laden? - - RemoteLinux::GenericRemoteLinuxCustomCommandDeploymentStep @@ -18625,7 +18708,7 @@ Diese Präfixe werden zusätzlich zum Dateinamen beim Wechseln zwischen Header- Debugger::Internal::StartRemoteEngineDialog Start Remote Engine - Entfernten Engine starten + Entfernte Engine starten &Host: @@ -19085,10 +19168,6 @@ Gibt an, wie sich die Rücktaste bezüglich Einrückung verhält. Animate navigation within file Navigation innerhalb einer Datei animieren - - Annotations next to lines - Anmerkungen neben Zeilen anzeigen - Next to editor content Neben Editorinhalt @@ -19101,6 +19180,14 @@ Gibt an, wie sich die Rücktaste bezüglich Einrückung verhält. Aligned at right side Rechtsbündig + + Line annotations + Zeilenannotationen + + + Between lines + Zwischen den Zeilen + TextEditor::Internal::HighlighterSettingsPage @@ -19656,6 +19743,10 @@ should a repository require SSH-authentication (see documentation on SSH and the Show textual graph log. Zeigt Graph als Text an. + + Reload + Neu laden + ProjectExplorer::Internal::ProjectListWidget @@ -19719,13 +19810,6 @@ should a repository require SSH-authentication (see documentation on SSH and the Suche in Anleitungen... - - QmlJSEditor::AddAnalysisMessageSuppressionComment - - Add a Comment to Suppress This Message - Fügen Sie einen Kommentar ein, um diese Nachricht zu unterdrücken - - QmlJSEditor::Internal::Operation @@ -20344,25 +20428,6 @@ should a repository require SSH-authentication (see documentation on SSH and the SDK-Manager - - Core::RemoveFileDialog - - Remove File - Datei entfernen - - - File to remove: - Zu entfernende Dateien: - - - &Delete file permanently - Datei dauerhaft &löschen - - - &Remove from Version Control - Aus Versionskontrolle &entfernen - - ProjectExplorer::Internal::DeviceFactorySelectionDialog @@ -20799,13 +20864,6 @@ should a repository require SSH-authentication (see documentation on SSH and the Deployment auf Android-Gerät - - Android::Internal::AndroidDeployConfigurationFactory - - Deploy on Android - Deployment auf Android-Gerät - - Android::Internal::AndroidDeviceFactory @@ -21447,21 +21505,6 @@ gehören nicht zu den verifizierten Remotes in %3. Anderen Ordner angeben?Gerät: - - QmlProfiler::Internal::QmlProfilerClientManager - - Debug connection opened - Debug-Verbindung geöffnet - - - Debug connection closed - Debug-Verbindung geschlossen - - - Debug connection failed - Debug-Verbindung gescheitert - - QmlProfiler::Internal::QmlProfilerStateWidget @@ -22023,8 +22066,8 @@ hinzufügen, um dem QML-Editor den wahrscheinlichen URI mitzuteilen.Ge&ladene Version - <html><head/><body><p><b>Note: You will not be able to check in this file without merging the changes (not supported by the plugin)</b></p></body></html> - <html><head/><body><p><b>Hinweis: Diese Datei kann nicht ohne Mergen der Änderungen eingecheckt werden (durch das Plugin nicht unterstützt)</b></p></body></html> + Note: You will not be able to check in this file without merging the changes (not supported by the plugin) + Hinweis: Diese Datei kann nicht ohne Mergen der Änderungen eingecheckt werden (durch das Plugin nicht unterstützt) @@ -22952,6 +22995,10 @@ Sie können hier eine andere Verbindung wählen, beispielsweise eine serielle Ve The installation location of the current Qt version's plugins. Das Installationsverzeichnis für Plugins der aktuellen Qt-Version. + + The installation location of the current Qt version's QML files. + Das Installationsverzeichnis für QML-Dateien der aktuellen Qt-Version. + The installation location of the current Qt version's imports. Das Installationsverzeichnis für Imports der aktuellen Qt-Version. @@ -23553,8 +23600,8 @@ Entfernt: %4 Position zurücksetzen und implizite Position verwenden. - Fill selected item to parent. - Elternelement mit ausgewähltem Element ausfüllen. + Fill selected item to parent. + Elternelement mit ausgewähltem Element ausfüllen. Reset anchors for selected item. @@ -23662,6 +23709,10 @@ Entfernt: %4 Invalid type %1 Ungültiger Typ %1 + + Unknown property for Imports %1 + Unbekannte Eigenschaft für Imports %1 + Unknown property for Type %1 Unbekannte Eigenschaft für Typ %1 @@ -23784,10 +23835,6 @@ Entfernt: %4 Select All "%1" Alles auswählen "%1" - - Toggle States Editor - States-Editor ein-/ausblenden - Switch Text/Design Zwischen Text und Design umschalten @@ -23796,6 +23843,10 @@ Entfernt: %4 &Restore Default View Vo&rgabe wiederherstellen + + Toggle States + States ein-/ausblenden + Toggle &Left Sidebar &Linke Seitenleiste umschalten @@ -24909,6 +24960,32 @@ Weitere Informationen finden Sie auf der Dokumentationsseite "Checking Code Number of commits between %1 and %2: %3 Anzahl der Commits zwischen %1 und %2: %3 + + Checked - Mark change as WIP. +Unchecked - Mark change as ready for review. +Partially checked - Do not change current state. + Markiert - Änderung als "WIP" markieren. +Nicht markiert - Änderung als bereit zur Prüfung markieren. +Teilmarkiert - Zustand nicht verändern. + + + Checked - Mark change as private. +Unchecked - Remove mark. +Partially checked - Do not change current state. + Markiert - Änderung als privat markieren. +Nicht markiert - Markierung entfernen. +Teilmarkiert - Zustand nicht verändern. + + + Supported on Gerrit 2.15 and later. + Unterstützt von Gerrit 2.15 und höher. + + + Checked - The change is a draft. +Unchecked - The change is not a draft. + Markiert - Die Änderung ist ein Entwurf. +Nicht markiert - Die Änderung ist kein Entwurf. + No remote branches found. This is probably the initial commit. Keine Branches im Remote-Repository gefunden. Dies ist wahrscheinlich der erste Commit. @@ -24921,10 +24998,6 @@ Weitere Informationen finden Sie auf der Dokumentationsseite "Checking Code ... Include older branches ... ... Ältere Branches einschließen ... - - &Draft - &Entwurf - &Topic: &Topic: @@ -24965,6 +25038,14 @@ Teilnamen können verwendet werden, sofern sie eindeutig sind. To: Nach: + + &Draft/private + &Entwurf/privat + + + &Work-in-progress + &In Arbeit + ProjectExplorer::DesktopDeviceConfigurationWidget @@ -25644,6 +25725,10 @@ Teilnamen können verwendet werden, sofern sie eindeutig sind. QbsProjectManager::Internal::QbsRunConfigurationWidget + + Add library paths to run environment + Bibliothekspfade zur Ausführungsumgebung hinzufügen + <unknown> <unbekannt> @@ -26264,10 +26349,6 @@ Bitte schließen Sie alle laufenden Instanzen Ihrer Anwendung vor dem Erstellen. Form Form - - Clang Code Model Warnings - Clang Codemodell-Warnungen - <i>The Clang Code Model is enabled because the corresponding plugin is loaded.</i> <i>Das Clang Codemodell ist aktiv, weil das entsprechende Plugin geladen ist.</i> @@ -26300,6 +26381,10 @@ Bitte schließen Sie alle laufenden Instanzen Ihrer Anwendung vor dem Erstellen. Ignore precompiled headers Vorkompilierte Header-Dateien nicht beachten + + Clang Diagnostics + Clang-Diagnose + Ios::Internal::IosBuildStep @@ -26385,6 +26470,32 @@ Bitte schließen Sie alle laufenden Instanzen Ihrer Anwendung vor dem Erstellen. Sets the letter spacing for the font. Gibt den Buchstabenabstand für die Schrift an. + + Performance + Leistung + + + Kerning + Unterschneidung + + + Enables or disables the kerning OpenType feature when shaping the text. Disabling this may improve performance when creating or changing the text, at the expense of some cosmetic features. The default value is true. + Aktiviert oder deaktiviert beim Zeichnen des Texts die Unterschneidung von OpenType. Dies zu deaktivieren kann die Geschwindigkeit beim Erstellen oder Ändern des Tests erhöhen, aber das Aussehen verschlechtern. Standardmäßig ist es aktiviert. + + + Sometimes, a font will apply complex rules to a set of characters in order to display them correctly. +In some writing systems, such as Brahmic scripts, this is required in order for the text to be legible, whereas in Latin script, + it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features +when they are not required, which will improve performance in most cases. + Manchmal wendet ein Font komplexe Regeln auf Zeichen an, um sie korrekt anzuzeigen. +In manchen Schriftsystemem, beispielsweise Brahmi, wäre Text sonst nicht lesbar, während es in Latin-Schriften nur der +Verschönerung dient. Die preferShaping-Eigenschaft auf "false" zu setzen deaktiviert diese Funktionalität, wenn sie nicht +benötigt wird, was meist die Geschwindigkeit erhöht. + + + Prefer shaping + Shaping bevorzugen + StandardTextSection @@ -26424,6 +26535,14 @@ Bitte schließen Sie alle laufenden Instanzen Ihrer Anwendung vor dem Erstellen. Specifies how the font size of the displayed text is determined. Legt fest wie die Schriftgröße des angezeigten Texts bestimmt wird. + + Line height + Zeilenhöhe + + + Sets the line height for the text. + Gibt die Zeilenhöhe für den Text an. + TextInputSpecifics @@ -26637,13 +26756,6 @@ Möchten Sie das vorhandene Paket deinstallieren? Der dSYM %1 scheint veraltet zu sein, dies kann den Debugger stören. - - Ios::Internal::IosDeployConfiguration - - Deploy to iOS - Deployment auf iOS - - Ios::Internal::IosDeployConfigurationFactory @@ -26885,10 +26997,6 @@ Möchten Sie das vorhandene Paket deinstallieren? DebugBreakProcess failed: DebugBreakProcess schlug fehl: - - %1 does not exist. If you built Qt Creator yourself, check out https://code.qt.io/cgit/qt-creator/binary-artifacts.git/. - %1 existiert nicht. Wenn Sie Qt Creator selbst erstellt haben, checken Sie bitte auch das Repository https://code.qt.io/cgit/qt-creator/binary-artifacts.git/ aus. - could not break the process. konnte den Prozess nicht anhalten. @@ -26901,6 +27009,10 @@ Möchten Sie das vorhandene Paket deinstallieren? Cannot interrupt process with pid %1: %2 Der Prozess mit der PID %1 konnte nicht unterbrochen werden: %2 + + %1 does not exist. If you built %2 yourself, check out https://code.qt.io/cgit/qt-creator/binary-artifacts.git/. + %1 existiert nicht. Wenn Sie %2 selbst erstellt haben, checken Sie bitte auch https://code.qt.io/cgit/qt-creator/binary-artifacts.git/ aus. + Cannot start %1. Check src\tools\win64interrupt\win64interrupt.c for more information. %1 konnte nicht gestartet werden. Für weiterführende Informationen siehe auch src\tools\win64interrupt\win64interrupt.c. @@ -26950,6 +27062,10 @@ Möchten Sie das vorhandene Paket deinstallieren? Select all kits Alle Kits auswählen + + Type to filter kits by name... + Kits nach Namen filtern... + Select Kits for Your Project Kits des Projekts einrichten @@ -27186,10 +27302,6 @@ Möchten Sie das vorhandene Paket deinstallieren? Could not get inferior PID. Die Prozess-ID des zu debuggenden Prozesses konnte nicht bestimmt werden. - - Could not get necessary ports the debugger connection. - Auf die für die Debugger-Verbindung notwendigen Ports konnte nicht zugegriffen werden. - Run failed. The settings in the Organizer window of Xcode might be incorrect. Die Ausführung schlug fehl: Möglicherweise sind die Einstellungen im Fenster "Organizer" von Xcode fehlerhaft. @@ -27620,9 +27732,9 @@ Möchten Sie das vorhandene Paket deinstallieren? 32-bit-Version - <html><body><p>Specify the path to the <a href="%1">Windows Console Debugger executable</a> (%2) here.</p></body></html> + Specify the path to the <a href="%1">Windows Console Debugger executable</a> (%2) here. Label text for path configuration. %2 is "x-bit version". - <html><body><p>Geben Sie hier den Pfad zur ausführbaren Datei des <a href="%1">Windows Console Debuggers</a> (%2) an.</p></body></html> + Geben Sie hier den Pfad zur ausführbaren Datei des <a href="%1">Windows Console Debuggers</a> (%2) an. @@ -27919,6 +28031,10 @@ Weder der Pfad zur Bibliothek noch der Pfad zu den Headerdateien wird zur .pro-D QML Debugging QML-Debuggen + + QMake Configuration + QMake-Konfiguration + The option will only take effect if the project is recompiled. Do you want to recompile now? Diese Einstellung wird nur nach einer Neuerstellung des Projekts wirksam. Möchten Sie das Projekt neu erstellen? @@ -30301,8 +30417,8 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.Die Ausgabe-Hilfsbibliothek wird benutzt um bestimmte Datentypen wie QString oder std::map in &quot;Lokale Variablen und Ausdrücke&quot; ansprechend anzuzeigen. - <html><head/><body><p>Python commands entered here will be executed after built-in debugging helpers have been loaded and fully initialized. You can load additional debugging helpers or modify existing ones here.</p></body></html> - <html><head/><body><p>Hier angegebene Python-Kommandos werden ausgeführt, nachdem die integrierte Ausgabe-Hilfsbibliothek geladen und vollständig initialisiert wurde. Sie können hier weitere Ausgabehelfer laden oder bereits existierende Ausgabehelfer ändern.</p></body></html> + Python commands entered here will be executed after built-in debugging helpers have been loaded and fully initialized. You can load additional debugging helpers or modify existing ones here. + Hier angegebene Python-Kommandos werden ausgeführt, nachdem die integrierte Ausgabe-Hilfsbibliothek geladen und vollständig initialisiert wurde. Sie können hier weitere Ausgabehelfer laden oder bereits existierende Ausgabehelfer ändern. Extra Debugging Helpers @@ -30645,6 +30761,22 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer. Utils::SettingsAccessor + + Failed to Read File + Datei konnte nicht gelesen werden + + + Could not open "%1". + "%1" kann nicht geöffnet werden. + + + Failed to Write File + Datei konnte nicht geschrieben werden + + + There was nothing to write. + Es sind keine Daten zu schreiben. + No Valid Settings Found Keine gültigen Einstellungen gefunden @@ -30661,16 +30793,13 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.<p>The versioned backup "%1" of the settings file is used, because the non-versioned file was created by an incompatible version of %2.</p><p>Settings changes made since the last time this version of %2 was used are ignored, and changes made now will <b>not</b> be propagated to the newer version.</p> <p>Das versionierte Backup "%1" der Einstellungsdatei wird verwendet, da die nicht versionierte Datei von einer inkompatiblen Version von %2 erstellt wurde.</p><p>Änderungen der Projekteinstellungen, die nach der letzten Verwendung dieser Version von %2 für dieses Projekt gemacht wurden, werden verworfen; jetzt vorgenommene Änderungen werden <b>nicht</b> auf die neue Version angewandt.</p> - - - ProjectExplorer::EnvironmentIdAccessor - <p>No .user settings file created by this instance of %1 was found.</p><p>Did you work with this project on another machine or using a different settings path before?</p><p>Do you still want to load the settings file "%2"?</p> - <p>Es konnte keine .user-Einstellungsdatei gefunden werden, die mit dieser Instanz von %1 erstellt wurde.</p><p>Haben Sie mit diesem Projekt auf einem anderen Computer gearbeitet oder einen anderen Pfad für die Einstellungen verwendet?</p><p>Möchten Sie die Einstellungsdatei "%2" trotzdem laden?</p> + Unsupported Shared Settings File + Nicht unterstützte gemeinsam genutzte Einstellungsdatei - Settings File for "%1" from a different Environment? - Einstellungsdatei für "%1" aus anderer Umgebung? + The version of your .shared file is not supported by %1. Do you want to try loading it anyway? + Diese Version der .shared-Datei wird nicht von %1 unterstützt. Möchten Sie sie trotzdem laden? @@ -30735,7 +30864,7 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer. PuppetCreator - Puppet is starting ... + Puppet is starting... Puppet wird gestartet... @@ -30763,8 +30892,8 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.Kit ist ungültig - The QML emulation layer (QML Puppet) cannot be built because the kit is not configured correctly. For example the compiler can be misconfigured. Fix the kit configuration and restart Qt Creator. Otherwise, the fallback emulation layer, which does not support all features, will be used. - Die QML-Emulationsschicht (QML Puppet) kann nicht erstellt werden, weil das Kit nicht korrekt konfiguriert ist. Beispielsweise könnte ein falscher Compiler eingestellt sein. Berichtigen Sie die Kit-Konfiguration und starten Sie Qt Creator neu. Sonst wird die Fallback QML-Emulationsschicht benutzt, die nicht alle Funktionen bietet. + The QML emulation layer (QML Puppet) cannot be built because the kit is not configured correctly. For example the compiler can be misconfigured. Fix the kit configuration and restart %1. Otherwise, the fallback emulation layer, which does not support all features, will be used. + Die QML-Emulationsschicht (QML Puppet) kann nicht erstellt werden, weil das Kit nicht korrekt konfiguriert ist. Beispielsweise könnte ein falscher Compiler eingestellt sein. Berichtigen Sie die Kit-Konfiguration und starten Sie %1 neu. Sonst wird die Fallback QML-Emulationsschicht benutzt, die nicht alle Funktionen bietet. @@ -31034,10 +31163,6 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.Open package location after build Paketverzeichnis nach dem Erstellen öffnen - - Qt Deployment - Deployment von Qt - Uses the external Ministro application to download and maintain Qt libraries. Verwendet die externe Ministro-Anwendung, um die Qt-Bibliotheken herunterzuladen und zu verwalten. @@ -31046,14 +31171,6 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.Use Ministro service to install Qt Verwende den Ministro-Dienst, um Qt zu installieren - - Creates a standalone APK. - Eigenständiges APK erstellen. - - - Bundle Qt libraries in APK - Qt-Bibliotheken in APK einpacken - Packages debug server with the APK to enable debugging. For the signed APK this option is unchecked by default. Schließt einen Debug-Server im APK-Paket ein um Debugging zu ermöglichen. Für ein signiertes APK ist diese Option standardmäßig abgewählt. @@ -31208,8 +31325,8 @@ Bitte installieren Sie ein Android-SDK der API-Version %1 oder neuer.Die installierte SDK-Tools-Version (%1) enthält keine Gradle-Skripte. Die Mindestversion von Qt für Gradle-Builds ist %2 - The minimum Qt version required for Gradle build to work is %2. It is recommended to install the latest Qt version. - Die älteste Qt-Version, die Gradle-Builds unterstützt ist %2. Es ist ratsam, die neueste Qt-Version zu verwenden. + The minimum Qt version required for Gradle build to work is %1. It is recommended to install the latest Qt version. + Die älteste Qt-Version, die Gradle-Builds unterstützt, ist %1. Es ist ratsam, die neueste Qt-Version zu verwenden. The API level set for the APK is less than the minimum required by the kit. @@ -32573,11 +32690,6 @@ Wählt eine für Desktop-Entwicklung geeignete Qt-Version aus, sofern sie verfü Qt 5.8 Qt 5.8 - - Use Qt Virtual Keyboard. - Using "Qt Virtual Keyboard" as a proper name. - Qt Virtual Keyboard verwenden. - Default Vorgabe @@ -32651,10 +32763,6 @@ Wählt eine für Desktop-Entwicklung geeignete Qt-Version aus, sofern sie verfü Qt Test Qt Test - - Googletest - Googletest - GUI Application GUI-Anwendung @@ -32731,6 +32839,22 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw Use Qt Virtual Keyboard Qt Virtual Keyboard verwenden + + Google Test + Google Test + + + Qt Quick Test + Qt Quick Test + + + Creates a scratch model using a temporary file. + Erzeugt ein Modell in einer temporären Datei. + + + Scratch Model + Modellentwurf + Creates a Qt Canvas 3D QML project, optionally including three.js. Erzeugt ein Qt Canvas 3D QML-Projekt. Dieses kann three.js verwenden. @@ -33359,18 +33483,6 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw Field has no name. Feld hat keinen Namen. - - Label data is not an object. - Label data ist kein Objekt. - - - No text given for Label. - Kein Text für Beschriftung angegeben. - - - Spacer data is not an object. - Spacer data ist kein Objekt. - Line Edit Validator Expander Line Edit Validator Expander @@ -33392,20 +33504,68 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw Beim Auswerten des Feldes "%1": %2 - "factor" is no integer value. - "factor" ist kein Ganzzahlwert. + Label ("%1") data is not an object. + Label ("%1") data ist kein Objekt. - LineEdit data is not an object. - LineEdit data ist kein Objekt. + Label ("%1") has no trText. + Label ("%1") hat kein trText. - Invalid regular expression "%1" in "validator". - Ungültiger regulärer Ausdruck "%1" in "validator". + Spacer ("%1") data is not an object. + Spacer ("%1") data ist kein Objekt. - TextEdit data is not an object. - TextEdit data ist kein Objekt. + Spacer ("%1") property "factor" is no integer value. + Spacer ("%1") Eigenschaft "factor" ist kein ganzzahliger Wert. + + + LineEdit ("%1") data is not an object. + LineEdit ("%1") data ist kein Objekt. + + + LineEdit ("%1") has an invalid regular expression "%2" in "validator". + LineEdit ("%1") hat einen ungültigen regulären Ausdruck "%2" in "validator". + + + TextEdit ("%1") data is not an object. + TextEdit ("%1") data ist kein Objekt. + + + CheckBox ("%1") data is not an object. + CheckBox ("%1") data ist kein Objekt. + + + CheckBox ("%1") values for checked and unchecked state are identical. + CheckBox ("%1")-Werte für checked- und unchecked-Status sind indentisch. + + + No JSON lists allowed inside List items. + In List-Elementen sind keine JSON-Listen erlaubt. + + + No "key" found in List items. + Kein "key" in List-Elementen gefunden. + + + %1 ("%2") data is not an object. + %1 ("%2") data ist kein Objekt. + + + %1 ("%2") "index" is not an integer value. + %1 ("%2") "index" ist kein ganzzahliger Wert. + + + %1 ("%2") "disabledIndex" is not an integer value. + %1 ("%2") "disabledIndex" ist kein ganzzahliger Wert. + + + %1 ("%2") "items" missing. + %1 ("%2") "items" fehlt. + + + %1 ("%2") "items" is not a JSON list. + %1 ("%2") "items" ist keine JSON-Liste. PathChooser data is not an object. @@ -33413,47 +33573,7 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw kind "%1" is not one of the supported "existingDirectory", "directory", "file", "saveFile", "existingCommand", "command", "any". - Wert "%1" von "kind" ist keines der unterstützten 'existingDirectory', 'directory', 'file', 'saveFile', 'existingCommand', 'command', 'any'. - - - No "key" found in ComboBox items. - Kein "key" in ComboBox-Elementen gefunden. - - - ComboBox "index" is not an integer value. - ComboBox "index" ist kein Ganzzahlwert. - - - ComboBox "disabledIndex" is not an integer value. - ComboBox "disabledIndex" ist kein Ganzzahlwert. - - - ComboBox "items" missing. - Combox "items" fehlt. - - - ComboBox "items" is not a list. - ComboBox "items" ist keine Liste. - - - Internal Error: ComboBox items lists got mixed up. - Interner Fehler: ComboBox-Elementliste ist durcheinander geraten. - - - CheckBox data is not an object. - CheckBox data ist kein Objekt. - - - CheckBox values for checked and unchecked state are identical. - CheckBox-Werte für checked- und unchecked-Status sind indentisch. - - - No lists allowed inside ComboBox items list. - In ComboBox items-Listen sind keine Listen erlaubt. - - - ComboBox data is not an object. - ComboBox data ist kein Objekt. + Wert von "kind" "%1" ist keiner der unterstützten "existingDirectory", "directory", "file", "saveFile", "existingCommand", "command", "any". Files data list entry is not an object. @@ -33668,6 +33788,10 @@ konnte dem Projekt "%2" nicht hinzugefügt werden. The environment setting value is invalid. Der Wert der Umgebungseinstellung ist ungültig. + + Environment + Umgebung + ProjectExplorer::Internal::KitEnvironmentConfigWidget @@ -33738,35 +33862,6 @@ konnte dem Projekt "%2" nicht hinzugefügt werden. Quellverzeichnis - - QmakeAndroidSupport::Internal::AndroidPackageInstallationFactory - - Deploy to device - Deployment auf Gerät - - - - QmakeAndroidSupport::Internal::AndroidPackageInstallationStep - - Copy application data - Anwendungsdaten kopieren - - - Removing directory %1 - Lösche Verzeichnis %1 - - - - QmakeAndroidSupport::Internal::AndroidPackageInstallationStepWidget - - <b>Make install</b> - <b>Make install</b> - - - Make install - Make install - - QmakeAndroidSupport::Internal::NoApplicationProFilePage @@ -33931,6 +34026,10 @@ Die Dateien aus dem Quellverzeichnis des Android-Pakets werden in das Verzeichni TextEditor::TextDocument + + Diff Against Current File + Mit aktueller Datei vergleichen + Opening File Öffne Datei @@ -35186,10 +35285,6 @@ Senden selbst auch Zeit benötigt. Debugging has failed Debuggen schlug fehl - - Setup failed. - Die Initialisierung schlug fehl. - Loading finished. Laden beendet. @@ -35610,25 +35705,13 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl &Delete &Löschen - - Model Editor - Modell Editor - Export Diagram... Diagramm exportieren... - Zoom In - Vergrößern - - - Zoom Out - Verkleinern - - - Reset Zoom - Vergrößerung zurücksetzen + Export Selected Elements... + Ausgewählte Elemente exportieren... Open Parent Diagram @@ -35651,8 +35734,12 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Canvasdiagramm hinzufügen - Synchronize Browser and Diagram<br><i><small>Press&Hold for options</small></i> - Browser und Diagramm synchronisieren<br><i><small>Gedrückt halten für Optionen</small></i> + Synchronize Browser and Diagram + Browser und Diagramm synchronisieren + + + Press && Hold for Options + Gedrückt halten für Optionen Edit Element Properties @@ -35677,22 +35764,6 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl <html><body style="color:#909090; font-size:14px"><div align='center'><div style="font-size:20px">Open a diagram</div><table><tr><td><hr/><div style="margin-top: 5px">&bull; Double-click on diagram in model tree</div><div style="margin-top: 5px">&bull; Select "Open Diagram" from package's context menu in model tree</div></td></tr></table></div></body></html> <html><body style="color:#909090; font-size:14px"><div align='center'><div style="font-size:20px">Diagramm öffnen</div><table><tr><td><hr/><div style="margin-top: 5px">&bull; Doppelklick auf ein Diagramm im Baum</div><div style="margin-top: 5px">&bull; Wählen Sie "Diagramm öffnen" aus dem Kontextmenü eines Pakets im Baum</div></td></tr></table></div></body></html> - - Add Package - Paket hinzufügen - - - Add Component - Komponente hinzufügen - - - Add Class - Klasse hinzufügen - - - Add Canvas Diagram - Canvasdiagramm hinzufügen - Synchronize Structure with Diagram Struktur gemäß Diagramm aktualisieren @@ -35717,6 +35788,18 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Export Diagram Diagramm exportieren + + Export Selected Elements + Ausgewählte Elemente exportieren + + + Exporting Selected Elements Failed + Ausgewählte Elemente konnten nicht exportiert werden + + + Exporting the selected elements of the current diagram into file<br>"%1"<br>failed. + Die ausgewählten Elemente des aktuellen Diagramms konnten nicht in die Datei <br>"%1"<br> exportiert werden. + Exporting Diagram Failed Fehler in Diagrammexport @@ -35725,22 +35808,42 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Exporting the diagram into file<br>"%1"<br>failed. Der Export des Diagramms in die Datei<br>"%1"<br>ist fehlgeschlagen. + + New %1 + Neu %1 + Package Paket + + New Package + Neues Paket + Component Komponente + + New Component + Neue Komponente + Class Klasse + + New Class + Neue Klasse + Item Element + + New Item + Neues Element + Annotation Annotation @@ -35862,7 +35965,7 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl ProjectExplorer::Internal::WaitForStopDialog Waiting for Applications to Stop - Warte auf Beendung laufender Anwendungen + Warte auf Beendigung laufender Anwendungen Cancel @@ -35870,7 +35973,7 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Waiting for applications to stop. - Warte auf Beendung laufender Anwendungen. + Warte auf Beendigung laufender Anwendungen. @@ -36600,7 +36703,7 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Go to Block Start - Zum Blockanfang gehen + Zum Blockanfang springen Ctrl+[ @@ -36608,7 +36711,7 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Go to Block End - Zum Blockende gehen + Zum Blockende springen Ctrl+] @@ -36634,45 +36737,53 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Select Word Under Cursor Wort unter Einfügemarke auswählen + + Go to Document Start + Zu Dokumentanfang springen + + + Go to Document End + Zu Dokumentende springen + Go to Line Start - Gehe zum Zeilenanfang + Zum Zeilenanfang springen Go to Line End - Gehe zum Zeilenende + Zum Zeilenende springen Go to Next Line - Gehe zur nächsten Zeile + Zur nächsten Zeile springen Go to Previous Line - Gehe zur vorhergehenden Zeile + Zur vorhergehenden Zeile springen Go to Previous Character - Gehe zum vorhergehenden Zeichen + Zum vorhergehenden Zeichen springen Go to Next Character - Gehe zum nächsten Zeichen + Zum nächsten Zeichen springen Go to Previous Word - Gehe zum vorhergehenden Wort + Zum vorhergehenden Wort springen Go to Next Word - Gehe zum nächsten Wort + Zum nächsten Wort springen Go to Previous Word Camel Case - Gehe zum vorhergehenden Wort (Camel Case) + Zum vorhergehenden Wort springen (Camel Case) Go to Next Word Camel Case - Gehe zum nächsten Wort (Camel Case) + Zum nächsten Wort springen (Camel Case) Go to Line Start with Selection @@ -36914,6 +37025,18 @@ Warnung: Dies ist eine experimentelle Funktion und könnte dazu führen, dass di Process arguments Argumente verarbeiten + + Framework + Framework + + + Group + Gruppe + + + Enables grouping of test cases. + Erlaubt das Gruppieren von Tests. + ClangCodeModel::Internal::ClangProjectSettingsWidget @@ -37023,10 +37146,6 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Form Formular - - Configuration to use: - Verwende Konfiguration: - Copy... Kopieren... @@ -37035,10 +37154,6 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Remove Entfernen - - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - Für passende Optionen lesen Sie das GCC oder Clang Handbuch oder auch die <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC-Onlinedokumentation</a>. - Copy Diagnostic Configuration Diagnosekonfiguration kopieren @@ -37055,6 +37170,10 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Option "%1" is invalid. Option "%1" ist ungültig. + + Copy this configuration to customize it. + Kopieren Sie diese Konfiguration, um sie anzupassen. + Configuration passes sanity checks. https://de.wikipedia.org/wiki/Sanity_Check @@ -37065,12 +37184,24 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu %1 - ValidationIcon - ValidationIcon + Clang + Clang - ValidationText - ValidationText + Clang-Tidy + Clang-Tidy + + + Clazy + Clazy + + + InfoIcon + InfoIcon + + + InfoText + InfoText @@ -37366,6 +37497,10 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Outline Kontur + + Flat + Flach + Emphasized Hervorgehoben @@ -37463,8 +37598,8 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Swimlanes - <font color=red>Invalid syntax.</font> - <font color=red>Fehlerhafte Syntax.</font> + Invalid syntax. + Ungültige Syntax. Multi-Selection @@ -37504,30 +37639,14 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Create Connection Verbindung herstellen - - New Package - Neues Paket - - - New Component - Neue Komponente - - - New Class - Neue Klasse - - - New Item - Neues Element - - - New %1 - Neu %1 - Drop Element Element fallen lassen + + Add Related Element + Zugehöriges Element hinzufügen + Add Element Element hinzufügen @@ -37547,6 +37666,10 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Run &All Tests Starte &alle Tests + + Run All Tests + Alle Tests starten + Alt+Shift+T,Alt+A Alt+Shift+T,Alt+A @@ -37555,6 +37678,10 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu &Run Selected Tests Sta&rte ausgewählte Tests + + Run Selected Tests + Ausgewählte Tests starten + Alt+Shift+T,Alt+R Alt+Shift+T,Alt+R @@ -37736,14 +37863,6 @@ Allerdings führt die Anwendung der weniger strikten und erweiterten Regeln dazu Expand All Alles aufklappen - - Run All Tests - Alle Tests starten - - - Run Selected Tests - Ausgewählte Tests starten - Stop Test Run Testlauf anhalten @@ -37919,10 +38038,6 @@ Maybe raise the timeout? Der Testfall wurde aufgrund einer Zeitüberschreitung abgebrochen. Gegebenenfalls sollten Sie das Zeitlimit erhöhen. - - <unknown> - <unbekannt> - No test cases left for execution. Canceling test run. Es sind keine Tests ausführbar. Der Testlauf wird abgebrochen. @@ -38331,12 +38446,12 @@ Bitte wählen Sie eine korrekte ausführbare Clang-Datei. Generator: %1<br>Zusätzlicher Generator: %2 - <br>Platform: %1 - <br>Plattform: %1 + Platform: %1 + Plattform: %1 - <br>Toolset: %1 - <br>Toolset: %1 + Toolset: %1 + Toolset: %1 CMake Generator @@ -38432,33 +38547,6 @@ Bitte wählen Sie eine korrekte ausführbare Clang-Datei. Die Themenänderung wird nach einem Neustart sichtbar. - - TextEditor::QuickFixFactory - - Create Getter and Setter Member Functions - Getter- und Setter-Funktionen erstellen - - - Create Getter Member Function - Getter-Funktion erstellen - - - Create Setter Member Function - Setter-Funktion erstellen - - - Convert to Stack Variable - In Stack-Variable umwandeln - - - Convert to Pointer - In Zeiger umwandeln - - - Generate Missing Q_PROPERTY Members - Fehlende Q_PROPERTY-Elemente erzeugen - - ClangDiagnosticConfigsModel @@ -38753,6 +38841,70 @@ Sie werden erhalten. Main Program Hauptprogramm + + Callee + Aufgerufene Funktion + + + Callee Description + Bescheibung der aufgerufenen Funktion + + + Caller + Aufrufende Funktion + + + Caller Description + Beschreibung der aufrufenden Funktion + + + Calls + Aufrufe + + + Details + Details + + + Location + Ort + + + Longest Time + Längste Dauer + + + Mean Time + Durchschnittliche Dauer + + + Self Time + Eigene Dauer + + + Self Time in Percent + Eigene Dauer in Prozent + + + Shortest Time + Kürzeste Dauer + + + Time in Percent + Dauer in Prozent + + + Total Time + Gesamtdauer + + + Type + Typ + + + Median Time + Mediandauer + +%1 in recursive calls +%1 in rekursiven Aufrufen @@ -39091,6 +39243,10 @@ Sie werden erhalten. Same Size Gleiche Größe + + Add Related Elements + Zugehörige Elemente hinzufügen + ImageViewer::Internal::ExportDialog @@ -39135,34 +39291,6 @@ Möchten Sie sie überschreiben? ImageViewer::Internal::ImageViewerPlugin - - Zoom In - Vergrößern - - - Ctrl++ - Ctrl++ - - - Zoom Out - Verkleinern - - - Ctrl+- - Ctrl+- - - - Original Size - Originalgröße - - - Meta+0 - Meta+0 - - - Ctrl+0 - Ctrl+0 - Fit to Screen An Bildschirm anpassen @@ -39492,6 +39620,10 @@ Drücken Sie zusätzlich die Umschalttaste, wird ein Escape-Zeichen an der aktue Export Property as Alias Eigenschaft als Alias exportieren + + Insert Keyframe + Keyframe einfügen + Binding Editor Binding-Editor @@ -39572,22 +39704,30 @@ Drücken Sie zusätzlich die Umschalttaste, wird ein Escape-Zeichen an der aktue You will not be able to use the AutoTest plugin without having at least one active test framework. Ohne ein aktives Test-Framework können Sie das AutoTest-Plugin nicht verwenden. + + Enable or disable test frameworks to be handled by the AutoTest plugin. + Vom AutoTest-Plugin zu verwendende Test-Frameworks ein- oder ausschalten. + + + Enable or disable grouping of test cases by folder. + Gruppierung von Testfällen nach Verzeichnis ein- oder ausschalten. + Add Filter Filter hinzufügen - <p>Specify a filter expression to be added to the list of filters.<br/>Wildcards are not supported.</p> - <p>Geben Sie einen Filterausdruck an um ihn der Filterliste hinzuzufügen.<br/>Platzhalter sind nicht erlaubt.</p> + Specify a filter expression to be added to the list of filters.<br/>Wildcards are not supported. + Geben Sie einen Filterausdruck an um ihn der Filterliste hinzuzufügen.<br/>Platzhalter sind nicht erlaubt. + + + Specify a filter expression that will replace "%1".<br/>Wildcards are not supported. + Geben Sie einen Filterausdruck um "%1" zu ersetzen.<br/>Platzhalter sind nicht erlaubt. Edit Filter Filter bearbeiten - - <p>Specify a filter expression that will replace "%1".<br/>Wildcards are not supported.</p> - <p>Geben Sie einen Filterausdruck um "%1" zu ersetzen.<br/>Platzhalter sind nicht erlaubt.</p> - TestTreeItem @@ -40926,13 +41066,6 @@ Warnung: Reinem Text fehlen manche Informationen, etwa die Dauer. Simulator Start Simulator starten - - Starting simulator devices... - - Starte Simulator-Gerät... - Starte Simulator-Geräte... - - Cannot start simulator (%1, %2) in current state: %3 Der Simulator (%1, %2) kann im momentanen Zustand (%3) nicht gestartet werden. @@ -40958,10 +41091,17 @@ Error: %2 Fehler: %2 - Do you really want to reset the contents and settings of the selected devices? + Starting %n simulator device(s)... + + Starte Simulator-Gerät... + Starte %n Simulator-Geräte... + + + + Do you really want to reset the contents and settings of the %n selected device(s)? Wollen Sie die Inhalte und Einstellungen des ausgewählten Geräts zurücksetzen? - Wollen Sie die Inhalte und Einstellungen der ausgewählten Geräte zurücksetzen? + Wollen Sie die Inhalte und Einstellungen der %n ausgewählten Geräte zurücksetzen? @@ -40993,30 +41133,30 @@ Fehler: %2 Gerät entfernen - Do you really want to delete the selected devices? + Do you really want to delete the %n selected device(s)? Wollen Sie das ausgewählte Gerät entfernen? - Wollen Sie die ausgewählten Geräte entfernen? + Wollen Sie die %n ausgewählten Geräte entfernen? - Deleting simulator devices... + Deleting %n simulator device(s)... Entferne Simulator-Gerät... - Entferne Simulator-Geräte... + Entferne %n Simulator-Geräte... + + + + Capturing screenshots from %n device(s)... + + Nehme Screenshot vom Gerät auf... + Nehme Screenshots von %n Geräten auf... simulator delete Simulator entfernen - - Capturing screenshots from devices... - - Nehme Screenshot vom Gerät auf... - Nehme Screenshot von Geräten auf... - - simulator screenshot Simulator Screenshot @@ -41599,13 +41739,6 @@ Fehler: %5 Dateifehler - - Utils::SaveFile - - File might be locked. - Vielleicht ist die Datei gesperrt. - - AndroidAvdManager @@ -41983,8 +42116,8 @@ Fehler: %5 Keine Build-Artefakte - Build artifacts:<br> - Build-Artefakte:<br> + Build artifacts: + Build-Artefakte: @@ -42140,8 +42273,8 @@ Fehler: %5 Die Auswertung des CMake-Projekts ist fehlgeschlagen. - %1 in line %3 - %1 in Zeile %3 + %1 in line %2 + %1 in Zeile %2 %1 @@ -42227,8 +42360,8 @@ Fehler: %5 Pasting zu KDE Paster benötigt eine Authentifizierung.<br/>Bitte geben Sie Ihre KDE Identity-Daten ein um fortzufahren. - <span style='background-color:LightYellow;color:red'>Login failed</span><br/><br/> - <span style='background-color:LightYellow;color:red'>Anmeldung fehlgeschlagen</span><br/><br/> + Login failed + Anmeldung fehlgeschlagen @@ -42343,28 +42476,6 @@ Fehler: %5 Vom Debugger gesteuerte ausführbare Datei - - Debugger::GdbServerPortsGatherer - - Checking available ports... - Prüfe Verfügbarkeit von Ports... - - - Found %n free ports. - - Ein freier Port gefunden. - %n freie Ports gefunden. - - - - Not enough free ports on device for C++ debugging. - Auf dem Gerät sind nicht genügend freie Ports zum C++-Debuggen vorhanden. - - - Not enough free ports on device for QML debugging. - Auf dem Gerät sind nicht genügend freie Ports zum QML-Debuggen vorhanden. - - Debuggger::Internal::ModulesHandler @@ -42867,7 +42978,7 @@ Ablaufdatum: %3 Nicht entfernen - Disable Kit %1 in This Project? + Disable Kit "%1" in This Project? Kit "%1" für dieses Projekt deaktivieren? @@ -43111,7 +43222,7 @@ Bitte aktualisieren Sie Ihr Kit oder wählen Sie eine mkspec für qmake, die bes QmlDesigner::DocumentWarningWidget - Ignore always these unsupported Qt Quick Designer warnings. + Always ignore these warnings about features not supported by Qt Quick Designer. Diese Warnungen über in Qt Quick Designer nicht unterstütze Features immer ignorieren. @@ -43697,10 +43808,6 @@ Beschreibung: %4 Each state must have a unique ID. Jeder Zustand muss eine eindeutige ID haben. - - Missing ID - Fehlende ID - Missing ID. Fehlende ID. @@ -43905,10 +44012,6 @@ Zeile: %4, Spalte: %5 Change initial state Ausgangszustand ändern - - Relayout - Neu anordnen - ScxmlEditor::PluginInterface::StateWarningItem @@ -44485,12 +44588,20 @@ Außer Leerzeichen innerhalb von Kommentaren und Zeichenketten. Unterstreichung der Kontexte von Warnungen. - Declaration - Deklaration + Function Declaration + Funktionsdeklaration - Declaration of a function, variable, and so on. - Deklaration einer Funktion, Variable oder vergleichbarem. + Style adjustments to (function) declarations. + Stilanpassungen für (Funktions-)Deklarationen. + + + Function Definition + Funktionsdefinition + + + Name of function at its definition. + Name einer Funktion in ihrer Definition. Output Argument @@ -44660,6 +44771,10 @@ Außer Leerzeichen innerhalb von Kommentaren und Zeichenketten. Quit Beenden + + %1 has crashed + %1 ist abgestürzt + We specifically send the following information: @@ -44954,8 +45069,8 @@ Breche ausstehende Operationen ab... Ausführungskonfiguration auswählen - Could not determine which run configuration to choose for running tests (%1) - Es konnte nicht bestimmt werden, welche Ausführungskonfiguration zum Ausführen von Tests (%1) gewählt werden soll + Could not determine which run configuration to choose for running tests + Es konnte nicht bestimmt werden, welche Ausführungskonfiguration zum Ausführen von Tests gewählt werden soll Run Configuration: @@ -45067,4 +45182,557 @@ Breche ausstehende Operationen ab... Verarbeite Unterschiede + + Utils::RemoveFileDialog + + Remove File + Datei entfernen + + + File to remove: + Zu entfernende Datei: + + + &Delete file permanently + Datei endgültig &löschen + + + &Remove from version control + Aus &Versionskontrolle entfernen + + + + CppTools::ClazyChecks + + Form + Formular + + + Each level adds checks to the previous level. For more information, see <a href="https://github.com/KDE/clazy">clazy's homepage</a>. + Jede Stufe fügt der niedrigeren Prüfungen hinzu. Weitere Informationen finden Sie auf der <a href="https://github.com/KDE/clazy">Homepage von Clazy</a>. + + + Disabled + Deaktiviert + + + Level 0: No false positives + Stufe 0: Keine Fehlalarme + + + Level 1: Very few false positives + Stufe 1: Sehr wenige Fehlalarme + + + Level 2: More false positives + Stufe 2: Mehr Fehlalarme + + + Not always correct, possibly very noisy, might require a knowledgeable developer to review, might have a very big rate of false-positives, might have bugs. + Nicht immer korrekt, möglicherweise sehr viele Meldungen, könnte die Prüfung durch einen erfahrenen Entwickler benötigen, könnte eine sehr hohe Rate von Fehlalarmen haben, könnte Fehler enthalten. + + + Level 3: Experimental checks + Stufe 3: Experimentelle Prüfungen + + + + CppTools::TidyChecks + + Form + Formular + + + + ProcessCreator + + Executable does not exist: %1 + Ausführbare Datei existiert nicht: %1 + + + Unknown error occurred. + Ein unbekannter Fehler ist aufgetreten. + + + Process crashed. + Der Prozess ist abgestürzt. + + + Process failed at startup. + Der Prozess konnte nicht gestartet werden. + + + Process timed out. + Der Prozess brauchte zu lange. + + + Cannot write to process. + Zum Prozess kann nicht geschrieben werden. + + + Cannot read from process. + Vom Prozess kann nicht gelesen werden. + + + + QmlDebug::QmlDebugConnectionManager + + Debug connection opened. + Debug-Verbindung geöffnet. + + + Debug connection closed. + Debug-Verbindung geschlossen. + + + Debug connection failed. + Debug-Verbindung gescheitert. + + + + Utils::EnvironmentIdAccessor + + <p>No .user settings file created by this instance of %1 was found.</p><p>Did you work with this project on another machine or using a different settings path before?</p><p>Do you still want to load the settings file "%2"?</p> + <p>Es konnte keine .user-Einstellungsdatei gefunden werden, die mit dieser Instanz von %1 erstellt wurde.</p><p>Haben Sie mit diesem Projekt auf einem anderen Computer gearbeitet oder einen anderen Pfad für die Einstellungen verwendet?</p><p>Möchten Sie die Einstellungsdatei "%2" trotzdem laden?</p> + + + Settings File for "%1" from a Different Environment? + Einstellungsdatei für "%1" aus anderer Umgebung? + + + + Android::AndroidPackageInstallationStep + + Copy application data + Anwendungsdaten kopieren + + + Removing directory %1 + Lösche Verzeichnis %1 + + + + Android::Internal::AndroidPackageInstallationStepWidget + + Make install + Make install + + + + Android::Internal::AndroidPackageInstallationFactory + + Deploy to device + Deployment auf Gerät + + + + Autotest::Internal::TestOutputReader + + Test executable crashed. + Die ausführbare Datei des Tests ist abgestürzt. + + + + Bookmarks::Internal::BookmarkFilter + + Bookmarks + Lesezeichen + + + + ClangHoverHandler + + %1 bytes + %1 Bytes + + + + Core::Internal::JavaScriptFilter + + Evaluate JavaScript + JavaScript auswerten + + + Reset Engine + Engine zurücksetzen + + + Engine aborted after timeout. + Engine brach nach Zeitüberschreitung ab. + + + Copy to clipboard: %1 + In die Zwischenablage kopieren: %1 + + + + Core::Internal::MenuBarFilter + + Actions from the Menu + Aktionen aus dem Menü + + + + QObject + + C++ Usages: + C++-Verwendungen: + + + + CppEditor::CppQuickFixFactory + + Create Getter and Setter Member Functions + Getter- und Setter-Funktionen erstellen + + + Create Getter Member Function + Getter-Funktion erstellen + + + Create Setter Member Function + Setter-Funktion erstellen + + + Convert to Stack Variable + In Stack-Variable umwandeln + + + Convert to Pointer + In Zeiger umwandeln + + + Generate Missing Q_PROPERTY Members + Fehlende Q_PROPERTY-Elemente erzeugen + + + + ProjectExplorer::BuildStepList + + Build + Display name of the build build step list. Used as part of the labels in the project window. + Erstellen + + + Clean + Display name of the clean build step list. Used as part of the labels in the project window. + Bereinigen + + + + AndroidPackageInstallationFactory + + Deploy to device + Deployment auf Gerät + + + + QmlDesignerAddResources + + Image Files + Bilddateien + + + + AddAnalysisMessageSuppressionComment + + Add a Comment to Suppress This Message + Fügen Sie einen Kommentar ein, um diese Nachricht zu unterdrücken + + + + QmlJS Code Model Marks + + Code Model Warning + Codemodell-Warnung + + + Code Model Error + Codemodell-Fehler + + + + RemoteLinux::RemoteLinuxKillAppService + + Trying to kill "%1" on remote device... + Versuche "%1" auf anderem Gerät zu beenden... + + + Remote application killed. + Anwendung auf anderem Gerät beendet. + + + Failed to kill remote application. Assuming it was not running. + Anwendung auf anderem Gerät konnte nicht beendet werden. Vermutlich lief sie nicht. + + + + RemoteLinux::RemoteLinuxKillAppStep + + Kill current application instance + Aktuelle Instanz der Anwendung beenden + + + + Valgrind::Internal::HeobDialog + + XML output file: + XML-Ausgabedatei: + + + Handle exceptions: + Ausnahmen behandeln: + + + Off + Aus + + + On + An + + + Only + Nur + + + Page protection: + Seitenschutz: + + + After + Danach + + + Before + Davor + + + Freed memory protection + Schutz freigegebenen Speichers + + + Raise breakpoint exception on error + Bei Fehler Haltepunktausnahme auslösen + + + Leak details: + Speicherleck-Details: + + + None + Keine + + + Simple + Einfach + + + Detect Leak Types + Speicherleck-Typen erkennen + + + Detect Leak Types (Show Reachable) + Speicherleck-Typen erkennen (erreichbare anzeigen) + + + Fuzzy Detect Leak Types + Speicherleck-Typen "fuzzy" erkennen + + + Fuzzy Detect Leak Types (Show Reachable) + Speicherleck-Typen "fuzzy" erkennen (erreichbare anzeigen) + + + Minimum leak size: + Speicherleck-Mindestgröße: + + + Control leak recording: + Speicherleck-Aufzeichnung steuern: + + + On (Start Disabled) + An (Deaktiviert starten) + + + On (Start Enabled) + An (Aktiviert starten) + + + Run with debugger + Mit Debugger ausführen + + + Extra arguments: + Zusätzliche Argumente: + + + Heob path: + Heob-Pfad: + + + The location of heob32.exe and heob64.exe. + Der Pfad zu heob32.exe und heob64.exe. + + + Save current settings as default. + Aktuelle Einstellungen als Vorgabe speichern. + + + OK + OK + + + Heob + Heob + + + + Valgrind::Internal::HeobData + + Process %1 + Prozess %1 + + + Process finished with exit code %1 (0x%2). + Der Prozess endete mit dem Rückgabewert %1 (0x%2). + + + Unknown argument: -%1 + Unbekanntes Argument: -%1 + + + Cannot create target process. + Zielprozess kann nicht erzeugt werden. + + + Wrong bitness. + Falsche Bitness. + + + Process killed. + Prozess beendet. + + + Only works with dynamically linked CRT. + Funktioniert nur mit dynamisch gelinktem CRT. + + + Process stopped with unhandled exception code 0x%1. + Prozess endete mit unbehandeltem Ausnahme-Code 0x%1. + + + Not enough memory to keep track of allocations. + Nicht genug Speicher um Allokationen aufzuzeichnen. + + + Application stopped unexpectedly. + Die Anwendung stoppte unerwartet. + + + Extra console. + Extrakonsole. + + + Unknown exit reason. + Grund der Beendigung unbekannt. + + + Heob stopped unexpectedly. + Heob stoppte unerwartet. + + + Heob: %1 + Heob: %1 + + + Heob: Failure in process attach handshake (%1). + Heob: Fehler im Handshake beim Verbinden zum Prozess (%1). + + + + CppTools::ClangBaseChecks + + Form + Formular + + + For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. + Für passende Optionen lesen Sie das GCC- oder Clang-Handbuch oder auch die <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC-Onlinedokumentation</a>. + + + + TextEditor::Internal::Snippets + + + Snippets are text fragments that can be inserted into an editor via the usual completion mechanics using a trigger text. The translated text (trigger variant) is used to disambiguate between snippets with the same trigger. + + + + derived from QObject + group:'C++' trigger:'class' + von QObject abgeleitet + + + derived from QWidget + group:'C++' trigger:'class' + von QWidget abgeleitet + + + template + group:'C++' trigger:'class' + template + + + with if + group:'C++' trigger:'else' + mit if + + + and else + group:'C++' trigger:'if' + und else + + + and catch + group:'C++' trigger:'try' + und catch + + + namespace + group:'C++' trigger:'using' + namespace + + + template + group:'C++' trigger:'struct' + template + + + with targets + group:'QML' trigger:'NumberAnimation' + mit mehreren target-Items + + + with target + group:'QML' trigger:'NumberAnimation' + mit einem target-Item + + + with targets + group:'QML' trigger:'PropertyAction' + mit mehreren target-Items + + + with target + group:'QML' trigger:'PropertyAction' + mit einem target-Item + + + example + group:'Text' trigger:'global' + Beispiel + + diff --git a/src/libs/flamegraph/qml/FlameGraphDetails.qml b/src/libs/flamegraph/qml/FlameGraphDetails.qml index 2f1110090ab..99ff3989b6e 100644 --- a/src/libs/flamegraph/qml/FlameGraphDetails.qml +++ b/src/libs/flamegraph/qml/FlameGraphDetails.qml @@ -155,14 +155,20 @@ Item { property int minimumWidth: { // max(width of longest label * 2, minimumInnerWidth) var result = minimumInnerWidth; - for (var i = 0; i < children.length; i += 2) - result = Math.max(children[i].implicitWidth * 2 + innerMargin, result); + for (var i = 0; i < children.length; ++i) { + if (children[i].isLabel) + result = Math.max(children[i].implicitWidth * 2 + innerMargin, result); + } + return result + 2 * outerMargin; } + property int labelWidth: (minimumWidth - innerMargin) / 2 - outerMargin + property int valueWidth: dragHandle.x - labelWidth - innerMargin - outerMargin + onMinimumWidthChanged: { - if (dragHandle.x < minimumWidth) - dragHandle.x = minimumWidth; + if (dragHandle.x < minimumWidth - outerMargin) + dragHandle.x = minimumWidth - outerMargin; } Repeater { @@ -171,8 +177,7 @@ Item { property bool isLabel: index % 2 === 0 font.bold: isLabel elide: Text.ElideRight - width: (text === "" || isLabel) - ? implicitWidth : (dragHandle.x - col.minimumWidth / 2 - innerMargin) + width: isLabel ? col.labelWidth : col.valueWidth text: isLabel ? (modelData + ":") : modelData color: contentTextColor } @@ -213,7 +218,7 @@ Item { MouseArea { anchors.fill: parent drag.target: parent - drag.minimumX: col.minimumWidth + drag.minimumX: col.minimumWidth - outerMargin drag.axis: Drag.XAxis cursorShape: Qt.SizeHorCursor } diff --git a/src/libs/timeline/qml/Detail.qml b/src/libs/timeline/qml/Detail.qml index 63668a78a66..e184bde3246 100644 --- a/src/libs/timeline/qml/Detail.qml +++ b/src/libs/timeline/qml/Detail.qml @@ -28,7 +28,8 @@ import QtQuick 2.1 TimelineText { property bool isLabel: false property int valueWidth: 170 + property int labelWidth: implicitWidth font.bold: isLabel elide: Text.ElideRight - width: text === "" ? 0 : (isLabel ? implicitWidth : valueWidth) + width: text === "" ? 0 : (isLabel ? labelWidth : valueWidth) } diff --git a/src/libs/timeline/qml/RangeDetails.qml b/src/libs/timeline/qml/RangeDetails.qml index f47e9e4c046..803a0526f0d 100644 --- a/src/libs/timeline/qml/RangeDetails.qml +++ b/src/libs/timeline/qml/RangeDetails.qml @@ -173,27 +173,35 @@ Item { //details Grid { + property int outerMargin: 10 + property int minimumWidth: 150 + property int labelWidth: (minimumWidth - spacing) / 2 - outerMargin + property int valueWidth: dragHandle.x - labelWidth - spacing - outerMargin + id: col - x: 10 + x: outerMargin y: 5 spacing: 5 columns: 2 - property int minimumWidth: 150 onChildrenChanged: { // max(width of longest label * 2, 150) var result = 150; - for (var i = 0; i < children.length; i += 2) - result = Math.max(children[i].implicitWidth * 2 + spacing, result); - minimumWidth = result + 20; - if (dragHandle.x < minimumWidth) - dragHandle.x = minimumWidth; + for (var i = 0; i < children.length; ++i) { + if (children[i].isLabel) + result = Math.max(children[i].implicitWidth * 2 + spacing, result); + } + + minimumWidth = result + 2 * outerMargin; + if (dragHandle.x < minimumWidth - outerMargin) + dragHandle.x = minimumWidth - outerMargin; } Repeater { model: eventInfo.ready ? eventInfo : 0 Detail { - valueWidth: (dragHandle.x - col.minimumWidth / 2 - col.spacing) + labelWidth: col.labelWidth + valueWidth: col.valueWidth isLabel: index % 2 === 0 text: (content === undefined) ? "" : (isLabel ? (content + ":") : content) } @@ -285,7 +293,7 @@ Item { MouseArea { anchors.fill: parent drag.target: parent - drag.minimumX: col.minimumWidth + drag.minimumX: col.minimumWidth - col.outerMargin drag.axis: Drag.XAxis cursorShape: Qt.SizeHorCursor } diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 0cf5461dbec..9142d3fd269 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -137,25 +137,34 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) m_avdName = info.avdname; m_serialNumber = info.serialNumber; - m_appProcessBinaries.clear(); - m_libdir = QLatin1String("lib"); + ProjectExplorer::BuildConfiguration *bc = target()->activeBuildConfiguration(); + m_filesToPull.clear(); + QString buildDir = bc ? bc->buildDirectory().toString() : QString(); + if (bc && !buildDir.endsWith("/")) { + buildDir += "/"; + } + QString linkerName("linker"); + QString libDirName("lib"); if (info.cpuAbi.contains(QLatin1String("arm64-v8a")) || info.cpuAbi.contains(QLatin1String("x86_64"))) { ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); if (tc && tc->targetAbi().wordWidth() == 64) { - m_appProcessBinaries << QLatin1String("/system/bin/app_process64"); - m_libdir += QLatin1String("64"); + m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process"; + libDirName = "lib64"; + linkerName = "linker64"; } else { - m_appProcessBinaries << QLatin1String("/system/bin/app_process32"); + m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process"; } } else { m_appProcessBinaries << QLatin1String("/system/bin/app_process32") << QLatin1String("/system/bin/app_process"); } + m_filesToPull["/system/bin/" + linkerName] = buildDir + linkerName; + m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so"; + AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); - ProjectExplorer::BuildConfiguration *bc = target()->activeBuildConfiguration(); QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); if (!version) @@ -176,7 +185,8 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) } m_command = tmp.toString(); - m_workingDirectory = bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString(); + m_workingDirectory = bc ? bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString() + : QString(); Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--verbose")); Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--output")); @@ -213,8 +223,6 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) } m_environment = bc ? bc->environment() : Utils::Environment(); - m_buildDirectory = bc ? bc->buildDirectory().toString() : QString(); - m_adbPath = AndroidConfigurations::currentConfig().adbToolPath().toString(); AndroidAvdManager avdManager; @@ -394,31 +402,18 @@ void AndroidDeployQtStep::run(QFutureInterface &fi) } emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage); - - QString localAppProcessFile = QString::fromLatin1("%1/app_process").arg(m_buildDirectory); - QFile::remove(localAppProcessFile); - - foreach (const QString &remoteAppProcessFile, m_appProcessBinaries) { + for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) { + QFile::remove(itr.value()); runCommand(m_adbPath, AndroidDeviceInfo::adbSelector(m_serialNumber) - << QLatin1String("pull") << remoteAppProcessFile - << localAppProcessFile); - if (QFileInfo::exists(localAppProcessFile)) - break; + << "pull" << itr.key() << itr.value()); + if (!QFileInfo::exists(itr.value())) { + emit addOutput(tr("Package deploy: Failed to pull \"%1\" to \"%2\".") + .arg(itr.key()) + .arg(itr.value()), OutputFormat::ErrorMessage); + } } - if (!QFileInfo::exists(localAppProcessFile)) { - returnValue = Failure; - emit addOutput(tr("Package deploy: Failed to pull \"%1\" to \"%2\".") - .arg(m_appProcessBinaries.join(QLatin1String("\", \""))) - .arg(localAppProcessFile), OutputFormat::ErrorMessage); - } - - runCommand(m_adbPath, - AndroidDeviceInfo::adbSelector(m_serialNumber) << QLatin1String("pull") - << QLatin1String("/system/") + m_libdir + QLatin1String("/libc.so") - << QString::fromLatin1("%1/libc.so").arg(m_buildDirectory)); - reportRunResult(fi, returnValue == NoError); } diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index 38ba56e12ee..fad99d545a1 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -113,11 +113,10 @@ private: Utils::FileName m_manifestName; QString m_serialNumber; - QString m_buildDirectory; QString m_avdName; QString m_apkPath; + QMap m_filesToPull; QStringList m_appProcessBinaries; - QString m_libdir; QString m_targetArch; bool m_uninstallPreviousPackage = false; diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp index 51d80a73c5c..cb10c8a4660 100644 --- a/src/plugins/bineditor/bineditorwidget.cpp +++ b/src/plugins/bineditor/bineditorwidget.cpp @@ -548,18 +548,21 @@ QRect BinEditorWidget::cursorRect() const return QRect(x, y, w, m_lineHeight); } -int BinEditorWidget::posAt(const QPoint &pos) const +Utils::optional BinEditorWidget::posAt(const QPoint &pos, bool includeEmptyArea) const { const int xoffset = horizontalScrollBar()->value(); int x = xoffset + pos.x() - m_margin - m_labelWidth; + if (!includeEmptyArea && x < 0) + return Utils::nullopt; int column = qMin(15, qMax(0,x) / m_columnWidth); const qint64 topLine = verticalScrollBar()->value(); const qint64 line = topLine + pos.y() / m_lineHeight; + // "clear text" area if (x > m_bytesPerLine * m_columnWidth + m_charWidth/2) { x -= m_bytesPerLine * m_columnWidth + m_charWidth; - for (column = 0; column < 15; ++column) { - const int dataPos = line * m_bytesPerLine + column; + for (column = 0; column < 16; ++column) { + const qint64 dataPos = line * m_bytesPerLine + column; if (dataPos < 0 || dataPos >= m_size) break; QChar qc(QLatin1Char(dataAt(dataPos))); @@ -569,9 +572,14 @@ int BinEditorWidget::posAt(const QPoint &pos) const if (x <= 0) break; } + if (!includeEmptyArea && x > 0) // right of the text area + return Utils::nullopt; } - return qMin(m_size - 1, line * m_bytesPerLine + column); + const qint64 bytePos = line * m_bytesPerLine + column; + if (!includeEmptyArea && bytePos >= m_size) + return Utils::nullopt; + return qMin(m_size - 1, bytePos); } bool BinEditorWidget::inTextArea(const QPoint &pos) const @@ -1041,7 +1049,7 @@ void BinEditorWidget::mousePressEvent(QMouseEvent *e) if (e->button() != Qt::LeftButton) return; MoveMode moveMode = e->modifiers() & Qt::ShiftModifier ? KeepAnchor : MoveAnchor; - setCursorPosition(posAt(e->pos()), moveMode); + setCursorPosition(posAt(e->pos()).value(), moveMode); setBlinkingCursorEnabled(true); if (m_hexCursor == inTextArea(e->pos())) { m_hexCursor = !m_hexCursor; @@ -1053,7 +1061,7 @@ void BinEditorWidget::mouseMoveEvent(QMouseEvent *e) { if (!(e->buttons() & Qt::LeftButton)) return; - setCursorPosition(posAt(e->pos()), KeepAnchor); + setCursorPosition(posAt(e->pos()).value(), KeepAnchor); if (m_hexCursor == inTextArea(e->pos())) { m_hexCursor = !m_hexCursor; updateLines(); @@ -1144,17 +1152,17 @@ bool BinEditorWidget::event(QEvent *e) QString BinEditorWidget::toolTip(const QHelpEvent *helpEvent) const { - int selStart = selectionStart(); - int selEnd = selectionEnd(); - int byteCount = std::min(8, selEnd - selStart + 1); + qint64 selStart = selectionStart(); + qint64 selEnd = selectionEnd(); + qint64 byteCount = std::min(8LL, selEnd - selStart + 1); // check even position against selection line by line bool insideSelection = false; - int startInLine = selStart; + qint64 startInLine = selStart; do { - const int lineIndex = startInLine / m_bytesPerLine; - const int endOfLine = (lineIndex + 1) * m_bytesPerLine - 1; - const int endInLine = std::min(selEnd, endOfLine); + const qint64 lineIndex = startInLine / m_bytesPerLine; + const qint64 endOfLine = (lineIndex + 1) * m_bytesPerLine - 1; + const qint64 endInLine = std::min(selEnd, endOfLine); const QPoint &startPoint = offsetToPos(startInLine); const QPoint &endPoint = offsetToPos(endInLine) + QPoint(m_columnWidth, 0); QRect selectionLineRect(startPoint, endPoint); @@ -1167,7 +1175,10 @@ QString BinEditorWidget::toolTip(const QHelpEvent *helpEvent) const } while (startInLine <= selEnd); if (!insideSelection) { // show popup for byte under cursor - selStart = posAt(helpEvent->pos()); + Utils::optional pos = posAt(helpEvent->pos(), /*includeEmptyArea*/false); + if (!pos) + return QString(); + selStart = pos.value(); selEnd = selStart; byteCount = 1; } diff --git a/src/plugins/bineditor/bineditorwidget.h b/src/plugins/bineditor/bineditorwidget.h index 6794a77d387..ce02c937932 100644 --- a/src/plugins/bineditor/bineditorwidget.h +++ b/src/plugins/bineditor/bineditorwidget.h @@ -29,6 +29,8 @@ #include "markup.h" #include "bineditorservice.h" +#include + #include #include #include @@ -210,7 +212,7 @@ private: QBasicTimer m_cursorBlinkTimer; void init(); - int posAt(const QPoint &pos) const; + Utils::optional posAt(const QPoint &pos, bool includeEmptyArea = true) const; bool inTextArea(const QPoint &pos) const; QRect cursorRect() const; void updateLines(); diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp index 95a39fad9b7..c5ef733d762 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp @@ -123,6 +123,7 @@ bool CMakeRunConfiguration::fromMap(const QVariantMap &map) m_executable = extraId; if (m_title.isEmpty()) m_title = extraId; + setDefaultDisplayName(m_title); } return true; diff --git a/src/plugins/diffeditor/descriptionwidgetwatcher.cpp b/src/plugins/diffeditor/descriptionwidgetwatcher.cpp new file mode 100644 index 00000000000..0e310cfbcd8 --- /dev/null +++ b/src/plugins/diffeditor/descriptionwidgetwatcher.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "descriptionwidgetwatcher.h" +#include "diffeditor.h" +#include "diffeditorcontroller.h" + +#include +#include +#include + +using namespace Core; + +namespace DiffEditor { + +DescriptionWidgetWatcher::DescriptionWidgetWatcher(DiffEditorController *controller) + : QObject(controller), m_document(controller->document()) +{ + const QList editors = DocumentModel::editorsForDocument(controller->document()); + for (auto *editor : editors) { + if (TextEditor::TextEditorWidget *widget = descriptionWidget(editor)) + m_widgets.append(widget); + } + + connect(EditorManager::instance(), &EditorManager::editorOpened, + [this](IEditor *editor) { + if (TextEditor::TextEditorWidget *widget = descriptionWidget(editor)) { + m_widgets.append(widget); + emit descriptionWidgetAdded(widget); + } + }); + + connect(EditorManager::instance(), &EditorManager::editorAboutToClose, + [this](IEditor *editor) { + if (TextEditor::TextEditorWidget *widget = descriptionWidget(editor)) { + emit descriptionWidgetRemoved(widget); + m_widgets.removeAll(widget); + } + }); +} + +QList DescriptionWidgetWatcher::descriptionWidgets() const +{ + return m_widgets; +} + +TextEditor::TextEditorWidget *DescriptionWidgetWatcher::descriptionWidget(Core::IEditor *editor) const +{ + if (Internal::DiffEditor *diffEditor = qobject_cast(editor)) { + if (diffEditor->document() == m_document) + return diffEditor->descriptionWidget(); + } + return nullptr; +} + +} // namespace DiffEditor diff --git a/src/plugins/diffeditor/descriptionwidgetwatcher.h b/src/plugins/diffeditor/descriptionwidgetwatcher.h new file mode 100644 index 00000000000..46988260fee --- /dev/null +++ b/src/plugins/diffeditor/descriptionwidgetwatcher.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "diffeditor_global.h" + +#include + +namespace Core { +class IDocument; +class IEditor; +} +namespace TextEditor { class TextEditorWidget; } + +namespace DiffEditor { + +class DiffEditorController; + +class DIFFEDITOR_EXPORT DescriptionWidgetWatcher : public QObject +{ + Q_OBJECT +public: + explicit DescriptionWidgetWatcher(DiffEditorController *controller); + QList descriptionWidgets() const; + +signals: + void descriptionWidgetAdded(TextEditor::TextEditorWidget *editor); + void descriptionWidgetRemoved(TextEditor::TextEditorWidget *editor); + +private: + TextEditor::TextEditorWidget *descriptionWidget(Core::IEditor *editor) const; + + QList m_widgets; + Core::IDocument *m_document = nullptr; +}; + +} // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index d3654d54390..6288f2405bc 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -81,22 +81,11 @@ public: virtual QSize sizeHint() const override; -signals: - void requestBranchList(); - protected: - void mouseMoveEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void setDisplaySettings(const DisplaySettings &ds) override; void setMarginSettings(const MarginSettings &ms) override; - bool findContentsUnderCursor(const QTextCursor &cursor); - void highlightCurrentContents(); - void handleCurrentContents(); - private: - QTextCursor m_currentCursor; Core::IContext *m_context; }; @@ -153,68 +142,6 @@ void DescriptionEditorWidget::setMarginSettings(const MarginSettings &ms) TextEditorWidget::setMarginSettings(MarginSettings()); } -void DescriptionEditorWidget::mouseMoveEvent(QMouseEvent *e) -{ - if (e->buttons()) { - TextEditorWidget::mouseMoveEvent(e); - return; - } - - Qt::CursorShape cursorShape; - - const QTextCursor cursor = cursorForPosition(e->pos()); - if (findContentsUnderCursor(cursor)) { - highlightCurrentContents(); - cursorShape = Qt::PointingHandCursor; - } else { - setExtraSelections(OtherSelection, QList()); - cursorShape = Qt::IBeamCursor; - } - - TextEditorWidget::mouseMoveEvent(e); - viewport()->setCursor(cursorShape); -} - -void DescriptionEditorWidget::mouseReleaseEvent(QMouseEvent *e) -{ - if (e->button() == Qt::LeftButton && !(e->modifiers() & Qt::ShiftModifier)) { - const QTextCursor cursor = cursorForPosition(e->pos()); - if (findContentsUnderCursor(cursor)) { - handleCurrentContents(); - e->accept(); - return; - } - } - - TextEditorWidget::mouseReleaseEvent(e); -} - -bool DescriptionEditorWidget::findContentsUnderCursor(const QTextCursor &cursor) -{ - m_currentCursor = cursor; - return cursor.block().text() == Constants::EXPAND_BRANCHES; -} - -void DescriptionEditorWidget::highlightCurrentContents() -{ - QTextEdit::ExtraSelection sel; - sel.cursor = m_currentCursor; - sel.cursor.select(QTextCursor::LineUnderCursor); - sel.format.setUnderlineStyle(QTextCharFormat::SingleUnderline); - const QColor textColor = TextEditorSettings::fontSettings().formatFor(C_TEXT).foreground(); - sel.format.setUnderlineColor(textColor.isValid() ? textColor : palette().color(QPalette::Foreground)); - setExtraSelections(TextEditorWidget::OtherSelection, - QList() << sel); -} - -void DescriptionEditorWidget::handleCurrentContents() -{ - m_currentCursor.select(QTextCursor::LineUnderCursor); - m_currentCursor.removeSelectedText(); - m_currentCursor.insertText("Branches: Expanding..."); - emit requestBranchList(); -} - ///////////////////////////////// DiffEditor ////////////////////////////////// DiffEditor::DiffEditor() @@ -296,8 +223,6 @@ void DiffEditor::setDocument(QSharedPointer doc) m_document = doc; - connect(m_descriptionWidget, &DescriptionEditorWidget::requestBranchList, - m_document.data(), &DiffEditorDocument::requestMoreInformation); connect(m_document.data(), &DiffEditorDocument::documentChanged, this, &DiffEditor::documentHasChanged); connect(m_document.data(), &DiffEditorDocument::descriptionChanged, diff --git a/src/plugins/diffeditor/diffeditor.pro b/src/plugins/diffeditor/diffeditor.pro index e9cf72b7fe3..5c8c9044956 100644 --- a/src/plugins/diffeditor/diffeditor.pro +++ b/src/plugins/diffeditor/diffeditor.pro @@ -1,7 +1,9 @@ DEFINES += DIFFEDITOR_LIBRARY include(../../qtcreatorplugin.pri) -HEADERS += diffeditor_global.h \ +HEADERS += \ + descriptionwidgetwatcher.h \ + diffeditor_global.h \ diffeditor.h \ diffeditorconstants.h \ diffeditorcontroller.h \ @@ -17,7 +19,9 @@ HEADERS += diffeditor_global.h \ unifieddiffeditorwidget.h \ diffeditoricons.h -SOURCES += diffeditor.cpp \ +SOURCES += \ + descriptionwidgetwatcher.cpp \ + diffeditor.cpp \ diffeditorcontroller.cpp \ diffeditordocument.cpp \ diffeditorfactory.cpp \ diff --git a/src/plugins/diffeditor/diffeditor.qbs b/src/plugins/diffeditor/diffeditor.qbs index 1c190a8dd2d..8d0a1a1820e 100644 --- a/src/plugins/diffeditor/diffeditor.qbs +++ b/src/plugins/diffeditor/diffeditor.qbs @@ -14,6 +14,8 @@ QtcPlugin { ] files: [ + "descriptionwidgetwatcher.cpp", + "descriptionwidgetwatcher.h", "diffeditor.cpp", "diffeditor.h", "diffeditor.qrc", diff --git a/src/plugins/diffeditor/diffeditorconstants.h b/src/plugins/diffeditor/diffeditorconstants.h index c44a5fb84d7..e1c9870c980 100644 --- a/src/plugins/diffeditor/diffeditorconstants.h +++ b/src/plugins/diffeditor/diffeditorconstants.h @@ -41,7 +41,5 @@ const char UNIFIED_VIEW_ID[] = "DiffEditor.Unified"; const char G_TOOLS_DIFF[] = "QtCreator.Group.Tools.Options"; -const char EXPAND_BRANCHES[] = "Branches: "; - } // namespace Constants } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index bb2738b985d..2cf36902af5 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -65,12 +65,6 @@ bool DiffEditorController::ignoreWhitespace() const return m_document->ignoreWhitespace(); } -QString DiffEditorController::revisionFromDescription() const -{ - // TODO: This is specific for git and does not belong here at all! - return m_document->description().mid(7, 12); -} - QString DiffEditorController::makePatch(int fileIndex, int chunkIndex, PatchOptions options) const { @@ -105,18 +99,9 @@ void DiffEditorController::setDescription(const QString &description) m_document->setDescription(description); } -void DiffEditorController::branchesReceived(const QString &branches) +QString DiffEditorController::description() const { - QString tmp = m_document->description(); - tmp.replace(Constants::EXPAND_BRANCHES, branches); - m_document->setDescription(tmp); -} - -void DiffEditorController::requestMoreInformation() -{ - const QString rev = revisionFromDescription(); - if (!rev.isEmpty()) - emit requestInformationForCommit(rev); + return m_document->description(); } /** diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index e5d5ca74184..4578a7f82a6 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -51,8 +51,6 @@ public: int contextLineCount() const; bool ignoreWhitespace() const; - QString revisionFromDescription() const; - enum PatchOption { NoOption = 0, Revert = 1, @@ -65,13 +63,12 @@ public: const QString &displayName); static DiffEditorController *controller(Core::IDocument *document); - void branchesReceived(const QString &branches); void requestChunkActions(QMenu *menu, int fileIndex, int chunkIndex); bool chunkExists(int fileIndex, int chunkIndex) const; + Core::IDocument *document() const; signals: void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex); - void requestInformationForCommit(const QString &revision); protected: // reloadFinished() should be called @@ -84,14 +81,11 @@ protected: const QString &baseDirectory = QString(), const QString &startupFile = QString()); void setDescription(const QString &description); + QString description() const; void forceContextLineCount(int lines); - Core::IDocument *document() const; private: - void requestMoreInformation(); - Internal::DiffEditorDocument *const m_document; - bool m_isReloading = false; friend class Internal::DiffEditorDocument; diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 0845f3ef03c..224d63dc2b1 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -69,11 +69,6 @@ void DiffEditorDocument::setController(DiffEditorController *controller) if (m_controller) m_controller->deleteLater(); m_controller = controller; - - if (m_controller) { - connect(this, &DiffEditorDocument::requestMoreInformation, - m_controller, &DiffEditorController::requestMoreInformation); - } } DiffEditorController *DiffEditorDocument::controller() const diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h index 2a5293dfaf1..a9dff53faaf 100644 --- a/src/plugins/diffeditor/diffeditordocument.h +++ b/src/plugins/diffeditor/diffeditordocument.h @@ -90,7 +90,6 @@ signals: void temporaryStateChanged(); void documentChanged(); void descriptionChanged(); - void requestMoreInformation(); private: void beginReload(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index cc346783d4d..ffbb2852027 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -62,9 +62,14 @@ #include #include +#include #include #include #include + +#include +#include + #include #include @@ -76,8 +81,9 @@ #include #include #include -#include +#include #include +#include const char GIT_DIRECTORY[] = ".git"; const char graphLogFormatC[] = "%h %d %an %s %ci"; @@ -112,6 +118,153 @@ const unsigned silentFlags = unsigned(VcsCommand::SuppressCommandLogging | VcsCommand::SuppressStdErr | VcsCommand::SuppressFailMessage); +static QString branchesDisplay(const QString &prefix, QStringList *branches, bool *first) +{ + const int limit = 12; + const int count = branches->count(); + int more = 0; + QString output; + if (*first) + *first = false; + else + output += QString(sizeof(BRANCHES_PREFIX) - 1, ' '); // Align + output += prefix + ": "; + // If there are more than 'limit' branches, list limit/2 (first limit/4 and last limit/4) + if (count > limit) { + const int leave = limit / 2; + more = count - leave; + branches->erase(branches->begin() + leave / 2 + 1, branches->begin() + count - leave / 2); + (*branches)[leave / 2] = "..."; + } + output += branches->join(", "); + //: Displayed after the untranslated message "Branches: branch1, branch2 'and %n more'" + // in git show. + if (more > 0) + output += ' ' + GitClient::tr("and %n more", 0, more); + return output; +} + +class DescriptionWidgetDecorator : public QObject +{ + Q_OBJECT +public: + DescriptionWidgetDecorator(DescriptionWidgetWatcher *watcher); + + bool eventFilter(QObject *watched, QEvent *event) override; + +signals: + void branchListRequested(); + +private: + bool checkContentsUnderCursor(const QTextCursor &cursor) const; + void highlightCurrentContents(TextEditor::TextEditorWidget *textEditor, + const QTextCursor &cursor); + void handleCurrentContents(const QTextCursor &cursor); + void addWatch(TextEditor::TextEditorWidget *widget); + void removeWatch(TextEditor::TextEditorWidget *widget); + + DescriptionWidgetWatcher *m_watcher; + QHash m_viewportToTextEditor; +}; + +DescriptionWidgetDecorator::DescriptionWidgetDecorator(DescriptionWidgetWatcher *watcher) + : QObject(), + m_watcher(watcher) +{ + QList widgets = m_watcher->descriptionWidgets(); + for (auto *widget : widgets) + addWatch(widget); + + connect(m_watcher, &DescriptionWidgetWatcher::descriptionWidgetAdded, + this, &DescriptionWidgetDecorator::addWatch); + connect(m_watcher, &DescriptionWidgetWatcher::descriptionWidgetRemoved, + this, &DescriptionWidgetDecorator::removeWatch); +} + +bool DescriptionWidgetDecorator::eventFilter(QObject *watched, QEvent *event) +{ + TextEditor::TextEditorWidget *textEditor = m_viewportToTextEditor.value(watched); + if (!textEditor) + return QObject::eventFilter(watched, event); + + if (event->type() == QEvent::MouseMove) { + QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->buttons()) + return QObject::eventFilter(watched, event); + + Qt::CursorShape cursorShape; + + const QTextCursor cursor = textEditor->cursorForPosition(mouseEvent->pos()); + if (checkContentsUnderCursor(cursor)) { + highlightCurrentContents(textEditor, cursor); + cursorShape = Qt::PointingHandCursor; + } else { + textEditor->setExtraSelections(TextEditor::TextEditorWidget::OtherSelection, + QList()); + cursorShape = Qt::IBeamCursor; + } + + bool ret = QObject::eventFilter(watched, event); + textEditor->viewport()->setCursor(cursorShape); + return ret; + } else if (event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast(event); + + if (mouseEvent->button() == Qt::LeftButton && !(mouseEvent->modifiers() & Qt::ShiftModifier)) { + const QTextCursor cursor = textEditor->cursorForPosition(mouseEvent->pos()); + if (checkContentsUnderCursor(cursor)) { + handleCurrentContents(cursor); + return true; + } + } + + return QObject::eventFilter(watched, event); + } + return QObject::eventFilter(watched, event); +} + +bool DescriptionWidgetDecorator::checkContentsUnderCursor(const QTextCursor &cursor) const +{ + return cursor.block().text() == Constants::EXPAND_BRANCHES; +} + +void DescriptionWidgetDecorator::highlightCurrentContents( + TextEditor::TextEditorWidget *textEditor, const QTextCursor &cursor) +{ + QTextEdit::ExtraSelection sel; + sel.cursor = cursor; + sel.cursor.select(QTextCursor::LineUnderCursor); + sel.format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + const QColor textColor = TextEditor::TextEditorSettings::fontSettings().formatFor(TextEditor::C_TEXT).foreground(); + sel.format.setUnderlineColor(textColor.isValid() ? textColor : textEditor->palette().color(QPalette::Foreground)); + textEditor->setExtraSelections(TextEditor::TextEditorWidget::OtherSelection, + QList() << sel); +} + +void DescriptionWidgetDecorator::handleCurrentContents(const QTextCursor &cursor) +{ + QTextCursor copy = cursor; + + copy.select(QTextCursor::LineUnderCursor); + copy.removeSelectedText(); + copy.insertText("Branches: Expanding..."); + emit branchListRequested(); +} + +void DescriptionWidgetDecorator::addWatch(TextEditor::TextEditorWidget *widget) +{ + m_viewportToTextEditor.insert(widget->viewport(), widget); + widget->viewport()->installEventFilter(this); +} + +void DescriptionWidgetDecorator::removeWatch(TextEditor::TextEditorWidget *widget) +{ + widget->viewport()->removeEventFilter(this); + m_viewportToTextEditor.remove(widget->viewport()); +} + +/////////////////////////////// + class GitDiffEditorController : public VcsBaseDiffEditorController { Q_OBJECT @@ -124,13 +277,75 @@ protected: QStringList addConfigurationArguments(const QStringList &args) const; QStringList addHeadWhenCommandInProgress() const; + +private: + void updateBranchList(); + + DescriptionWidgetWatcher m_watcher; + DescriptionWidgetDecorator m_decorator; }; GitDiffEditorController::GitDiffEditorController(IDocument *document, const QString &workingDirectory) : - VcsBaseDiffEditorController(document, GitPlugin::client(), workingDirectory) + VcsBaseDiffEditorController(document, GitPlugin::client(), workingDirectory), + m_watcher(this), + m_decorator(&m_watcher) { + connect(&m_decorator, &DescriptionWidgetDecorator::branchListRequested, + this, &GitDiffEditorController::updateBranchList); } +void GitDiffEditorController::updateBranchList() +{ + const QString revision = description().mid(7, 12); + if (revision.isEmpty()) + return; + + const QString workingDirectory = baseDirectory(); + VcsCommand *command = GitPlugin::client()->vcsExec( + workingDirectory, {"branch", noColorOption, "-a", "--contains", revision}, nullptr, + false, 0, workingDirectory); + connect(command, &VcsCommand::stdOutText, [this](const QString &text) { + const QString remotePrefix = "remotes/"; + const QString localPrefix = ""; + const int prefixLength = remotePrefix.length(); + QString output = BRANCHES_PREFIX; + QStringList branches; + QString previousRemote = localPrefix; + bool first = true; + for (const QString &branch : text.split('\n')) { + const QString b = branch.mid(2).trimmed(); + if (b.isEmpty()) + continue; + if (b.startsWith(remotePrefix)) { + const int nextSlash = b.indexOf('/', prefixLength); + if (nextSlash < 0) + continue; + const QString remote = b.mid(prefixLength, nextSlash - prefixLength); + if (remote != previousRemote) { + output += branchesDisplay(previousRemote, &branches, &first) + '\n'; + branches.clear(); + previousRemote = remote; + } + branches << b.mid(nextSlash + 1); + } else { + branches << b; + } + } + if (branches.isEmpty()) { + if (previousRemote == localPrefix) + output += tr(""); + } else { + output += branchesDisplay(previousRemote, &branches, &first); + } + const QString branchList = output.trimmed(); + QString newDescription = description(); + newDescription.replace(Constants::EXPAND_BRANCHES, branchList); + setDescription(newDescription); + }); +} + +/////////////////////////////// + void GitDiffEditorController::runCommand(const QList &args, QTextCodec *codec) { VcsBaseDiffEditorController::runCommand(args, diffExecutionFlags(), codec); @@ -679,8 +894,6 @@ void GitClient::requestReload(const QString &documentId, const QString &source, connect(controller, &DiffEditorController::chunkActionsRequested, this, &GitClient::chunkActionsRequested, Qt::DirectConnection); - connect(controller, &DiffEditorController::requestInformationForCommit, - this, &GitClient::branchesForCommit); VcsBasePlugin::setSource(document, sourceCopy); EditorManager::activateEditorForDocument(document); @@ -1379,76 +1592,6 @@ void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const } } -static QString branchesDisplay(const QString &prefix, QStringList *branches, bool *first) -{ - const int limit = 12; - const int count = branches->count(); - int more = 0; - QString output; - if (*first) - *first = false; - else - output += QString(sizeof(BRANCHES_PREFIX) - 1, ' '); // Align - output += prefix + ": "; - // If there are more than 'limit' branches, list limit/2 (first limit/4 and last limit/4) - if (count > limit) { - const int leave = limit / 2; - more = count - leave; - branches->erase(branches->begin() + leave / 2 + 1, branches->begin() + count - leave / 2); - (*branches)[leave / 2] = "..."; - } - output += branches->join(", "); - //: Displayed after the untranslated message "Branches: branch1, branch2 'and %n more'" - // in git show. - if (more > 0) - output += ' ' + GitClient::tr("and %n more", 0, more); - return output; -} - -void GitClient::branchesForCommit(const QString &revision) -{ - auto controller = qobject_cast(sender()); - QString workingDirectory = controller->baseDirectory(); - VcsCommand *command = vcsExec( - workingDirectory, {"branch", noColorOption, "-a", "--contains", revision}, nullptr, - false, 0, workingDirectory); - connect(command, &VcsCommand::stdOutText, controller, [controller](const QString &text) { - const QString remotePrefix = "remotes/"; - const QString localPrefix = ""; - const int prefixLength = remotePrefix.length(); - QString output = BRANCHES_PREFIX; - QStringList branches; - QString previousRemote = localPrefix; - bool first = true; - for (const QString &branch : text.split('\n')) { - const QString b = branch.mid(2).trimmed(); - if (b.isEmpty()) - continue; - if (b.startsWith(remotePrefix)) { - const int nextSlash = b.indexOf('/', prefixLength); - if (nextSlash < 0) - continue; - const QString remote = b.mid(prefixLength, nextSlash - prefixLength); - if (remote != previousRemote) { - output += branchesDisplay(previousRemote, &branches, &first) + '\n'; - branches.clear(); - previousRemote = remote; - } - branches << b.mid(nextSlash + 1); - } else { - branches << b; - } - } - if (branches.isEmpty()) { - if (previousRemote == localPrefix) - output += tr(""); - } else { - output += branchesDisplay(previousRemote, &branches, &first); - } - controller->branchesReceived(output.trimmed()); - }); -} - bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &commit) { return !vcsFullySynchronousExec( @@ -2110,7 +2253,7 @@ QString GitClient::extendedShowDescription(const QString &workingDirectory, cons // Empty line before headers and commit message const int emptyLine = modText.indexOf("\n\n"); if (emptyLine != -1) - modText.insert(emptyLine, QString('\n') + DiffEditor::Constants::EXPAND_BRANCHES); + modText.insert(emptyLine, QString('\n') + Constants::EXPAND_BRANCHES); return modText; } diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 206a3c7b7bb..655b49c9e08 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -330,7 +330,6 @@ public: private: void finishSubmoduleUpdate(); void chunkActionsRequested(QMenu *menu, int fileIndex, int chunkIndex); - void branchesForCommit(const QString &revision); void stage(DiffEditor::DiffEditorController *diffController, const QString &patch, bool revert); diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index 6d81196c328..d817fcda286 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -53,5 +53,7 @@ const char C_GITEDITORID[] = "Git Editor"; const int OBSOLETE_COMMIT_AGE_IN_DAYS = 90; +const char EXPAND_BRANCHES[] = "Branches: "; + } // namespace Constants } // namespace Git diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index 6e071c90e0a..df327d76548 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -160,10 +160,13 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption // that it contains more "stuff". - vfs->readFile(file.toString(), QMakeVfs::VfsCumulative, &contents, &errorMessage); + int cid = vfs->idForFileName(file.toString(), QMakeVfs::VfsCumulative); + vfs->readFile(cid, &contents, &errorMessage); // If the cumulative evaluation botched the file too much, try the exact one. - if (contents.isEmpty()) - vfs->readFile(file.toString(), QMakeVfs::VfsExact, &contents, &errorMessage); + if (contents.isEmpty()) { + int eid = vfs->idForFileName(file.toString(), QMakeVfs::VfsExact); + vfs->readFile(eid, &contents, &errorMessage); + } auto resourceNode = new ResourceEditor::ResourceTopLevelNode(file, false, contents, vfolder); vfolder->addNode(resourceNode); } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 6a62d98fb9a..a8d36e02786 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -236,7 +236,8 @@ QmakePriFile::~QmakePriFile() void QmakePriFile::scheduleUpdate() { - QtSupport::ProFileCacheManager::instance()->discardFile(filePath().toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + filePath().toString(), m_project->qmakeVfs()); m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater); } @@ -291,11 +292,11 @@ static QStringList fileListForVar( } void QmakePriFile::extractSources( - QHash proToResult, QmakePriFileEvalResult *fallback, + QHash proToResult, QmakePriFileEvalResult *fallback, QVector sourceFiles, FileType type) { foreach (const ProFileEvaluator::SourceFile &source, sourceFiles) { - QmakePriFileEvalResult *result = proToResult.value(source.proFile); + auto *result = proToResult.value(source.proFileId); if (!result) result = fallback; result->foundFiles[type].insert(FileName::fromString(source.fileName)); @@ -303,12 +304,12 @@ void QmakePriFile::extractSources( } void QmakePriFile::extractInstalls( - QHash proToResult, QmakePriFileEvalResult *fallback, + QHash proToResult, QmakePriFileEvalResult *fallback, const InstallsList &installList) { for (const InstallsItem &item : installList.items) { for (const ProFileEvaluator::SourceFile &source : item.files) { - auto *result = proToResult.value(source.proFile); + auto *result = proToResult.value(source.proFileId); if (!result) result = fallback; result->folders.insert(FileName::fromString(source.fileName)); @@ -620,7 +621,8 @@ bool QmakePriFile::saveModifiedEditors() return false; // force instant reload of ourselves - QtSupport::ProFileCacheManager::instance()->discardFile(filePath().toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + filePath().toString(), m_project->qmakeVfs()); QmakeProject::notifyChanged(filePath()); return true; } @@ -700,7 +702,7 @@ QPair QmakePriFile::readProFile(const QString &file) QMakeVfs vfs; QtSupport::ProMessageHandler handler; QMakeParser parser(nullptr, &vfs, &handler); - includeFile = parser.parsedProBlock(QStringRef(&contents), file, 1); + includeFile = parser.parsedProBlock(QStringRef(&contents), 0, file, 1); } return qMakePair(includeFile, lines); } @@ -737,7 +739,7 @@ bool QmakePriFile::renameFile(const QString &oldName, QMakeParser parser(nullptr, nullptr, nullptr); QString contents = lines.join(QLatin1Char('\n')); includeFile = parser.parsedProBlock(QStringRef(&contents), - filePath().toString(), 1, QMakeParser::FullGrammar); + 0, filePath().toString(), 1, QMakeParser::FullGrammar); QTC_ASSERT(includeFile, return false); // The file should still be valid after what we did. ProWriter::addFiles(includeFile, &lines, @@ -1293,7 +1295,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) result->includedFiles.proFile = pro; result->includedFiles.name = input.projectFilePath; - QHash proToResult; + QHash proToResult; result->projectType = proFileTemplateTypeToProjectType( @@ -1331,7 +1333,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) childTree->proFile = child; childTree->name = childName; current->children.insert(childName, childTree); - proToResult[child] = &childTree->result; + proToResult[child->id()] = &childTree->result; } } toBuild.append(current->children.values()); @@ -1367,7 +1369,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) childTree->proFile = child; childTree->name = childName; current->children.insert(childName, childTree); - proToResult[child] = &childTree->result; + proToResult[child->id()] = &childTree->result; } } toBuild.append(current->children.values()); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 27dad4aae92..0889d23022a 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -201,11 +201,11 @@ private: static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir); static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir); static void extractSources( - QHash proToResult, + QHash proToResult, Internal::QmakePriFileEvalResult *fallback, QVector sourceFiles, ProjectExplorer::FileType type); static void extractInstalls( - QHash proToResult, + QHash proToResult, Internal::QmakePriFileEvalResult *fallback, const InstallsList &installList); static void processValues(Internal::QmakePriFileEvalResult &result); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 7fcde3e0066..43cbe75afba 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -372,12 +372,14 @@ void QmakeProject::updateQmlJSCodeModel() QString errorMessage; foreach (const QString &rc, exactResources) { QString contents; - if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsExact, &contents, &errorMessage) == QMakeVfs::ReadOk) + int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsExact); + if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) projectInfo.resourceFileContents[rc] = contents; } foreach (const QString &rc, cumulativeResources) { QString contents; - if (m_qmakeVfs->readFile(rc, QMakeVfs::VfsCumulative, &contents, &errorMessage) == QMakeVfs::ReadOk) + int id = m_qmakeVfs->idForFileName(rc, QMakeVfs::VfsCumulative); + if (m_qmakeVfs->readFile(id, &contents, &errorMessage) == QMakeVfs::ReadOk) projectInfo.resourceFileContents[rc] = contents; } if (!hasQmlLib) { @@ -734,7 +736,7 @@ void QmakeProject::destroyProFileReader(QtSupport::ProFileReader *reader) QString dir = projectFilePath().toString(); if (!dir.endsWith(QLatin1Char('/'))) dir += QLatin1Char('/'); - QtSupport::ProFileCacheManager::instance()->discardFiles(dir); + QtSupport::ProFileCacheManager::instance()->discardFiles(dir, qmakeVfs()); QtSupport::ProFileCacheManager::instance()->decRefCount(); m_qmakeGlobals.reset(); @@ -842,7 +844,8 @@ void QmakeProject::setAllBuildConfigurationsEnabled(bool enabled) static void notifyChangedHelper(const FileName &fileName, QmakeProFile *file) { if (file->filePath() == fileName) { - QtSupport::ProFileCacheManager::instance()->discardFile(fileName.toString()); + QtSupport::ProFileCacheManager::instance()->discardFile( + fileName.toString(), file->project()->qmakeVfs()); file->scheduleUpdate(QmakeProFile::ParseNow); } diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 6d904a49c22..d0dd85e7558 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -36,6 +36,8 @@ #include #include +#include + #include #include #include @@ -62,12 +64,14 @@ SettingsPageWidget::SettingsPageWidget(QWidget *parent) : m_ui.designerShowDebuggerCheckBox->setChecked(true); } ); - m_ui.resetFallbackPuppetPathButton->hide(); connect(m_ui.resetFallbackPuppetPathButton, &QPushButton::clicked, [=]() { m_ui.fallbackPuppetPathLineEdit->setPath( PuppetCreator::defaultPuppetFallbackDirectory()); } ); + m_ui.fallbackPuppetPathLineEdit->setPath(PuppetCreator::defaultPuppetFallbackDirectory()); + m_ui.fallbackPuppetPathLineEdit->lineEdit()->setPlaceholderText(PuppetCreator::defaultPuppetFallbackDirectory()); + connect(m_ui.resetQmlPuppetBuildPathButton, &QPushButton::clicked, [=]() { m_ui.puppetBuildPathLineEdit->setPath( PuppetCreator::defaultPuppetToplevelBuildDirectory()); @@ -129,10 +133,16 @@ DesignerSettings SettingsPageWidget::settings() const settings.insert(DesignerSettingsKey::DEBUG_PUPPET, m_ui.debugPuppetComboBox->currentText()); - if (!m_ui.fallbackPuppetPathLineEdit->path().isEmpty() && - m_ui.fallbackPuppetPathLineEdit->path() != PuppetCreator::defaultPuppetFallbackDirectory()) { + QString newFallbackPuppetPath = m_ui.fallbackPuppetPathLineEdit->path(); + QTC_CHECK(PuppetCreator::defaultPuppetFallbackDirectory() == + m_ui.fallbackPuppetPathLineEdit->lineEdit()->placeholderText()); + if (newFallbackPuppetPath.isEmpty()) + newFallbackPuppetPath = m_ui.fallbackPuppetPathLineEdit->lineEdit()->placeholderText(); + QString oldFallbackPuppetPath = settings.value(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY, + PuppetCreator::defaultPuppetFallbackDirectory()).toString(); + if (oldFallbackPuppetPath != newFallbackPuppetPath) { settings.insert(DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY, - m_ui.fallbackPuppetPathLineEdit->path()); + newFallbackPuppetPath); } if (!m_ui.puppetBuildPathLineEdit->path().isEmpty() && diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 48bde825b9f..0dc0f6f2091 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -312,8 +312,7 @@ void ExamplesListModel::parseExamples(QXmlStreamReader *reader, item.projectPath = attributes.value(QLatin1String("projectPath")).toString(); item.hasSourceCode = !item.projectPath.isEmpty(); item.projectPath = relativeOrInstallPath(item.projectPath, projectsOffset, examplesInstallPath); - item.imageUrl = Utils::StyleHelper::dpiSpecificImageFile( - attributes.value(QLatin1String("imageUrl")).toString()); + item.imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); QPixmapCache::remove(item.imageUrl); item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); item.isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() == QLatin1String("true"); @@ -412,7 +411,8 @@ void ExamplesListModel::parseTutorials(QXmlStreamReader *reader, const QString & item.hasSourceCode = !item.projectPath.isEmpty(); item.projectPath.prepend(slash); item.projectPath.prepend(projectsOffset); - item.imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); + item.imageUrl = Utils::StyleHelper::dpiSpecificImageFile( + attributes.value(QLatin1String("imageUrl")).toString()); QPixmapCache::remove(item.imageUrl); item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); item.isVideo = attributes.value(QLatin1String("isVideo")).toString() == QLatin1String("true"); diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index b284d2869d9..0a71aca1e37 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -413,7 +413,8 @@ public: QRect pixmapRect = inner; if (!pm.isNull()) { painter->setPen(foregroundColor2); - pixmapRect = inner.adjusted(6, 20, -6, -15); + if (!m_showExamples) + pixmapRect = inner.adjusted(6, 20, -6, -15); QPoint pixmapPos = pixmapRect.center(); pixmapPos.rx() -= pm.width() / pm.devicePixelRatio() / 2; pixmapPos.ry() -= pm.height() / pm.devicePixelRatio() / 2; @@ -533,6 +534,8 @@ public: return QAbstractItemDelegate::editorEvent(ev, model, option, idx); } + void setShowExamples(bool showExamples) { m_showExamples = showExamples; goon(); } + signals: void tagClicked(const QString &tag); @@ -547,6 +550,7 @@ private: mutable QRect m_currentArea; mutable QPointer m_currentWidget; mutable QVector> m_currentTagRects; + bool m_showExamples = true; }; class ExamplesPageWidget : public QWidget @@ -555,6 +559,7 @@ public: ExamplesPageWidget(bool isExamples) : m_isExamples(isExamples) { + m_exampleDelegate.setShowExamples(isExamples); const int sideMargin = 27; static ExamplesListModel *s_examplesModel = new ExamplesListModel(this); m_examplesModel = s_examplesModel; diff --git a/src/plugins/qtsupport/profilereader.cpp b/src/plugins/qtsupport/profilereader.cpp index 0985a64b750..86ec0f16d7f 100644 --- a/src/plugins/qtsupport/profilereader.cpp +++ b/src/plugins/qtsupport/profilereader.cpp @@ -166,16 +166,17 @@ void ProFileCacheManager::clear() // loop is concerned. Use a shared pointer once this is not true anymore. delete m_cache; m_cache = 0; + QMakeVfs::clearIds(); } -void ProFileCacheManager::discardFiles(const QString &prefix) +void ProFileCacheManager::discardFiles(const QString &prefix, QMakeVfs *vfs) { if (m_cache) - m_cache->discardFiles(prefix); + m_cache->discardFiles(prefix, vfs); } -void ProFileCacheManager::discardFile(const QString &fileName) +void ProFileCacheManager::discardFile(const QString &fileName, QMakeVfs *vfs) { if (m_cache) - m_cache->discardFile(fileName); + m_cache->discardFile(fileName, vfs); } diff --git a/src/plugins/qtsupport/profilereader.h b/src/plugins/qtsupport/profilereader.h index 5e53d2d2dc7..c2245b488aa 100644 --- a/src/plugins/qtsupport/profilereader.h +++ b/src/plugins/qtsupport/profilereader.h @@ -93,8 +93,8 @@ class QTSUPPORT_EXPORT ProFileCacheManager : public QObject public: static ProFileCacheManager *instance() { return s_instance; } ProFileCache *cache(); - void discardFiles(const QString &prefix); - void discardFile(const QString &fileName); + void discardFiles(const QString &prefix, QMakeVfs *vfs); + void discardFile(const QString &fileName, QMakeVfs *vfs); void incRefCount(); void decRefCount(); diff --git a/src/plugins/qtsupport/qtcreator_tutorials.xml b/src/plugins/qtsupport/qtcreator_tutorials.xml index 2464a480917..0948cca5fa7 100644 --- a/src/plugins/qtsupport/qtcreator_tutorials.xml +++ b/src/plugins/qtsupport/qtcreator_tutorials.xml @@ -66,6 +66,10 @@ qt creator,video + + + qt creator,qt quick,video + diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 97e4c0b8ed4..0552bd10972 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -35,8 +35,13 @@ # include # include # include +# include +# include +# include #endif +#define fL1S(s) QString::fromLatin1(s) + QT_BEGIN_NAMESPACE using namespace QMakeInternal; @@ -59,21 +64,22 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName) bool IoUtils::isRelativePath(const QString &path) { - if (path.startsWith(QLatin1Char('/'))) - return false; #ifdef QMAKE_BUILTIN_PRFS if (path.startsWith(QLatin1String(":/"))) return false; #endif #ifdef Q_OS_WIN - if (path.startsWith(QLatin1Char('\\'))) - return false; - // Unlike QFileInfo, this won't accept a relative path with a drive letter. - // Such paths result in a royal mess anyway ... + // Unlike QFileInfo, this considers only paths with both a drive prefix and + // a subsequent (back-)slash absolute: if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter() - && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) + && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) { return false; -#endif + } + // (... unless, of course, they're UNC, which qmake fails on anyway) +#else + if (path.startsWith(QLatin1Char('/'))) + return false; +#endif // Q_OS_WIN return true; } @@ -93,6 +99,12 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) return QString(); if (isAbsolutePath(fileName)) return QDir::cleanPath(fileName); +#ifdef Q_OS_WIN // Add drive to otherwise-absolute path: + if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') { + Q_ASSERT(isAbsolutePath(baseDir)); + return QDir::cleanPath(baseDir.left(2) + fileName); + } +#endif // Q_OS_WIN return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); } @@ -181,4 +193,105 @@ QString IoUtils::shellQuoteWin(const QString &arg) return ret; } +#if defined(PROEVALUATOR_FULL) + +# if defined(Q_OS_WIN) +static QString windowsErrorCode() +{ + wchar_t *string = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&string, + 0, + NULL); + QString ret = QString::fromWCharArray(string); + LocalFree((HLOCAL)string); + return ret.trimmed(); +} +# endif + +bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString) +{ +# ifdef Q_OS_UNIX + struct stat st; + if (stat(referenceFileName.toLocal8Bit().constData(), &st)) { + *errorString = fL1S("Cannot stat() reference file %1: %2.").arg(referenceFileName, fL1S(strerror(errno))); + return false; + } +# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L + const struct timespec times[2] = { { 0, UTIME_NOW }, st.st_mtim }; + const bool utimeError = utimensat(AT_FDCWD, targetFileName.toLocal8Bit().constData(), times, 0) < 0; +# else + struct utimbuf utb; + utb.actime = time(0); + utb.modtime = st.st_mtime; + const bool utimeError= utime(targetFileName.toLocal8Bit().constData(), &utb) < 0; +# endif + if (utimeError) { + *errorString = fL1S("Cannot touch %1: %2.").arg(targetFileName, fL1S(strerror(errno))); + return false; + } +# else + HANDLE rHand = CreateFile((wchar_t*)referenceFileName.utf16(), + GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (rHand == INVALID_HANDLE_VALUE) { + *errorString = fL1S("Cannot open reference file %1: %2").arg(referenceFileName, windowsErrorCode()); + return false; + } + FILETIME ft; + GetFileTime(rHand, 0, 0, &ft); + CloseHandle(rHand); + HANDLE wHand = CreateFile((wchar_t*)targetFileName.utf16(), + GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (wHand == INVALID_HANDLE_VALUE) { + *errorString = fL1S("Cannot open %1: %2").arg(targetFileName, windowsErrorCode()); + return false; + } + SetFileTime(wHand, 0, 0, &ft); + CloseHandle(wHand); +# endif + return true; +} + +#if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX) +bool IoUtils::readLinkTarget(const QString &symlinkPath, QString *target) +{ + const QByteArray localSymlinkPath = QFile::encodeName(symlinkPath); +# if defined(__GLIBC__) && !defined(PATH_MAX) +# define PATH_CHUNK_SIZE 256 + char *s = 0; + int len = -1; + int size = PATH_CHUNK_SIZE; + + forever { + s = (char *)::realloc(s, size); + len = ::readlink(localSymlinkPath.constData(), s, size); + if (len < 0) { + ::free(s); + break; + } + if (len < size) + break; + size *= 2; + } +# else + char s[PATH_MAX+1]; + int len = readlink(localSymlinkPath.constData(), s, PATH_MAX); +# endif + if (len <= 0) + return false; + *target = QFile::decodeName(QByteArray(s, len)); +# if defined(__GLIBC__) && !defined(PATH_MAX) + ::free(s); +# endif + return true; +} +#endif + +#endif // PROEVALUATOR_FULL + QT_END_NAMESPACE diff --git a/src/shared/proparser/ioutils.h b/src/shared/proparser/ioutils.h index d7fc596b0df..71a7ffed565 100644 --- a/src/shared/proparser/ioutils.h +++ b/src/shared/proparser/ioutils.h @@ -60,6 +60,12 @@ public: #else { return shellQuoteWin(arg); } #endif +#if defined(PROEVALUATOR_FULL) + static bool touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString); +# if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX) + static bool readLinkTarget(const QString &symlinkPath, QString *target); +# endif +#endif }; } // namespace ProFileEvaluatorInternal diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index a3425ec6cbd..0cb1f2ca041 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -196,13 +196,15 @@ QVector ProFileEvaluator::absoluteFileValues( ProFileEvaluator::TemplateType ProFileEvaluator::templateType() const { + static QString str_staticlib = QStringLiteral("staticlib"); + const ProStringList &templ = d->values(ProKey("TEMPLATE")); if (templ.count() >= 1) { const QString &t = templ.at(0).toQString(); if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive)) return TT_Application; if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive)) - return d->isActiveConfig(QStringLiteral("staticlib")) ? TT_StaticLibrary : TT_SharedLibrary; + return d->isActiveConfig(QStringRef(&str_staticlib)) ? TT_StaticLibrary : TT_SharedLibrary; if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive)) return TT_Script; if (!t.compare(QLatin1String("aux"), Qt::CaseInsensitive)) @@ -224,6 +226,10 @@ bool ProFileEvaluator::loadNamedSpec(const QString &specDir, bool hostSpec) bool ProFileEvaluator::accept(ProFile *pro, QMakeEvaluator::LoadFlags flags) { + static QString str_no_include_pwd = QStringLiteral("no_include_pwd"); + static QString str_plugin = QStringLiteral("plugin"); + static QString str_plugin_no_share_shlib_cflags = QStringLiteral("plugin_no_share_shlib_cflags"); + if (d->visitProFile(pro, QMakeHandler::EvalProjectFile, flags) != QMakeEvaluator::ReturnTrue) return false; @@ -232,7 +238,7 @@ bool ProFileEvaluator::accept(ProFile *pro, QMakeEvaluator::LoadFlags flags) ProStringList &incpath = d->valuesRef(ProKey("INCLUDEPATH")); incpath += d->values(ProKey("QMAKE_INCDIR")); - if (!d->isActiveConfig(QStringLiteral("no_include_pwd"))) { + if (!d->isActiveConfig(QStringRef(&str_no_include_pwd))) { incpath.prepend(ProString(pro->directoryName())); // It's pretty stupid that this is appended - it should be the second entry. if (pro->directoryName() != d->m_outputDir) @@ -249,8 +255,8 @@ bool ProFileEvaluator::accept(ProFile *pro, QMakeEvaluator::LoadFlags flags) break; case TT_SharedLibrary: { - bool plugin = d->isActiveConfig(QStringLiteral("plugin")); - if (!plugin || !d->isActiveConfig(QStringLiteral("plugin_no_share_shlib_cflags"))) + bool plugin = d->isActiveConfig(QStringRef(&str_plugin)); + if (!plugin || !d->isActiveConfig(QStringRef(&str_plugin_no_share_shlib_cflags))) cxxflags += d->values(ProKey("QMAKE_CXXFLAGS_SHLIB")); if (plugin) cxxflags += d->values(ProKey("QMAKE_CXXFLAGS_PLUGIN")); diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index b0116aebd4c..ce1675dd4b4 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -55,7 +55,7 @@ public: struct SourceFile { QString fileName; - const ProFile *proFile; + int proFileId; }; // Call this from a concurrency-free context diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 795b8b4564a..db4f386cae8 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -71,6 +71,11 @@ ProString::ProString(const QString &str) : { } +ProString::ProString(const QStringRef &str) : + m_string(*str.string()), m_offset(str.position()), m_length(str.size()), m_file(0), m_hash(0x80000000) +{ +} + ProString::ProString(const char *str, DoPreHashing) : m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0) { @@ -333,7 +338,7 @@ ProString ProString::trimmed() const QTextStream &operator<<(QTextStream &t, const ProString &str) { - t << str.toQString(); // XXX optimize ... somehow + t << str.toQStringRef(); return t; } @@ -393,9 +398,12 @@ void ProStringList::removeAll(const char *str) void ProStringList::removeEach(const ProStringList &value) { - for (const ProString &str : value) + for (const ProString &str : value) { + if (isEmpty()) + break; if (!str.isEmpty()) removeAll(str); + } } void ProStringList::removeEmpty() @@ -455,6 +463,14 @@ bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const return false; } +bool ProStringList::contains(const QStringRef &str, Qt::CaseSensitivity cs) const +{ + for (int i = 0; i < size(); i++) + if (!at(i).toQStringRef().compare(str, cs)) + return true; + return false; +} + bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const { for (int i = 0; i < size(); i++) @@ -463,9 +479,10 @@ bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const return false; } -ProFile::ProFile(const QString &fileName) +ProFile::ProFile(int id, const QString &fileName) : m_refCount(1), m_fileName(fileName), + m_id(id), m_ok(true), m_hostBuild(false) { @@ -482,7 +499,7 @@ ProString ProFile::getStr(const ushort *&tPtr) { uint len = *tPtr++; ProString ret(items(), tPtr - tokPtr(), len); - ret.setSource(this); + ret.setSource(m_id); tPtr += len; return ret; } diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 31e662bcf06..a7566be2205 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -64,13 +64,14 @@ public: ProString(); ProString(const ProString &other); PROITEM_EXPLICIT ProString(const QString &str); + PROITEM_EXPLICIT ProString(const QStringRef &str); PROITEM_EXPLICIT ProString(const char *str); ProString(const QString &str, int offset, int length); void setValue(const QString &str); void clear() { m_string.clear(); m_length = 0; } ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; } - ProString &setSource(const ProFile *pro) { m_file = pro; return *this; } - const ProFile *sourceFile() const { return m_file; } + ProString &setSource(int id) { m_file = id; return *this; } + int sourceFile() const { return m_file; } ProString &prepend(const ProString &other); ProString &append(const ProString &other, bool *pending = 0); @@ -90,6 +91,7 @@ public: bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); } bool operator==(const QString &other) const { return toQStringRef() == other; } + bool operator==(const QStringRef &other) const { return toQStringRef() == other; } bool operator==(QLatin1String other) const { return toQStringRef() == other; } bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); } bool operator!=(const ProString &other) const { return !(*this == other); } @@ -159,7 +161,7 @@ private: QString m_string; int m_offset, m_length; - const ProFile *m_file; + int m_file; mutable uint m_hash; QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget); uint updatedHash() const; @@ -199,14 +201,14 @@ Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); uint qHash(const ProString &str); QString operator+(const ProString &one, const ProString &two); inline QString operator+(const ProString &one, const QString &two) - { return one + ProString(two); } + { return one.toQStringRef() + two; } inline QString operator+(const QString &one, const ProString &two) - { return ProString(one) + two; } + { return one + two.toQStringRef(); } inline QString operator+(const ProString &one, const char *two) - { return one + ProString(two); } // XXX optimize + { return one.toQStringRef() + QLatin1String(two); } inline QString operator+(const char *one, const ProString &two) - { return ProString(one) + two; } // XXX optimize + { return QLatin1String(one) + two.toQStringRef(); } inline QString &operator+=(QString &that, const ProString &other) { return that += other.toQStringRef(); } @@ -244,6 +246,7 @@ public: void removeDuplicates(); bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + bool contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return contains(ProString(str), cs); } bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; @@ -320,6 +323,9 @@ enum ProToken { // - function name: hash (2), length (1), chars (length) // - body length (2) // - body + TokTerminator (body length) + TokBypassNesting, // escape from function local variable scopes: + // - block length (2) + // - block + TokTerminator (block length) TokMask = 0xff, TokQuoted = 0x100, // The expression is quoted => join expanded stringlist TokNewStr = 0x200 // Next stringlist element @@ -328,9 +334,10 @@ enum ProToken { class QMAKE_EXPORT ProFile { public: - explicit ProFile(const QString &fileName); + ProFile(int id, const QString &fileName); ~ProFile(); + int id() const { return m_id; } QString fileName() const { return m_fileName; } QString directoryName() const { return m_directoryName; } const QString &items() const { return m_proitems; } @@ -355,6 +362,7 @@ private: QString m_proitems; QString m_fileName; QString m_directoryName; + int m_id; bool m_ok; bool m_hostBuild; }; diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index 046143c8efb..0d717d9ce9d 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -176,7 +176,7 @@ QString ProWriter::compileScope(const QString &scope) if (scope.isEmpty()) return QString(); QMakeParser parser(0, 0, 0); - ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), QLatin1String("no-file"), 1); + ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), 0, QLatin1String("no-file"), 1); if (!includeFile) return QString(); QString result = includeFile->items(); diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index c2625166cb2..9d9afdd2afe 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -52,7 +52,6 @@ #ifdef Q_OS_UNIX #include -#include #include #include #include @@ -98,7 +97,7 @@ enum TestFunc { T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, T_DEFINED, T_DISCARD_FROM, T_CONTAINS, T_INFILE, T_COUNT, T_ISEMPTY, T_PARSE_JSON, T_INCLUDE, T_LOAD, T_DEBUG, T_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF, - T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE + T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE, T_RELOAD_PROPERTIES }; void QMakeEvaluator::initFunctionStatics() @@ -107,53 +106,53 @@ void QMakeEvaluator::initFunctionStatics() const char * const name; const ExpandFunc func; } expandInits[] = { - {"member", E_MEMBER}, - {"str_member", E_STR_MEMBER}, - {"first", E_FIRST}, - {"take_first", E_TAKE_FIRST}, - {"last", E_LAST}, - {"take_last", E_TAKE_LAST}, - {"size", E_SIZE}, - {"str_size", E_STR_SIZE}, - {"cat", E_CAT}, - {"fromfile", E_FROMFILE}, - {"eval", E_EVAL}, - {"list", E_LIST}, - {"sprintf", E_SPRINTF}, - {"format_number", E_FORMAT_NUMBER}, - {"num_add", E_NUM_ADD}, - {"join", E_JOIN}, - {"split", E_SPLIT}, - {"basename", E_BASENAME}, - {"dirname", E_DIRNAME}, - {"section", E_SECTION}, - {"find", E_FIND}, - {"system", E_SYSTEM}, - {"unique", E_UNIQUE}, - {"sorted", E_SORTED}, - {"reverse", E_REVERSE}, - {"quote", E_QUOTE}, - {"escape_expand", E_ESCAPE_EXPAND}, - {"upper", E_UPPER}, - {"lower", E_LOWER}, - {"title", E_TITLE}, - {"re_escape", E_RE_ESCAPE}, - {"val_escape", E_VAL_ESCAPE}, - {"files", E_FILES}, - {"prompt", E_PROMPT}, - {"replace", E_REPLACE}, - {"sort_depends", E_SORT_DEPENDS}, - {"resolve_depends", E_RESOLVE_DEPENDS}, - {"enumerate_vars", E_ENUMERATE_VARS}, - {"shadowed", E_SHADOWED}, - {"absolute_path", E_ABSOLUTE_PATH}, - {"relative_path", E_RELATIVE_PATH}, - {"clean_path", E_CLEAN_PATH}, - {"system_path", E_SYSTEM_PATH}, - {"shell_path", E_SHELL_PATH}, - {"system_quote", E_SYSTEM_QUOTE}, - {"shell_quote", E_SHELL_QUOTE}, - {"getenv", E_GETENV}, + { "member", E_MEMBER }, + { "str_member", E_STR_MEMBER }, + { "first", E_FIRST }, + { "take_first", E_TAKE_FIRST }, + { "last", E_LAST }, + { "take_last", E_TAKE_LAST }, + { "size", E_SIZE }, + { "str_size", E_STR_SIZE }, + { "cat", E_CAT }, + { "fromfile", E_FROMFILE }, + { "eval", E_EVAL }, + { "list", E_LIST }, + { "sprintf", E_SPRINTF }, + { "format_number", E_FORMAT_NUMBER }, + { "num_add", E_NUM_ADD }, + { "join", E_JOIN }, + { "split", E_SPLIT }, + { "basename", E_BASENAME }, + { "dirname", E_DIRNAME }, + { "section", E_SECTION }, + { "find", E_FIND }, + { "system", E_SYSTEM }, + { "unique", E_UNIQUE }, + { "sorted", E_SORTED }, + { "reverse", E_REVERSE }, + { "quote", E_QUOTE }, + { "escape_expand", E_ESCAPE_EXPAND }, + { "upper", E_UPPER }, + { "lower", E_LOWER }, + { "title", E_TITLE }, + { "re_escape", E_RE_ESCAPE }, + { "val_escape", E_VAL_ESCAPE }, + { "files", E_FILES }, + { "prompt", E_PROMPT }, + { "replace", E_REPLACE }, + { "sort_depends", E_SORT_DEPENDS }, + { "resolve_depends", E_RESOLVE_DEPENDS }, + { "enumerate_vars", E_ENUMERATE_VARS }, + { "shadowed", E_SHADOWED }, + { "absolute_path", E_ABSOLUTE_PATH }, + { "relative_path", E_RELATIVE_PATH }, + { "clean_path", E_CLEAN_PATH }, + { "system_path", E_SYSTEM_PATH }, + { "shell_path", E_SHELL_PATH }, + { "system_quote", E_SYSTEM_QUOTE }, + { "shell_quote", E_SHELL_QUOTE }, + { "getenv", E_GETENV }, }; statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0]))); for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) @@ -163,40 +162,41 @@ void QMakeEvaluator::initFunctionStatics() const char * const name; const TestFunc func; } testInits[] = { - {"requires", T_REQUIRES}, - {"greaterThan", T_GREATERTHAN}, - {"lessThan", T_LESSTHAN}, - {"equals", T_EQUALS}, - {"isEqual", T_EQUALS}, - {"versionAtLeast", T_VERSION_AT_LEAST}, - {"versionAtMost", T_VERSION_AT_MOST}, - {"exists", T_EXISTS}, - {"export", T_EXPORT}, - {"clear", T_CLEAR}, - {"unset", T_UNSET}, - {"eval", T_EVAL}, - {"CONFIG", T_CONFIG}, - {"if", T_IF}, - {"isActiveConfig", T_CONFIG}, - {"system", T_SYSTEM}, - {"discard_from", T_DISCARD_FROM}, - {"defined", T_DEFINED}, - {"contains", T_CONTAINS}, - {"infile", T_INFILE}, - {"count", T_COUNT}, - {"isEmpty", T_ISEMPTY}, - {"parseJson", T_PARSE_JSON}, - {"load", T_LOAD}, - {"include", T_INCLUDE}, - {"debug", T_DEBUG}, - {"log", T_LOG}, - {"message", T_MESSAGE}, - {"warning", T_WARNING}, - {"error", T_ERROR}, - {"mkpath", T_MKPATH}, - {"write_file", T_WRITE_FILE}, - {"touch", T_TOUCH}, - {"cache", T_CACHE}, + { "requires", T_REQUIRES }, + { "greaterThan", T_GREATERTHAN }, + { "lessThan", T_LESSTHAN }, + { "equals", T_EQUALS }, + { "isEqual", T_EQUALS }, + { "versionAtLeast", T_VERSION_AT_LEAST }, + { "versionAtMost", T_VERSION_AT_MOST }, + { "exists", T_EXISTS }, + { "export", T_EXPORT }, + { "clear", T_CLEAR }, + { "unset", T_UNSET }, + { "eval", T_EVAL }, + { "CONFIG", T_CONFIG }, + { "if", T_IF }, + { "isActiveConfig", T_CONFIG }, + { "system", T_SYSTEM }, + { "discard_from", T_DISCARD_FROM }, + { "defined", T_DEFINED }, + { "contains", T_CONTAINS }, + { "infile", T_INFILE }, + { "count", T_COUNT }, + { "isEmpty", T_ISEMPTY }, + { "parseJson", T_PARSE_JSON }, + { "load", T_LOAD }, + { "include", T_INCLUDE }, + { "debug", T_DEBUG }, + { "log", T_LOG }, + { "message", T_MESSAGE }, + { "warning", T_WARNING }, + { "error", T_ERROR }, + { "mkpath", T_MKPATH }, + { "write_file", T_WRITE_FILE }, + { "touch", T_TOUCH }, + { "cache", T_CACHE }, + { "reload_properties", T_RELOAD_PROPERTIES }, }; statics.functions.reserve((int)(sizeof(testInits)/sizeof(testInits[0]))); for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i) @@ -251,23 +251,6 @@ QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringLis return true; } -#if defined(Q_OS_WIN) && defined(PROEVALUATOR_FULL) -static QString windowsErrorCode() -{ - wchar_t *string = 0; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&string, - 0, - NULL); - QString ret = QString::fromWCharArray(string); - LocalFree((HLOCAL)string); - return ret.trimmed(); -} -#endif - QString QMakeEvaluator::quoteValue(const ProString &val) { @@ -392,14 +375,47 @@ static void addJsonValue(const QJsonValue &value, const QString &keyPrefix, ProV } } +struct ErrorPosition { + int line; + int column; +}; + +static ErrorPosition calculateErrorPosition(const QByteArray &json, int offset) +{ + ErrorPosition pos = { 0, 0 }; + offset--; // offset is 1-based, switching to 0-based + for (int i = 0; i < offset; ++i) { + switch (json.at(i)) { + case '\n': + pos.line++; + pos.column = 0; + break; + case '\r': + break; + case '\t': + pos.column = (pos.column + 8) & ~7; + break; + default: + pos.column++; + break; + } + } + // Lines and columns in text editors are 1-based: + pos.line++; + pos.column++; + return pos; +} + QMakeEvaluator::VisitReturn QMakeEvaluator::parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value) { QJsonParseError error; QJsonDocument document = QJsonDocument::fromJson(json, &error); if (document.isNull()) { - if (error.error != QJsonParseError::NoError) - evalError(fL1S("Error parsing json at offset %1: %2") - .arg(error.offset).arg(error.errorString())); + if (error.error != QJsonParseError::NoError) { + ErrorPosition errorPos = calculateErrorPosition(json, error.offset); + evalError(fL1S("Error parsing JSON at %1:%2: %3") + .arg(errorPos.line).arg(errorPos.column).arg(error.errorString())); + } return QMakeEvaluator::ReturnFalse; } @@ -420,13 +436,16 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, QMakeVfs::VfsFlags flags, const QString &contents) { + int oldId = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); + int id = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsCreate); QString errStr; - if (!m_vfs->writeFile(fn, mode, flags, contents, &errStr)) { + if (!m_vfs->writeFile(id, mode, flags, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3") .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; } - m_parser->discardFileFromCache(fn); + if (oldId) + m_parser->discardFileFromCache(oldId); return ReturnTrue; } @@ -522,11 +541,9 @@ void QMakeEvaluator::populateDeps( } } -ProStringList QMakeEvaluator::evaluateBuiltinExpand( - int func_t, const ProKey &func, const ProStringList &args) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( + int func_t, const ProKey &func, const ProStringList &args, ProStringList &ret) { - ProStringList ret; - traceMsg("calling built-in $$%s(%s)", dbgKey(func), dbgSepStrList(args)); switch (func_t) { @@ -540,8 +557,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( int end = -1; if (func_t == E_SECTION) { if (args.count() != 3 && args.count() != 4) { - evalError(fL1S("%1(var) section(var, sep, begin, end) requires" - " three or four arguments.").arg(func.toQString(m_tmp1))); + evalError(fL1S("section(var, sep, begin, end) requires three or four arguments.")); } else { var = args[0]; sep = args.at(1).toQString(); @@ -567,8 +583,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( if (regexp) { QRegExp sepRx(sep); for (const ProString &str : strings) { - const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end); - ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str)); + const QString &rstr = str.toQString(m_tmp[m_toggle ^= 1]).section(sepRx, beg, end); + ret << (rstr.isSharedWith(m_tmp[m_toggle]) ? str : ProString(rstr).setSource(str)); } } else { for (const ProString &str : strings) { @@ -598,7 +614,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( int width = 0; bool zeropad = false; bool leftalign = false; - enum {DefaultSign, PadSign, AlwaysSign } sign = DefaultSign; + enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign; if (args.count() >= 2) { const auto opts = split_value_list(args.at(1).toQStringRef()); for (const ProString &opt : opts) { @@ -696,9 +712,9 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( after = args[3]; const ProStringList &var = values(map(args.at(0))); if (!var.isEmpty()) { - const ProFile *src = currentProFile(); + int src = currentFileId(); for (const ProString &v : var) - if (const ProFile *s = v.sourceFile()) { + if (int s = v.sourceFile()) { src = s; break; } @@ -714,9 +730,9 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep; const auto vars = values(map(args.at(0))); for (const ProString &var : vars) { - const auto splits = var.toQString(m_tmp2).split(sep); - for (const QString &splt : splits) - ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt).setSource(var)); + const auto splits = var.toQStringRef().split(sep); + for (const auto &splt : splits) + ret << ProString(splt).setSource(var); } } break; @@ -802,7 +818,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( if (args.count() < 1 || args.count() > 2) { evalError(fL1S("cat(file, singleline=true) requires one or two arguments.")); } else { - const QString &file = args.at(0).toQString(m_tmp1); + QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1))); + fn.detach(); bool blob = false; bool lines = false; @@ -817,7 +834,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( lines = true; } - QFile qfile(resolvePath(m_option->expandEnvVars(file))); + QFile qfile(fn); if (qfile.open(QIODevice::ReadOnly)) { QTextStream stream(&qfile); if (blob) { @@ -868,12 +885,10 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( evalError(fL1S("find(var, str) requires two arguments.")); } else { QRegExp regx(args.at(1).toQString()); - int t = 0; const auto vals = values(map(args.at(0))); for (const ProString &val : vals) { - if (regx.indexIn(val.toQString(m_tmp[t])) != -1) + if (regx.indexIn(val.toQString(m_tmp[m_toggle ^= 1])) != -1) ret += val; - t ^= 1; } } break; @@ -895,7 +910,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( lines = true; } int exitCode; - QByteArray bytes = getCommandOutput(args.at(0).toQString(m_tmp2), &exitCode); + QByteArray bytes = getCommandOutput(args.at(0).toQString(), &exitCode); if (args.count() > 2 && !args.at(2).isEmpty()) { m_valuemapStack.top()[args.at(2).toKey()] = ProStringList(ProString(QString::number(exitCode))); @@ -960,10 +975,10 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( struct { char in, out; } mapped_quotes[] = { - {'n', '\n' }, - {'t', '\t' }, - {'r', '\r' }, - {0, 0 } + { 'n', '\n' }, + { 't', '\t' }, + { 'r', '\r' }, + { 0, 0 } }; for (int i = 0; mapped_quotes[i].in; ++i) { if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) { @@ -1049,27 +1064,38 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( dirs.append(fname + QLatin1Char('/')); } if (regex.exactMatch(qdir[i])) - ret += ProString(fname).setSource(currentProFile()); + ret += ProString(fname).setSource(currentFileId()); } } } break; #ifdef PROEVALUATOR_FULL case E_PROMPT: { - if (args.count() != 1) { - evalError(fL1S("prompt(question) requires one argument.")); + if (args.count() != 1 && args.count() != 2) { + evalError(fL1S("prompt(question, [decorate=true]) requires one or two arguments.")); // } else if (currentFileName() == QLatin1String("-")) { // evalError(fL1S("prompt(question) cannot be used when '-o -' is used")); } else { QString msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp1)); - if (!msg.endsWith(QLatin1Char('?'))) - msg += QLatin1Char('?'); - fprintf(stderr, "Project PROMPT: %s ", qPrintable(msg)); - + bool decorate = true; + if (args.count() == 2) + decorate = isTrue(args.at(1)); + if (decorate) { + if (!msg.endsWith(QLatin1Char('?'))) + msg += QLatin1Char('?'); + fprintf(stderr, "Project PROMPT: %s ", qPrintable(msg)); + } else { + fputs(qPrintable(msg), stderr); + } QFile qfile; if (qfile.open(stdin, QIODevice::ReadOnly)) { QTextStream t(&qfile); const QString &line = t.readLine(); + if (t.atEnd()) { + fputs("\n", stderr); + evalError(fL1S("Unexpected EOF.")); + return ReturnError; + } ret = split_value_list(QStringRef(&line)); } } @@ -1086,7 +1112,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( QString rstr = val.toQString(m_tmp1); QString copy = rstr; // Force a detach on modify rstr.replace(before, after); - ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr).setSource(val)); + ret << (rstr.isSharedWith(m_tmp1) + ? val + : rstr.isSharedWith(m_tmp2) + ? args.at(2) + : ProString(rstr).setSource(val)); } } break; @@ -1144,9 +1174,9 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("absolute_path(path[, base]) requires one or two arguments.")); } else { - QString rstr = QDir::cleanPath( - QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()) - .absoluteFilePath(args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : args.count() > 1 && rstr.isSharedWith(m_tmp2) @@ -1158,9 +1188,10 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("relative_path(path[, base]) requires one or two arguments.")); } else { - QDir baseDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()); - QString rstr = baseDir.relativeFilePath(baseDir.absoluteFilePath( - args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); + QString rstr = QDir(baseDir).relativeFilePath(absArg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); } break; @@ -1239,7 +1270,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( break; } - return ret; + return ReturnTrue; } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( @@ -1305,7 +1336,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } QString fn = resolvePath(args.at(0).toQString(m_tmp1)); - ProFile *pro = m_parser->parsedProFile(fn, QMakeParser::ParseOnlyCached); + QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); + int pro = m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly); if (!pro) return ReturnFalse; ProValueMap &vmap = m_valuemapStack.first(); @@ -1324,7 +1356,22 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } ++vit; } - pro->deref(); + for (auto fit = m_functionDefs.testFunctions.begin(); fit != m_functionDefs.testFunctions.end(); ) { + if (fit->pro()->id() == pro) + fit = m_functionDefs.testFunctions.erase(fit); + else + ++fit; + } + for (auto fit = m_functionDefs.replaceFunctions.begin(); fit != m_functionDefs.replaceFunctions.end(); ) { + if (fit->pro()->id() == pro) + fit = m_functionDefs.replaceFunctions.erase(fit); + else + ++fit; + } + ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")]; + int idx = iif.indexOf(ProString(fn)); + if (idx >= 0) + iif.removeAt(idx); return ReturnTrue; } case T_INFILE: @@ -1346,12 +1393,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( copy.detach(); regx.setPattern(copy); } - int t = 0; const auto strings = vars.value(map(args.at(1))); for (const ProString &s : strings) { - if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry) + if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[m_toggle ^= 1]))) || s == qry) return ReturnTrue; - t ^= 1; } } return ReturnFalse; @@ -1365,7 +1410,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( VisitReturn ret = ReturnFalse; QString contents = args.join(statics.field_sep); ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents), - m_current.pro->fileName(), m_current.line); + 0, m_current.pro->fileName(), m_current.line); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1389,13 +1434,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } if (args.count() == 1) - return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2))); - const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|')); + return returnBool(isActiveConfig(args.at(0).toQStringRef())); + const auto mutuals = args.at(1).toQStringRef().split(QLatin1Char('|')); const ProStringList &configs = values(statics.strCONFIG); for (int i = configs.size() - 1; i >= 0; i--) { for (int mut = 0; mut < mutuals.count(); mut++) { - if (configs[i] == mutuals[mut].trimmed()) + if (configs[i].toQStringRef() == mutuals[mut].trimmed()) return returnBool(configs[i] == args[0]); } } @@ -1416,21 +1461,19 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } const ProStringList &l = values(map(args.at(0))); if (args.count() == 2) { - int t = 0; for (int i = 0; i < l.size(); ++i) { const ProString &val = l[i]; - if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[t]))) || val == qry) + if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1]))) || val == qry) return ReturnTrue; - t ^= 1; } } else { - const QStringList &mutuals = args.at(2).toQString(m_tmp3).split(QLatin1Char('|')); + const auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|')); for (int i = l.size() - 1; i >= 0; i--) { const ProString val = l[i]; for (int mut = 0; mut < mutuals.count(); mut++) { - if (val == mutuals[mut].trimmed()) { + if (val.toQStringRef() == mutuals[mut].trimmed()) { return returnBool((!regx.isEmpty() - && regx.exactMatch(val.toQString(m_tmp2))) + && regx.exactMatch(val.toQString(m_tmp[m_toggle ^= 1]))) || val == qry); } } @@ -1495,7 +1538,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } return returnBool(values(map(args.at(0))).join(statics.field_sep) - == args.at(1).toQString(m_tmp1)); + == args.at(1).toQStringRef()); case T_VERSION_AT_LEAST: case T_VERSION_AT_MOST: { if (args.count() != 2) { @@ -1666,7 +1709,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( #ifndef QT_BOOTSTRAPPED QProcess proc; proc.setProcessChannelMode(QProcess::ForwardedChannels); - runProcess(&proc, args.at(0).toQString(m_tmp2)); + runProcess(&proc, args.at(0).toQString()); return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0); #else int ec = system((QLatin1String("cd ") @@ -1703,8 +1746,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnTrue; int slsh = file.lastIndexOf(QLatin1Char('/')); QString fn = file.mid(slsh+1); + fn.detach(); if (fn.contains(QLatin1Char('*')) || fn.contains(QLatin1Char('?'))) { QString dirstr = file.left(slsh+1); + dirstr.detach(); if (!QDir(dirstr).entryList(QStringList(fn)).isEmpty()) return ReturnTrue; } @@ -1717,7 +1762,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } #ifdef PROEVALUATOR_FULL - const QString &fn = resolvePath(args.at(0).toQString(m_tmp1)); + QString fn = resolvePath(args.at(0).toQString(m_tmp1)); + fn.detach(); if (!QDir::current().mkpath(fn)) { evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn))); return ReturnFalse; @@ -1740,13 +1786,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( if (args.count() >= 3) { const auto opts = split_value_list(args.at(2).toQStringRef()); for (const ProString &opt : opts) { - opt.toQString(m_tmp3); - if (m_tmp3 == QLatin1String("append")) { + if (opt == QLatin1String("append")) { mode = QIODevice::Append; - } else if (m_tmp3 == QLatin1String("exe")) { + } else if (opt == QLatin1String("exe")) { flags |= QMakeVfs::VfsExecutable; } else { - evalError(fL1S("write_file(): invalid flag %1.").arg(m_tmp3)); + evalError(fL1S("write_file(): invalid flag %1.").arg(opt.toQString(m_tmp3))); return ReturnFalse; } } @@ -1764,40 +1809,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( #ifdef PROEVALUATOR_FULL const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1)); const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2)); -#ifdef Q_OS_UNIX - struct stat st; - if (stat(rfn.toLocal8Bit().constData(), &st)) { - evalError(fL1S("Cannot stat() reference file %1: %2.").arg(rfn, fL1S(strerror(errno)))); + QString error; + if (!IoUtils::touchFile(tfn, rfn, &error)) { + evalError(error); return ReturnFalse; } - struct utimbuf utb; - utb.actime = time(0); - utb.modtime = st.st_mtime; - if (utime(tfn.toLocal8Bit().constData(), &utb)) { - evalError(fL1S("Cannot touch %1: %2.").arg(tfn, fL1S(strerror(errno)))); - return ReturnFalse; - } -#else - HANDLE rHand = CreateFile((wchar_t*)rfn.utf16(), - GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (rHand == INVALID_HANDLE_VALUE) { - evalError(fL1S("Cannot open reference file %1: %2").arg(rfn, windowsErrorCode())); - return ReturnFalse; - } - FILETIME ft; - GetFileTime(rHand, 0, 0, &ft); - CloseHandle(rHand); - HANDLE wHand = CreateFile((wchar_t*)tfn.utf16(), - GENERIC_WRITE, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (wHand == INVALID_HANDLE_VALUE) { - evalError(fL1S("Cannot open %1: %2").arg(tfn, windowsErrorCode())); - return ReturnFalse; - } - SetFileTime(wHand, 0, 0, &ft); - CloseHandle(wHand); -#endif #endif return ReturnTrue; } @@ -1813,21 +1829,20 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( if (args.count() >= 2) { const auto opts = split_value_list(args.at(1).toQStringRef()); for (const ProString &opt : opts) { - opt.toQString(m_tmp3); - if (m_tmp3 == QLatin1String("transient")) { + if (opt == QLatin1String("transient")) { persist = false; - } else if (m_tmp3 == QLatin1String("super")) { + } else if (opt == QLatin1String("super")) { target = TargetSuper; - } else if (m_tmp3 == QLatin1String("stash")) { + } else if (opt == QLatin1String("stash")) { target = TargetStash; - } else if (m_tmp3 == QLatin1String("set")) { + } else if (opt == QLatin1String("set")) { mode = CacheSet; - } else if (m_tmp3 == QLatin1String("add")) { + } else if (opt == QLatin1String("add")) { mode = CacheAdd; - } else if (m_tmp3 == QLatin1String("sub")) { + } else if (opt == QLatin1String("sub")) { mode = CacheSub; } else { - evalError(fL1S("cache(): invalid flag %1.").arg(m_tmp3)); + evalError(fL1S("cache(): invalid flag %1.").arg(opt.toQString(m_tmp3))); return ReturnFalse; } } @@ -1969,6 +1984,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } return writeFile(fL1S("cache "), fn, QIODevice::Append, flags, varstr); } + case T_RELOAD_PROPERTIES: +#ifdef QT_BUILD_QMAKE + m_option->reloadProperties(); +#endif + return ReturnTrue; default: evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1))); return ReturnFalse; diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 9eb14251ba9..00c87a7a23c 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -149,6 +149,7 @@ void QMakeEvaluator::initStatics() statics.strhost_build = QLatin1String("host_build"); statics.strTEMPLATE = ProKey("TEMPLATE"); statics.strQMAKE_PLATFORM = ProKey("QMAKE_PLATFORM"); + statics.strQMAKE_DIR_SEP = ProKey("QMAKE_DIR_SEP"); statics.strQMAKESPEC = ProKey("QMAKESPEC"); #ifdef PROEVALUATOR_FULL statics.strREQUIRES = ProKey("REQUIRES"); @@ -161,27 +162,27 @@ void QMakeEvaluator::initStatics() static const struct { const char * const oldname, * const newname; } mapInits[] = { - {"INTERFACES", "FORMS"}, - {"QMAKE_POST_BUILD", "QMAKE_POST_LINK"}, - {"TARGETDEPS", "POST_TARGETDEPS"}, - {"LIBPATH", "QMAKE_LIBDIR"}, - {"QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC"}, - {"QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC"}, - {"QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP"}, - {"PRECOMPH", "PRECOMPILED_HEADER"}, - {"PRECOMPCPP", "PRECOMPILED_SOURCE"}, - {"INCPATH", "INCLUDEPATH"}, - {"QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS"}, - {"QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS"}, - {"QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS"}, - {"QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS"}, - {"QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES"}, - {"QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES"}, - {"QMAKE_RPATH", "QMAKE_LFLAGS_RPATH"}, - {"QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH"}, - {"QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS"}, - {"IN_PWD", "PWD"}, - {"DEPLOYMENT", "INSTALLS"} + { "INTERFACES", "FORMS" }, + { "QMAKE_POST_BUILD", "QMAKE_POST_LINK" }, + { "TARGETDEPS", "POST_TARGETDEPS" }, + { "LIBPATH", "QMAKE_LIBDIR" }, + { "QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC" }, + { "QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC" }, + { "QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP" }, + { "PRECOMPH", "PRECOMPILED_HEADER" }, + { "PRECOMPCPP", "PRECOMPILED_SOURCE" }, + { "INCPATH", "INCLUDEPATH" }, + { "QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS" }, + { "QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS" }, + { "QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS" }, + { "QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS" }, + { "QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES" }, + { "QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES" }, + { "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" }, + { "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" }, + { "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" }, + { "IN_PWD", "PWD" }, + { "DEPLOYMENT", "INSTALLS" } }; statics.varMap.reserve((int)(sizeof(mapInits)/sizeof(mapInits[0]))); for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i) @@ -222,6 +223,7 @@ QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeV m_skipLevel = 0; #endif m_listCount = 0; + m_toggle = 0; m_valuemapStack.push(ProValueMap()); m_valuemapInited = false; } @@ -267,13 +269,13 @@ void QMakeEvaluator::skipHashStr(const ushort *&tokPtr) // FIXME: this should not build new strings for direct sections. // Note that the E_SPRINTF and E_LIST implementations rely on the deep copy. -ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, const ProFile *source) +ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, int source) { QString build; ProStringList ret; if (!source) - source = currentProFile(); + source = currentFileId(); const QChar *vals_data = vals.data(); const int vals_len = vals.length(); @@ -591,6 +593,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( tokPtr += blockLen; okey = true, or_op = false; // force next evaluation break; + case TokBypassNesting: + blockLen = getBlockLen(tokPtr); + if ((m_cumulative || okey != or_op) && blockLen) { + ProValueMapStack savedValuemapStack = m_valuemapStack; + m_valuemapStack.clear(); + m_valuemapStack.append(savedValuemapStack.takeFirst()); + traceMsg("visiting nesting-bypassing block"); + ret = visitProBlock(tokPtr); + traceMsg("visited nesting-bypassing block"); + savedValuemapStack.prepend(m_valuemapStack.first()); + m_valuemapStack = savedValuemapStack; + } else { + traceMsg("skipped nesting-bypassing block"); + ret = ReturnTrue; + } + tokPtr += blockLen; + okey = true, or_op = false; // force next evaluation + break; case TokTestDef: case TokReplaceDef: if (m_cumulative || okey != or_op) { @@ -626,7 +646,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( evalError(fL1S("Conditional must expand to exactly one word.")); okey = false; } else { - okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true); + okey = isActiveConfig(curr.at(0).toQStringRef(), true); traceMsg("condition %s is %s", dbgStr(curr.at(0)), dbgBool(okey)); okey ^= invert; } @@ -753,7 +773,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( } infinite = true; } else { - const QString &itl = it_list.toQString(m_tmp1); + const QStringRef &itl = it_list.toQStringRef(); int dotdot = itl.indexOf(statics.strDotDot); if (dotdot != -1) { bool ok; @@ -850,13 +870,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( ProStringList varVal; if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError) return ReturnError; - const QString &val = varVal.at(0).toQString(m_tmp1); + const QStringRef &val = varVal.at(0).toQStringRef(); if (val.length() < 4 || val.at(0) != QLatin1Char('s')) { evalError(fL1S("The ~= operator can handle only the s/// function.")); return ReturnTrue; } QChar sep = val.at(1); - QStringList func = val.split(sep); + auto func = val.split(sep); if (func.count() < 3 || func.count() > 4) { evalError(fL1S("The s/// function expects 3 or 4 arguments.")); return ReturnTrue; @@ -868,8 +888,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( case_sense = func[3].indexOf(QLatin1Char('i')) == -1; quote = func[3].indexOf(QLatin1Char('q')) != -1; } - QString pattern = func[1]; - QString replace = func[2]; + QString pattern = func[1].toString(); + QString replace = func[2].toString(); if (quote) pattern = QRegExp::escape(pattern); @@ -917,11 +937,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( setTemplate(); else if (varName == statics.strQMAKE_PLATFORM) m_featureRoots = 0; + else if (varName == statics.strQMAKE_DIR_SEP) + m_dirSep = first(varName); else if (varName == statics.strQMAKESPEC) { if (!values(varName).isEmpty()) { QString spec = values(varName).first().toQString(); if (IoUtils::isAbsolutePath(spec)) { m_qmakespec = spec; + m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); m_featureRoots = 0; } } @@ -947,11 +970,9 @@ void QMakeEvaluator::setTemplate() values.erase(values.begin() + 1, values.end()); } if (!m_option->user_template_prefix.isEmpty()) { - QString val = values.first().toQString(m_tmp1); - if (!val.startsWith(m_option->user_template_prefix)) { - val.prepend(m_option->user_template_prefix); - values = ProStringList(ProString(val)); - } + ProString val = values.first(); + if (!val.startsWith(m_option->user_template_prefix)) + values = ProStringList(ProString(m_option->user_template_prefix + val)); } } @@ -968,6 +989,13 @@ static ProString msvcBinDirToQMakeArch(QString subdir) subdir = subdir.toLower(); if (subdir == QLatin1String("amd64")) return ProString("x86_64"); + // Since 2017 the folder structure from here is HostX64|X86/x64|x86 + idx = subdir.indexOf(QLatin1Char('\\')); + if (idx == -1) + return ProString("x86"); + subdir.remove(0, idx + 1); + if (subdir == QLatin1String("x64")) + return ProString("x86_64"); return ProString(subdir); } @@ -1062,8 +1090,12 @@ void QMakeEvaluator::loadDefaults() vars[ProKey("QMAKE_HOST.arch")] << archStr; # if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake + // Since VS 2017 we need VCToolsInstallDir instead of VCINSTALLDIR + QString vcInstallDir = m_option->getEnv(QLatin1String("VCToolsInstallDir")); + if (vcInstallDir.isEmpty()) + vcInstallDir = m_option->getEnv(QLatin1String("VCINSTALLDIR")); vars[ProKey("QMAKE_TARGET.arch")] = msvcArchitecture( - m_option->getEnv(QLatin1String("VCINSTALLDIR")), + vcInstallDir, m_option->getEnv(QLatin1String("PATH"))); # endif #elif defined(Q_OS_UNIX) @@ -1187,8 +1219,6 @@ bool QMakeEvaluator::loadSpecInternal() // This also ensures that m_featureRoots is valid. if (evaluateFeatureFile(QLatin1String("spec_post.prf")) != ReturnTrue) return false; - // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it - m_dirSep = first(ProKey("QMAKE_DIR_SEP")); return true; } @@ -1280,7 +1310,7 @@ void QMakeEvaluator::setupProject() { setTemplate(); ProValueMap &vars = m_valuemapStack.top(); - ProFile *proFile = currentProFile(); + int proFile = currentFileId(); vars[ProKey("TARGET")] << ProString(QFileInfo(currentFileName()).baseName()).setSource(proFile); vars[ProKey("_PRO_FILE_")] << ProString(currentFileName()).setSource(proFile); vars[ProKey("_PRO_FILE_PWD_")] << ProString(currentDirectory()).setSource(proFile); @@ -1290,7 +1320,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), 0, where, -1); if (pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1411,6 +1441,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( if (flags & LoadPreFiles) { setupProject(); + if (!m_option->extra_cmds[QMakeEvalEarly].isEmpty()) + evaluateCommand(m_option->extra_cmds[QMakeEvalEarly], fL1S("(command line -early)")); + for (ProValueMap::ConstIterator it = m_extraVars.constBegin(); it != m_extraVars.constEnd(); ++it) m_valuemapStack.first().insert(it.key(), it.value()); @@ -1422,8 +1455,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( if ((vr = evaluateFeatureFile(QLatin1String("default_pre.prf"))) == ReturnError) goto failed; - if (!m_option->precmds.isEmpty()) { - evaluateCommand(m_option->precmds, fL1S("(command line)")); + if (!m_option->extra_cmds[QMakeEvalBefore].isEmpty()) { + evaluateCommand(m_option->extra_cmds[QMakeEvalBefore], fL1S("(command line)")); // Again, after user configs, to override them applyExtraConfigs(); @@ -1436,7 +1469,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( debugMsg(1, "done visiting file %s", qPrintable(pro->fileName())); if (flags & LoadPostFiles) { - evaluateCommand(m_option->postcmds, fL1S("(command line -after)")); + evaluateCommand(m_option->extra_cmds[QMakeEvalAfter], fL1S("(command line -after)")); // Again, to ensure the project does not mess with us. // Specifically, do not allow a project to override debug/release within a @@ -1446,6 +1479,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile( if ((vr = evaluateFeatureFile(QLatin1String("default_post.prf"))) == ReturnError) goto failed; + if (!m_option->extra_cmds[QMakeEvalLate].isEmpty()) + evaluateCommand(m_option->extra_cmds[QMakeEvalLate], fL1S("(command line -late)")); + if ((vr = evaluateConfigFeatures()) == ReturnError) goto failed; } @@ -1493,7 +1529,7 @@ void QMakeEvaluator::updateFeaturePaths() feature_roots += m_option->getPathListEnv(QLatin1String("QMAKEFEATURES")); feature_roots += m_qmakefeatures; feature_roots += m_option->splitPathList( - m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString(m_mtmp)); + m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString()); QStringList feature_bases; if (!m_buildRoot.isEmpty()) { @@ -1568,6 +1604,14 @@ ProFile *QMakeEvaluator::currentProFile() const return 0; } +int QMakeEvaluator::currentFileId() const +{ + ProFile *pro = currentProFile(); + if (pro) + return pro->id(); + return 0; +} + QString QMakeEvaluator::currentFileName() const { ProFile *pro = currentProFile(); @@ -1584,7 +1628,7 @@ QString QMakeEvaluator::currentDirectory() const return QString(); } -bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) +bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex) { // magic types for easy flipping if (config == statics.strtrue) @@ -1596,21 +1640,17 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) return m_hostBuild; if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) { - QString cfg = config; - cfg.detach(); // Keep m_tmp out of QRegExp's cache - QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard); + QRegExp re(config.toString(), Qt::CaseSensitive, QRegExp::Wildcard); // mkspecs if (re.exactMatch(m_qmakespecName)) return true; // CONFIG variable - int t = 0; const auto configValues = values(statics.strCONFIG); for (const ProString &configValue : configValues) { - if (re.exactMatch(configValue.toQString(m_tmp[t]))) + if (re.exactMatch(configValue.toQString(m_tmp[m_toggle ^= 1]))) return true; - t ^= 1; } } else { // mkspecs @@ -1618,7 +1658,7 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) return true; // CONFIG variable - if (values(statics.strCONFIG).contains(ProString(config))) + if (values(statics.strCONFIG).contains(config)) return true; } @@ -1713,7 +1753,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction( if (ret.at(0) == statics.strtrue) return ReturnTrue; bool ok; - int val = ret.at(0).toQString(m_tmp1).toInt(&ok); + int val = ret.at(0).toInt(&ok); if (ok) { if (val) return ReturnTrue; @@ -1762,8 +1802,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction( ProStringList args; if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError) return ReturnError; - *ret = evaluateBuiltinExpand(func_t, func, args); - return ReturnTrue; + return evaluateBuiltinExpand(func_t, func, args, *ret); } QHash::ConstIterator it = @@ -1785,7 +1824,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( const QStringRef &cond, const QString &where, int line) { VisitReturn ret = ReturnFalse; - ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); + ProFile *pro = m_parser->parsedProBlock(cond, 0, where, line, QMakeParser::TestGrammar); if (pro->isOk()) { m_locationStack.push(m_current); ret = visitProBlock(pro, pro->tokPtr()); diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index d1e734346b2..7e1911501bb 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -173,12 +173,13 @@ public: void setTemplate(); - ProStringList split_value_list(const QStringRef &vals, const ProFile *source = 0); + ProStringList split_value_list(const QStringRef &vals, int source = 0); VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined); QString currentFileName() const; QString currentDirectory() const; ProFile *currentProFile() const; + int currentFileId() const; QString resolvePath(const QString &fileName) const { return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); } @@ -209,7 +210,7 @@ public: VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret); VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr); - ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args); + VisitReturn evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args, ProStringList &ret); VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args); VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1); @@ -220,7 +221,7 @@ public: void updateMkspecPaths(); void updateFeaturePaths(); - bool isActiveConfig(const QString &config, bool regex = false); + bool isActiveConfig(const QStringRef &config, bool regex = false); void populateDeps( const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes, @@ -282,6 +283,7 @@ public: QString m_outputDir; int m_listCount; + int m_toggle; bool m_valuemapInited; bool m_hostBuild; QString m_qmakespec; @@ -301,7 +303,6 @@ public: ProStringList m_returnValue; ProValueMapStack m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii. QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString - mutable QString m_mtmp; QMakeGlobals *m_option; QMakeParser *m_parser; diff --git a/src/shared/proparser/qmakeevaluator_p.h b/src/shared/proparser/qmakeevaluator_p.h index 91c3922106d..0caa64c2321 100644 --- a/src/shared/proparser/qmakeevaluator_p.h +++ b/src/shared/proparser/qmakeevaluator_p.h @@ -39,7 +39,7 @@ r == ReturnNext ? "next" : \ r == ReturnReturn ? "return" : \ "") -# define dbgKey(s) qPrintable(s.toString().toQString()) +# define dbgKey(s) s.toString().toQStringRef().toLocal8Bit().constData() # define dbgStr(s) qPrintable(formatValue(s, true)) # define dbgStrList(s) qPrintable(formatValueList(s)) # define dbgSepStrList(s) qPrintable(formatValueList(s, true)) @@ -74,6 +74,7 @@ struct QMakeStatics { QString strhost_build; ProKey strTEMPLATE; ProKey strQMAKE_PLATFORM; + ProKey strQMAKE_DIR_SEP; ProKey strQMAKESPEC; #ifdef PROEVALUATOR_FULL ProKey strREQUIRES; diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index a50fa5437a0..5889cfcc79f 100644 --- a/src/shared/proparser/qmakeglobals.cpp +++ b/src/shared/proparser/qmakeglobals.cpp @@ -65,6 +65,7 @@ #endif QT_BEGIN_NAMESPACE +using namespace QMakeInternal; // for IoUtils #define fL1S(s) QString::fromLatin1(s) @@ -93,9 +94,9 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s { QString ret = QDir::cleanPath(spec); if (ret.contains(QLatin1Char('/'))) { - QString absRet = QDir(state.pwd).absoluteFilePath(ret); + QString absRet = IoUtils::resolvePath(state.pwd, ret); if (QFile::exists(absRet)) - ret = QDir::cleanPath(absRet); + ret = absRet; } return ret; } @@ -108,10 +109,7 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( QString arg = args.at(*pos); switch (argState) { case ArgConfig: - if (state.after) - state.postconfigs << arg; - else - state.preconfigs << arg; + state.configs[state.phase] << arg; break; case ArgSpec: qmakespec = args[*pos] = cleanSpec(state, arg); @@ -126,20 +124,26 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( user_template_prefix = arg; break; case ArgCache: - cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; case ArgQtConf: - qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; default: if (arg.startsWith(QLatin1Char('-'))) { if (arg == QLatin1String("--")) { state.extraargs = args.mid(*pos + 1); - *pos = args.size(); + args.erase(args.begin() + *pos, args.end()); return ArgumentsOk; } - if (arg == QLatin1String("-after")) - state.after = true; + if (arg == QLatin1String("-early")) + state.phase = QMakeEvalEarly; + else if (arg == QLatin1String("-before")) + state.phase = QMakeEvalBefore; + else if (arg == QLatin1String("-after")) + state.phase = QMakeEvalAfter; + else if (arg == QLatin1String("-late")) + state.phase = QMakeEvalLate; else if (arg == QLatin1String("-config")) argState = ArgConfig; else if (arg == QLatin1String("-nocache")) @@ -163,10 +167,7 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( else return ArgumentUnknown; } else if (arg.contains(QLatin1Char('='))) { - if (state.after) - state.postcmds << arg; - else - state.precmds << arg; + state.cmds[state.phase] << arg; } else { return ArgumentUnknown; } @@ -181,18 +182,17 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state) { - if (!state.preconfigs.isEmpty()) - state.precmds << (fL1S("CONFIG += ") + state.preconfigs.join(QLatin1Char(' '))); if (!state.extraargs.isEmpty()) { QString extra = fL1S("QMAKE_EXTRA_ARGS ="); foreach (const QString &ea, state.extraargs) extra += QLatin1Char(' ') + QMakeEvaluator::quoteValue(ProString(ea)); - state.precmds << extra; + state.cmds[QMakeEvalBefore] << extra; + } + for (int p = 0; p < 4; p++) { + if (!state.configs[p].isEmpty()) + state.cmds[p] << (fL1S("CONFIG += ") + state.configs[p].join(QLatin1Char(' '))); + extra_cmds[p] = state.cmds[p].join(QLatin1Char('\n')); } - precmds = state.precmds.join(QLatin1Char('\n')); - if (!state.postconfigs.isEmpty()) - state.postcmds << (fL1S("CONFIG += ") + state.postconfigs.join(QLatin1Char(' '))); - postcmds = state.postcmds.join(QLatin1Char('\n')); if (xqmakespec.isEmpty()) xqmakespec = qmakespec; @@ -257,11 +257,11 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const { QStringList ret; if (!val.isEmpty()) { - QDir bdir; + QString cwd(QDir::currentPath()); const QStringList vals = val.split(dirlist_sep); ret.reserve(vals.length()); for (const QString &it : vals) - ret << QDir::cleanPath(bdir.absoluteFilePath(it)); + ret << IoUtils::resolvePath(cwd, it); } return ret; } @@ -316,7 +316,7 @@ bool QMakeGlobals::initProperties() return false; data = proc.readAll(); #else - if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation) + if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation) + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) { char buff[1024]; while (!feof(proc)) diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 98b269a30a2..96e22992140 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -46,6 +46,8 @@ QT_BEGIN_NAMESPACE class QMakeEvaluator; +enum QMakeEvalPhase { QMakeEvalEarly, QMakeEvalBefore, QMakeEvalAfter, QMakeEvalLate }; + class QMakeBaseKey { public: @@ -79,12 +81,13 @@ public: class QMAKE_EXPORT QMakeCmdLineParserState { public: - QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), after(false) {} + QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), phase(QMakeEvalBefore) {} QString pwd; - QStringList precmds, preconfigs, postcmds, postconfigs, extraargs; - bool after; + QStringList cmds[4], configs[4]; + QStringList extraargs; + QMakeEvalPhase phase; - void flush() { after = false; } + void flush() { phase = QMakeEvalBefore; } }; class QMAKE_EXPORT QMakeGlobals @@ -101,12 +104,12 @@ public: QProcessEnvironment environment; #endif QString qmake_abslocation; - QStringList qmake_args; + QStringList qmake_args, qmake_extra_args; QString qtconf; QString qmakespec, xqmakespec; QString user_template, user_template_prefix; - QString precmds, postcmds; + QString extra_cmds[4]; #ifdef PROEVALUATOR_DEBUG int debugLevel; @@ -121,6 +124,7 @@ public: void setDirectories(const QString &input_dir, const QString &output_dir); #ifdef QT_BUILD_QMAKE void setQMakeProperty(QMakeProperty *prop) { property = prop; } + void reloadProperties() { property->reload(); } ProString propertyValue(const ProKey &name) const { return property->value(name); } #else static void parseProperties(const QByteArray &data, QHash &props); diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index 5d1bd710431..6b0ae22e83d 100644 --- a/src/shared/proparser/qmakeparser.cpp +++ b/src/shared/proparser/qmakeparser.cpp @@ -49,12 +49,22 @@ ProFileCache::~ProFileCache() ent.pro->deref(); } -void ProFileCache::discardFile(const QString &fileName) +void ProFileCache::discardFile(const QString &fileName, QMakeVfs *vfs) +{ + int eid = vfs->idForFileName(fileName, QMakeVfs::VfsExact | QMakeVfs::VfsAccessedOnly); + if (eid) + discardFile(eid); + int cid = vfs->idForFileName(fileName, QMakeVfs::VfsCumulative | QMakeVfs::VfsAccessedOnly); + if (cid && cid != eid) + discardFile(cid); +} + +void ProFileCache::discardFile(int id) { #ifdef PROPARSER_THREAD_SAFE QMutexLocker lck(&mutex); #endif - QHash::Iterator it = parsed_files.find(fileName); + auto it = parsed_files.find(id); if (it != parsed_files.end()) { #ifdef PROPARSER_THREAD_SAFE if (it->locker) { @@ -74,16 +84,16 @@ void ProFileCache::discardFile(const QString &fileName) } } -void ProFileCache::discardFiles(const QString &prefix) +void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs) { #ifdef PROPARSER_THREAD_SAFE QMutexLocker lck(&mutex); #endif - QHash::Iterator - it = parsed_files.begin(), - end = parsed_files.end(); - while (it != end) - if (it.key().startsWith(prefix)) { + auto it = parsed_files.begin(), end = parsed_files.end(); + while (it != end) { + // Note: this is empty for virtual files from other VFSes. + QString fn = vfs->fileNameForId(it.key()); + if (fn.startsWith(prefix)) { #ifdef PROPARSER_THREAD_SAFE if (it->locker) { if (!it->locker->done) { @@ -102,6 +112,7 @@ void ProFileCache::discardFiles(const QString &prefix) } else { ++it; } + } } ////////// Parser /////////// @@ -115,6 +126,7 @@ static struct { QString strfor; QString strdefineTest; QString strdefineReplace; + QString strbypassNesting; QString stroption; QString strreturn; QString strnext; @@ -138,6 +150,7 @@ void QMakeParser::initialize() statics.strfor = QLatin1String("for"); statics.strdefineTest = QLatin1String("defineTest"); statics.strdefineReplace = QLatin1String("defineReplace"); + statics.strbypassNesting = QLatin1String("bypassNesting"); statics.stroption = QLatin1String("option"); statics.strreturn = QLatin1String("return"); statics.strnext = QLatin1String("next"); @@ -162,18 +175,15 @@ QMakeParser::QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) { ProFile *pro; - if ((flags & (ParseUseCache|ParseOnlyCached)) && m_cache) { + QMakeVfs::VfsFlags vfsFlags = ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative + : QMakeVfs::VfsExact); + int id = m_vfs->idForFileName(fileName, vfsFlags); + if ((flags & ParseUseCache) && m_cache) { ProFileCache::Entry *ent; #ifdef PROPARSER_THREAD_SAFE QMutexLocker locker(&m_cache->mutex); #endif - QHash::Iterator it; -#ifdef PROEVALUATOR_DUAL_VFS - QString virtFileName = ((flags & ParseCumulative) ? '-' : '+') + fileName; - it = m_cache->parsed_files.find(virtFileName); - if (it == m_cache->parsed_files.end()) -#endif - it = m_cache->parsed_files.find(fileName); + auto it = m_cache->parsed_files.find(id); if (it != m_cache->parsed_files.end()) { ent = &*it; #ifdef PROPARSER_THREAD_SAFE @@ -190,24 +200,15 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) #endif if ((pro = ent->pro)) pro->ref(); - } else if (!(flags & ParseOnlyCached)) { - QString contents; - QMakeVfs::VfsFlags vfsFlags = - ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); - bool virt = false; -#ifdef PROEVALUATOR_DUAL_VFS - virt = m_vfs->readVirtualFile(fileName, vfsFlags, &contents); - if (virt) - ent = &m_cache->parsed_files[virtFileName]; - else -#endif - ent = &m_cache->parsed_files[fileName]; + } else { + ent = &m_cache->parsed_files[id]; #ifdef PROPARSER_THREAD_SAFE ent->locker = new ProFileCache::Entry::Locker; locker.unlock(); #endif - if (virt || readFile(fileName, vfsFlags | QMakeVfs::VfsNoVirtual, flags, &contents)) { - pro = parsedProBlock(QStringRef(&contents), fileName, 1, FullGrammar); + QString contents; + if (readFile(id, flags, &contents)) { + pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); pro->itemsRef()->squeeze(); pro->ref(); } else { @@ -224,46 +225,39 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) ent->locker = 0; } #endif - } else { - pro = 0; } - } else if (!(flags & ParseOnlyCached)) { + } else { QString contents; - QMakeVfs::VfsFlags vfsFlags = - ((flags & ParseCumulative) ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); - if (readFile(fileName, vfsFlags, flags, &contents)) - pro = parsedProBlock(QStringRef(&contents), fileName, 1, FullGrammar); + if (readFile(id, flags, &contents)) + pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); else pro = 0; - } else { - pro = 0; } return pro; } ProFile *QMakeParser::parsedProBlock( - const QStringRef &contents, const QString &name, int line, SubGrammar grammar) + const QStringRef &contents, int id, const QString &name, int line, SubGrammar grammar) { - ProFile *pro = new ProFile(name); + ProFile *pro = new ProFile(id, name); read(pro, contents, line, grammar); return pro; } -void QMakeParser::discardFileFromCache(const QString &fileName) +void QMakeParser::discardFileFromCache(int id) { if (m_cache) - m_cache->discardFile(fileName); + m_cache->discardFile(id); } -bool QMakeParser::readFile( - const QString &fn, QMakeVfs::VfsFlags vfsFlags, ParseFlags flags, QString *contents) +bool QMakeParser::readFile(int id, ParseFlags flags, QString *contents) { QString errStr; - QMakeVfs::ReadResult result = m_vfs->readFile(fn, vfsFlags, contents, &errStr); + QMakeVfs::ReadResult result = m_vfs->readFile(id, contents, &errStr); if (result != QMakeVfs::ReadOk) { if (m_handler && ((flags & ParseReportMissing) || result != QMakeVfs::ReadNotFound)) m_handler->message(QMakeParserHandler::ParserIoError, - fL1S("Cannot read %1: %2").arg(fn, errStr)); + fL1S("Cannot read %1: %2").arg(m_vfs->fileNameForId(id), errStr)); return false; } return true; @@ -1171,6 +1165,25 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg } parseError(fL1S("%1(function) requires one literal argument.").arg(*defName)); return; + } else if (m_tmp == statics.strbypassNesting) { + if (*uce != TokFuncTerminator) { + bogusTest(tokPtr, fL1S("%1() requires zero arguments.").arg(m_tmp)); + return; + } + if (!(m_blockstack.top().nest & NestFunction)) { + bogusTest(tokPtr, fL1S("Unexpected %1().").arg(m_tmp)); + return; + } + if (m_invert) { + bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp)); + return; + } + flushScopes(tokPtr); + putLineMarker(tokPtr); + putOperator(tokPtr); + putTok(tokPtr, TokBypassNesting); + enterScope(tokPtr, true, StCtrl); + return; } else if (m_tmp == statics.strreturn) { if (m_blockstack.top().nest & NestFunction) { if (argc > 1) { @@ -1439,7 +1452,7 @@ static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outS "TokReturn", "TokBreak", "TokNext", "TokNot", "TokAnd", "TokOr", "TokBranch", "TokForLoop", - "TokTestDef", "TokReplaceDef" + "TokTestDef", "TokReplaceDef", "TokBypassNesting" }; while (offset != limit) { @@ -1523,6 +1536,9 @@ static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outS if (ok) ok = getSubBlock(tokens, limit, offset, outStr, indent, "body"); break; + case TokBypassNesting: + ok = getSubBlock(tokens, limit, offset, outStr, indent, "block"); + break; default: Q_ASSERT(!"unhandled token"); } diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h index 43fa354b9e4..0612b922620 100644 --- a/src/shared/proparser/qmakeparser.h +++ b/src/shared/proparser/qmakeparser.h @@ -75,7 +75,6 @@ public: enum ParseFlag { ParseDefault = 0, ParseUseCache = 1, - ParseOnlyCached = 2, ParseReportMissing = 4, #ifdef PROEVALUATOR_DUAL_VFS ParseCumulative = 8 @@ -90,10 +89,10 @@ public: enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); - ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0, + ProFile *parsedProBlock(const QStringRef &contents, int id, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); - void discardFileFromCache(const QString &fileName); + void discardFileFromCache(int id); #ifdef PROPARSER_DEBUG static QString formatProBlock(const QString &block); @@ -132,7 +131,7 @@ private: ushort terminator; // '}' if replace function call is braced, ':' if test function }; - bool readFile(const QString &fn, QMakeVfs::VfsFlags vfsFlags, QMakeParser::ParseFlags flags, QString *contents); + bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents); void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); @@ -201,8 +200,9 @@ public: ProFileCache() {} ~ProFileCache(); - void discardFile(const QString &fileName); - void discardFiles(const QString &prefix); + void discardFile(int id); + void discardFile(const QString &fileName, QMakeVfs *vfs); + void discardFiles(const QString &prefix, QMakeVfs *vfs); private: struct Entry { @@ -218,7 +218,7 @@ private: #endif }; - QHash parsed_files; + QHash parsed_files; #ifdef PROPARSER_THREAD_SAFE QMutex mutex; #endif diff --git a/src/shared/proparser/qmakevfs.cpp b/src/shared/proparser/qmakevfs.cpp index 4dd1192aff7..d7248fbd5be 100644 --- a/src/shared/proparser/qmakevfs.cpp +++ b/src/shared/proparser/qmakevfs.cpp @@ -51,19 +51,85 @@ QMakeVfs::QMakeVfs() #endif } -bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags flags, +#ifdef PROPARSER_THREAD_SAFE +QMutex QMakeVfs::s_mutex; +#endif +QAtomicInt QMakeVfs::s_fileIdCounter; +QHash QMakeVfs::s_fileIdMap; +QHash QMakeVfs::s_idFileMap; + +int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags) +{ +#ifdef PROEVALUATOR_DUAL_VFS + { +# ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&m_vmutex); +# endif + int idx = (flags & VfsCumulative) ? 1 : 0; + if (flags & VfsCreate) { + int &id = m_virtualFileIdMap[idx][fn]; + if (!id) { + id = ++s_fileIdCounter; + m_virtualIdFileMap[id] = fn; + } + return id; + } + int id = m_virtualFileIdMap[idx].value(fn); + if (id || (flags & VfsCreatedOnly)) + return id; + } +#endif + if (!(flags & VfsAccessedOnly)) { +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + int &id = s_fileIdMap[fn]; + if (!id) { + id = ++s_fileIdCounter; + s_idFileMap[id] = fn; + } + return id; + } + return s_fileIdMap.value(fn); +} + +QString QMakeVfs::fileNameForId(int id) +{ +#ifdef PROEVALUATOR_DUAL_VFS + { +# ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&m_vmutex); +# endif + const QString &fn = m_virtualIdFileMap.value(id); + if (!fn.isEmpty()) + return fn; + } +#endif +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + return s_idFileMap.value(id); +} + +void QMakeVfs::clearIds() +{ +#ifdef PROEVALUATOR_THREAD_SAFE + QMutexLocker locker(&s_mutex); +#endif + s_fileIdCounter = 0; + s_fileIdMap.clear(); + s_idFileMap.clear(); +} + +bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif -#ifdef PROEVALUATOR_DUAL_VFS - QString *cont = &m_files[((flags & VfsCumulative) ? '-' : '+') + fn]; -#else - QString *cont = &m_files[fn]; + QString *cont = &m_files[id]; Q_UNUSED(flags) -#endif if (mode & QIODevice::Append) *cont += contents; else @@ -71,13 +137,13 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags f Q_UNUSED(errStr) return true; #else - QFileInfo qfi(fn); + QFileInfo qfi(fileNameForId(id)); if (!QDir::current().mkpath(qfi.path())) { *errStr = fL1S("Cannot create parent directory"); return false; } QByteArray bytes = contents.toLocal8Bit(); - QFile cfile(fn); + QFile cfile(qfi.filePath()); if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (cfile.readAll() == bytes) { if (flags & VfsExecutable) { @@ -108,53 +174,13 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags f #endif } -#ifndef PROEVALUATOR_FULL -bool QMakeVfs::readVirtualFile(const QString &fn, VfsFlags flags, QString *contents) -{ -# ifdef PROEVALUATOR_THREAD_SAFE - QMutexLocker locker(&m_mutex); -# endif - QHash::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) { - *contents = *it; - return true; - } -# else - it = m_files.constFind(fn); - if (it != m_files.constEnd() - && it->constData() != m_magicMissing.constData() - && it->constData() != m_magicExisting.constData()) { - *contents = *it; - return true; - } - Q_UNUSED(flags) -# endif - return false; -} -#endif - -QMakeVfs::ReadResult QMakeVfs::readFile( - const QString &fn, VfsFlags flags, QString *contents, QString *errStr) +QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errStr) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - if (!(flags & VfsNoVirtual)) { - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) { - *contents = *it; - return ReadOk; - } - } -# else - Q_UNUSED(flags) -# endif - it = m_files.constFind(fn); + auto it = m_files.constFind(id); if (it != m_files.constEnd()) { if (it->constData() == m_magicMissing.constData()) { *errStr = fL1S("No such file or directory"); @@ -165,15 +191,13 @@ QMakeVfs::ReadResult QMakeVfs::readFile( return ReadOk; } } -#else - Q_UNUSED(flags) #endif - QFile file(fn); + QFile file(fileNameForId(id)); if (!file.open(QIODevice::ReadOnly)) { if (!file.exists()) { #ifndef PROEVALUATOR_FULL - m_files[fn] = m_magicMissing; + m_files[id] = m_magicMissing; #endif *errStr = fL1S("No such file or directory"); return ReadNotFound; @@ -182,7 +206,7 @@ QMakeVfs::ReadResult QMakeVfs::readFile( return ReadOtherError; } #ifndef PROEVALUATOR_FULL - m_files[fn] = m_magicExisting; + m_files[id] = m_magicExisting; #endif QByteArray bcont = file.readAll(); @@ -205,15 +229,8 @@ bool QMakeVfs::exists(const QString &fn, VfsFlags flags) # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash::ConstIterator it; -# ifdef PROEVALUATOR_DUAL_VFS - it = m_files.constFind(((flags & VfsCumulative) ? '-' : '+') + fn); - if (it != m_files.constEnd()) - return true; -# else - Q_UNUSED(flags) -# endif - it = m_files.constFind(fn); + int id = idForFileName(fn, flags); + auto it = m_files.constFind(id); if (it != m_files.constEnd()) return it->constData() != m_magicMissing.constData(); #else @@ -221,7 +238,7 @@ bool QMakeVfs::exists(const QString &fn, VfsFlags flags) #endif bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular; #ifndef PROEVALUATOR_FULL - m_files[fn] = ex ? m_magicExisting : m_magicMissing; + m_files[id] = ex ? m_magicExisting : m_magicMissing; #endif return ex; } @@ -233,7 +250,7 @@ void QMakeVfs::invalidateCache() # ifdef PROEVALUATOR_THREAD_SAFE QMutexLocker locker(&m_mutex); # endif - QHash::Iterator it = m_files.begin(), eit = m_files.end(); + auto it = m_files.begin(), eit = m_files.end(); while (it != eit) { if (it->constData() == m_magicMissing.constData() ||it->constData() == m_magicExisting.constData()) diff --git a/src/shared/proparser/qmakevfs.h b/src/shared/proparser/qmakevfs.h index b6b93fb5dd5..da0d0626d8f 100644 --- a/src/shared/proparser/qmakevfs.h +++ b/src/shared/proparser/qmakevfs.h @@ -27,13 +27,11 @@ #include "qmake_global.h" -# include -#ifndef PROEVALUATOR_FULL -# include -# include -# ifdef PROEVALUATOR_THREAD_SAFE -# include -# endif +#include +#include +#include +#ifdef PROEVALUATOR_THREAD_SAFE +# include #endif #ifndef QT_NO_TEXTCODEC @@ -62,23 +60,27 @@ public: VfsExact = 0, #ifdef PROEVALUATOR_DUAL_VFS VfsCumulative = 2, - VfsNoVirtual = 4 + VfsCreate = 4, + VfsCreatedOnly = 8, #else VfsCumulative = 0, - VfsNoVirtual = 0 + VfsCreate = 0, + VfsCreatedOnly = 0, #endif + VfsAccessedOnly = 16 }; Q_DECLARE_FLAGS(VfsFlags, VfsFlag) QMakeVfs(); - bool writeFile(const QString &fn, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr); - ReadResult readFile(const QString &fn, VfsFlags flags, QString *contents, QString *errStr); - bool exists(const QString &fn, VfsFlags flags); + int idForFileName(const QString &fn, VfsFlags flags); + QString fileNameForId(int id); + static void clearIds(); + bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr); + ReadResult readFile(int id, QString *contents, QString *errStr); + bool exists(const QString &fn, QMakeVfs::VfsFlags flags); #ifndef PROEVALUATOR_FULL - bool readVirtualFile(const QString &fn, VfsFlags flags, QString *contents); - void invalidateCache(); void invalidateContents(); #endif @@ -88,11 +90,34 @@ public: #endif private: +#ifdef PROEVALUATOR_THREAD_SAFE + static QMutex s_mutex; +#endif + static QAtomicInt s_fileIdCounter; + // Qt Creator's ProFile cache is a singleton to maximize its cross-project + // effectiveness (shared prf files from QtVersions). + // For this to actually work, real files need a global mapping. + // This is fine, because the namespace of real files is indeed global. + static QHash s_fileIdMap; + static QHash s_idFileMap; +#ifdef PROEVALUATOR_DUAL_VFS +# ifdef PROEVALUATOR_THREAD_SAFE + // The simple way to avoid recursing m_mutex. + QMutex m_vmutex; +# endif + // Virtual files are bound to the project context they were created in, + // so their ids need to be local as well. + // We violate that rule in lupdate (which has a non-dual VFS), but that + // does not matter, because it has only one project context anyway. + QHash m_virtualFileIdMap[2]; // Exact and cumulative + QHash m_virtualIdFileMap; // Only one map, as ids are unique across realms. +#endif + #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE QMutex m_mutex; # endif - QHash m_files; + QHash m_files; QString m_magicMissing; QString m_magicExisting; #endif diff --git a/src/shared/qbs b/src/shared/qbs index abfc4c1b37d..2c0962017e2 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit abfc4c1b37d18515c8da0678a665886d7cb69af5 +Subproject commit 2c0962017e24574b3d92599229384b2e7beb1794 diff --git a/tests/auto/profilewriter/profilewriter.qbs b/tests/auto/profilewriter/profilewriter.qbs index 03de7d00d37..ba420c4817f 100644 --- a/tests/auto/profilewriter/profilewriter.qbs +++ b/tests/auto/profilewriter/profilewriter.qbs @@ -25,4 +25,5 @@ QtcAutotest { files: "tst_profilewriter.cpp" } cpp.includePaths: base.concat([proParserGroup.prefix]) + cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS") } diff --git a/tests/auto/profilewriter/tst_profilewriter.cpp b/tests/auto/profilewriter/tst_profilewriter.cpp index 999ac0ae41c..0e927e1e9a3 100644 --- a/tests/auto/profilewriter/tst_profilewriter.cpp +++ b/tests/auto/profilewriter/tst_profilewriter.cpp @@ -448,7 +448,7 @@ void tst_ProFileWriter::adds() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringRef(&input), QLatin1String(BASE_DIR "/test.pro"), 1); + ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope); proFile->deref(); @@ -619,7 +619,7 @@ void tst_ProFileWriter::removes() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringRef(&input), QLatin1String(BASE_DIR "/test.pro"), 1); + ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); QmakeProjectManager::Internal::ProWriter::removeVarValues(proFile, &lines, values, vars); proFile->deref(); @@ -648,7 +648,7 @@ void tst_ProFileWriter::multiVar() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringRef(&input), QLatin1String(BASE_DIR "/test.pro"), 1); + ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); QmakeProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, baseDir, files, vars); proFile->deref(); @@ -669,7 +669,7 @@ void tst_ProFileWriter::addFiles() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringRef(&input), QLatin1String(BASE_DIR "/test.pro"), 1); + ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines, QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"), @@ -691,7 +691,7 @@ void tst_ProFileWriter::removeFiles() QMakeVfs vfs; QMakeParser parser(0, &vfs, &parseHandler); - ProFile *proFile = parser.parsedProBlock(QStringRef(&input), QLatin1String(BASE_DIR "/test.pro"), 1); + ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); QmakeProjectManager::Internal::ProWriter::removeFiles(proFile, &lines, QDir(BASE_DIR), QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"), diff --git a/tests/system/shared/workarounds.py b/tests/system/shared/workarounds.py index 7ab37d44731..cb1cc0ba845 100644 --- a/tests/system/shared/workarounds.py +++ b/tests/system/shared/workarounds.py @@ -255,18 +255,9 @@ class JIRA: # for later lookup which function to call for which bug # ALWAYS update this dict when adding a new function for a workaround! def __initBugDict__(self): - self.__bugs__= { - 'QTCREATORBUG-19717':self._workaroundCreator19717_, - } + self.__bugs__= {} # helper function - will be called if no workaround for the requested bug is deposited def _exitFatal_(self, bugType, number): test.fatal("No workaround found for bug %s-%d" % (bugType, number)) ############### functions that hold workarounds ################################# - - def _workaroundCreator19717_(self, *args): - targetname = Targets.getStringForTarget(Targets.DESKTOP_5_3_1_DEFAULT) - switchViewTo(ViewConstants.PROJECTS) - mouseClick(waitForObjectItem(":Projects.ProjectNavigationTreeView", - "Build & Run." + targetname.replace(".", "\\."))) - switchViewTo(ViewConstants.EDIT) diff --git a/tests/system/suite_debugger/tst_qml_js_console/test.py b/tests/system/suite_debugger/tst_qml_js_console/test.py index 7c324b6970b..7187fc9ceaa 100644 --- a/tests/system/suite_debugger/tst_qml_js_console/test.py +++ b/tests/system/suite_debugger/tst_qml_js_console/test.py @@ -124,8 +124,6 @@ def main(): if not startedWithoutPluginError(): return - JIRA.performWorkaroundForBug(19717) - # if Debug is enabled - 1 valid kit is assigned - real check for this is done in tst_qml_locals fancyDebugButton = waitForObject(":*Qt Creator.Start Debugging_Core::Internal::FancyToolButton") if test.verify(waitFor('fancyDebugButton.enabled', 5000), "Start Debugging is enabled."): diff --git a/tests/system/suite_debugger/tst_qml_locals/test.py b/tests/system/suite_debugger/tst_qml_locals/test.py index 54be9f918a7..fb6d45c649c 100644 --- a/tests/system/suite_debugger/tst_qml_locals/test.py +++ b/tests/system/suite_debugger/tst_qml_locals/test.py @@ -43,7 +43,6 @@ def main(): startApplication('qtcreator' + SettingsPath + ' "%s"' % qmlProjFile) if not startedWithoutPluginError(): return - JIRA.performWorkaroundForBug(19717) waitFor('object.exists(":Qt Creator_Utils::NavigationTreeView")', 10000) fancyConfButton = findObject(":*Qt Creator_Core::Internal::FancyToolButton") fancyRunButton = findObject(":*Qt Creator.Run_Core::Internal::FancyToolButton") diff --git a/tests/system/suite_editors/tst_qml_editor/test.py b/tests/system/suite_editors/tst_qml_editor/test.py index c61b7aa43de..06679825214 100644 --- a/tests/system/suite_editors/tst_qml_editor/test.py +++ b/tests/system/suite_editors/tst_qml_editor/test.py @@ -25,10 +25,12 @@ source("../../shared/qtcreator.py") +focusDocumentPath = "keyinteraction.Resources.keyinteraction\.qrc./keyinteraction.focus.%s" + def main(): - target = Targets.DESKTOP_5_3_1_DEFAULT - sourceExample = os.path.join(Qt5Path.examplesPath(target), "declarative/keyinteraction/focus") - proFile = "focus.pro" + target = Targets.DESKTOP_5_6_1_DEFAULT + sourceExample = os.path.join(Qt5Path.examplesPath(target), "quick/keyinteraction") + proFile = "keyinteraction.pro" if not neededFilePresent(os.path.join(sourceExample, proFile)): return startApplication("qtcreator" + SettingsPath) @@ -36,9 +38,9 @@ def main(): return # add docs to have the correct tool tips addHelpDocumentation([os.path.join(Qt5Path.docsPath(target), "qtquick.qch")]) - templateDir = prepareTemplate(sourceExample, "/../../helper") + templateDir = prepareTemplate(sourceExample) openQmakeProject(os.path.join(templateDir, proFile), [target]) - openDocument("focus.QML.qml" + os.sep + "focus.focus\\.qml") + openDocument(focusDocumentPath % "focus\\.qml") testRenameId() testFindUsages() testHovering() @@ -47,20 +49,20 @@ def main(): def testRenameId(): test.log("Testing rename of id") - files = ["FocusCore.ContextMenu\\.qml", "FocusCore.GridMenu\\.qml", - "FocusCore.ListMenu\\.qml", "focus\\.qml"] + files = ["Core.ContextMenu\\.qml", "Core.GridMenu\\.qml", + "Core.ListMenu\\.qml", "focus\\.qml"] originalTexts = {} editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") formerTxt = editor.plainText for file in files: - openDocument("focus.QML.qml" + os.sep + "focus.%s" % file) + openDocument(focusDocumentPath % file) # wait until editor content switched to the double-clicked file while formerTxt==editor.plainText: editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") # store content for next round formerTxt = editor.plainText originalTexts.setdefault(file, "%s" % formerTxt) - test.log("stored %s's content" % file.replace("FocusCore.","").replace("\\","")) + test.log("stored %s's content" % file.replace("Core.","").replace("\\","")) # last opened file is the main file focus.qml line = "FocusScope\s*\{" if not placeCursorToLine(editor, line, True): @@ -77,18 +79,18 @@ def testRenameId(): # store editor content for synchronizing purpose formerTxt = editor.plainText for file in files: - openDocument("focus.QML.qml" + os.sep + "focus.%s" % file) + openDocument(focusDocumentPath % file) # wait until editor content switched to double-clicked file while formerTxt==editor.plainText: editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") # store content for next round formerTxt = editor.plainText originalText = originalTexts.get(file).replace("mainView", "renamedView") - test.compare(originalText,formerTxt, "Comparing %s" % file.replace("FocusCore.","").replace("\\","")) + test.compare(originalText,formerTxt, "Comparing %s" % file.replace("Core.","").replace("\\","")) invokeMenuItem("File","Save All") def __invokeFindUsage__(filename, line, additionalKeyPresses, expectedCount): - openDocument("focus.QML.qml" + os.sep + "focus.%s" % filename) + openDocument(focusDocumentPath % filename) editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") if not placeCursorToLine(editor, line, True): test.fatal("File seems to have changed... Canceling current test") @@ -101,17 +103,18 @@ def __invokeFindUsage__(filename, line, additionalKeyPresses, expectedCount): def testFindUsages(): test.log("Testing find usage of an ID") - __invokeFindUsage__("focus\\.qml", "FocusScope\s*\{", [""], 6) + __invokeFindUsage__("focus\\.qml", "FocusScope\s*\{", [""], 7) test.log("Testing find usage of a property") clickButton(waitForObject(":*Qt Creator.Clear_QToolButton")) home = "" if platform.system() == "Darwin": home = "" - __invokeFindUsage__("focus\\.qml", "id: window", ["", "", home], 26) + __invokeFindUsage__("focus\\.qml", "id: window", ["", "", home], + 29 if JIRA.isBugStillOpen(19915) else 30) def testHovering(): test.log("Testing hovering elements") - openDocument("focus.QML.qml" + os.sep + "focus.focus\\.qml") + openDocument(focusDocumentPath % "focus\\.qml") editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") lines=["FocusScope\s*\{", "Rectangle\s*\{"] if platform.system() == "Darwin": @@ -129,7 +132,7 @@ def testHovering(): alternativeValues = [{"text":"FocusScope"}, {"text":"Rectangle"}] verifyHoveringOnEditor(editor, lines, additionalKeyPresses, expectedTypes, expectedValues, alternativeValues) test.log("Testing hovering properties") - openDocument("focus.QML.qml" + os.sep + "focus.focus\\.qml") + openDocument(focusDocumentPath % "focus\\.qml") editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") lines = ['focus:\s*true', 'color:\s*"black"', 'states:\s*State\s*\{', 'transitions:\s*Transition\s*\{'] expectedTypes = ["TextTip", "TextTip", "TextTip", "TextTip"] @@ -141,15 +144,19 @@ def testHovering(): '>'}, {'text':'
string

This property holds the color used to fill the rectangle.' '

  
'}, - {'text':'
State

This property holds a list of states defined by the item.' + {'text':'
State

This property holds the list of possible states for this item. ' + 'To change the state of this item, set the state property to one of these states, or set the state property ' + 'to an empty string to revert the item to its default state.' '

  
'}, - {'text':'
Transition

This property holds a list of transitions defined by ' - 'the item.

  
'} + {'text':'
Transition

This property holds the list of transitions for this item. ' + 'These define the transitions to be applied to the item whenever it changes its state.' + '

  
'} ] - alternativeValues = [{"text":"boolean"}, {"text":"string"}, {"text":"State"}, {"text":"Transition"}] + alternativeValues = [{"text":"Rectangle" if JIRA.isBugStillOpen(20020) else "boolean"}, + {"text":"string"}, {"text":"State"}, {"text":"Transition"}] verifyHoveringOnEditor(editor, lines, additionalKeyPresses, expectedTypes, expectedValues, alternativeValues) test.log("Testing hovering expressions") - openDocument("focus.QML.qml" + os.sep + "focus.focus\\.qml") + openDocument(focusDocumentPath % "focus\\.qml") editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") lines=['color:\s*"black"', 'color:\s*"#3E606F"'] additionalKeyPresses = [""] @@ -157,7 +164,7 @@ def testHovering(): alternativeValues = [None, "#39616B"] expectedTypes = ["ColorTip", "ColorTip"] verifyHoveringOnEditor(editor, lines, additionalKeyPresses, expectedTypes, expectedValues, alternativeValues) - openDocument("focus.QML.qml" + os.sep + "focus.FocusCore.ListMenu\\.qml") + openDocument(focusDocumentPath % "Core.ListMenu\\.qml") editor = waitForObject(":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget") lines=['Rectangle\s*\{.*color:\s*"#D1DBBD"', 'NumberAnimation\s*\{\s*.*Easing.OutQuint\s*\}'] additionalKeyPresses = ["", "", "", ""] diff --git a/tests/system/suite_general/tst_opencreator_qbs/test.py b/tests/system/suite_general/tst_opencreator_qbs/test.py index 60cc0d34444..9a11127df8f 100644 --- a/tests/system/suite_general/tst_opencreator_qbs/test.py +++ b/tests/system/suite_general/tst_opencreator_qbs/test.py @@ -26,9 +26,8 @@ source("../../shared/qtcreator.py") def main(): - if platform.system() == 'Darwin': - test.warning("This needs a Qt 5.4 kit. Skipping it.") - return + test.warning("This needs a Qt 5.6.2 kit. Skipping it.") + return pathCreator = os.path.join(srcPath, "creator", "qtcreator.qbs") if not neededFilePresent(pathCreator): return diff --git a/tests/system/suite_general/tst_rename_file/test.py b/tests/system/suite_general/tst_rename_file/test.py index ee55e9c2b47..7bf2c882ea7 100644 --- a/tests/system/suite_general/tst_rename_file/test.py +++ b/tests/system/suite_general/tst_rename_file/test.py @@ -101,8 +101,12 @@ def renameFile(projectDir, proFile, branch, oldname, newname): else: menu = ":Qt Creator.Project.Menu.File_QMenu" activateItem(waitForObjectItem(menu, "Rename...")) - type(waitForObject(":Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit"), newname) - type(waitForObject(":Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit"), "") + replaceEdit = waitForObject(":Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit") + if not (oldname.lower().endswith(".qrc") and JIRA.isBugStillOpen(20057)): + test.compare(replaceEdit.selectedText, oldname.rsplit(".", 1)[0], + "Only the filename without the extension is selected?") + replaceEditorContent(replaceEdit, newname) + type(replaceEdit, "") test.verify(waitFor("os.path.exists(newFilePath)", 1000), "Verify that file with new name exists: %s" % newFilePath) test.compare(readFile(newFilePath), oldFileText, diff --git a/tests/system/suite_qtquick/tst_qtquick_creation3/test.py b/tests/system/suite_qtquick/tst_qtquick_creation3/test.py index 6338fdb94ec..b47da5d58d7 100644 --- a/tests/system/suite_qtquick/tst_qtquick_creation3/test.py +++ b/tests/system/suite_qtquick/tst_qtquick_creation3/test.py @@ -42,7 +42,7 @@ def main(): test.fatal("Failed to activate kit %s" % kit) continue test.log("Running project Qt Quick UI Prototype (%s)" % kit) - qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(1, 0, workingDir, projectName, 11223, quick) + qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(2, 1, workingDir, projectName, 11223, quick) if qmlViewer!=None: qmlViewerPath = os.path.dirname(qmlViewer) qmlViewer = os.path.basename(qmlViewer)