From 3e1a2c6c53bbb8633bb14ae7f6166b3f51f83d09 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 27 Feb 2014 10:32:05 +0100 Subject: [PATCH 01/32] Debugger: Add "Separate Window" display option for QUrl objects Change-Id: Ifd4f60a96856d15993efd857d33421f691bb8824 Reviewed-by: Simon Hausmann --- share/qtcreator/debugger/qttypes.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index d9d94e5ff24..a84927cb253 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -1824,6 +1824,9 @@ def qdump__QTextDocument(d, value): d.putCallItem("toPlainText", value, "toPlainText") +def qform__QUrl(): + return "Inline,Separate Window" + def qdump__QUrl(d, value): if d.qtVersion() < 0x050000: privAddress = d.extractPointer(value) @@ -1884,6 +1887,14 @@ def qdump__QUrl(d, value): url += ''.join(["%02x00" % ord(c) for c in str(port)]) url += path d.putValue(url, Hex4EncodedLittleEndian) + + format = d.currentItemFormat() + if format == 1: + d.putDisplay(StopDisplay) + elif format == 2: + d.putField("editformat", DisplayUtf16String) + d.putField("editvalue", url) + d.putNumChild(8) if d.isExpanded(): stringType = d.lookupType(d.qtNamespace() + "QString") From ead00db2d3884262eeaf921cf3e0d05ec39fe2b8 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 27 Feb 2014 10:24:54 +0100 Subject: [PATCH 02/32] CppEditor: Fix Qt4 compile Change-Id: I3bad3687e06a5333359bd926cae2493f709aeff2 Reviewed-by: Orgad Shaneh --- src/plugins/cppeditor/cppincludehierarchy_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cppeditor/cppincludehierarchy_test.cpp b/src/plugins/cppeditor/cppincludehierarchy_test.cpp index d37448dd162..e9235b5cdf1 100644 --- a/src/plugins/cppeditor/cppincludehierarchy_test.cpp +++ b/src/plugins/cppeditor/cppincludehierarchy_test.cpp @@ -40,6 +40,8 @@ #include #include +Q_DECLARE_METATYPE(QList) + using namespace CPlusPlus; using namespace CppEditor::Internal; using namespace CppTools; From 3804de502385a9e921f69dc0415e0c216d1d7d1f Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 24 Feb 2014 12:36:47 +0100 Subject: [PATCH 03/32] Vcs: Add variables containing the Vcs name (Git, etc.) and topic This allows to have the git branch names (or tags, etc.) in the build path or to pass that information to scripts. Task-number: QTCREATORBUG-10376 Change-Id: I151990bdc7b85abbb427b2afae220adb4e918f4f Reviewed-by: Eike Ziller --- src/plugins/vcsbase/vcsbaseconstants.h | 3 ++ src/plugins/vcsbase/vcsplugin.cpp | 43 ++++++++++++++++++++++++++ src/plugins/vcsbase/vcsplugin.h | 1 + 3 files changed, 47 insertions(+) diff --git a/src/plugins/vcsbase/vcsbaseconstants.h b/src/plugins/vcsbase/vcsbaseconstants.h index 01356cda9ae..1dd5c8a9936 100644 --- a/src/plugins/vcsbase/vcsbaseconstants.h +++ b/src/plugins/vcsbase/vcsbaseconstants.h @@ -49,6 +49,9 @@ const char VCS_ID_SUBVERSION[] = "J.Subversion"; const char VCS_ID_PERFORCE[] = "P.Perforce"; const char VCS_ID_CVS[] = "Z.CVS"; +const char VAR_VCS_NAME[] = "CurrentProject:VcsName"; +const char VAR_VCS_TOPIC[] = "CurrentProject:VcsTopic"; + } // namespace Constants } // namespace VcsBase diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index bcd28297b3a..350bd5c63d2 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -28,12 +28,20 @@ ****************************************************************************/ #include "vcsplugin.h" + +#include "vcsbaseconstants.h" + #include "commonsettingspage.h" #include "nicknamedialog.h" #include "vcsbaseoutputwindow.h" #include "corelistener.h" +#include #include +#include +#include +#include +#include #include #include @@ -74,6 +82,15 @@ bool VcsPlugin::initialize(const QStringList &arguments, QString *errorMessage) connect(m_settingsPage, SIGNAL(settingsChanged(VcsBase::Internal::CommonVcsSettings)), this, SLOT(slotSettingsChanged())); slotSettingsChanged(); + + connect(Core::VariableManager::instance(), SIGNAL(variableUpdateRequested(QByteArray)), + this, SLOT(updateVariable(QByteArray))); + + Core::VariableManager::registerVariable(Constants::VAR_VCS_NAME, + tr("Name of the version control system in use by the current project.")); + Core::VariableManager::registerVariable(Constants::VAR_VCS_TOPIC, + tr("The current version control topic (branch or tag) identification of the current project.")); + return true; } @@ -122,6 +139,32 @@ void VcsPlugin::slotSettingsChanged() populateNickNameModel(); } +void VcsPlugin::updateVariable(const QByteArray &variable) +{ + static ProjectExplorer::Project *cachedProject = 0; + static Core::IVersionControl *cachedVc = 0; + static QString cachedTopLevel; + + ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::currentProject(); + if (cachedProject != project) { + cachedVc = Core::VcsManager::findVersionControlForDirectory(project->projectDirectory(), + &cachedTopLevel); + cachedProject = project; + } + + if (variable == Constants::VAR_VCS_NAME) { + if (cachedVc) + Core::VariableManager::insert(variable, cachedVc->displayName()); + else + Core::VariableManager::remove(variable); + } else if (variable == Constants::VAR_VCS_TOPIC) { + if (cachedVc) + Core::VariableManager::insert(variable, cachedVc->vcsTopic(cachedTopLevel)); + else + Core::VariableManager::remove(variable); + } +} + } // namespace Internal } // namespace VcsBase diff --git a/src/plugins/vcsbase/vcsplugin.h b/src/plugins/vcsbase/vcsplugin.h index fd73b0d89a3..c0baf218562 100644 --- a/src/plugins/vcsbase/vcsplugin.h +++ b/src/plugins/vcsbase/vcsplugin.h @@ -72,6 +72,7 @@ signals: private slots: void slotSettingsChanged(); + void updateVariable(const QByteArray &variable); private: void populateNickNameModel(); From 136f58c164fa5380c4b07b68c4d72a51b4403e4d Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 26 Feb 2014 16:02:25 +0100 Subject: [PATCH 04/32] Nodes: Remove findFile and findFolder methods There may be more than one matching node, so these methods provided a false sense of reliability. Change-Id: I6471b74a1d2dd4e8afc7e836fec45355696a0741 Reviewed-by: Daniel Teske --- src/plugins/projectexplorer/projectnodes.cpp | 18 ------------------ src/plugins/projectexplorer/projectnodes.h | 3 --- src/plugins/qbsprojectmanager/qbsnodes.cpp | 18 ++++++++++++++++-- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 04066d750e3..622644cd248 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -313,24 +313,6 @@ void FolderNode::setIcon(const QIcon &icon) m_icon = icon; } -FileNode *FolderNode::findFile(const QString &path) -{ - foreach (FileNode *n, fileNodes()) { - if (n->path() == path) - return n; - } - return 0; -} - -FolderNode *FolderNode::findSubFolder(const QString &path) -{ - foreach (FolderNode *n, subFolderNodes()) { - if (n->path() == path) - return n; - } - return 0; -} - bool FolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded) { if (projectNode()) diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 6592bcd1667..f15de786bf5 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -174,9 +174,6 @@ public: void setDisplayName(const QString &name); void setIcon(const QIcon &icon); - FileNode *findFile(const QString &path); - FolderNode *findSubFolder(const QString &path); - virtual bool addFiles(const QStringList &filePaths, QStringList *notAdded = 0); virtual bool removeFiles(const QStringList &filePaths, QStringList *notRemoved = 0); virtual bool deleteFiles(const QStringList &filePaths); diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp index 5ad45828fde..8ea6551dcd3 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp @@ -424,7 +424,14 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root, // Handle files: if (c->isFile()) { - ProjectExplorer::FileNode *fn = root->findFile(path); + ProjectExplorer::FileNode *fn = 0; + foreach (ProjectExplorer::FileNode *f, root->fileNodes()) { + // There can be one match only here! + if (f->path() != path) + continue; + fn = f; + break; + } if (fn) { filesToRemove.removeOne(fn); if (updateExisting) @@ -435,7 +442,14 @@ void QbsGroupNode::setupFolder(ProjectExplorer::FolderNode *root, } continue; } else { - FolderNode *fn = root->findSubFolder(c->path()); + ProjectExplorer::FolderNode *fn = 0; + foreach (ProjectExplorer::FolderNode *f, root->subFolderNodes()) { + // There can be one match only here! + if (f->path() != path) + continue; + fn = f; + break; + } if (!fn) { fn = new FolderNode(c->path()); root->addFolderNodes(QList() << fn); From 60be34ee3d45230b19a2d6beacf4b4d9eea0cc00 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Thu, 27 Feb 2014 11:10:33 +0100 Subject: [PATCH 05/32] ProjectNodes: Do not try to sort directories not yet mapped Do not try to sort directories that were not yet mapped into the FlatModel. This avoids an assert where QModelIndex is out of range (-1) because the data for that directory is not yet available in the model. Do not bother to map the data, just forget the request to sort in this case as the data will be sorted when it gets mapped anyway. Task-number: QBS-521 Change-Id: I19de7513405e6a0b84c988a2a86f763e3135811d Reviewed-by: Daniel Teske --- src/plugins/projectexplorer/projectmodels.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index e84e052ddcb..1427d84ca85 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -823,6 +823,9 @@ void FlatModel::removeFromCache(QList list) void FlatModel::changedSortKey(FolderNode *folderNode, Node *node) { + if (!m_childNodes.contains(folderNode)) + return; // The directory was not yet mapped, so there is no need to sort it. + QList nodes = m_childNodes.value(folderNode); int oldIndex = nodes.indexOf(node); From b8a1807542822c9981cd83b73c98f2247bbea299 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 20 Feb 2014 15:58:45 +0100 Subject: [PATCH 06/32] Squish: Fix tst_session_handling Change-Id: I85348bffe6c24be4663f67fc62e95a3e663b828c Reviewed-by: Robert Loehning --- tests/system/suite_general/tst_session_handling/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/suite_general/tst_session_handling/test.py b/tests/system/suite_general/tst_session_handling/test.py index ce3d8264e19..9d81da376d0 100644 --- a/tests/system/suite_general/tst_session_handling/test.py +++ b/tests/system/suite_general/tst_session_handling/test.py @@ -44,7 +44,7 @@ def main(): for project in projects: openQmakeProject(project) progressBarWait(20000) - checkNavigator(49, "Verifying whether all projects have been opened.") + checkNavigator(68, "Verifying whether all projects have been opened.") openDocument("propertyanimation.QML.qml.color-animation\\.qml") openDocument("declarative-music-browser.Headers.utility\\.h") checkOpenDocuments(2, "Verifying whether 2 files are open.") @@ -57,7 +57,7 @@ def main(): switchSession(sessionName) test.verify(waitFor("sessionName in str(mainWindow.windowTitle)", 2000), "Verifying window title contains created session name.") - checkNavigator(49, "Verifying whether all projects have been re-opened.") + checkNavigator(68, "Verifying whether all projects have been re-opened.") checkOpenDocuments(2, "Verifying whether 2 files have been re-opened.") if test.verify("utility.h" in str(mainWindow.windowTitle), "Verifying whether utility.h has been opened."): From 9f10e8daac9e4bbd117aafa63bdd6fc8ddc1c108 Mon Sep 17 00:00:00 2001 From: jkobus Date: Thu, 27 Feb 2014 12:22:47 +0100 Subject: [PATCH 07/32] Refactor internal structures inside diff editor Move "changed" property out of TextLineData into RowData as "equal". Change-Id: Id9cb87d099cecb61a2774e7a4fffcc162dece604 Reviewed-by: Jarek Kobus --- .../diffeditor/sidebysidediffeditorwidget.cpp | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index f9ea7705c18..11c0bd3e8c8 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -73,22 +73,23 @@ public: Separator, Invalid }; - TextLineData() : textLineType(Invalid), changed(true) {} - TextLineData(const QString &txt) : textLineType(TextLine), text(txt), changed(true) {} - TextLineData(TextLineType t) : textLineType(t), changed(true) {} + TextLineData() : textLineType(Invalid) {} + TextLineData(const QString &txt) : textLineType(TextLine), text(txt) {} + TextLineData(TextLineType t) : textLineType(t) {} TextLineType textLineType; QString text; - bool changed; // true if anything was changed in this line (inserted or removed), taking whitespaces into account }; class RowData { public: + RowData() : equal(false) {} RowData(const TextLineData &l) - : leftLine(l), rightLine(l) {} + : leftLine(l), rightLine(l), equal(true) {} RowData(const TextLineData &l, const TextLineData &r) - : leftLine(l), rightLine(r) {} + : leftLine(l), rightLine(r), equal(false) {} TextLineData leftLine; TextLineData rightLine; + bool equal; }; class ChunkData { @@ -113,7 +114,6 @@ public: static QList assemblyRows(const QStringList &lines, const QMap &lineSpans, - const QMap &equalLines, const QMap &changedPositions, QMap *outputChangedPositions) { @@ -135,8 +135,6 @@ static QList assemblyRows(const QStringList &lines, const int textLength = lines.at(i).count() + 1; pos += textLength; data.append(lines.at(i)); - if (equalLines.contains(i)) - data.last().changed = false; } while (changedIt != changedEnd) { if (changedIt.key() >= pos) @@ -229,9 +227,8 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, // QMap leftSpans; QMap rightSpans; - // - QMap leftEqualLines; - QMap rightEqualLines; + // + QMap equalLines; int leftLineNumber = 0; int rightLineNumber = 0; @@ -310,16 +307,12 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, } // check if lines are equal - if (line < newLeftLines.count() - 1 || i == leftDiffList.count()) { - // left line is equal + if ((line < commonLineCount - 1) // before the last common line in equality + || (line == commonLineCount - 1 // or the last common line in equality + && i == leftDiffList.count() // and it's the last iteration + && j == rightDiffList.count())) { if (line > 0 || lastLineEqual) - leftEqualLines.insert(leftLineNumber, true); - } - - if (line < newRightLines.count() - 1 || j == rightDiffList.count()) { - // right line is equal - if (line > 0 || lastLineEqual) - rightEqualLines.insert(rightLineNumber, true); + equalLines.insert(leftLineNumber, rightLineNumber); } if (line > 0) @@ -334,12 +327,10 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, QList leftData = assemblyRows(leftLines, leftSpans, - leftEqualLines, leftChangedPositions, &chunkData.changedLeftPositions); QList rightData = assemblyRows(rightLines, rightSpans, - rightEqualLines, rightChangedPositions, &chunkData.changedRightPositions); @@ -350,8 +341,22 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, rightData.append(TextLineData(TextLineData::Separator)); const int visualLineCount = leftData.count(); - for (int i = 0; i < visualLineCount; i++) - chunkData.rows.append(RowData(leftData.at(i), rightData.at(i))); + int leftLine = -1; + int rightLine = -1; + for (int i = 0; i < visualLineCount; i++) { + const TextLineData &leftTextLine = leftData.at(i); + const TextLineData &rightTextLine = rightData.at(i); + RowData row(leftTextLine, rightTextLine); + + if (leftTextLine.textLineType == TextLineData::TextLine) + ++leftLine; + if (rightTextLine.textLineType == TextLineData::TextLine) + ++rightLine; + if (equalLines.value(leftLine, -1) == rightLine) + row.equal = true; + + chunkData.rows.append(row); + } return chunkData; } @@ -1194,13 +1199,13 @@ FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &origi int i = 0; while (i < originalData.rows.count()) { const RowData &row = originalData.rows[i]; - if (!row.leftLine.changed && !row.rightLine.changed) { + if (row.equal) { // count how many equal int equalRowStart = i; i++; while (i < originalData.rows.count()) { const RowData originalRow = originalData.rows.at(i); - if (originalRow.leftLine.changed || originalRow.rightLine.changed) + if (!originalRow.equal) break; i++; } @@ -1509,7 +1514,7 @@ void SideBySideDiffEditorWidget::colorDiff(const QList &fileDataList) leftPos += rowData.leftLine.text.count() + 1; // +1 for '\n' rightPos += rowData.rightLine.text.count() + 1; // +1 for '\n' - if (rowData.leftLine.changed) { + if (!rowData.equal) { if (rowData.leftLine.textLineType == TextLineData::TextLine) { leftLinePos[leftLastDiffBlockStartPos] = leftPos; leftLastSkippedBlockStartPos = leftPos; @@ -1517,12 +1522,6 @@ void SideBySideDiffEditorWidget::colorDiff(const QList &fileDataList) leftSkippedPos[leftLastSkippedBlockStartPos] = leftPos; leftLastDiffBlockStartPos = leftPos; } - } else { - leftLastDiffBlockStartPos = leftPos; - leftLastSkippedBlockStartPos = leftPos; - } - - if (rowData.rightLine.changed) { if (rowData.rightLine.textLineType == TextLineData::TextLine) { rightLinePos[rightLastDiffBlockStartPos] = rightPos; rightLastSkippedBlockStartPos = rightPos; @@ -1531,6 +1530,8 @@ void SideBySideDiffEditorWidget::colorDiff(const QList &fileDataList) rightLastDiffBlockStartPos = rightPos; } } else { + leftLastDiffBlockStartPos = leftPos; + leftLastSkippedBlockStartPos = leftPos; rightLastDiffBlockStartPos = rightPos; rightLastSkippedBlockStartPos = rightPos; } @@ -1616,8 +1617,7 @@ void SideBySideDiffEditorWidget::slotLeftJumpToOriginalFileRequested(int diffFil if (rowData.rightLine.textLineType == TextLineData::TextLine) rightLineNumber++; if (leftLineNumber == lineNumber) { - int colNr = !rowData.leftLine.changed && !rowData.rightLine.changed - ? columnNumber : 0; + int colNr = rowData.equal ? columnNumber : 0; jumpToOriginalFile(leftFileName, rightLineNumber, colNr); return; } @@ -1852,14 +1852,12 @@ void DiffEditor::SideBySideDiffEditorWidget::testAssemblyRows() QMap changedPositions; changedPositions[5] = 14; // changed text from position 5 to position 14, occupy 9 characters: "efgh\nijkl" - QMap equalLines; // no equal lines - QMap expectedChangedPositions; expectedChangedPositions[5] = 20; // "efgh\n[\n\n\n\n\n\n]ijkl" - [\n] means inserted span QMap outputChangedPositions; - assemblyRows(lines, lineSpans, equalLines, changedPositions, &outputChangedPositions); + assemblyRows(lines, lineSpans, changedPositions, &outputChangedPositions); QVERIFY(outputChangedPositions == expectedChangedPositions); } From 139a1a8dbee95ad09cdfd79b775acf8ff2f9744c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 20 Feb 2014 17:03:55 +0100 Subject: [PATCH 08/32] Squish: Fix tst_rename_file Change-Id: Ic8c7aac5133b3df32b25188c1ab325a985cc3d42 Reviewed-by: Robert Loehning --- tests/system/objects.map | 1 + tests/system/suite_general/tst_rename_file/test.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/system/objects.map b/tests/system/objects.map index 20e6055b4e2..6dbacef2a53 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -131,6 +131,7 @@ :Qt Creator.Help_Search for:_QLineEdit {leftWidget=':Qt Creator.Search for:_QLabel' type='QLineEdit' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.Issues_QListView {type='QListView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Issues'} :Qt Creator.Project.Menu.File_QMenu {name='Project.Menu.File' type='QMenu'} +:Qt Creator.Project.Menu.Folder_QMenu {name='Project.Menu.Folder' type='QMenu' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.QtCreator.MenuBar_QMenuBar {name='QtCreator.MenuBar' type='QMenuBar' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.ReRun_QToolButton {toolTip='Re-run this run-configuration' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.Replace All_QToolButton {name='replaceAllButton' text='Replace All' type='QToolButton' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} diff --git a/tests/system/suite_general/tst_rename_file/test.py b/tests/system/suite_general/tst_rename_file/test.py index a8cc687d0f0..c3252e82566 100644 --- a/tests/system/suite_general/tst_rename_file/test.py +++ b/tests/system/suite_general/tst_rename_file/test.py @@ -82,7 +82,10 @@ def renameFile(projectDir, proFile, branch, oldname, newname): openItemContextMenu(treeview, itemText, 5, 5, 0) except: openItemContextMenu(treeview, addBranchWildcardToRoot(itemText), 5, 5, 0) - activateItem(waitForObjectItem(":Qt Creator.Project.Menu.File_QMenu", "Rename...")) + if oldname.endswith(".qrc"): + activateItem(waitForObjectItem(":Qt Creator.Project.Menu.Folder_QMenu", "Rename File")) + else: + activateItem(waitForObjectItem(":Qt Creator.Project.Menu.File_QMenu", "Rename...")) type(waitForObject(":Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit"), newname) type(waitForObject(":Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit"), "") test.verify(waitFor("os.path.exists(newFilePath)", 1000), From c4ef72dd399bda662b5127b3d3733a0c8c79f054 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 25 Feb 2014 13:27:54 +0100 Subject: [PATCH 09/32] CMake: work-around for CodeBlocks lack of framework support. CodeBlocks is utterly ignorant of frameworks on Mac, and won't report framework paths. The work-around is to check if the include path ends in ".framework", and if so, add the parent directory as framework path. Task-number: QTCREATORBUG-11445 Change-Id: I794dd72d755d5593e36ebf59543d0a5e9fda3cce Reviewed-by: Daniel Teske Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakeproject.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index a4658cb99ce..4bce4fa8e2b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -349,7 +349,22 @@ bool CMakeProject::parseCMakeLists() // This explicitly adds -I. to the include paths part->includePaths += projectDirectory(); - part->includePaths += cbpparser.includeFiles(); + + foreach (const QString &includeFile, cbpparser.includeFiles()) { + // CodeBlocks is utterly ignorant of frameworks on Mac, and won't report framework + // paths. The work-around is to check if the include path ends in ".framework", and + // if so, add the parent directory as framework path. + if (includeFile.endsWith(QLatin1String(".framework"))) { + const int slashIdx = includeFile.lastIndexOf(QLatin1Char('/')); + if (slashIdx != -1) { + part->frameworkPaths += includeFile.left(slashIdx); + continue; + } + } + + part->includePaths += includeFile; + } + part->projectDefines += cbpparser.defines(); CppTools::ProjectFileAdder adder(part->files); From 8a8092912b23aef54b9d6c9f02075a4057335f19 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Feb 2014 16:39:09 +0100 Subject: [PATCH 10/32] Fix location of qbs plugins. They are not (arch-independent) resources. Task-number: QTCREATORBUG-10074 Change-Id: If257dfc3a8a866003c84331409162699b162eb19 Reviewed-by: Joerg Bornemann --- qtcreator.pro | 2 ++ src/plugins/qbsprojectmanager/qbsproject.cpp | 18 ++++++++++++++---- src/plugins/qbsprojectmanager/qbsproject.h | 3 ++- src/shared/qbs | 2 +- src/src.qbs | 1 + 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/qtcreator.pro b/qtcreator.pro index 7271ab940c4..1e250446d5e 100644 --- a/qtcreator.pro +++ b/qtcreator.pro @@ -43,6 +43,8 @@ exists(src/shared/qbs/qbs.pro) { system("echo QBS_LIB_INSTALL_DIR = $${QTC_PREFIX}/$${IDE_LIBRARY_BASENAME}/qtcreator >> $$qmake_cache") system("echo QBS_RESOURCES_BUILD_DIR = $${maybe_backslash}\"$${IDE_DATA_PATH}/qbs$${maybe_backslash}\" >> $$qmake_cache") system("echo QBS_RESOURCES_INSTALL_DIR = $${QTC_PREFIX}/share/qtcreator/qbs >> $$qmake_cache") + system("echo QBS_PLUGINS_BUILD_DIR = $${maybe_backslash}\"$${IDE_BUILD_TREE}/lib/qtcreator/$${maybe_backslash}\" >> $$qmake_cache") + system("echo QBS_PLUGINS_INSTALL_DIR = $${QTC_PREFIX}/lib/qtcreator >> $$qmake_cache") system("echo CONFIG += qbs_no_dev_install >> $$qmake_cache") } diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 8a4e1112787..03c15752262 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -63,6 +63,8 @@ #include +#include +#include #include using namespace Core; @@ -462,9 +464,8 @@ void QbsProject::parse(const QVariantMap &config, const Environment &env, const params.setIgnoreDifferentProjectFilePath(false); params.setEnvironment(env.toProcessEnvironment()); const qbs::Preferences prefs(QbsManager::settings(), profileName); - const QString qbsDir = qbsDirectory(); - params.setSearchPaths(prefs.searchPaths(qbsDir)); - params.setPluginPaths(prefs.pluginPaths(qbsDir)); + params.setSearchPaths(prefs.searchPaths(resourcesBaseDirectory())); + params.setPluginPaths(prefs.pluginPaths(pluginsBaseDirectory())); // Do the parsing: prepareForParsing(); @@ -705,7 +706,7 @@ void QbsProject::updateDeploymentInfo(const qbs::Project &project) activeTarget()->setDeploymentData(deploymentData); } -QString QbsProject::qbsDirectory() const +QString QbsProject::resourcesBaseDirectory() const { const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR); if (!qbsInstallDir.isEmpty()) @@ -713,5 +714,14 @@ QString QbsProject::qbsDirectory() const return ICore::resourcePath() + QLatin1String("/qbs"); } +QString QbsProject::pluginsBaseDirectory() const +{ + const QString qbsInstallDir = QLatin1String(QBS_INSTALL_DIR); + if (!qbsInstallDir.isEmpty()) + return qbsInstallDir + QLatin1String("/lib/"); + return QDir::cleanPath(QCoreApplication::applicationDirPath() + + QLatin1String("/../lib/qtcreator")); +} + } // namespace Internal } // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 1ca9003717e..51d4031553a 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -131,7 +131,8 @@ private: void updateQmlJsCodeModel(const qbs::ProjectData &prj); void updateApplicationTargets(const qbs::ProjectData &projectData); void updateDeploymentInfo(const qbs::Project &project); - QString qbsDirectory() const; + QString resourcesBaseDirectory() const; + QString pluginsBaseDirectory() const; QbsManager *const m_manager; const QString m_projectName; diff --git a/src/shared/qbs b/src/shared/qbs index de8682b7d4f..0816b8e476d 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit de8682b7d4fccdef5c93759336e51ab73ecd5021 +Subproject commit 0816b8e476d20e00cbcffd1e71162adf93e85658 diff --git a/src/src.qbs b/src/src.qbs index d0aa9a4957c..d7ba55a39a5 100644 --- a/src/src.qbs +++ b/src/src.qbs @@ -27,6 +27,7 @@ Project { property path libRPaths: qbs.targetOS.contains("osx") ? ["@loader_path/.."] : ["$ORIGIN/.."] property path resourcesInstallDir: project.ide_data_path + "/qbs" + property string pluginsInstallDir: "lib/qtcreator" references: [ qbsBaseDir + "/src/lib/libs.qbs", From 3173548a118d01d97a83613cdddfc588e1640f52 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Feb 2014 12:00:27 +0100 Subject: [PATCH 11/32] Shortcut settings: Update collision markers when resetting shortcut Task-number: QTCREATORBUG-6400 Change-Id: Ibef1da2fb71d157769412d7cbbd730e7656979ed Reviewed-by: Daniel Teske Reviewed-by: Eike Ziller --- src/plugins/coreplugin/dialogs/shortcutsettings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index c9d1e996d85..af679852914 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -200,6 +200,8 @@ void ShortcutSettings::resetTargetIdentifier() if (current && current->data(0, Qt::UserRole).isValid()) { ShortcutItem *scitem = qvariant_cast(current->data(0, Qt::UserRole)); setKeySequence(scitem->m_cmd->defaultKeySequence()); + foreach (ShortcutItem *item, m_scitems) + markCollisions(item); } } From dd10686ddb8092fe74d360a8bbc67fd488db86ea Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Feb 2014 11:49:53 +0100 Subject: [PATCH 12/32] Do '&', '&&' conversion when creating id for external tool Task-number: QTCREATORBUG-5827 Change-Id: Ib2a30a5c051be652ea99ff1923456d352b23a71d Reviewed-by: Orgad Shaneh --- src/plugins/coreplugin/toolsettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/coreplugin/toolsettings.cpp b/src/plugins/coreplugin/toolsettings.cpp index 18043415260..da5d1f4f778 100644 --- a/src/plugins/coreplugin/toolsettings.cpp +++ b/src/plugins/coreplugin/toolsettings.cpp @@ -89,6 +89,7 @@ static QString getUserFilePath(const QString &proposalFileName) static QString idFromDisplayName(const QString &displayName) { QString id = displayName; + id.remove(QRegExp(QLatin1String("&(?!&)"))); QChar *c = id.data(); while (!c->isNull()) { if (!c->isLetterOrNumber()) From bc4532194922dc6f5ccb021cc1b637323aa5e396 Mon Sep 17 00:00:00 2001 From: hluk Date: Wed, 26 Feb 2014 16:15:33 +0100 Subject: [PATCH 13/32] FakeVim: Allow to insert space on Change-Id: I20f3e8e6602c35b812e2a1f29fdc2b1b458468e5 Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 7f1fc081adf..046f777b6e8 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -973,7 +973,7 @@ public: // cursor keys. This breaks some of the logic later on // relying on text() being empty for "special" keys. // FIXME: Check the real conditions. - if (x.unicode() <= ' ') + if (x.unicode() < ' ') m_text.clear(); else if (x.isLetter()) m_key = x.toUpper().unicode(); @@ -1061,7 +1061,7 @@ public: return m_key < a.m_key; // Text for some mapped key cannot be determined (e.g. ) so if text is not set for // one of compared keys ignore it. - if (!m_text.isEmpty() && !a.m_text.isEmpty()) + if (!m_text.isEmpty() && !a.m_text.isEmpty() && m_text != _(" ")) return m_text < a.m_text; return m_modifiers < a.m_modifiers; } From 9e3005ee951f81ef6e49b6c4e1191db8918f8db9 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Feb 2014 15:52:22 +0100 Subject: [PATCH 14/32] Debugger: Rework gdb Q_OBJECT detection (again) We need to filter out Q_GADGETS Change-Id: Id0ec18188e5b40506d69908e7218e3971cbddad9 Reviewed-by: hjk --- share/qtcreator/debugger/gdbbridge.py | 69 +++++++++++++++------------ 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index fb1c612d98b..2bfa0f1f8f7 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -833,47 +833,54 @@ class Dumper(DumperBase): def extractByte(self, addr): return struct.unpack("b", self.readRawMemory(addr, 1))[0] - def extractStaticMetaObjectHelper(self, typeobj): + + def extractStaticMetaObjectHelper(self, typeName): """ Checks whether type has a Q_OBJECT macro. Returns the staticMetaObject, or 0. """ + # No templates for now. + if typeName.find('<') >= 0: + return 0 + + staticMetaObjectName = typeName + "::staticMetaObject" + if hasattr(gdb, 'lookup_global_symbol'): + result = gdb.lookup_global_symbol(staticMetaObjectName) + result = result.value() if result else 0 + else: + # Older GDB... + try: + result = gdb.parse_and_eval(staticMetaObjectName) + except: + result = 0 + + # We need to distinguish Q_OBJECT from Q_GADGET: + # a Q_OBJECT SMO has a non-null superdata (unless it's QObject itself), + # a Q_GADGET SMO has a null superdata (hopefully) + if result and typeName != self.qtNamespace() + "QObject": + if not self.extractPointer(result): + # This looks like a Q_GADGET + result = 0 + + return result + + def extractStaticMetaObject(self, typeobj): + """ + Checks recursively whether a type derives from QObject. + """ typeName = str(typeobj) result = self.knownStaticMetaObjects.get(typeName, None) if result is not None: # Is 0 or the static metaobject. return result - staticMetaObjectName = typeName + "::staticMetaObject" - try: - result = gdb.lookup_global_symbol(staticMetaObjectName) - result = result.value() if result else 0 - self.knownStaticMetaObjects[typeName] = result - return result - except: - pass + result = self.extractStaticMetaObjectHelper(typeName) + if not result: + fields = typeobj.fields() + if len(fields) and fields[0].is_base_class: + result = self.extractStaticMetaObject(fields[0].type) - # Older GDB... - try: - result = gdb.parse_and_eval(staticMetaObjectName) - self.knownStaticMetaObjects[typeName] = result - return result - except: - self.knownStaticMetaObjects[typeName] = 0 - return 0 - - def extractStaticMetaObject(self, typeobj): - """ - Checks recursively whether a type derives from QObject. - """ - result = self.extractStaticMetaObjectHelper(typeobj) - if result: - return result - fields = typeobj.fields() - if not len(fields): - return 0 - if not fields[0].is_base_class: - return 0 - return self.extractStaticMetaObject(fields[0].type) + self.knownStaticMetaObjects[typeName] = result + return result def put(self, value): From c03bcef429cc3320dba91e0cbc1b5c61d3604ec5 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Thu, 27 Feb 2014 13:47:48 +0100 Subject: [PATCH 15/32] VcsBase: Replace a struct with class Change-Id: I5895e759820a358cd1d54888bfe84ddccb484967 Reviewed-by: Tobias Hunger --- src/plugins/vcsbase/vcsbaseoutputwindow.cpp | 3 ++- src/plugins/vcsbase/vcsbaseoutputwindow.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.cpp b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp index 6a8cc4626a6..3ec044e271d 100644 --- a/src/plugins/vcsbase/vcsbaseoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp @@ -264,8 +264,9 @@ void OutputWindowPlainTextEdit::setFormat(enum VcsBaseOutputWindow::MessageStyle } // namespace Internal // ------------------- VcsBaseOutputWindowPrivate -struct VcsBaseOutputWindowPrivate +class VcsBaseOutputWindowPrivate { +public: static VcsBaseOutputWindow *instance; Internal::OutputWindowPlainTextEdit *plainTextEdit(); diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.h b/src/plugins/vcsbase/vcsbaseoutputwindow.h index 8e2636a2ae9..6e52b7aebd8 100644 --- a/src/plugins/vcsbase/vcsbaseoutputwindow.h +++ b/src/plugins/vcsbase/vcsbaseoutputwindow.h @@ -36,7 +36,7 @@ namespace VcsBase { -struct VcsBaseOutputWindowPrivate; +class VcsBaseOutputWindowPrivate; class VCSBASE_EXPORT VcsBaseOutputWindow : public Core::IOutputPane { From d2cad7d1a6444ca1e5c81582f5e8c4ba1db56480 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Thu, 27 Feb 2014 13:48:33 +0100 Subject: [PATCH 16/32] VcsOutputPane: Filter passwords from URLs Task-number: QTCREATORBUG-11246 Change-Id: Ib204b2e0392d1c1876f01876d7f90f56e91218d4 Reviewed-by: Tobias Hunger --- src/plugins/vcsbase/vcsbaseoutputwindow.cpp | 19 ++++++++++++++++++- src/plugins/vcsbase/vcsbaseoutputwindow.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.cpp b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp index 3ec044e271d..94b5d645f0a 100644 --- a/src/plugins/vcsbase/vcsbaseoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsbaseoutputwindow.cpp @@ -272,6 +272,7 @@ public: QPointer m_plainTextEdit; QString repository; + QRegExp passwordRegExp; }; // Create log editor on demand. Some errors might be logged @@ -289,9 +290,25 @@ VcsBaseOutputWindow *VcsBaseOutputWindowPrivate::instance = 0; VcsBaseOutputWindow::VcsBaseOutputWindow() : d(new VcsBaseOutputWindowPrivate) { + d->passwordRegExp = QRegExp(QLatin1String("://([^@:]+):([^@]+)@")); + Q_ASSERT(d->passwordRegExp.isValid()); VcsBaseOutputWindowPrivate::instance = this; } +QString VcsBaseOutputWindow::filterPasswordFromUrls(const QString &input) +{ + int pos = 0; + QString result = input; + while ((pos = d->passwordRegExp.indexIn(result, pos)) >= 0) { + QString tmp = result.left(pos + 3) + d->passwordRegExp.cap(1) + QLatin1String(":***@"); + int newStart = tmp.count(); + tmp += result.mid(pos + d->passwordRegExp.matchedLength()); + result = tmp; + pos = newStart; + } + return result; +} + VcsBaseOutputWindow::~VcsBaseOutputWindow() { VcsBaseOutputWindowPrivate::instance = 0; @@ -443,7 +460,7 @@ QString VcsBaseOutputWindow::msgExecutionLogEntry(const QString &workingDir, void VcsBaseOutputWindow::appendCommand(const QString &text) { - append(text, Command, true); + append(filterPasswordFromUrls(text), Command, true); } void VcsBaseOutputWindow::appendCommand(const QString &workingDirectory, diff --git a/src/plugins/vcsbase/vcsbaseoutputwindow.h b/src/plugins/vcsbase/vcsbaseoutputwindow.h index 6e52b7aebd8..84fa6999bb7 100644 --- a/src/plugins/vcsbase/vcsbaseoutputwindow.h +++ b/src/plugins/vcsbase/vcsbaseoutputwindow.h @@ -121,6 +121,8 @@ public slots: private: VcsBaseOutputWindow(); + QString filterPasswordFromUrls(const QString &input); + VcsBaseOutputWindowPrivate *d; }; From 18906fac4f0f7146976de343ab00c79f43af4fa4 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 26 Feb 2014 15:22:06 +0200 Subject: [PATCH 17/32] Git: Protect against removal of the "Local Branches" node ... When a single local branch is being removed Change-Id: I4321d045ebb6faaf5f864ff33cb4f34c15d2264b Reviewed-by: Tobias Hunger --- src/plugins/git/branchmodel.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 75e5c7cbc93..93cce7de063 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -692,14 +692,18 @@ QModelIndex BranchModel::nodeToIndex(BranchNode *node) const void BranchModel::removeNode(const QModelIndex &idx) { - QModelIndex tmp = idx; // tmp is a leaf, so count must be 0. - while (indexToNode(tmp)->count() == 0) { - QModelIndex tmpParent = parent(tmp); - beginRemoveRows(tmpParent, tmp.row(), tmp.row()); - indexToNode(tmpParent)->children.removeAt(tmp.row()); - delete indexToNode(tmp); + QModelIndex nodeIndex = idx; // idx is a leaf, so count must be 0. + BranchNode *node = indexToNode(nodeIndex); + while (node->count() == 0 && node->parent != m_rootNode) { + BranchNode *parentNode = node->parent; + const QModelIndex parentIndex = nodeToIndex(parentNode); + const int nodeRow = nodeIndex.row(); + beginRemoveRows(parentIndex, nodeRow, nodeRow); + parentNode->children.removeAt(nodeRow); + delete node; endRemoveRows(); - tmp = tmpParent; + node = parentNode; + nodeIndex = parentIndex; } } From 5c942d04c5060803316ced0b87151b4fcb1649d9 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 26 Feb 2014 22:04:52 +0200 Subject: [PATCH 18/32] Git: Suppress show-ref command logging Yet another plumbing command... Change-Id: I88ba2349d8c15e47372addb3034f1bed2de170f2 Reviewed-by: Tobias Hunger --- src/plugins/git/gitclient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 22c094c1711..8c918a3c4b4 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2001,7 +2001,8 @@ bool GitClient::synchronousHeadRefs(const QString &workingDirectory, QStringList << QLatin1String("--abbrev=10") << QLatin1String("--dereference"); QByteArray outputText; QByteArray errorText; - const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText); + const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText, + VcsBasePlugin::SuppressCommandLogging); if (!rc) { msgCannotRun(args, workingDirectory, errorText, errorMessage); return false; From cb7f9fe49650c013755db2ad4e8f7727fb2cd251 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Feb 2014 09:22:09 +0200 Subject: [PATCH 19/32] Git: Remove refs/heads/ prefix from reset message in branches dialog Change-Id: Ia93cbb52038c1ea29f5fa441c9eb0e88cb11d9aa Reviewed-by: Tobias Hunger --- src/plugins/git/branchdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index a18c9a0d397..7d922a5cd75 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -323,8 +323,8 @@ void BranchDialog::log() void BranchDialog::reset() { - QString currentName = m_model->fullName(m_model->currentBranch(), true); - QString branchName = m_model->fullName(selectedIndex(), true); + QString currentName = m_model->fullName(m_model->currentBranch()); + QString branchName = m_model->fullName(selectedIndex()); if (currentName.isEmpty() || branchName.isEmpty()) return; From 4465276e10b9feafb20375aed6d7f5b7060398b8 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Feb 2014 09:23:44 +0200 Subject: [PATCH 20/32] Git: Conditionally enable Reset button in branches dialog Conditions: * There is an active local branch * The selected node is a leaf * The selected node is not the active branch Change-Id: I539dd13750737934378e503484646634e50a1aa7 Reviewed-by: Tobias Hunger --- src/plugins/git/branchdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index 7d922a5cd75..8798f4657d5 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -128,6 +128,7 @@ void BranchDialog::enableButtons() m_ui->diffButton->setEnabled(hasActions); m_ui->checkoutButton->setEnabled(hasActions && !currentSelected); m_ui->rebaseButton->setEnabled(hasActions && !currentSelected); + m_ui->resetButton->setEnabled(hasActions && currentLocal && !currentSelected); m_ui->mergeButton->setEnabled(hasActions && !currentSelected); m_ui->cherryPickButton->setEnabled(hasActions && !currentSelected); m_ui->trackButton->setEnabled(hasActions && currentLocal && !currentSelected && !isTag); From f74021260a0b81c9b74532e9a4ce868ed351760c Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Feb 2014 09:28:26 +0200 Subject: [PATCH 21/32] Git: Reorder buttons in branches dialog Reset works on current branch by the contents of another, like Merge and Rebase. Change-Id: I904823c177dd3c79ff8e1f49fe32d82be9bb8797 Reviewed-by: Tobias Hunger --- src/plugins/git/branchdialog.ui | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui index 8f7be998ad6..320c78bbd69 100644 --- a/src/plugins/git/branchdialog.ui +++ b/src/plugins/git/branchdialog.ui @@ -130,13 +130,6 @@ - - - - Reset - - - @@ -158,6 +151,13 @@ + + + + Reset + + + From 1817c48c7bcdbb334ffb27e2410704ecc8f35b30 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 26 Feb 2014 22:03:55 +0200 Subject: [PATCH 22/32] Git: Use `git describe` for topic before falling back to "Detach Head" Change-Id: Iaf8be78ac3b6119f01ad3491eec7eccfa5f45e26 Reviewed-by: Tobias Hunger --- src/plugins/git/gitclient.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 8c918a3c4b4..507a11dbb4f 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2052,9 +2052,19 @@ QString GitClient::synchronousTopic(const QString &workingDirectory) (derefInd == -1) ? -1 : derefInd - remoteStart.size()); } } + if (!remoteBranch.isEmpty()) + return remoteBranch; - // No tag - return remoteBranch.isEmpty() ? tr("Detached HEAD") : remoteBranch; + // No tag or remote branch - try git describe + QByteArray output; + QStringList arguments; + arguments << QLatin1String("describe"); + if (fullySynchronousGit(workingDirectory, arguments, &output, 0, VcsBasePlugin::NoOutput)) { + const QString describeOutput = commandOutputFromLocal8Bit(output.trimmed()); + if (!describeOutput.isEmpty()) + return describeOutput; + } + return tr("Detached HEAD"); } bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QString &ref, From 3cc743f1bf54da047cefc575dac03aa71a0dc88b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 27 Feb 2014 12:14:45 +0100 Subject: [PATCH 23/32] QmlProfiler: Provide a horizontal scroll bar for the timeline This requires the consolidation of the nested Flickable elements into one, which is probably a good idea anyway. The horizontal scroll bar is important because people might not understand that they can use the overview for scrolling. Change-Id: Ie1555265fc3edafaf6e6e4f34d77b0d034d45639 Reviewed-by: Kai Koehne --- src/plugins/qmlprofiler/qml/MainView.qml | 323 +++++++++--------- .../qmlprofiler/qml/SelectionRange.qml | 6 +- src/plugins/qmlprofiler/qml/TimeMarks.qml | 2 +- 3 files changed, 164 insertions(+), 167 deletions(-) diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index 0f5c805604d..8659e5e8ba8 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -66,6 +66,8 @@ Rectangle { property date recordingStartDate property real elapsedTime + color: "#dcdcdc" + // ***** connections with external objects Connections { target: zoomControl @@ -230,158 +232,20 @@ Rectangle { } Flickable { - id: vertflick + id: labelsflick flickableDirection: Flickable.VerticalFlick - anchors.fill: parent - clip: true - contentHeight: labels.height - boundsBehavior: Flickable.StopAtBounds - - // ScrollView will try to deinteractivate it. We don't want that - // as the horizontal flickable is interactive, too. We do occasionally - // switch to non-interactive ourselves, though. - property bool stayInteractive: true - onInteractiveChanged: interactive = stayInteractive - onStayInteractiveChanged: interactive = stayInteractive - - // ***** child items - TimeMarks { - id: backgroundMarks - y: vertflick.contentY - height: vertflick.height - width: root.width - labels.width - anchors.left: labels.right - } - - Flickable { - function setContentWidth() { - var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); - if (duration > 0) - contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; - } - - id: flick - anchors.top: parent.top - anchors.topMargin: labels.y - anchors.right: parent.right - anchors.left: labels.right - contentWidth: 0 - height: labels.height + labelsTail.height - flickableDirection: Flickable.HorizontalFlick - boundsBehavior: Flickable.StopAtBounds - - onContentXChanged: view.updateZoomControl() - onWidthChanged: setContentWidth() - - clip:true - - SelectionRange { - id: selectionRange - visible: root.selectionRangeMode && creationState !== 0 - height: parent.height - z: 2 - } - - TimelineRenderer { - id: view - - profilerModelProxy: qmlProfilerModelProxy - - x: flick.contentX - y: vertflick.contentY - width: flick.width - height: vertflick.height - - onEndTimeChanged: requestPaint() - onYChanged: requestPaint() - onHeightChanged: requestPaint() - - function updateZoomControl() { - var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) + - qmlProfilerModelProxy.traceStartTime(); - if (Math.abs(newStartTime - startTime) > 1) { - var newEndTime = Math.round((flick.contentX + flick.width) * - (endTime - startTime) / - flick.width) + - qmlProfilerModelProxy.traceStartTime(); - zoomControl.setRange(newStartTime, newEndTime); - } - } - - function updateFlickRange(start, end) { - if (start !== startTime || end !== endTime) { - startTime = start; - endTime = end; - var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) * - flick.width / (endTime-startTime); - if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1) - flick.contentX = newStartX; - } - } - - onSelectedItemChanged: { - if (selectedItem !== -1) { - // display details - rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem)); - rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem)); - - // center view (horizontally) - var windowLength = view.endTime - view.startTime; - var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem); - var eventEndTime = eventStartTime + - qmlProfilerModelProxy.getDuration(selectedModel, selectedItem); - - if (eventEndTime < view.startTime || eventStartTime > view.endTime) { - var center = (eventStartTime + eventEndTime)/2; - var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength, - Math.max(0, Math.floor(center - windowLength/2))); - - zoomControl.setRange(from, from + windowLength); - - } - } else { - root.hideRangeDetails(); - } - } - - onItemPressed: { - var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem); - if (location.hasOwnProperty("file")) // not empty - root.gotoSourceLocation(location.file, location.line, location.column); - } - - // hack to pass mouse events to the other mousearea if enabled - startDragArea: selectionRange.ready ? selectionRange.getLeft() : -flick.contentX - endDragArea: selectionRange.ready ? selectionRange.getRight() : -flick.contentX-1 - } - MouseArea { - id: selectionRangeControl - enabled: false - width: flick.width - height: flick.height - x: flick.contentX - hoverEnabled: enabled - z: 2 - - onReleased: { - selectionRange.releasedOnCreation(); - } - onPressed: { - selectionRange.pressedOnCreation(); - } - onCanceled: { - selectionRange.releasedOnCreation(); - } - onPositionChanged: { - selectionRange.movedOnCreation(); - } - } - } + interactive: false + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + width: labels.width + contentY: flick.contentY Rectangle { id: labels + anchors.left: parent.left width: 150 - color: "#dcdcdc" + color: root.color height: col.height property int rowCount: qmlProfilerModelProxy.categoryCount(); @@ -394,28 +258,163 @@ Rectangle { } } } + } - Rectangle { - id: labelsTail - anchors.top: labels.bottom - height: Math.max(0, vertflick.height - labels.height) - width: labels.width - color: labels.color + // border between labels and timeline + Rectangle { + id: labelsborder + anchors.left: labelsflick.right + anchors.top: parent.top + anchors.bottom: parent.bottom + width: 1 + color: "#858585" + } + + Flickable { + id: flick + contentHeight: labels.height + contentWidth: 0 + flickableDirection: Flickable.HorizontalAndVerticalFlick + boundsBehavior: Flickable.StopAtBounds + clip:true + + // ScrollView will try to deinteractivate it. We don't want that + // as the horizontal flickable is interactive, too. We do occasionally + // switch to non-interactive ourselves, though. + property bool stayInteractive: true + onInteractiveChanged: interactive = stayInteractive + onStayInteractiveChanged: interactive = stayInteractive + + function setContentWidth() { + var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); + if (duration > 0) + contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; } - // border between labels and timeline - Rectangle { - anchors.left: labels.right - anchors.top: labels.top - anchors.bottom: labelsTail.bottom - width: 1 - color: "#858585" + onContentXChanged: view.updateZoomControl() + onWidthChanged: setContentWidth() + + // ***** child items + TimeMarks { + id: backgroundMarks + y: flick.contentY + x: flick.contentX + height: flick.height + width: scroller.width + } + + SelectionRange { + id: selectionRange + visible: root.selectionRangeMode && creationState !== 0 + z: 2 + } + + TimelineRenderer { + id: view + + profilerModelProxy: qmlProfilerModelProxy + + x: flick.contentX + y: flick.contentY + + // paint "under" the vertical scrollbar, so that it always matches with the timemarks + width: scroller.width + height: flick.height + + onEndTimeChanged: requestPaint() + onYChanged: requestPaint() + onHeightChanged: requestPaint() + + function updateZoomControl() { + var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) + + qmlProfilerModelProxy.traceStartTime(); + if (Math.abs(newStartTime - startTime) > 1) { + var newEndTime = Math.round((flick.contentX + flick.width) * + (endTime - startTime) / + flick.width) + + qmlProfilerModelProxy.traceStartTime(); + zoomControl.setRange(newStartTime, newEndTime); + } + } + + function updateFlickRange(start, end) { + if (start !== startTime || end !== endTime) { + startTime = start; + endTime = end; + var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) * + flick.width / (endTime-startTime); + if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1) + flick.contentX = newStartX; + } + } + + onSelectedItemChanged: { + if (selectedItem !== -1) { + // display details + rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem)); + rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem)); + + // center view (horizontally) + var windowLength = view.endTime - view.startTime; + var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem); + var eventEndTime = eventStartTime + + qmlProfilerModelProxy.getDuration(selectedModel, selectedItem); + + if (eventEndTime < view.startTime || eventStartTime > view.endTime) { + var center = (eventStartTime + eventEndTime)/2; + var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength, + Math.max(0, Math.floor(center - windowLength/2))); + + zoomControl.setRange(from, from + windowLength); + + } + } else { + root.hideRangeDetails(); + } + } + + onItemPressed: { + var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem); + if (location.hasOwnProperty("file")) // not empty + root.gotoSourceLocation(location.file, location.line, location.column); + } + + // hack to pass mouse events to the other mousearea if enabled + startDragArea: selectionRange.ready ? selectionRange.getLeft() : -flick.contentX + endDragArea: selectionRange.ready ? selectionRange.getRight() : -flick.contentX-1 + } + MouseArea { + id: selectionRangeControl + enabled: false + width: flick.width + height: flick.height + x: flick.contentX + y: flick.contentY + hoverEnabled: enabled + z: 2 + + onReleased: { + selectionRange.releasedOnCreation(); + } + onPressed: { + selectionRange.pressedOnCreation(); + } + onCanceled: { + selectionRange.releasedOnCreation(); + } + onPositionChanged: { + selectionRange.movedOnCreation(); + } } } ScrollView { - contentItem: vertflick - anchors.fill: parent + id: scroller + contentItem: flick + anchors.left: labelsborder.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right } SelectionRangeDetails { diff --git a/src/plugins/qmlprofiler/qml/SelectionRange.qml b/src/plugins/qmlprofiler/qml/SelectionRange.qml index f565571294e..47a1bd94b4e 100644 --- a/src/plugins/qmlprofiler/qml/SelectionRange.qml +++ b/src/plugins/qmlprofiler/qml/SelectionRange.qml @@ -107,8 +107,7 @@ RangeMover { // creation control function releasedOnCreation() { if (selectionRange.creationState === 2) { - flick.interactive = true; - vertflick.stayInteractive = true; + flick.stayInteractive = true; selectionRange.creationState = 3; selectionRangeControl.enabled = false; } @@ -116,8 +115,7 @@ RangeMover { function pressedOnCreation() { if (selectionRange.creationState === 1) { - flick.interactive = false; - vertflick.stayInteractive = false; + flick.stayInteractive = false; selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX); selectionRange.creationState = 2; } diff --git a/src/plugins/qmlprofiler/qml/TimeMarks.qml b/src/plugins/qmlprofiler/qml/TimeMarks.qml index f9ac8e3590e..94e8fd058b0 100644 --- a/src/plugins/qmlprofiler/qml/TimeMarks.qml +++ b/src/plugins/qmlprofiler/qml/TimeMarks.qml @@ -128,7 +128,7 @@ Canvas { // bottom if (height > labels.height - y) { context.fillStyle = "#f5f5f5"; - context.fillRect(0, labels.height - y, width, Math.min(height - labels.height + y, labelsTail.height)); + context.fillRect(0, labels.height - y, width, height - labels.height + y); } } } From bd43c1c51b0fb16b5be3b036baade03cdf564d58 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 27 Feb 2014 12:48:32 +0100 Subject: [PATCH 24/32] QmlProfiler: take the left border into account when painting time marks Without this the time marks are 1 pixel off in relation to the main view. Change-Id: Iee8aaee447fedb9c57934c8089874414d9000995 Reviewed-by: Kai Koehne --- src/plugins/qmlprofiler/qml/TimeDisplay.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmlprofiler/qml/TimeDisplay.qml b/src/plugins/qmlprofiler/qml/TimeDisplay.qml index 12cecf435f1..4327d427312 100644 --- a/src/plugins/qmlprofiler/qml/TimeDisplay.qml +++ b/src/plugins/qmlprofiler/qml/TimeDisplay.qml @@ -54,17 +54,18 @@ Canvas { context.fillStyle = "white"; context.fillRect(0, 0, width, height); + var realWidth = width - 1; // account for left border var totalTime = endTime - startTime; - var spacing = width / totalTime; + var spacing = realWidth / totalTime; var initialBlockLength = 120; - var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width * initialBlockLength ) / Math.LN2 ) ); + var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / realWidth * initialBlockLength ) / Math.LN2 ) ); var pixelsPerBlock = timePerBlock * spacing; var pixelsPerSection = pixelsPerBlock / 5; - var blockCount = width / pixelsPerBlock; + var blockCount = realWidth / pixelsPerBlock; var realStartTime = Math.floor(startTime/timePerBlock) * timePerBlock; - var realStartPos = (startTime-realStartTime) * spacing; + var realStartPos = (startTime - realStartTime) * spacing - 1; timePerPixel = timePerBlock/pixelsPerBlock; From 24a5c3e913f1cafe4471078853a2c1f1858609fa Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 20 Feb 2014 21:39:34 +0200 Subject: [PATCH 25/32] Tests: Record macro definition check Change-Id: Ia2151ead6ba4ad2e2a3598d05dfc24a10e6a7cdb Reviewed-by: Nikolai Kosjar --- .../preprocessor/tst_preprocessor.cpp | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp index ca3460335d2..be153ab0abb 100644 --- a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp +++ b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include //TESTED_COMPONENT=src/libs/cplusplus using namespace CPlusPlus; @@ -116,9 +117,17 @@ public: } virtual void passedMacroDefinitionCheck(unsigned /*offset*/, - unsigned /*line*/, - const Macro &/*macro*/) {} - virtual void failedMacroDefinitionCheck(unsigned /*offset*/, const ByteArrayRef &/*name*/) {} + unsigned line, + const Macro ¯o) + { + m_definitionsResolvedFromLines[macro.name()].append(line); + } + + virtual void failedMacroDefinitionCheck(unsigned /*offset*/, + const ByteArrayRef &name) + { + m_unresolvedDefines.insert(name.toByteArray()); + } virtual void notifyMacroReference(unsigned offset, unsigned line, const Macro ¯o) { @@ -249,6 +258,12 @@ public: QHash > macroUsesLine() const { return m_macroUsesLine; } + QHash > definitionsResolvedFromLines() const + { return m_definitionsResolvedFromLines; } + + QSet unresolvedDefines() const + { return m_unresolvedDefines; } + const QList macroArgsCount() const { return m_macroArgsCount; } @@ -266,6 +281,8 @@ private: QList m_definedMacros; QList m_definedMacrosLine; QHash > m_macroUsesLine; + QHash > m_definitionsResolvedFromLines; + QSet m_unresolvedDefines; QList m_macroArgsCount; }; @@ -326,6 +343,7 @@ private slots: void extra_va_args(); void defined(); void defined_data(); + void defined_usage(); void empty_macro_args(); void macro_args_count(); void invalid_param_count(); @@ -1058,6 +1076,36 @@ void tst_Preprocessor::defined_data() "#endif\n"; } +void tst_Preprocessor::defined_usage() +{ + QByteArray output; + Environment env; + MockClient client(&env, &output); + Preprocessor pp(&client, &env); + QByteArray source = + "#define X\n" + "#define Y\n" + "#ifdef X\n" + "#endif\n" + "#ifdef Y\n" + "#endif\n" + "#ifndef X\n" + "#endif\n" + "#ifndef Y\n" + "#endif\n" + "#ifdef ABSENT\n" + "#endif\n" + "#ifndef ABSENT2\n" + "#endif\n" + ; + pp.run(QLatin1String(""), source); + QHash > definitionsResolvedFromLines = + client.definitionsResolvedFromLines(); + QCOMPARE(definitionsResolvedFromLines["X"], QList() << 3 << 7); + QCOMPARE(definitionsResolvedFromLines["Y"], QList() << 5 << 9); + QCOMPARE(client.unresolvedDefines(), QSet() << "ABSENT" << "ABSENT2"); +} + void tst_Preprocessor::dont_eagerly_expand_data() { QTest::addColumn("input"); From 36dccb42faf256756d94b4ad797bfb40bb449f07 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 5 Feb 2014 13:11:16 +0100 Subject: [PATCH 26/32] C++: fix indentation for static var decls of anonymous classes. Task-number: QTCREATORBUG-11392 Change-Id: Ie5dd9014383b639e63653e8abc856fea9e620e49 Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/cppcodeformatter.cpp | 3 ++ .../codeformatter/tst_codeformatter.cpp | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index 08d51889459..543e0d4deb8 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -179,6 +179,9 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) case declaration_start: switch (kind) { + case T_CLASS: + case T_STRUCT: turnInto(class_start); continue; + case T_ENUM: turnInto(enum_start); continue; case T_RBRACE: leave(true); continue; case T_SEMICOLON: leave(true); break; case T_EQUAL: enter(assign_open_or_initializer); break; diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp index 0704fbc8af5..8528d8e4339 100644 --- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp +++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp @@ -127,6 +127,7 @@ private Q_SLOTS: void functionDefaultArgument(); void attributeInAccessSpecifier(); void braceReturn(); + void staticVarDeclWithTypeDecl(); }; struct Line { @@ -2111,6 +2112,43 @@ void tst_CodeFormatter::braceReturn() checkIndent(data); } +void tst_CodeFormatter::staticVarDeclWithTypeDecl() +{ + QList data; + data << Line("static class: public Foo {") + << Line("public:") + << Line(" int bar();") + << Line("} mooze;") + << Line("") + << Line("static enum Col {") + << Line(" red,") + << Line(" yellow,") + << Line(" green") + << Line("} Loc;") + << Line("") + << Line("static enum {") + << Line(" red,") + << Line(" yellow,") + << Line(" green") + << Line("} Loc;") + << Line("") + << Line("enum class Col {") + << Line(" red,") + << Line(" yellow,") + << Line(" green") + << Line("};") + << Line("") + << Line("static enum class Col") + << Line("{") + << Line(" red,") + << Line(" yellow,") + << Line(" green") + << Line("} Loc;") + << Line("") + ; + checkIndent(data); +} + QTEST_MAIN(tst_CodeFormatter) #include "tst_codeformatter.moc" From 346e84d219448bb583dbc4ad71a2850db30e1cc8 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 5 Feb 2014 16:44:35 +0100 Subject: [PATCH 27/32] C++: introduce a project config file field in the projectPart. This field is used by the generic project manager which passes the ".config" file in it. The advantage is that both the SnapshotUpdater and the clang code model do not need to do anything smart, but can pass it directly to the preprocessor. Task-number: QTCREATORBUG-11390 Change-Id: I44fc7b20afd28fb59608412f2cce86af6f7e7d6b Reviewed-by: Nikolai Kosjar --- src/plugins/clangcodemodel/clangutils.cpp | 3 +++ .../cppeditor/cppcodemodelinspectordialog.cpp | 19 +++++++++++------- src/plugins/cpptools/cppmodelmanager.cpp | 7 ++++++- .../cpptools/cppmodelmanagerinterface.cpp | 20 +++++++++++++++++++ .../cpptools/cppmodelmanagerinterface.h | 4 ++++ src/plugins/cpptools/cppsnapshotupdater.cpp | 9 +++++++++ src/plugins/cpptools/cppsnapshotupdater.h | 1 + .../genericprojectmanager/genericproject.cpp | 16 +-------------- .../genericprojectmanager/genericproject.h | 2 -- .../genericprojectwizard.cpp | 7 ++++++- 10 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index f594486de33..dae5f1a835c 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -198,6 +198,9 @@ QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind result << QLatin1String("-fmacro-backtrace-limit=0"); result << QLatin1String("-fretain-comments-from-system-headers"); + if (!pPart->projectConfigFile.isEmpty()) + result << QLatin1String("-include") << pPart->projectConfigFile; + result << buildDefines(pPart->toolchainDefines, false); result << buildDefines(pPart->projectDefines, false); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 461ce25a8e4..c602bd25d0b 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -560,14 +560,16 @@ void CppCodeModelInspectorDumper::dumpProjectInfos( projectName = project->displayName(); projectFilePath = project->projectFilePath(); } + if (!part->projectConfigFile.isEmpty()) + m_out << i3 << "Project Config File: " << part->projectConfigFile << "\n"; m_out << i2 << "Project Part \"" << part->projectFile << "\"{{{3\n"; - m_out << i3 << "Project Part Name: " << part->displayName << "\n"; - m_out << i3 << "Project Name : " << projectName << "\n"; - m_out << i3 << "Project File : " << projectFilePath << "\n"; - m_out << i3 << "C Version : " << toString(part->cVersion) << "\n"; - m_out << i3 << "CXX Version : " << toString(part->cxxVersion) << "\n"; - m_out << i3 << "CXX Extensions : " << toString(part->cxxExtensions) << "\n"; - m_out << i3 << "Qt Version : " << toString(part->qtVersion) << "\n"; + m_out << i3 << "Project Part Name : " << part->displayName << "\n"; + m_out << i3 << "Project Name : " << projectName << "\n"; + m_out << i3 << "Project File : " << projectFilePath << "\n"; + m_out << i3 << "C Version : " << toString(part->cVersion) << "\n"; + m_out << i3 << "CXX Version : " << toString(part->cxxVersion) << "\n"; + m_out << i3 << "CXX Extensions : " << toString(part->cxxExtensions) << "\n"; + m_out << i3 << "Qt Version : " << toString(part->qtVersion) << "\n"; if (!part->files.isEmpty()) { m_out << i3 << "Files:{{{4\n"; @@ -2246,6 +2248,9 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr & << qMakePair(QString::fromLatin1("CXX Extensions"), toString(part->cxxExtensions)) << qMakePair(QString::fromLatin1("Qt Version"), toString(part->qtVersion)) ; + if (!part->projectConfigFile.isEmpty()) + table.prepend(qMakePair(QString::fromLatin1("Project Config File"), + part->projectConfigFile)); m_partGenericInfoModel->configure(table); resizeColumns(m_ui->partGeneralView); diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 5a0e96a3696..1363bef7b67 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -65,7 +65,7 @@ namespace CppTools { uint qHash(const ProjectPart &p) { uint h = qHash(p.toolchainDefines) ^ qHash(p.projectDefines) ^ p.cVersion ^ p.cxxVersion - ^ p.cxxExtensions ^ p.qtVersion; + ^ p.cxxExtensions ^ p.qtVersion ^ qHash(p.projectConfigFile); foreach (const QString &i, p.includePaths) h ^= qHash(i); @@ -83,6 +83,8 @@ bool operator==(const ProjectPart &p1, return false; if (p1.projectDefines != p2.projectDefines) return false; + if (p1.projectConfigFile != p2.projectConfigFile) + return false; if (p1.cVersion != p2.cVersion) return false; if (p1.cxxVersion != p2.cxxVersion) @@ -393,6 +395,8 @@ QByteArray CppModelManager::internalDefinedMacros() const foreach (const ProjectPart::Ptr &part, pinfo.projectParts()) { addUnique(part->toolchainDefines.split('\n'), ¯os, &alreadyIn); addUnique(part->projectDefines.split('\n'), ¯os, &alreadyIn); + if (!part->projectConfigFile.isEmpty()) + macros += readProjectConfigFile(part); } } return macros; @@ -434,6 +438,7 @@ void CppModelManager::dumpModelManagerConfiguration() qDebug() << "cxxVersion:" << cxxVersion; qDebug() << "cxxExtensions:" << cxxExtensions; qDebug() << "Qt version:" << part->qtVersion; + qDebug() << "project config file:" << part->projectConfigFile; qDebug() << "precompiled header:" << part->precompiledHeaders; qDebug() << "toolchain defines:" << part->toolchainDefines; qDebug() << "project defines:" << part->projectDefines; diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.cpp b/src/plugins/cpptools/cppmodelmanagerinterface.cpp index 0f65f162255..5b31d4a2a25 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.cpp +++ b/src/plugins/cpptools/cppmodelmanagerinterface.cpp @@ -223,4 +223,24 @@ void CppModelManagerInterface::ProjectInfo::appendProjectPart(const ProjectPart: m_defines.append('\n'); m_defines.append(part->toolchainDefines); m_defines.append(part->projectDefines); + if (!part->projectConfigFile.isEmpty()) { + m_defines.append('\n'); + m_defines += readProjectConfigFile(part); + m_defines.append('\n'); + } } + +QByteArray CppModelManagerInterface::readProjectConfigFile(const ProjectPart::Ptr &part) +{ + QByteArray result; + + QFile f(part->projectConfigFile); + if (f.open(QIODevice::ReadOnly)) { + QTextStream is(&f); + result = is.readAll().toUtf8(); + f.close(); + } + + return result; +} + diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index 188367c68ad..5bd7be3cc27 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -106,6 +106,7 @@ public: QString projectFile; ProjectExplorer::Project *project; QList files; + QString projectConfigFile; // currently only used by the Generic Project Manager QByteArray projectDefines; QByteArray toolchainDefines; QStringList includePaths; @@ -290,6 +291,9 @@ public slots: virtual void updateModifiedSourceFiles() = 0; virtual void GC() = 0; + +protected: + static QByteArray readProjectConfigFile(const ProjectPart::Ptr &part); }; } // namespace CppTools diff --git a/src/plugins/cpptools/cppsnapshotupdater.cpp b/src/plugins/cpptools/cppsnapshotupdater.cpp index 85a282ae34e..4d4de1021c7 100644 --- a/src/plugins/cpptools/cppsnapshotupdater.cpp +++ b/src/plugins/cpptools/cppsnapshotupdater.cpp @@ -60,6 +60,7 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy) QStringList includePaths; QStringList frameworkPaths; QStringList precompiledHeaders; + QString projectConfigFile; updateProjectPart(); @@ -73,6 +74,7 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy) configFile += m_projectPart->projectDefines; includePaths = m_projectPart->includePaths; frameworkPaths = m_projectPart->frameworkPaths; + projectConfigFile = m_projectPart->projectConfigFile; if (m_usePrecompiledHeaders) precompiledHeaders = m_projectPart->precompiledHeaders; } @@ -99,6 +101,11 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy) invalidateSnapshot = true; } + if (projectConfigFile != m_projectConfigFile) { + m_projectConfigFile = projectConfigFile; + invalidateSnapshot = true; + } + if (precompiledHeaders != m_precompiledHeaders) { m_precompiledHeaders = precompiledHeaders; invalidateSnapshot = true; @@ -160,6 +167,8 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy) preproc.setIncludePaths(m_includePaths); preproc.setFrameworkPaths(m_frameworkPaths); preproc.run(configurationFileName); + if (!m_projectConfigFile.isEmpty()) + preproc.run(m_projectConfigFile); if (m_usePrecompiledHeaders) { foreach (const QString &precompiledHeader, m_precompiledHeaders) preproc.run(precompiledHeader); diff --git a/src/plugins/cpptools/cppsnapshotupdater.h b/src/plugins/cpptools/cppsnapshotupdater.h index c5d14189465..92741cf006d 100644 --- a/src/plugins/cpptools/cppsnapshotupdater.h +++ b/src/plugins/cpptools/cppsnapshotupdater.h @@ -78,6 +78,7 @@ private: QByteArray m_editorDefines; QStringList m_includePaths; QStringList m_frameworkPaths; + QString m_projectConfigFile; QStringList m_precompiledHeaders; CPlusPlus::Snapshot m_snapshot; CPlusPlus::DependencyTable m_deps; diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 68d77143513..a8d4bdadab3 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -218,15 +218,6 @@ void GenericProject::parseProject(RefreshOptions options) // TODO: Possibly load some configuration from the project file //QSettings projectInfo(m_fileName, QSettings::IniFormat); - - m_defines.clear(); - - QFile configFile(configFileName()); - if (configFile.open(QFile::ReadOnly)) { - // convert from local/file encoding to UTF-8 - QTextStream configStream(&configFile); - m_defines = configStream.readAll().toUtf8(); - } } if (options & Files) @@ -265,7 +256,7 @@ void GenericProject::refresh(RefreshOptions options) } part->cxxVersion = CppTools::ProjectPart::CXX11; // assume C++11 - part->projectDefines += m_defines; + part->projectConfigFile = configFileName(); // ### add _defines. @@ -348,11 +339,6 @@ QStringList GenericProject::files() const return m_files; } -QByteArray GenericProject::defines() const -{ - return m_defines; -} - QString GenericProject::displayName() const { return m_projectName; diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h index 18ca8798c67..30a657ff253 100644 --- a/src/plugins/genericprojectmanager/genericproject.h +++ b/src/plugins/genericprojectmanager/genericproject.h @@ -81,7 +81,6 @@ public: void refresh(RefreshOptions options); - QByteArray defines() const; QStringList projectIncludePaths() const; QStringList files() const; @@ -108,7 +107,6 @@ private: QStringList m_files; QHash m_rawListEntries; QStringList m_projectIncludePaths; - QByteArray m_defines; GenericProjectNode *m_rootNode; QFuture m_codeModelFuture; diff --git a/src/plugins/genericprojectmanager/genericprojectwizard.cpp b/src/plugins/genericprojectmanager/genericprojectwizard.cpp index a7d700efc8b..f8059adb2c2 100644 --- a/src/plugins/genericprojectmanager/genericprojectwizard.cpp +++ b/src/plugins/genericprojectmanager/genericprojectwizard.cpp @@ -48,6 +48,11 @@ namespace GenericProjectManager { namespace Internal { +static const char *const ConfigFileTemplate = + "// Add predefined macros for your project here. For example:\n" + "// #define THE_ANSWER 42\n" + ; + ////////////////////////////////////////////////////////////////////////////// // // GenericProjectWizardDialog @@ -189,7 +194,7 @@ Core::GeneratedFiles GenericProjectWizard::generateFiles(const QWizard *w, generatedIncludesFile.setContents(includePaths.join(QLatin1String("\n"))); Core::GeneratedFile generatedConfigFile(configFileName); - generatedConfigFile.setContents(QLatin1String("// ADD PREDEFINED MACROS HERE!\n")); + generatedConfigFile.setContents(QLatin1String(ConfigFileTemplate)); Core::GeneratedFiles files; files.append(generatedFilesFile); From e94526100c97787948db6f68d3167553aa57351d Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 27 Feb 2014 13:45:39 +0100 Subject: [PATCH 28/32] Core: Delay coreOpened signal emission This prevents some window restoring flickering. Change-Id: Iead0e0f2129b969e1de7e22dbf15e641740e40e1 Reviewed-by: Orgad Shaneh Reviewed-by: Eike Ziller --- src/plugins/coreplugin/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 55b9db99b02..dbc0ee8bcc2 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -351,9 +351,9 @@ void MainWindow::extensionsInitialized() emit m_coreImpl->coreAboutToOpen(); show(); - emit m_coreImpl->coreOpened(); // Delay restoreWindowState, since it is overridden by LayoutRequest event QTimer::singleShot(0, this, SLOT(restoreWindowState())); + QTimer::singleShot(0, m_coreImpl, SIGNAL(coreOpened())); } void MainWindow::closeEvent(QCloseEvent *event) From 8ff63de72802af6111530fab834421b492c97137 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 27 Feb 2014 12:57:35 +0100 Subject: [PATCH 29/32] gitignore: ignore .qmake.stash files Change-Id: I6ebea0f6ce680ee95190be68ec2ae96ec04958ad Reviewed-by: Eike Ziller --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 97887bbbb43..48c74fa1610 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ Thumbs.db *.rc *.embed.manifest /.qmake.cache +/.qmake.stash # qtcreator generated files *.pro.user* From 5d2cd2e56d507623a2970e91afacd2c26f458714 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 6 Feb 2014 23:18:18 +0200 Subject: [PATCH 30/32] C++: Fix handling of #undef * If the macro is defined before, track its reference * Synchronize environment line before calling remove, which currently sets incorrect line * Set macro offset Task-number: QTCREATORBUG-10454 Change-Id: I480d16423a976a025bb8c71046610a46f9d7b0fd Reviewed-by: Nikolai Kosjar --- src/libs/cplusplus/pp-engine.cpp | 13 +++++- .../preprocessor/tst_preprocessor.cpp | 41 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index 21440bc86c1..41439ad7904 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -1951,10 +1951,19 @@ void Preprocessor::handleUndefDirective(PPToken *tk) lex(tk); // consume "undef" token if (tk->is(T_IDENTIFIER)) { const ByteArrayRef macroName = tk->asByteArrayRef(); - const Macro *macro = m_env->remove(macroName); + const unsigned offset = tk->offset + m_state.m_offsetRef; + // Track macro use if previously defined + if (m_client) { + if (const Macro *existingMacro = m_env->resolve(macroName)) + m_client->notifyMacroReference(offset, tk->lineno, *existingMacro); + } + synchronizeOutputLines(*tk); + Macro *macro = m_env->remove(macroName); - if (m_client && macro) + if (m_client && macro) { + macro->setOffset(offset); m_client->macroAdded(*macro); + } lex(tk); // consume macro name #ifndef NO_DEBUG } else { diff --git a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp index be153ab0abb..808bd75a007 100644 --- a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp +++ b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp @@ -374,6 +374,7 @@ private slots: void include_guard_data(); void empty_trailing_lines(); void empty_trailing_lines_data(); + void undef(); }; // Remove all #... lines, and 'simplify' string, to allow easily comparing the result @@ -1739,6 +1740,46 @@ void tst_Preprocessor::empty_trailing_lines_data() ); } +void tst_Preprocessor::undef() +{ + Environment env; + QByteArray output; + MockClient client(&env, &output); + Preprocessor preprocess(&client, &env); + QByteArray input = + "#define FOO\n" + "#define FOO2\n" + "#undef FOO\n" + "#undef BAR\n"; + preprocess.run(QLatin1String(""), input); + QCOMPARE(env.macroCount(), 4U); + Macro *macro = env.macroAt(0); + QCOMPARE(macro->name(), QByteArray("FOO")); + QCOMPARE(macro->offset(), 8U); + QCOMPARE(macro->line(), 1U); + QVERIFY(!macro->isHidden()); + macro = env.macroAt(1); + QCOMPARE(macro->name(), QByteArray("FOO2")); + QCOMPARE(macro->offset(), 20U); + QCOMPARE(macro->line(), 2U); + QVERIFY(!macro->isHidden()); + macro = env.macroAt(2); + QCOMPARE(macro->name(), QByteArray("FOO")); + QCOMPARE(macro->offset(), 32U); + QCOMPARE(macro->line(), 3U); + QVERIFY(macro->isHidden()); + macro = env.macroAt(3); + QCOMPARE(macro->name(), QByteArray("BAR")); + QCOMPARE(macro->offset(), 43U); + QCOMPARE(macro->line(), 4U); + QVERIFY(macro->isHidden()); + QList macros = client.definedMacros(); + QVERIFY(macros.contains("FOO")); + QVERIFY(macros.contains("FOO2")); + QCOMPARE(client.macroUsesLine()["FOO"], (QList() << 3U)); + QVERIFY(client.macroUsesLine()["BAR"].isEmpty()); +} + void tst_Preprocessor::compare_input_output(bool keepComments) { QFETCH(QByteArray, input); From 0ba55199b26b165836bdb4500c74b8b5b641e4b0 Mon Sep 17 00:00:00 2001 From: jkobus Date: Thu, 27 Feb 2014 16:16:11 +0100 Subject: [PATCH 31/32] Prepare for patch generation, fix internals. Change-Id: Ib3b7c5c433f9f9230eb14d23a3029681841e2e68 Reviewed-by: Jarek Kobus --- src/plugins/diffeditor/diffeditorplugin.cpp | 4 +- src/plugins/diffeditor/diffeditorplugin.h | 2 +- .../diffeditor/sidebysidediffeditorwidget.cpp | 204 +++++++++++------- .../diffeditor/sidebysidediffeditorwidget.h | 2 +- 4 files changed, 129 insertions(+), 83 deletions(-) diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 1d3aed67ae1..afe74fbd98f 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -138,9 +138,9 @@ QString DiffEditorPlugin::getFileContents(const QString &fileName) const #include "sidebysidediffeditorwidget.h" -void DiffEditor::Internal::DiffEditorPlugin::testAssemblyRows() +void DiffEditor::Internal::DiffEditorPlugin::testFixPositions() { - SideBySideDiffEditorWidget::testAssemblyRows(); + SideBySideDiffEditorWidget::testFixPositions(); } #endif // WITH_TESTS diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index e40a10014d3..703c97496fd 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -54,7 +54,7 @@ private slots: void diff(); #ifdef WITH_TESTS - void testAssemblyRows(); + void testFixPositions(); #endif // WITH_TESTS private: diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 11c0bd3e8c8..e64fb83c59d 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -97,6 +97,7 @@ public: ChunkData() : contextChunk(false) {} QList rows; bool contextChunk; + // start position, end position, TextLineData::Separator lines not taken into account QMap changedLeftPositions; // counting from the beginning of the chunk QMap changedRightPositions; // counting from the beginning of the chunk }; @@ -113,49 +114,16 @@ public: ////////////////////// static QList assemblyRows(const QStringList &lines, - const QMap &lineSpans, - const QMap &changedPositions, - QMap *outputChangedPositions) + const QMap &lineSpans) { QList data; - int previousSpanOffset = 0; - int spanOffset = 0; - int pos = 0; - bool usePreviousSpanOffsetForStartPosition = false; - QMap::ConstIterator changedIt = changedPositions.constBegin(); - QMap::ConstIterator changedEnd = changedPositions.constEnd(); const int lineCount = lines.count(); for (int i = 0; i <= lineCount; i++) { - for (int j = 0; j < lineSpans.value(i); j++) { + for (int j = 0; j < lineSpans.value(i); j++) data.append(TextLineData(TextLineData::Separator)); - spanOffset++; - } - if (i < lineCount) { - const int textLength = lines.at(i).count() + 1; - pos += textLength; + if (i < lineCount) data.append(lines.at(i)); - } - while (changedIt != changedEnd) { - if (changedIt.key() >= pos) - break; - - if (changedIt.value() >= pos) { - usePreviousSpanOffsetForStartPosition = true; - previousSpanOffset = spanOffset; - break; - } - - const int startSpanOffset = usePreviousSpanOffsetForStartPosition - ? previousSpanOffset : spanOffset; - usePreviousSpanOffsetForStartPosition = false; - - const int startPos = changedIt.key() + startSpanOffset; - const int endPos = changedIt.value() + spanOffset; - if (outputChangedPositions) - outputChangedPositions->insert(startPos, endPos); - ++changedIt; - } } return data; } @@ -221,9 +189,6 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, QStringList leftLines; QStringList rightLines; - // - QMap leftChangedPositions; - QMap rightChangedPositions; // QMap leftSpans; QMap rightSpans; @@ -248,13 +213,13 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, if (leftDiff.command == Diff::Delete) { // process delete - handleDifference(leftDiff.text, &leftLines, &leftChangedPositions, &leftLineNumber, &leftCharNumber); + handleDifference(leftDiff.text, &leftLines, &chunkData.changedLeftPositions, &leftLineNumber, &leftCharNumber); lastLineEqual = lastLinesEqual(leftLines, rightLines); i++; } if (rightDiff.command == Diff::Insert) { // process insert - handleDifference(rightDiff.text, &rightLines, &rightChangedPositions, &rightLineNumber, &rightCharNumber); + handleDifference(rightDiff.text, &rightLines, &chunkData.changedRightPositions, &rightLineNumber, &rightCharNumber); lastLineEqual = lastLinesEqual(leftLines, rightLines); j++; } @@ -326,13 +291,9 @@ static ChunkData calculateOriginalData(const QList &leftDiffList, } QList leftData = assemblyRows(leftLines, - leftSpans, - leftChangedPositions, - &chunkData.changedLeftPositions); + leftSpans); QList rightData = assemblyRows(rightLines, - rightSpans, - rightChangedPositions, - &chunkData.changedRightPositions); + rightSpans); // fill ending separators for (int i = leftData.count(); i < rightData.count(); i++) @@ -1230,6 +1191,8 @@ FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &origi int rightCharCounter = 0; QMap::ConstIterator leftChangedIt = originalData.changedLeftPositions.constBegin(); QMap::ConstIterator rightChangedIt = originalData.changedRightPositions.constBegin(); + const QMap::ConstIterator leftChangedItEnd = originalData.changedLeftPositions.constEnd(); + const QMap::ConstIterator rightChangedItEnd = originalData.changedRightPositions.constEnd(); while (i < originalData.rows.count()) { if (!hiddenRows.contains(i)) { ChunkData chunkData; @@ -1242,11 +1205,13 @@ FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &origi RowData rowData = originalData.rows.at(i); chunkData.rows.append(rowData); - leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n' - rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n' + if (rowData.leftLine.textLineType == TextLineData::TextLine) + leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n' + if (rowData.rightLine.textLineType == TextLineData::TextLine) + rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n' i++; } - while (leftChangedIt != originalData.changedLeftPositions.constEnd()) { + while (leftChangedIt != leftChangedItEnd) { if (leftChangedIt.key() < leftOffset || leftChangedIt.key() > leftCharCounter) break; @@ -1256,7 +1221,7 @@ FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &origi chunkData.changedLeftPositions.insert(startPos - leftOffset, endPos - leftOffset); leftChangedIt++; } - while (rightChangedIt != originalData.changedRightPositions.constEnd()) { + while (rightChangedIt != rightChangedItEnd) { if (rightChangedIt.key() < rightOffset || rightChangedIt.key() > rightCharCounter) break; @@ -1276,8 +1241,10 @@ FileData SideBySideDiffEditorWidget::calculateContextData(const ChunkData &origi RowData rowData = originalData.rows.at(i); chunkData.rows.append(rowData); - leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n' - rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n' + if (rowData.leftLine.textLineType == TextLineData::TextLine) + leftCharCounter += rowData.leftLine.text.count() + 1; // +1 for '\n' + if (rowData.rightLine.textLineType == TextLineData::TextLine) + rightCharCounter += rowData.rightLine.text.count() + 1; // +1 for '\n' i++; } fileData.chunks.append(chunkData); @@ -1446,6 +1413,86 @@ QList SideBySideDiffEditorWidget::colorPositions( return lineSelections; } +void fixPositions(QMap::ConstIterator *it, + const QMap::ConstIterator &itEnd, + int fileOffset, + int charCounter, + int spanCounter, + int *lastSpanCounter, + QMap *changedPositions) +{ + while (*it != itEnd) { + if (it->key() >= charCounter) + break; + + if (it->value() >= charCounter) { + if (*lastSpanCounter != -1) + break; + + *lastSpanCounter = spanCounter; + break; + } + + const int startSpanOffset = *lastSpanCounter != -1 + ? *lastSpanCounter : spanCounter; + *lastSpanCounter = -1; + + const int startPos = it->key() + startSpanOffset + fileOffset; + const int endPos = it->value() + spanCounter + fileOffset; + changedPositions->insert(startPos, endPos); + ++(*it); + } +} + +static void fixPositions(const ChunkData &chunkData, + const int leftFileOffset, + const int rightFileOffset, + QMap *leftCharPos, + QMap *rightCharPos) +{ + QMap::ConstIterator leftIt = chunkData.changedLeftPositions.constBegin(); + const QMap::ConstIterator leftItEnd = chunkData.changedLeftPositions.constEnd(); + QMap::ConstIterator rightIt = chunkData.changedRightPositions.constBegin(); + const QMap::ConstIterator rightItEnd = chunkData.changedRightPositions.constEnd(); + if (leftIt == leftItEnd && rightIt == rightItEnd) + return; + + int leftCharCounter = 0; + int rightCharCounter = 0; + int leftSpanCounter = 0; + int rightSpanCounter = 0; + int leftLastSpanCounter = -1; + int rightLastSpanCounter = -1; + for (int i = 0; i < chunkData.rows.count(); i++) { + const RowData &row = chunkData.rows.at(i); + + if (row.leftLine.textLineType == TextLineData::TextLine) + leftCharCounter += row.leftLine.text.count() + 1; // +1 for '\n' + else + ++leftSpanCounter; + + if (row.rightLine.textLineType == TextLineData::TextLine) + rightCharCounter += row.rightLine.text.count() + 1; // +1 for '\n' + else + ++rightSpanCounter; + + fixPositions(&leftIt, + leftItEnd, + leftFileOffset, + leftCharCounter, + leftSpanCounter, + &leftLastSpanCounter, + leftCharPos); + fixPositions(&rightIt, + rightItEnd, + rightFileOffset, + rightCharCounter, + rightSpanCounter, + &rightLastSpanCounter, + rightCharPos); + } +} + void SideBySideDiffEditorWidget::colorDiff(const QList &fileDataList) { QPalette pal = m_leftEditor->extraArea()->palette(); @@ -1494,19 +1541,7 @@ void SideBySideDiffEditorWidget::colorDiff(const QList &fileDataList) leftLastSkippedBlockStartPos = leftPos; rightLastSkippedBlockStartPos = rightPos; - QMapIterator itLeft(chunkData.changedLeftPositions); - while (itLeft.hasNext()) { - itLeft.next(); - - leftCharPos[itLeft.key() + leftFileOffset] = itLeft.value() + leftFileOffset; - } - - QMapIterator itRight(chunkData.changedRightPositions); - while (itRight.hasNext()) { - itRight.next(); - - rightCharPos[itRight.key() + rightFileOffset] = itRight.value() + rightFileOffset; - } + fixPositions(chunkData, leftFileOffset, rightFileOffset, &leftCharPos, &rightCharPos); for (int k = 0; k < chunkData.rows.count(); k++) { RowData rowData = chunkData.rows.at(k); @@ -1840,25 +1875,36 @@ void SideBySideDiffEditorWidget::synchronizeFoldings(SideDiffEditorWidget *sourc #ifdef WITH_TESTS #include -void DiffEditor::SideBySideDiffEditorWidget::testAssemblyRows() +void DiffEditor::SideBySideDiffEditorWidget::testFixPositions() { - QStringList lines; - lines << QLatin1String("abcd efgh"); // line 0 - lines << QLatin1String("ijkl mnop"); // line 1 + ChunkData chunkData; + chunkData.rows.append(RowData(TextLineData(QLatin1String("abcd efgh")), TextLineData(QLatin1String("abcd ")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(TextLineData::Separator), TextLineData(QLatin1String("")))); + chunkData.rows.append(RowData(TextLineData(QLatin1String("ijkl mnop")), TextLineData(QLatin1String(" mnop")))); - QMap lineSpans; - lineSpans[1] = 6; // before line 1 insert 6 span lines + chunkData.changedLeftPositions.insert(5, 14); // changed text from position 5 to position 14, occupy 9 characters: "efgh\nijkl" - QMap changedPositions; - changedPositions[5] = 14; // changed text from position 5 to position 14, occupy 9 characters: "efgh\nijkl" + QMap expectedLeftChangedPositions; + expectedLeftChangedPositions[5] = 20; // "efgh\n[\n\n\n\n\n\n]ijkl" - [\n] means inserted span - QMap expectedChangedPositions; - expectedChangedPositions[5] = 20; // "efgh\n[\n\n\n\n\n\n]ijkl" - [\n] means inserted span + QMap outputLeftChangedPositions; + QMap outputRightChangedPositions; - QMap outputChangedPositions; + fixPositions(chunkData, 0, 0, &outputLeftChangedPositions, &outputRightChangedPositions); + QVERIFY(outputLeftChangedPositions == expectedLeftChangedPositions); - assemblyRows(lines, lineSpans, changedPositions, &outputChangedPositions); - QVERIFY(outputChangedPositions == expectedChangedPositions); + QMap expectedLeftMovedPositions; + expectedLeftMovedPositions[15] = 30; // moved by 10 + outputLeftChangedPositions.clear(); + outputRightChangedPositions.clear(); + + fixPositions(chunkData, 10, 0, &outputLeftChangedPositions, &outputRightChangedPositions); + QVERIFY(outputLeftChangedPositions == expectedLeftMovedPositions); } #endif // WITH_TESTS diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index 5686fbf0a7d..cf7cbbd8849 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -63,7 +63,7 @@ public: DiffEditorGuiController *diffEditorGuiController() const; #ifdef WITH_TESTS - static void testAssemblyRows(); + static void testFixPositions(); #endif // WITH_TESTS private slots: From e4c2f569a8bb5dddec42f08023caf7614d55578b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Feb 2014 17:10:24 +0100 Subject: [PATCH 32/32] Fix crash when restoring settings in registerShortcut Introduced by c5cc4b1f131cbfc84622a93716ed421dd57f4da5 Change-Id: Id546a4cf87cfb3709f11ee32439662fcda00bdd4 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/actionmanager/actionmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 93f31496029..271b883f032 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -283,7 +283,6 @@ Command *ActionManager::registerShortcut(QShortcut *shortcut, Id id, const Conte } else { sc = new Shortcut(id); d->m_idCmdMap.insert(id, sc); - d->readUserSettings(id, sc); } if (sc->shortcut()) { @@ -299,6 +298,7 @@ Command *ActionManager::registerShortcut(QShortcut *shortcut, Id id, const Conte sc->setShortcut(shortcut); sc->setScriptable(scriptable); sc->setContext(context); + d->readUserSettings(id, sc); emit m_instance->commandListChanged(); emit m_instance->commandAdded(id.toString());