diff options
Diffstat (limited to 'src')
37 files changed, 1146 insertions, 1284 deletions
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index 10c7f3f883..b8810d5922 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -638,6 +638,12 @@ std::string LocalsSymbolGroup::module() const const char *WatchesSymbolGroup::watchInamePrefix = "watch"; +bool WatchesSymbolGroup::isWatchIname(const std::string &iname) +{ + static const size_t prefLen = std::strlen(WatchesSymbolGroup::watchInamePrefix); + return !iname.compare(0, prefLen, WatchesSymbolGroup::watchInamePrefix); +} + WatchesSymbolGroup::WatchesSymbolGroup(CIDebugSymbolGroup *sg) : SymbolGroup(sg, SymbolParameterVector(), std::string(), WatchesSymbolGroup::watchInamePrefix) { @@ -776,9 +782,8 @@ std::string WatchesSymbolGroup::fixWatchExpression(CIDebugSymbols *s, const std: bool WatchesSymbolGroup::addWatch(CIDebugSymbols *s, std::string iname, const std::string &expression, std::string *errorMessage) { // "watch.0" -> "0" - const size_t prefLen = std::strlen(WatchesSymbolGroup::watchInamePrefix); - if (!iname.compare(0, prefLen, WatchesSymbolGroup::watchInamePrefix)) - iname.erase(0, prefLen + 1); + if (isWatchIname(iname)) + iname.erase(0, std::strlen(WatchesSymbolGroup::watchInamePrefix) + 1); // Already in? if (root()->childByIName(iname.c_str())) return true; diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h index 13a4dc7d0a..d479b9899e 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.h +++ b/src/libs/qtcreatorcdbext/symbolgroup.h @@ -157,6 +157,7 @@ public: typedef std::map<std::string, std::string> InameExpressionMap; static const char *watchInamePrefix; + static bool isWatchIname(const std::string &iname); // Add a symbol as 'watch.0' or '0' with expression bool addWatch(CIDebugSymbols *s, std::string iname, const std::string &expression, std::string *errorMessage); diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index e72fe878f7..f036c54c0c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -196,8 +196,10 @@ void AbstractSymbolGroupNode::dumpBasicData(std::ostream &str, const std::string str << "iname=\"" << aFullIname << "\",name=\"" << aName << '"'; if (!type.empty()) str << ",type=\"" << type << '"'; - if (!expression.empty()) - str << ",exp=\"" << expression << '"'; + if (WatchesSymbolGroup::isWatchIname(aFullIname)) + str << ",exp=\"" << aName << '"'; + else if (!expression.empty()) + str << ",exp=\"" << expression << '"'; } void AbstractSymbolGroupNode::setParent(AbstractSymbolGroupNode *n) diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index c56bd6b67a..8de0c2bb0b 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -2148,34 +2148,94 @@ static bool dumpQTime(const SymbolGroupValue &v, std::wostream &str) return false; } +static bool dumpQTimeZone(const SymbolGroupValue &v, std::wostream &str) +{ + return dumpQByteArrayFromQPrivateClass(v, QPDM_qSharedDataPadded, SymbolGroupValue::pointerSize(), str); +} + +// Convenience to dump a QTimeZone from the unexported private class of a Qt class. +static bool dumpQTimeZoneFromQPrivateClass(const SymbolGroupValue &v, + QPrivateDumpMode mode, + unsigned additionalOffset, + std::wostream &str) +{ + std::string errorMessage; + const ULONG64 timeZoneAddress = addressOfQPrivateMember(v, mode, additionalOffset); + if (!timeZoneAddress) + return false; + std::string dumpType = QtInfo::get(v.context()).prependQtCoreModule("QTimeZone"); + std::string symbolName = SymbolGroupValue::pointedToSymbolName(timeZoneAddress , dumpType); + if (SymbolGroupValue::verbose > 1) + DebugPrint() << "dumpQTimeZoneFromQPrivateClass of " << v.name() << '/' + << v.type() << " mode=" << mode + << " offset=" << additionalOffset << " address=0x" << std::hex << timeZoneAddress + << std::dec << " expr=" << symbolName; + SymbolGroupNode *timeZoneNode = + v.node()->symbolGroup()->addSymbol(v.module(), symbolName, std::string(), &errorMessage); + if (!timeZoneNode && errorMessage.find("DEBUG_ANY_ID") != std::string::npos) { + // HACK: + // In some rare cases the AddSymbol can't create a node with a given module name, + // but is able to add the symbol without any modulename. + dumpType = QtInfo::get(v.context()).prependModuleAndNameSpace("QTimeZone", "", QtInfo::get(v.context()).nameSpace); + symbolName = SymbolGroupValue::pointedToSymbolName(timeZoneAddress , dumpType); + timeZoneNode = v.node()->symbolGroup()->addSymbol(v.module(), symbolName, std::string(), &errorMessage); + if (!timeZoneNode) + return false; + } + return dumpQTimeZone(SymbolGroupValue(timeZoneNode, v.context()), str); +} + // QDateTime has an unexported private class. Obtain date and time // from memory. static bool dumpQDateTime(const SymbolGroupValue &v, std::wostream &str) { // QDate is 64bit starting from Qt 5 which is always aligned 64bit. if (QtInfo::get(v.context()).version == 5) { - int additionalOffset = 8 /*int64*/ + SymbolGroupValue::sizeOf("Qt::TimeSpec") - + SymbolGroupValue::intSize() + SymbolGroupValue::sizeOf("QTimeZone"); - const ULONG64 statusAddr = addressOfQPrivateMember(v, QPDM_qSharedDataPadded, - additionalOffset); - if (!statusAddr) + // the dumper on the creator side expects msecs/spec/offset/tz/status + const char separator = '/'; + const ULONG64 msecsAddr = addressOfQPrivateMember(v, QPDM_None, 0); + if (!msecsAddr) return false; + int addrOffset = 8 /*QSharedData + padded*/; + const LONG64 msecs = SymbolGroupValue::readSignedValue( + v.context().dataspaces, msecsAddr + addrOffset, 8, 0); + + addrOffset += 8 /*int64*/; + const int spec = SymbolGroupValue::readIntValue( + v.context().dataspaces, msecsAddr + addrOffset); + + addrOffset += SymbolGroupValue::sizeOf("Qt::TimeSpec"); + const int offset = SymbolGroupValue::readIntValue( + v.context().dataspaces, msecsAddr + addrOffset); + + addrOffset += SymbolGroupValue::intSize(); + std::wostringstream timeZoneStream; + dumpQTimeZoneFromQPrivateClass(v, QPDM_None, addrOffset, timeZoneStream); + const std::wstring &timeZoneString = timeZoneStream.str(); + + addrOffset += SymbolGroupValue::sizeOf("QTimeZone"); + const int status = SymbolGroupValue::readIntValue( + v.context().dataspaces, msecsAddr + addrOffset); + enum StatusFlag { ValidDate = 0x04, ValidTime = 0x08, ValidDateTime = 0x10 }; - const int status = SymbolGroupValue::readIntValue(v.context().dataspaces, statusAddr); if (!(status & ValidDateTime || ((status & ValidDate) && (status & ValidTime)))) return true; - const ULONG64 msecsAddr = addressOfQPrivateMember(v, QPDM_qSharedDataPadded, 0); - if (!msecsAddr) - return false; - const LONG64 msecs = SymbolGroupValue::readSignedValue( - v.context().dataspaces, msecsAddr, 8, 0); - if (msecs) - str << msecs; + + str << msecs << separator + << spec << separator + << offset << separator + << std::hex; + if (timeZoneString.length() > 2) { + for (int i = 1; i < timeZoneString.length() - 1; ++i) // remove '"' + str << (int)timeZoneString.at(i); + } + str << std::dec << separator << status; + return true; } @@ -2197,11 +2257,6 @@ static bool dumpQDateTime(const SymbolGroupValue &v, std::wostream &str) return true; } -static bool dumpQTimeZone(const SymbolGroupValue &v, std::wostream &str) -{ - return dumpQByteArrayFromQPrivateClass(v, QPDM_qSharedDataPadded, SymbolGroupValue::pointerSize(), str); -} - static bool dumpQPixmap(const SymbolGroupValue &v, std::wostream &str) { const SymbolGroupValue pixmapSharedData = v["data"]["d"]; diff --git a/src/plugins/bazaar/commiteditor.cpp b/src/plugins/bazaar/commiteditor.cpp index 332f753949..c2372d06f1 100644 --- a/src/plugins/bazaar/commiteditor.cpp +++ b/src/plugins/bazaar/commiteditor.cpp @@ -61,8 +61,9 @@ void CommitEditor::setFields(const QString &repositoryRoot, bazaarWidget->setFields(branch, userName, email); m_fileModel = new VcsBase::SubmitFileModel(this); + m_fileModel->setRepositoryRoot(repositoryRoot); foreach (const VcsBase::VcsBaseClient::StatusItem &item, repoStatus) if (item.flags != QLatin1String("Unknown")) m_fileModel->addFile(item.file, item.flags); - setFileModel(m_fileModel, repositoryRoot); + setFileModel(m_fileModel); } diff --git a/src/plugins/clearcase/clearcasesubmiteditor.cpp b/src/plugins/clearcase/clearcasesubmiteditor.cpp index 2f36dabcaf..f4936c4cb9 100644 --- a/src/plugins/clearcase/clearcasesubmiteditor.cpp +++ b/src/plugins/clearcase/clearcasesubmiteditor.cpp @@ -58,11 +58,12 @@ void ClearCaseSubmitEditor::setStatusList(const QStringList &statusOutput) { typedef QStringList::const_iterator ConstIterator; auto model = new VcsBase::SubmitFileModel(this); + model->setRepositoryRoot(checkScriptWorkingDirectory()); const ConstIterator cend = statusOutput.constEnd(); for (ConstIterator it = statusOutput.constBegin(); it != cend; ++it) model->addFile(*it, QLatin1String("C")); - setFileModel(model, checkScriptWorkingDirectory()); + setFileModel(model); if (statusOutput.count() > 1) submitEditorWidget()->addKeep(); } diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index 8e2a073949..498945f8da 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -62,8 +62,7 @@ static const char settingsGroupC[] = "DiffEditor"; static const char descriptionVisibleKeyC[] = "DescriptionVisible"; -static const char horizontalScrollBarSynchronizationKeyC[] = - "HorizontalScrollBarSynchronization"; +static const char horizontalScrollBarSynchronizationKeyC[] = "HorizontalScrollBarSynchronization"; static const char contextLineCountKeyC[] = "ContextLineNumbers"; static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace"; @@ -74,6 +73,19 @@ static const char useDiffEditorKeyC[] = "UseDiffEditor"; using namespace TextEditor; +namespace { + +class Guard +{ +public: + Guard(int *state) : m_state(state) { ++(*state); } + ~Guard() { --(*m_state); QTC_ASSERT(*m_state >= 0, return); } +private: + int *m_state; +}; + +} // namespace + namespace DiffEditor { namespace Internal { @@ -210,19 +222,19 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc) , m_stackedWidget(0) , m_toolBar(0) , m_entriesComboBox(0) + , m_contextSpinBox(0) , m_toggleSyncAction(0) , m_whitespaceButtonAction(0) - , m_contextLabelAction(0) - , m_contextSpinBoxAction(0) , m_toggleDescriptionAction(0) , m_reloadAction(0) - , m_diffEditorSwitcher(0) + , m_viewSwitcherAction(0) , m_currentViewIndex(-1) , m_currentDiffFileIndex(-1) + , m_ignoreChanges(0) , m_sync(false) , m_showDescription(true) - , m_ignoreChanges(true) { + Guard guard(&m_ignoreChanges); QTC_ASSERT(m_document, return); setDuplicateSupported(true); @@ -254,9 +266,7 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc) toolBar(); loadSettings(); - updateDescription(); - - m_ignoreChanges = false; + documentHasChanged(); } DiffEditor::~DiffEditor() @@ -314,58 +324,46 @@ QWidget *DiffEditor::toolBar() this, &DiffEditor::setCurrentDiffFileIndex); m_toolBar->addWidget(m_entriesComboBox); - m_whitespaceButton = new QToolButton(m_toolBar); - m_whitespaceButton->setText(tr("Ignore Whitespace")); - m_whitespaceButton->setCheckable(true); - m_whitespaceButton->setChecked(m_document->ignoreWhitespace()); - m_whitespaceButtonAction = m_toolBar->addWidget(m_whitespaceButton); + m_contextLabel = new QLabel(m_toolBar); - QLabel *contextLabel = new QLabel(m_toolBar); - contextLabel->setText(tr("Context Lines:")); - contextLabel->setContentsMargins(6, 0, 6, 0); - m_contextLabelAction = m_toolBar->addWidget(contextLabel); + m_contextLabel->setText(tr("Context Lines:")); + m_contextLabel->setContentsMargins(6, 0, 6, 0); + m_toolBar->addWidget(m_contextLabel); m_contextSpinBox = new QSpinBox(m_toolBar); m_contextSpinBox->setRange(1, 100); m_contextSpinBox->setValue(m_document->contextLineCount()); m_contextSpinBox->setFrame(false); - m_contextSpinBox->setSizePolicy(QSizePolicy::Minimum, - QSizePolicy::Expanding); // Mac Qt5 - m_contextSpinBoxAction = m_toolBar->addWidget(m_contextSpinBox); - - QToolButton *toggleDescription = new QToolButton(m_toolBar); - toggleDescription->setIcon(QIcon(QLatin1String(Constants::ICON_TOP_BAR))); - toggleDescription->setCheckable(true); - toggleDescription->setChecked(m_showDescription); - m_toggleDescriptionAction = m_toolBar->addWidget(toggleDescription); - updateDescription(); + m_contextSpinBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); // Mac Qt5 + m_toolBar->addWidget(m_contextSpinBox); + + m_whitespaceButtonAction = m_toolBar->addAction(tr("Ignore Whitespace")); + m_whitespaceButtonAction->setCheckable(true); + m_whitespaceButtonAction->setChecked(m_document->ignoreWhitespace()); + + m_toggleDescriptionAction = m_toolBar->addAction(QIcon(QLatin1String(Constants::ICON_TOP_BAR)), + QString()); + m_toggleDescriptionAction->setCheckable(true); - QToolButton *reloadButton = new QToolButton(m_toolBar); - reloadButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RELOAD_GRAY))); - reloadButton->setToolTip(tr("Reload Editor")); - m_reloadAction = m_toolBar->addWidget(reloadButton); + m_reloadAction = m_toolBar->addAction(QIcon(QLatin1String(Core::Constants::ICON_RELOAD_GRAY)), + tr("Reload Diff")); + m_reloadAction->setToolTip(tr("Reload Diff")); documentStateChanged(); - QToolButton *toggleSync = new QToolButton(m_toolBar); - toggleSync->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK))); - toggleSync->setCheckable(true); - m_toggleSyncAction = m_toolBar->addWidget(toggleSync); + m_toggleSyncAction = m_toolBar->addAction(QIcon(QLatin1String(Core::Constants::ICON_LINK)), + QString()); + m_toggleSyncAction->setCheckable(true); - m_diffEditorSwitcher = new QToolButton(m_toolBar); - m_toolBar->addWidget(m_diffEditorSwitcher); + m_viewSwitcherAction = m_toolBar->addAction(QIcon(), QString()); updateDiffEditorSwitcher(); - connect(m_whitespaceButton, &QToolButton::clicked, - this, &DiffEditor::ignoreWhitespaceHasChanged); + connect(m_whitespaceButtonAction, &QAction::toggled, this, &DiffEditor::ignoreWhitespaceHasChanged); connect(m_contextSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &DiffEditor::contextLineCountHasChanged); - connect(toggleSync, &QAbstractButton::clicked, this, &DiffEditor::toggleSync); - connect(toggleDescription, &QAbstractButton::clicked, - this, &DiffEditor::toggleDescription); - connect(m_diffEditorSwitcher, &QAbstractButton::clicked, - this, [this]() { showDiffView(nextView()); }); - - connect(reloadButton, &QAbstractButton::clicked, this, [this]() { m_document->reload(); }); + connect(m_toggleSyncAction, &QAction::toggled, this, &DiffEditor::toggleSync); + connect(m_toggleDescriptionAction, &QAction::toggled, this, &DiffEditor::toggleDescription); + connect(m_viewSwitcherAction, &QAction::triggered, this, [this]() { showDiffView(nextView()); }); + connect(m_reloadAction, &QAction::triggered, this, [this]() { m_document->reload(); }); connect(m_document.data(), &DiffEditorDocument::temporaryStateChanged, this, &DiffEditor::documentStateChanged); @@ -374,72 +372,76 @@ QWidget *DiffEditor::toolBar() void DiffEditor::documentHasChanged() { - m_ignoreChanges = true; - const QList<FileData> diffFileList = m_document->diffFiles(); - - currentView()->setDiff(diffFileList, m_document->baseDirectory()); - - m_entriesComboBox->clear(); int index = 0; - const int count = diffFileList.count(); - for (int i = 0; i < count; i++) { - const DiffFileInfo leftEntry = diffFileList.at(i).leftFileInfo; - const DiffFileInfo rightEntry = diffFileList.at(i).rightFileInfo; - const QString leftShortFileName = Utils::FileName::fromString(leftEntry.fileName).fileName(); - const QString rightShortFileName = Utils::FileName::fromString(rightEntry.fileName).fileName(); - QString itemText; - QString itemToolTip; - if (leftEntry.fileName == rightEntry.fileName) { - itemText = leftShortFileName; - - if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { - itemToolTip = leftEntry.fileName; - } else { - itemToolTip = tr("[%1] vs. [%2] %3") - .arg(leftEntry.typeInfo, - rightEntry.typeInfo, - leftEntry.fileName); - } - } else { - if (leftShortFileName == rightShortFileName) { + { + Guard guard(&m_ignoreChanges); + const QList<FileData> diffFileList = m_document->diffFiles(); + + updateDescription(); + currentView()->setDiff(diffFileList, m_document->baseDirectory()); + + m_entriesComboBox->clear(); + const int count = diffFileList.count(); + for (int i = 0; i < count; i++) { + const DiffFileInfo leftEntry = diffFileList.at(i).leftFileInfo; + const DiffFileInfo rightEntry = diffFileList.at(i).rightFileInfo; + const QString leftShortFileName = Utils::FileName::fromString(leftEntry.fileName).fileName(); + const QString rightShortFileName = Utils::FileName::fromString(rightEntry.fileName).fileName(); + QString itemText; + QString itemToolTip; + if (leftEntry.fileName == rightEntry.fileName) { itemText = leftShortFileName; - } else { - itemText = tr("%1 vs. %2") - .arg(leftShortFileName, - rightShortFileName); - } - if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { - itemToolTip = tr("%1 vs. %2") - .arg(leftEntry.fileName, - rightEntry.fileName); + if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { + itemToolTip = leftEntry.fileName; + } else { + itemToolTip = tr("[%1] vs. [%2] %3") + .arg(leftEntry.typeInfo, + rightEntry.typeInfo, + leftEntry.fileName); + } } else { - itemToolTip = tr("[%1] %2 vs. [%3] %4") - .arg(leftEntry.typeInfo, - leftEntry.fileName, - rightEntry.typeInfo, - rightEntry.fileName); + if (leftShortFileName == rightShortFileName) { + itemText = leftShortFileName; + } else { + itemText = tr("%1 vs. %2") + .arg(leftShortFileName, + rightShortFileName); + } + + if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { + itemToolTip = tr("%1 vs. %2") + .arg(leftEntry.fileName, + rightEntry.fileName); + } else { + itemToolTip = tr("[%1] %2 vs. [%3] %4") + .arg(leftEntry.typeInfo, + leftEntry.fileName, + rightEntry.typeInfo, + rightEntry.fileName); + } } + if (m_currentFileChunk.first == leftEntry.fileName + && m_currentFileChunk.second == rightEntry.fileName) + index = i; + m_entriesComboBox->addItem(itemText); + m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, + leftEntry.fileName, Qt::UserRole); + m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, + rightEntry.fileName, Qt::UserRole + 1); + m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, + itemToolTip, Qt::ToolTipRole); } - if (m_currentFileChunk.first == leftEntry.fileName - && m_currentFileChunk.second == rightEntry.fileName) - index = i; - m_entriesComboBox->addItem(itemText); - m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, - leftEntry.fileName, Qt::UserRole); - m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, - rightEntry.fileName, Qt::UserRole + 1); - m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, - itemToolTip, Qt::ToolTipRole); } - m_ignoreChanges = false; - setCurrentDiffFileIndex(m_entriesComboBox->count() > 0 ? index : -1); } void DiffEditor::toggleDescription() { + if (m_ignoreChanges > 0) + return; + m_showDescription = !m_showDescription; saveSetting(QLatin1String(descriptionVisibleKeyC), m_showDescription); updateDescription(); @@ -447,23 +449,25 @@ void DiffEditor::toggleDescription() void DiffEditor::updateDescription() { + QTC_ASSERT(m_toolBar, return); + QString description = m_document->description(); m_descriptionWidget->setPlainText(description); m_descriptionWidget->setVisible(m_showDescription && !description.isEmpty()); - QTC_ASSERT(m_toolBar, return); - QTC_ASSERT(m_toggleDescriptionAction, return); - - QWidget *toggle = m_toolBar->widgetForAction(m_toggleDescriptionAction); - toggle->setToolTip(m_showDescription ? tr("Hide Change Description") - : tr("Show Change Description")); + Guard guard(&m_ignoreChanges); + m_toggleDescriptionAction->setChecked(m_showDescription); + m_toggleDescriptionAction->setToolTip(m_showDescription ? tr("Hide Change Description") + : tr("Show Change Description")); + m_toggleDescriptionAction->setText(m_showDescription ? tr("Hide Change Description") + : tr("Show Change Description")); m_toggleDescriptionAction->setVisible(!description.isEmpty()); } void DiffEditor::contextLineCountHasChanged(int lines) { QTC_ASSERT(!m_document->isContextLineCountForced(), return); - if (m_ignoreChanges || lines == m_document->contextLineCount()) + if (m_ignoreChanges > 0 || lines == m_document->contextLineCount()) return; m_document->setContextLineCount(lines); @@ -472,13 +476,15 @@ void DiffEditor::contextLineCountHasChanged(int lines) m_document->reload(); } -void DiffEditor::ignoreWhitespaceHasChanged(bool ignore) +void DiffEditor::ignoreWhitespaceHasChanged() { - if (m_ignoreChanges || ignore == m_document->ignoreWhitespace()) - return; + const bool ignore = m_whitespaceButtonAction->isChecked(); + if (m_ignoreChanges > 0 || ignore == m_document->ignoreWhitespace()) + return; m_document->setIgnoreWhitespace(ignore); saveSetting(QLatin1String(ignoreWhitespaceKeyC), ignore); + m_document->reload(); } @@ -496,10 +502,11 @@ void DiffEditor::prepareForReload() m_currentFileChunk = qMakePair(QString(), QString()); } - m_ignoreChanges = true; - m_contextSpinBox->setValue(m_document->contextLineCount()); - m_whitespaceButton->setChecked(m_document->ignoreWhitespace()); - m_ignoreChanges = false; + { + Guard guard(&m_ignoreChanges); + m_contextSpinBox->setValue(m_document->contextLineCount()); + m_whitespaceButtonAction->setChecked(m_document->ignoreWhitespace()); + } currentView()->beginOperation(); } @@ -522,20 +529,17 @@ void DiffEditor::updateEntryToolTip() void DiffEditor::setCurrentDiffFileIndex(int index) { - if (m_ignoreChanges) + if (m_ignoreChanges > 0) return; QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return); - m_ignoreChanges = true; - + Guard guard(&m_ignoreChanges); m_currentDiffFileIndex = index; currentView()->setCurrentDiffFileIndex(index); m_entriesComboBox->setCurrentIndex(m_entriesComboBox->count() > 0 ? qMax(0, index) : -1); updateEntryToolTip(); - - m_ignoreChanges = false; } void DiffEditor::documentStateChanged() @@ -544,22 +548,26 @@ void DiffEditor::documentStateChanged() const bool contextVisible = !m_document->isContextLineCountForced(); m_whitespaceButtonAction->setVisible(canReload); - m_contextLabelAction->setVisible(canReload && contextVisible); - m_contextSpinBoxAction->setVisible(canReload && contextVisible); + m_contextLabel->setVisible(canReload && contextVisible); + m_contextSpinBox->setVisible(canReload && contextVisible); m_reloadAction->setVisible(canReload); } void DiffEditor::updateDiffEditorSwitcher() { - if (!m_diffEditorSwitcher) + if (!m_viewSwitcherAction) return; IDiffView *next = nextView(); - m_diffEditorSwitcher->setIcon(next->icon()); - m_diffEditorSwitcher->setToolTip(next->toolTip()); + m_viewSwitcherAction->setIcon(next->icon()); + m_viewSwitcherAction->setToolTip(next->toolTip()); + m_viewSwitcherAction->setText(next->toolTip()); } void DiffEditor::toggleSync() { + if (m_ignoreChanges > 0) + return; + QTC_ASSERT(currentView(), return); m_sync = !m_sync; saveSetting(QLatin1String(horizontalScrollBarSynchronizationKeyC), m_sync); @@ -587,10 +595,8 @@ void DiffEditor::loadSettings() // Read current settings: s->beginGroup(QLatin1String(settingsGroupC)); - m_showDescription = s->value(QLatin1String(descriptionVisibleKeyC), - true).toBool(); - m_sync = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC), - true).toBool(); + m_showDescription = s->value(QLatin1String(descriptionVisibleKeyC), true).toBool(); + m_sync = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC), true).toBool(); m_document->setIgnoreWhitespace(s->value(QLatin1String(ignoreWhitespaceKeyC), false).toBool()); m_document->setContextLineCount(s->value(QLatin1String(contextLineCountKeyC), 3).toInt()); Core::Id id = Core::Id::fromSetting(s->value(QLatin1String(diffViewKeyC))); @@ -651,9 +657,13 @@ void DiffEditor::setupView(IDiffView *view) saveSetting(QLatin1String(diffViewKeyC), currentView()->id().toSetting()); - m_toggleSyncAction->setVisible(currentView()->supportsSync()); - m_toggleSyncAction->setToolTip(currentView()->syncToolTip()); - m_toggleSyncAction->setChecked(m_sync); + { + Guard guard(&m_ignoreChanges); + m_toggleSyncAction->setVisible(currentView()->supportsSync()); + m_toggleSyncAction->setToolTip(currentView()->syncToolTip()); + m_toggleSyncAction->setText(currentView()->syncToolTip()); + m_toggleSyncAction->setChecked(m_sync); + } view->setDocument(m_document.data()); view->setSync(m_sync); diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index 78134cc24c..3be67972e4 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -38,6 +38,7 @@ QT_BEGIN_NAMESPACE class QComboBox; +class QLabel; class QSpinBox; class QToolBar; class QToolButton; @@ -76,7 +77,7 @@ private slots: void toggleDescription(); void updateDescription(); void contextLineCountHasChanged(int lines); - void ignoreWhitespaceHasChanged(bool ignore); + void ignoreWhitespaceHasChanged(); void prepareForReload(); void reloadHasFinished(bool success); void setCurrentDiffFileIndex(int index); @@ -102,21 +103,19 @@ private: QVector<IDiffView *> m_views; QToolBar *m_toolBar; QComboBox *m_entriesComboBox; - QToolButton *m_whitespaceButton; QSpinBox *m_contextSpinBox; QAction *m_toggleSyncAction; QAction *m_whitespaceButtonAction; - QAction *m_contextLabelAction; - QAction *m_contextSpinBoxAction; QAction *m_toggleDescriptionAction; QAction *m_reloadAction; - QToolButton *m_diffEditorSwitcher; + QLabel *m_contextLabel; + QAction *m_viewSwitcherAction; QPair<QString, QString> m_currentFileChunk; int m_currentViewIndex; int m_currentDiffFileIndex; + int m_ignoreChanges; bool m_sync; bool m_showDescription; - bool m_ignoreChanges; }; } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 0937a230e0..b091c3eece 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -160,6 +160,7 @@ QString DiffEditorDocument::description() const void DiffEditorDocument::setContextLineCount(int lines) { + QTC_ASSERT(!m_isContextLineCountForced, return); m_contextLineCount = lines; } @@ -181,8 +182,6 @@ bool DiffEditorDocument::isContextLineCountForced() const void DiffEditorDocument::setIgnoreWhitespace(bool ignore) { - if (m_isContextLineCountForced) - return; m_ignoreWhitespace = ignore; } diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 76a989c42c..ffa5f48047 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -60,9 +60,6 @@ #include <utils/tooltip/tooltip.h> -//static const int FILE_LEVEL = 1; -//static const int CHUNK_LEVEL = 2; - using namespace Core; using namespace TextEditor; using namespace Utils; @@ -70,30 +67,6 @@ using namespace Utils; namespace DiffEditor { namespace Internal { -//////////////////////// -/* -class MultiHighlighter : public SyntaxHighlighter -{ - Q_OBJECT -public: - MultiHighlighter(SideDiffEditorWidget *editor, QTextDocument *document = 0); - ~MultiHighlighter(); - - virtual void setFontSettings(const FontSettings &fontSettings); - void setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents); - -protected: - virtual void highlightBlock(const QString &text); - -private: - SideDiffEditorWidget *m_editor; - QMap<QString, HighlighterFactory *> m_mimeTypeToHighlighterFactory; - QList<SyntaxHighlighter *> m_highlighters; - QList<QTextDocument *> m_documents; -}; -*/ -//////////////////////// - class SideDiffEditorWidget : public SelectableTextEditorWidget { Q_OBJECT @@ -127,7 +100,6 @@ public: QTextBlock firstVisibleBlock() const { return TextEditorWidget::firstVisibleBlock(); } -// void setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents); void saveState(); void restoreState(); @@ -154,17 +126,12 @@ protected: virtual bool replacementVisible(int blockNumber) const; QColor replacementPenColor(int blockNumber) const; virtual QString plainTextFromSelection(const QTextCursor &cursor) const; -// virtual void drawCollapsedBlockPopup(QPainter &painter, -// const QTextBlock &block, -// QPointF offset, -// const QRect &clip); void mouseDoubleClickEvent(QMouseEvent *e); void contextMenuEvent(QContextMenuEvent *e); virtual void paintEvent(QPaintEvent *e); virtual void scrollContentsBy(int dx, int dy); private: -// void paintCollapsedBlockPopup(QPainter &painter, const QRect &clipRect); void paintSeparator(QPainter &painter, QColor &color, const QString &text, const QTextBlock &block, int top); void jumpToOriginalFile(const QTextCursor &cursor); @@ -185,98 +152,8 @@ private: QColor m_chunkLineForeground; QColor m_textForeground; QByteArray m_state; -// MultiHighlighter *m_highlighter; }; -//////////////////////// -/* -MultiHighlighter::MultiHighlighter(SideDiffEditorWidget *editor, QTextDocument *document) - : SyntaxHighlighter(document), - m_editor(editor) -{ - const QList<HighlighterFactory *> &factories = - ExtensionSystem::PluginManager::getObjects<HighlighterFactory>(); - foreach (HighlighterFactory *factory, factories) { - QStringList mimeTypes = factory->mimeTypes(); - foreach (const QString &mimeType, mimeTypes) - m_mimeTypeToHighlighterFactory.insert(mimeType, factory); - } -} - -MultiHighlighter::~MultiHighlighter() -{ - setDocuments(QList<QPair<DiffFileInfo, QString> >()); -} - -void MultiHighlighter::setFontSettings(const FontSettings &fontSettings) -{ - foreach (SyntaxHighlighter *highlighter, m_highlighters) { - if (highlighter) { - highlighter->setFontSettings(fontSettings); - highlighter->rehighlight(); - } - } -} - -void MultiHighlighter::setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents) -{ - // clear old documents - qDeleteAll(m_documents); - m_documents.clear(); - qDeleteAll(m_highlighters); - m_highlighters.clear(); - - // create new documents - for (int i = 0; i < documents.count(); i++) { - DiffFileInfo fileInfo = documents.at(i).first; - const QString contents = documents.at(i).second; - QTextDocument *document = new QTextDocument(contents); - const MimeType mimeType = MimeDatabase::findByFile(QFileInfo(fileInfo.fileName)); - SyntaxHighlighter *highlighter = 0; - if (const HighlighterFactory *factory = m_mimeTypeToHighlighterFactory.value(mimeType.type())) { - highlighter = factory->createHighlighter(); - if (highlighter) - highlighter->setDocument(document); - } - if (!highlighter) { - highlighter = createGenericSyntaxHighlighter(mimeType); - highlighter->setDocument(document); - } - m_documents.append(document); - m_highlighters.append(highlighter); - } -} - -void MultiHighlighter::highlightBlock(const QString &text) -{ - Q_UNUSED(text) - - QTextBlock block = currentBlock(); - const int fileIndex = m_editor->fileIndexForBlockNumber(block.blockNumber()); - if (fileIndex < 0) - return; - - SyntaxHighlighter *currentHighlighter = m_highlighters.at(fileIndex); - if (!currentHighlighter) - return; - - // find block in document - QTextDocument *currentDocument = m_documents.at(fileIndex); - if (!currentDocument) - return; - - QTextBlock documentBlock = currentDocument->findBlockByNumber( - block.blockNumber() - m_editor->blockNumberForFileIndex(fileIndex)); - - if (!documentBlock.isValid()) - return; - - QList<QTextLayout::FormatRange> formats = documentBlock.layout()->additionalFormats(); - setExtraAdditionalFormats(block, formats); -} -*/ -//////////////////////// - SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent) : SelectableTextEditorWidget("DiffEditor.SideDiffEditor", parent), m_lineNumberDigits(1), @@ -299,11 +176,6 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent) else ToolTip::hide(); }); - -// setCodeFoldingSupported(true); - -// m_highlighter = new MultiHighlighter(this, baseTextDocument()->document()); -// baseTextDocument()->setSyntaxHighlighter(m_highlighter); } void SideDiffEditorWidget::saveState() @@ -630,109 +502,7 @@ void SideDiffEditorWidget::paintEvent(QPaintEvent *e) } currentBlock = currentBlock.next(); } -// paintCollapsedBlockPopup(painter, e->rect()); -} -/* -void SideDiffEditorWidget::paintCollapsedBlockPopup(QPainter &painter, const QRect &clipRect) -{ - QPointF offset(contentOffset()); - QRect viewportRect = viewport()->rect(); - QTextBlock block = firstVisibleBlock(); - QTextBlock visibleCollapsedBlock; - QPointF visibleCollapsedBlockOffset; - - while (block.isValid()) { - - QRectF r = blockBoundingRect(block).translated(offset); - - offset.ry() += r.height(); - - if (offset.y() > viewportRect.height()) - break; - - block = block.next(); - - if (!block.isVisible()) { - if (block.blockNumber() == visibleFoldedBlockNumber()) { - visibleCollapsedBlock = block; - visibleCollapsedBlockOffset = offset + QPointF(0,1); - break; - } - - // invisible blocks do have zero line count - block = document()->findBlockByLineNumber(block.firstLineNumber()); - } - } - if (visibleCollapsedBlock.isValid()) { - drawCollapsedBlockPopup(painter, - visibleCollapsedBlock, - visibleCollapsedBlockOffset, - clipRect); - } -} - -void SideDiffEditorWidget::drawCollapsedBlockPopup(QPainter &painter, - const QTextBlock &block, - QPointF offset, - const QRect &clip) -{ - // We ignore the call coming from the SelectableTextEditorWidget::paintEvent() - // since we will draw it later, after custom drawings of this paintEvent. - // We need to draw it after our custom drawings, otherwise custom - // drawings will appear in front of block popup. - if (m_inPaintEvent) - return; - - int margin = block.document()->documentMargin(); - qreal maxWidth = 0; - qreal blockHeight = 0; - QTextBlock b = block; - - while (!b.isVisible()) { - if (!m_separators.contains(b.blockNumber())) { - b.setVisible(true); // make sure block bounding rect works - QRectF r = blockBoundingRect(b).translated(offset); - - QTextLayout *layout = b.layout(); - for (int i = layout->lineCount()-1; i >= 0; --i) - maxWidth = qMax(maxWidth, layout->lineAt(i).naturalTextWidth() + 2*margin); - - blockHeight += r.height(); - - b.setVisible(false); // restore previous state - b.setLineCount(0); // restore 0 line count for invisible block - } - b = b.next(); - } - - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); - painter.translate(.5, .5); - QBrush brush = palette().base(); - painter.setBrush(brush); - painter.drawRoundedRect(QRectF(offset.x(), - offset.y(), - maxWidth, blockHeight).adjusted(0, 0, 0, 0), 3, 3); - painter.restore(); - - QTextBlock end = b; - b = block; - while (b != end) { - if (!m_separators.contains(b.blockNumber())) { - b.setVisible(true); // make sure block bounding rect works - QRectF r = blockBoundingRect(b).translated(offset); - QTextLayout *layout = b.layout(); - QVector<QTextLayout::FormatRange> selections; - layout->draw(&painter, offset, selections, clip); - - b.setVisible(false); // restore previous state - b.setLineCount(0); // restore 0 line count for invisible block - offset.ry() += r.height(); - } - b = b.next(); - } } -*/ ////////////////// @@ -1196,8 +966,8 @@ void SideBySideDiffEditorWidget::slotSendChunkToCodePaster() return; // Retrieve service by soft dependency. - QObject *pasteService= ExtensionSystem::PluginManager::getObjectByClassName( - QLatin1String("CodePaster::CodePasterService")); + QObject *pasteService + = ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("CodePaster::CodePasterService")); if (pasteService) { QMetaObject::invokeMethod(pasteService, "postText", Q_ARG(QString, patch), diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index 54386f8970..18341aac1f 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -93,12 +93,9 @@ private slots: void rightHSliderChanged(); void leftCursorPositionChanged(); void rightCursorPositionChanged(); -// void leftDocumentSizeChanged(); -// void rightDocumentSizeChanged(); private: void showDiff(); -// void synchronizeFoldings(SideDiffEditorWidget *source, SideDiffEditorWidget *destination); void jumpToOriginalFile(const QString &fileName, int lineNumber, int columnNumber); void patch(bool revert); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 58a9ead1b0..ff068d46fd 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -361,8 +361,6 @@ private: void ShowController::reload() { - QTC_ASSERT(m_state == Idle, return); - QStringList args; args << QLatin1String("show") << QLatin1String("-s") << QLatin1String(noColorOption) << QLatin1String(decorateOption) << m_id; diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 298e154c87..819b9b73c6 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -174,6 +174,7 @@ void GitSubmitEditor::setCommitData(const CommitData &d) setEmptyFileListEnabled(m_commitType == AmendCommit); // Allow for just correcting the message m_model = new GitSubmitFileModel(this); + m_model->setRepositoryRoot(d.panelInfo.repository); if (!d.files.isEmpty()) { for (QList<CommitData::StateFilePair>::const_iterator it = d.files.constBegin(); it != d.files.constEnd(); ++it) { @@ -192,7 +193,7 @@ void GitSubmitEditor::setCommitData(const CommitData &d) QVariant(static_cast<int>(state))); } } - setFileModel(m_model, d.panelInfo.repository); + setFileModel(m_model); } void GitSubmitEditor::slotDiffSelected(const QList<int> &rows) diff --git a/src/plugins/glsleditor/glsleditor.cpp b/src/plugins/glsleditor/glsleditor.cpp index aa14a53fcf..b71b5f5a7a 100644 --- a/src/plugins/glsleditor/glsleditor.cpp +++ b/src/plugins/glsleditor/glsleditor.cpp @@ -214,13 +214,12 @@ void GlslEditorWidget::updateDocumentNow() const QByteArray preprocessedCode = contents.toLatin1(); // ### use the QtCreator C++ preprocessor. Document::Ptr doc(new Document()); - Engine engine; doc->_engine = new Engine(); Parser parser(doc->_engine, preprocessedCode.constData(), preprocessedCode.size(), variant); TranslationUnitAST *ast = parser.parse(); if (ast != 0 || extraSelections(CodeWarningsSelection).isEmpty()) { Semantic sem; - Scope *globalScope = engine.newNamespace(); + Scope *globalScope = new Namespace(); doc->_globalScope = globalScope; const GlslEditorPlugin::InitFile *file = GlslEditorPlugin::shaderInit(variant); sem.translationUnit(file->ast, globalScope, file->engine); @@ -232,7 +231,7 @@ void GlslEditorWidget::updateDocumentNow() file = GlslEditorPlugin::fragmentShaderInit(variant); sem.translationUnit(file->ast, globalScope, file->engine); } - sem.translationUnit(ast, globalScope, &engine); + sem.translationUnit(ast, globalScope, doc->_engine); CreateRanges createRanges(document(), doc); createRanges(ast); @@ -248,7 +247,7 @@ void GlslEditorWidget::updateDocumentNow() QList<QTextEdit::ExtraSelection> sels; QSet<int> errors; - foreach (const DiagnosticMessage &m, engine.diagnosticMessages()) { + foreach (const DiagnosticMessage &m, doc->_engine->diagnosticMessages()) { if (! m.line()) continue; else if (errors.contains(m.line())) diff --git a/src/plugins/help/helpwidget.cpp b/src/plugins/help/helpwidget.cpp index 98ca352d44..0d62fa81a1 100644 --- a/src/plugins/help/helpwidget.cpp +++ b/src/plugins/help/helpwidget.cpp @@ -335,7 +335,7 @@ void HelpWidget::addSideBar() m_bookmarkAction = new QAction(tr("Activate Help Bookmarks View"), this); cmd = Core::ActionManager::registerAction(m_bookmarkAction, Constants::HELP_BOOKMARKS, m_context->context()); - cmd->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+B") + cmd->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Alt+Meta+M") : tr("Ctrl+Shift+B"))); shortcutMap.insert(QLatin1String(Constants::HELP_BOOKMARKS), cmd); diff --git a/src/plugins/mercurial/commiteditor.cpp b/src/plugins/mercurial/commiteditor.cpp index 724ce2d100..4ab9e4f5b7 100644 --- a/src/plugins/mercurial/commiteditor.cpp +++ b/src/plugins/mercurial/commiteditor.cpp @@ -64,6 +64,7 @@ void CommitEditor::setFields(const QFileInfo &repositoryRoot, const QString &bra mercurialWidget->setFields(repositoryRoot.absoluteFilePath(), branch, userName, email); fileModel = new SubmitFileModel(this); + fileModel->setRepositoryRoot(repositoryRoot.absoluteFilePath()); QStringList shouldTrack; @@ -74,8 +75,7 @@ void CommitEditor::setFields(const QFileInfo &repositoryRoot, const QString &bra fileModel->addFile(item.file, item.flags, Unchecked); } - VcsBaseSubmitEditor::filterUntrackedFilesOfProject(repositoryRoot.absoluteFilePath(), - &shouldTrack); + VcsBaseSubmitEditor::filterUntrackedFilesOfProject(fileModel->repositoryRoot(), &shouldTrack); foreach (const QString &track, shouldTrack) { foreach (const VcsBaseClient::StatusItem &item, repoStatus) { @@ -84,7 +84,7 @@ void CommitEditor::setFields(const QFileInfo &repositoryRoot, const QString &bra } } - setFileModel(fileModel, repositoryRoot.absoluteFilePath()); + setFileModel(fileModel); } QString CommitEditor::committerInfo() diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 716e03bddd..55425a9de2 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -941,6 +941,9 @@ bool SessionManager::loadSession(const QString &session) d->restoreValues(reader); emit m_instance->aboutToLoadSession(session); + // retrieve all values before the following code could change them again + Id modeId = Id::fromSetting(value(QLatin1String("ActiveMode"))); + QColor c = QColor(reader.restoreValue(QLatin1String("Color")).toString()); if (c.isValid()) StyleHelper::setBaseColor(c); @@ -965,7 +968,6 @@ bool SessionManager::loadSession(const QString &session) d->m_future = QFutureInterface<void>(); // restore the active mode - Id modeId = Id::fromSetting(value(QLatin1String("ActiveMode"))); if (!modeId.isValid()) modeId = Id(Core::Constants::MODE_EDIT); diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp new file mode 100644 index 0000000000..3de2b6fcc2 --- /dev/null +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "makefileparse.h" + +#include <qtsupport/qtversionmanager.h> +#include <qtsupport/baseqtversion.h> +#include <utils/qtcprocess.h> + +#include <QDebug> +#include <QDir> +#include <QFileInfo> +#include <QTextStream> +#include <QLoggingCategory> + +using namespace QmakeProjectManager; +using namespace Internal; + +using Utils::FileName; +using Utils::QtcProcess; +using QtSupport::QtVersionManager; +using QtSupport::BaseQtVersion; + +static QString findQMakeLine(const QString &makefile, const QString &key) +{ + QFile fi(makefile); + if (fi.exists() && fi.open(QFile::ReadOnly)) { + QTextStream ts(&fi); + while (!ts.atEnd()) { + const QString line = ts.readLine(); + if (line.startsWith(key)) + return line; + } + } + return QString(); +} + +/// This function trims the "#Command /path/to/qmake" from the line +static QString trimLine(const QString &line) +{ + + // Actually the first space after #Command: /path/to/qmake + const int firstSpace = line.indexOf(QLatin1Char(' '), 11); + return line.mid(firstSpace).trimmed(); +} + +void MakeFileParse::parseArgs(const QString &args, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments) +{ + QRegExp regExp(QLatin1String("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)")); + bool after = false; + bool ignoreNext = false; + m_unparsedArguments = args; + QtcProcess::ArgIterator ait(&m_unparsedArguments); + while (ait.next()) { + if (ignoreNext) { + // Ignoring + ignoreNext = false; + ait.deleteArg(); + } else if (ait.value() == QLatin1String("-after")) { + after = true; + ait.deleteArg(); + } else if (ait.value().contains(QLatin1Char('='))) { + if (regExp.exactMatch(ait.value())) { + QMakeAssignment qa; + qa.variable = regExp.cap(1); + qa.op = regExp.cap(2); + qa.value = regExp.cap(3).trimmed(); + if (after) + afterAssignments->append(qa); + else + assignments->append(qa); + } else { + qDebug()<<"regexp did not match"; + } + ait.deleteArg(); + } else if (ait.value() == QLatin1String("-o")) { + ignoreNext = true; + ait.deleteArg(); +#if defined(Q_OS_WIN32) + } else if (ait.value() == QLatin1String("-win32")) { +#elif defined(Q_OS_MAC) + } else if (ait.value() == QLatin1String("-macx")) { +#elif defined(Q_OS_QNX6) + } else if (ait.value() == QLatin1String("-qnx6")) { +#else + } else if (ait.value() == QLatin1String("-unix")) { +#endif + ait.deleteArg(); + } + } + ait.deleteArg(); // The .pro file is always the last arg +} + +void dumpQMakeAssignments(const QList<QMakeAssignment> &list) +{ + foreach (const QMakeAssignment &qa, list) { + qCDebug(MakeFileParse::logging()) << " " << qa.variable << qa.op << qa.value; + } +} + +void MakeFileParse::parseAssignments(QList<QMakeAssignment> *assignments) +{ + bool foundSeparateDebugInfo = false; + bool foundForceDebugInfo = false; + QList<QMakeAssignment> oldAssignments = *assignments; + assignments->clear(); + foreach (const QMakeAssignment &qa, oldAssignments) { + if (qa.variable == QLatin1String("CONFIG")) { + QStringList values = qa.value.split(QLatin1Char(' ')); + QStringList newValues; + foreach (const QString &value, values) { + if (value == QLatin1String("debug")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitDebug = true; + m_qmakeBuildConfig.explicitRelease = false; + } else { + m_qmakeBuildConfig.explicitDebug = false; + m_qmakeBuildConfig.explicitRelease = true; + } + } else if (value == QLatin1String("release")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitDebug = false; + m_qmakeBuildConfig.explicitRelease = true; + } else { + m_qmakeBuildConfig.explicitDebug = true; + m_qmakeBuildConfig.explicitRelease = false; + } + } else if (value == QLatin1String("debug_and_release")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitBuildAll = true; + m_qmakeBuildConfig.explicitNoBuildAll = false; + } else { + m_qmakeBuildConfig.explicitBuildAll = false; + m_qmakeBuildConfig.explicitNoBuildAll = true; + } + } else if (value == QLatin1String("x86")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::X86; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("x86_64")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::X86_64; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("ppc")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::PPC; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("ppc64")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::PPC64; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("iphonesimulator")) { + if (qa.op == QLatin1String("+=")) + m_config.osType = QMakeStepConfig::IphoneSimulator; + else + m_config.osType = QMakeStepConfig::NoOsType; + } else if (value == QLatin1String("iphoneos")) { + if (qa.op == QLatin1String("+=")) + m_config.osType = QMakeStepConfig::IphoneOS; + else + m_config.osType = QMakeStepConfig::NoOsType; + } else if (value == QLatin1String("declarative_debug")) { + if (qa.op == QLatin1String("+=")) + m_config.linkQmlDebuggingQQ1 = true; + else + m_config.linkQmlDebuggingQQ1 = false; + } else if (value == QLatin1String("qml_debug")) { + if (qa.op == QLatin1String("+=")) + m_config.linkQmlDebuggingQQ2 = true; + else + m_config.linkQmlDebuggingQQ2 = false; + } else if (value == QLatin1String("qtquickcompiler")) { + if (qa.op == QLatin1String("+=")) + m_config.useQtQuickCompiler = true; + else + m_config.useQtQuickCompiler = false; + } else if (value == QLatin1String("force_debug_info")) { + if (qa.op == QLatin1String("+=")) + foundForceDebugInfo = true; + else + foundForceDebugInfo = false; + } else if (value == QLatin1String("separate_debug_info")) { + if (qa.op == QLatin1String("+=")) + foundSeparateDebugInfo = true; + else + foundSeparateDebugInfo = false; + } else { + newValues.append(value); + } + QMakeAssignment newQA = qa; + newQA.value = newValues.join(QLatin1Char(' ')); + if (!newValues.isEmpty()) + assignments->append(newQA); + } + } else { + assignments->append(qa); + } + } + + if (foundForceDebugInfo && foundSeparateDebugInfo) { + m_config.separateDebugInfo = true; + } else if (foundForceDebugInfo) { + // Found only force_debug_info, so readd it + QMakeAssignment newQA; + newQA.variable = QLatin1String("CONFIG"); + newQA.op = QLatin1String("+="); + newQA.value = QLatin1String("force_debug_info"); + assignments->append(newQA); + } else if (foundSeparateDebugInfo) { + // Found only separate_debug_info, so readd it + QMakeAssignment newQA; + newQA.variable = QLatin1String("CONFIG"); + newQA.op = QLatin1String("+="); + newQA.value = QLatin1String("separate_debug_info"); + assignments->append(newQA); + } +} + +static FileName findQMakeBinaryFromMakefile(const QString &makefile) +{ + bool debugAdding = false; + QFile fi(makefile); + if (fi.exists() && fi.open(QFile::ReadOnly)) { + QTextStream ts(&fi); + QRegExp r1(QLatin1String("QMAKE\\s*=(.*)")); + while (!ts.atEnd()) { + QString line = ts.readLine(); + if (r1.exactMatch(line)) { + if (debugAdding) + qDebug()<<"#~~ QMAKE is:"<<r1.cap(1).trimmed(); + QFileInfo qmake(r1.cap(1).trimmed()); + QString qmakePath = qmake.filePath(); + if (!QString::fromLatin1(QTC_HOST_EXE_SUFFIX).isEmpty() + && !qmakePath.endsWith(QLatin1String(QTC_HOST_EXE_SUFFIX))) { + qmakePath.append(QLatin1String(QTC_HOST_EXE_SUFFIX)); + } + // Is qmake still installed? + QFileInfo fi(qmakePath); + if (fi.exists()) + return FileName(fi); + } + } + } + return FileName(); +} + +MakeFileParse::MakeFileParse(const QString &makefile) +{ + qCDebug(logging()) << "Parsing makefile" << makefile; + if (!QFileInfo::exists(makefile)) { + qCDebug(logging()) << "**doesn't exist"; + m_state = MakefileMissing; + return; + } + + // Qt Version! + m_qmakePath = findQMakeBinaryFromMakefile(makefile); + qCDebug(logging()) << " qmake:" << m_qmakePath; + + QString line = findQMakeLine(makefile, QLatin1String("# Project:")).trimmed(); + if (line.isEmpty()) { + m_state = CouldNotParse; + qCDebug(logging()) << "**No Project line"; + return; + } + + line.remove(0, line.indexOf(QLatin1Char(':')) + 1); + line = line.trimmed(); + + // Src Pro file + m_srcProFile = QDir::cleanPath(QFileInfo(makefile).absoluteDir().filePath(line)); + qCDebug(logging()) << " source .pro file:" << m_srcProFile; + + line = findQMakeLine(makefile, QLatin1String("# Command:")); + if (line.trimmed().isEmpty()) { + m_state = CouldNotParse; + qCDebug(logging()) << "**No Command line found"; + return; + } + + line = trimLine(line); + + QList<QMakeAssignment> assignments; + QList<QMakeAssignment> afterAssignments; + // Split up args into assignments and other arguments, writes m_unparsedArguments + parseArgs(line, &assignments, &afterAssignments); + qCDebug(logging()) << " Initial assignments:"; + dumpQMakeAssignments(assignments); + + // Filter out CONFIG arguments we know into m_qmakeBuildConfig and m_config + parseAssignments(&assignments); + qCDebug(logging()) << " After parsing"; + dumpQMakeAssignments(assignments); + + qCDebug(logging()) << " Explicit Debug" << m_qmakeBuildConfig.explicitDebug; + qCDebug(logging()) << " Explicit Release" << m_qmakeBuildConfig.explicitRelease; + qCDebug(logging()) << " Explicit BuildAll" << m_qmakeBuildConfig.explicitBuildAll; + qCDebug(logging()) << " Explicit NoBuildAll" << m_qmakeBuildConfig.explicitNoBuildAll; + qCDebug(logging()) << " TargetArch" << m_config.archConfig; + qCDebug(logging()) << " OsType" << m_config.osType; + qCDebug(logging()) << " LinkQmlDebuggingQQ1" << m_config.linkQmlDebuggingQQ1; + qCDebug(logging()) << " LinkQmlDebuggingQQ2" << m_config.linkQmlDebuggingQQ2; + qCDebug(logging()) << " Qt Quick Compiler" << m_config.useQtQuickCompiler; + qCDebug(logging()) << " Separate Debug Info" << m_config.separateDebugInfo; + + + // Create command line of all unfiltered arguments + foreach (const QMakeAssignment &qa, assignments) + QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value); + if (!afterAssignments.isEmpty()) { + QtcProcess::addArg(&m_unparsedArguments, QLatin1String("-after")); + foreach (const QMakeAssignment &qa, afterAssignments) + QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value); + } + m_state = Okay; +} + +MakeFileParse::MakefileState MakeFileParse::makeFileState() const +{ + return m_state; +} + +Utils::FileName MakeFileParse::qmakePath() const +{ + return m_qmakePath; +} + +QString MakeFileParse::srcProFile() const +{ + return m_srcProFile; +} + +QMakeStepConfig MakeFileParse::config() const +{ + return m_config; +} + + +QString MakeFileParse::unparsedArguments() const +{ + return m_unparsedArguments; +} + +BaseQtVersion::QmakeBuildConfigs MakeFileParse::effectiveBuildConfig(BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) const +{ + BaseQtVersion::QmakeBuildConfigs buildConfig = defaultBuildConfig; + if (m_qmakeBuildConfig.explicitDebug) + buildConfig = buildConfig | BaseQtVersion::DebugBuild; + else if (m_qmakeBuildConfig.explicitRelease) + buildConfig = buildConfig & ~BaseQtVersion::DebugBuild; + if (m_qmakeBuildConfig.explicitBuildAll) + buildConfig = buildConfig | BaseQtVersion::BuildAll; + else if (m_qmakeBuildConfig.explicitNoBuildAll) + buildConfig = buildConfig &~ BaseQtVersion::BuildAll; + return buildConfig; +} + +const QLoggingCategory &MakeFileParse::logging() +{ + static const QLoggingCategory category("qtc.qmakeprojectmanager.import"); + return category; +} + diff --git a/src/plugins/qmakeprojectmanager/makefileparse.h b/src/plugins/qmakeprojectmanager/makefileparse.h new file mode 100644 index 0000000000..a5690929aa --- /dev/null +++ b/src/plugins/qmakeprojectmanager/makefileparse.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef MAKEFILEPARSE_H +#define MAKEFILEPARSE_H + +#include <utils/fileutils.h> +#include <qtsupport/baseqtversion.h> +#include <qmakeprojectmanager/qmakestep.h> + +QT_BEGIN_NAMESPACE +class QLogggingCategory; +QT_END_NAMESPACE + +namespace QmakeProjectManager { +namespace Internal { + +struct QMakeAssignment +{ + QString variable; + QString op; + QString value; +}; + +class MakeFileParse +{ +public: + MakeFileParse(const QString &makefile); + + enum MakefileState { MakefileMissing, CouldNotParse, Okay }; + + MakefileState makeFileState() const; + Utils::FileName qmakePath() const; + QString srcProFile() const; + QMakeStepConfig config() const; + + QString unparsedArguments() const; + + QtSupport::BaseQtVersion::QmakeBuildConfigs + effectiveBuildConfig(QtSupport::BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) const; + + static const QLoggingCategory &logging(); + +private: + void parseArgs(const QString &args, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments); + void parseAssignments(QList<QMakeAssignment> *assignments); + + class QmakeBuildConfig + { + public: + QmakeBuildConfig() + : explicitDebug(false), + explicitRelease(false), + explicitBuildAll(false), + explicitNoBuildAll(false) + {} + bool explicitDebug; + bool explicitRelease; + bool explicitBuildAll; + bool explicitNoBuildAll; + }; + + MakefileState m_state; + Utils::FileName m_qmakePath; + QString m_srcProFile; + + QmakeBuildConfig m_qmakeBuildConfig; + QMakeStepConfig m_config; + QString m_unparsedArguments; +}; + +} // namespace Internal +} // namespace QmakeProjectManager + + +#endif // MAKEFILEPARSE_H diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index fe638e69ae..1dd793b1b5 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -38,6 +38,7 @@ #include "qmakenodes.h" #include "qmakestep.h" #include "makestep.h" +#include "makefileparse.h" #include <coreplugin/documentmanager.h> #include <coreplugin/icore.h> @@ -59,6 +60,7 @@ #include <QDebug> #include <QInputDialog> +#include <QLoggingCategory> #include <limits> @@ -329,105 +331,116 @@ MakeStep *QmakeBuildConfiguration::makeStep() const // Returns true if both are equal. QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile) { + const QLoggingCategory &logs = MakeFileParse::logging(); + qCDebug(logs) << "QMakeBuildConfiguration::compareToImport"; + QMakeStep *qs = qmakeStep(); - if (QFileInfo::exists(makefile) && qs) { - FileName qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(makefile); - BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit()); - if (!version) - return MakefileForWrongProject; - if (QtSupport::QtVersionManager::makefileIsFor(makefile, qs->project()->projectFilePath().toString()) - != QtSupport::QtVersionManager::SameProject) { - if (debug) { - qDebug() << "different profile used to generate the Makefile:" - << makefile << " expected profile:" << qs->project()->projectFilePath(); - } - return MakefileIncompatible; - } - if (version->qmakeCommand() == qmakePath) { - // same qtversion - QPair<BaseQtVersion::QmakeBuildConfigs, QString> result = - QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig()); - if (qmakeBuildConfiguration() == result.first) { - // The qmake Build Configuration are the same, - // now compare arguments lists - // we have to compare without the spec/platform cmd argument - // and compare that on its own - QString workingDirectory = QFileInfo(makefile).absolutePath(); - QStringList actualArgs; - QString userArgs = qs->userArguments(); - // This copies the settings from userArgs to actualArgs (minus some we - // are not interested in), splitting them up into individual strings: - extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs); - actualArgs = qs->deducedArguments() + actualArgs; - FileName actualSpec = qs->mkspec(); - - QString qmakeArgs = result.second; - QStringList parsedArgs; - FileName parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs); - - if (debug) { - qDebug() << "Actual args:" << actualArgs; - qDebug() << "Parsed args:" << parsedArgs; - qDebug() << "Actual spec:" << actualSpec.toString(); - qDebug() << "Parsed spec:" << parsedSpec.toString(); - } - - // Comparing the sorted list is obviously wrong - // Though haven written a more complete version - // that managed had around 200 lines and yet faild - // to be actually foolproof at all, I think it's - // not feasible without actually taking the qmake - // command line parsing code - - // Things, sorting gets wrong: - // parameters to positional parameters matter - // e.g. -o -spec is different from -spec -o - // -o 1 -spec 2 is diffrent from -spec 1 -o 2 - // variable assignment order matters - // variable assignment vs -after - // -norecursive vs. recursive - actualArgs.sort(); - parsedArgs.sort(); - if (actualArgs == parsedArgs) { - // Specs match exactly - if (actualSpec == parsedSpec) - return MakefileMatches; - // Actual spec is the default one -// qDebug() << "AS vs VS" << actualSpec << version->mkspec(); - if ((actualSpec == version->mkspec() || actualSpec == FileName::fromLatin1("default")) - && (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty())) - return MakefileMatches; - } - return MakefileIncompatible; - } else { - if (debug) - qDebug() << "different qmake buildconfigurations buildconfiguration:" - << qmakeBuildConfiguration() << " Makefile:" << result.first; - return MakefileIncompatible; - } - } else { - if (debug) - qDebug() << "different Qt versions, buildconfiguration:" << version->qmakeCommand().toString() - << " Makefile:"<< qmakePath.toString(); - return MakefileForWrongProject; - } + MakeFileParse parse(makefile); + + if (parse.makeFileState() == MakeFileParse::MakefileMissing) { + qCDebug(logs) << "**Makefile missing"; + return MakefileMissing; + } + if (parse.makeFileState() == MakeFileParse::CouldNotParse) { + qCDebug(logs) << "**Makefile incompatible"; + return MakefileIncompatible; } - return MakefileMissing; -} -bool QmakeBuildConfiguration::removeQMLInspectorFromArguments(QString *args) -{ - bool removedArgument = false; - for (QtcProcess::ArgIterator ait(args); ait.next(); ) { - const QString arg = ait.value(); - if (arg.contains(QLatin1String(Constants::QMAKEVAR_QMLJSDEBUGGER_PATH)) - || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK1_DEBUG)) - || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK2_DEBUG))) { - ait.deleteArg(); - removedArgument = true; - } + if (!qs) { + qCDebug(logs) << "**No qmake step"; + return MakefileMissing; + } + + BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit()); + if (!version) { + qCDebug(logs) << "**No qt version in kit"; + return MakefileForWrongProject; + } + + if (parse.srcProFile() != qs->project()->projectFilePath().toString()) { + qCDebug(logs) << "**Different profile used to generate the Makefile:" + << parse.srcProFile() << " expected profile:" << qs->project()->projectFilePath(); + return MakefileIncompatible; + } + + if (version->qmakeCommand() != parse.qmakePath()) { + qCDebug(logs) << "**Different Qt versions, buildconfiguration:" << version->qmakeCommand().toString() + << " Makefile:"<< parse.qmakePath().toString(); + return MakefileForWrongProject; + } + + // same qtversion + BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig()); + if (qmakeBuildConfiguration() != buildConfig) { + qCDebug(logs) << "**Different qmake buildconfigurations buildconfiguration:" + << qmakeBuildConfiguration() << " Makefile:" << buildConfig; + return MakefileIncompatible; + } + + // The qmake Build Configuration are the same, + // now compare arguments lists + // we have to compare without the spec/platform cmd argument + // and compare that on its own + QString workingDirectory = QFileInfo(makefile).absolutePath(); + QStringList actualArgs; + QString userArgs = qs->userArguments(); + // This copies the settings from userArgs to actualArgs (minus some we + // are not interested in), splitting them up into individual strings: + extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs); + FileName actualSpec = qs->mkspec(); + + QString qmakeArgs = parse.unparsedArguments(); + QStringList parsedArgs; + FileName parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs); + + qCDebug(logs) << " Actual args:" << actualArgs; + qCDebug(logs) << " Parsed args:" << parsedArgs; + qCDebug(logs) << " Actual spec:" << actualSpec.toString(); + qCDebug(logs) << " Parsed spec:" << parsedSpec.toString(); + qCDebug(logs) << " Actual config:" << qs->deducedArguments(); + qCDebug(logs) << " Parsed config:" << parse.config(); + + // Comparing the sorted list is obviously wrong + // Though haven written a more complete version + // that managed had around 200 lines and yet faild + // to be actually foolproof at all, I think it's + // not feasible without actually taking the qmake + // command line parsing code + + // Things, sorting gets wrong: + // parameters to positional parameters matter + // e.g. -o -spec is different from -spec -o + // -o 1 -spec 2 is diffrent from -spec 1 -o 2 + // variable assignment order matters + // variable assignment vs -after + // -norecursive vs. recursive + actualArgs.sort(); + parsedArgs.sort(); + if (actualArgs != parsedArgs) { + qCDebug(logs) << "**Mismateched args"; + return MakefileIncompatible; } - return removedArgument; + + if (parse.config() != qs->deducedArguments()) { + qCDebug(logs) << "**Mismatched config"; + return MakefileIncompatible; + } + + // Specs match exactly + if (actualSpec == parsedSpec) { + qCDebug(logs) << "**Matched specs (1)"; + return MakefileMatches; + } + // Actual spec is the default one +// qDebug() << "AS vs VS" << actualSpec << version->mkspec(); + if ((actualSpec == version->mkspec() || actualSpec == FileName::fromLatin1("default")) + && (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty())) { + qCDebug(logs) << "**Matched specs (2)"; + return MakefileMatches; + } + + qCDebug(logs) << "**Incompatible specs"; + return MakefileIncompatible; } FileName QmakeBuildConfiguration::extractSpecFromArguments(QString *args, @@ -499,52 +512,6 @@ FileName QmakeBuildConfiguration::extractSpecFromArguments(QString *args, return parsedSpec; } -QStringList QmakeBuildConfiguration::extractDeducedArguments(QString *args) -{ - QStringList allPossibleDeducedArguments; - allPossibleDeducedArguments << QLatin1String("CONFIG+=x86") - << QLatin1String("CONFIG+=x86_64") - << QLatin1String("CONFIG+=iphonesimulator") - << QLatin1String("CONFIG+=ppc") - << QLatin1String("CONFIG+=ppc64") - << QLatin1String("CONFIG+=iphoneos"); - QStringList result; - for (QtcProcess::ArgIterator ait(args); ait.next(); ) { - QString arg = ait.value(); - if (allPossibleDeducedArguments.contains(arg)) { - result << arg; - ait.deleteArg(); - } - } - return result; -} - -QStringList QmakeBuildConfiguration::deduceArgumentsForTargetAbi(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version) -{ - QStringList arguments; - if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) - && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { - if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { - if (targetAbi.wordWidth() == 32) - arguments << QLatin1String("CONFIG+=x86"); - else if (targetAbi.wordWidth() == 64) - arguments << QLatin1String("CONFIG+=x86_64"); - - const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; - if (version && version->type() == QLatin1String(IOSQT)) // ugly, we can't distinguish between ios and mac toolchains - arguments << QLatin1String("CONFIG+=iphonesimulator"); - } else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) { - if (targetAbi.wordWidth() == 32) - arguments << QLatin1String("CONFIG+=ppc"); - else if (targetAbi.wordWidth() == 64) - arguments << QLatin1String("CONFIG+=ppc64"); - } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) { - arguments << QLatin1String("CONFIG+=iphoneos"); - } - } - return arguments; -} - bool QmakeBuildConfiguration::isEnabled() const { return m_isEnabled; @@ -702,13 +669,13 @@ void QmakeBuildConfigurationFactory::configureBuildConfiguration(Target *parent, cleanSteps->insertStep(0, cleanStep); QString additionalArguments = qmakeInfo->additionalArguments; - - bool enableQmlDebugger - = QmakeBuildConfiguration::removeQMLInspectorFromArguments(&additionalArguments); if (!additionalArguments.isEmpty()) qmakeStep->setUserArguments(additionalArguments); if (!qmakeInfo->makefile.isEmpty()) - qmakeStep->setLinkQmlDebuggingLibrary(enableQmlDebugger); + qmakeStep->setLinkQmlDebuggingLibrary(qmakeInfo->config.linkQmlDebuggingQQ1 + || qmakeInfo->config.linkQmlDebuggingQQ2); + qmakeStep->setSeparateDebugInfo(qmakeInfo->config.separateDebugInfo); + qmakeStep->setUseQtQuickCompiler(qmakeInfo->config.useQtQuickCompiler); bc->setQMakeBuildConfiguration(config); diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index 112e8f10db..f47c551451 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -92,12 +92,9 @@ public: enum MakefileState { MakefileMatches, MakefileForWrongProject, MakefileIncompatible, MakefileMissing }; MakefileState compareToImportFrom(const QString &makefile); - static bool removeQMLInspectorFromArguments(QString *args); static Utils::FileName extractSpecFromArguments(QString *arguments, const QString &directory, const QtSupport::BaseQtVersion *version, QStringList *outArgs = 0); - static QStringList extractDeducedArguments(QString *args); - static QStringList deduceArgumentsForTargetAbi(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); QVariantMap toMap() const; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h index 5aa77d1ee7..87f8fe17ce 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h @@ -32,6 +32,7 @@ #define QMAKEBUILDINFO_H #include "qmakebuildconfiguration.h" +#include "qmakestep.h" #include <projectexplorer/buildinfo.h> #include <projectexplorer/kitmanager.h> @@ -48,6 +49,7 @@ public: ProjectExplorer::BuildConfiguration::BuildType type; QString additionalArguments; QString makefile; + QMakeStepConfig config; bool operator==(const QmakeBuildInfo &o) { return displayName == o.displayName @@ -55,7 +57,8 @@ public: && buildDirectory == o.buildDirectory && kitId == o.kitId && type == o.type - && additionalArguments == o.additionalArguments; + && additionalArguments == o.additionalArguments + && config == o.config; } QList<ProjectExplorer::Task> reportIssues(const QString &projectPath, diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp index 9f41387929..762323c4e1 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp @@ -34,6 +34,8 @@ #include "qmakekitinformation.h" #include "qmakebuildconfiguration.h" #include "qmakeproject.h" +#include "makefileparse.h" +#include "qmakestep.h" #include <coreplugin/icore.h> #include <coreplugin/idocument.h> @@ -52,6 +54,7 @@ #include <QFileInfo> #include <QMessageBox> #include <QStringList> +#include <QLoggingCategory> using namespace ProjectExplorer; using namespace QtSupport; @@ -61,6 +64,7 @@ namespace QmakeProjectManager { namespace Internal { const Core::Id QT_IS_TEMPORARY("Qmake.TempQt"); +const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // ugly QmakeProjectImporter::QmakeProjectImporter(const QString &path) : ProjectImporter(path) @@ -68,47 +72,58 @@ QmakeProjectImporter::QmakeProjectImporter(const QString &path) : QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool silent) { + const auto &logs = MakeFileParse::logging(); + qCDebug(logs) << "QmakeProjectImporter::import" << importPath << silent; + QList<BuildInfo *> result; QFileInfo fi = importPath.toFileInfo(); - if (!fi.exists() && !fi.isDir()) + if (!fi.exists() && !fi.isDir()) { + qCDebug(logs) << "**doesn't exist"; return result; + } QStringList makefiles = QDir(importPath.toString()).entryList(QStringList(QLatin1String("Makefile*"))); + qCDebug(logs) << " Makefiles:" << makefiles; - BaseQtVersion *version = 0; bool temporaryVersion = false; foreach (const QString &file, makefiles) { + qCDebug(logs) << " Parsing makefile" << file; // find interesting makefiles QString makefile = importPath.toString() + QLatin1Char('/') + file; - FileName qmakeBinary = QtVersionManager::findQMakeBinaryFromMakefile(makefile); - QFileInfo qmakeFi = qmakeBinary.toFileInfo(); + MakeFileParse parse(makefile); + QFileInfo qmakeFi = parse.qmakePath().toFileInfo(); FileName canonicalQmakeBinary = FileName::fromString(qmakeFi.canonicalFilePath()); - if (canonicalQmakeBinary.isEmpty()) + if (canonicalQmakeBinary.isEmpty()) { + qCDebug(logs) << " " << parse.qmakePath() << "doesn't exist anymore"; continue; - if (QtVersionManager::makefileIsFor(makefile, projectFilePath()) != QtVersionManager::SameProject) + } + if (parse.srcProFile() != projectFilePath()) { + qCDebug(logs) << " pro files doesn't match" << parse.srcProFile() << projectFilePath(); continue; - - // Find version: - foreach (BaseQtVersion *v, QtVersionManager::versions()) { - QFileInfo vfi = v->qmakeCommand().toFileInfo(); - FileName current = FileName::fromString(vfi.canonicalFilePath()); - if (current == canonicalQmakeBinary) { - version = v; - break; - } } + qCDebug(logs) << " QMake:" << canonicalQmakeBinary; + + BaseQtVersion *version + = Utils::findOrDefault(QtVersionManager::versions(), + [&canonicalQmakeBinary](BaseQtVersion *v) -> bool { + QFileInfo vfi = v->qmakeCommand().toFileInfo(); + FileName current = FileName::fromString(vfi.canonicalFilePath()); + return current == canonicalQmakeBinary; + }); + if (version) { // Check if version is a temporary qt int qtId = version->uniqueId(); temporaryVersion = Utils::anyOf(KitManager::kits(), [&qtId](Kit *k){ return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId; }); + qCDebug(logs) << " qt version already exist. Temporary:" << temporaryVersion; } else { // Create a new version if not found: // Do not use the canonical path here... - version = QtVersionFactory::createQtVersionFromQMakePath(qmakeBinary); + version = QtVersionFactory::createQtVersionFromQMakePath(parse.qmakePath()); if (!version) continue; @@ -116,28 +131,58 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool QtVersionManager::addVersion(version); setIsUpdating(oldIsUpdating); temporaryVersion = true; + qCDebug(logs) << " created new qt version"; } - // find qmake arguments and mkspec - QPair<BaseQtVersion::QmakeBuildConfigs, QString> makefileBuildConfig = - QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig()); + QMakeStepConfig::TargetArchConfig archConfig = parse.config().archConfig; + QMakeStepConfig::OsType osType = parse.config().osType; + qCDebug(logs) << " archConfig:" << archConfig; + qCDebug(logs) << " osType: " << osType; + if (version->type() == QLatin1String(IOSQT) + && osType == QMakeStepConfig::NoOsType) { + osType = QMakeStepConfig::IphoneOS; + qCDebug(logs) << " IOS found without osType, adjusting osType" << osType; + } - QString additionalArguments = makefileBuildConfig.second; + if (version->type() == QLatin1String(Constants::DESKTOPQT)) { + QList<ProjectExplorer::Abi> abis = version->qtAbis(); + if (!abis.isEmpty()) { + ProjectExplorer::Abi abi = abis.first(); + if (abi.os() == ProjectExplorer::Abi::MacOS) { + if (abi.wordWidth() == 64) + archConfig = QMakeStepConfig::X86_64; + else + archConfig = QMakeStepConfig::X86; + qCDebug(logs) << " OS X found without targetarch, adjusting archType" << archConfig; + } + } + } + + + // find qmake arguments and mkspec + QString additionalArguments = parse.unparsedArguments(); + qCDebug(logs) << " Unparsed arguments:" << additionalArguments; FileName parsedSpec = QmakeBuildConfiguration::extractSpecFromArguments(&additionalArguments, importPath.toString(), version); - QStringList deducedArguments = - QmakeBuildConfiguration::extractDeducedArguments(&additionalArguments); + qCDebug(logs) << " Extracted spec:" << parsedSpec; + qCDebug(logs) << " Arguments now:" << additionalArguments; FileName versionSpec = version->mkspec(); - if (parsedSpec.isEmpty() || parsedSpec == FileName::fromLatin1("default")) + if (parsedSpec.isEmpty() || parsedSpec == FileName::fromLatin1("default")) { parsedSpec = versionSpec; + qCDebug(logs) << " No parsed spec or default spec => parsed spec now:" << parsedSpec; + } QString specArgument; // Compare mkspecs and add to additional arguments - if (parsedSpec != versionSpec) + if (parsedSpec != versionSpec) { specArgument = QLatin1String("-spec ") + QtcProcess::quoteArg(parsedSpec.toUserOutput()); - QtcProcess::addArgs(&specArgument, additionalArguments); + QtcProcess::addArgs(&specArgument, additionalArguments); + qCDebug(logs) << " custom spec added to additionalArguments:" << additionalArguments; + } + qCDebug(logs) << "*******************"; + qCDebug(logs) << "* Looking for kits"; // Find kits (can be more than one, e.g. (Linux-)Desktop and embedded linux): QList<Kit *> kitList; foreach (Kit *k, KitManager::kits()) { @@ -146,17 +191,23 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool ToolChain *tc = ToolChainKitInformation::toolChain(k); if (kitSpec.isEmpty() && kitVersion) kitSpec = kitVersion->mkspecFor(tc); - QStringList kitDeducedArguments; - if (tc) - kitDeducedArguments = QmakeBuildConfiguration::deduceArgumentsForTargetAbi(tc->targetAbi(), kitVersion); - + QMakeStepConfig::TargetArchConfig kitTargetArch = QMakeStepConfig::targetArchFor(tc->targetAbi(), kitVersion); + QMakeStepConfig::OsType kitOsType = QMakeStepConfig::osTypeFor(tc->targetAbi(), kitVersion); + qCDebug(logs) << k->displayName() + << "version:" << (kitVersion == version) + << "spec:" << (kitSpec == parsedSpec) + << "targetarch:" << (kitTargetArch == archConfig) + << "ostype:" << (kitOsType == osType); if (kitVersion == version && kitSpec == parsedSpec - && kitDeducedArguments == deducedArguments) + && kitTargetArch == archConfig + && kitOsType == osType) kitList.append(k); } - if (kitList.isEmpty()) - kitList.append(createTemporaryKit(version, temporaryVersion, parsedSpec, deducedArguments)); + if (kitList.isEmpty()) { + kitList.append(createTemporaryKit(version, temporaryVersion, parsedSpec, archConfig, osType)); + qCDebug(logs) << " No matching kits found, created new kit"; + } foreach (Kit *k, kitList) { addProject(k); @@ -169,7 +220,8 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool // create info: QmakeBuildInfo *info = new QmakeBuildInfo(factory); - if (makefileBuildConfig.first & BaseQtVersion::DebugBuild) { + BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig()); + if (buildConfig & BaseQtVersion::DebugBuild) { info->type = BuildConfiguration::Debug; info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Debug"); } else { @@ -179,6 +231,7 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool info->kitId = k->id(); info->buildDirectory = FileName::fromString(fi.absoluteFilePath()); info->additionalArguments = additionalArguments; + info->config = parse.config(); info->makefile = makefile; bool found = false; @@ -289,7 +342,7 @@ void QmakeProjectImporter::makePermanent(Kit *k) ProjectImporter::makePermanent(k); } -static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &ms, const QStringList &deducedArguments) +static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &ms, const QMakeStepConfig::TargetArchConfig &archConfig) { const FileName spec = ms.isEmpty() ? qtVersion->mkspec() : ms; @@ -297,25 +350,27 @@ static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &m QList<Abi> qtAbis = qtVersion->qtAbis(); return findOr(toolchains, toolchains.isEmpty() ? 0 : toolchains.first(), - [&spec, &deducedArguments, &qtAbis](ToolChain *tc) -> bool{ + [&spec, &archConfig, &qtAbis, &qtVersion](ToolChain *tc) -> bool{ return qtAbis.contains(tc->targetAbi()) && tc->suggestedMkspecList().contains(spec) - && QmakeBuildConfiguration::deduceArgumentsForTargetAbi(tc->targetAbi(), 0) == deducedArguments; + && QMakeStepConfig::targetArchFor(tc->targetAbi(), qtVersion) == archConfig; }); } Kit *QmakeProjectImporter::createTemporaryKit(BaseQtVersion *version, bool temporaryVersion, const FileName &parsedSpec, - const QStringList &deducedQmakeArguments) + const QMakeStepConfig::TargetArchConfig &archConfig, + const QMakeStepConfig::OsType &osType) { + Q_UNUSED(osType); // TODO use this to select the right toolchain? Kit *k = new Kit; bool oldIsUpdating = setIsUpdating(true); { KitGuard guard(k); QtKitInformation::setQtVersion(k, version); - ToolChainKitInformation::setToolChain(k, preferredToolChain(version, parsedSpec, deducedQmakeArguments)); + ToolChainKitInformation::setToolChain(k, preferredToolChain(version, parsedSpec, archConfig)); QmakeKitInformation::setMkspec(k, parsedSpec); markTemporary(k); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h index 2e5336ed18..f0f006eb6c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h @@ -31,6 +31,8 @@ #ifndef QMAKEPROJECTIMPORTER_H #define QMAKEPROJECTIMPORTER_H +#include "qmakestep.h" + #include <projectexplorer/projectimporter.h> namespace QtSupport { class BaseQtVersion; } @@ -58,7 +60,8 @@ public: private: ProjectExplorer::Kit *createTemporaryKit(QtSupport::BaseQtVersion *version, bool temporaryVersion, - const Utils::FileName &parsedSpec, const QStringList &deducedQmakeArguments); + const Utils::FileName &parsedSpec, + const QmakeProjectManager::QMakeStepConfig::TargetArchConfig &archConfig, const QMakeStepConfig::OsType &osType); }; } // namespace Internal diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro index af4371dd0a..204ea2adf4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro @@ -51,7 +51,8 @@ HEADERS += \ findqmakeprofiles.h \ qmakeprojectmanager_global.h \ desktopqmakerunconfiguration.h \ - profilecompletionassist.h + profilecompletionassist.h \ + makefileparse.h SOURCES += \ qmakekitconfigwidget.cpp \ @@ -98,6 +99,7 @@ SOURCES += \ findqmakeprofiles.cpp \ desktopqmakerunconfiguration.cpp \ profilecompletionassist.cpp \ + makefileparse.cpp FORMS += makestep.ui \ qmakestep.ui \ diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs index 13a7c4d607..24e1d9f158 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs @@ -28,6 +28,7 @@ QtcPlugin { "librarydetailscontroller.cpp", "librarydetailscontroller.h", "librarydetailswidget.ui", "makestep.cpp", "makestep.h", "makestep.ui", + "makefileparse.cpp", "makefileparse.h", "profilecompletionassist.cpp", "profilecompletionassist.h", "profileeditor.cpp", "profileeditor.h", "profilehighlighter.cpp", "profilehighlighter.h", diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h index 077c55dbf9..15ba074051 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h @@ -72,11 +72,6 @@ const char QMAKEPROJECT_ID[] = "Qt4ProjectManager.Qt4Project"; // ICONS const char ICON_QTQUICK_APP[] = ":/wizards/images/qtquickapp.png"; -// Env variables -const char QMAKEVAR_QMLJSDEBUGGER_PATH[] = "QMLJSDEBUGGER_PATH"; -const char QMAKEVAR_QUICK1_DEBUG[] = "CONFIG+=declarative_debug"; -const char QMAKEVAR_QUICK2_DEBUG[] = "CONFIG+=qml_debug"; - } // namespace Constants } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 76ae18bca0..0f69f809c9 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -49,6 +49,7 @@ #include <qtsupport/debugginghelperbuildtask.h> #include <qtsupport/qtkitinformation.h> #include <qtsupport/qtversionmanager.h> +#include <qtsupport/qtsupportconstants.h> #include <utils/algorithm.h> #include <utils/hostosinfo.h> #include <utils/qtcprocess.h> @@ -58,6 +59,7 @@ using namespace QmakeProjectManager; using namespace QmakeProjectManager::Internal; +using namespace QtSupport; using namespace ProjectExplorer; using namespace Utils; @@ -154,7 +156,7 @@ QString QMakeStep::allArguments(bool shorted) // Find out what flags we pass on to qmake arguments << bc->configCommandLineArguments(); - arguments << deducedArguments(); + arguments << deducedArguments().toArguments(); QString args = QtcProcess::joinArgs(arguments); // User arguments @@ -162,40 +164,36 @@ QString QMakeStep::allArguments(bool shorted) return args; } -/// -/// moreArguments, -/// iphoneos/iphonesimulator for ios -/// QMAKE_VAR_QMLJSDEBUGGER_PATH -QStringList QMakeStep::deducedArguments() +QMakeStepConfig QMakeStep::deducedArguments() { - QStringList arguments; + ProjectExplorer::Kit *kit = target()->kit(); + QMakeStepConfig config; ProjectExplorer::ToolChain *tc - = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit()); + = ProjectExplorer::ToolChainKitInformation::toolChain(kit); ProjectExplorer::Abi targetAbi; if (tc) targetAbi = tc->targetAbi(); - // explicitly add architecture to CONFIG - QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); - arguments << QmakeBuildConfiguration::deduceArgumentsForTargetAbi(targetAbi, version); + + config.archConfig = QMakeStepConfig::targetArchFor(targetAbi, version); + config.osType = QMakeStepConfig::osTypeFor(targetAbi, version); if (linkQmlDebuggingLibrary() && version) { - arguments << QLatin1String(Constants::QMAKEVAR_QUICK1_DEBUG); + config.linkQmlDebuggingQQ1 = true; if (version->qtVersion().majorVersion >= 5) - arguments << QLatin1String(Constants::QMAKEVAR_QUICK2_DEBUG); + config.linkQmlDebuggingQQ2 = true; } if (useQtQuickCompiler() && version) - arguments << QLatin1String("CONFIG+=qtquickcompiler"); + config.useQtQuickCompiler = true; - if (separateDebugInfo()) { - arguments << QLatin1String("CONFIG+=force_debug_info") - << QLatin1String("CONFIG+=separate_debug_info"); - } + if (separateDebugInfo()) + config.separateDebugInfo = true; - return arguments; + return config; } + bool QMakeStep::init() { QmakeBuildConfiguration *qt4bc = qmakeBuildConfiguration(); @@ -822,3 +820,76 @@ QString QMakeStepFactory::displayNameForId(Core::Id id) const return tr("qmake"); return QString(); } + + +QMakeStepConfig::TargetArchConfig QMakeStepConfig::targetArchFor(const Abi &targetAbi, const BaseQtVersion *version) +{ + QMakeStepConfig::TargetArchConfig arch = QMakeStepConfig::NoArch; + if (!version || version->type() != QLatin1String(QtSupport::Constants::DESKTOPQT)) + return arch; + if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) + && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { + if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { + if (targetAbi.wordWidth() == 32) + arch = QMakeStepConfig::X86; + else if (targetAbi.wordWidth() == 64) + arch = QMakeStepConfig::X86_64; + } else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) { + if (targetAbi.wordWidth() == 32) + arch = QMakeStepConfig::PPC; + else if (targetAbi.wordWidth() == 64) + arch = QMakeStepConfig::PPC64; + } + } + return arch; +} + +QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version) +{ + QMakeStepConfig::OsType os = QMakeStepConfig::NoOsType; + const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; + if (!version || version->type() != QLatin1String(IOSQT)) + return os; + if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) + && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { + if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { + os = QMakeStepConfig::IphoneSimulator; + } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) { + os = QMakeStepConfig::IphoneOS; + } + } + return os; +} + +QStringList QMakeStepConfig::toArguments() const +{ + QStringList arguments; + if (archConfig == X86) + arguments << QLatin1String("CONFIG+=x86"); + else if (archConfig == X86_64) + arguments << QLatin1String("CONFIG+=x86_64"); + else if (archConfig == PPC) + arguments << QLatin1String("CONFIG+=ppc"); + else if (archConfig == PPC64) + arguments << QLatin1String("CONFIG+=ppc64"); + + if (osType == IphoneSimulator) + arguments << QLatin1String("CONFIG+=iphonesimulator"); + else if (osType == IphoneOS) + arguments << QLatin1String("CONFIG+=iphoneos"); + + if (linkQmlDebuggingQQ1) + arguments << QLatin1String("CONFIG+=declarative_debug"); + if (linkQmlDebuggingQQ2) + arguments << QLatin1String("CONFIG+=qml_debug"); + + if (useQtQuickCompiler) + arguments << QLatin1String("CONFIG+=qtquickcompiler"); + + if (separateDebugInfo) + arguments << QLatin1String("CONFIG+=force_debug_info") + << QLatin1String("CONFIG+=separate_debug_info"); + + return arguments; +} + diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index 6314533dbf..85891a7fff 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -36,14 +36,20 @@ #include <QStringList> +#include <tuple> + namespace Utils { class FileName; } namespace ProjectExplorer { +class Abi; class BuildStep; class IBuildStepFactory; class Project; +class Kit; } +namespace QtSupport { class BaseQtVersion; } + namespace QmakeProjectManager { class QmakeBuildConfiguration; class QmakeProject; @@ -71,6 +77,56 @@ public: } // namespace Internal +class QMAKEPROJECTMANAGER_EXPORT QMakeStepConfig +{ +public: + enum TargetArchConfig { + NoArch, X86, X86_64, PPC, PPC64 + }; + + enum OsType { + NoOsType, IphoneSimulator, IphoneOS + }; + + static TargetArchConfig targetArchFor(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); + static OsType osTypeFor(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); + + + QMakeStepConfig() + : archConfig(NoArch), + osType(NoOsType), + linkQmlDebuggingQQ1(false), + linkQmlDebuggingQQ2(false), + useQtQuickCompiler(false), + separateDebugInfo(false) + {} + + QStringList toArguments() const; + + // Actual data + TargetArchConfig archConfig; + OsType osType; + bool linkQmlDebuggingQQ1; + bool linkQmlDebuggingQQ2; + bool useQtQuickCompiler; + bool separateDebugInfo; +}; + + +inline bool operator ==(const QMakeStepConfig &a, const QMakeStepConfig &b) { + return std::tie(a.archConfig, a.osType, a.linkQmlDebuggingQQ1, a.linkQmlDebuggingQQ2, a.useQtQuickCompiler, a.separateDebugInfo) + == std::tie(b.archConfig, b.osType, b.linkQmlDebuggingQQ1, b.linkQmlDebuggingQQ2, b.useQtQuickCompiler, b.separateDebugInfo); +} + +inline bool operator !=(const QMakeStepConfig &a, const QMakeStepConfig &b) { + return !(a == b); +} + +inline QDebug operator<<(QDebug dbg, const QMakeStepConfig &c) +{ + dbg << c.archConfig << c.osType << c.linkQmlDebuggingQQ1 << c.linkQmlDebuggingQQ2 << c.useQtQuickCompiler << c.separateDebugInfo; + return dbg; +} class QMAKEPROJECTMANAGER_EXPORT QMakeStep : public ProjectExplorer::AbstractProcessStep { @@ -100,8 +156,7 @@ public: // the complete argument line QString allArguments(bool shorted = false); - // deduced arguments e.g. qmljs debugging - QStringList deducedArguments(); + QMakeStepConfig deducedArguments(); // arguments passed to the pro file parser QStringList parserArguments(); // arguments set by the user diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index ea1e99851b..7513ad40e3 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -64,13 +64,6 @@ namespace QtSupport { using namespace Internal; -struct QMakeAssignment -{ - QString variable; - QString op; - QString value; -}; - const char QTVERSION_DATA_KEY[] = "QtVersion."; const char QTVERSION_TYPE_KEY[] = "QtVersion.Type"; const char QTVERSION_FILE_VERSION_KEY[] = "Version"; @@ -107,36 +100,6 @@ bool qtVersionNumberCompare(BaseQtVersion *a, BaseQtVersion *b) { return a->qtVersion() > b->qtVersion() || (a->qtVersion() == b->qtVersion() && a->uniqueId() < b->uniqueId()); } - -static QString findQMakeLine(const QString &makefile, const QString &key) -{ - QFile fi(makefile); - if (fi.exists() && fi.open(QFile::ReadOnly)) { - QTextStream ts(&fi); - while (!ts.atEnd()) { - const QString line = ts.readLine(); - if (line.startsWith(key)) - return line; - } - } - return QString(); -} - -/// This function trims the "#Command /path/to/qmake" from the line -static QString trimLine(const QString &line) -{ - - // Actually the first space after #Command: /path/to/qmake - const int firstSpace = line.indexOf(QLatin1Char(' '), 11); - return line.mid(firstSpace).trimmed(); -} - -static void parseArgs(const QString &args, - QList<QMakeAssignment> *assignments, - QList<QMakeAssignment> *afterAssignments, - QString *additionalArguments); -static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments, - BaseQtVersion::QmakeBuildConfigs defaultBuildConfig); static bool restoreQtVersions(); static void findSystemQt(); static void saveQtVersions(); @@ -608,210 +571,9 @@ void QtVersionManager::setNewQtVersions(QList<BaseQtVersion *> newVersions) emit m_instance->qtVersionsChanged(addedVersions, removedVersions, changedVersions); } -// Returns the version that was used to build the project in that directory -// That is returns the directory -// To find out whether we already have a qtversion for that directory call -// QtVersion *QtVersionManager::qtVersionForDirectory(const QString directory); -FileName QtVersionManager::findQMakeBinaryFromMakefile(const QString &makefile) -{ - bool debugAdding = false; - QFile fi(makefile); - if (fi.exists() && fi.open(QFile::ReadOnly)) { - QTextStream ts(&fi); - QRegExp r1(QLatin1String("QMAKE\\s*=(.*)")); - while (!ts.atEnd()) { - QString line = ts.readLine(); - if (r1.exactMatch(line)) { - if (debugAdding) - qDebug()<<"#~~ QMAKE is:"<<r1.cap(1).trimmed(); - QFileInfo qmake(r1.cap(1).trimmed()); - QString qmakePath = qmake.filePath(); - if (!QString::fromLatin1(QTC_HOST_EXE_SUFFIX).isEmpty() - && !qmakePath.endsWith(QLatin1String(QTC_HOST_EXE_SUFFIX))) { - qmakePath.append(QLatin1String(QTC_HOST_EXE_SUFFIX)); - } - // Is qmake still installed? - QFileInfo fi(qmakePath); - if (fi.exists()) - return FileName(fi); - } - } - } - return FileName(); -} - BaseQtVersion *QtVersionManager::qtVersionForQMakeBinary(const FileName &qmakePath) { return Utils::findOrDefault(versions(), Utils::equal(&BaseQtVersion::qmakeCommand, qmakePath)); } -void dumpQMakeAssignments(const QList<QMakeAssignment> &list) -{ - foreach (const QMakeAssignment &qa, list) { - qDebug()<<qa.variable<<qa.op<<qa.value; - } -} - -QtVersionManager::MakefileCompatible QtVersionManager::makefileIsFor(const QString &makefile, const QString &proFile) -{ - if (proFile.isEmpty()) - return CouldNotParse; - - // The Makefile.Debug / Makefile.Release lack a # Command: line - if (findQMakeLine(makefile, QLatin1String("# Command:")).trimmed().isEmpty()) - return CouldNotParse; - - QString line = findQMakeLine(makefile, QLatin1String("# Project:")).trimmed(); - if (line.isEmpty()) - return CouldNotParse; - - line.remove(0, line.indexOf(QLatin1Char(':')) + 1); - line = line.trimmed(); - - QFileInfo srcFileInfo(QFileInfo(makefile).absoluteDir(), line); - QFileInfo proFileInfo(proFile); - return (srcFileInfo == proFileInfo) ? SameProject : DifferentProject; -} - -QPair<BaseQtVersion::QmakeBuildConfigs, QString> QtVersionManager::scanMakeFile(const QString &makefile, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) -{ - if (debug) - qDebug()<<"ScanMakeFile, the gory details:"; - BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig; - QString result2; - - QString line = findQMakeLine(makefile, QLatin1String("# Command:")); - if (!line.isEmpty()) { - if (debug) - qDebug()<<"Found line"<<line; - line = trimLine(line); - QList<QMakeAssignment> assignments; - QList<QMakeAssignment> afterAssignments; - parseArgs(line, &assignments, &afterAssignments, &result2); - - if (debug) { - dumpQMakeAssignments(assignments); - if (!afterAssignments.isEmpty()) - qDebug()<<"-after"; - dumpQMakeAssignments(afterAssignments); - } - - // Search in assignments for CONFIG(+=,-=,=)(debug,release,debug_and_release) - // Also remove them from the list - result = qmakeBuildConfigFromCmdArgs(&assignments, defaultBuildConfig); - - if (debug) - dumpQMakeAssignments(assignments); - - foreach (const QMakeAssignment &qa, assignments) - QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); - if (!afterAssignments.isEmpty()) { - QtcProcess::addArg(&result2, QLatin1String("-after")); - foreach (const QMakeAssignment &qa, afterAssignments) - QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); - } - } - - // Dump the gathered information: - if (debug) { - qDebug()<<"\n\nDumping information from scanMakeFile"; - qDebug()<<"QMake CONFIG variable parsing"; - qDebug()<<" "<< (result & BaseQtVersion::NoBuild ? QByteArray("No Build") : QByteArray::number(int(result))); - qDebug()<<" "<< (result & BaseQtVersion::DebugBuild ? "debug" : "release"); - qDebug()<<" "<< (result & BaseQtVersion::BuildAll ? "debug_and_release" : "no debug_and_release"); - qDebug()<<"\nAddtional Arguments"; - qDebug()<<result2; - qDebug()<<"\n\n"; - } - return qMakePair(result, result2); -} - -static void parseArgs(const QString &args, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments, QString *additionalArguments) -{ - QRegExp regExp(QLatin1String("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)")); - bool after = false; - bool ignoreNext = false; - *additionalArguments = args; - QtcProcess::ArgIterator ait(additionalArguments); - while (ait.next()) { - if (ignoreNext) { - // Ignoring - ignoreNext = false; - ait.deleteArg(); - } else if (ait.value() == QLatin1String("-after")) { - after = true; - ait.deleteArg(); - } else if (ait.value().contains(QLatin1Char('='))) { - if (regExp.exactMatch(ait.value())) { - QMakeAssignment qa; - qa.variable = regExp.cap(1); - qa.op = regExp.cap(2); - qa.value = regExp.cap(3).trimmed(); - if (after) - afterAssignments->append(qa); - else - assignments->append(qa); - } else { - qDebug()<<"regexp did not match"; - } - ait.deleteArg(); - } else if (ait.value() == QLatin1String("-o")) { - ignoreNext = true; - ait.deleteArg(); -#if defined(Q_OS_WIN32) - } else if (ait.value() == QLatin1String("-win32")) { -#elif defined(Q_OS_MAC) - } else if (ait.value() == QLatin1String("-macx")) { -#elif defined(Q_OS_QNX6) - } else if (ait.value() == QLatin1String("-qnx6")) { -#else - } else if (ait.value() == QLatin1String("-unix")) { -#endif - ait.deleteArg(); - } - } - ait.deleteArg(); // The .pro file is always the last arg -} - -/// This function extracts all the CONFIG+=debug, CONFIG+=release -static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) -{ - BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig; - QList<QMakeAssignment> oldAssignments = *assignments; - assignments->clear(); - foreach (const QMakeAssignment &qa, oldAssignments) { - if (qa.variable == QLatin1String("CONFIG")) { - QStringList values = qa.value.split(QLatin1Char(' ')); - QStringList newValues; - foreach (const QString &value, values) { - if (value == QLatin1String("debug")) { - if (qa.op == QLatin1String("+=")) - result = result | BaseQtVersion::DebugBuild; - else - result = result & ~BaseQtVersion::DebugBuild; - } else if (value == QLatin1String("release")) { - if (qa.op == QLatin1String("+=")) - result = result & ~BaseQtVersion::DebugBuild; - else - result = result | BaseQtVersion::DebugBuild; - } else if (value == QLatin1String("debug_and_release")) { - if (qa.op == QLatin1String("+=")) - result = result | BaseQtVersion::BuildAll; - else - result = result & ~BaseQtVersion::BuildAll; - } else { - newValues.append(value); - } - QMakeAssignment newQA = qa; - newQA.value = newValues.join(QLatin1Char(' ')); - if (!newValues.isEmpty()) - assignments->append(newQA); - } - } else { - assignments->append(qa); - } - } - return result; -} - } // namespace QtVersion diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h index d70b67d20c..0754a56675 100644 --- a/src/plugins/qtsupport/qtversionmanager.h +++ b/src/plugins/qtsupport/qtversionmanager.h @@ -66,11 +66,6 @@ public: static void addVersion(BaseQtVersion *version); static void removeVersion(BaseQtVersion *version); - enum MakefileCompatible { CouldNotParse, DifferentProject, SameProject }; - static MakefileCompatible makefileIsFor(const QString &makefile, const QString &proFile); - static QPair<BaseQtVersion::QmakeBuildConfigs, QString> scanMakeFile(const QString &makefile, - BaseQtVersion::QmakeBuildConfigs defaultBuildConfig); - static Utils::FileName findQMakeBinaryFromMakefile(const QString &directory); static bool isValidId(int id); signals: diff --git a/src/plugins/subversion/subversionsubmiteditor.cpp b/src/plugins/subversion/subversionsubmiteditor.cpp index 9483d720bc..21186879c8 100644 --- a/src/plugins/subversion/subversionsubmiteditor.cpp +++ b/src/plugins/subversion/subversionsubmiteditor.cpp @@ -47,13 +47,14 @@ void SubversionSubmitEditor::setStatusList(const QList<StatusFilePair> &statusOu { typedef QList<StatusFilePair>::const_iterator ConstIterator; auto model = new VcsBase::SubmitFileModel(this); + // Hack to allow completion in "description" field : completion needs a root repository, the + // checkScriptWorkingDirectory property is fine (at this point it was set by SubversionPlugin) + model->setRepositoryRoot(checkScriptWorkingDirectory()); const ConstIterator cend = statusOutput.constEnd(); for (ConstIterator it = statusOutput.constBegin(); it != cend; ++it) model->addFile(it->second, it->first); - // Hack to allow completion in "description" field : completion needs a root repository, the - // checkScriptWorkingDirectory property is fine (at this point it was set by SubversionPlugin) - setFileModel(model, this->checkScriptWorkingDirectory()); + setFileModel(model); } QByteArray SubversionSubmitEditor::fileContents() const diff --git a/src/plugins/vcsbase/submitfilemodel.cpp b/src/plugins/vcsbase/submitfilemodel.cpp index 354bd39c66..8bfbba6036 100644 --- a/src/plugins/vcsbase/submitfilemodel.cpp +++ b/src/plugins/vcsbase/submitfilemodel.cpp @@ -45,8 +45,11 @@ namespace VcsBase { enum { fileColumn = 1 }; -static QList<QStandardItem *> createFileRow(const QString &fileName, const QString &status, - CheckMode checked, const QVariant &v) +static QList<QStandardItem *> createFileRow(const QString &repositoryRoot, + const QString &fileName, + const QString &status, + CheckMode checked, + const QVariant &v) { auto statusItem = new QStandardItem(status); Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; @@ -58,7 +61,11 @@ static QList<QStandardItem *> createFileRow(const QString &fileName, const QStri statusItem->setData(v); auto fileItem = new QStandardItem(fileName); fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - fileItem->setIcon(Core::FileIconProvider::icon(fileName)); + // For some reason, Windows (at least) requires a valid (existing) file path to the icon, so + // the repository root is needed here. + // Note: for "overlaid" icons in Core::FileIconProvider a valid file path is not required + const QFileInfo fi(repositoryRoot + QLatin1Char('/') + fileName); + fileItem->setIcon(Core::FileIconProvider::icon(fi)); QList<QStandardItem *> row; row << statusItem << fileItem; return row; @@ -86,10 +93,20 @@ SubmitFileModel::SubmitFileModel(QObject *parent) : setHorizontalHeaderLabels(headerLabels); } +const QString &SubmitFileModel::repositoryRoot() const +{ + return m_repositoryRoot; +} + +void SubmitFileModel::setRepositoryRoot(const QString &repoRoot) +{ + m_repositoryRoot = repoRoot; +} + QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, CheckMode checkMode, const QVariant &v) { - const QList<QStandardItem *> row = createFileRow(fileName, status, checkMode, v); + const QList<QStandardItem *> row = createFileRow(m_repositoryRoot, fileName, status, checkMode, v); appendRow(row); return row; } diff --git a/src/plugins/vcsbase/submitfilemodel.h b/src/plugins/vcsbase/submitfilemodel.h index ccb17906ba..db5bec44a2 100644 --- a/src/plugins/vcsbase/submitfilemodel.h +++ b/src/plugins/vcsbase/submitfilemodel.h @@ -50,6 +50,9 @@ class VCSBASE_EXPORT SubmitFileModel : public QStandardItemModel public: explicit SubmitFileModel(QObject *parent = 0); + const QString &repositoryRoot() const; + void setRepositoryRoot(const QString &repoRoot); + // Convenience to create and add rows containing a file plus status text. QList<QStandardItem *> addFile(const QString &fileName, const QString &status = QString(), CheckMode checkMode = Checked, const QVariant &data = QVariant()); @@ -69,6 +72,9 @@ public: unsigned int filterFiles(const QStringList &filter); virtual void updateSelections(SubmitFileModel *source); + +private: + QString m_repositoryRoot; }; } // namespace VcsBase diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index b0610527c1..2b40ceb67e 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -432,7 +432,7 @@ QStringList VcsBaseSubmitEditor::checkedFiles() const return d->m_widget->checkedFiles(); } -void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model, const QString &repositoryDirectory) +void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model) { QTC_ASSERT(model, return); if (SubmitFileModel *oldModel = d->m_widget->fileModel()) { @@ -446,7 +446,7 @@ void VcsBaseSubmitEditor::setFileModel(SubmitFileModel *model, const QString &re // Iterate over the files and get interesting symbols for (int row = 0; row < model->rowCount(); ++row) { - const QFileInfo fileInfo(repositoryDirectory, model->file(row)); + const QFileInfo fileInfo(model->repositoryRoot(), model->file(row)); // Add file name uniqueSymbols.insert(fileInfo.fileName()); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h index 4adefffd3b..5bfbf38a52 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.h +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h @@ -121,7 +121,7 @@ public: QStringList checkedFiles() const; - void setFileModel(SubmitFileModel *m, const QString &repositoryDirectory = QString()); + void setFileModel(SubmitFileModel *m); SubmitFileModel *fileModel() const; virtual void updateFileModel() { } QStringList rowsToFiles(const QList<int> &rows) const; diff --git a/src/tools/qmlprofilertool/qmlprofilerapplication.cpp b/src/tools/qmlprofilertool/qmlprofilerapplication.cpp deleted file mode 100644 index 7a6e90dcc2..0000000000 --- a/src/tools/qmlprofilertool/qmlprofilerapplication.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms and -** conditions see http://www.qt.io/terms-conditions. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "qmlprofilerapplication.h" -#include "constants.h" -#include <utils/qtcassert.h> -#include <QStringList> -#include <QTextStream> -#include <QProcess> -#include <QTimer> -#include <QDateTime> -#include <QFileInfo> -#include <QDebug> - -using namespace QmlJsDebugClient; - -static const char usageTextC[] = -"Usage:\n" -" qmlprofiler [options] [program] [program-options]\n" -" qmlprofiler [options] -attach [hostname]\n" -"\n" -"QML Profiler retrieves QML tracing data from a running application.\n" -"The data collected can then be visualized in Qt Creator.\n" -"\n" -"The application to be profiled has to enable QML debugging. See the Qt Creator\n" -"documentation on how to do this for different Qt versions.\n" -"\n" -"Options:\n" -" -help Show this information and exit.\n" -" -fromStart\n" -" Record as soon as the engine is started, default is false.\n" -" -p <number>, -port <number>\n" -" TCP/IP port to use, default is 3768.\n" -" -v, -verbose\n" -" Print debugging output.\n" -" -version\n" -" Show the version of qmlprofiler and exit.\n"; - -static const char commandTextC[] = -"Commands:\n" -" r, record\n" -" Switch recording on or off.\n" -" q, quit\n" -" Terminate program."; - -static const char TraceFileExtension[] = ".qtd"; - -QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) : - QCoreApplication(argc, argv), - m_runMode(LaunchMode), - m_process(0), - m_tracePrefix(QLatin1String("trace")), - m_hostName(QLatin1String("127.0.0.1")), - m_port(3768), - m_verbose(false), - m_quitAfterSave(false), - m_qmlProfilerClient(&m_connection), - m_v8profilerClient(&m_connection), - m_connectionAttempts(0) -{ - m_connectTimer.setInterval(1000); - connect(&m_connectTimer, SIGNAL(timeout()), this, SLOT(tryToConnect())); - - connect(&m_connection, SIGNAL(connected()), this, SLOT(connected())); - connect(&m_connection, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(connectionStateChanged(QAbstractSocket::SocketState))); - connect(&m_connection, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError))); - - connect(&m_qmlProfilerClient, SIGNAL(enabledChanged()), this, SLOT(traceClientEnabled())); - connect(&m_qmlProfilerClient, SIGNAL(recordingChanged(bool)), this, SLOT(recordingChanged())); - connect(&m_qmlProfilerClient, SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)), &m_eventList, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation))); - connect(&m_qmlProfilerClient, SIGNAL(complete()), this, SLOT(qmlComplete())); - - connect(&m_v8profilerClient, SIGNAL(enabledChanged()), this, SLOT(profilerClientEnabled())); - connect(&m_v8profilerClient, SIGNAL(v8range(int,QString,QString,int,double,double)), &m_eventList, SLOT(addV8Event(int,QString,QString,int,double,double))); - connect(&m_v8profilerClient, SIGNAL(complete()), this, SLOT(v8Complete())); - - connect(&m_eventList, SIGNAL(error(QString)), this, SLOT(logError(QString))); - connect(&m_eventList, SIGNAL(dataReady()), this, SLOT(traceFinished())); -} - -QmlProfilerApplication::~QmlProfilerApplication() -{ - if (!m_process) - return; - logStatus("Terminating process..."); - m_process->disconnect(); - m_process->terminate(); - if (!m_process->waitForFinished(1000)) { - logStatus("Killing process..."); - m_process->kill(); - } - delete m_process; -} - -bool QmlProfilerApplication::parseArguments() -{ - for (int argPos = 1; argPos < arguments().size(); ++argPos) { - const QString arg = arguments().at(argPos); - if (arg == QLatin1String("-attach") || arg == QLatin1String("-a")) { - if (argPos + 1 == arguments().size()) - return false; - m_hostName = arguments().at(++argPos); - m_runMode = AttachMode; - } else if (arg == QLatin1String("-port") || arg == QLatin1String("-p")) { - if (argPos + 1 == arguments().size()) - return false; - const QString portStr = arguments().at(++argPos); - bool isNumber; - m_port = portStr.toUShort(&isNumber); - if (!isNumber) { - logError(QString("'%1' is not a valid port").arg(portStr)); - return false; - } - } else if (arg == QLatin1String("-fromStart")) { - m_qmlProfilerClient.setRecording(true); - m_v8profilerClient.setRecording(true); - } else if (arg == QLatin1String("-help") || arg == QLatin1String("-h") || arg == QLatin1String("/h") || arg == QLatin1String("/?")) { - return false; - } else if (arg == QLatin1String("-verbose") || arg == QLatin1String("-v")) { - m_verbose = true; - } else if (arg == QLatin1String("-version")) { - print(QString("QML Profiler based on Qt %1.").arg(qVersion())); - ::exit(1); - return false; - } else { - if (m_programPath.isEmpty()) { - m_programPath = arg; - m_tracePrefix = QFileInfo(m_programPath).fileName(); - } else { - m_programArguments << arg; - } - } - } - - if (m_runMode == LaunchMode - && m_programPath.isEmpty()) - return false; - - if (m_runMode == AttachMode - && !m_programPath.isEmpty()) - return false; - - return true; -} - -void QmlProfilerApplication::printUsage() -{ - print(QLatin1String(usageTextC)); - print(QLatin1String(commandTextC)); -} - -int QmlProfilerApplication::exec() -{ - QTimer::singleShot(0, this, SLOT(run())); - return QCoreApplication::exec(); -} - -void QmlProfilerApplication::printCommands() -{ - print(QLatin1String(commandTextC)); -} - -QString QmlProfilerApplication::traceFileName() const -{ - QString fileName = m_tracePrefix + QLatin1Char('_') + - QDateTime::currentDateTime().toString(QLatin1String("yyMMdd_hhmmss")) + TraceFileExtension; - if (QFileInfo(fileName).exists()) { - QString baseName; - int suffixIndex = 0; - do { - baseName = QFileInfo(fileName).baseName() - + QString::number(suffixIndex++); - } while (QFileInfo(baseName + TraceFileExtension).exists()); - fileName = baseName + TraceFileExtension; - } - - return QFileInfo(fileName).absoluteFilePath(); -} - -void QmlProfilerApplication::userCommand(const QString &command) -{ - QString cmd = command.trimmed(); - if (cmd == Constants::CMD_HELP - || cmd == Constants::CMD_HELP2 - || cmd == Constants::CMD_HELP3) { - printCommands(); - } else if (cmd == Constants::CMD_RECORD - || cmd == Constants::CMD_RECORD2) { - m_qmlProfilerClient.setRecording(!m_qmlProfilerClient.isRecording()); - m_v8profilerClient.setRecording(!m_v8profilerClient.isRecording()); - m_qmlDataReady = false; - m_v8DataReady = false; - } else if (cmd == Constants::CMD_QUIT - || cmd == Constants::CMD_QUIT2) { - print(QLatin1String("Quit")); - if (m_qmlProfilerClient.isRecording()) { - m_quitAfterSave = true; - m_qmlDataReady = false; - m_v8DataReady = false; - m_qmlProfilerClient.setRecording(false); - m_v8profilerClient.setRecording(false); - } else { - quit(); - } - } -} - -void QmlProfilerApplication::run() -{ - if (m_runMode == LaunchMode) { - m_process = new QProcess(this); - QStringList arguments; - arguments << QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_port); - arguments << m_programArguments; - - m_process->setProcessChannelMode(QProcess::MergedChannels); - connect(m_process, SIGNAL(readyRead()), this, SLOT(processHasOutput())); - connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished())); - logStatus(QString("Starting '%1 %2'...").arg(m_programPath, arguments.join(" "))); - m_process->start(m_programPath, arguments); - if (!m_process->waitForStarted()) { - logError(QString("Could not run '%1': %2").arg(m_programPath, m_process->errorString())); - exit(1); - } - - } - m_connectTimer.start(); -} - -void QmlProfilerApplication::tryToConnect() -{ - Q_ASSERT(!m_connection.isConnected()); - ++ m_connectionAttempts; - - if (!m_verbose && !(m_connectionAttempts % 5)) {// print every 5 seconds - if (!m_verbose) - logError(QString("Could not connect to %1:%2 for %3 seconds...").arg( - m_hostName, QString::number(m_port), QString::number(m_connectionAttempts))); - } - - if (m_connection.state() == QAbstractSocket::UnconnectedState) { - logStatus(QString("Connecting to %1:%2...").arg(m_hostName, QString::number(m_port))); - m_connection.connectToHost(m_hostName, m_port); - } -} - -void QmlProfilerApplication::connected() -{ - m_connectTimer.stop(); - print(QString(QLatin1String("Connected to host:port %1:%2. Wait for profile data or type a command (type 'help'' to show list of commands).")).arg(m_hostName).arg((m_port))); - QString recordingStatus(QLatin1String("Recording Status: %1")); - if (!m_qmlProfilerClient.isRecording() && !m_v8profilerClient.isRecording()) - recordingStatus = recordingStatus.arg(QLatin1String("Off")); - else - recordingStatus = recordingStatus.arg(QLatin1String("On")); - print(recordingStatus); -} - -void QmlProfilerApplication::connectionStateChanged(QAbstractSocket::SocketState state) -{ - if (m_verbose) - qDebug() << state; -} - -void QmlProfilerApplication::connectionError(QAbstractSocket::SocketError error) -{ - if (m_verbose) - qDebug() << error; -} - -void QmlProfilerApplication::processHasOutput() -{ - QTC_ASSERT(m_process, return); - while (m_process->bytesAvailable()) { - QTextStream out(stdout); - out << m_process->readAll(); - } -} - -void QmlProfilerApplication::processFinished() -{ - QTC_ASSERT(m_process, return); - if (m_process->exitStatus() == QProcess::NormalExit) { - logStatus(QString("Process exited (%1).").arg(m_process->exitCode())); - - if (m_qmlProfilerClient.isRecording()) { - logError("Process exited while recording, last trace is lost!"); - exit(2); - } else { - exit(0); - } - } else { - logError("Process crashed! Exiting..."); - exit(3); - } -} - -void QmlProfilerApplication::traceClientEnabled() -{ - if (m_verbose) - qDebug() << "Trace client is attached."; - logStatus("Trace client is attached."); - // blocked server is waiting for recording message from both clients - // once the last one is connected, both messages should be sent - m_qmlProfilerClient.sendRecordingStatus(); - m_v8profilerClient.sendRecordingStatus(); -} - -void QmlProfilerApplication::profilerClientEnabled() -{ - if (m_verbose) - qDebug() << "Profiler client is attached."; - logStatus("Profiler client is attached."); - - // blocked server is waiting for recording message from both clients - // once the last one is connected, both messages should be sent - m_qmlProfilerClient.sendRecordingStatus(); - m_v8profilerClient.sendRecordingStatus(); -} - -void QmlProfilerApplication::traceFinished() -{ - const QString fileName = traceFileName(); - - if (m_eventList.save(fileName)) - print(QString("Saving trace to %1.").arg(fileName)); - - if (m_quitAfterSave) - quit(); -} - -void QmlProfilerApplication::recordingChanged() -{ - if (m_qmlProfilerClient.isRecording()) - print(QLatin1String("Recording is on.")); - else - print(QLatin1String("Recording is off.")); -} - -void QmlProfilerApplication::print(const QString &line) -{ - QTextStream err(stderr); - err << line << endl; -} - -void QmlProfilerApplication::logError(const QString &error) -{ - QTextStream err(stderr); - err << "Error: " << error << endl; -} - -void QmlProfilerApplication::logStatus(const QString &status) -{ - if (!m_verbose) - return; - QTextStream err(stderr); - err << status << endl; -} - -void QmlProfilerApplication::qmlComplete() -{ - m_qmlDataReady = true; - if (m_v8profilerClient.status() != QDeclarativeDebugClient::Enabled || m_v8DataReady) { - m_eventList.complete(); - // once complete is sent, reset the flag - m_qmlDataReady = false; - } -} - -void QmlProfilerApplication::v8Complete() -{ - m_v8DataReady = true; - if (m_qmlProfilerClient.status() != QDeclarativeDebugClient::Enabled || m_qmlDataReady) { - m_eventList.complete(); - // once complete is sent, reset the flag - m_v8DataReady = false; - } -} |