From 1d2b476320b8ba579587455bbd34b1ef485711e1 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 8 Mar 2018 08:40:48 +0100 Subject: [PATCH 01/48] BinEditor: Do now show tool tip if mouse is not over data Task-number: QTCREATORBUG-17573 Change-Id: Ida0497006e702dfafe70f434373088325bbc6db7 Reviewed-by: David Schulz --- src/plugins/bineditor/bineditorwidget.cpp | 39 +++++++++++++++-------- src/plugins/bineditor/bineditorwidget.h | 4 ++- 2 files changed, 28 insertions(+), 15 deletions(-) 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(); From 1fae424f83282d598ce0e6b1cd3f2767332f0097 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Mon, 12 Mar 2018 18:03:42 +0100 Subject: [PATCH 02/48] Android: Pull linker from device/emulator Task-number: QTCREATORBUG-19931 Change-Id: If8f0b5fe767f9e816ac5163142d4fa38e0f6540f Reviewed-by: hjk --- src/plugins/android/androiddeployqtstep.cpp | 52 +++++++++------------ src/plugins/android/androiddeployqtstep.h | 3 +- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 9d497ba52a6..4207c25adab 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -139,25 +139,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->buildDirectory().toString(); + if (!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) @@ -213,8 +222,6 @@ bool AndroidDeployQtStep::init(QList &earlierSteps) } m_environment = bc->environment(); - m_buildDirectory = bc->buildDirectory().toString(); - m_adbPath = AndroidConfigurations::currentConfig().adbToolPath().toString(); AndroidAvdManager avdManager; @@ -389,31 +396,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; From 36132751ff98b922b8027cf76cc8c1a594f8fcce Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 20 Feb 2018 10:45:11 +0100 Subject: [PATCH 03/48] Update German translation Change-Id: I8960605dbf5a06ae4cce0e965103e67505e0434b Reviewed-by: Christian Stenger --- share/qtcreator/translations/qtcreator_de.ts | 1762 ++++++++++++------ 1 file changed, 1215 insertions(+), 547 deletions(-) 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 + + From eece1be3168d798a1de43f4fbc732261ea4c4c37 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Mar 2018 17:16:37 +0100 Subject: [PATCH 04/48] CMake: Re-add RunConfiguration display name Amends 6f04ca646 for QTCREATORBUG-19762? Task-number: QTCREATORBUG-19954 Change-Id: I5da8bf15b5b62500fd0936d15451dfefd878b57b Reviewed-by: Tobias Hunger --- src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp index 6b68d478685..1c79c3a4634 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp @@ -144,6 +144,8 @@ bool CMakeRunConfiguration::fromMap(const QVariantMap &map) CMakeProject *project = static_cast(target()->project()); const CMakeBuildTarget ct = project->buildTargetForTitle(m_title); extraAspect()->setDefaultWorkingDirectory(ct.workingDirectory); + + setDefaultDisplayName(m_title); } return true; From e7f611cc67503d00ee27ceb7f2f5c50035122cd1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Mar 2018 15:09:55 +0100 Subject: [PATCH 05/48] Wizards: Fix Qt Unit test wizard Remove unused define which lead to build errors if the build directory contained white spaces. Task-number: QTCREATORBUG-20047 Change-Id: Ieea4b61d6936479dfcd87714baed0854d4b4ced1 Reviewed-by: Tobias Hunger --- src/plugins/qmakeprojectmanager/wizards/testwizard.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/wizards/testwizard.cpp b/src/plugins/qmakeprojectmanager/wizards/testwizard.cpp index 3f2ebfc6191..a0c4d553061 100644 --- a/src/plugins/qmakeprojectmanager/wizards/testwizard.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/testwizard.cpp @@ -171,8 +171,7 @@ Core::GeneratedFiles TestWizard::generateFiles(const QWizard *w, QString *errorM QtProjectParameters::writeProFileHeader(proStr); projectParams.writeProFile(proStr); proStr << "\n\nSOURCES +=" - << " \\\n " << Utils::FileName::fromString(sourceFilePath).fileName() - << " \n\nDEFINES += SRCDIR=\\\\\\\"$$PWD/\\\\\\\"\n"; + << " \\\n " << Utils::FileName::fromString(sourceFilePath).fileName(); } profile.setContents(contents); From 38326b181123b319b2449c84204420e1506ed3a3 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 13 Mar 2018 21:52:42 +0100 Subject: [PATCH 06/48] Squish: Skip tst_opencreator_qbs Change-Id: I0935a52f5b58c444bd6dd66cc9d93301444f0157 Reviewed-by: Christian Stenger --- tests/system/suite_general/tst_opencreator_qbs/test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 From 139d64615e2626bdae2bafc4df8bbffbe4c1def5 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 13 Mar 2018 21:18:58 +0100 Subject: [PATCH 07/48] Squish: Revert workarounds for fixed bug This reverts commits 47355608dbbacc60bc0c60765ef54c427a8144cc and 6cc61be23bf827d9593d8b34bf1b71f21fb1547c. Task-number: QTCREATORBUG-19717 Change-Id: I052ff84ab33a5c483c11b66eaf55a175cc34c28d Reviewed-by: Christian Stenger --- tests/system/shared/workarounds.py | 11 +---------- .../system/suite_debugger/tst_qml_js_console/test.py | 2 -- tests/system/suite_debugger/tst_qml_locals/test.py | 1 - .../suite_qtquick/tst_qtquick_creation3/test.py | 2 +- 4 files changed, 2 insertions(+), 14 deletions(-) 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_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) From e4bdf0ee89da705243bdbe4c1010b0f687cfbc41 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 14 Mar 2018 12:27:18 +0100 Subject: [PATCH 08/48] Doc: Add link to Qt Quick Designer tutorial video from Tutorials Change-Id: I17c4188e828295549c3c741ec4c8ab95c5bb5a3e Reviewed-by: Alessandro Portale Reviewed-by: Thomas Hartmann --- src/plugins/qtsupport/qtcreator_tutorials.xml | 4 ++++ 1 file changed, 4 insertions(+) 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 + From 4385d4fb55761d65d9c8dcf4752ba42369b681e9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 14 Mar 2018 14:32:50 +0100 Subject: [PATCH 09/48] Update 4.6 changes file Change-Id: I53ce5cdba0291002e58d75bdb3cb12989ec7df4b Reviewed-by: Leena Miettinen --- dist/changes-4.6.0.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) 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 From 99f0237c8082b8a8d99172bc9b028133a7ec1ac2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 1 Mar 2018 20:55:19 +0100 Subject: [PATCH 10/48] qmake: restore coding style this reverts 2631ffabd5a7955a40b9779b0d52af64e3bd3a60 for qmake*.cpp. i refuse to deal with the merging hell this introduced, thank you very much. Change-Id: I3e3a11fc0ad73c600976da0f3a13c8791250eb09 Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 172 ++++++++++++------------ src/shared/proparser/qmakeevaluator.cpp | 42 +++--- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index c2625166cb2..cb605e58103 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -107,53 +107,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 +163,40 @@ 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 }, }; statics.functions.reserve((int)(sizeof(testInits)/sizeof(testInits[0]))); for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i) @@ -598,7 +598,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) { @@ -960,10 +960,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)) { diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 9eb14251ba9..5e318b170d8 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -161,27 +161,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) From 24a687c64188261a0ca32f4dcd0316368a88aae9 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 9 Nov 2016 13:11:31 +0100 Subject: [PATCH 11/48] fix $$section()'s bad argument count error message Change-Id: I02b8663b96c7d96cdb3c19639e2213e49fd2bcec Reviewed-by: Joerg Bornemann (cherry picked from qtbase/8db556d29919fd0c0ddb23b743cb5e6c218b1ae2) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index cb605e58103..4977c14b6d3 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -540,8 +540,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(); From 9edc24133ab23697c5147d4b5a30ac8cd7360fde Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 11 Nov 2016 15:22:45 +0100 Subject: [PATCH 12/48] Improve QMake JSON error We can not improve the result from JSON parsing without changing API, so instead recalculate the line and column based on input and offset. Change-Id: I54149233f71023aa5d30deff854d6f3406c5c48c Reviewed-by: Oswald Buddenhagen (cherry picked from qtbase/887e260a9370dfd8061754ed47cda7d9e4621711) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 39 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 4977c14b6d3..14991c6a947 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -392,14 +392,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; } From 9d9bef2e2f6c55b0a8eef1d88a3ad8915a9e9498 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 10 Nov 2016 20:04:20 +0100 Subject: [PATCH 13/48] qmake: add "undecorated" mode to $$prompt() sync-up with qmake; no effect on creator. Change-Id: I01689c7a6573415801862348b32bafc6a609ed4a (cherry picked from qtbase/cff05b398cb767af7fddae6a617f26f998c7a781) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 14991c6a947..0efa6af0eb9 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1088,16 +1088,22 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( 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); From ad478db4e4f3f3230302d973d89158b3d5b387d2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Nov 2016 20:01:53 +0100 Subject: [PATCH 14/48] qmake: let discard_from() discard function definitions as well for completeness. Change-Id: I3ffc14e041408c773e277442828170e3df04ec8d (cherry picked from qtbase/965e861e61ec56c91216d483987d33fb5a508b85) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 0efa6af0eb9..17712874e7a 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1362,6 +1362,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } ++vit; } + for (auto fit = m_functionDefs.testFunctions.begin(); fit != m_functionDefs.testFunctions.end(); ) { + if (fit->pro() == pro) + fit = m_functionDefs.testFunctions.erase(fit); + else + ++fit; + } + for (auto fit = m_functionDefs.replaceFunctions.begin(); fit != m_functionDefs.replaceFunctions.end(); ) { + if (fit->pro() == pro) + fit = m_functionDefs.replaceFunctions.erase(fit); + else + ++fit; + } pro->deref(); return ReturnTrue; } From ab23dce95f2a7dc4f1849c54d96d84abeadf05b7 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Nov 2016 14:45:48 +0100 Subject: [PATCH 15/48] qmake: make discard_from() patch up QMAKE_INTERNAL_INCLUDED_FILES as well when the file's effects are discarded, the mention of the file should be as well. Change-Id: I894b7e2b887dd34d18533b197bfa9d0d84d647e7 (cherry picked from qtbase/c05f0a83fdb4823604d76f61bb884e206887e704) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 17712874e7a..393b946bbb9 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1375,6 +1375,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ++fit; } pro->deref(); + 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: From 21b8eb121c1ef1721612c21388f802fb8b7da9e3 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Thu, 17 Nov 2016 10:40:44 +0100 Subject: [PATCH 16/48] qmake: Add support for Visual Studio 2017 Change-Id: I21f56edca3852b52edd2c5fdcce76817141e8d4a (cherry picked from qtbase/38675e18fcc841228141568a2ecfafdeb99eba2a) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeevaluator.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 5e318b170d8..702ec650c4d 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -968,6 +968,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 +1069,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) From f7669c82ff3d1dc36596cca94f0a24538c0ec305 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 25 Nov 2016 20:41:20 +0100 Subject: [PATCH 17/48] qmake: abort when $$prompt() gets EOF sync-up with qmake; no effect on creator. Change-Id: I51ca7df8d694c6ffe9d9899cba414b1b46f5ce95 (cherry picked from qtbase/80e63223f80643a93255cde9e0a4e82c705b2262) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 13 ++++++++----- src/shared/proparser/qmakeevaluator.cpp | 3 +-- src/shared/proparser/qmakeevaluator.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 393b946bbb9..91bd6c251fc 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -555,11 +555,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) { @@ -1108,6 +1106,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( 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)); } } @@ -1277,7 +1280,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( break; } - return ret; + return ReturnTrue; } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 702ec650c4d..bec43b1d4ed 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -1773,8 +1773,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 = diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index d1e734346b2..3816769792d 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -209,7 +209,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); From 5e2b4c37f9566c0d17d482f6a65bf0ea10080c3e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 24 Nov 2016 18:41:48 +0100 Subject: [PATCH 18/48] qmake: introduce reload_properties() function Task-number: QTCREATORBUG-18220 Change-Id: I4526ef64b3c89d9851e10f83965fe479ed7f39f6 (cherry picked from qtbase/169a40d511165f6c3c9a71cd5c079786c22d2aca) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 8 +++++++- src/shared/proparser/qmakeglobals.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 91bd6c251fc..a4cdb389e41 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -98,7 +98,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() @@ -197,6 +197,7 @@ void QMakeEvaluator::initFunctionStatics() { "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) @@ -2026,6 +2027,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/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 98b269a30a2..90e2b007ccd 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -121,6 +121,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); From 94957d6f4e6e244897a1ea968a3e3d08606dc8e1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Nov 2016 11:40:24 +0100 Subject: [PATCH 19/48] qmake: introduce magic bypassNesting() scope Task-number: QTCREATORBUG-18220 Change-Id: If14e6944fe84767bd67604ecde98076f873749ef (cherry picked from qtbase/b6b44b368c6fc2df168195eaee57a2f925a29646) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/proitems.h | 3 +++ src/shared/proparser/qmakeevaluator.cpp | 18 +++++++++++++++++ src/shared/proparser/qmakeparser.cpp | 26 ++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 31e662bcf06..d98d0d9f974 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -320,6 +320,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 diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index bec43b1d4ed..7fa0c3e5d73 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -591,6 +591,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) { diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index 5d1bd710431..a9a1b6d9a7f 100644 --- a/src/shared/proparser/qmakeparser.cpp +++ b/src/shared/proparser/qmakeparser.cpp @@ -115,6 +115,7 @@ static struct { QString strfor; QString strdefineTest; QString strdefineReplace; + QString strbypassNesting; QString stroption; QString strreturn; QString strnext; @@ -138,6 +139,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"); @@ -1171,6 +1173,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 +1460,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 +1544,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"); } From a8a2424a7f2a29fb9b19785ae2db9405c5624433 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 16 Dec 2016 13:11:49 +0100 Subject: [PATCH 20/48] qmake: make QMAKE_DIR_SEP magic on writing Change-Id: I45ab3156b8e040f683328ac46e48b09c2eb94ef7 (cherry picked from qtbase/f2b31fdb6bb357c0c5c97d4fabd2561da3ba2093) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeevaluator.cpp | 5 +++-- src/shared/proparser/qmakeevaluator_p.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 7fa0c3e5d73..3009c7e87e5 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"); @@ -935,6 +936,8 @@ 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(); @@ -1216,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; } diff --git a/src/shared/proparser/qmakeevaluator_p.h b/src/shared/proparser/qmakeevaluator_p.h index 91c3922106d..9f7a58e2fe6 100644 --- a/src/shared/proparser/qmakeevaluator_p.h +++ b/src/shared/proparser/qmakeevaluator_p.h @@ -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; From 0c621d2af5785474483b4beb4645765afe709509 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 16 Dec 2016 13:31:07 +0100 Subject: [PATCH 21/48] qmake: fix conditionals on the spec after assigning QMAKESPEC Change-Id: Ibdd9a9c85067623f0f1f064d139d23b4e6b0677d (cherry picked from qtbase/d88ff29c57b5407339da00389c522e5f1d4e3398) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeevaluator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 3009c7e87e5..5d7d9c5420c 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -943,6 +943,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( QString spec = values(varName).first().toQString(); if (IoUtils::isAbsolutePath(spec)) { m_qmakespec = spec; + m_qmakespecName = IoUtils::fileName(m_qmakespec).toString(); m_featureRoots = 0; } } From 897305f35627583a646080c8fbc7984fcacbe2ea Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 16 Dec 2016 13:34:02 +0100 Subject: [PATCH 22/48] qmake: micro-optimize FOO-=$$BAR for empty FOO Change-Id: I86c89bf0ad726a5ab7ead990a27ef7cc32caebbf (cherry picked from qtbase/33c33f6475910bad607abac67eef6c581d6188dd) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/proitems.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 795b8b4564a..e28e1b19f8d 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -393,9 +393,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() From dd482d681f8909c77614638eb34db3e296b60df5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 3 Jan 2017 19:10:14 +0100 Subject: [PATCH 23/48] qmake: don't pass qmake configure arguments to sub-projects the arguments after '--' are by definition meant only for the top-level project, as that's where configure is invoked from. passing them to sub-projects just adds noise to the make output and misleads users. note that this specifically does not support qmake -r, which will break if the subprojects rely on the arguments being absent. this isn't a problem, because the qt build doesn't support qmake -r anyway. note on cherry-picking: qt creator parses projects like qmake -r would, so this is hypothetically more of a problem here. we presume that nobody would actually include configure arguments in their build configuration, which may or may not be true ... Change-Id: I7ecff6212ce3137526005fc324a4a7ae45e3345e (cherry picked from qtbase/34cc41d8a17e6e30f01f22c5d382c28d49ae37e1) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeglobals.cpp | 2 +- src/shared/proparser/qmakeglobals.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index a50fa5437a0..04ff561e9d6 100644 --- a/src/shared/proparser/qmakeglobals.cpp +++ b/src/shared/proparser/qmakeglobals.cpp @@ -135,7 +135,7 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( 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")) diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 90e2b007ccd..7e9cf09281d 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -101,7 +101,7 @@ public: QProcessEnvironment environment; #endif QString qmake_abslocation; - QStringList qmake_args; + QStringList qmake_args, qmake_extra_args; QString qtconf; QString qmakespec, xqmakespec; From bfbe67a2554a4531eac42e0407febec112ce9590 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 3 Feb 2017 18:12:52 +0100 Subject: [PATCH 24/48] qmake: add a bunch of complementary options to -after in particular, -before (just for symmetry, as it's the default), -early (the actual objective), and -late (for symmetry again). Change-Id: I274303582a348b052c3e5106ff360ab4fd7d4ee2 (cherry picked from qtbase/4adc1012e19f5e12ab2fb96effc9ea88d2a05eda) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeevaluator.cpp | 12 ++++++--- src/shared/proparser/qmakeglobals.cpp | 33 ++++++++++++------------- src/shared/proparser/qmakeglobals.h | 13 ++++++---- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 5d7d9c5420c..4b9ebe8f208 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -1442,6 +1442,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()); @@ -1453,8 +1456,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(); @@ -1467,7 +1470,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 @@ -1477,6 +1480,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; } diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index 04ff561e9d6..9d6f628b242 100644 --- a/src/shared/proparser/qmakeglobals.cpp +++ b/src/shared/proparser/qmakeglobals.cpp @@ -108,10 +108,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); @@ -138,8 +135,14 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( 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 +166,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 +181,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; diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 7e9cf09281d..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 @@ -106,7 +109,7 @@ public: QString qtconf; QString qmakespec, xqmakespec; QString user_template, user_template_prefix; - QString precmds, postcmds; + QString extra_cmds[4]; #ifdef PROEVALUATOR_DEBUG int debugLevel; From d38ffb6b58b430a093d7dc72cac46f6b52cf5aa2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2018 14:54:40 +0100 Subject: [PATCH 25/48] qmake: make QMakeEvaluator::isActiveConfig() take a QStringRef argument saves some more cheap but pointless conversions to QString. this makes the introduction of the ProStringList::contains(QStringRef) overload necessary. Change-Id: Ic61993bd9a4b28fbba1b8e346345fd5f5636c6f0 Reviewed-by: Joerg Bornemann (cherry picked from qtbase/11d957d04381c7162dd5621c61f9963580ec7041) (cherry picked from qtbase/9f98935d33cc15c938be2b9295ba2fbe4edb0ee0) Reviewed-by: Tobias Hunger --- src/shared/proparser/profileevaluator.cpp | 14 ++++++++++---- src/shared/proparser/proitems.cpp | 8 ++++++++ src/shared/proparser/proitems.h | 1 + src/shared/proparser/qmakebuiltins.cpp | 2 +- src/shared/proparser/qmakeevaluator.cpp | 10 ++++------ src/shared/proparser/qmakeevaluator.h | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) 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/proitems.cpp b/src/shared/proparser/proitems.cpp index e28e1b19f8d..3c4fe3bc2e1 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -458,6 +458,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++) diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index d98d0d9f974..efcd888c724 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -244,6 +244,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; diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index a4cdb389e41..44113f47d0d 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1447,7 +1447,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } if (args.count() == 1) - return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2))); + return returnBool(isActiveConfig(args.at(0).toQStringRef())); const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|')); const ProStringList &configs = values(statics.strCONFIG); diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 4b9ebe8f208..e455fb3858b 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -645,7 +645,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; } @@ -1621,7 +1621,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) @@ -1633,9 +1633,7 @@ 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)) @@ -1655,7 +1653,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; } diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index 3816769792d..a2ba21025f7 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -220,7 +220,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, From 1ccf674e9743823bdd071b34723f142b47642ce8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 7 Apr 2017 17:07:12 +0200 Subject: [PATCH 26/48] QMakeEvaluator: port a QString::split() to a QStringRef::split() loop Change-Id: I91a65776124f88a7e2e4778dbe9154b597f52212 Reviewed-by: Oswald Buddenhagen (cherry picked from qtbase/cdbe9d1483b0761c9b5e72cc56dacf09d1b54118) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 44113f47d0d..7d32611f56b 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1448,12 +1448,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } if (args.count() == 1) return returnBool(isActiveConfig(args.at(0).toQStringRef())); - const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|')); + 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]); } } @@ -1482,11 +1482,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( 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))) || val == qry); From 6bee0b695d5a3b1ebc2ce14baba7651ae37a2f1e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 23 Feb 2017 14:53:27 +0100 Subject: [PATCH 27/48] qmake: improve time stamp precision of the touch() function sync-up with qmake; no effect on creator. Change-Id: I6928660230d84f8511bf0f58e268906d2e575e04 (cherry picked from qtbase/d83a20af1d05b5958d3559482b715777a57dea7a) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 7d32611f56b..c935a364fe2 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -1828,10 +1829,16 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("Cannot stat() reference file %1: %2.").arg(rfn, fL1S(strerror(errno)))); return ReturnFalse; } +#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L + const struct timespec times[2] = { { 0, UTIME_NOW }, st.st_mtim }; + const bool utimeError = utimensat(AT_FDCWD, tfn.toLocal8Bit().constData(), times, 0) < 0; +#else struct utimbuf utb; utb.actime = time(0); utb.modtime = st.st_mtime; - if (utime(tfn.toLocal8Bit().constData(), &utb)) { + const bool utimeError = utime(tfn.toLocal8Bit().constData(), &utb) < 0; +#endif + if (utimeError) { evalError(fL1S("Cannot touch %1: %2.").arg(tfn, fL1S(strerror(errno)))); return ReturnFalse; } From fe70177c177abb23c286b8cf483772900e8d9fe2 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 24 Feb 2017 16:22:53 +0100 Subject: [PATCH 28/48] qmake: Preserve last modification timestamps of installed files sync-up with qmake; no effect on creator. Change-Id: I3064d29a2b8c7b009a1efbf8f00b84c079ea5417 Reviewed-by: Oswald Buddenhagen (cherry picked from qtbase/2ad7f6ddf5042d7442c97a89b083ca2853cf5721) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/ioutils.cpp | 70 ++++++++++++++++++++++++++ src/shared/proparser/ioutils.h | 3 ++ src/shared/proparser/qmakebuiltins.cpp | 60 ++-------------------- 3 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 97e4c0b8ed4..c0bbbe768a5 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; @@ -181,4 +186,69 @@ 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; +} +#endif + QT_END_NAMESPACE diff --git a/src/shared/proparser/ioutils.h b/src/shared/proparser/ioutils.h index d7fc596b0df..150c837369a 100644 --- a/src/shared/proparser/ioutils.h +++ b/src/shared/proparser/ioutils.h @@ -60,6 +60,9 @@ public: #else { return shellQuoteWin(arg); } #endif +#if defined(PROEVALUATOR_FULL) + static bool touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString); +#endif }; } // namespace ProFileEvaluatorInternal diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index c935a364fe2..d93efd53eb7 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -52,9 +52,7 @@ #ifdef Q_OS_UNIX #include -#include #include -#include #include #include #include @@ -253,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) { @@ -1823,46 +1804,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; } -#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L - const struct timespec times[2] = { { 0, UTIME_NOW }, st.st_mtim }; - const bool utimeError = utimensat(AT_FDCWD, tfn.toLocal8Bit().constData(), times, 0) < 0; -#else - struct utimbuf utb; - utb.actime = time(0); - utb.modtime = st.st_mtime; - const bool utimeError = utime(tfn.toLocal8Bit().constData(), &utb) < 0; -#endif - if (utimeError) { - 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; } From 274726efb0bbc5055f02b1b76f2481564ad27f46 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 1 Mar 2017 12:41:48 +0100 Subject: [PATCH 29/48] qmake: Preserve last modification timestamps of installed directories sync-up with qmake; no effect on creator. Change-Id: Id5931a467196d5cd67acfa0deffc2488af8a3669 Reviewed-by: Oswald Buddenhagen (cherry picked from qtbase/c12b96daf2195c475c086f8f9be833aa0e28b26c) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/ioutils.cpp | 36 ++++++++++++++++++++++++++++++++ src/shared/proparser/ioutils.h | 3 +++ 2 files changed, 39 insertions(+) diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index c0bbbe768a5..552df764c32 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -249,6 +249,42 @@ bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceF # 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 150c837369a..71a7ffed565 100644 --- a/src/shared/proparser/ioutils.h +++ b/src/shared/proparser/ioutils.h @@ -62,6 +62,9 @@ public: #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 }; From 60245e55d7551f525c951d8d866aab081be88a69 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 14 Aug 2017 18:30:29 +0200 Subject: [PATCH 30/48] qmake: Change source identifier type in ProString The strings remember in which file they were created/assigned. However, this used a non-counting reference to a ProFile, which could become dangling. If a subsequent ProFile re-used the exact same address, a string's source would be mis-identified, which would be fatal in conjunction with discard_from(). Since we actually need only a unique id for comparison, let's use an integer for that. comment on cherry-pick: this is actually a lot more than a cherry-pick, because the file ids need to be aware of the dual VFS which was concurrently introduced on the qtc side. Started-by: Simon Hausmann Change-Id: I395153afaf7c835d0119690ee7f4b915e6f90d4a (cherry picked from qtbase/190aa94be7f5e146bef44862b974d733755cec85) Reviewed-by: Tobias Hunger --- .../qmakenodetreebuilder.cpp | 9 +- .../qmakeprojectmanager/qmakeparsernodes.cpp | 24 +-- .../qmakeprojectmanager/qmakeparsernodes.h | 4 +- .../qmakeprojectmanager/qmakeproject.cpp | 11 +- src/plugins/qtsupport/profilereader.cpp | 9 +- src/plugins/qtsupport/profilereader.h | 4 +- src/shared/proparser/profileevaluator.h | 2 +- src/shared/proparser/proitems.cpp | 5 +- src/shared/proparser/proitems.h | 10 +- src/shared/proparser/prowriter.cpp | 2 +- src/shared/proparser/qmakebuiltins.cpp | 23 +-- src/shared/proparser/qmakeevaluator.cpp | 18 ++- src/shared/proparser/qmakeevaluator.h | 3 +- src/shared/proparser/qmakeparser.cpp | 86 +++++----- src/shared/proparser/qmakeparser.h | 14 +- src/shared/proparser/qmakevfs.cpp | 149 ++++++++++-------- src/shared/proparser/qmakevfs.h | 55 +++++-- .../auto/profilewriter/tst_profilewriter.cpp | 10 +- 18 files changed, 248 insertions(+), 190 deletions(-) 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 4c47e34d2f2..9e0b1d248c5 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -237,7 +237,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); } @@ -292,11 +293,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)); @@ -304,12 +305,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)); @@ -621,7 +622,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; } @@ -701,7 +703,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); } @@ -738,7 +740,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, @@ -1294,7 +1296,7 @@ QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input) result->includedFiles.proFile = pro; result->includedFiles.name = input.projectFilePath; - QHash proToResult; + QHash proToResult; result->projectType = proFileTemplateTypeToProjectType( @@ -1332,7 +1334,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()); @@ -1368,7 +1370,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 7d10a31cd8d..44ebc927b66 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(); @@ -840,7 +842,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/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/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 3c4fe3bc2e1..30ddef65c40 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -474,9 +474,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) { @@ -493,7 +494,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 efcd888c724..6199efc8c72 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -69,8 +69,8 @@ public: 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); @@ -159,7 +159,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; @@ -332,9 +332,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; } @@ -359,6 +360,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 d93efd53eb7..4ca018c5de2 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -436,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; } @@ -709,9 +712,9 @@ QMakeEvaluator::VisitReturn 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; } @@ -1062,7 +1065,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( dirs.append(fname + QLatin1Char('/')); } if (regex.exactMatch(qdir[i])) - ret += ProString(fname).setSource(currentProFile()); + ret += ProString(fname).setSource(currentFileId()); } } } @@ -1329,7 +1332,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(); @@ -1349,18 +1353,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( ++vit; } for (auto fit = m_functionDefs.testFunctions.begin(); fit != m_functionDefs.testFunctions.end(); ) { - if (fit->pro() == pro) + 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() == pro) + if (fit->pro()->id() == pro) fit = m_functionDefs.replaceFunctions.erase(fit); else ++fit; } - pro->deref(); ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")]; int idx = iif.indexOf(ProString(fn)); if (idx >= 0) @@ -1405,7 +1408,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()); diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index e455fb3858b..b555102bf84 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -268,13 +268,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(); @@ -1311,7 +1311,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); @@ -1321,7 +1321,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()); @@ -1605,6 +1605,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(); @@ -1819,7 +1827,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 a2ba21025f7..c39b8abcde5 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); } diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index a9a1b6d9a7f..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 /////////// @@ -164,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 @@ -192,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 { @@ -226,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; 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/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"), From 2053a5710a45dae5680e9ce5fad8fb8097013bcd Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 10 Aug 2017 20:53:15 +0200 Subject: [PATCH 31/48] qmake: make yet more use of ProString::toQStringRef() in most cases, the main advantage is not using toQString(m_tmp), which reduces the possibility of raw data leaks. in cases where we used toQString() without temporary, this is a slight optimization. Change-Id: Ib343acffd383aa2c4fefab75fb52762fb534dfc6 Reviewed-by: Joerg Bornemann (cherry picked from qtbase/eb0ba90b0af9fa7d5b70c74140f64295f2d05c18) Reviewed-by: Tobias Hunger --- src/shared/proparser/proitems.cpp | 7 ++++++- src/shared/proparser/proitems.h | 6 ++++-- src/shared/proparser/qmakebuiltins.cpp | 8 ++++---- src/shared/proparser/qmakeevaluator.cpp | 10 +++++----- src/shared/proparser/qmakeevaluator_p.h | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 30ddef65c40..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; } diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 6199efc8c72..58349ddb716 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -64,6 +64,7 @@ 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); @@ -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); } @@ -199,9 +201,9 @@ 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 diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 4ca018c5de2..8331e86bfeb 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -730,9 +730,9 @@ QMakeEvaluator::VisitReturn 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; @@ -1538,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) { diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index b555102bf84..cfb78fc1d55 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -772,7 +772,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; @@ -869,13 +869,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; @@ -887,8 +887,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); diff --git a/src/shared/proparser/qmakeevaluator_p.h b/src/shared/proparser/qmakeevaluator_p.h index 9f7a58e2fe6..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)) From 11753bfd9d139e7dbfe47a37d2cf27c32cb6bf27 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 13:24:43 +0200 Subject: [PATCH 32/48] qmake: fix excessive detaching of raw data ... in $$basename(), $$dirname(), and contains(). the latter case is marginal, as it only applies to mutuals which are regexes, which i don't remember ever seeing used. QRegExp saves a copy of the matched string, so it's necessary to alternate between two temporaries to avoid detaching. we already did that in most places. Change-Id: I97b8294585c17c76d1756f83971f42cb88353af0 Reviewed-by: Joerg Bornemann (cherry picked from qtbase/5131bb9bed3af7a2ecfce27af3940ff11ed219c2) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 8331e86bfeb..54d0fb2c000 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -583,8 +583,8 @@ QMakeEvaluator::VisitReturn 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) { @@ -1473,7 +1473,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( for (int mut = 0; mut < mutuals.count(); mut++) { 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); } } From 10f5676cab339e0318accdb7f8cb9a3858692e85 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 14:55:37 +0200 Subject: [PATCH 33/48] qmake: fix raw data detach avoidance the m_tmp array is a member, so the index toggle for accessing it also needs to be one - otherwise, odd iteration counts will defeat the mechanism. Change-Id: If7a800ed5a4b4168625daf1ebbd5d2d164569d8e Reviewed-by: Joerg Bornemann (cherry picked from qtbase/ccb8afcda752093bfb6bc32f560131a91bd826a1) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 12 +++--------- src/shared/proparser/qmakeevaluator.cpp | 5 ++--- src/shared/proparser/qmakeevaluator.h | 1 + 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 54d0fb2c000..2dc4d87a71c 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -884,12 +884,10 @@ QMakeEvaluator::VisitReturn 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; @@ -1389,12 +1387,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; @@ -1459,12 +1455,10 @@ 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 auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|')); diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index cfb78fc1d55..cbaf28440f9 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -223,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; } @@ -1648,12 +1649,10 @@ bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex) 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 diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index c39b8abcde5..21e13451d66 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -283,6 +283,7 @@ public: QString m_outputDir; int m_listCount; + int m_toggle; bool m_valuemapInited; bool m_hostBuild; QString m_qmakespec; From c86ea1c8ceba95b3d6d5cc566af1dfe3801b3dee Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 12:16:57 +0200 Subject: [PATCH 34/48] qmake: make more use of ProString built-ins saves some noisy toQString() uses. Change-Id: I62a9e2725c4baabac311124d19c7d8b40f54c8f7 Reviewed-by: Joerg Bornemann (cherry picked from qtbase/ce5e6876d4a191087969134e489db99cf167ca69) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 22 ++++++++++------------ src/shared/proparser/qmakeevaluator.cpp | 10 ++++------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 2dc4d87a71c..198a85c94cc 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1777,13 +1777,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; } } @@ -1821,21 +1820,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; } } diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index cbaf28440f9..84f971b0cd2 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -970,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)); } } @@ -1755,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; From d5014234f2ea3424be046419410c95279ff45333 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2018 18:42:35 +0100 Subject: [PATCH 35/48] optimize operator+ ProString vs. char* we have all necessary overloads now. Change-Id: Ic4472eba15d4234e968fcb9443d0f79011aa43fd (cherry picked from qtbase/f137957e0887a9321b69b9ba83ed6ccaedee57bb) (cherry picked from qtbase/14505bbfea220a39c2158480db8ba788707ff332) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/proitems.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 58349ddb716..a7566be2205 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -206,9 +206,9 @@ inline QString operator+(const QString &one, const ProString &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(); } From c76fc433eb3c22d67ba0149b7b2aa63328d27185 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 15:52:47 +0200 Subject: [PATCH 36/48] qmake: remove pointless use of raw data in $$[QMAKEFEATURES] access property values are de-facto guaranteed to be backed by full QStrings, so there is nothing to be gained from using the raw data optimization, while doing so risks raw data leaks. Change-Id: I3d43da9aaadd4d5811c4b1a9d7ac734049da423c Reviewed-by: Joerg Bornemann (cherry picked from qtbase/18533ae2a72aba9ad8c0f1862e1e6ace50655864) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakeevaluator.cpp | 2 +- src/shared/proparser/qmakeevaluator.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 84f971b0cd2..00c87a7a23c 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -1529,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()) { diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index 21e13451d66..7e1911501bb 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -303,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; From 42e3f980ecbedb3ec0a65d71bba4da4d4d1a5ef2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 14:36:23 +0200 Subject: [PATCH 37/48] qmake: fix hypothetical raw data leaks relating to qt i/o classes technically, we should not rely on the i/o classes not storing the strings beyond the instantiated object's life time. Change-Id: I0990769b3cf86860184869036c096c531160e9be Reviewed-by: Joerg Bornemann (cherry picked from qtbase/702be65532263bd52ad0b67235c112083120699e) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 198a85c94cc..102252fdaf8 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -818,7 +818,8 @@ QMakeEvaluator::VisitReturn 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; @@ -833,7 +834,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( lines = true; } - QFile qfile(resolvePath(m_option->expandEnvVars(file))); + QFile qfile(fn); if (qfile.open(QIODevice::ReadOnly)) { QTextStream stream(&qfile); if (blob) { @@ -909,7 +910,7 @@ QMakeEvaluator::VisitReturn 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))); @@ -1703,7 +1704,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 ") @@ -1740,8 +1741,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; } @@ -1754,7 +1757,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; From a13776d84860e7a517d7eeb024c95c1e1a1eec21 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 11 Aug 2017 13:41:39 +0200 Subject: [PATCH 38/48] qmake: fix hypothetical raw data leak in $$replace() the replacement value may well constitute the whole output string - this is in fact common, given this rather typical usage pattern: BAR = $$replace(FOO, -flag, -otherflag) this must be considered when constructing the return value. compare e1cee308a. as of now, this is irrelevant, as QString::replace(QRegExp, QString) will always memcpy the replacement into a detached copy of the target, but one never knows. Change-Id: Ia1f271f45023746040fc28ce6d88a6609e05e5c2 Reviewed-by: Joerg Bornemann (cherry picked from qtbase/e8b9a17a3bd770f6bf1bc8f4e0586565acf425e2) Reviewed-by: Tobias Hunger --- src/shared/proparser/qmakebuiltins.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 102252fdaf8..5bfbdca8d65 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1112,7 +1112,11 @@ QMakeEvaluator::VisitReturn 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; From 912dd8df64c05fcdcbc9d862a41052654dd07546 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 28 Jul 2017 13:25:27 +0200 Subject: [PATCH 39/48] qmake: require a drive in a DOS path for it to be absolute For Q_OS_WIN, a path is only truly absolute if it includes a drive letter; merely starting with a slash is not enough. (We can't support UNC paths, so don't even try: qmake runs various commands in the source directory using CMD.exe, which doesn't support UNC as PWD.) This requires, when resolving a path relative to a root, transcribing the root's drive to such not-quite-absolute paths. Changed QMakeGlobals, $$absolute_path() and $$relative_path() to now use IoUtils::resolvePath() rather than delegating to QDir's absolute path method, since that doesn't correctly recognize the need for a drive letter (and qmake did run into problems with some paths, from splitPathList and a failing test, as a result). Change-Id: I2bfc13c1bfbe1ae09997274622ea55cb3de31b43 Reviewed-by: Oswald Buddenhagen (cherry picked from qtbase/e86f3c018833141776db2d15772ba53995656eac) Reviewed-by: Joerg Bornemann Reviewed-by: Tobias Hunger --- src/shared/proparser/ioutils.cpp | 23 +++++++++++++++-------- src/shared/proparser/qmakebuiltins.cpp | 13 +++++++------ src/shared/proparser/qmakeglobals.cpp | 15 ++++++++------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 552df764c32..0552bd10972 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -64,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; } @@ -98,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); } diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 5bfbdca8d65..9d9afdd2afe 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -1174,9 +1174,9 @@ QMakeEvaluator::VisitReturn 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) @@ -1188,9 +1188,10 @@ QMakeEvaluator::VisitReturn 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; diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index 9d6f628b242..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; } @@ -123,10 +124,10 @@ 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('-'))) { @@ -256,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; } @@ -315,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)) From 21d3d0a55dda1ec003c98299dbf73a4f7f43f807 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 14 Mar 2018 17:27:02 +0100 Subject: [PATCH 40/48] QtSupport: Fix loading of tutorial thumbnails Amends 7d83472906566857f9afaa95440a41d1ed5edcae Used the HighDpi loader in the wrong place. Change-Id: I5bb7328167c0a9da811db92102feea67ee97c6c4 Reviewed-by: Alessandro Portale --- src/plugins/qtsupport/exampleslistmodel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 199f581b6c1..408dffedafd 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -301,8 +301,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(); item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); item.isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() == QLatin1String("true"); @@ -399,7 +398,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()); item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); item.isVideo = attributes.value(QLatin1String("isVideo")).toString() == QLatin1String("true"); item.videoUrl = attributes.value(QLatin1String("videoUrl")).toString(); From af99c3fe7d73e2f373a391ccfd0381e78c4cbff2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 9 Mar 2018 12:28:22 +0100 Subject: [PATCH 41/48] Fix width calculations in flamegraph and timeline Relying on the index of a detail entry in the children array is dangerous as the repeater may create the children in any order. Rather, use the isLabel property to find out if an item is a label. Also, recognize that the drag handle sits in the outer margin. Therefore, as the minimumWidth includes margins, we have to subtract one margin in order to get the x value of the handle. Task-number: QTCREATORBUG-20012 Change-Id: I828b116c2c52d5aa7f8e3e726f59e3fa9f9095ec Reviewed-by: Christian Kandeler --- src/libs/flamegraph/qml/FlameGraphDetails.qml | 19 +++++++++----- src/libs/timeline/qml/Detail.qml | 3 ++- src/libs/timeline/qml/RangeDetails.qml | 26 ++++++++++++------- 3 files changed, 31 insertions(+), 17 deletions(-) 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 } From 1f3a106025b7dc48d0828372c14e62632fa531bf Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 15 Mar 2018 08:20:55 +0100 Subject: [PATCH 42/48] Tests: Fix Qbs build Change-Id: I5bc5ec98994ce83137ac1599682251db35e26663 Reviewed-by: Joerg Bornemann --- tests/auto/profilewriter/profilewriter.qbs | 1 + 1 file changed, 1 insertion(+) 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") } From 710b459e351c05420dc3952e631d52189ce0d552 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 14 Mar 2018 14:45:13 +0100 Subject: [PATCH 43/48] QmlPuppet: enable reset the default puppet button Also fix the logic that empty means that it should use the default fallback puppet. Task-number: QTCREATORBUG-19511 Change-Id: Ia36907523281386a1ed56362a76e37aaa9ee16b2 Reviewed-by: Eike Ziller Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/settingspage.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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() && From 6d5e1f508dd8ef892513eea40d2bdc8cb8fea418 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 15 Mar 2018 10:11:28 +0100 Subject: [PATCH 44/48] Update qbs submodule To HEAD of 1.11 branch. Change-Id: I12a6938563f7c7b109146123137aa7d278310fcb Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 24db24734d92f2f3edc9bc1a17851e6ac0df643e Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Fri, 9 Mar 2018 12:51:24 +0100 Subject: [PATCH 45/48] Squish: Open example from Qt 5.6 in tst_qml_editor Change-Id: Ibd5bd516d8409fa5389da3e330d6723ba772f135 Reviewed-by: Christian Stenger --- .../suite_editors/tst_qml_editor/test.py | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) 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 = ["", "", "", ""] From da2c66b1d0f0bf868f4ec88c7e61a57fd1095366 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Feb 2018 12:53:35 +0100 Subject: [PATCH 46/48] Move git specific stuff out of diff editor plugin Move it to the git plugin. Change-Id: I8151573ed50df70776f7ebf0475dd41fb84fae83 Reviewed-by: Tobias Hunger --- .../diffeditor/descriptionwidgetwatcher.cpp | 78 +++++ .../diffeditor/descriptionwidgetwatcher.h | 60 ++++ src/plugins/diffeditor/diffeditor.cpp | 75 ----- src/plugins/diffeditor/diffeditor.pro | 8 +- src/plugins/diffeditor/diffeditor.qbs | 2 + src/plugins/diffeditor/diffeditorconstants.h | 2 - .../diffeditor/diffeditorcontroller.cpp | 19 +- src/plugins/diffeditor/diffeditorcontroller.h | 10 +- src/plugins/diffeditor/diffeditordocument.cpp | 5 - src/plugins/diffeditor/diffeditordocument.h | 1 - src/plugins/git/gitclient.cpp | 293 +++++++++++++----- src/plugins/git/gitclient.h | 1 - src/plugins/git/gitconstants.h | 2 + 13 files changed, 370 insertions(+), 186 deletions(-) create mode 100644 src/plugins/diffeditor/descriptionwidgetwatcher.cpp create mode 100644 src/plugins/diffeditor/descriptionwidgetwatcher.h 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 f642f8ba7e6..92803826d61 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 From 454c7f83ff660fafa77488a4d33a020b9982f1cc Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 15 Mar 2018 13:53:01 +0100 Subject: [PATCH 47/48] Fix image border for examples browser It was made smaller for the tutorials to fit the new aspect ratio for their images, but we may not do that for the examples. Fixup for 7d834729065668 Task-number: QTCREATORBUG-20078 Change-Id: I556536a7e299e8f675332cd7450ece5fca6fab0a Reviewed-by: Christian Stenger --- src/plugins/qtsupport/gettingstartedwelcomepage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index 156c956ad54..0413e5c5059 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -440,7 +440,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; @@ -560,6 +561,8 @@ public: return QAbstractItemDelegate::editorEvent(ev, model, option, idx); } + void setShowExamples(bool showExamples) { m_showExamples = showExamples; goon(); } + signals: void tagClicked(const QString &tag); @@ -575,6 +578,7 @@ private: mutable QPointer m_currentWidget; mutable QVector> m_currentTagRects; mutable QPixmapCache m_pixmapCache; + bool m_showExamples = true; }; class ExamplesPageWidget : public QWidget @@ -583,6 +587,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; From fad75a3d566f730731fd715a77649ef8ebd57892 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 13 Mar 2018 23:03:33 +0100 Subject: [PATCH 48/48] Squish: Update tst_rename_file Creator only selects the filename now, the extension will be left unchanged by default. Task-number: QTCREATORBUG-20057 Change-Id: I66bbbb5b95e1d487c2087efa596a87a240721e44 Reviewed-by: Christian Stenger --- tests/system/suite_general/tst_rename_file/test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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,