diff options
Diffstat (limited to 'src')
116 files changed, 2887 insertions, 2163 deletions
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 80ef5bc5ff..ef3b5c5e77 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -38,6 +38,10 @@ #include <QDateTime> #include <QMessageBox> +#ifdef Q_OS_WIN +#include <qt_windows.h> +#endif + namespace Utils { /*! \class Utils::FileUtils @@ -237,6 +241,60 @@ bool FileUtils::makeWritable(const FileName &path) return QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser); } +#ifdef Q_OS_WIN +static QString getShortPathName(const QString &name) +{ + if (name.isEmpty()) + return name; + + // Determine length, then convert. + const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW + const DWORD length = GetShortPathNameW(nameC, NULL, 0); + if (length == 0) + return name; + QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]); + GetShortPathNameW(nameC, buffer.data(), length); + const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1); + return rc; +} + +static QString getLongPathName(const QString &name) +{ + if (name.isEmpty()) + return name; + + // Determine length, then convert. + const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW + const DWORD length = GetLongPathNameW(nameC, NULL, 0); + if (length == 0) + return name; + QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]); + GetLongPathNameW(nameC, buffer.data(), length); + const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1); + return rc; +} +#endif // Q_OS_WIN + +// makes sure that capitalization of directories is canonical on Windows. +// This mimics the logic in QDeclarative_isFileCaseCorrect +QString FileUtils::normalizePathName(const QString &name) +{ +#ifdef Q_OS_WIN + QString canonicalName = getShortPathName(name); + if (canonicalName.isEmpty()) + return name; + canonicalName = getLongPathName(canonicalName); + if (canonicalName.isEmpty()) + return name; + // Upper case drive letter + if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':')) + canonicalName[0] = canonicalName.at(0).toUpper(); + return canonicalName; +#else // Filesystem is case-insensitive only on Windows + return name; +#endif +} + QByteArray FileReader::fetchQrc(const QString &fileName) { QTC_ASSERT(fileName.startsWith(QLatin1Char(':')), return QByteArray()); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 0cf1db64b1..0b19a913fb 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -98,6 +98,7 @@ public: static QString shortNativePath(const FileName &path); static QString fileSystemFriendlyName(const QString &name); static bool makeWritable(const FileName &path); + static QString normalizePathName(const QString &name); }; class QTCREATOR_UTILS_EXPORT FileReader diff --git a/src/libs/utils/function.cpp b/src/libs/utils/function.cpp index 68370976d8..45f02f776d 100644 --- a/src/libs/utils/function.cpp +++ b/src/libs/utils/function.cpp @@ -41,7 +41,7 @@ void functionUser(Utils::function<int()> generator, Utils::function<void(int)> c struct GenFunctor { - int operator()() { return 29; } + int operator()() const { return 29; } }; struct ConsumerFunctor @@ -49,6 +49,13 @@ struct ConsumerFunctor void operator()(int) {} }; +struct ConsumerFunctor2 +{ + ConsumerFunctor2() : i(0) { } + int i; + void operator()(int j) { i = j; } +}; + int generatorF() { return 42; @@ -64,6 +71,9 @@ void test() { functionUser(GenFunctor(), ConsumerFunctor()); functionUser(&generatorF, &consumerF); + ConsumerFunctor2 f2; + GenFunctor g2; + functionUser(Utils::cref(g2), Utils::ref(f2)); } } // end namespace diff --git a/src/libs/utils/function.h b/src/libs/utils/function.h index d6dbc2f999..52938f385e 100644 --- a/src/libs/utils/function.h +++ b/src/libs/utils/function.h @@ -39,9 +39,9 @@ # ifdef __GNUC__ # include <tr1/functional> # endif -namespace Utils { using std::tr1::function; } +namespace Utils { using std::tr1::function; using std::tr1::ref; using std::tr1::cref; } #else -namespace Utils { using std::function; } +namespace Utils { using std::function; using std::ref; using std::cref; } #endif #endif // QTC_FUNCTION_H diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 9305680ad5..d6e3a59301 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -654,6 +654,11 @@ void PathChooser::installLineEditVersionToolTip(QLineEdit *le, const QStringList ef->setArguments(arguments); } +void PathChooser::setHistoryCompleter(const QString &historyKey) +{ + d->m_lineEdit->setHistoryCompleter(historyKey); +} + QStringList PathChooser::commandVersionArguments() const { return d->m_binaryVersionToolTipEventFilter ? diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h index 2dc33c0c9d..483c94e576 100644 --- a/src/libs/utils/pathchooser.h +++ b/src/libs/utils/pathchooser.h @@ -128,6 +128,9 @@ public: // Install a tooltip on lineedits used for binaries showing the version. static void installLineEditVersionToolTip(QLineEdit *le, const QStringList &arguments); + // Enable a history completer with a history of entries. + void setHistoryCompleter(const QString &historyKey); + bool isReadOnly() const; void setReadOnly(bool b); diff --git a/src/libs/utils/winutils.cpp b/src/libs/utils/winutils.cpp index cf54a24d4f..59daad82df 100644 --- a/src/libs/utils/winutils.cpp +++ b/src/libs/utils/winutils.cpp @@ -129,54 +129,6 @@ QTCREATOR_UTILS_EXPORT QString winGetDLLVersion(WinDLLVersionType t, return rc; } -QTCREATOR_UTILS_EXPORT QString getShortPathName(const QString &name) -{ - if (name.isEmpty()) - return name; - - // Determine length, then convert. - const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW - const DWORD length = GetShortPathNameW(nameC, NULL, 0); - if (length == 0) - return name; - QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]); - GetShortPathNameW(nameC, buffer.data(), length); - const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1); - return rc; -} - -QTCREATOR_UTILS_EXPORT QString getLongPathName(const QString &name) -{ - if (name.isEmpty()) - return name; - - // Determine length, then convert. - const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(name.utf16()); // MinGW - const DWORD length = GetLongPathNameW(nameC, NULL, 0); - if (length == 0) - return name; - QScopedArrayPointer<TCHAR> buffer(new TCHAR[length]); - GetLongPathNameW(nameC, buffer.data(), length); - const QString rc = QString::fromUtf16(reinterpret_cast<const ushort *>(buffer.data()), length - 1); - return rc; -} - -// makes sure that capitalization of directories is canonical. -// This mimics the logic in QDeclarative_isFileCaseCorrect -QTCREATOR_UTILS_EXPORT QString normalizePathName(const QString &name) -{ - QString canonicalName = getShortPathName(name); - if (canonicalName.isEmpty()) - return name; - canonicalName = getLongPathName(canonicalName); - if (canonicalName.isEmpty()) - return name; - // Upper case drive letter - if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':')) - canonicalName[0] = canonicalName.at(0).toUpper(); - return canonicalName; -} - QTCREATOR_UTILS_EXPORT bool winIs64BitSystem() { SYSTEM_INFO systemInfo; diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 80d1c9451a..ee39135f5d 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -44,6 +44,7 @@ #include <projectexplorer/devicesupport/devicemanager.h> #include <projectexplorer/toolchainmanager.h> #include <projectexplorer/session.h> +#include <debugger/debuggeritemmanager.h> #include <debugger/debuggerkitinformation.h> #include <qtsupport/baseqtversion.h> #include <qtsupport/qtkitinformation.h> diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 405f317ef5..75e39a6f9e 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -336,7 +336,7 @@ void AndroidDeployQtStep::runCommand(const QString &program, const QStringList & QString mainMessage = tr("Packaging Error: Command '%1 %2' failed.") .arg(program).arg(arguments.join(QLatin1String(" "))); if (buildProc.error() != QProcess::UnknownError) - mainMessage += tr(" Reason: %1").arg(buildProc.errorString()); + mainMessage += QLatin1Char(' ') + tr("Reason: %1").arg(buildProc.errorString()); else mainMessage += tr("Exit code: %1").arg(buildProc.exitCode()); emit addOutput(mainMessage, BuildStep::ErrorMessageOutput); diff --git a/src/plugins/android/androiddeploystep.cpp b/src/plugins/android/androiddeploystep.cpp index d8264898d8..dcdb8968ff 100644 --- a/src/plugins/android/androiddeploystep.cpp +++ b/src/plugins/android/androiddeploystep.cpp @@ -239,7 +239,7 @@ bool AndroidDeployStep::runCommand(QProcess *buildProc, QString mainMessage = tr("Packaging Error: Command '%1 %2' failed.") .arg(program).arg(arguments.join(QLatin1String(" "))); if (buildProc->error() != QProcess::UnknownError) - mainMessage += tr(" Reason: %1").arg(buildProc->errorString()); + mainMessage += QLatin1Char(' ') + tr("Reason: %1").arg(buildProc->errorString()); else mainMessage += tr("Exit code: %1").arg(buildProc->exitCode()); writeOutput(mainMessage, BuildStep::ErrorMessageOutput); diff --git a/src/plugins/android/androidpackagecreationstep.cpp b/src/plugins/android/androidpackagecreationstep.cpp index 285f7b3ee5..a72b9ac695 100644 --- a/src/plugins/android/androidpackagecreationstep.cpp +++ b/src/plugins/android/androidpackagecreationstep.cpp @@ -613,7 +613,7 @@ bool AndroidPackageCreationStep::createPackage() emit addOutput(tr("Copy Qt app & libs to Android package ..."), MessageOutput); QStringList build; - build << QLatin1String("-silent"); + // build << QLatin1String("-silent"); //TODO depends on ant 1.9.0, enabled, not *now* build << QLatin1String("clean"); QFile::remove(m_gdbServerDestination.toString()); if (m_signPackageForRun) { @@ -803,7 +803,7 @@ bool AndroidPackageCreationStep::runCommand(QProcess *buildProc QString mainMessage = tr("Packaging Error: Command '%1 %2' failed.") .arg(program).arg(arguments.join(QLatin1String(" "))); if (buildProc->error() != QProcess::UnknownError) - mainMessage += tr(" Reason: %1").arg(buildProc->errorString()); + mainMessage += QLatin1Char(' ') + tr("Reason: %1").arg(buildProc->errorString()); else mainMessage += tr("Exit code: %1").arg(buildProc->exitCode()); raiseError(mainMessage); diff --git a/src/plugins/clearcase/settingspage.cpp b/src/plugins/clearcase/settingspage.cpp index 983dac4845..2dc0ad0019 100644 --- a/src/plugins/clearcase/settingspage.cpp +++ b/src/plugins/clearcase/settingspage.cpp @@ -86,7 +86,8 @@ void SettingsPageWidget::setSettings(const ClearCaseSettings &s) } else { QString diffWarning = tr("In order to use External diff, 'diff' command needs to be accessible."); if (HostOsInfo::isWindowsHost()) { - diffWarning.append(tr(" DiffUtils is available for free download " + diffWarning += QLatin1Char(' '); + diffWarning.append(tr("DiffUtils is available for free download " "<a href=\"http://gnuwin32.sourceforge.net/packages/diffutils.htm\">here</a>. " "Please extract it to a directory in your PATH.")); } diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp index a68a919c1d..f3a49624e9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp @@ -455,7 +455,7 @@ ShadowBuildPage::ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard, bool chang QLabel *label = new QLabel(this); label->setWordWrap(true); if (change) - label->setText(tr("Please enter the directory in which you want to build your project. ")); + label->setText(tr("Please enter the directory in which you want to build your project.") + QLatin1Char(' ')); else label->setText(tr("Please enter the directory in which you want to build your project. " "Qt Creator recommends to not use the source directory for building. " @@ -507,13 +507,14 @@ void ChooseCMakePage::updateErrorText() } else { QString text = tr("Specify the path to the CMake executable. No CMake executable was found in the path."); if (!cmakeExecutable.isEmpty()) { + text += QLatin1Char(' '); QFileInfo fi(cmakeExecutable); if (!fi.exists()) - text += tr(" The CMake executable (%1) does not exist.").arg(cmakeExecutable); + text += tr("The CMake executable (%1) does not exist.").arg(cmakeExecutable); else if (!fi.isExecutable()) - text += tr(" The path %1 is not an executable.").arg(cmakeExecutable); + text += tr("The path %1 is not an executable.").arg(cmakeExecutable); else - text += tr(" The path %1 is not a valid CMake executable.").arg(cmakeExecutable); + text += tr("The path %1 is not a valid CMake executable.").arg(cmakeExecutable); } m_cmakeLabel->setText(text); } diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp index e256fbe4f0..50e5a4d6af 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp @@ -193,7 +193,12 @@ QString CMakeRunConfiguration::defaultDisplayName() const { if (m_title.isEmpty()) return tr("Run CMake kit"); - return m_title + (m_enabled ? QString() : tr(" (disabled)")); + QString result = m_title; + if (!m_enabled) { + result += QLatin1Char(' '); + result += tr("(disabled)"); + } + return result; } QWidget *CMakeRunConfiguration::createConfigurationWidget() diff --git a/src/plugins/coreplugin/basefilewizard.cpp b/src/plugins/coreplugin/basefilewizard.cpp index bb26839348..9ba83657a5 100644 --- a/src/plugins/coreplugin/basefilewizard.cpp +++ b/src/plugins/coreplugin/basefilewizard.cpp @@ -407,9 +407,9 @@ BaseFileWizard::OverwriteResult BaseFileWizard::promptOverwrite(GeneratedFiles * QStringList existingFiles; bool oddStuffFound = false; - static const QString readOnlyMsg = tr(" [read only]"); - static const QString directoryMsg = tr(" [folder]"); - static const QString symLinkMsg = tr(" [symbolic link]"); + static const QString readOnlyMsg = tr("[read only]"); + static const QString directoryMsg = tr("[folder]"); + static const QString symLinkMsg = tr("[symbolic link]"); foreach (const GeneratedFile &file, *files) { const QFileInfo fi(file.path()); @@ -432,17 +432,17 @@ BaseFileWizard::OverwriteResult BaseFileWizard::promptOverwrite(GeneratedFiles * do { if (fi.isDir()) { oddStuffFound = true; - fileNamesMsgPart += directoryMsg; + fileNamesMsgPart += QLatin1Char(' ') + directoryMsg; break; } if (fi.isSymLink()) { oddStuffFound = true; - fileNamesMsgPart += symLinkMsg; + fileNamesMsgPart += QLatin1Char(' ') + symLinkMsg; break; } if (!fi.isWritable()) { oddStuffFound = true; - fileNamesMsgPart += readOnlyMsg; + fileNamesMsgPart += QLatin1Char(' ') + readOnlyMsg; } } while (false); } diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index bb6783bcda..4593488c1b 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -400,6 +400,8 @@ void SettingsDialog::createGui() mainGridLayout->setColumnStretch(1, 4); setLayout(mainGridLayout); setMinimumSize(1000, 550); + if (Utils::HostOsInfo::isMacHost()) + setMinimumHeight(minimumHeight() * 1.1); } SettingsDialog::~SettingsDialog() diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 93a7c3c739..073b89dc5b 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -854,10 +854,13 @@ static void setFocusToEditorViewAndUnmaximizePanes(EditorView *view) void EditorManager::doEscapeKeyFocusMoveMagic() { // use cases to cover: - // 1. if app focus is in mode or external window without editor view (e.g. Projects, ext. Help) - // activate & raise the current editor view (can be external) - // if that is in edit mode - // activate edit mode and unmaximize output pane + // 1. if app focus is in mode or external window without editor view (e.g. Design, Projects, ext. Help) + // if there are extra views (e.g. output) + // hide them + // otherwise + // activate & raise the current editor view (can be external) + // if that is in edit mode + // activate edit mode and unmaximize output pane // 2. if app focus is in external window with editor view // hide find if necessary // 2. if app focus is in mode with editor view @@ -874,44 +877,54 @@ void EditorManager::doEscapeKeyFocusMoveMagic() // otherwise (i.e. mode is edit mode) // hide extra views (find, help, output) + QWidget *activeWindow = qApp->activeWindow(); + if (!activeWindow) + return; + QWidget *focus = qApp->focusWidget(); EditorView *editorView = currentEditorView(); - bool editorViewActive = (qApp->focusWidget() == editorView->focusWidget()); + bool editorViewActive = (focus && focus == editorView->focusWidget()); bool editorViewVisible = editorView->isVisible(); - if (!editorViewActive && editorViewVisible) { - setFocusToEditorViewAndUnmaximizePanes(editorView); - return; - } - if (!editorViewActive && !editorViewVisible) { - // assumption is that editorView is in main window then - ModeManager::activateMode(Id(Constants::MODE_EDIT)); - QTC_CHECK(editorView->isVisible()); - setFocusToEditorViewAndUnmaximizePanes(editorView); - return; - } - if (editorViewActive) { - QTC_CHECK(editorViewVisible); + + if (!( editorViewVisible && !editorViewActive && editorView->window() == activeWindow )) { bool stuffHidden = false; QWidget *findPane = FindToolBarPlaceHolder::getCurrent(); - if (findPane && findPane->isVisibleTo(editorView)) { + if (findPane && findPane->isVisible() && findPane->window() == activeWindow) { findPane->hide(); stuffHidden = true; } QWidget *outputPane = OutputPanePlaceHolder::getCurrent(); - if (outputPane && outputPane->isVisibleTo(editorView)) { + if (outputPane && outputPane->isVisible() && outputPane->window() == activeWindow) { OutputPaneManager::instance()->slotHide(); stuffHidden = true; } QWidget *rightPane = RightPanePlaceHolder::current(); - if (rightPane && rightPane->isVisibleTo(editorView)) { + if (rightPane && rightPane->isVisible() && rightPane->window() == activeWindow) { RightPaneWidget::instance()->setShown(false); stuffHidden = true; } - if (!stuffHidden && editorView->window() == ICore::mainWindow()) { - // we are in a editor view and there's nothing to hide, switch to edit - ModeManager::activateMode(Id(Constants::MODE_EDIT)); - // next call works only because editor views in main window are shared between modes - setFocusToEditorViewAndUnmaximizePanes(editorView); - } + if (stuffHidden) + return; + } + + if (!editorViewActive && editorViewVisible) { + setFocusToEditorViewAndUnmaximizePanes(editorView); + return; + } + + if (!editorViewActive && !editorViewVisible) { + // assumption is that editorView is in main window then + ModeManager::activateMode(Id(Constants::MODE_EDIT)); + QTC_CHECK(editorView->isVisible()); + setFocusToEditorViewAndUnmaximizePanes(editorView); + return; + } + + if (editorView->window() == ICore::mainWindow()) { + // we are in a editor view and there's nothing to hide, switch to edit + ModeManager::activateMode(Id(Constants::MODE_EDIT)); + QTC_CHECK(editorView->isVisible()); + // next call works only because editor views in main window are shared between modes + setFocusToEditorViewAndUnmaximizePanes(editorView); } } diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 7564a59f02..a226c2b609 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -415,7 +415,9 @@ static QString compilerString() #elif defined(Q_CC_GNU) return QLatin1String("GCC " ) + QLatin1String(__VERSION__); #elif defined(Q_CC_MSVC) - if (_MSC_VER >= 1500) // 1500: MSVC 2008, 1600: MSVC 2010, ... + if (_MSC_VER >= 1800) // 1800: MSVC 2013 (yearly release cycle) + return QLatin1String("MSVC ") + QString::number(2008 + ((_MSC_VER / 100) - 13)); + if (_MSC_VER >= 1500) // 1500: MSVC 2008, 1600: MSVC 2010, ... (2-year release cycle) return QLatin1String("MSVC ") + QString::number(2008 + 2 * ((_MSC_VER / 100) - 15)); #endif return QLatin1String("<unknown compiler>"); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 0604edde96..fe072bde82 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -518,6 +518,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent) , m_objcEnabled(false) , m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings()) , m_followSymbolUnderCursor(new FollowSymbolUnderCursor(this)) + , m_preprocessorButton(0) { qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo"); @@ -647,10 +648,13 @@ void CPPEditorWidget::createToolBar(CPPEditor *editor) connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateUses())); connect(this, SIGNAL(textChanged()), this, SLOT(updateUses())); - QToolButton *hashButton = new QToolButton(this); - hashButton->setText(QLatin1String("#")); - connect(hashButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget())); - editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, hashButton); + m_preprocessorButton = new QToolButton(this); + m_preprocessorButton->setText(QLatin1String("#")); + Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG); + connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updatePreprocessorButtonTooltip())); + updatePreprocessorButtonTooltip(); + connect(m_preprocessorButton, SIGNAL(clicked()), this, SLOT(showPreProcessorWidget())); + editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_preprocessorButton); editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo); } @@ -1012,6 +1016,14 @@ void CPPEditorWidget::onContentsChanged(int position, int charsRemoved, int char updateUses(); } +void CPPEditorWidget::updatePreprocessorButtonTooltip() +{ + QTC_ASSERT(m_preprocessorButton, return); + Core::Command *cmd = Core::ActionManager::command(Constants::OPEN_PREPROCESSOR_DIALOG); + QTC_ASSERT(cmd, return); + m_preprocessorButton->setToolTip(cmd->action()->toolTip()); +} + void CPPEditorWidget::jumpToOutlineElement(int index) { QModelIndex modelIndex = m_outlineCombo->view()->currentIndex(); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index ae1f57e31b..ba3b58ccee 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE class QComboBox; class QSortFilterProxyModel; +class QToolButton; QT_END_NAMESPACE namespace CPlusPlus { @@ -175,6 +176,7 @@ private Q_SLOTS: void onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink> link); void onDocumentUpdated(); void onContentsChanged(int position, int charsRemoved, int charsAdded); + void updatePreprocessorButtonTooltip(); void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo); void highlightSymbolUsages(int from, int to); @@ -258,7 +260,7 @@ private: CppTools::CommentsSettings m_commentsSettings; QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor; - QString m_preProcessorAdditions; + QToolButton *m_preprocessorButton; }; } // namespace Internal diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index b9c66de4a1..d7dd630a43 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -210,7 +210,7 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err contextMenu->addAction(cmd); cppToolsMenu->addAction(cmd); - QAction *openPreprocessorDialog = new QAction(tr("Additional Preprocessor Directives"), this); + QAction *openPreprocessorDialog = new QAction(tr("Additional Preprocessor Directives..."), this); cmd = ActionManager::registerAction(openPreprocessorDialog, Constants::OPEN_PREPROCESSOR_DIALOG, context); cmd->setDefaultKeySequence(QKeySequence()); diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index 33e32593f4..c9e6f5e873 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -138,6 +138,10 @@ private slots: void test_FollowSymbolUnderCursor_virtualFunctionCall_allOverrides(); void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides1(); void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides2(); + void test_FollowSymbolUnderCursor_virtualFunctionCall_fallbackToDeclaration(); + void test_FollowSymbolUnderCursor_virtualFunctionCall_itemOrder(); + void test_FollowSymbolUnderCursor_virtualFunctionCall_onDotMemberAccessOfReferenceTypes(); + void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDotMemberAccessOfNonReferenceType(); void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified(); void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDeclaration(); void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefinition(); diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index ad4a8c3012..0b6cd23a6d 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -55,35 +55,57 @@ typedef BaseTextEditorWidget::Link Link; namespace { -bool lookupVirtualFunctionOverrides(const QString &expression, Function *function, Scope *scope, +bool lookupVirtualFunctionOverrides(TypeOfExpression &typeOfExpression, + const Document::Ptr &document, + const Function *function, + Scope *scope, const Snapshot &snapshot) { - if (expression.isEmpty() || !function || !scope || scope->isClass() || snapshot.isEmpty()) + if (!document || !function || !scope || scope->isClass() || snapshot.isEmpty()) + return false; + + ExpressionAST *expressionAST = typeOfExpression.expressionAST(); + if (!expressionAST) + return false; + CallAST *callAST = expressionAST->asCall(); + if (!callAST) + return false; + ExpressionAST *baseExpressionAST = callAST->base_expression; + if (!baseExpressionAST) return false; bool result = false; - Document::Ptr expressionDocument = documentForExpression(expression.toUtf8()); - if (ExpressionAST *expressionAST = extractExpressionAST(expressionDocument)) { - if (CallAST *callAST = expressionAST->asCall()) { - if (ExpressionAST *baseExpressionAST = callAST->base_expression) { - if (IdExpressionAST *idExpressionAST = baseExpressionAST->asIdExpression()) { - NameAST *name = idExpressionAST->name; - result = name && !name->asQualifiedName(); - } else if (MemberAccessAST *memberAccessAST = baseExpressionAST->asMemberAccess()) { - NameAST *name = memberAccessAST->member_name; - const bool nameIsQualified = name && name->asQualifiedName(); - - TranslationUnit *unit = expressionDocument->translationUnit(); - QTC_ASSERT(unit, return false); - const int tokenKind = unit->tokenKind(memberAccessAST->access_token); - result = tokenKind == T_ARROW && !nameIsQualified; + if (IdExpressionAST *idExpressionAST = baseExpressionAST->asIdExpression()) { + NameAST *name = idExpressionAST->name; + const bool nameIsQualified = name && name->asQualifiedName(); + result = !nameIsQualified && FunctionHelper::isVirtualFunction(function, snapshot); + } else if (MemberAccessAST *memberAccessAST = baseExpressionAST->asMemberAccess()) { + NameAST *name = memberAccessAST->member_name; + const bool nameIsQualified = name && name->asQualifiedName(); + if (!nameIsQualified && FunctionHelper::isVirtualFunction(function, snapshot)) { + const Document::Ptr expressionDocument + = typeOfExpression.context().expressionDocument(); + QTC_ASSERT(expressionDocument, return false); + TranslationUnit *unit = expressionDocument->translationUnit(); + QTC_ASSERT(unit, return false); + const int accessTokenKind = unit->tokenKind(memberAccessAST->access_token); + + if (accessTokenKind == T_ARROW) { + result = true; + } else if (accessTokenKind == T_DOT) { + const QList<LookupItem> items = typeOfExpression.reference( + memberAccessAST->base_expression, document, scope); + if (!items.isEmpty()) { + const LookupItem item = items.first(); + if (Symbol *declaration = item.declaration()) + result = declaration->type()->isReferenceType(); } } } } - return result && FunctionHelper::isVirtualFunction(function, snapshot); + return result; } Link findMacroLink_helper(const QByteArray &name, Document::Ptr doc, const Snapshot &snapshot, @@ -530,16 +552,27 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor & // Consider to show a pop-up displaying overrides for the function Function *function = symbol->type()->asFunctionType(); - if (lookupVirtualFunctionOverrides(expression, function, scope, snapshot)) { + if (lookupVirtualFunctionOverrides(typeOfExpression, doc, function, scope, snapshot)) { Class *klass = symbolFinder->findMatchingClassDeclaration(function, snapshot); QTC_CHECK(klass); - if (m_virtualFunctionAssistProvider->configure(klass, function, snapshot, - inNextSplit)) { + VirtualFunctionAssistProvider::Parameters params; + params.startClass = klass; + params.function = function; + params.snapshot = snapshot; + params.cursorPosition = cursor.position(); + params.openInNextSplit = inNextSplit; + + if (m_virtualFunctionAssistProvider->configure(params)) { m_widget->invokeAssist(TextEditor::FollowSymbol, m_virtualFunctionAssistProvider); } - return Link(); + + // Ensure a valid link text, so the symbol name will be underlined on Ctrl+Hover. + Link link; + link.linkTextStart = beginOfToken; + link.linkTextEnd = endOfToken; + return link; } if (resolveTarget) { diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.cpp b/src/plugins/cppeditor/cppincludehierarchymodel.cpp index 7b6909f617..7709bed2d5 100644 --- a/src/plugins/cppeditor/cppincludehierarchymodel.cpp +++ b/src/plugins/cppeditor/cppincludehierarchymodel.cpp @@ -117,11 +117,11 @@ QVariant CppIncludeHierarchyModel::data(const QModelIndex &index, int role) cons if (role == Qt::DisplayRole) { if ((item == m_includesItem && m_includesItem->childCount() == 0) || (item == m_includedByItem && m_includedByItem->childCount() == 0)) { - return QString(item->fileName() + tr(" (none)")); + return QString(item->fileName() + QLatin1Char(' ') + tr("(none)")); } if (item->isCyclic()) - return QString(item->fileName() + tr(" (cyclic)")); + return QString(item->fileName() + QLatin1Char(' ') + tr("(cyclic)")); return item->fileName(); } diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp index 5f44589885..76d6cc0d17 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp @@ -40,6 +40,8 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> +#include <cpptools/symbolfinder.h> + #include <texteditor/codeassist/basicproposalitemlistmodel.h> #include <texteditor/codeassist/genericproposal.h> #include <texteditor/codeassist/genericproposalwidget.h> @@ -107,16 +109,13 @@ private: class VirtualFunctionsAssistProcessor : public IAssistProcessor { public: - VirtualFunctionsAssistProcessor(const VirtualFunctionAssistProvider *provider) - : m_startClass(provider->startClass()) - , m_function(provider->function()) - , m_snapshot(provider->snapshot()) - , m_openInNextSplit(provider->openInNextSplit()) + VirtualFunctionsAssistProcessor(const VirtualFunctionAssistProvider::Parameters ¶ms) + : m_params(params) {} - IAssistProposal *immediateProposal(const TextEditor::IAssistInterface *interface) + IAssistProposal *immediateProposal(const TextEditor::IAssistInterface *) { - QTC_ASSERT(m_function, return 0); + QTC_ASSERT(m_params.function, return 0); BasicProposalItem *hintItem = new VirtualFunctionProposalItem(CPPEditorWidget::Link()); hintItem->setText(QCoreApplication::translate("VirtualFunctionsAssistProcessor", @@ -124,69 +123,67 @@ public: hintItem->setOrder(-1000); QList<BasicProposalItem *> items; - items << itemFromSymbol(m_function, m_function); + items << itemFromSymbol(maybeDefinitionFor(m_params.function)); items << hintItem; - return new VirtualFunctionProposal(interface->position(), + return new VirtualFunctionProposal(m_params.cursorPosition, new BasicProposalItemListModel(items), - m_openInNextSplit); + m_params.openInNextSplit); } - IAssistProposal *perform(const IAssistInterface *interface) + IAssistProposal *perform(const IAssistInterface *) { - if (!interface) - return 0; + QTC_ASSERT(m_params.startClass, return 0); + QTC_ASSERT(m_params.function, return 0); + QTC_ASSERT(!m_params.snapshot.isEmpty(), return 0); - QTC_ASSERT(m_startClass, return 0); - QTC_ASSERT(m_function, return 0); - QTC_ASSERT(!m_snapshot.isEmpty(), return 0); + const QList<Symbol *> overrides + = FunctionHelper::overrides(m_params.startClass, m_params.function, m_params.snapshot); + if (overrides.isEmpty()) + return 0; - const QList<Symbol *> overrides = FunctionHelper::overrides(m_startClass, m_function, - m_snapshot); QList<BasicProposalItem *> items; foreach (Symbol *symbol, overrides) - items << itemFromSymbol(symbol, m_function); + items << itemFromSymbol(maybeDefinitionFor(symbol)); + items.first()->setOrder(1000); // Ensure top position for function of static type - return new VirtualFunctionProposal(interface->position(), + return new VirtualFunctionProposal(m_params.cursorPosition, new BasicProposalItemListModel(items), - m_openInNextSplit); + m_params.openInNextSplit); } - BasicProposalItem *itemFromSymbol(Symbol *symbol, Symbol *firstSymbol) const +private: + Symbol *maybeDefinitionFor(Symbol *symbol) + { + if (Function *definition = m_finder.findMatchingDefinition(symbol, m_params.snapshot)) + return definition; + return symbol; + } + + BasicProposalItem *itemFromSymbol(Symbol *symbol) const { const QString text = m_overview.prettyName(LookupContext::fullyQualifiedName(symbol)); const CPPEditorWidget::Link link = CPPEditorWidget::linkToSymbol(symbol); - BasicProposalItem *item = new VirtualFunctionProposalItem(link, m_openInNextSplit); + BasicProposalItem *item = new VirtualFunctionProposalItem(link, m_params.openInNextSplit); item->setText(text); item->setIcon(m_icons.iconForSymbol(symbol)); - if (symbol == firstSymbol) - item->setOrder(1000); // Ensure top position for function of static type return item; } -private: - Class *m_startClass; - Function *m_function; - Snapshot m_snapshot; - bool m_openInNextSplit; + VirtualFunctionAssistProvider::Parameters m_params; Overview m_overview; Icons m_icons; + CppTools::SymbolFinder m_finder; }; VirtualFunctionAssistProvider::VirtualFunctionAssistProvider() - : m_function(0) - , m_openInNextSplit(false) { } -bool VirtualFunctionAssistProvider::configure(Class *startClass, Function *function, - const Snapshot &snapshot, bool openInNextSplit) +bool VirtualFunctionAssistProvider::configure(const Parameters ¶meters) { - m_startClass = startClass; - m_function = function; - m_snapshot = snapshot; - m_openInNextSplit = openInNextSplit; + m_params = parameters; return true; } @@ -202,7 +199,7 @@ bool VirtualFunctionAssistProvider::supportsEditor(const Core::Id &editorId) con IAssistProcessor *VirtualFunctionAssistProvider::createProcessor() const { - return new VirtualFunctionsAssistProcessor(this); + return new VirtualFunctionsAssistProcessor(m_params); } enum VirtualType { Virtual, PureVirtual }; @@ -263,9 +260,6 @@ QList<Symbol *> FunctionHelper::overrides(Class *startClass, Function *function, const Name *referenceName = function->name(); QTC_ASSERT(referenceName && referenceType.isValid(), return result); - // Add itself - result << function; - // Find overrides CppEditor::Internal::CppClass cppClass = CppClass(startClass); cppClass.lookupDerived(startClass, snapshot); diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h index c634b4ed44..b5ff42d846 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h @@ -35,6 +35,8 @@ #include <cplusplus/CppDocument.h> #include <cplusplus/Symbols.h> +#include <QTextCursor> + namespace CppEditor { namespace Internal { @@ -43,22 +45,25 @@ class VirtualFunctionAssistProvider : public TextEditor::IAssistProvider public: VirtualFunctionAssistProvider(); - virtual bool configure(CPlusPlus::Class *startClass, CPlusPlus::Function *function, - const CPlusPlus::Snapshot &snapshot, bool openInNextSplit); - CPlusPlus::Class *startClass() const { return m_startClass; } - CPlusPlus::Function *function() const { return m_function; } - CPlusPlus::Snapshot snapshot() const { return m_snapshot; } - bool openInNextSplit() const { return m_openInNextSplit; } + struct Parameters { + Parameters() : startClass(0), function(0), cursorPosition(-1), openInNextSplit(false) {} + + CPlusPlus::Class *startClass; + CPlusPlus::Function *function; + CPlusPlus::Snapshot snapshot; + int cursorPosition; + bool openInNextSplit; + }; + + virtual bool configure(const Parameters ¶meters); + Parameters params() const { return m_params; } bool isAsynchronous() const; bool supportsEditor(const Core::Id &editorId) const; TextEditor::IAssistProcessor *createProcessor() const; private: - CPlusPlus::Class *m_startClass; - CPlusPlus::Function *m_function; - CPlusPlus::Snapshot m_snapshot; - bool m_openInNextSplit; + Parameters m_params; }; class FunctionHelper diff --git a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h b/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h index 7d09c9db2c..44cf50dcc9 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h +++ b/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h @@ -41,6 +41,7 @@ public: VirtualFunctionProposalItem(const TextEditor::BaseTextEditorWidget::Link &link, bool openInSplit = true); void apply(TextEditor::BaseTextEditor * /* editor */, int /* basePosition */) const; + TextEditor::BaseTextEditorWidget::Link link() const { return m_link; } // Exposed for tests private: TextEditor::BaseTextEditorWidget::Link m_link; diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 19f33336ae..2a2c754e63 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -31,6 +31,7 @@ #include "cppeditorplugin.h" #include "cppelementevaluator.h" #include "cppvirtualfunctionassistprovider.h" +#include "cppvirtualfunctionproposalitem.h" #include <texteditor/codeassist/iassistproposal.h> #include <texteditor/codeassist/iassistprocessor.h> @@ -59,6 +60,35 @@ using namespace CppTools; using namespace TextEditor; using namespace Core; +class OverrideItem { +public: + OverrideItem() : line(0) {} + OverrideItem(const QString &text, int line = 0) : text(text), line(line) {} + bool isValid() { return line != 0; } + + QString text; + int line; +}; +typedef QList<OverrideItem> OverrideItemList; +Q_DECLARE_METATYPE(OverrideItem) + +inline bool operator==(const OverrideItem &lhs, const OverrideItem &rhs) +{ + return lhs.text == rhs.text && lhs.line == rhs.line; +} + +QT_BEGIN_NAMESPACE +namespace QTest { +template<> char *toString(const OverrideItem &data) +{ + QByteArray ba = "OverrideItem("; + ba += data.text.toLatin1() + ", " + QByteArray::number(data.line); + ba += ")"; + return qstrdup(ba.data()); +} +} +QT_END_NAMESPACE + namespace { /// A fake virtual functions assist provider that runs processor->perform() already in configure() @@ -72,14 +102,13 @@ public: // Invoke the processor already here to calculate the proposals. Return false in order to // indicate that configure failed, so the actual code assist invocation leading to a pop-up // will not happen. - bool configure(CPlusPlus::Class *startClass, CPlusPlus::Function *function, - const CPlusPlus::Snapshot &snapshot, bool openInNextSplit) + bool configure(const VirtualFunctionAssistProvider::Parameters ¶ms) { - VirtualFunctionAssistProvider::configure(startClass, function, snapshot, openInNextSplit); + VirtualFunctionAssistProvider::configure(params); IAssistProcessor *processor = createProcessor(); - IAssistInterface *assistInterface = m_editorWidget->createAssistInterface(FollowSymbol, - ExplicitlyInvoked); + IAssistInterface *assistInterface + = m_editorWidget->createAssistInterface(FollowSymbol, ExplicitlyInvoked); IAssistProposal *immediateProposal = processor->immediateProposal(assistInterface); IAssistProposal *finalProposal = processor->perform(assistInterface); @@ -89,27 +118,36 @@ public: return false; } - static QStringList itemList(IAssistProposalModel *imodel) + static OverrideItemList itemList(IAssistProposalModel *imodel) { - QStringList immediateItems; + OverrideItemList result; BasicProposalItemListModel *model = dynamic_cast<BasicProposalItemListModel *>(imodel); if (!model) - return immediateItems; + return result; + + // Mimic relevant GenericProposalWidget::showProposal() calls + model->removeDuplicates(); + model->reset(); if (model->isSortable(QString())) model->sort(QString()); - model->removeDuplicates(); for (int i = 0, size = model->size(); i < size; ++i) { + VirtualFunctionProposalItem *item + = dynamic_cast<VirtualFunctionProposalItem *>(model->proposalItem(i)); + const QString text = model->text(i); - immediateItems.append(text); + const int line = item->link().targetLine; +// Uncomment for updating/generating reference data: +// qDebug("<< OverrideItem(QLatin1String(\"%s\"), %d)", qPrintable(text), line); + result << OverrideItem(text, line); } - return immediateItems; + return result; } public: - QStringList m_immediateItems; - QStringList m_finalItems; + OverrideItemList m_immediateItems; + OverrideItemList m_finalItems; private: CPPEditorWidget *m_editorWidget; @@ -199,11 +237,11 @@ public: }; TestCase(CppEditorAction action, const QByteArray &source, - const QStringList &expectedVirtualFunctionImmediateProposal = QStringList(), - const QStringList &expectedVirtualFunctionFinalProposal = QStringList()); + const OverrideItemList &expectedVirtualFunctionImmediateProposal = OverrideItemList(), + const OverrideItemList &expectedVirtualFunctionFinalProposal = OverrideItemList()); TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles, - const QStringList &expectedVirtualSymbolsImmediateProposal = QStringList(), - const QStringList &expectedVirtualSymbolsFinalProposal = QStringList()); + const OverrideItemList &expectedVirtualFunctionImmediateProposal = OverrideItemList(), + const OverrideItemList &expectedVirtualFunctionFinalProposal = OverrideItemList()); ~TestCase(); void run(bool expectedFail = false); @@ -220,18 +258,18 @@ private: private: CppEditorAction m_action; QList<TestDocumentPtr> m_testFiles; - QStringList m_expectedVirtualSymbolsImmediateProposal; // for virtual functions - QStringList m_expectedVirtualSymbolsFinalProposals; // for virtual functions + OverrideItemList m_expectedVirtualFunctionImmediateProposal; + OverrideItemList m_expectedVirtualFunctionFinalProposals; }; /// Convenience function for creating a TestDocument. /// See TestDocument. TestCase::TestCase(CppEditorAction action, const QByteArray &source, - const QStringList &expectedVirtualFunctionImmediateProposal, - const QStringList &expectedVirtualFunctionFinalProposal) + const OverrideItemList &expectedVirtualFunctionImmediateProposal, + const OverrideItemList &expectedVirtualFunctionFinalProposal) : m_action(action) - , m_expectedVirtualSymbolsImmediateProposal(expectedVirtualFunctionImmediateProposal) - , m_expectedVirtualSymbolsFinalProposals(expectedVirtualFunctionFinalProposal) + , m_expectedVirtualFunctionImmediateProposal(expectedVirtualFunctionImmediateProposal) + , m_expectedVirtualFunctionFinalProposals(expectedVirtualFunctionFinalProposal) { m_testFiles << TestDocument::create(source, QLatin1String("file.cpp")); init(); @@ -242,12 +280,12 @@ TestCase::TestCase(CppEditorAction action, const QByteArray &source, /// Exactly one test document must be provided that contains '$', the target position marker. /// It can be the same document. TestCase::TestCase(CppEditorAction action, const QList<TestDocumentPtr> theTestFiles, - const QStringList &expectedVirtualSymbolsImmediateProposal, - const QStringList &expectedVirtualSymbolsFinalProposal) + const OverrideItemList &expectedVirtualFunctionImmediateProposal, + const OverrideItemList &expectedVirtualFunctionFinalProposal) : m_action(action) , m_testFiles(theTestFiles) - , m_expectedVirtualSymbolsImmediateProposal(expectedVirtualSymbolsImmediateProposal) - , m_expectedVirtualSymbolsFinalProposals(expectedVirtualSymbolsFinalProposal) + , m_expectedVirtualFunctionImmediateProposal(expectedVirtualFunctionImmediateProposal) + , m_expectedVirtualFunctionFinalProposals(expectedVirtualFunctionFinalProposal) { init(); } @@ -365,8 +403,8 @@ void TestCase::run(bool expectedFail) // qDebug() << "Initial line:" << initialTestFile->editor->currentLine(); // qDebug() << "Initial column:" << initialTestFile->editor->currentColumn() - 1; - QStringList immediateVirtualSymbolResults; - QStringList finalVirtualSymbolResults; + OverrideItemList immediateVirtualSymbolResults; + OverrideItemList finalVirtualSymbolResults; // Trigger the action switch (m_action) { @@ -416,8 +454,8 @@ void TestCase::run(bool expectedFail) // qDebug() << immediateVirtualSymbolResults; // qDebug() << finalVirtualSymbolResults; - QCOMPARE(immediateVirtualSymbolResults, m_expectedVirtualSymbolsImmediateProposal); - QCOMPARE(finalVirtualSymbolResults, m_expectedVirtualSymbolsFinalProposals); + QCOMPARE(immediateVirtualSymbolResults, m_expectedVirtualFunctionImmediateProposal); + QCOMPARE(finalVirtualSymbolResults, m_expectedVirtualFunctionFinalProposals); } } // anonymous namespace @@ -1232,22 +1270,19 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_allOverri "struct CD2 : C { void virt(); };\n" "void CD2::virt() {}\n" "\n" - "int f(A *o)\n" - "{\n" - " o->$@virt();\n" + "int f(A *o) { o->$@virt(); }\n" "}\n" ; - const QStringList immediateResults = QStringList() - << QLatin1String("A::virt") - << QLatin1String("...searching overrides"); - const QStringList finalResults = QStringList() - << QLatin1String("A::virt") - << QLatin1String("A::virt") // TODO: Double entry - << QLatin1String("B::virt") - << QLatin1String("C::virt") - << QLatin1String("CD1::virt") - << QLatin1String("CD2::virt"); + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 2) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 2) + << OverrideItem(QLatin1String("B::virt"), 5) + << OverrideItem(QLatin1String("C::virt"), 8) + << OverrideItem(QLatin1String("CD1::virt"), 11) + << OverrideItem(QLatin1String("CD2::virt"), 14); TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); test.run(); @@ -1272,21 +1307,18 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleO "struct CD2 : C { void virt(); };\n" "void CD2::virt() {}\n" "\n" - "int f(B *o)\n" - "{\n" - " o->$@virt();\n" + "int f(B *o) { o->$@virt(); }\n" "}\n" ; - const QStringList immediateResults = QStringList() - << QLatin1String("B::virt") - << QLatin1String("...searching overrides"); - const QStringList finalResults = QStringList() - << QLatin1String("B::virt") - << QLatin1String("B::virt") // Double entry - << QLatin1String("C::virt") - << QLatin1String("CD1::virt") - << QLatin1String("CD2::virt"); + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("B::virt"), 5) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("B::virt"), 5) + << OverrideItem(QLatin1String("C::virt"), 8) + << OverrideItem(QLatin1String("CD1::virt"), 11) + << OverrideItem(QLatin1String("CD2::virt"), 14); TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); test.run(); @@ -1296,40 +1328,121 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleO void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides2() { const QByteArray source = - "struct A { virtual void f(); };\n" - "void A::f() {}\n" + "struct A { virtual void virt(); };\n" + "void A::virt() {}\n" + "\n" + "struct B : public A { void virt(); };\n" + "void B::virt() {}\n" + "\n" + "struct C : public B { void g() { virt$@(); } }; \n" + "\n" + "struct D : public C { void virt(); };\n" + "void D::virt() {}\n" + ; + + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("B::virt"), 5) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("B::virt"), 5) + << OverrideItem(QLatin1String("D::virt"), 10); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: If no definition is found, fallback to the declaration. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_fallbackToDeclaration() +{ + const QByteArray source = + "struct A { virtual void virt(); };\n" + "\n" + "int f(A *o) { o->$@virt(); }\n" + ; + + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 1) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 1); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: Ensure that the first entry in the final results is the same as the first in the +/// immediate results. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_itemOrder() +{ + const QByteArray source = + "struct C { virtual void virt() = 0; };\n" + "void C::virt() {}\n" "\n" - "struct B : public A { void f(); };\n" - "void B::f() {}\n" + "struct B : C { void virt(); };\n" + "void B::virt() {}\n" "\n" - "struct C : public B { void g() { f$@(); } }; \n" + "struct A : B { void virt(); };\n" + "void A::virt() {}\n" + "\n" + "int f(C *o) { o->$@virt(); }\n" + ; + + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("C::virt"), 2) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("C::virt"), 2) + << OverrideItem(QLatin1String("A::virt"), 8) + << OverrideItem(QLatin1String("B::virt"), 5); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); + test.run(); +} + +/// Check: Trigger on a.virt() if a is of type &A. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_onDotMemberAccessOfReferenceTypes() +{ + const QByteArray source = + "struct A { virtual void virt() = 0; };\n" + "void A::virt() {}\n" "\n" - "struct D : public C { void f(); };\n" - "void D::f() {}\n" + "void client(A &o) { o.$@virt(); }\n" ; - const QStringList immediateResults = QStringList() - << QLatin1String("B::f") - << QLatin1String("...searching overrides"); - const QStringList finalResults = QStringList() - << QLatin1String("B::f") - << QLatin1String("B::f") - << QLatin1String("D::f"); + const OverrideItemList immediateResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 2) + << OverrideItem(QLatin1String("...searching overrides")); + const OverrideItemList finalResults = OverrideItemList() + << OverrideItem(QLatin1String("A::virt"), 2); TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults); test.run(); } +/// Check: Do not trigger on a.virt() if a is of type A. +void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDotMemberAccessOfNonReferenceType() +{ + const QByteArray source = + "struct A { virtual void virt(); };\n" + "void A::$virt() {}\n" + "\n" + "void client(A o) { o.@virt(); }\n" + ; + + TestCase test(TestCase::FollowSymbolUnderCursorAction, source); + test.run(); +} + /// Check: Do not trigger on qualified function calls. void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified() { const QByteArray source = - "struct A { virtual void f(); };\n" - "void A::$f() {}\n" + "struct A { virtual void virt(); };\n" + "void A::$virt() {}\n" "\n" "struct B : public A {\n" - " void f();\n" - " void g() { A::@f(); }\n" + " void virt();\n" + " void g() { A::@virt(); }\n" "};\n" ; @@ -1341,11 +1454,11 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQual void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDeclaration() { const QByteArray source = - "struct A { virtual void f(); };\n" - "void A::f() {}\n" + "struct A { virtual void virt(); };\n" + "void A::virt() {}\n" "\n" - "struct B : public A { void f@(); };\n" - "void B::$f() {}\n" + "struct B : public A { void virt@(); };\n" + "void B::$virt() {}\n" ; TestCase test(TestCase::FollowSymbolUnderCursorAction, source); @@ -1356,11 +1469,11 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDecl void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefinition() { const QByteArray source = - "struct A { virtual void f(); };\n" - "void A::f() {}\n" + "struct A { virtual void virt(); };\n" + "void A::virt() {}\n" "\n" - "struct B : public A { void $f(); };\n" - "void B::@f() {}\n" + "struct B : public A { void $virt(); };\n" + "void B::@virt() {}\n" ; TestCase test(TestCase::FollowSymbolUnderCursorAction, source); @@ -1370,13 +1483,13 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefi void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnNonPointerNonReference() { const QByteArray source = - "struct A { virtual void f(); };\n" - "void A::f() {}\n" + "struct A { virtual void virt(); };\n" + "void A::virt() {}\n" "\n" - "struct B : public A { void f(); };\n" - "void B::$f() {}\n" + "struct B : public A { void virt(); };\n" + "void B::$virt() {}\n" "\n" - "void client(B b) { b.@f(); }\n" + "void client(B b) { b.@virt(); }\n" ; TestCase test(TestCase::FollowSymbolUnderCursorAction, source); diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index ff69f7746a..b720645032 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -51,11 +51,9 @@ #include <coreplugin/vcsmanager.h> #include <cppeditor/cppeditorconstants.h> +#include <utils/fileutils.h> #include <utils/hostosinfo.h> #include <utils/qtcassert.h> -#ifdef Q_OS_WIN -#include <utils/winutils.h> -#endif #include <QtPlugin> #include <QFileInfo> @@ -352,11 +350,7 @@ QString correspondingHeaderOrSource(const QString &fileName, bool *wasHeader) foreach (const QString &candidateDir, candidateDirs) { foreach (const QString &candidateFileName, candidateFileNames) { const QString candidateFilePath = candidateDir + QLatin1Char('/') + candidateFileName; -#ifdef Q_OS_WIN - const QString normalized = Utils::normalizePathName(candidateFilePath); -#else - const QString normalized = candidateFilePath; -#endif + const QString normalized = Utils::FileUtils::normalizePathName(candidateFilePath); const QFileInfo candidateFi(normalized); if (candidateFi.isFile()) { m_headerSourceMapping[fi.absoluteFilePath()] = candidateFi.absoluteFilePath(); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 52331b4e18..5376b4c914 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2879,11 +2879,7 @@ CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDeb const QString fileName = cdbSourcePathMapping(QDir::toNativeSeparators(f), m_sourcePathMappings, DebuggerToSource); // Up/lower case normalization according to Windows. -#ifdef Q_OS_WIN - QString normalized = Utils::normalizePathName(fileName); -#else - QString normalized = fileName; -#endif + const QString normalized = Utils::FileUtils::normalizePathName(fileName); if (debugSourceMapping) qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized)); // Check if it really exists, that is normalize worked and QFileInfo confirms it. diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index ce31216535..7798cf0bfe 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -24,9 +24,13 @@ HEADERS += \ debuggercore.h \ debuggerconstants.h \ debuggerinternalconstants.h \ + debuggeritem.h \ + debuggeritemmanager.h \ + debuggeritemmodel.h \ debuggerdialogs.h \ debuggerengine.h \ debuggermainwindow.h \ + debuggeroptionspage.h \ debuggerplugin.h \ debuggerprotocol.h \ debuggerrunconfigurationaspect.h \ @@ -80,12 +84,16 @@ SOURCES += \ debuggeractions.cpp \ debuggerdialogs.cpp \ debuggerengine.cpp \ + debuggeritem.cpp \ + debuggeritemmanager.cpp \ + debuggeritemmodel.cpp \ debuggermainwindow.cpp \ debuggerplugin.cpp \ debuggerprotocol.cpp \ debuggerrunconfigurationaspect.cpp \ debuggerrunner.cpp \ debuggerstreamops.cpp \ + debuggeroptionspage.cpp \ debuggerkitconfigwidget.cpp \ debuggerkitinformation.cpp \ disassembleragent.cpp \ diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 9032e84660..709dc128c3 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -40,9 +40,13 @@ QtcPlugin { "debuggerdialogs.cpp", "debuggerdialogs.h", "debuggerengine.cpp", "debuggerengine.h", "debuggerinternalconstants.h", + "debuggeritem.cpp", "debuggeritem.h", + "debuggeritemmanager.cpp", "debuggeritemmanager.h", + "debuggeritemmodel.cpp", "debuggeritemmodel.h", "debuggerkitconfigwidget.cpp", "debuggerkitconfigwidget.h", "debuggerkitinformation.cpp", "debuggerkitinformation.h", "debuggermainwindow.cpp", "debuggermainwindow.h", + "debuggeroptionspage.cpp", "debuggeroptionspage.h", "debuggerplugin.cpp", "debuggerplugin.h", "debuggerprotocol.cpp", "debuggerprotocol.h", "debuggerruncontrolfactory.h", diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 13f292de99..b1db49211d 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -248,7 +248,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) d->localExecutablePathChooser = new PathChooser(this); d->localExecutablePathChooser->setExpectedKind(PathChooser::File); d->localExecutablePathChooser->setPromptDialogTitle(tr("Select Executable")); - d->localExecutablePathChooser->lineEdit()->setHistoryCompleter(QLatin1String("LocalExecutable")); + d->localExecutablePathChooser->setHistoryCompleter(QLatin1String("LocalExecutable")); d->arguments = new FancyLineEdit(this); d->arguments->setHistoryCompleter(QLatin1String("CommandlineArguments")); @@ -256,7 +256,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) d->workingDirectory = new PathChooser(this); d->workingDirectory->setExpectedKind(PathChooser::ExistingDirectory); d->workingDirectory->setPromptDialogTitle(tr("Select Working Directory")); - d->workingDirectory->lineEdit()->setHistoryCompleter(QLatin1String("WorkingDirectory")); + d->workingDirectory->setHistoryCompleter(QLatin1String("WorkingDirectory")); d->runInTerminalCheckBox = new QCheckBox(this); @@ -633,7 +633,7 @@ AddressDialog::AddressDialog(QWidget *parent) : setWindowTitle(tr("Select Start Address")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); QHBoxLayout *hLayout = new QHBoxLayout; - hLayout->addWidget(new QLabel(tr("Enter an address: "))); + hLayout->addWidget(new QLabel(tr("Enter an address:") + QLatin1Char(' '))); hLayout->addWidget(m_lineEdit); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addLayout(hLayout); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 71b196a710..2bbea66f5b 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1676,9 +1676,9 @@ QString DebuggerEngine::msgInterrupted() void DebuggerEngine::showStoppedBySignalMessageBox(QString meaning, QString name) { if (name.isEmpty()) - name = tr(" <Unknown> ", "name"); + name = QLatin1Char(' ') + tr("<Unknown>", "name") + QLatin1Char(' '); if (meaning.isEmpty()) - meaning = tr(" <Unknown> ", "meaning"); + meaning = QLatin1Char(' ') + tr("<Unknown>", "meaning") + QLatin1Char(' '); const QString msg = tr("<p>The inferior stopped because it received a " "signal from the Operating System.<p>" "<table><tr><td>Signal name : </td><td>%1</td></tr>" diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp new file mode 100644 index 0000000000..0768d2ecdd --- /dev/null +++ b/src/plugins/debugger/debuggeritem.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "debuggerkitinformation.h" +#include "debuggerkitconfigwidget.h" +#include "debuggeroptionspage.h" + +#include <projectexplorer/abi.h> +#include <utils/fileutils.h> + +#include <QProcess> +#include <QUuid> + +using namespace Debugger::Internal; +using namespace ProjectExplorer; +using namespace Utils; + +static const char DEBUGGER_INFORMATION_COMMAND[] = "Binary"; +static const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName"; +static const char DEBUGGER_INFORMATION_ID[] = "Id"; +static const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType"; +static const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected"; +static const char DEBUGGER_INFORMATION_ABIS[] = "Abis"; + +namespace Debugger { + +// -------------------------------------------------------------------------- +// DebuggerItem +// -------------------------------------------------------------------------- + +DebuggerItem::DebuggerItem() +{ + m_id = QUuid::createUuid().toString(); + m_engineType = NoEngineType; + m_isAutoDetected = false; +} + +DebuggerItem::DebuggerItem(const QVariant &id) +{ + m_id = id; + m_engineType = NoEngineType; + m_isAutoDetected = false; +} + +DebuggerItem::DebuggerItem(const QVariantMap &data) +{ + m_command = FileName::fromUserInput(data.value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString()); + m_id = data.value(QLatin1String(DEBUGGER_INFORMATION_ID)).toString(); + m_displayName = data.value(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME)).toString(); + m_isAutoDetected = data.value(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), false).toBool(); + m_engineType = DebuggerEngineType(data.value(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), + static_cast<int>(NoEngineType)).toInt()); + + foreach (const QString &a, data.value(QLatin1String(DEBUGGER_INFORMATION_ABIS)).toStringList()) { + Abi abi(a); + if (abi.isValid()) + m_abis.append(abi); + } +} + +void DebuggerItem::reinitializeFromFile() +{ + QProcess proc; + proc.start(m_command.toString(), QStringList() << QLatin1String("--version")); + proc.waitForStarted(); + proc.waitForFinished(); + QByteArray ba = proc.readAll(); + if (ba.contains("gdb")) { + m_engineType = GdbEngineType; + const char needle[] = "This GDB was configured as \""; + // E.g. "--host=i686-pc-linux-gnu --target=arm-unknown-nto-qnx6.5.0". + // or "i686-linux-gnu" + int pos1 = ba.indexOf(needle); + if (pos1 != -1) { + pos1 += int(sizeof(needle)); + int pos2 = ba.indexOf('"', pos1 + 1); + QByteArray target = ba.mid(pos1, pos2 - pos1); + int pos3 = target.indexOf("--target="); + if (pos3 >= 0) + target = target.mid(pos3 + 9); + m_abis.append(Abi::abiFromTargetTriplet(QString::fromLatin1(target))); + } else { + // Fallback. + m_abis = Abi::abisOfBinary(m_command); // FIXME: Wrong. + } + return; + } + if (ba.contains("lldb") || ba.startsWith("LLDB")) { + m_engineType = LldbEngineType; + m_abis = Abi::abisOfBinary(m_command); + return; + } + if (ba.startsWith("Python")) { + m_engineType = PdbEngineType; + return; + } + m_engineType = NoEngineType; +} + +QString DebuggerItem::engineTypeName() const +{ + switch (m_engineType) { + case Debugger::NoEngineType: + return DebuggerOptionsPage::tr("Not recognized"); + case Debugger::GdbEngineType: + return QLatin1String("GDB"); + case Debugger::CdbEngineType: + return QLatin1String("CDB"); + case Debugger::LldbEngineType: + return QLatin1String("LLDB"); + default: + return QString(); + } +} + +QStringList DebuggerItem::abiNames() const +{ + QStringList list; + foreach (const Abi &abi, m_abis) + list.append(abi.toString()); + return list; +} + +bool DebuggerItem::operator==(const DebuggerItem &other) const +{ + return m_id == other.m_id + && m_displayName == other.m_displayName + && m_isAutoDetected == other.m_isAutoDetected + && m_command == other.m_command; +} + +QVariantMap DebuggerItem::toMap() const +{ + QVariantMap data; + data.insert(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME), m_displayName); + data.insert(QLatin1String(DEBUGGER_INFORMATION_ID), m_id); + data.insert(QLatin1String(DEBUGGER_INFORMATION_COMMAND), m_command.toUserOutput()); + data.insert(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), int(m_engineType)); + data.insert(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), m_isAutoDetected); + data.insert(QLatin1String(DEBUGGER_INFORMATION_ABIS), abiNames()); + return data; +} + +void DebuggerItem::setDisplayName(const QString &displayName) +{ + m_displayName = displayName; +} + +void DebuggerItem::setEngineType(const DebuggerEngineType &engineType) +{ + m_engineType = engineType; +} + +void DebuggerItem::setCommand(const Utils::FileName &command) +{ + m_command = command; +} + +void DebuggerItem::setAutoDetected(bool isAutoDetected) +{ + m_isAutoDetected = isAutoDetected; +} + +void DebuggerItem::setAbis(const QList<ProjectExplorer::Abi> &abis) +{ + m_abis = abis; +} + +void DebuggerItem::setAbi(const Abi &abi) +{ + m_abis.clear(); + m_abis.append(abi); +} + +static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &targetAbi) +{ + if (debuggerAbi.architecture() != Abi::UnknownArchitecture + && debuggerAbi.architecture() != targetAbi.architecture()) + return DebuggerItem::DoesNotMatch; + + if (debuggerAbi.os() != Abi::UnknownOS + && debuggerAbi.os() != targetAbi.os()) + return DebuggerItem::DoesNotMatch; + + if (debuggerAbi.binaryFormat() != Abi::UnknownFormat + && debuggerAbi.binaryFormat() != targetAbi.binaryFormat()) + return DebuggerItem::DoesNotMatch; + + if (debuggerAbi.os() == Abi::WindowsOS) { + if (debuggerAbi.osFlavor() == Abi::WindowsMSysFlavor && targetAbi.osFlavor() != Abi::WindowsMSysFlavor) + return DebuggerItem::DoesNotMatch; + if (debuggerAbi.osFlavor() != Abi::WindowsMSysFlavor && targetAbi.osFlavor() == Abi::WindowsMSysFlavor) + return DebuggerItem::DoesNotMatch; + } + + if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) + return DebuggerItem::MatchesSomewhat; + if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth()) + return DebuggerItem::DoesNotMatch; + + return DebuggerItem::MatchesPerfectly; +} + +DebuggerItem::MatchLevel DebuggerItem::matchTarget(const Abi &targetAbi) const +{ + MatchLevel bestMatch = DoesNotMatch; + foreach (const Abi &debuggerAbi, m_abis) { + MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi); + if (currentMatch > bestMatch) + bestMatch = currentMatch; + } + return bestMatch; +} + +bool Debugger::DebuggerItem::isValid() const +{ + return !m_id.isNull(); +} + +} // namespace Debugger; + +#ifdef WITH_TESTS + +# include <QTest> +# include "debuggerplugin.h" + +void Debugger::DebuggerPlugin::testDebuggerMatching_data() +{ + QTest::addColumn<QStringList>("debugger"); + QTest::addColumn<QString>("target"); + QTest::addColumn<int>("result"); + + QTest::newRow("Invalid data") + << QStringList() + << QString() + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("Invalid debugger") + << QStringList() + << QString::fromLatin1("x86-linux-generic-elf-32bit") + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("Invalid target") + << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) + << QString() + << int(DebuggerItem::DoesNotMatch); + + QTest::newRow("Fuzzy match 1") + << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit")) + << QString::fromLatin1("x86-linux-generic-elf-32bit") + << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior? + QTest::newRow("Fuzzy match 2") + << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit")) + << QString::fromLatin1("arm-windows-msys-pe-64bit") + << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior? + + QTest::newRow("Architecture mismatch") + << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) + << QString::fromLatin1("arm-linux-generic-elf-32bit") + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("OS mismatch") + << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) + << QString::fromLatin1("x86-macosx-generic-elf-32bit") + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("Format mismatch") + << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) + << QString::fromLatin1("x86-linux-generic-pe-32bit") + << int(DebuggerItem::DoesNotMatch); + + QTest::newRow("Linux perfect match") + << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) + << QString::fromLatin1("x86-linux-generic-elf-32bit") + << int(DebuggerItem::MatchesPerfectly); + QTest::newRow("Linux match") + << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")) + << QString::fromLatin1("x86-linux-generic-elf-32bit") + << int(DebuggerItem::MatchesSomewhat); + + QTest::newRow("Windows perfect match 1") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) + << QString::fromLatin1("x86-windows-msvc2013-pe-64bit") + << int(DebuggerItem::MatchesPerfectly); + QTest::newRow("Windows perfect match 2") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) + << QString::fromLatin1("x86-windows-msvc2012-pe-64bit") + << int(DebuggerItem::MatchesPerfectly); + QTest::newRow("Windows match 1") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) + << QString::fromLatin1("x86-windows-msvc2013-pe-32bit") + << int(DebuggerItem::MatchesSomewhat); + QTest::newRow("Windows match 2") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) + << QString::fromLatin1("x86-windows-msvc2012-pe-32bit") + << int(DebuggerItem::MatchesSomewhat); + QTest::newRow("Windows mismatch on word size") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit")) + << QString::fromLatin1("x86-windows-msvc2013-pe-64bit") + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("Windows mismatch on osflavor 1") + << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit")) + << QString::fromLatin1("x86-windows-msys-pe-64bit") + << int(DebuggerItem::DoesNotMatch); + QTest::newRow("Windows mismatch on osflavor 2") + << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit")) + << QString::fromLatin1("x86-windows-msvc2010-pe-64bit") + << int(DebuggerItem::DoesNotMatch); +} + +void Debugger::DebuggerPlugin::testDebuggerMatching() +{ + QFETCH(QStringList, debugger); + QFETCH(QString, target); + QFETCH(int, result); + + DebuggerItem::MatchLevel expectedLevel = static_cast<DebuggerItem::MatchLevel>(result); + + QList<Abi> debuggerAbis; + foreach (const QString &abi, debugger) + debuggerAbis << Abi(abi); + + DebuggerItem item; + item.setAbis(debuggerAbis); + + DebuggerItem::MatchLevel level = item.matchTarget(Abi(target)); + + QCOMPARE(expectedLevel, level); +} +#endif diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h new file mode 100644 index 0000000000..14219471e9 --- /dev/null +++ b/src/plugins/debugger/debuggeritem.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DEBUGGER_DEBUGGERITEM_H +#define DEBUGGER_DEBUGGERITEM_H + +#include "debugger_global.h" +#include "debuggerconstants.h" + +#include <projectexplorer/abi.h> + +#include <utils/fileutils.h> + +#include <QList> +#include <QVariant> + +namespace Debugger { + +namespace Internal { class DebuggerItemModel; } + +// ----------------------------------------------------------------------- +// DebuggerItem +// ----------------------------------------------------------------------- + +class DEBUGGER_EXPORT DebuggerItem +{ +public: + DebuggerItem(); + DebuggerItem(const QVariantMap &data); + + bool canClone() const { return true; } + bool isValid() const; + QString engineTypeName() const; + + QVariantMap toMap() const; + void reinitializeFromFile(); + + QVariant id() const { return m_id; } + + QString displayName() const { return m_displayName; } + void setDisplayName(const QString &displayName); + + DebuggerEngineType engineType() const { return m_engineType; } + void setEngineType(const DebuggerEngineType &engineType); + + Utils::FileName command() const { return m_command; } + void setCommand(const Utils::FileName &command); + + bool isAutoDetected() const { return m_isAutoDetected; } + void setAutoDetected(bool isAutoDetected); + + QList<ProjectExplorer::Abi> abis() const { return m_abis; } + void setAbis(const QList<ProjectExplorer::Abi> &abis); + void setAbi(const ProjectExplorer::Abi &abi); + + enum MatchLevel { DoesNotMatch, MatchesSomewhat, MatchesPerfectly }; + MatchLevel matchTarget(const ProjectExplorer::Abi &targetAbi) const; + + QStringList abiNames() const; + + bool operator==(const DebuggerItem &other) const; + +private: + DebuggerItem(const QVariant &id); + + QVariant m_id; + QString m_displayName; + DebuggerEngineType m_engineType; + Utils::FileName m_command; + bool m_isAutoDetected; + QList<ProjectExplorer::Abi> m_abis; + + friend class Internal::DebuggerItemModel; +}; + +} // namespace Debugger + +#endif // DEBUGGER_DEBUGGERITEM_H diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp new file mode 100644 index 0000000000..fcca5d8eac --- /dev/null +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "debuggeritemmanager.h" + +#include "debuggeritemmodel.h" +#include "debuggerkitinformation.h" + +#include <coreplugin/icore.h> + +#include <utils/environment.h> +#include <utils/fileutils.h> +#include <utils/persistentsettings.h> +#include <utils/qtcassert.h> + +#include <QDebug> +#include <QDir> +#include <QFileInfo> + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Debugger { + +static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count"; +static const char DEBUGGER_DATA_KEY[] = "DebuggerItem."; +static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml"; +static const char DEBUGGER_FILE_VERSION_KEY[] = "Version"; +static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml"; + +// -------------------------------------------------------------------------- +// DebuggerItemManager +// -------------------------------------------------------------------------- + +static DebuggerItemManager *m_instance = 0; + +static FileName userSettingsFileName() +{ + QFileInfo settingsLocation(Core::ICore::settings()->fileName()); + return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME)); +} + +static void readDebuggers(const FileName &fileName, bool isSystem) +{ + PersistentSettingsReader reader; + if (!reader.load(fileName)) + return; + QVariantMap data = reader.restoreValues(); + + // Check version + int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt(); + if (version < 1) + return; + + int count = data.value(QLatin1String(DEBUGGER_COUNT_KEY), 0).toInt(); + for (int i = 0; i < count; ++i) { + const QString key = QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(i); + if (!data.contains(key)) + continue; + const QVariantMap dbMap = data.value(key).toMap(); + DebuggerItem item(dbMap); + if (isSystem) { + item.setAutoDetected(true); + // SDK debuggers are always considered to be up-to-date, so no need to recheck them. + } else { + // User settings. + if (item.isAutoDetected() && (!item.isValid() || item.engineType() == NoEngineType)) { + qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid") + .arg(item.command().toString()).arg(item.id().toString()); + continue; + } + } + DebuggerItemManager::registerDebugger(item); + } +} + +QList<DebuggerItem> DebuggerItemManager::m_debuggers; +PersistentSettingsWriter * DebuggerItemManager::m_writer = 0; + +DebuggerItemManager::DebuggerItemManager(QObject *parent) + : QObject(parent) +{ + m_instance = this; + m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger")); + connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), + this, SLOT(saveDebuggers())); +} + +QObject *DebuggerItemManager::instance() +{ + return m_instance; +} + +DebuggerItemManager::~DebuggerItemManager() +{ + disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), + this, SLOT(saveDebuggers())); + delete m_writer; +} + +QList<DebuggerItem> DebuggerItemManager::debuggers() +{ + return m_debuggers; +} + +void DebuggerItemManager::autoDetectCdbDebuggers() +{ + QList<FileName> cdbs; + + QStringList programDirs; + programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles"))); + programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)"))); + programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432"))); + + foreach (const QString &dirName, programDirs) { + if (dirName.isEmpty()) + continue; + QDir dir(dirName); + // Windows SDK's starting from version 8 live in + // "ProgramDir\Windows Kits\<version>" + const QString windowsKitsFolderName = QLatin1String("Windows Kits"); + if (dir.exists(windowsKitsFolderName)) { + QDir windowKitsFolder = dir; + if (windowKitsFolder.cd(windowsKitsFolderName)) { + // Check in reverse order (latest first) + const QFileInfoList kitFolders = + windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, + QDir::Time | QDir::Reversed); + foreach (const QFileInfo &kitFolderFi, kitFolders) { + const QString path = kitFolderFi.absoluteFilePath(); + const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe")); + if (cdb32.isExecutable()) + cdbs.append(FileName::fromString(cdb32.absoluteFilePath())); + const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe")); + if (cdb64.isExecutable()) + cdbs.append(FileName::fromString(cdb64.absoluteFilePath())); + } + } + } + + // Pre Windows SDK 8: Check 'Debugging Tools for Windows' + foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")), + QDir::Dirs | QDir::NoDotAndDotDot)) { + FileName filePath(fi); + filePath.appendPath(QLatin1String("cdb.exe")); + if (!cdbs.contains(filePath)) + cdbs.append(filePath); + } + } + + foreach (const FileName &cdb, cdbs) { + if (findByCommand(cdb)) + continue; + DebuggerItem item; + item.setAutoDetected(true); + item.setAbis(Abi::abisOfBinary(cdb)); + item.setCommand(cdb); + item.setEngineType(CdbEngineType); + item.setDisplayName(uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput()))); + addDebugger(item); + } +} + +void DebuggerItemManager::autoDetectGdbOrLldbDebuggers() +{ + QStringList filters; + filters.append(QLatin1String("gdb-i686-pc-mingw32")); + filters.append(QLatin1String("gdb")); + filters.append(QLatin1String("lldb")); + filters.append(QLatin1String("lldb-*")); + +// DebuggerItem result; +// result.setAutoDetected(true); +// result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName())); + /* + // Check suggestions from the SDK. + Environment env = Environment::systemEnvironment(); + if (tc) { + tc->addToEnvironment(env); // Find MinGW gdb in toolchain environment. + QString path = tc->suggestedDebugger().toString(); + if (!path.isEmpty()) { + const QFileInfo fi(path); + if (!fi.isAbsolute()) + path = env.searchInPath(path); + result.command = FileName::fromString(path); + result.engineType = engineTypeFromBinary(path); + return maybeAddDebugger(result, false); + } + } + */ + + QFileInfoList suspects; + + QStringList path = Environment::systemEnvironment().path(); + foreach (const QString &base, path) { + QDir dir(base); + dir.setNameFilters(filters); + suspects += dir.entryInfoList(); + } + + foreach (const QFileInfo &fi, suspects) { + if (fi.exists()) { + FileName command = FileName::fromString(fi.absoluteFilePath()); + if (findByCommand(command)) + continue; + DebuggerItem item; + item.setCommand(command); + item.reinitializeFromFile(); + //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path + item.setDisplayName(tr("System %1 at %2") + .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath()))); + item.setAutoDetected(true); + addDebugger(item); + } + } +} + +void DebuggerItemManager::readLegacyDebuggers() +{ + QFileInfo settingsLocation(Core::ICore::settings()->fileName()); + FileName legacyKits = FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME)); + + PersistentSettingsReader reader; + if (!reader.load(legacyKits)) + return; + + foreach (const QVariant &v, reader.restoreValues()) { + QVariantMap data1 = v.toMap(); + QString kitName = data1.value(QLatin1String("PE.Profile.Name")).toString(); + QVariantMap data2 = data1.value(QLatin1String("PE.Profile.Data")).toMap(); + QVariant v3 = data2.value(DebuggerKitInformation::id().toString()); + QString fn; + if (v3.type() == QVariant::String) + fn = v3.toString(); + else + fn = v3.toMap().value(QLatin1String("Binary")).toString(); + if (fn.isEmpty()) + continue; + if (fn.startsWith(QLatin1Char('{'))) + continue; + if (fn == QLatin1String("auto")) + continue; + FileName command = FileName::fromUserInput(fn); + if (findByCommand(command)) + continue; + DebuggerItem item; + item.setCommand(command); + item.setAutoDetected(true); + item.reinitializeFromFile(); + item.setDisplayName(tr("Extracted from Kit %1").arg(kitName)); + addDebugger(item); + } +} + +const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command) +{ + foreach (const DebuggerItem &item, m_debuggers) + if (item.command() == command) + return &item; + + return 0; +} + +const DebuggerItem *DebuggerItemManager::findById(const QVariant &id) +{ + foreach (const DebuggerItem &item, m_debuggers) + if (item.id() == id) + return &item; + + return 0; +} + +void DebuggerItemManager::restoreDebuggers() +{ + // Read debuggers from SDK + QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); + readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true); + + // Read all debuggers from user file. + readDebuggers(userSettingsFileName(), false); + + // Auto detect current. + autoDetectCdbDebuggers(); + autoDetectGdbOrLldbDebuggers(); + + // Add debuggers from pre-3.x profiles.xml + readLegacyDebuggers(); +} + +void DebuggerItemManager::saveDebuggers() +{ + QTC_ASSERT(m_writer, return); + QVariantMap data; + data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1); + + int count = 0; + foreach (const DebuggerItem &item, m_debuggers) { + if (item.isValid() && item.engineType() != NoEngineType) { + QVariantMap tmp = item.toMap(); + if (tmp.isEmpty()) + continue; + data.insert(QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(count), tmp); + ++count; + } + } + data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count); + m_writer->save(data, Core::ICore::mainWindow()); + + // Do not save default debuggers as they are set by the SDK. +} + +QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item) +{ + QTC_ASSERT(!findById(item.id()), return item.id()); + + return addDebugger(item); +} + +void DebuggerItemManager::deregisterDebugger(const DebuggerItem &item) +{ + QTC_ASSERT(!item.command().isEmpty(), return); + QTC_ASSERT(!item.displayName().isEmpty(), return); + QTC_ASSERT(item.engineType() != NoEngineType, return); + + if (findById(item.id())) + removeDebugger(item.id()); +} + +QVariant DebuggerItemManager::addDebugger(const DebuggerItem &item) +{ + QTC_ASSERT(item.id().isValid(), return QVariant()); + m_debuggers.append(item); + QVariant id = item.id(); + emit m_instance->debuggerAdded(id); + return id; +} + +void DebuggerItemManager::removeDebugger(const QVariant &id) +{ + bool ok = false; + for (int i = 0, n = m_debuggers.size(); i != n; ++i) { + if (m_debuggers.at(i).id() == id) { + emit m_instance->aboutToRemoveDebugger(id); + m_debuggers.removeAt(i); + emit m_instance->debuggerRemoved(id); + ok = true; + break; + } + } + + QTC_ASSERT(ok, return); +} + +QString DebuggerItemManager::uniqueDisplayName(const QString &base) +{ + foreach (const DebuggerItem &item, m_debuggers) + if (item.displayName() == base) + return uniqueDisplayName(base + QLatin1String(" (1)")); + + return base; +} + +void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName) +{ + for (int i = 0, n = m_debuggers.size(); i != n; ++i) { + DebuggerItem &item = m_debuggers[i]; + if (item.id() == id) { + item.setDisplayName(displayName); + item.setCommand(fileName); + item.reinitializeFromFile(); + emit m_instance->debuggerUpdated(id); + break; + } + } +} + +} // namespace Debugger; diff --git a/src/plugins/debugger/debuggeritemmanager.h b/src/plugins/debugger/debuggeritemmanager.h new file mode 100644 index 0000000000..27ad45614b --- /dev/null +++ b/src/plugins/debugger/debuggeritemmanager.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DEBUGGER_DEBUGGERITEMMANAGER_H +#define DEBUGGER_DEBUGGERITEMMANAGER_H + +#include "debugger_global.h" +#include "debuggeritem.h" +#include "debuggeritemmodel.h" + +#include <QList> +#include <QObject> +#include <QString> + +namespace Utils { class PersistentSettingsWriter; } + +namespace Debugger { + +// ----------------------------------------------------------------------- +// DebuggerItemManager +// ----------------------------------------------------------------------- + +class DEBUGGER_EXPORT DebuggerItemManager : public QObject +{ + Q_OBJECT + +public: + static QObject *instance(); + ~DebuggerItemManager(); + + static QList<DebuggerItem> debuggers(); + + static QVariant registerDebugger(const DebuggerItem &item); + static void deregisterDebugger(const DebuggerItem &item); + static void setItemData(const QVariant &id, const QString& displayName, const Utils::FileName &fileName); + + static const DebuggerItem *findByCommand(const Utils::FileName &command); + static const DebuggerItem *findById(const QVariant &id); + + static void restoreDebuggers(); + static QString uniqueDisplayName(const QString &base); + + static void removeDebugger(const QVariant &id); + static QVariant addDebugger(const DebuggerItem &item); + +signals: + void debuggerAdded(const QVariant &id); + void aboutToRemoveDebugger(const QVariant &id); + void debuggerRemoved(const QVariant &id); + void debuggerUpdated(const QVariant &id); + +public slots: + void saveDebuggers(); + +private: + explicit DebuggerItemManager(QObject *parent = 0); + static void autoDetectGdbOrLldbDebuggers(); + static void autoDetectCdbDebuggers(); + static void readLegacyDebuggers(); + + static Utils::PersistentSettingsWriter *m_writer; + static QList<DebuggerItem> m_debuggers; + + friend class Internal::DebuggerItemModel; + friend class DebuggerPlugin; // Enable constrcutor for DebuggerPlugin +}; + +} // namespace Debugger + +#endif // DEBUGGER_DEBUGGERITEMMANAGER_H diff --git a/src/plugins/debugger/debuggeritemmodel.cpp b/src/plugins/debugger/debuggeritemmodel.cpp new file mode 100644 index 0000000000..2adb8d75d4 --- /dev/null +++ b/src/plugins/debugger/debuggeritemmodel.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "debuggeritemmodel.h" + +#include "debuggeritem.h" +#include "debuggeritemmanager.h" + +#include <utils/qtcassert.h> + +namespace Debugger { +namespace Internal { + +static QList<QStandardItem *> describeItem(const DebuggerItem &item) +{ + QList<QStandardItem *> row; + row.append(new QStandardItem(item.displayName())); + row.append(new QStandardItem(item.command().toUserOutput())); + row.append(new QStandardItem(item.engineTypeName())); + row.at(0)->setData(item.id()); + row.at(0)->setData(item.abiNames(), Qt::UserRole + 2); + row.at(0)->setEditable(false); + row.at(1)->setEditable(false); + row.at(1)->setData(item.toMap()); + row.at(2)->setEditable(false); + row.at(2)->setData(static_cast<int>(item.engineType())); + row.at(0)->setSelectable(true); + row.at(1)->setSelectable(true); + row.at(2)->setSelectable(true); + return row; +} + +static QList<QStandardItem *> createRow(const QString &display) +{ + QList<QStandardItem *> row; + row.append(new QStandardItem(display)); + row.append(new QStandardItem()); + row.append(new QStandardItem()); + row.at(0)->setEditable(false); + row.at(1)->setEditable(false); + row.at(2)->setEditable(false); + row.at(0)->setSelectable(false); + row.at(1)->setSelectable(false); + row.at(2)->setSelectable(false); + return row; +} + +// -------------------------------------------------------------------------- +// DebuggerItemModel +// -------------------------------------------------------------------------- + +DebuggerItemModel::DebuggerItemModel(QObject *parent) + : QStandardItemModel(parent) +{ + setColumnCount(3); + + QList<QStandardItem *> row = createRow(tr("Auto-detected")); + m_autoRoot = row.at(0); + appendRow(row); + + row = createRow(tr("Manual")); + m_manualRoot = row.at(0); + appendRow(row); + + foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) + addDebuggerStandardItem(item, false); + + QObject *manager = DebuggerItemManager::instance(); + connect(manager, SIGNAL(debuggerAdded(QVariant)), + this, SLOT(onDebuggerAdded(QVariant))); + connect(manager, SIGNAL(debuggerUpdated(QVariant)), + this, SLOT(onDebuggerUpdate(QVariant))); + connect(manager, SIGNAL(debuggerRemoved(QVariant)), + this, SLOT(onDebuggerRemoval(QVariant))); +} + +QVariant DebuggerItemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + switch (section) { + case 0: + return tr("Name"); + case 1: + return tr("Path"); + case 2: + return tr("Type"); + } + } + return QVariant(); +} + +bool DebuggerItemModel::addDebuggerStandardItem(const DebuggerItem &item, bool changed) +{ + if (findStandardItemById(item.id())) + return false; + + QList<QStandardItem *> row = describeItem(item); + foreach (QStandardItem *cell, row) { + QFont font = cell->font(); + font.setBold(changed); + cell->setFont(font); + } + (item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row); + return true; +} + +bool DebuggerItemModel::removeDebuggerStandardItem(const QVariant &id) +{ + QStandardItem *sitem = findStandardItemById(id); + QTC_ASSERT(sitem, return false); + QStandardItem *parent = sitem->parent(); + QTC_ASSERT(parent, return false); + // This will trigger a change of m_currentDebugger via changing the + // view selection. + parent->removeRow(sitem->row()); + return true; +} + +bool DebuggerItemModel::updateDebuggerStandardItem(const DebuggerItem &item, bool changed) +{ + QStandardItem *sitem = findStandardItemById(item.id()); + QTC_ASSERT(sitem, return false); + QStandardItem *parent = sitem->parent(); + QTC_ASSERT(parent, return false); + int row = sitem->row(); + QFont font = sitem->font(); + font.setBold(changed); + parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole); + parent->child(row, 0)->setFont(font); + parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole); + parent->child(row, 1)->setFont(font); + parent->child(row, 2)->setData(item.engineTypeName(), Qt::DisplayRole); + parent->child(row, 2)->setData(static_cast<int>(item.engineType())); + parent->child(row, 2)->setFont(font); + return true; +} + +DebuggerItem DebuggerItemModel::debuggerItem(QStandardItem *sitem) const +{ + DebuggerItem item = DebuggerItem(QVariant()); + if (sitem && sitem->parent()) { + item.setAutoDetected(sitem->parent() == m_autoRoot); + + QStandardItem *i = sitem->parent()->child(sitem->row(), 0); + item.m_id = i->data(); + item.setDisplayName(i->data(Qt::DisplayRole).toString()); + + QStringList abis = i->data(Qt::UserRole + 2).toStringList(); + QList<ProjectExplorer::Abi> abiList; + foreach (const QString &abi, abis) + abiList << ProjectExplorer::Abi(abi); + item.setAbis(abiList); + + i = sitem->parent()->child(sitem->row(), 1); + item.setCommand(Utils::FileName::fromUserInput(i->data(Qt::DisplayRole).toString())); + + i = sitem->parent()->child(sitem->row(), 2); + item.setEngineType(static_cast<DebuggerEngineType>(i->data().toInt())); + } + return item; +} + +QList<DebuggerItem> DebuggerItemModel::debuggerItems() const +{ + QList<DebuggerItem> result; + for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) + result << debuggerItem(m_autoRoot->child(i)); + for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) + result << debuggerItem(m_manualRoot->child(i)); + return result; +} + +QStandardItem *DebuggerItemModel::currentStandardItem() const +{ + return findStandardItemById(m_currentDebugger); +} + +QStandardItem *DebuggerItemModel::findStandardItemById(const QVariant &id) const +{ + for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) { + QStandardItem *sitem = m_autoRoot->child(i); + if (sitem->data() == id) + return sitem; + } + for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) { + QStandardItem *sitem = m_manualRoot->child(i); + if (sitem->data() == id) + return sitem; + } + return 0; +} + +QModelIndex DebuggerItemModel::currentIndex() const +{ + QStandardItem *current = currentStandardItem(); + return current ? current->index() : QModelIndex(); +} + +QModelIndex DebuggerItemModel::lastIndex() const +{ + int n = m_manualRoot->rowCount(); + QStandardItem *current = m_manualRoot->child(n - 1); + return current ? current->index() : QModelIndex(); +} + +void DebuggerItemModel::onDebuggerAdded(const QVariant &id) +{ + const DebuggerItem *item = DebuggerItemManager::findById(id); + QTC_ASSERT(item, return); + if (!addDebuggerStandardItem(*item, false)) + updateDebuggerStandardItem(*item, false); // already had it added, so just update it. +} + +void DebuggerItemModel::onDebuggerUpdate(const QVariant &id) +{ + const DebuggerItem *item = DebuggerItemManager::findById(id); + QTC_ASSERT(item, return); + updateDebuggerStandardItem(*item, false); +} + +void DebuggerItemModel::onDebuggerRemoval(const QVariant &id) +{ + removeDebuggerStandardItem(id); +} + +void DebuggerItemModel::addDebugger(const DebuggerItem &item) +{ + addDebuggerStandardItem(item, true); +} + +void DebuggerItemModel::removeDebugger(const QVariant &id) +{ + if (!removeDebuggerStandardItem(id)) // Nothing there! + return; + + if (DebuggerItemManager::findById(id)) + m_removedItems.append(id); +} + +void DebuggerItemModel::updateDebugger(const DebuggerItem &item) +{ + updateDebuggerStandardItem(item, true); +} + +void DebuggerItemModel::apply() +{ + foreach (const QVariant &id, m_removedItems) { + const DebuggerItem *item = DebuggerItemManager::findById(id); + QTC_CHECK(item); + DebuggerItemManager::deregisterDebugger(*item); + } + + foreach (const DebuggerItem &item, debuggerItems()) { + const DebuggerItem *managed = DebuggerItemManager::findById(item.id()); + if (managed) { + if (*managed == item) + continue; + else + DebuggerItemManager::setItemData(item.id(), item.displayName(), item.command()); + } else { + DebuggerItemManager::registerDebugger(item); + } + } +} + +void DebuggerItemModel::setCurrentIndex(const QModelIndex &index) +{ + QStandardItem *sit = itemFromIndex(index); + m_currentDebugger = sit ? sit->data() : QVariant(); +} + +DebuggerItem DebuggerItemModel::currentDebugger() const +{ + return debuggerItem(currentStandardItem()); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/debuggeritemmodel.h b/src/plugins/debugger/debuggeritemmodel.h new file mode 100644 index 0000000000..1f26169625 --- /dev/null +++ b/src/plugins/debugger/debuggeritemmodel.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DEBUGGER_DEBUGGERITEMMODEL_H +#define DEBUGGER_DEBUGGERITEMMODEL_H + +#include "debuggeritem.h" + +#include <QStandardItemModel> +#include <QVariant> + +namespace Debugger { +namespace Internal { + +// ----------------------------------------------------------------------- +// DebuggerItemModel +//------------------------------------------------------------------------ + +class DebuggerItemModel : public QStandardItemModel +{ + Q_OBJECT + +public: + DebuggerItemModel(QObject *parent = 0); + + QModelIndex currentIndex() const; + QModelIndex lastIndex() const; + void setCurrentIndex(const QModelIndex &index); + QVariant currentDebuggerId() const { return m_currentDebugger; } + DebuggerItem currentDebugger() const; + void addDebugger(const DebuggerItem &item); + void removeDebugger(const QVariant &id); + void updateDebugger(const DebuggerItem &item); + + void apply(); + +private slots: + void onDebuggerAdded(const QVariant &id); + void onDebuggerUpdate(const QVariant &id); + void onDebuggerRemoval(const QVariant &id); + +private: + QStandardItem *currentStandardItem() const; + QStandardItem *findStandardItemById(const QVariant &id) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + bool addDebuggerStandardItem(const DebuggerItem &item, bool changed); + bool removeDebuggerStandardItem(const QVariant &id); + bool updateDebuggerStandardItem(const DebuggerItem &item, bool changed); + + DebuggerItem debuggerItem(QStandardItem *sitem) const; + QList<DebuggerItem> debuggerItems() const; + + QVariant m_currentDebugger; + + QStandardItem *m_autoRoot; + QStandardItem *m_manualRoot; + QStringList removed; + + QList<QVariant> m_removedItems; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_DEBUGGERITEMMODEL_H diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp index 9d9f0b23a9..9ced9edf69 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.cpp +++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp @@ -29,6 +29,10 @@ #include "debuggerkitconfigwidget.h" +#include "debuggeritemmanager.h" +#include "debuggeritemmodel.h" +#include "debuggerkitinformation.h" + #include <coreplugin/icore.h> #include <projectexplorer/abi.h> @@ -64,816 +68,10 @@ using namespace Utils; using namespace Debugger::Internal; namespace Debugger { - -static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging"; - -static const char DEBUGGER_DATA_KEY[] = "DebuggerItem."; -static const char DEBUGGER_COUNT_KEY[] = "DebuggerItem.Count"; -static const char DEBUGGER_FILE_VERSION_KEY[] = "Version"; -static const char DEBUGGER_FILENAME[] = "/qtcreator/debuggers.xml"; -static const char DEBUGGER_LEGACY_FILENAME[] = "/qtcreator/profiles.xml"; - -// -------------------------------------------------------------------------- -// DebuggerKitInformation -// -------------------------------------------------------------------------- - -DebuggerKitInformation::DebuggerKitInformation() -{ - setObjectName(QLatin1String("DebuggerKitInformation")); - setId(DebuggerKitInformation::id()); - setPriority(28000); -} - -QVariant DebuggerKitInformation::defaultValue(Kit *k) const -{ - ToolChain *tc = ToolChainKitInformation::toolChain(k); - QTC_ASSERT(tc, return QVariant()); - - const Abi toolChainAbi = tc->targetAbi(); - foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) - foreach (const Abi targetAbi, item.abis()) - if (targetAbi.isCompatibleWith(toolChainAbi)) - return item.id(); - - return QVariant(); -} - -void DebuggerKitInformation::setup(Kit *k) -{ - // Get one of the available debugger matching the kit's toolchain. - const ToolChain *tc = ToolChainKitInformation::toolChain(k); - const Abi toolChainAbi = tc ? tc->targetAbi() : Abi::hostAbi(); - - // This can be anything (Id, binary path, "auto") - const QVariant rawId = k->value(DebuggerKitInformation::id()); - - enum { - NotDetected, DetectedAutomatically, DetectedByFile, DetectedById - } detection = NotDetected; - DebuggerEngineType autoEngine = NoEngineType; - FileName fileName; - - // With 3.0 we have: - // <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value> - // Before we had: - // <valuemap type="QVariantMap" key="Debugger.Information"> - // <value type="QString" key="Binary">/data/dev/debugger/gdb-git/gdb/gdb</value> - // <value type="int" key="EngineType">1</value> - // </valuemap> - // Or for force auto-detected CDB - // <valuemap type="QVariantMap" key="Debugger.Information"> - // <value type="QString" key="Binary">auto</value> - // <value type="int" key="EngineType">4</value> - // </valuemap> - - if (rawId.isNull()) { - // Initial setup of a kit - detection = NotDetected; - } else if (rawId.type() == QVariant::String) { - detection = DetectedById; - } else { - QMap<QString, QVariant> map = rawId.toMap(); - QString binary = map.value(QLatin1String("Binary")).toString(); - if (binary == QLatin1String("auto")) { - detection = DetectedAutomatically; - autoEngine = DebuggerEngineType(map.value(QLatin1String("EngineType")).toInt()); - } else { - detection = DetectedByFile; - fileName = FileName::fromUserInput(binary); - } - } - - const DebuggerItem *bestItem = 0; - DebuggerItem::MatchLevel bestLevel = DebuggerItem::DoesNotMatch; - foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) { - const DebuggerItem *goodItem = 0; - if (detection == DetectedById && item.id() == rawId) - goodItem = &item; - if (detection == DetectedByFile && item.command() == fileName) - goodItem = &item; - if (detection == DetectedAutomatically && item.engineType() == autoEngine) - goodItem = &item; - - if (goodItem) { - DebuggerItem::MatchLevel level = goodItem->matchTarget(toolChainAbi); - if (level > bestLevel) { - bestLevel = level; - bestItem = goodItem; - } - } - } - - // If we have an existing debugger with matching id _and_ - // matching target ABI we are fine. - if (bestItem) { - k->setValue(DebuggerKitInformation::id(), bestItem->id()); - return; - } - - // We didn't find an existing debugger that matched by whatever - // data we found in the kit (i.e. no id, filename, "auto") - // (or what we found did not match ABI-wise) - // Let's try to pick one with matching ABI. - QVariant bestId; - bestLevel = DebuggerItem::DoesNotMatch; - foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) { - DebuggerItem::MatchLevel level = item.matchTarget(toolChainAbi); - if (level > bestLevel) { - bestLevel = level; - bestId = item.id(); - } - } - - k->setValue(DebuggerKitInformation::id(), bestId); -} - - -// This handles the upgrade path from 2.8 to 3.0 -void DebuggerKitInformation::fix(Kit *k) -{ - // This can be Id, binary path, but not "auto" anymore. - const QVariant rawId = k->value(DebuggerKitInformation::id()); - - if (rawId.isNull()) // No debugger set, that is fine. - return; - - if (rawId.type() == QVariant::String) { - if (!DebuggerItemManager::findById(rawId)) { - qWarning("Unknown debugger id %s in kit %s", - qPrintable(rawId.toString()), qPrintable(k->displayName())); - k->setValue(DebuggerKitInformation::id(), QVariant()); - } - return; // All fine (now). - } - - QMap<QString, QVariant> map = rawId.toMap(); - QString binary = map.value(QLatin1String("Binary")).toString(); - if (binary == QLatin1String("auto")) { - // This should not happen as "auto" is handled by setup() already. - QTC_CHECK(false); - k->setValue(DebuggerKitInformation::id(), QVariant()); - return; - } - - FileName fileName = FileName::fromUserInput(binary); - const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName); - if (!item) { - qWarning("Debugger command %s invalid in kit %s", - qPrintable(binary), qPrintable(k->displayName())); - k->setValue(DebuggerKitInformation::id(), QVariant()); - return; - } - - k->setValue(DebuggerKitInformation::id(), item->id()); -} - -// Check the configuration errors and return a flag mask. Provide a quick check and -// a verbose one with a list of errors. - -enum DebuggerConfigurationErrors { - NoDebugger = 0x1, - DebuggerNotFound = 0x2, - DebuggerNotExecutable = 0x4, - DebuggerNeedsAbsolutePath = 0x8 -}; - -static unsigned debuggerConfigurationErrors(const Kit *k) -{ - QTC_ASSERT(k, return NoDebugger); - - const DebuggerItem *item = DebuggerKitInformation::debugger(k); - if (!item) - return NoDebugger; - - if (item->command().isEmpty()) - return NoDebugger; - - unsigned result = 0; - const QFileInfo fi = item->command().toFileInfo(); - if (!fi.exists() || fi.isDir()) - result |= DebuggerNotFound; - else if (!fi.isExecutable()) - result |= DebuggerNotExecutable; - - if (!fi.exists() || fi.isDir()) { - if (item->engineType() == NoEngineType) - return NoDebugger; - - // We need an absolute path to be able to locate Python on Windows. - if (item->engineType() == GdbEngineType) - if (const ToolChain *tc = ToolChainKitInformation::toolChain(k)) - if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute()) - result |= DebuggerNeedsAbsolutePath; - } - return result; -} - -const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit) -{ - QTC_ASSERT(kit, return 0); - const QVariant id = kit->value(DebuggerKitInformation::id()); - return DebuggerItemManager::findById(id); -} - -bool DebuggerKitInformation::isValidDebugger(const Kit *k) -{ - return debuggerConfigurationErrors(k) == 0; -} - -QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k) -{ - QList<Task> result; - - const unsigned errors = debuggerConfigurationErrors(k); - if (!errors) - return result; - - QString path; - if (const DebuggerItem *item = debugger(k)) - path = item->command().toUserOutput(); - - const Core::Id id = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM; - if (errors & NoDebugger) - result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id); - - if (errors & DebuggerNotFound) - result << Task(Task::Error, tr("Debugger '%1' not found.").arg(path), - FileName(), -1, id); - if (errors & DebuggerNotExecutable) - result << Task(Task::Error, tr("Debugger '%1' not executable.").arg(path), FileName(), -1, id); - - if (errors & DebuggerNeedsAbsolutePath) { - const QString message = - tr("The debugger location must be given as an " - "absolute path (%1).").arg(path); - result << Task(Task::Error, message, FileName(), -1, id); - } - return result; -} - -KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const -{ - return new Internal::DebuggerKitConfigWidget(k, this); -} - -KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const -{ - return ItemList() << qMakePair(tr("Debugger"), displayString(k)); -} - -FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k) -{ - const DebuggerItem *item = debugger(k); - QTC_ASSERT(item, return FileName()); - return item->command(); -} - -DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k) -{ - const DebuggerItem *item = debugger(k); - QTC_ASSERT(item, return NoEngineType); - return item->engineType(); -} - -QString DebuggerKitInformation::displayString(const Kit *k) -{ - const DebuggerItem *item = debugger(k); - if (!item) - return tr("No Debugger"); - QString binary = item->command().toUserOutput(); - QString name = tr("%1 Engine").arg(item->engineTypeName()); - return binary.isEmpty() ? tr("%1 <None>").arg(name) : tr("%1 using \"%2\"").arg(name, binary); -} - -void DebuggerKitInformation::setDebugger(Kit *k, const QVariant &id) -{ - // Only register reasonably complete debuggers. - QTC_ASSERT(DebuggerItemManager::findById(id), return); - k->setValue(DebuggerKitInformation::id(), id); -} - -Core::Id DebuggerKitInformation::id() -{ - return "Debugger.Information"; -} - -// -------------------------------------------------------------------------- -// DebuggerItemManager -// -------------------------------------------------------------------------- - -static DebuggerItemManager *m_instance = 0; - -static FileName userSettingsFileName() -{ - QFileInfo settingsLocation(Core::ICore::settings()->fileName()); - return FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_FILENAME)); -} - -static void readDebuggers(const FileName &fileName, bool isSystem) -{ - PersistentSettingsReader reader; - if (!reader.load(fileName)) - return; - QVariantMap data = reader.restoreValues(); - - // Check version - int version = data.value(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 0).toInt(); - if (version < 1) - return; - - int count = data.value(QLatin1String(DEBUGGER_COUNT_KEY), 0).toInt(); - for (int i = 0; i < count; ++i) { - const QString key = QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(i); - if (!data.contains(key)) - continue; - const QVariantMap dbMap = data.value(key).toMap(); - DebuggerItem item; - item.fromMap(dbMap); - if (isSystem) { - item.setAutoDetected(true); - // SDK debuggers are always considered to be up-to-date, so no need to recheck them. - } else { - // User settings. - if (item.isAutoDetected() && !item.isValid()) { - qWarning() << QString::fromLatin1("DebuggerItem \"%1\" (%2) dropped since it is not valid") - .arg(item.command().toString()).arg(item.id().toString()); - continue; - } - } - DebuggerItemManager::registerDebugger(item); - } -} - -QList<DebuggerItem> DebuggerItemManager::m_debuggers; -DebuggerItemModel* DebuggerItemManager::m_model = 0; -PersistentSettingsWriter * DebuggerItemManager::m_writer = 0; - -DebuggerItemManager::DebuggerItemManager(QObject *parent) - : QObject(parent) -{ - m_instance = this; - m_writer = new PersistentSettingsWriter(userSettingsFileName(), QLatin1String("QtCreatorDebugger")); - m_model = new Debugger::Internal::DebuggerItemModel(this); - connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), - this, SLOT(saveDebuggers())); -} - -QObject *DebuggerItemManager::instance() -{ - return m_instance; -} - -DebuggerItemManager::~DebuggerItemManager() -{ - disconnect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), - this, SLOT(saveDebuggers())); - delete m_writer; -} - -QList<DebuggerItem> DebuggerItemManager::debuggers() -{ - return m_debuggers; -} - -DebuggerItemModel *DebuggerItemManager::model() -{ - return m_model; -} - -void DebuggerItemManager::autoDetectCdbDebuggers() -{ - QList<FileName> cdbs; - - QStringList programDirs; - programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles"))); - programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramFiles(x86)"))); - programDirs.append(QString::fromLocal8Bit(qgetenv("ProgramW6432"))); - - foreach (const QString &dirName, programDirs) { - if (dirName.isEmpty()) - continue; - QDir dir(dirName); - // Windows SDK's starting from version 8 live in - // "ProgramDir\Windows Kits\<version>" - const QString windowsKitsFolderName = QLatin1String("Windows Kits"); - if (dir.exists(windowsKitsFolderName)) { - QDir windowKitsFolder = dir; - if (windowKitsFolder.cd(windowsKitsFolderName)) { - // Check in reverse order (latest first) - const QFileInfoList kitFolders = - windowKitsFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, - QDir::Time | QDir::Reversed); - foreach (const QFileInfo &kitFolderFi, kitFolders) { - const QString path = kitFolderFi.absoluteFilePath(); - const QFileInfo cdb32(path + QLatin1String("/Debuggers/x86/cdb.exe")); - if (cdb32.isExecutable()) - cdbs.append(FileName::fromString(cdb32.absoluteFilePath())); - const QFileInfo cdb64(path + QLatin1String("/Debuggers/x64/cdb.exe")); - if (cdb64.isExecutable()) - cdbs.append(FileName::fromString(cdb64.absoluteFilePath())); - } - } - } - - // Pre Windows SDK 8: Check 'Debugging Tools for Windows' - foreach (const QFileInfo &fi, dir.entryInfoList(QStringList(QLatin1String("Debugging Tools for Windows*")), - QDir::Dirs | QDir::NoDotAndDotDot)) { - FileName filePath(fi); - filePath.appendPath(QLatin1String("cdb.exe")); - if (!cdbs.contains(filePath)) - cdbs.append(filePath); - } - } - - foreach (const FileName &cdb, cdbs) { - if (findByCommand(cdb)) - continue; - DebuggerItem item; - item.setAutoDetected(true); - item.setAbis(Abi::abisOfBinary(cdb)); - item.setCommand(cdb); - item.setEngineType(CdbEngineType); - item.setDisplayName(uniqueDisplayName(tr("Auto-detected CDB at %1").arg(cdb.toUserOutput()))); - addDebugger(item); - } -} - -void DebuggerItemManager::autoDetectGdbOrLldbDebuggers() -{ - QStringList filters; - filters.append(QLatin1String("gdb-i686-pc-mingw32")); - filters.append(QLatin1String("gdb")); - filters.append(QLatin1String("lldb")); - filters.append(QLatin1String("lldb-*")); - -// DebuggerItem result; -// result.setAutoDetected(true); -// result.setDisplayName(tr("Auto-detected for Tool Chain %1").arg(tc->displayName())); - /* - // Check suggestions from the SDK. - Environment env = Environment::systemEnvironment(); - if (tc) { - tc->addToEnvironment(env); // Find MinGW gdb in toolchain environment. - QString path = tc->suggestedDebugger().toString(); - if (!path.isEmpty()) { - const QFileInfo fi(path); - if (!fi.isAbsolute()) - path = env.searchInPath(path); - result.command = FileName::fromString(path); - result.engineType = engineTypeFromBinary(path); - return maybeAddDebugger(result, false); - } - } - */ - - QFileInfoList suspects; - - QStringList path = Environment::systemEnvironment().path(); - foreach (const QString &base, path) { - QDir dir(base); - dir.setNameFilters(filters); - suspects += dir.entryInfoList(); - } - - foreach (const QFileInfo &fi, suspects) { - if (fi.exists()) { - FileName command = FileName::fromString(fi.absoluteFilePath()); - if (findByCommand(command)) - continue; - DebuggerItem item; - item.setCommand(command); - item.reinitializeFromFile(); - //: %1: Debugger engine type (GDB, LLDB, CDB...), %2: Path - item.setDisplayName(tr("System %1 at %2") - .arg(item.engineTypeName()).arg(QDir::toNativeSeparators(fi.absoluteFilePath()))); - item.setAutoDetected(true); - addDebugger(item); - } - } -} - -void DebuggerItemManager::readLegacyDebuggers() -{ - QFileInfo settingsLocation(Core::ICore::settings()->fileName()); - FileName legacyKits = FileName::fromString(settingsLocation.absolutePath() + QLatin1String(DEBUGGER_LEGACY_FILENAME)); - - PersistentSettingsReader reader; - if (!reader.load(legacyKits)) - return; - - foreach (const QVariant &v, reader.restoreValues()) { - QVariantMap data1 = v.toMap(); - QString kitName = data1.value(QLatin1String("PE.Profile.Name")).toString(); - QVariantMap data2 = data1.value(QLatin1String("PE.Profile.Data")).toMap(); - QVariant v3 = data2.value(DebuggerKitInformation::id().toString()); - QString fn; - if (v3.type() == QVariant::String) - fn = v3.toString(); - else - fn = v3.toMap().value(QLatin1String("Binary")).toString(); - if (fn.isEmpty()) - continue; - if (fn.startsWith(QLatin1Char('{'))) - continue; - if (fn == QLatin1String("auto")) - continue; - FileName command = FileName::fromUserInput(fn); - if (findByCommand(command)) - continue; - DebuggerItem item; - item.setCommand(command); - item.setAutoDetected(true); - item.reinitializeFromFile(); - item.setDisplayName(tr("Extracted from Kit %1").arg(kitName)); - addDebugger(item); - } -} - -const DebuggerItem *DebuggerItemManager::findByCommand(const FileName &command) -{ - foreach (const DebuggerItem &item, m_debuggers) - if (item.command() == command) - return &item; - - return 0; -} - -const DebuggerItem *DebuggerItemManager::findById(const QVariant &id) -{ - foreach (const DebuggerItem &item, m_debuggers) - if (item.id() == id) - return &item; - - return 0; -} - -void DebuggerItemManager::restoreDebuggers() -{ - // Read debuggers from SDK - QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName()); - readDebuggers(FileName::fromString(systemSettingsFile.absolutePath() + QLatin1String(DEBUGGER_FILENAME)), true); - - // Read all debuggers from user file. - readDebuggers(userSettingsFileName(), false); - - // Auto detect current. - autoDetectCdbDebuggers(); - autoDetectGdbOrLldbDebuggers(); - - // Add debuggers from pre-3.x profiles.xml - readLegacyDebuggers(); -} - -void DebuggerItemManager::saveDebuggers() -{ - QTC_ASSERT(m_writer, return); - QVariantMap data; - data.insert(QLatin1String(DEBUGGER_FILE_VERSION_KEY), 1); - - int count = 0; - foreach (const DebuggerItem &item, m_debuggers) { - if (item.isValid()) { - QVariantMap tmp = item.toMap(); - if (tmp.isEmpty()) - continue; - data.insert(QString::fromLatin1(DEBUGGER_DATA_KEY) + QString::number(count), tmp); - ++count; - } - } - data.insert(QLatin1String(DEBUGGER_COUNT_KEY), count); - m_writer->save(data, Core::ICore::mainWindow()); - - // Do not save default debuggers as they are set by the SDK. -} - -QVariant DebuggerItemManager::registerDebugger(const DebuggerItem &item) -{ - if (findByCommand(item.command())) - return item.id(); - - return addDebugger(item); -} - -void DebuggerItemManager::deregisterDebugger(const DebuggerItem &item) -{ - if (findByCommand(item.command())) - removeDebugger(item.id()); -} - -QVariant DebuggerItemManager::addDebugger(const DebuggerItem& item0) -{ - DebuggerItem item = item0; - QTC_ASSERT(!item.command().isEmpty(), return QVariant()); - QTC_ASSERT(!item.displayName().isEmpty(), return QVariant()); - QTC_ASSERT(item.engineType() != NoEngineType, return QVariant()); - if (item.id().isNull()) - item.setId(QUuid::createUuid().toString()); - m_debuggers.append(item); - m_model->addDebugger(item); - return item.id(); -} - -void DebuggerItemManager::removeDebugger(const QVariant &id) -{ - bool ok = false; - for (int i = 0, n = m_debuggers.size(); i != n; ++i) { - if (m_debuggers.at(i).id() == id) { - m_debuggers.removeAt(i); - ok = true; - break; - } - } - - QTC_ASSERT(ok, return); - m_model->removeDebugger(id); -} - -QString DebuggerItemManager::uniqueDisplayName(const QString &base) -{ - foreach (const DebuggerItem &item, m_debuggers) - if (item.displayName() == base) - return uniqueDisplayName(base + QLatin1String(" (1)")); - - return base; -} - -void DebuggerItemManager::setItemData(const QVariant &id, const QString &displayName, const FileName &fileName) -{ - for (int i = 0, n = m_debuggers.size(); i != n; ++i) { - DebuggerItem &item = m_debuggers[i]; - if (item.id() == id) { - item.setDisplayName(displayName); - item.setCommand(fileName); - item.reinitializeFromFile(); - emit m_model->updateDebugger(item.id()); - break; - } - } -} - namespace Internal { -static QList<QStandardItem *> describeItem(const DebuggerItem &item) -{ - QList<QStandardItem *> row; - row.append(new QStandardItem(item.displayName())); - row.append(new QStandardItem(item.command().toUserOutput())); - row.append(new QStandardItem(item.engineTypeName())); - row.at(0)->setData(item.id()); - row.at(0)->setEditable(false); - row.at(1)->setEditable(false); - row.at(2)->setEditable(false); - row.at(0)->setSelectable(true); - row.at(1)->setSelectable(true); - row.at(2)->setSelectable(true); - return row; -} - -static QList<QStandardItem *> createRow(const QString &display) -{ - QList<QStandardItem *> row; - row.append(new QStandardItem(display)); - row.append(new QStandardItem()); - row.append(new QStandardItem()); - row.at(0)->setEditable(false); - row.at(1)->setEditable(false); - row.at(2)->setEditable(false); - row.at(0)->setSelectable(false); - row.at(1)->setSelectable(false); - row.at(2)->setSelectable(false); - return row; -} - class DebuggerItemConfigWidget; -// -------------------------------------------------------------------------- -// DebuggerItemModel -// -------------------------------------------------------------------------- - -DebuggerItemModel::DebuggerItemModel(QObject *parent) - : QStandardItemModel(parent) -{ - setColumnCount(3); - - QList<QStandardItem *> row = createRow(tr("Auto-detected")); - m_autoRoot = row.at(0); - appendRow(row); - - row = createRow(tr("Manual")); - m_manualRoot = row.at(0); - appendRow(row); -} - -QVariant DebuggerItemModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (section) { - case 0: - return tr("Name"); - case 1: - return tr("Path"); - case 2: - return tr("Type"); - } - } - return QVariant(); -} - -QStandardItem *DebuggerItemModel::currentStandardItem() const -{ - return findStandardItemById(m_currentDebugger); -} - -QStandardItem *DebuggerItemModel::findStandardItemById(const QVariant &id) const -{ - for (int i = 0, n = m_autoRoot->rowCount(); i != n; ++i) { - QStandardItem *sitem = m_autoRoot->child(i); - if (sitem->data() == id) - return sitem; - } - for (int i = 0, n = m_manualRoot->rowCount(); i != n; ++i) { - QStandardItem *sitem = m_manualRoot->child(i); - if (sitem->data() == id) - return sitem; - } - return 0; -} - -QModelIndex DebuggerItemModel::currentIndex() const -{ - QStandardItem *current = currentStandardItem(); - return current ? current->index() : QModelIndex(); -} - -QModelIndex DebuggerItemModel::lastIndex() const -{ - int n = m_manualRoot->rowCount(); - QStandardItem *current = m_manualRoot->child(n - 1); - return current ? current->index() : QModelIndex(); -} - -void DebuggerItemModel::markCurrentDirty() -{ - QStandardItem *sitem = currentStandardItem(); - QTC_ASSERT(sitem, return); - QFont font = sitem->font(); - font.setBold(true); - sitem->setFont(font); -} - -void DebuggerItemModel::addDebugger(const DebuggerItem &item0) -{ - DebuggerItem item = item0; - if (item.id().isNull()) - item.setId(QUuid::createUuid().toString()); - QList<QStandardItem *> row = describeItem(item); - (item.isAutoDetected() ? m_autoRoot : m_manualRoot)->appendRow(row); - emit debuggerAdded(item.id(), item.displayName()); -} - -void DebuggerItemModel::removeDebugger(const QVariant &id) -{ - QStandardItem *sitem = findStandardItemById(id); - QTC_ASSERT(sitem, return); - QStandardItem *parent = sitem->parent(); - QTC_ASSERT(parent, return); - // This will trigger a change of m_currentDebugger via changing the - // view selection. - parent->removeRow(sitem->row()); - emit debuggerRemoved(id); -} - -void DebuggerItemModel::updateDebugger(const QVariant &id) -{ - QList<DebuggerItem> debuggers = DebuggerItemManager::debuggers(); - for (int i = 0, n = debuggers.size(); i != n; ++i) { - DebuggerItem &item = debuggers[i]; - if (item.id() == id) { - QStandardItem *sitem = findStandardItemById(id); - QTC_ASSERT(sitem, return); - QStandardItem *parent = sitem->parent(); - QTC_ASSERT(parent, return); - int row = sitem->row(); - QFont font = sitem->font(); - font.setBold(false); - parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole); - parent->child(row, 0)->setFont(font); - parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole); - parent->child(row, 1)->setFont(font); - parent->child(row, 2)->setData(item.engineTypeName(), Qt::DisplayRole); - parent->child(row, 2)->setFont(font); - emit debuggerUpdated(id, item.displayName()); - return; - } - } -} - -void DebuggerItemModel::setCurrentIndex(const QModelIndex &index) -{ - QStandardItem *sit = itemFromIndex(index); - m_currentDebugger = sit ? sit->data() : QVariant(); -} - // ----------------------------------------------------------------------- // DebuggerKitConfigWidget // ----------------------------------------------------------------------- @@ -881,9 +79,6 @@ void DebuggerItemModel::setCurrentIndex(const QModelIndex &index) DebuggerKitConfigWidget::DebuggerKitConfigWidget(Kit *workingCopy, const KitInformation *ki) : KitConfigWidget(workingCopy, ki) { - DebuggerItemModel *model = DebuggerItemManager::model(); - QTC_CHECK(model); - m_comboBox = new QComboBox; m_comboBox->setEnabled(true); m_comboBox->setToolTip(toolTip()); @@ -898,11 +93,12 @@ DebuggerKitConfigWidget::DebuggerKitConfigWidget(Kit *workingCopy, const KitInfo m_manageButton->setContentsMargins(0, 0, 0, 0); connect(m_manageButton, SIGNAL(clicked()), this, SLOT(manageDebuggers())); - connect(model, SIGNAL(debuggerAdded(QVariant,QString)), - this, SLOT(onDebuggerAdded(QVariant,QString))); - connect(model, SIGNAL(debuggerUpdated(QVariant,QString)), - this, SLOT(onDebuggerUpdated(QVariant,QString))); - connect(model, SIGNAL(debuggerRemoved(QVariant)), + QObject *manager = DebuggerItemManager::instance(); + connect(manager, SIGNAL(debuggerAdded(QVariant)), + this, SLOT(onDebuggerAdded(QVariant))); + connect(manager, SIGNAL(debuggerUpdated(QVariant)), + this, SLOT(onDebuggerUpdated(QVariant))); + connect(manager, SIGNAL(debuggerRemoved(QVariant)), this, SLOT(onDebuggerRemoved(QVariant))); } @@ -957,20 +153,22 @@ void DebuggerKitConfigWidget::currentDebuggerChanged(int) m_kit->setValue(DebuggerKitInformation::id(), id); } -void DebuggerKitConfigWidget::onDebuggerAdded(const QVariant &id, const QString &displayName) +void DebuggerKitConfigWidget::onDebuggerAdded(const QVariant &id) { - m_comboBox->setEnabled(true); - m_comboBox->addItem(displayName, id); + const DebuggerItem *item = DebuggerItemManager::findById(id); + QTC_ASSERT(item, return); + m_comboBox->addItem(item->displayName(), id); updateComboBox(id); } -void DebuggerKitConfigWidget::onDebuggerUpdated(const QVariant &id, const QString &displayName) +void DebuggerKitConfigWidget::onDebuggerUpdated(const QVariant &id) { - m_comboBox->setEnabled(true); + const DebuggerItem *item = DebuggerItemManager::findById(id); + QTC_ASSERT(item, return); const int pos = indexOf(id); if (pos < 0) return; - m_comboBox->setItemText(pos, displayName); + m_comboBox->setItemText(pos, item->displayName()); } void DebuggerKitConfigWidget::onDebuggerRemoved(const QVariant &id) @@ -1007,296 +205,5 @@ void DebuggerKitConfigWidget::updateComboBox(const QVariant &id) m_comboBox->setCurrentIndex(0); } -// ----------------------------------------------------------------------- -// DebuggerItemConfigWidget -// ----------------------------------------------------------------------- - -class DebuggerItemConfigWidget : public QWidget -{ - Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget) -public: - explicit DebuggerItemConfigWidget(); - void loadItem(); - void saveItem(); - void connectDirty(); - void disconnectDirty(); - -private: - QLineEdit *m_displayNameLineEdit; - QLabel *m_cdbLabel; - PathChooser *m_binaryChooser; - QLineEdit *m_abis; -}; - -DebuggerItemConfigWidget::DebuggerItemConfigWidget() -{ - m_displayNameLineEdit = new QLineEdit(this); - - m_binaryChooser = new PathChooser(this); - m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand); - m_binaryChooser->setMinimumWidth(400); - - m_cdbLabel = new QLabel(this); - m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - m_cdbLabel->setOpenExternalLinks(true); - - m_abis = new QLineEdit(this); - m_abis->setEnabled(false); - - QFormLayout *formLayout = new QFormLayout(this); - formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit); -// formLayout->addRow(new QLabel(tr("Type:")), m_engineTypeComboBox); - formLayout->addRow(m_cdbLabel); - formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser); - formLayout->addRow(new QLabel(tr("ABIs:")), m_abis); - - connectDirty(); -} - -void DebuggerItemConfigWidget::connectDirty() -{ - DebuggerItemModel *model = DebuggerItemManager::model(); - connect(m_displayNameLineEdit, SIGNAL(textChanged(QString)), - model, SLOT(markCurrentDirty())); - connect(m_binaryChooser, SIGNAL(changed(QString)), - model, SLOT(markCurrentDirty())); -} - -void DebuggerItemConfigWidget::disconnectDirty() -{ - DebuggerItemModel *model = DebuggerItemManager::model(); - disconnect(m_displayNameLineEdit, SIGNAL(textChanged(QString)), - model, SLOT(markCurrentDirty())); - disconnect(m_binaryChooser, SIGNAL(changed(QString)), - model, SLOT(markCurrentDirty())); -} - -void DebuggerItemConfigWidget::loadItem() -{ - DebuggerItemModel *model = DebuggerItemManager::model(); - const DebuggerItem *item = DebuggerItemManager::findById(model->m_currentDebugger); - if (!item) - return; - - disconnectDirty(); - m_displayNameLineEdit->setEnabled(!item->isAutoDetected()); - m_displayNameLineEdit->setText(item->displayName()); - - m_binaryChooser->setEnabled(!item->isAutoDetected()); - m_binaryChooser->setFileName(item->command()); - connectDirty(); - - QString text; - QString versionCommand; - if (item->engineType() == CdbEngineType) { -#ifdef Q_OS_WIN - const bool is64bit = winIs64BitSystem(); -#else - const bool is64bit = false; -#endif - const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version"); - //: Label text for path configuration. %2 is "x-bit version". - text = tr("<html><body><p>Specify the path to the " - "<a href=\"%1\">Windows Console Debugger executable</a>" - " (%2) here.</p>""</body></html>"). - arg(QLatin1String(debuggingToolsWikiLinkC), versionString); - versionCommand = QLatin1String("-version"); - } else { - versionCommand = QLatin1String("--version"); - } - - m_cdbLabel->setText(text); - m_cdbLabel->setVisible(!text.isEmpty()); - m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand)); - - m_abis->setText(item->abiNames().join(QLatin1String(", "))); -} - -void DebuggerItemConfigWidget::saveItem() -{ - DebuggerItemModel *model = DebuggerItemManager::model(); - const DebuggerItem *item = DebuggerItemManager::findById(model->m_currentDebugger); - QTC_ASSERT(item, return); - DebuggerItemManager::setItemData(item->id(), m_displayNameLineEdit->text(), - m_binaryChooser->fileName()); -} - -// -------------------------------------------------------------------------- -// DebuggerOptionsPage -// -------------------------------------------------------------------------- - -DebuggerOptionsPage::DebuggerOptionsPage() -{ - m_model = 0; - m_debuggerView = 0; - m_container = 0; - m_addButton = 0; - m_cloneButton = 0; - m_delButton = 0; - - setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID); - setDisplayName(tr("Debuggers")); - setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY); - setDisplayCategory(QCoreApplication::translate("ProjectExplorer", - ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY)); - setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON)); -} - -QWidget *DebuggerOptionsPage::createPage(QWidget *parent) -{ - m_configWidget = new QWidget(parent); - - m_addButton = new QPushButton(tr("Add"), m_configWidget); - m_cloneButton = new QPushButton(tr("Clone"), m_configWidget); - m_delButton = new QPushButton(tr("Remove"), m_configWidget); - - m_container = new DetailsWidget(m_configWidget); - m_container->setState(DetailsWidget::NoSummary); - m_container->setVisible(false); - - m_model = DebuggerItemManager::model(); - - m_debuggerView = new QTreeView(m_configWidget); - m_debuggerView->setModel(m_model); - m_debuggerView->setUniformRowHeights(true); - m_debuggerView->setSelectionMode(QAbstractItemView::SingleSelection); - m_debuggerView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_debuggerView->expandAll(); - - QHeaderView *header = m_debuggerView->header(); - header->setStretchLastSection(false); - header->setResizeMode(0, QHeaderView::ResizeToContents); - header->setResizeMode(1, QHeaderView::ResizeToContents); - header->setResizeMode(2, QHeaderView::Stretch); - - QVBoxLayout *buttonLayout = new QVBoxLayout(); - buttonLayout->setSpacing(6); - buttonLayout->setContentsMargins(0, 0, 0, 0); - buttonLayout->addWidget(m_addButton); - buttonLayout->addWidget(m_cloneButton); - buttonLayout->addWidget(m_delButton); - buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); - - QVBoxLayout *verticalLayout = new QVBoxLayout(); - verticalLayout->addWidget(m_debuggerView); - verticalLayout->addWidget(m_container); - - QHBoxLayout *horizontalLayout = new QHBoxLayout(m_configWidget); - horizontalLayout->addLayout(verticalLayout); - horizontalLayout->addLayout(buttonLayout); - - connect(m_debuggerView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), - this, SLOT(debuggerSelectionChanged())); - - connect(m_addButton, SIGNAL(clicked()), this, SLOT(addDebugger()), Qt::QueuedConnection); - connect(m_cloneButton, SIGNAL(clicked()), this, SLOT(cloneDebugger()), Qt::QueuedConnection); - connect(m_delButton, SIGNAL(clicked()), this, SLOT(removeDebugger()), Qt::QueuedConnection); - - m_searchKeywords = tr("Debuggers"); - - m_itemConfigWidget = new DebuggerItemConfigWidget; - m_container->setWidget(m_itemConfigWidget); - - updateState(); - - return m_configWidget; -} - -void DebuggerOptionsPage::apply() -{ - m_itemConfigWidget->saveItem(); - debuggerModelChanged(); -} - -void DebuggerOptionsPage::cloneDebugger() -{ - const DebuggerItem *item = DebuggerItemManager::findById(m_model->currentDebugger()); - QTC_ASSERT(item, return); - DebuggerItem newItem; - newItem.setCommand(item->command()); - newItem.setEngineType(item->engineType()); - newItem.setAbis(item->abis()); - newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item->displayName()))); - newItem.setAutoDetected(false); - DebuggerItemManager::addDebugger(newItem); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); -} - -void DebuggerOptionsPage::addDebugger() -{ - DebuggerItem item; - item.setEngineType(NoEngineType); - item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger"))); - item.setAutoDetected(false); - DebuggerItemManager::addDebugger(item); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); -} - -void DebuggerOptionsPage::removeDebugger() -{ - QVariant id = m_model->currentDebugger(); - DebuggerItemManager::removeDebugger(id); - m_debuggerView->setCurrentIndex(m_model->lastIndex()); -} - -void DebuggerOptionsPage::finish() -{ - // Deleted by settingsdialog. - m_configWidget = 0; - - // Children of m_configWidget. - m_container = 0; - m_debuggerView = 0; - m_addButton = 0; - m_cloneButton = 0; - m_delButton = 0; -} - -bool DebuggerOptionsPage::matches(const QString &s) const -{ - return m_searchKeywords.contains(s, Qt::CaseInsensitive); -} - -void DebuggerOptionsPage::debuggerSelectionChanged() -{ - QTC_ASSERT(m_container, return); - - QModelIndex mi = m_debuggerView->currentIndex(); - mi = mi.sibling(mi.row(), 0); - m_model->setCurrentIndex(mi); - - m_itemConfigWidget->loadItem(); - m_container->setVisible(m_model->m_currentDebugger.isValid()); - updateState(); -} - -void DebuggerOptionsPage::debuggerModelChanged() -{ - QTC_ASSERT(m_container, return); - - m_itemConfigWidget->loadItem(); - m_container->setVisible(m_model->m_currentDebugger.isValid()); - m_debuggerView->setCurrentIndex(m_model->currentIndex()); - updateState(); -} - -void DebuggerOptionsPage::updateState() -{ - if (!m_cloneButton) - return; - - bool canCopy = false; - bool canDelete = false; - - if (const DebuggerItem *item = DebuggerItemManager::findById(m_model->m_currentDebugger)) { - canCopy = item->isValid() && item->canClone(); - canDelete = !item->isAutoDetected(); - canDelete = true; // Do we want to remove auto-detected items? - } - m_cloneButton->setEnabled(canCopy); - m_delButton->setEnabled(canDelete); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerkitconfigwidget.h b/src/plugins/debugger/debuggerkitconfigwidget.h index f2ab06695f..e126f513f9 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.h +++ b/src/plugins/debugger/debuggerkitconfigwidget.h @@ -30,7 +30,7 @@ #ifndef DEBUGGER_DEBUGGERKITCONFIGWIDGET_H #define DEBUGGER_DEBUGGERKITCONFIGWIDGET_H -#include "debuggerkitinformation.h" +#include "debuggeritemmodel.h" #include <coreplugin/dialogs/ioptionspage.h> #include <projectexplorer/kitconfigwidget.h> @@ -52,52 +52,6 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { -class DebuggerItemConfigWidget; -class DebuggerKitConfigWidget; - -// ----------------------------------------------------------------------- -// DebuggerItemModel -//------------------------------------------------------------------------ -class DebuggerItemModel : public QStandardItemModel -{ - Q_OBJECT - -public: - DebuggerItemModel(QObject *parent); - - QModelIndex currentIndex() const; - QModelIndex lastIndex() const; - void setCurrentIndex(const QModelIndex &index); - QVariant currentDebugger() const { return m_currentDebugger; } - void addDebugger(const DebuggerItem &item); - void removeDebugger(const QVariant &id); - void updateDebugger(const QVariant &id); - -public slots: - void markCurrentDirty(); - -signals: - void debuggerAdded(const QVariant &id, const QString &display); - void debuggerUpdated(const QVariant &id, const QString &display); - void debuggerRemoved(const QVariant &id); - -private: - friend class Debugger::DebuggerKitInformation; - friend class DebuggerKitConfigWidget; - friend class DebuggerItemConfigWidget; - friend class DebuggerOptionsPage; - - QStandardItem *currentStandardItem() const; - QStandardItem *findStandardItemById(const QVariant &id) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - - QVariant m_currentDebugger; - - QStandardItem *m_autoRoot; - QStandardItem *m_manualRoot; - QStringList removed; -}; - // ----------------------------------------------------------------------- // DebuggerKitConfigWidget // ----------------------------------------------------------------------- @@ -121,8 +75,8 @@ public: private slots: void manageDebuggers(); void currentDebuggerChanged(int idx); - void onDebuggerAdded(const QVariant &id, const QString &displayName); - void onDebuggerUpdated(const QVariant &id, const QString &displayName); + void onDebuggerAdded(const QVariant &id); + void onDebuggerUpdated(const QVariant &id); void onDebuggerRemoved(const QVariant &id); private: @@ -135,44 +89,7 @@ private: QPushButton *m_manageButton; }; -// -------------------------------------------------------------------------- -// DebuggerOptionsPage -// -------------------------------------------------------------------------- - -class DebuggerOptionsPage : public Core::IOptionsPage -{ - Q_OBJECT - -public: - DebuggerOptionsPage(); - - QWidget *createPage(QWidget *parent); - void apply(); - void finish(); - bool matches(const QString &) const; - -private slots: - void debuggerSelectionChanged(); - void debuggerModelChanged(); - void updateState(); - void cloneDebugger(); - void addDebugger(); - void removeDebugger(); - -private: - QWidget *m_configWidget; - QString m_searchKeywords; - - DebuggerItemModel *m_model; - DebuggerItemConfigWidget *m_itemConfigWidget; - QTreeView *m_debuggerView; - Utils::DetailsWidget *m_container; - QPushButton *m_addButton; - QPushButton *m_cloneButton; - QPushButton *m_delButton; -}; - } // namespace Internal } // namespace Debugger -#endif // DEBUGGER_DEBUGGERKITINFORMATION_H +#endif // DEBUGGER_DEBUGGERKITCONFIGWIDGET_H diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index 30ca4f2c23..7ee98c619d 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -28,312 +28,305 @@ ****************************************************************************/ #include "debuggerkitinformation.h" + +#include "debuggeritemmanager.h" #include "debuggerkitconfigwidget.h" -#include <projectexplorer/abi.h> +#include "projectexplorer/toolchain.h" +#include "projectexplorer/projectexplorerconstants.h" + #include <utils/fileutils.h> +#include <utils/qtcassert.h> -#include <QProcess> +#include <QFileInfo> -using namespace Debugger::Internal; using namespace ProjectExplorer; using namespace Utils; -static const char DEBUGGER_INFORMATION_COMMAND[] = "Binary"; -static const char DEBUGGER_INFORMATION_DISPLAYNAME[] = "DisplayName"; -static const char DEBUGGER_INFORMATION_ID[] = "Id"; -static const char DEBUGGER_INFORMATION_ENGINETYPE[] = "EngineType"; -static const char DEBUGGER_INFORMATION_AUTODETECTED[] = "AutoDetected"; -static const char DEBUGGER_INFORMATION_ABIS[] = "Abis"; - namespace Debugger { // -------------------------------------------------------------------------- -// DebuggerItem +// DebuggerKitInformation // -------------------------------------------------------------------------- -DebuggerItem::DebuggerItem() +DebuggerKitInformation::DebuggerKitInformation() { - m_engineType = NoEngineType; - m_isAutoDetected = false; + setObjectName(QLatin1String("DebuggerKitInformation")); + setId(DebuggerKitInformation::id()); + setPriority(28000); } -void DebuggerItem::reinitializeFromFile() +QVariant DebuggerKitInformation::defaultValue(Kit *k) const { - QProcess proc; - proc.start(m_command.toString(), QStringList() << QLatin1String("--version")); - proc.waitForStarted(); - proc.waitForFinished(); - QByteArray ba = proc.readAll(); - if (ba.contains("gdb")) { - m_engineType = GdbEngineType; - const char needle[] = "This GDB was configured as \""; - // E.g. "--host=i686-pc-linux-gnu --target=arm-unknown-nto-qnx6.5.0". - // or "i686-linux-gnu" - int pos1 = ba.indexOf(needle); - if (pos1 != -1) { - pos1 += int(sizeof(needle)); - int pos2 = ba.indexOf('"', pos1 + 1); - QByteArray target = ba.mid(pos1, pos2 - pos1); - int pos3 = target.indexOf("--target="); - if (pos3 >= 0) - target = target.mid(pos3 + 9); - m_abis.append(Abi::abiFromTargetTriplet(QString::fromLatin1(target))); + ToolChain *tc = ToolChainKitInformation::toolChain(k); + QTC_ASSERT(tc, return QVariant()); + + const Abi toolChainAbi = tc->targetAbi(); + foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) + foreach (const Abi targetAbi, item.abis()) + if (targetAbi.isCompatibleWith(toolChainAbi)) + return item.id(); + + return QVariant(); +} + +void DebuggerKitInformation::setup(Kit *k) +{ + // Get one of the available debugger matching the kit's toolchain. + const ToolChain *tc = ToolChainKitInformation::toolChain(k); + const Abi toolChainAbi = tc ? tc->targetAbi() : Abi::hostAbi(); + + // This can be anything (Id, binary path, "auto") + const QVariant rawId = k->value(DebuggerKitInformation::id()); + + enum { + NotDetected, DetectedAutomatically, DetectedByFile, DetectedById + } detection = NotDetected; + DebuggerEngineType autoEngine = NoEngineType; + FileName fileName; + + // With 3.0 we have: + // <value type="QString" key="Debugger.Information">{75ecf347-f221-44c3-b613-ea1d29929cd4}</value> + // Before we had: + // <valuemap type="QVariantMap" key="Debugger.Information"> + // <value type="QString" key="Binary">/data/dev/debugger/gdb-git/gdb/gdb</value> + // <value type="int" key="EngineType">1</value> + // </valuemap> + // Or for force auto-detected CDB + // <valuemap type="QVariantMap" key="Debugger.Information"> + // <value type="QString" key="Binary">auto</value> + // <value type="int" key="EngineType">4</value> + // </valuemap> + + if (rawId.isNull()) { + // Initial setup of a kit + detection = NotDetected; + } else if (rawId.type() == QVariant::String) { + detection = DetectedById; + } else { + QMap<QString, QVariant> map = rawId.toMap(); + QString binary = map.value(QLatin1String("Binary")).toString(); + if (binary == QLatin1String("auto")) { + detection = DetectedAutomatically; + autoEngine = DebuggerEngineType(map.value(QLatin1String("EngineType")).toInt()); } else { - // Fallback. - m_abis = Abi::abisOfBinary(m_command); // FIXME: Wrong. + detection = DetectedByFile; + fileName = FileName::fromUserInput(binary); } - return; } - if (ba.contains("lldb") || ba.startsWith("LLDB")) { - m_engineType = LldbEngineType; - m_abis = Abi::abisOfBinary(m_command); - return; + + const DebuggerItem *bestItem = 0; + DebuggerItem::MatchLevel bestLevel = DebuggerItem::DoesNotMatch; + foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) { + const DebuggerItem *goodItem = 0; + if (detection == DetectedById && item.id() == rawId) + goodItem = &item; + if (detection == DetectedByFile && item.command() == fileName) + goodItem = &item; + if (detection == DetectedAutomatically && item.engineType() == autoEngine) + goodItem = &item; + + if (goodItem) { + DebuggerItem::MatchLevel level = goodItem->matchTarget(toolChainAbi); + if (level > bestLevel) { + bestLevel = level; + bestItem = goodItem; + } + } } - if (ba.startsWith("Python")) { - m_engineType = PdbEngineType; + + // If we have an existing debugger with matching id _and_ + // matching target ABI we are fine. + if (bestItem) { + k->setValue(DebuggerKitInformation::id(), bestItem->id()); return; } - m_engineType = NoEngineType; -} -QString DebuggerItem::engineTypeName() const -{ - switch (m_engineType) { - case Debugger::NoEngineType: - return DebuggerOptionsPage::tr("Not recognized"); - case Debugger::GdbEngineType: - return QLatin1String("GDB"); - case Debugger::CdbEngineType: - return QLatin1String("CDB"); - case Debugger::LldbEngineType: - return QLatin1String("LLDB"); - default: - return QString(); + // We didn't find an existing debugger that matched by whatever + // data we found in the kit (i.e. no id, filename, "auto") + // (or what we found did not match ABI-wise) + // Let's try to pick one with matching ABI. + QVariant bestId; + bestLevel = DebuggerItem::DoesNotMatch; + foreach (const DebuggerItem &item, DebuggerItemManager::debuggers()) { + DebuggerItem::MatchLevel level = item.matchTarget(toolChainAbi); + if (level > bestLevel) { + bestLevel = level; + bestId = item.id(); + } } -} -QStringList DebuggerItem::abiNames() const -{ - QStringList list; - foreach (const Abi &abi, m_abis) - list.append(abi.toString()); - return list; + k->setValue(DebuggerKitInformation::id(), bestId); } -QVariantMap DebuggerItem::toMap() const -{ - QVariantMap data; - data.insert(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME), m_displayName); - data.insert(QLatin1String(DEBUGGER_INFORMATION_ID), m_id); - data.insert(QLatin1String(DEBUGGER_INFORMATION_COMMAND), m_command.toUserOutput()); - data.insert(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE), int(m_engineType)); - data.insert(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED), m_isAutoDetected); - data.insert(QLatin1String(DEBUGGER_INFORMATION_ABIS), abiNames()); - return data; -} -void DebuggerItem::fromMap(const QVariantMap &data) +// This handles the upgrade path from 2.8 to 3.0 +void DebuggerKitInformation::fix(Kit *k) { - m_command = FileName::fromUserInput(data.value(QLatin1String(DEBUGGER_INFORMATION_COMMAND)).toString()); - m_id = data.value(QLatin1String(DEBUGGER_INFORMATION_ID)).toString(); - m_displayName = data.value(QLatin1String(DEBUGGER_INFORMATION_DISPLAYNAME)).toString(); - m_isAutoDetected = data.value(QLatin1String(DEBUGGER_INFORMATION_AUTODETECTED)).toBool(); - m_engineType = DebuggerEngineType(data.value(QLatin1String(DEBUGGER_INFORMATION_ENGINETYPE)).toInt()); - - m_abis.clear(); - foreach (const QString &a, data.value(QLatin1String(DEBUGGER_INFORMATION_ABIS)).toStringList()) { - Abi abi(a); - if (abi.isValid()) - m_abis.append(abi); + // This can be Id, binary path, but not "auto" anymore. + const QVariant rawId = k->value(DebuggerKitInformation::id()); + + if (rawId.isNull()) // No debugger set, that is fine. + return; + + if (rawId.type() == QVariant::String) { + if (!DebuggerItemManager::findById(rawId)) { + qWarning("Unknown debugger id %s in kit %s", + qPrintable(rawId.toString()), qPrintable(k->displayName())); + k->setValue(DebuggerKitInformation::id(), QVariant()); + } + return; // All fine (now). } -} -void DebuggerItem::setId(const QVariant &id) -{ - m_id = id; + QMap<QString, QVariant> map = rawId.toMap(); + QString binary = map.value(QLatin1String("Binary")).toString(); + if (binary == QLatin1String("auto")) { + // This should not happen as "auto" is handled by setup() already. + QTC_CHECK(false); + k->setValue(DebuggerKitInformation::id(), QVariant()); + return; + } + + FileName fileName = FileName::fromUserInput(binary); + const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName); + if (!item) { + qWarning("Debugger command %s invalid in kit %s", + qPrintable(binary), qPrintable(k->displayName())); + k->setValue(DebuggerKitInformation::id(), QVariant()); + return; + } + + k->setValue(DebuggerKitInformation::id(), item->id()); } -void DebuggerItem::setDisplayName(const QString &displayName) +// Check the configuration errors and return a flag mask. Provide a quick check and +// a verbose one with a list of errors. + +enum DebuggerConfigurationErrors { + NoDebugger = 0x1, + DebuggerNotFound = 0x2, + DebuggerNotExecutable = 0x4, + DebuggerNeedsAbsolutePath = 0x8 +}; + +static unsigned debuggerConfigurationErrors(const Kit *k) { - m_displayName = displayName; + QTC_ASSERT(k, return NoDebugger); + + const DebuggerItem *item = DebuggerKitInformation::debugger(k); + if (!item) + return NoDebugger; + + if (item->command().isEmpty()) + return NoDebugger; + + unsigned result = 0; + const QFileInfo fi = item->command().toFileInfo(); + if (!fi.exists() || fi.isDir()) + result |= DebuggerNotFound; + else if (!fi.isExecutable()) + result |= DebuggerNotExecutable; + + if (!fi.exists() || fi.isDir()) { + if (item->engineType() == NoEngineType) + return NoDebugger; + + // We need an absolute path to be able to locate Python on Windows. + if (item->engineType() == GdbEngineType) + if (const ToolChain *tc = ToolChainKitInformation::toolChain(k)) + if (tc->targetAbi().os() == Abi::WindowsOS && !fi.isAbsolute()) + result |= DebuggerNeedsAbsolutePath; + } + return result; } -void DebuggerItem::setEngineType(const DebuggerEngineType &engineType) +const DebuggerItem *DebuggerKitInformation::debugger(const Kit *kit) { - m_engineType = engineType; + QTC_ASSERT(kit, return 0); + const QVariant id = kit->value(DebuggerKitInformation::id()); + return DebuggerItemManager::findById(id); } -void DebuggerItem::setCommand(const Utils::FileName &command) +bool DebuggerKitInformation::isValidDebugger(const Kit *k) { - m_command = command; + return debuggerConfigurationErrors(k) == 0; } -void DebuggerItem::setAutoDetected(bool isAutoDetected) +QList<Task> DebuggerKitInformation::validateDebugger(const Kit *k) { - m_isAutoDetected = isAutoDetected; + QList<Task> result; + + const unsigned errors = debuggerConfigurationErrors(k); + if (!errors) + return result; + + QString path; + if (const DebuggerItem *item = debugger(k)) + path = item->command().toUserOutput(); + + const Core::Id id = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM; + if (errors & NoDebugger) + result << Task(Task::Warning, tr("No debugger set up."), FileName(), -1, id); + + if (errors & DebuggerNotFound) + result << Task(Task::Error, tr("Debugger '%1' not found.").arg(path), + FileName(), -1, id); + if (errors & DebuggerNotExecutable) + result << Task(Task::Error, tr("Debugger '%1' not executable.").arg(path), FileName(), -1, id); + + if (errors & DebuggerNeedsAbsolutePath) { + const QString message = + tr("The debugger location must be given as an " + "absolute path (%1).").arg(path); + result << Task(Task::Error, message, FileName(), -1, id); + } + return result; } -void DebuggerItem::setAbis(const QList<ProjectExplorer::Abi> &abis) +KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const { - m_abis = abis; + return new Internal::DebuggerKitConfigWidget(k, this); } -void DebuggerItem::setAbi(const Abi &abi) +KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const { - m_abis.clear(); - m_abis.append(abi); + return ItemList() << qMakePair(tr("Debugger"), displayString(k)); } -static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &targetAbi) +FileName DebuggerKitInformation::debuggerCommand(const ProjectExplorer::Kit *k) { - if (debuggerAbi.architecture() != Abi::UnknownArchitecture - && debuggerAbi.architecture() != targetAbi.architecture()) - return DebuggerItem::DoesNotMatch; - - if (debuggerAbi.os() != Abi::UnknownOS - && debuggerAbi.os() != targetAbi.os()) - return DebuggerItem::DoesNotMatch; - - if (debuggerAbi.binaryFormat() != Abi::UnknownFormat - && debuggerAbi.binaryFormat() != targetAbi.binaryFormat()) - return DebuggerItem::DoesNotMatch; - - if (debuggerAbi.os() == Abi::WindowsOS) { - if (debuggerAbi.osFlavor() == Abi::WindowsMSysFlavor && targetAbi.osFlavor() != Abi::WindowsMSysFlavor) - return DebuggerItem::DoesNotMatch; - if (debuggerAbi.osFlavor() != Abi::WindowsMSysFlavor && targetAbi.osFlavor() == Abi::WindowsMSysFlavor) - return DebuggerItem::DoesNotMatch; - } - - if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) - return DebuggerItem::MatchesSomewhat; - if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth()) - return DebuggerItem::DoesNotMatch; - - return DebuggerItem::MatchesPerfectly; + const DebuggerItem *item = debugger(k); + QTC_ASSERT(item, return FileName()); + return item->command(); } -DebuggerItem::MatchLevel DebuggerItem::matchTarget(const Abi &targetAbi) const +DebuggerEngineType DebuggerKitInformation::engineType(const ProjectExplorer::Kit *k) { - MatchLevel bestMatch = DoesNotMatch; - foreach (const Abi &debuggerAbi, m_abis) { - MatchLevel currentMatch = matchSingle(debuggerAbi, targetAbi); - if (currentMatch > bestMatch) - bestMatch = currentMatch; - } - return bestMatch; + const DebuggerItem *item = debugger(k); + QTC_ASSERT(item, return NoEngineType); + return item->engineType(); } -bool Debugger::DebuggerItem::isValid() const +QString DebuggerKitInformation::displayString(const Kit *k) { - return m_engineType != NoEngineType; + const DebuggerItem *item = debugger(k); + if (!item) + return tr("No Debugger"); + QString binary = item->command().toUserOutput(); + QString name = tr("%1 Engine").arg(item->engineTypeName()); + return binary.isEmpty() ? tr("%1 <None>").arg(name) : tr("%1 using \"%2\"").arg(name, binary); } -} // namespace Debugger; - -#ifdef WITH_TESTS - -# include <QTest> -# include "debuggerplugin.h" - -void Debugger::DebuggerPlugin::testDebuggerMatching_data() +void DebuggerKitInformation::setDebugger(Kit *k, const QVariant &id) { - QTest::addColumn<QStringList>("debugger"); - QTest::addColumn<QString>("target"); - QTest::addColumn<int>("result"); - - QTest::newRow("Invalid data") - << QStringList() - << QString() - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("Invalid debugger") - << QStringList() - << QString::fromLatin1("x86-linux-generic-elf-32bit") - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("Invalid target") - << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) - << QString() - << int(DebuggerItem::DoesNotMatch); - - QTest::newRow("Fuzzy match 1") - << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit")) - << QString::fromLatin1("x86-linux-generic-elf-32bit") - << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior? - QTest::newRow("Fuzzy match 2") - << (QStringList() << QLatin1String("unknown-unknown-unknown-unknown-0bit")) - << QString::fromLatin1("arm-windows-msys-pe-64bit") - << int(DebuggerItem::MatchesPerfectly); // Is this the expected behavior? - - QTest::newRow("Architecture mismatch") - << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) - << QString::fromLatin1("arm-linux-generic-elf-32bit") - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("OS mismatch") - << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) - << QString::fromLatin1("x86-macosx-generic-elf-32bit") - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("Format mismatch") - << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) - << QString::fromLatin1("x86-linux-generic-pe-32bit") - << int(DebuggerItem::DoesNotMatch); - - QTest::newRow("Linux perfect match") - << (QStringList() << QLatin1String("x86-linux-generic-elf-32bit")) - << QString::fromLatin1("x86-linux-generic-elf-32bit") - << int(DebuggerItem::MatchesPerfectly); - QTest::newRow("Linux match") - << (QStringList() << QLatin1String("x86-linux-generic-elf-64bit")) - << QString::fromLatin1("x86-linux-generic-elf-32bit") - << int(DebuggerItem::MatchesSomewhat); - - QTest::newRow("Windows perfect match 1") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) - << QString::fromLatin1("x86-windows-msvc2013-pe-64bit") - << int(DebuggerItem::MatchesPerfectly); - QTest::newRow("Windows perfect match 2") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) - << QString::fromLatin1("x86-windows-msvc2012-pe-64bit") - << int(DebuggerItem::MatchesPerfectly); - QTest::newRow("Windows match 1") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) - << QString::fromLatin1("x86-windows-msvc2013-pe-32bit") - << int(DebuggerItem::MatchesSomewhat); - QTest::newRow("Windows match 2") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-64bit")) - << QString::fromLatin1("x86-windows-msvc2012-pe-32bit") - << int(DebuggerItem::MatchesSomewhat); - QTest::newRow("Windows mismatch on word size") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit")) - << QString::fromLatin1("x86-windows-msvc2013-pe-64bit") - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("Windows mismatch on osflavor 1") - << (QStringList() << QLatin1String("x86-windows-msvc2013-pe-32bit")) - << QString::fromLatin1("x86-windows-msys-pe-64bit") - << int(DebuggerItem::DoesNotMatch); - QTest::newRow("Windows mismatch on osflavor 2") - << (QStringList() << QLatin1String("x86-windows-msys-pe-32bit")) - << QString::fromLatin1("x86-windows-msvc2010-pe-64bit") - << int(DebuggerItem::DoesNotMatch); + // Only register reasonably complete debuggers. + QTC_ASSERT(DebuggerItemManager::findById(id), return); + k->setValue(DebuggerKitInformation::id(), id); } -void Debugger::DebuggerPlugin::testDebuggerMatching() +Core::Id DebuggerKitInformation::id() { - QFETCH(QStringList, debugger); - QFETCH(QString, target); - QFETCH(int, result); - - DebuggerItem::MatchLevel expectedLevel = static_cast<DebuggerItem::MatchLevel>(result); - - QList<Abi> debuggerAbis; - foreach (const QString &abi, debugger) - debuggerAbis << Abi(abi); - - DebuggerItem item; - item.setAbis(debuggerAbis); - - DebuggerItem::MatchLevel level = item.matchTarget(Abi(target)); - - QCOMPARE(expectedLevel, level); + return "Debugger.Information"; } -#endif + +} // namespace Debugger diff --git a/src/plugins/debugger/debuggerkitinformation.h b/src/plugins/debugger/debuggerkitinformation.h index dfdf6350a4..3e03e19d2e 100644 --- a/src/plugins/debugger/debuggerkitinformation.h +++ b/src/plugins/debugger/debuggerkitinformation.h @@ -32,6 +32,7 @@ #include "debugger_global.h" #include "debuggerconstants.h" +#include "debuggeritem.h" #include <projectexplorer/abi.h> #include <projectexplorer/kitinformation.h> @@ -40,106 +41,6 @@ namespace Debugger { -namespace Internal { class DebuggerItemModel; } - -// ----------------------------------------------------------------------- -// DebuggerItem -// ----------------------------------------------------------------------- - -class DEBUGGER_EXPORT DebuggerItem -{ -public: - DebuggerItem(); - - bool canClone() const { return true; } - bool isValid() const; - QString engineTypeName() const; - - QVariantMap toMap() const; - void fromMap(const QVariantMap &data); - void reinitializeFromFile(); - - QVariant id() const { return m_id; } - - QString displayName() const { return m_displayName; } - void setDisplayName(const QString &displayName); - - DebuggerEngineType engineType() const { return m_engineType; } - void setEngineType(const DebuggerEngineType &engineType); - - Utils::FileName command() const { return m_command; } - void setCommand(const Utils::FileName &command); - - bool isAutoDetected() const { return m_isAutoDetected; } - void setAutoDetected(bool isAutoDetected); - - QList<ProjectExplorer::Abi> abis() const { return m_abis; } - void setAbis(const QList<ProjectExplorer::Abi> &abis); - void setAbi(const ProjectExplorer::Abi &abi); - - enum MatchLevel { DoesNotMatch, MatchesSomewhat, MatchesPerfectly }; - MatchLevel matchTarget(const ProjectExplorer::Abi &targetAbi) const; - - QStringList abiNames() const; - -private: - friend class Debugger::Internal::DebuggerItemModel; - friend class DebuggerItemManager; - void setId(const QVariant &id); - - QVariant m_id; - QString m_displayName; - DebuggerEngineType m_engineType; - Utils::FileName m_command; - bool m_isAutoDetected; - QList<ProjectExplorer::Abi> m_abis; -}; - -// ----------------------------------------------------------------------- -// DebuggerItemManager -// ----------------------------------------------------------------------- - -class DEBUGGER_EXPORT DebuggerItemManager : public QObject -{ - Q_OBJECT - -public: - static QObject *instance(); - ~DebuggerItemManager(); - - static QList<DebuggerItem> debuggers(); - static Debugger::Internal::DebuggerItemModel *model(); - - static QVariant registerDebugger(const DebuggerItem &item); - static void deregisterDebugger(const DebuggerItem &item); - - static const DebuggerItem *findByCommand(const Utils::FileName &command); - static const DebuggerItem *findById(const QVariant &id); - - static void restoreDebuggers(); - static QString uniqueDisplayName(const QString &base); - static void setItemData(const QVariant &id, const QString& displayName, const Utils::FileName &fileName); - - static void removeDebugger(const QVariant &id); - static QVariant addDebugger(const DebuggerItem &item); - -public slots: - void saveDebuggers(); - -private: - explicit DebuggerItemManager(QObject *parent = 0); - static void autoDetectGdbOrLldbDebuggers(); - static void autoDetectCdbDebuggers(); - static void readLegacyDebuggers(); - - static Utils::PersistentSettingsWriter *m_writer; - static QList<DebuggerItem> m_debuggers; - static Debugger::Internal::DebuggerItemModel *m_model; - - friend class Internal::DebuggerItemModel; - friend class DebuggerPlugin; // Enable constrcutor for DebuggerPlugin -}; - class DEBUGGER_EXPORT DebuggerKitInformation : public ProjectExplorer::KitInformation { Q_OBJECT diff --git a/src/plugins/debugger/debuggeroptionspage.cpp b/src/plugins/debugger/debuggeroptionspage.cpp new file mode 100644 index 0000000000..884edf439f --- /dev/null +++ b/src/plugins/debugger/debuggeroptionspage.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "debuggeroptionspage.h" + +#include "debuggeritemmanager.h" +#include "debuggeritemmodel.h" + +#include <projectexplorer/projectexplorerconstants.h> + +#include <utils/detailswidget.h> +#include <utils/pathchooser.h> +#include <utils/qtcassert.h> + +#include <QFormLayout> +#include <QHeaderView> +#include <QLabel> +#include <QLineEdit> +#include <QObject> +#include <QPushButton> +#include <QTreeView> +#include <QWidget> + +using namespace Utils; + +namespace Debugger { +namespace Internal { + +static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Creator_Windows_Debugging"; + +// ----------------------------------------------------------------------- +// DebuggerItemConfigWidget +// ----------------------------------------------------------------------- + +class DebuggerItemConfigWidget : public QWidget +{ + Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget) + +public: + explicit DebuggerItemConfigWidget(DebuggerItemModel *model); + void setItem(const DebuggerItem &item); + void apply(); + +private: + QLineEdit *m_displayNameLineEdit; + QLabel *m_cdbLabel; + PathChooser *m_binaryChooser; + QLineEdit *m_abis; + DebuggerItemModel *m_model; +}; + +DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : + m_model(model) +{ + QTC_CHECK(model); + + m_displayNameLineEdit = new QLineEdit(this); + + m_binaryChooser = new PathChooser(this); + m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand); + m_binaryChooser->setMinimumWidth(400); + m_binaryChooser->setHistoryCompleter(QLatin1String("DebuggerPaths")); + + m_cdbLabel = new QLabel(this); + m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + m_cdbLabel->setOpenExternalLinks(true); + + m_abis = new QLineEdit(this); + m_abis->setEnabled(false); + + QFormLayout *formLayout = new QFormLayout(this); + formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit); +// formLayout->addRow(new QLabel(tr("Type:")), m_engineTypeComboBox); + formLayout->addRow(m_cdbLabel); + formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser); + formLayout->addRow(new QLabel(tr("ABIs:")), m_abis); +} + +void DebuggerItemConfigWidget::setItem(const DebuggerItem &item) +{ + m_displayNameLineEdit->setEnabled(!item.isAutoDetected()); + m_displayNameLineEdit->setText(item.displayName()); + + m_binaryChooser->setEnabled(!item.isAutoDetected()); + m_binaryChooser->setFileName(item.command()); + + QString text; + QString versionCommand; + if (item.engineType() == CdbEngineType) { +#ifdef Q_OS_WIN + const bool is64bit = winIs64BitSystem(); +#else + const bool is64bit = false; +#endif + const QString versionString = is64bit ? tr("64-bit version") : tr("32-bit version"); + //: Label text for path configuration. %2 is "x-bit version". + text = tr("<html><body><p>Specify the path to the " + "<a href=\"%1\">Windows Console Debugger executable</a>" + " (%2) here.</p>""</body></html>"). + arg(QLatin1String(debuggingToolsWikiLinkC), versionString); + versionCommand = QLatin1String("-version"); + } else { + versionCommand = QLatin1String("--version"); + } + + m_cdbLabel->setText(text); + m_cdbLabel->setVisible(!text.isEmpty()); + m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand)); + + m_abis->setText(item.abiNames().join(QLatin1String(", "))); +} + +void DebuggerItemConfigWidget::apply() +{ + DebuggerItem item = m_model->currentDebugger(); + QTC_ASSERT(item.isValid(), return); + + item.setDisplayName(m_displayNameLineEdit->text()); + item.setCommand(m_binaryChooser->fileName()); + item.reinitializeFromFile(); + m_model->updateDebugger(item); +} + +// -------------------------------------------------------------------------- +// DebuggerOptionsPage +// -------------------------------------------------------------------------- + +DebuggerOptionsPage::DebuggerOptionsPage() +{ + m_model = 0; + m_debuggerView = 0; + m_container = 0; + m_addButton = 0; + m_cloneButton = 0; + m_delButton = 0; + + setId(ProjectExplorer::Constants::DEBUGGER_SETTINGS_PAGE_ID); + setDisplayName(tr("Debuggers")); + setCategory(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY); + setDisplayCategory(QCoreApplication::translate("ProjectExplorer", + ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_TR_CATEGORY)); + setCategoryIcon(QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY_ICON)); +} + +QWidget *DebuggerOptionsPage::createPage(QWidget *parent) +{ + m_configWidget = new QWidget(parent); + + m_addButton = new QPushButton(tr("Add"), m_configWidget); + m_cloneButton = new QPushButton(tr("Clone"), m_configWidget); + m_delButton = new QPushButton(tr("Remove"), m_configWidget); + + m_container = new DetailsWidget(m_configWidget); + m_container->setState(DetailsWidget::NoSummary); + m_container->setVisible(false); + + m_model = new DebuggerItemModel(parent); + + m_debuggerView = new QTreeView(m_configWidget); + m_debuggerView->setModel(m_model); + m_debuggerView->setUniformRowHeights(true); + m_debuggerView->setSelectionMode(QAbstractItemView::SingleSelection); + m_debuggerView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_debuggerView->expandAll(); + + QHeaderView *header = m_debuggerView->header(); + header->setStretchLastSection(false); + header->setResizeMode(0, QHeaderView::ResizeToContents); + header->setResizeMode(1, QHeaderView::ResizeToContents); + header->setResizeMode(2, QHeaderView::Stretch); + + QVBoxLayout *buttonLayout = new QVBoxLayout(); + buttonLayout->setSpacing(6); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->addWidget(m_addButton); + buttonLayout->addWidget(m_cloneButton); + buttonLayout->addWidget(m_delButton); + buttonLayout->addItem(new QSpacerItem(10, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + QVBoxLayout *verticalLayout = new QVBoxLayout(); + verticalLayout->addWidget(m_debuggerView); + verticalLayout->addWidget(m_container); + + QHBoxLayout *horizontalLayout = new QHBoxLayout(m_configWidget); + horizontalLayout->addLayout(verticalLayout); + horizontalLayout->addLayout(buttonLayout); + + connect(m_debuggerView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(debuggerSelectionChanged())); + + connect(m_addButton, SIGNAL(clicked()), this, SLOT(addDebugger()), Qt::QueuedConnection); + connect(m_cloneButton, SIGNAL(clicked()), this, SLOT(cloneDebugger()), Qt::QueuedConnection); + connect(m_delButton, SIGNAL(clicked()), this, SLOT(removeDebugger()), Qt::QueuedConnection); + + m_searchKeywords = tr("Debuggers"); + + m_itemConfigWidget = new DebuggerItemConfigWidget(m_model); + m_container->setWidget(m_itemConfigWidget); + + updateState(); + + return m_configWidget; +} + +void DebuggerOptionsPage::apply() +{ + m_itemConfigWidget->apply(); + m_model->apply(); +} + +void DebuggerOptionsPage::cloneDebugger() +{ + DebuggerItem item = m_model->currentDebugger(); + if (!item.isValid()) + return; + + DebuggerItem newItem; + newItem.setCommand(item.command()); + newItem.setEngineType(item.engineType()); + newItem.setAbis(item.abis()); + newItem.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("Clone of %1").arg(item.displayName()))); + newItem.setAutoDetected(false); + m_model->addDebugger(newItem); + m_debuggerView->setCurrentIndex(m_model->lastIndex()); +} + +void DebuggerOptionsPage::addDebugger() +{ + DebuggerItem item; + item.setEngineType(NoEngineType); + item.setDisplayName(DebuggerItemManager::uniqueDisplayName(tr("New Debugger"))); + item.setAutoDetected(false); + m_model->addDebugger(item); + m_debuggerView->setCurrentIndex(m_model->lastIndex()); +} + +void DebuggerOptionsPage::removeDebugger() +{ + QVariant id = m_model->currentDebuggerId(); + m_model->removeDebugger(id); + m_debuggerView->setCurrentIndex(m_model->lastIndex()); +} + +void DebuggerOptionsPage::finish() +{ + // Deleted by settingsdialog. + m_configWidget = 0; + + // Children of m_configWidget. + m_container = 0; + m_debuggerView = 0; + m_addButton = 0; + m_cloneButton = 0; + m_delButton = 0; +} + +bool DebuggerOptionsPage::matches(const QString &s) const +{ + return m_searchKeywords.contains(s, Qt::CaseInsensitive); +} + +void DebuggerOptionsPage::debuggerSelectionChanged() +{ + QTC_ASSERT(m_container, return); + + QModelIndex mi = m_debuggerView->currentIndex(); + mi = mi.sibling(mi.row(), 0); + m_model->setCurrentIndex(mi); + + DebuggerItem item = m_model->currentDebugger(); + + m_itemConfigWidget->setItem(item); + m_container->setVisible(item.isValid()); + updateState(); +} + +void DebuggerOptionsPage::debuggerModelChanged() +{ + QTC_ASSERT(m_container, return); + + QVariant id = m_model->currentDebuggerId(); + const DebuggerItem *item = DebuggerItemManager::findById(id); + if (!item) + return; + + m_itemConfigWidget->setItem(*item); + m_container->setVisible(m_model->currentDebuggerId().isValid()); + m_debuggerView->setCurrentIndex(m_model->currentIndex()); + updateState(); +} + +void DebuggerOptionsPage::updateState() +{ + if (!m_cloneButton) + return; + + bool canCopy = false; + bool canDelete = false; + + DebuggerItem item = m_model->currentDebugger(); + + canCopy = item.isValid() && item.canClone(); + canDelete = !item.isAutoDetected(); + + m_cloneButton->setEnabled(canCopy); + m_delButton->setEnabled(canDelete); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/debuggeroptionspage.h b/src/plugins/debugger/debuggeroptionspage.h new file mode 100644 index 0000000000..fd1782f4b4 --- /dev/null +++ b/src/plugins/debugger/debuggeroptionspage.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DEBUGGER_DEBUGGEROPTIONSPAGE_H +#define DEBUGGER_DEBUGGEROPTIONSPAGE_H + +#include <coreplugin/dialogs/ioptionspage.h> + +QT_BEGIN_NAMESPACE +class QPushButton; +class QTreeView; +class QWidget; +QT_END_NAMESPACE + +namespace Utils { class DetailsWidget; } + +namespace Debugger { +namespace Internal { + +class DebuggerItemModel; +class DebuggerItemConfigWidget; +class DebuggerKitConfigWidget; + +// -------------------------------------------------------------------------- +// DebuggerOptionsPage +// -------------------------------------------------------------------------- + +class DebuggerOptionsPage : public Core::IOptionsPage +{ + Q_OBJECT + +public: + DebuggerOptionsPage(); + + QWidget *createPage(QWidget *parent); + void apply(); + void finish(); + bool matches(const QString &) const; + +private slots: + void debuggerSelectionChanged(); + void debuggerModelChanged(); + void updateState(); + void cloneDebugger(); + void addDebugger(); + void removeDebugger(); + +private: + QWidget *m_configWidget; + QString m_searchKeywords; + + DebuggerItemModel *m_model; + DebuggerItemConfigWidget *m_itemConfigWidget; + QTreeView *m_debuggerView; + Utils::DetailsWidget *m_container; + QPushButton *m_addButton; + QPushButton *m_cloneButton; + QPushButton *m_delButton; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_DEBUGGEROPTIONSPAGE_H diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index a01bdc9b63..67953afcfc 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -36,11 +36,13 @@ #include "debuggerkitconfigwidget.h" #include "debuggerdialogs.h" #include "debuggerengine.h" +#include "debuggeritemmanager.h" #include "debuggermainwindow.h" #include "debuggerrunner.h" #include "debuggerrunconfigurationaspect.h" #include "debuggerruncontrolfactory.h" #include "debuggerstringutils.h" +#include "debuggeroptionspage.h" #include "debuggerkitinformation.h" #include "memoryagent.h" #include "breakhandler.h" diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index a7d33fdb5e..59c2158dcf 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -43,7 +43,6 @@ #ifdef Q_OS_WIN # include "shared/peutils.h" -# include <utils/winutils.h> #endif #include <projectexplorer/localapplicationrunconfiguration.h> // For LocalApplication* @@ -55,6 +54,7 @@ #include <projectexplorer/taskhub.h> #include <utils/checkablemessagebox.h> +#include <utils/fileutils.h> #include <utils/qtcassert.h> #include <utils/qtcprocess.h> #include <coreplugin/icore.h> @@ -344,12 +344,9 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu if (!fillParameters(&sp, kit, errorMessage)) return sp; sp.environment = environment->environment(); - sp.workingDirectory = rc->workingDirectory(); -#if defined(Q_OS_WIN) - // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) - sp.workingDirectory = normalizePathName(sp.workingDirectory); -#endif + // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) + sp.workingDirectory = FileUtils::normalizePathName(rc->workingDirectory()); sp.executable = rc->executable(); if (sp.executable.isEmpty()) @@ -385,7 +382,7 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu || server.listen(QHostAddress::LocalHostIPv6); if (!canListen) { if (errorMessage) - *errorMessage = DebuggerPlugin::tr("Not enough free ports for QML debugging. "); + *errorMessage = DebuggerPlugin::tr("Not enough free ports for QML debugging.") + QLatin1Char(' '); return sp; } sp.qmlServerAddress = server.serverAddress().toString(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 7e8febf779..9341d1d74e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -277,7 +277,7 @@ QString GdbEngine::errorMessage(QProcess::ProcessError error) return tr("The gdb process failed to start. Either the " "invoked program \"%1\" is missing, or you may have insufficient " "permissions to invoke the program.\n%2") - .arg(m_gdb, gdbProc()->errorString()); + .arg(m_gdb, m_gdbProc->errorString()); case QProcess::Crashed: if (targetState() == DebuggerFinished) return tr("The gdb process crashed some time after starting " @@ -296,15 +296,10 @@ QString GdbEngine::errorMessage(QProcess::ProcessError error) return tr("An error occurred when attempting to read from " "the gdb process. For example, the process may not be running."); default: - return tr("An unknown error in the gdb process occurred. "); + return tr("An unknown error in the gdb process occurred."); } } -GdbProcess *GdbEngine::gdbProc() const -{ - return m_gdbProc; -} - #if 0 static void dump(const char *first, const char *middle, const QString & to) { @@ -338,7 +333,7 @@ static inline QString msgWinException(const QByteArray &data, unsigned *exCodeIn const quint64 address = data.mid(addressPos).trimmed().toULongLong(0, 0); QString rc; QTextStream str(&rc); - str << GdbEngine::tr("An exception was triggered: "); + str << GdbEngine::tr("An exception was triggered:") << ' '; formatWindowsException(exCode, address, 0, 0, 0, str); str << '.'; return rc; @@ -794,7 +789,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) void GdbEngine::readGdbStandardError() { - QByteArray err = gdbProc()->readAllStandardError(); + QByteArray err = m_gdbProc->readAllStandardError(); showMessage(_("UNEXPECTED GDB STDERR: " + err)); if (err == "Undefined command: \"bb\". Try \"help\".\n") return; @@ -810,7 +805,7 @@ void GdbEngine::readGdbStandardOutput() int newstart = 0; int scan = m_inbuffer.size(); - QByteArray out = gdbProc()->readAllStandardOutput(); + QByteArray out = m_gdbProc->readAllStandardOutput(); m_inbuffer.append(out); // This can trigger when a dialog starts a nested event loop. @@ -974,7 +969,7 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0) return; } - QTC_ASSERT(gdbProc()->state() == QProcess::Running, return); + QTC_ASSERT(m_gdbProc->state() == QProcess::Running, return); const int token = ++currentToken(); @@ -1055,7 +1050,7 @@ void GdbEngine::commandTimeout() if (mb->exec() == QMessageBox::Ok) { showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER")); // This is an undefined state, so we just pull the emergency brake. - gdbProc()->kill(); + m_gdbProc->kill(); } else { showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER")); } @@ -2044,9 +2039,9 @@ void GdbEngine::notifyAdapterShutdownOk() { QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); showMessage(_("INITIATE GDBENGINE SHUTDOWN IN STATE %1, PROC: %2") - .arg(lastGoodState()).arg(gdbProc()->state())); + .arg(lastGoodState()).arg(m_gdbProc->state())); m_commandsDoneCallback = 0; - switch (gdbProc()->state()) { + switch (m_gdbProc->state()) { case QProcess::Running: postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit)); break; @@ -2056,7 +2051,7 @@ void GdbEngine::notifyAdapterShutdownOk() break; case QProcess::Starting: showMessage(_("GDB NOT REALLY RUNNING; KILLING IT")); - gdbProc()->kill(); + m_gdbProc->kill(); notifyEngineShutdownFailed(); break; } @@ -2073,7 +2068,7 @@ void GdbEngine::handleGdbExit(const GdbResponse &response) QString::fromLocal8Bit(response.data["msg"].data())); qDebug() << (_("GDB WON'T EXIT (%1); KILLING IT").arg(msg)); showMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg)); - gdbProc()->kill(); + m_gdbProc->kill(); } } @@ -4758,7 +4753,7 @@ void GdbEngine::startGdb(const QStringList &args) foreach (int test, m_testCases) showMessage(_("ENABLING TEST CASE: " + QByteArray::number(test))); - gdbProc()->disconnect(); // From any previous runs + m_gdbProc->disconnect(); // From any previous runs const DebuggerStartParameters &sp = startParameters(); m_gdb = gdbBinary(sp); @@ -4783,19 +4778,19 @@ void GdbEngine::startGdb(const QStringList &args) } gdbArgs += args; - connect(gdbProc(), SIGNAL(error(QProcess::ProcessError)), + connect(m_gdbProc, SIGNAL(error(QProcess::ProcessError)), SLOT(handleGdbError(QProcess::ProcessError))); - connect(gdbProc(), SIGNAL(finished(int,QProcess::ExitStatus)), + connect(m_gdbProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(handleGdbFinished(int,QProcess::ExitStatus))); - connect(gdbProc(), SIGNAL(readyReadStandardOutput()), + connect(m_gdbProc, SIGNAL(readyReadStandardOutput()), SLOT(readGdbStandardOutput())); - connect(gdbProc(), SIGNAL(readyReadStandardError()), + connect(m_gdbProc, SIGNAL(readyReadStandardError()), SLOT(readGdbStandardError())); showMessage(_("STARTING ") + m_gdb + _(" ") + gdbArgs.join(_(" "))); - gdbProc()->start(m_gdb, gdbArgs); + m_gdbProc->start(m_gdb, gdbArgs); - if (!gdbProc()->waitForStarted()) { + if (!m_gdbProc->waitForStarted()) { handleGdbStartFailed(); const QString msg = errorMessage(QProcess::FailedToStart); handleAdapterStartFailed(msg); @@ -5009,7 +5004,7 @@ void GdbEngine::handleGdbError(QProcess::ProcessError error) case QProcess::WriteError: case QProcess::Timedout: default: - //gdbProc()->kill(); + //m_gdbProc->kill(); //notifyEngineIll(); showMessageBox(QMessageBox::Critical, tr("GDB I/O Error"), msg); break; @@ -5050,8 +5045,8 @@ void GdbEngine::abortDebugger() if (targetState() == DebuggerFinished) { // We already tried. Try harder. showMessage(_("ABORTING DEBUGGER. SECOND TIME.")); - QTC_ASSERT(gdbProc(), return); - gdbProc()->kill(); + QTC_ASSERT(m_gdbProc, return); + m_gdbProc->kill(); } else { // Be friendly the first time. This will change targetState(). showMessage(_("ABORTING DEBUGGER. FIRST TIME.")); @@ -5215,7 +5210,7 @@ void GdbEngine::handleBreakOnQFatal(const GdbResponse &response) void GdbEngine::notifyInferiorSetupFailed(const QString &msg) { - showStatusMessage(tr("Failed to start application: ") + msg); + showStatusMessage(tr("Failed to start application:") + QLatin1Char(' ') + msg); if (state() == EngineSetupFailed) { showMessage(_("INFERIOR START FAILED, BUT ADAPTER DIED ALREADY")); return; // Adapter crashed meanwhile, so this notification is meaningless. @@ -5240,7 +5235,7 @@ void GdbEngine::handleAdapterCrashed(const QString &msg) notifyEngineIll(); // No point in being friendly here ... - gdbProc()->kill(); + m_gdbProc->kill(); if (!msg.isEmpty()) showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg); @@ -5385,7 +5380,7 @@ bool GdbEngine::attemptQuickStart() const void GdbEngine::write(const QByteArray &data) { - gdbProc()->write(data); + m_gdbProc->write(data); } bool GdbEngine::prepareCommand() diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index fd278d51ae..592be2b0a9 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -649,7 +649,6 @@ protected: // Convenience Functions // QString errorMessage(QProcess::ProcessError error); - GdbProcess *gdbProc() const; void showExecutionError(const QString &message); static QByteArray tooltipIName(const QString &exp); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 9526e5e608..46dfd62aef 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -110,8 +110,8 @@ void LldbEngine::runCommand(const Command &command) QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll()); ++m_lastToken; QByteArray token = QByteArray::number(m_lastToken); - QByteArray cmd = "db {'cmd':'" + command.function + "'," - + command.args + "'token':" + token + "}\n"; + QByteArray cmd = "{\"cmd\":\"" + command.function + "\"," + + command.args + "\"token\":" + token + "}\n"; showMessage(_(token + cmd), LogInput); m_lldbProc.write(cmd); } @@ -156,7 +156,7 @@ void LldbEngine::setupEngine() m_lldbProc.start(_("python"), args); if (!m_lldbProc.waitForStarted()) { - const QString msg = tr("Unable to start LLDB '%1': %2") + const QString msg = tr("Unable to start LLDB \"%1\": %2") .arg(m_lldbCmd, m_lldbProc.errorString()); notifyEngineSetupFailed(); showMessage(_("ADAPTER START FAILED")); @@ -645,7 +645,7 @@ bool LldbEngine::setToolTipExpression(const QPoint &mousePos, } if (!hasLetterOrNumber(exp)) { - QToolTip::showText(m_toolTipPos, tr("'%1' contains no identifier.").arg(exp)); + QToolTip::showText(m_toolTipPos, tr("\"%1\" contains no identifier.").arg(exp)); return true; } @@ -665,7 +665,7 @@ bool LldbEngine::setToolTipExpression(const QPoint &mousePos, if (hasSideEffects(exp)) { QToolTip::showText(m_toolTipPos, - tr("Cowardly refusing to evaluate expression '%1' " + tr("Cowardly refusing to evaluate expression \"%1\" " "with potential side effects.").arg(exp)); return true; } @@ -794,7 +794,7 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const switch (error) { case QProcess::FailedToStart: return tr("The LLDB process failed to start. Either the " - "invoked program '%1' is missing, or you may have insufficient " + "invoked program \"%1\" is missing, or you may have insufficient " "permissions to invoke the program.") .arg(m_lldbCmd); case QProcess::Crashed: @@ -812,7 +812,7 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const return tr("An error occurred when attempting to read from " "the Lldb process. For example, the process may not be running."); default: - return tr("An unknown error in the Lldb process occurred. "); + return tr("An unknown error in the Lldb process occurred.") + QLatin1Char(' '); } } @@ -836,15 +836,14 @@ void LldbEngine::readLldbStandardError() void LldbEngine::readLldbStandardOutput() { QByteArray out = m_lldbProc.readAllStandardOutput(); - //showMessage(_("Lldb stdout: " + out)); - showMessage(_(out), LogDebug); + showMessage(_("Lldb stdout: " + out)); m_inbuffer.append(out); while (true) { - int pos = m_inbuffer.indexOf("@\n"); + int pos = m_inbuffer.indexOf('\n'); if (pos == -1) break; QByteArray response = m_inbuffer.left(pos).trimmed(); - m_inbuffer = m_inbuffer.mid(pos + 2); + m_inbuffer = m_inbuffer.mid(pos + 1); emit outputReady(response); } } @@ -856,12 +855,12 @@ void LldbEngine::requestUpdateWatchers() while (it.hasNext()) { it.next(); QHash<QByteArray, QByteArray> hash; - hash["iname"] = "'watch." + QByteArray::number(it.value()) + '\''; - hash["exp"] = '\'' + it.key().toHex() + '\''; + hash["iname"] = "\"watch." + QByteArray::number(it.value()) + '"'; + hash["exp"] = '"' + it.key().toHex() + '"'; watcherData.append(Command::toData(hash)); } Command cmd("setWatchers"); - cmd.args.append("'watchers':" + Command::toData(watcherData) + ','); + cmd.args.append("\"watchers\":" + Command::toData(watcherData) + ','); runCommand(cmd); } @@ -1117,9 +1116,9 @@ DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters) const LldbEngine::Command &LldbEngine::Command::argHelper(const char *name, const QByteArray &data) const { - args.append('\''); + args.append('"'); args.append(name); - args.append("':"); + args.append("\":"); args.append(data); args.append(","); return *this; @@ -1144,7 +1143,7 @@ QByteArray LldbEngine::Command::toData(const QHash<QByteArray, QByteArray> &valu it.next(); if (!res.isEmpty()) res.append(','); - res += '\'' + it.key() + "':" + it.value(); + res += '"' + it.key() + "\":" + it.value(); } return '{' + res + '}'; } @@ -1176,20 +1175,20 @@ const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const QByt const LldbEngine::Command &LldbEngine::Command::arg(const char *name, const char *value) const { - args.append('\''); + args.append('"'); args.append(name); - args.append("':'"); + args.append("\":\""); args.append(value); - args.append("',"); + args.append("\","); return *this; } const LldbEngine::Command &LldbEngine::Command::beginList(const char *name) const { if (name) { - args += '\''; + args += '"'; args += name; - args += "':"; + args += "\":"; } args += '['; return *this; @@ -1205,9 +1204,9 @@ void LldbEngine::Command::endList() const const LldbEngine::Command &LldbEngine::Command::beginGroup(const char *name) const { if (name) { - args += '\''; + args += '"'; args += name; - args += "':"; + args += "\":"; } args += '{'; return *this; diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 702bd1cefa..71453f46f0 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -596,7 +596,7 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const return tr("An error occurred when attempting to read from " "the Pdb process. For example, the process may not be running."); default: - return tr("An unknown error in the Pdb process occurred. "); + return tr("An unknown error in the Pdb process occurred.") + QLatin1Char(' '); } } diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 89929350c7..4308c42c48 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -1167,7 +1167,7 @@ void QmlEngine::updateCurrentContext() QmlJS::ConsoleManagerInterface *consoleManager = qmlConsoleManager(); if (consoleManager) - consoleManager->setContext(tr("Context: ").append(context)); + consoleManager->setContext(tr("Context:") + QLatin1Char(' ') + context); } void QmlEngine::appendDebugOutput(QtMsgType type, const QString &message, diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index 68974bf9d4..c1e4f41b4f 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -454,7 +454,8 @@ void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value, } else if (type == "SET_BINDING_R" || type == "RESET_BINDING_R" || type == "SET_METHOD_BODY_R") { - QString msg = QLatin1String(type) + tr("Success: "); + QString msg = QLatin1String(type) + tr("Success:"); + msg += QLatin1Char(' '); msg += value.toBool() ? QLatin1Char('1') : QLatin1Char('0'); if (!value.toBool()) emit automaticUpdateFailed(); diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 8cad1a3c13..cead6220a3 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -392,7 +392,8 @@ QString WatchData::toToolTip() const } if (val.size() > 1000) { val.truncate(1000); - val += tr(" ... <cut off>"); + val += QLatin1Char(' '); + val += tr("... <cut off>"); } formatToolTipRow(str, tr("Value"), val); if (address) diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 1619cfeb2f..7539387542 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -649,7 +649,7 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) QString msg = (individualFormat == -1 && typeFormat != -1) ? tr("Use Format for Type (Currently %1)") .arg(alternativeFormats.at(typeFormat)) - : tr("Use Display Format Based on Type "); + : tr("Use Display Format Based on Type") + QLatin1Char(' '); clearIndividualFormatAction = formatMenu.addAction(spacer + msg); clearIndividualFormatAction->setCheckable(true); clearIndividualFormatAction->setChecked(individualFormat == -1); diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 59a65c0ac2..5c3050f81d 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1576,7 +1576,6 @@ public: QTextBlock previousLine(const QTextBlock &block) const; // previous line (respects wrapped parts) int linesOnScreen() const; - int columnsOnScreen() const; int linesInDocument() const; // The following use all zero-based counting. @@ -3673,9 +3672,12 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) setCursorPosition(&m_cursor, pos); handleStartOfLine(); } else if (g.gflag && input.is('m')) { - moveToStartOfLine(); - moveRight(qMin(columnsOnScreen() / 2, rightDist()) - 1); - setTargetColumn(); + const QPoint pos(EDITOR(viewport()->width()) / 2, EDITOR(cursorRect(m_cursor)).y()); + QTextCursor tc = EDITOR(cursorForPosition(pos)); + if (!tc.isNull()) { + m_cursor = tc; + setTargetColumn(); + } } else if (input.is('M')) { m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2))); handleStartOfLine(); @@ -5397,7 +5399,7 @@ bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd) if (!error.isEmpty()) showMessage(MessageError, error); } else { - showMessage(MessageError, FakeVimHandler::tr("Unknown option: ") + cmd.args); + showMessage(MessageError, FakeVimHandler::tr("Unknown option:") + QLatin1Char(' ') + cmd.args); } updateMiniBuffer(); updateEditor(); @@ -6370,25 +6372,16 @@ int FakeVimHandler::Private::cursorLineOnScreen() const { if (!editor()) return 0; - QRect rect = EDITOR(cursorRect()); - return rect.y() / rect.height(); + const QRect rect = EDITOR(cursorRect(m_cursor)); + return rect.height() > 0 ? rect.y() / rect.height() : 0; } int FakeVimHandler::Private::linesOnScreen() const { if (!editor()) return 1; - QRect rect = EDITOR(cursorRect()); - return EDITOR(viewport()->height()) / rect.height(); -} - -int FakeVimHandler::Private::columnsOnScreen() const -{ - if (!editor()) - return 1; - QRect rect = EDITOR(cursorRect()); - // qDebug() << "WID: " << EDITOR(width()) << "RECT: " << rect; - return EDITOR(viewport()->width()) / rect.width(); + const int h = EDITOR(cursorRect(m_cursor)).height(); + return h > 0 ? EDITOR(viewport()->height()) / h : 1; } int FakeVimHandler::Private::cursorLine() const diff --git a/src/plugins/git/gerrit/gerritdialog.cpp b/src/plugins/git/gerrit/gerritdialog.cpp index 27f84d55be..8859af24e7 100644 --- a/src/plugins/git/gerrit/gerritdialog.cpp +++ b/src/plugins/git/gerrit/gerritdialog.cpp @@ -101,7 +101,7 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p, , m_filterLineEdit(new Utils::FilterLineEdit) , m_repositoryChooser(new Utils::PathChooser) , m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Close)) - , m_repositoryChooserLabel(new QLabel(tr("Apply in: "), this)) + , m_repositoryChooserLabel(new QLabel(tr("Apply in:") + QLatin1Char(' '), this)) , m_fetchRunning(false) { setWindowTitle(tr("Gerrit %1@%2").arg(p->user, p->host)); diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index 4cba759995..c8b0537a22 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -37,6 +37,7 @@ #include <QDateTime> #include <QDir> +#include <QRegExpValidator> namespace Gerrit { namespace Internal { @@ -156,6 +157,9 @@ GerritPushDialog::GerritPushDialog(const QString &workingDir, const QString &rev connect(m_ui->branchComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setChangeRange())); setRemoteBranches(); m_ui->reviewersLineEdit->setText(reviewerList); + + m_ui->topicLineEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("^\\S+$")), this)); + m_valid = true; } diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 764ba726b0..416c29e5d3 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2767,7 +2767,7 @@ void GitClient::continuePreviousGitCommand(const QString &workingDirectory, == GitClient::StatusChanged; } if (!hasChanges) - msgBoxText.prepend(tr("No changes found. ")); + msgBoxText.prepend(tr("No changes found.") + QLatin1Char(' ')); QMessageBox msgBox(QMessageBox::Question, msgBoxTitle, msgBoxText, QMessageBox::NoButton, Core::ICore::mainWindow()); if (hasChanges || isRebase) @@ -2808,7 +2808,7 @@ QString GitClient::extendedShowDescription(const QString &workingDirectory, cons if (branchCount > 20) { const int leave = 10; //: Displayed after the untranslated message "Branches: branch1, branch2 'and %n more'" in git show. - moreBranches = tr(" and %n more", 0, branchCount - leave); + moreBranches = QLatin1Char(' ') + tr("and %n more", 0, branchCount - leave); branches.erase(branches.begin() + leave, branches.end()); } if (!branches.isEmpty()) { diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index ebfca0293f..1eaa690bc9 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -42,6 +42,7 @@ #include <projectexplorer/toolchain.h> #include <projectexplorer/gcctoolchain.h> #include <projectexplorer/projectexplorerconstants.h> +#include <debugger/debuggeritemmanager.h> #include <debugger/debuggerkitinformation.h> #include <qtsupport/baseqtversion.h> #include <qtsupport/qtkitinformation.h> diff --git a/src/plugins/ios/iosdevice.cpp b/src/plugins/ios/iosdevice.cpp index d258d34991..524eff4728 100644 --- a/src/plugins/ios/iosdevice.cpp +++ b/src/plugins/ios/iosdevice.cpp @@ -33,6 +33,7 @@ #include "iostoolhandler.h" #include <projectexplorer/devicesupport/devicemanager.h> #include <projectexplorer/kitinformation.h> +#include <coreplugin/helpmanager.h> #include <QCoreApplication> #include <QVariant> @@ -318,11 +319,12 @@ void IosDeviceManager::deviceInfo(IosToolHandler *, const QString &uid, mBox.setText(tr("An iOS device in user mode has been detected.")); mBox.setInformativeText(tr("Do you want to see how to set it up for development?")); mBox.setStandardButtons(QMessageBox::NoAll | QMessageBox::No | QMessageBox::Yes); - mBox.setDefaultButton(QMessageBox::No); + mBox.setDefaultButton(QMessageBox::Yes); int ret = mBox.exec(); switch (ret) { case QMessageBox::Yes: - // open doc + Core::HelpManager::handleHelpRequest( + QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-developing-ios.html")); break; case QMessageBox::No: newDev->m_ignoreDevice = true; diff --git a/src/plugins/locator/executefilter.cpp b/src/plugins/locator/executefilter.cpp index 4b4ef46b0b..20e940a1d7 100644 --- a/src/plugins/locator/executefilter.cpp +++ b/src/plugins/locator/executefilter.cpp @@ -168,6 +168,11 @@ void ExecuteFilter::runHeadCommand() m_process->setCommand(fullPath, d.arguments); m_process->start(); m_process->closeWriteChannel(); + if (!m_process->waitForStarted(1000)) { + MessageManager::write(tr("Could not start process: %1").arg(m_process->errorString())); + m_taskQueue.dequeue(); + runHeadCommand(); + } } } diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index b0c45aa001..aafe96ccd9 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -311,18 +311,19 @@ Abi::Abi(const Architecture &a, const OS &o, m_osFlavor = UnknownFlavor; break; case ProjectExplorer::Abi::LinuxOS: - if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > MaemoLinuxFlavor) + if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > AndroidLinuxFlavor) m_osFlavor = UnknownFlavor; break; case ProjectExplorer::Abi::BsdOS: - m_osFlavor = FreeBsdFlavor; + if (m_osFlavor < FreeBsdFlavor || m_osFlavor > OpenBsdFlavor) + m_osFlavor = UnknownFlavor; break; case ProjectExplorer::Abi::MacOS: if (m_osFlavor < GenericMacFlavor || m_osFlavor > GenericMacFlavor) m_osFlavor = UnknownFlavor; break; case ProjectExplorer::Abi::UnixOS: - if (m_osFlavor < GenericUnixFlavor || m_osFlavor > GenericUnixFlavor) + if (m_osFlavor < GenericUnixFlavor || m_osFlavor > SolarisUnixFlavor) m_osFlavor = UnknownFlavor; break; case ProjectExplorer::Abi::WindowsOS: @@ -387,10 +388,6 @@ Abi::Abi(const QString &abiString) : m_osFlavor = NetBsdFlavor; else if (abiParts.at(2) == QLatin1String("openbsd") && m_os == BsdOS) m_osFlavor = OpenBsdFlavor; - else if (abiParts.at(2) == QLatin1String("maemo") && m_os == LinuxOS) - m_osFlavor = MaemoLinuxFlavor; - else if (abiParts.at(2) == QLatin1String("harmattan") && m_os == LinuxOS) - m_osFlavor = HarmattanLinuxFlavor; else if (abiParts.at(2) == QLatin1String("generic") && m_os == MacOS) m_osFlavor = GenericMacFlavor; else if (abiParts.at(2) == QLatin1String("generic") && m_os == UnixOS) @@ -637,10 +634,6 @@ QString Abi::toString(const OSFlavor &of) return QLatin1String("netbsd"); case ProjectExplorer::Abi::OpenBsdFlavor: return QLatin1String("openbsd"); - case ProjectExplorer::Abi::MaemoLinuxFlavor: - return QLatin1String("maemo"); - case ProjectExplorer::Abi::HarmattanLinuxFlavor: - return QLatin1String("harmattan"); case ProjectExplorer::Abi::GenericMacFlavor: return QLatin1String("generic"); case ProjectExplorer::Abi::GenericUnixFlavor: @@ -698,8 +691,7 @@ QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o) case BsdOS: return result << FreeBsdFlavor << OpenBsdFlavor << NetBsdFlavor << UnknownFlavor; case LinuxOS: - return result << GenericLinuxFlavor << HarmattanLinuxFlavor << MaemoLinuxFlavor - << AndroidLinuxFlavor << UnknownFlavor; + return result << GenericLinuxFlavor << AndroidLinuxFlavor << UnknownFlavor; case MacOS: return result << GenericMacFlavor << UnknownFlavor; case UnixOS: diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 473918b918..e7e7a9669e 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -73,8 +73,6 @@ public: // Linux GenericLinuxFlavor, AndroidLinuxFlavor, - HarmattanLinuxFlavor, - MaemoLinuxFlavor, // Mac GenericMacFlavor, diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index a3667fbece..e04b94731d 100644 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -35,10 +35,8 @@ #include <coreplugin/icore.h> #include <utils/consoleprocess.h> +#include <utils/fileutils.h> #include <utils/qtcprocess.h> -#ifdef Q_OS_WIN -#include <utils/winutils.h> -#endif #include <QTextCodec> @@ -131,19 +129,10 @@ ApplicationLauncher::~ApplicationLauncher() void ApplicationLauncher::setWorkingDirectory(const QString &dir) { -#ifdef Q_OS_WIN // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) - const QString fixedPath = Utils::normalizePathName(dir); -#else -# define fixedPath dir -#endif - + const QString fixedPath = Utils::FileUtils::normalizePathName(dir); d->m_guiProcess.setWorkingDirectory(fixedPath); d->m_consoleProcess.setWorkingDirectory(fixedPath); - -#ifndef Q_OS_WIN -# undef fixedPath -#endif } void ApplicationLauncher::setEnvironment(const Utils::Environment &env) diff --git a/src/plugins/projectexplorer/copytaskhandler.cpp b/src/plugins/projectexplorer/copytaskhandler.cpp index 58c3f691ad..1b641a7ce1 100644 --- a/src/plugins/projectexplorer/copytaskhandler.cpp +++ b/src/plugins/projectexplorer/copytaskhandler.cpp @@ -45,11 +45,11 @@ void CopyTaskHandler::handle(const ProjectExplorer::Task &task) switch (task.type) { case Task::Error: //: Task is of type: error - type = tr("error: "); + type = tr("error:") + QLatin1Char(' '); break; case Task::Warning: //: Task is of type: warning - type = tr("warning: "); + type = tr("warning:") + QLatin1Char(' '); break; default: break; diff --git a/src/plugins/projectexplorer/customparserconfigdialog.cpp b/src/plugins/projectexplorer/customparserconfigdialog.cpp index b45c745c8f..2a6c0f7202 100644 --- a/src/plugins/projectexplorer/customparserconfigdialog.cpp +++ b/src/plugins/projectexplorer/customparserconfigdialog.cpp @@ -147,7 +147,7 @@ void CustomParserConfigDialog::changed() int pos = rx.indexIn(ui->errorMessage->text()); if (rx.isEmpty() || !rx.isValid() || pos < 0) { - QString error = QLatin1String("<font color=\"red\">") + tr("Not applicable: "); + QString error = QLatin1String("<font color=\"red\">") + tr("Not applicable:") + QLatin1Char(' '); if (rx.isEmpty()) error += tr("Pattern is empty."); else if (!rx.isValid()) diff --git a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp index c2d736b3f5..719739bce2 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp @@ -85,14 +85,16 @@ void DesktopProcessSignalOperation::appendMsgCannotKill(int pid, const QString & { if (!m_errorMessage.isEmpty()) m_errorMessage += QChar::fromLatin1('\n'); - m_errorMessage += tr("Cannot kill process with pid %1: %3 ").arg(pid).arg(why); + m_errorMessage += tr("Cannot kill process with pid %1: %3").arg(pid).arg(why); + m_errorMessage += QLatin1Char(' '); } void DesktopProcessSignalOperation::appendMsgCannotInterrupt(int pid, const QString &why) { if (!m_errorMessage.isEmpty()) m_errorMessage += QChar::fromLatin1('\n'); - m_errorMessage += tr("Cannot interrupt process with pid %1: %3 ").arg(pid).arg(why); + m_errorMessage += tr("Cannot interrupt process with pid %1: %3").arg(pid).arg(why); + m_errorMessage += QLatin1Char(' '); } void DesktopProcessSignalOperation::killProcessSilently(int pid) @@ -165,8 +167,8 @@ GDB 32bit | Api | Api | N/A | Win32 m_specialInterrupt == Win64Interrupt && creatorIs64Bit || m_specialInterrupt == Win32Interrupt && !creatorIs64Bit) { if (!DebugBreakProcess(inferior)) { - appendMsgCannotInterrupt(pid, tr("DebugBreakProcess failed: ") - + Utils::winErrorMessage(GetLastError())); + appendMsgCannotInterrupt(pid, tr("DebugBreakProcess failed:") + + QLatin1Char(' ') + Utils::winErrorMessage(GetLastError())); } } else if (m_specialInterrupt == Win32Interrupt || m_specialInterrupt == Win64Interrupt) { QString executable = QCoreApplication::applicationDirPath(); @@ -189,7 +191,7 @@ GDB 32bit | Api | Api | N/A | Win32 break; default: appendMsgCannotInterrupt(pid, QDir::toNativeSeparators(executable) - + tr(" could not break the process.")); + + QLatin1Char(' ') + tr("could not break the process.")); break; } } diff --git a/src/plugins/projectexplorer/foldernavigationwidget.cpp b/src/plugins/projectexplorer/foldernavigationwidget.cpp index 6aad3a6b20..4e26ef1101 100644 --- a/src/plugins/projectexplorer/foldernavigationwidget.cpp +++ b/src/plugins/projectexplorer/foldernavigationwidget.cpp @@ -158,6 +158,8 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) this, SLOT(slotOpenItem(QModelIndex))); connect(m_filterHiddenFilesAction, SIGNAL(toggled(bool)), this, SLOT(setHiddenFilesFilter(bool))); connect(m_toggleSync, SIGNAL(clicked(bool)), this, SLOT(toggleAutoSynchronization())); + connect(m_filterModel, SIGNAL(layoutChanged()), + this, SLOT(ensureCurrentIndex())); } void FolderNavigationWidget::toggleAutoSynchronization() @@ -225,10 +227,17 @@ bool FolderNavigationWidget::setCurrentDirectory(const QString &directory) setCurrentTitle(QString(), QString()); return false; } - m_listView->setRootIndex(m_filterModel->mapFromSource(index)); + QModelIndex oldRootIndex = m_listView->rootIndex(); + QModelIndex newRootIndex = m_filterModel->mapFromSource(index); + m_listView->setRootIndex(newRootIndex); const QDir current(QDir::cleanPath(newDirectory)); setCurrentTitle(current.dirName(), QDir::toNativeSeparators(current.absolutePath())); + if (oldRootIndex.parent() == newRootIndex) { // cdUp, so select the old directory + m_listView->setCurrentIndex(oldRootIndex); + m_listView->scrollTo(oldRootIndex, QAbstractItemView::EnsureVisible); + } + return !directory.isEmpty(); } @@ -365,6 +374,17 @@ bool FolderNavigationWidget::hiddenFilesFilter() const return m_filterHiddenFilesAction->isChecked(); } +void FolderNavigationWidget::ensureCurrentIndex() +{ + QModelIndex index = m_listView->currentIndex(); + if (!index.isValid() + || index.parent() != m_listView->rootIndex()) { + index = m_listView->rootIndex().child(0, 0); + m_listView->setCurrentIndex(index); + } + m_listView->scrollTo(index); +} + // --------------------FolderNavigationWidgetFactory FolderNavigationWidgetFactory::FolderNavigationWidgetFactory() { diff --git a/src/plugins/projectexplorer/foldernavigationwidget.h b/src/plugins/projectexplorer/foldernavigationwidget.h index 6b6aaed266..f99a9262e8 100644 --- a/src/plugins/projectexplorer/foldernavigationwidget.h +++ b/src/plugins/projectexplorer/foldernavigationwidget.h @@ -70,6 +70,7 @@ private slots: void setCurrentFile(const QString &filePath); void slotOpenItem(const QModelIndex &viewIndex); void setHiddenFilesFilter(bool filter); + void ensureCurrentIndex(); protected: virtual void contextMenuEvent(QContextMenuEvent *ev); diff --git a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp b/src/plugins/projectexplorer/kitinformationconfigwidget.cpp index d3a43ba096..7c5ac9bcad 100644 --- a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitinformationconfigwidget.cpp @@ -89,7 +89,7 @@ void SysRootInformationConfigWidget::refresh() void SysRootInformationConfigWidget::makeReadOnly() { - m_chooser->setReadOnly(true); + m_chooser->setEnabled(false); } QWidget *SysRootInformationConfigWidget::mainWidget() const diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 0bc41b7b84..653d9e30f7 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -31,9 +31,7 @@ #include "projectexplorerconstants.h" #include <utils/qtcassert.h> -#ifdef Q_OS_WIN -#include <utils/winutils.h> -#endif +#include <utils/fileutils.h> static const char FILE_POS_PATTERN[] = "(cl|LINK|.+) : "; static const char ERROR_PATTERN[] = "[A-Z]+\\d\\d\\d\\d ?:"; @@ -58,11 +56,7 @@ static QPair<Utils::FileName, int> parseFileName(const QString &input) } } } -#ifdef Q_OS_WIN - const QString normalized = Utils::normalizePathName(fileName); -#else - const QString normalized = fileName; -#endif + const QString normalized = Utils::FileUtils::normalizePathName(fileName); return qMakePair(Utils::FileName::fromUserInput(normalized), linenumber); } diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index db71fccfa8..fa2b24a995 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -29,8 +29,6 @@ #include "projectwelcomepage.h" -#include <utils/stringutils.h> - #include <QQmlContext> #include <QQmlEngine> #include <QFileInfo> @@ -42,9 +40,8 @@ #include <projectexplorer/projectexplorer.h> #include <projectexplorer/sessiondialog.h> -#ifdef Q_OS_WIN -#include <utils/winutils.h> -#endif +#include <utils/fileutils.h> +#include <utils/stringutils.h> namespace ProjectExplorer { namespace Internal { @@ -225,12 +222,9 @@ void ProjectWelcomePage::facilitateQml(QQmlEngine *engine) QUrl ProjectWelcomePage::pageLocation() const { - QString resourcePath = Core::ICore::resourcePath(); -#ifdef Q_OS_WIN // normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows - resourcePath = Utils::normalizePathName(resourcePath); -#endif - return QUrl::fromLocalFile(resourcePath + QLatin1String("/welcomescreen/develop.qml")); + const QString resourcePath = Utils::FileUtils::normalizePathName(Core::ICore::resourcePath()); + return QUrl::fromLocalFile(resourcePath + QLatin1String("/welcomescreen/develop.qml")); } ProjectWelcomePage::Id ProjectWelcomePage::id() const diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index 504871cb5b..95a99377a0 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -418,7 +418,7 @@ Target *TargetSettingsPanelWidget::cloneTarget(Target *sourceTarget, Kit *k) if (!runconfigurationError.isEmpty()) { if (!error.isEmpty()) error.append(QLatin1Char('\n')); - error += tr("Run configurations ") + error += tr("Run configurations") + QLatin1Char(' ') + runconfigurationError.join(QLatin1String("\n")); } diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index ce094aeff8..34ab0c6d01 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -48,6 +48,7 @@ #include <QStyledItemDelegate> #include <QMenu> #include <QToolButton> +#include <QScrollBar> namespace { const int ELLIPSIS_GRADIENT_WIDTH = 16; @@ -74,6 +75,8 @@ class TaskDelegate : public QStyledItemDelegate { Q_OBJECT + friend class TaskView; // for using Positions::minimumSize() + public: TaskDelegate(QObject * parent = 0); ~TaskDelegate(); @@ -126,11 +129,11 @@ private: int right() const { return m_totalWidth - ITEM_MARGIN; } int bottom() const { return m_bottom; } int firstLineHeight() const { return m_fontHeight + 1; } - int minimumHeight() const { return taskIconHeight() + 2 * ITEM_MARGIN; } + static int minimumHeight() { return taskIconHeight() + 2 * ITEM_MARGIN; } int taskIconLeft() const { return left(); } - int taskIconWidth() const { return TASK_ICON_SIZE; } - int taskIconHeight() const { return TASK_ICON_SIZE; } + static int taskIconWidth() { return TASK_ICON_SIZE; } + static int taskIconHeight() { return TASK_ICON_SIZE; } int taskIconRight() const { return taskIconLeft() + taskIconWidth(); } QRect taskIcon() const { return QRect(taskIconLeft(), top(), taskIconWidth(), taskIconHeight()); } @@ -169,6 +172,13 @@ TaskView::TaskView(QWidget *parent) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + QFontMetrics fm(font()); + int vStepSize = fm.height() + 3; + if (vStepSize < TaskDelegate::Positions::minimumHeight()) + vStepSize = TaskDelegate::Positions::minimumHeight(); + + verticalScrollBar()->setSingleStep(vStepSize); } TaskView::~TaskView() diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 03f5c72654..970626a241 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -412,7 +412,14 @@ void QbsProject::parse(const QVariantMap &config, const Environment &env, const QTC_ASSERT(!dir.isNull(), return); qbs::SetupProjectParameters params; - params.setBuildConfiguration(config); + QVariantMap baseConfig; + QVariantMap userConfig = config; + QString specialKey = QLatin1String(Constants::QBS_CONFIG_PROFILE_KEY); + baseConfig.insert(specialKey, userConfig.take(specialKey)); + specialKey = QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY); + baseConfig.insert(specialKey, userConfig.take(specialKey)); + params.setBuildConfiguration(baseConfig); + params.setOverriddenValues(userConfig); qbs::ErrorInfo err = params.expandBuildConfiguration(m_manager->settings()); if (err.hasError()) { generateErrors(err); @@ -423,7 +430,7 @@ void QbsProject::parse(const QVariantMap &config, const Environment &env, const const qbs::Project ¤tProject = qbsProject(); if (!m_forceParsing && currentProject.isValid() - && currentProject.projectConfiguration() == params.buildConfiguration()) { + && currentProject.projectConfiguration() == params.finalBuildConfigurationTree()) { QHash<QString, QString> usedEnv = currentProject.usedEnvironment(); bool canSkip = true; for (QHash<QString, QString>::const_iterator i = usedEnv.constBegin(); diff --git a/src/plugins/qmldesigner/components/componentcore/tabviewdesigneraction.cpp b/src/plugins/qmldesigner/components/componentcore/tabviewdesigneraction.cpp index 9a04a2cec3..82411e6b98 100644 --- a/src/plugins/qmldesigner/components/componentcore/tabviewdesigneraction.cpp +++ b/src/plugins/qmldesigner/components/componentcore/tabviewdesigneraction.cpp @@ -151,7 +151,7 @@ void TabViewDesignerAction::addNewTab() QString newFilePath = directoryPath +QLatin1String("/") + tabName + QLatin1String(".qml"); if (QFileInfo(newFilePath).exists()) { - QMessageBox::warning(Core::ICore::mainWindow(), tr("Name Error"), tr("Component already exists.")); + QMessageBox::warning(Core::ICore::mainWindow(), tr("Naming Error"), tr("Component already exists.")); } else { bool fileCreated = createFile(newFilePath); diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index 2b7823ccbe..013b4a2f56 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -147,8 +147,8 @@ void DebugView::nodeIdChanged(const ModelNode &node, const QString &newId, const QString string; message.setString(&string); message << node; - message << tr("New Id: ") << newId << lineBreak; - message << tr("Old Id: ") << oldId << lineBreak; + message << tr("New Id:") << ' ' << newId << lineBreak; + message << tr("Old Id:") << ' ' << oldId << lineBreak; log(tr("Node id changed:"), string); } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml index 793d7ea7f0..697d3a95a8 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsView.qml @@ -223,6 +223,7 @@ content position out of scope regarding the scrollbar. */ anchors.bottom: parent.bottom anchors.bottomMargin: 1 anchors.right: parent.right + anchors.rightMargin: 2 width: (itemsFlickable.contentHeight > itemsFlickable.height)? 11:0 Scrollbar { diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml index e5f29de94c..c112ffa50f 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/ItemsViewStyle.qml @@ -61,7 +61,7 @@ Item { property int textWidth: 95 property int textHeight: 15 - property int cellHorizontalMargin: 5 + property int cellHorizontalMargin: 4 property int cellVerticalSpacing: 7 property int cellVerticalMargin: 10 diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml index 33bc50fc80..23adc86abb 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/Scrollbar.qml @@ -39,11 +39,11 @@ Item { property variant flickable function scroll(delta) { - handle.y = Math.max(0, Math.min(scrollHeight, handle.y + delta)) + handle.y = Math.max(2, Math.min(scrollHeight, handle.y + delta)) } function reset() { - handle.y = 0 + handle.y = 2 } // internal @@ -62,8 +62,7 @@ Item { anchors.bottom: parent.bottom anchors.bottomMargin: 3 anchors.horizontalCenter: parent.horizontalCenter - width: 6 - radius: 3 + width: 10 color: style.scrollbarColor border.width: 1 border.color: style.scrollbarBorderColor @@ -77,7 +76,7 @@ Item { flickable.contentY / (flickable.contentHeight - flickable.height), 1) else - handle.y = 0 + handle.y = 2 handle.updateFlickable = true } @@ -109,6 +108,7 @@ Item { Item { id: handle + y: 2 anchors.left: parent.left anchors.right: parent.right @@ -125,27 +125,20 @@ Item { width: parent.height height: parent.width y: -height - 2 - x: -2 rotation: 90 transformOrigin: Item.BottomLeft border.color: style.scrollbarBorderColor border.width: 1 - radius: 3 - - gradient: Gradient { - GradientStop { position: 0.15; color: style.scrollbarGradientStartColor } - GradientStop { position: 0.78; color: style.scrollbarGradientMiddleColor } - GradientStop { position: 0.80; color: style.scrollbarGradientEndColor } - } + color: style.sectionTitleBackgroundColor } MouseArea { anchors.fill: parent drag.target: parent drag.axis: "YAxis" - drag.minimumY: 0 + drag.minimumY: 2 drag.maximumY: scrollHeight } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml b/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml index 5a43d7de75..bfc324ebe4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml +++ b/src/plugins/qmldesigner/components/itemlibrary/qml/SectionView.qml @@ -28,6 +28,7 @@ ****************************************************************************/ import QtQuick 2.1 +import QtQuick.Controls 1.0 as Controls // view displaying one item library section including its grid @@ -114,12 +115,27 @@ Column { width: parent.width height: style.sectionTitleHeight - color: style.sectionTitleBackgroundColor + gradient: Gradient { + GradientStop {color: '#555' ; position: 0} + GradientStop {color: '#444' ; position: 1} + } + + Rectangle { + color:"#333" + width: parent.width + height: 1 + } + + Rectangle { + color: "#333" + anchors.bottom: parent.bottom + width: parent.width + height: 1 + } Item { id: arrow - Rectangle { y: 0; x: 0; height: 1; width: 11; color: style.sectionArrowColor } Rectangle { y: 1; x: 1; height: 1; width: 9; color: style.sectionArrowColor } Rectangle { y: 2; x: 2; height: 1; width: 7; color: style.sectionArrowColor } Rectangle { y: 3; x: 3; height: 1; width: 5; color: style.sectionArrowColor } @@ -127,25 +143,26 @@ Column { Rectangle { y: 5; x: 5; height: 1; width: 1; color: style.sectionArrowColor } anchors.left: parent.left - anchors.leftMargin: 10 + anchors.leftMargin: 4 anchors.verticalCenter: parent.verticalCenter width: 11 height: 6 transformOrigin: Item.Center } - Text { + Controls.Label { id: text anchors.verticalCenter: parent.verticalCenter anchors.left: arrow.right - anchors.leftMargin: 12 + anchors.leftMargin: 4 text: sectionName // to be set by model color: style.sectionTitleTextColor elide: Text.ElideMiddle font.bold: true - renderType: Text.NativeRendering + style: Text.Sunken + styleColor: "#292929" } MouseArea { id: mouseArea @@ -161,6 +178,9 @@ Column { Item { id: gridFrame + Behavior on opacity { NumberAnimation{easing.type: Easing.Linear ; duration: 80} } + Behavior on height { NumberAnimation{easing.type: Easing.OutCubic ; duration: 140} } + function toggleExpanded() { state = ((state == "")? "shrunk":"") diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 05b2511778..67376a966b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -44,9 +44,7 @@ #include <qmljs/qmljssimplereader.h> -#ifdef Q_OS_WIN -#include <utils/winutils.h> -#endif +#include <utils/fileutils.h> enum { debug = false @@ -95,12 +93,8 @@ static QObject *variantToQObject(const QVariant &value) static QString applicationDirPath() { -#ifdef Q_OS_WIN // normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows - return Utils::normalizePathName(QCoreApplication::applicationDirPath()); -#else - return QCoreApplication::applicationDirPath(); -#endif + return Utils::FileUtils::normalizePathName(QCoreApplication::applicationDirPath()); } #ifdef Q_OS_MAC diff --git a/src/plugins/qmldesigner/components/resources/scrollbar.css b/src/plugins/qmldesigner/components/resources/scrollbar.css index 34e8af8acb..661c987cb9 100644 --- a/src/plugins/qmldesigner/components/resources/scrollbar.css +++ b/src/plugins/qmldesigner/components/resources/scrollbar.css @@ -1,26 +1,21 @@ QScrollBar:vertical { - border-image: url(:/qmldesigner/images/scrollbar-borderimage-vertical.png); - border-left: 0; - border-right: 0; - border-top: 3; - border-bottom: 3; + background-color: #444444; + border: 1px solid #333333; margin-top: 3; margin-bottom: 3; width: 10; } QScrollBar::handle:vertical { - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, - stop: 0.20 #888888, - stop: 0.23 #656565, - stop: 0.85 #393939); + background-color: #656565; margin-top: -5; margin-bottom: -5; min-height: 18px; width: 8px; border: 1px solid #313131; - border-radius: 4px; border-width: 1; + margin-left: -1; + margin-right: -1; } QScrollBar::add-line:vertical { @@ -49,28 +44,24 @@ } QScrollBar:horizontal { - border-image: url(:/qmldesigner/images/scrollbar-borderimage-horizontal.png); - border-left: 3; - border-right: 3; - border-top: 0; - border-bottom: 0; + background-color: #444444; + border: 1px solid #333333; margin-left: 3; margin-right: 3; height: 10; } QScrollBar::handle:horizontal { - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0.20 #888888, - stop: 0.23 #656565, - stop: 0.85 #393939); + background-color: #656565; + margin-left: -5; margin-right: -5; min-width: 18px; height: 8px; border: 1px solid #313131; - border-radius: 4px; border-width: 1; + margin-top: -1; + margin-bottom: -1; } QScrollBar::add-line:horizontal { diff --git a/src/plugins/qmldesigner/components/stateseditor/HorizontalScrollBar.qml b/src/plugins/qmldesigner/components/stateseditor/HorizontalScrollBar.qml index a1077e7ead..08479b6a70 100644 --- a/src/plugins/qmldesigner/components/stateseditor/HorizontalScrollBar.qml +++ b/src/plugins/qmldesigner/components/stateseditor/HorizontalScrollBar.qml @@ -55,9 +55,8 @@ Item { Rectangle { id: groove width: parent.width - 4 - height: 6 + height: 10 color: "#444444" - radius: 3 border.width: 1 border.color: "#333333" anchors.right: parent.right @@ -95,13 +94,8 @@ Item { y:0 border.color: "#333333" border.width: 1 - radius: 3 - gradient: Gradient { - GradientStop { position: 0.20; color: "#888888" } - GradientStop { position: 0.23; color: "#656565" } - GradientStop { position: 0.85; color: "#393939" } - } + color: "#656565" MouseArea { property int dragging:0; diff --git a/src/plugins/qmldesigner/componentsplugin/Controls/ButtonSpecifics.qml b/src/plugins/qmldesigner/componentsplugin/Controls/ButtonSpecifics.qml index 4633c06fc3..f02154a92a 100644 --- a/src/plugins/qmldesigner/componentsplugin/Controls/ButtonSpecifics.qml +++ b/src/plugins/qmldesigner/componentsplugin/Controls/ButtonSpecifics.qml @@ -135,7 +135,7 @@ Column { Label { text: qsTr("Focus on press") - toolTip: "Determines whether the check box gets focus if pressed." + toolTip: "Determines whether the button gets focus if pressed." } SecondColumnLayout { diff --git a/src/plugins/qmldesigner/componentsplugin/Controls/CheckBoxSpecifics.qml b/src/plugins/qmldesigner/componentsplugin/Controls/CheckBoxSpecifics.qml index 7ec2cfd91d..6384c65e01 100644 --- a/src/plugins/qmldesigner/componentsplugin/Controls/CheckBoxSpecifics.qml +++ b/src/plugins/qmldesigner/componentsplugin/Controls/CheckBoxSpecifics.qml @@ -44,7 +44,7 @@ Column { Label { text: qsTr("Text") - toolTip: qsTr("The text shown on the check button") + toolTip: qsTr("The text shown on the check box") } SecondColumnLayout { @@ -59,7 +59,7 @@ Column { Label { text: qsTr("Checked") - toolTip: qsTr("The state of the check button") + toolTip: qsTr("The state of the check box") } SecondColumnLayout { @@ -75,7 +75,7 @@ Column { Label { text: qsTr("Focus on press") - toolTip: "Determines whether the check box gets focus if pressed." + toolTip: qsTr("Determines whether the check box gets focus if pressed.") } SecondColumnLayout { diff --git a/src/plugins/qmldesigner/componentsplugin/Controls/TextAreaSpecifics.qml b/src/plugins/qmldesigner/componentsplugin/Controls/TextAreaSpecifics.qml index 9bd9a5c56c..7c031333ee 100644 --- a/src/plugins/qmldesigner/componentsplugin/Controls/TextAreaSpecifics.qml +++ b/src/plugins/qmldesigner/componentsplugin/Controls/TextAreaSpecifics.qml @@ -58,7 +58,7 @@ Column { Label { text: qsTr("Text") - toolTip: qsTr("The text shown on the button") + toolTip: qsTr("The text shown on the text area") } SecondColumnLayout { @@ -73,7 +73,7 @@ Column { Label { text: qsTr("Read only") - toolTip: qsTr("Determines whether the text field is read only.") + toolTip: qsTr("Determines whether the text area is read only.") } SecondColumnLayout { diff --git a/src/plugins/qmldesigner/componentsplugin/Controls/TextFieldSpecifics.qml b/src/plugins/qmldesigner/componentsplugin/Controls/TextFieldSpecifics.qml index 7bad915625..4967a34021 100644 --- a/src/plugins/qmldesigner/componentsplugin/Controls/TextFieldSpecifics.qml +++ b/src/plugins/qmldesigner/componentsplugin/Controls/TextFieldSpecifics.qml @@ -44,7 +44,7 @@ Column { Label { text: qsTr("Text") - toolTip: qsTr("The text shown on the button") + toolTip: qsTr("The text shown on the text field") } SecondColumnLayout { diff --git a/src/plugins/qmlprofiler/qmlprofilereventview.cpp b/src/plugins/qmlprofiler/qmlprofilereventview.cpp index 01d8504510..6790478a52 100644 --- a/src/plugins/qmlprofiler/qmlprofilereventview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilereventview.cpp @@ -524,7 +524,7 @@ void QmlProfilerEventsMainView::parseModelProxy() QString toolTipText; if (event.eventType == Binding) { if (event.bindingType == (int)OptimizedBinding) { - typeString = typeString + tr(" (Opt)"); + typeString = typeString + QLatin1Char(' ') + tr("(Opt)"); toolTipText = tr("Binding is evaluated by the optimized engine."); } else if (event.bindingType == (int)V8Binding) { toolTipText = tr("Binding not optimized (e.g. has side effects or assignments,\n" diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index f133d802b9..2d17f24d5b 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -37,11 +37,13 @@ #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/icore.h> #include <projectexplorer/target.h> -#include <utils/qtcprocess.h> #include <qtsupport/qtkitinformation.h> #include <qtsupport/qtoutputformatter.h> #include <qtsupport/qtsupportconstants.h> +#include <utils/fileutils.h> +#include <utils/qtcprocess.h> + #ifdef Q_OS_WIN #include <utils/winutils.h> #endif @@ -159,13 +161,7 @@ QString QmlProjectRunConfiguration::workingDirectory() const is exactly like the capitalization on disk.*/ QString QmlProjectRunConfiguration::canonicalCapsPath(const QString &fileName) { - QString canonicalPath = QFileInfo(fileName).canonicalFilePath(); - -#if defined(Q_OS_WIN) - canonicalPath = Utils::normalizePathName(canonicalPath); -#endif - - return canonicalPath; + return Utils::FileUtils::normalizePathName(QFileInfo(fileName).canonicalFilePath()); } diff --git a/src/plugins/qnx/blackberryapplicationrunner.cpp b/src/plugins/qnx/blackberryapplicationrunner.cpp index 7e2ed84025..8178f2b3af 100644 --- a/src/plugins/qnx/blackberryapplicationrunner.cpp +++ b/src/plugins/qnx/blackberryapplicationrunner.cpp @@ -32,6 +32,7 @@ #include "blackberryapplicationrunner.h" #include "blackberrydeployconfiguration.h" +#include "blackberrydeviceconnectionmanager.h" #include "blackberryrunconfiguration.h" #include "blackberrylogprocessrunner.h" #include "qnxconstants.h" @@ -94,28 +95,17 @@ BlackBerryApplicationRunner::BlackBerryApplicationRunner(bool debugMode, BlackBe void BlackBerryApplicationRunner::start() { - QStringList args; - args << QLatin1String("-launchApp"); - if (m_debugMode) - args << QLatin1String("-debugNative"); - args << QLatin1String("-device") << m_sshParams.host; - if (!m_sshParams.password.isEmpty()) - args << QLatin1String("-password") << m_sshParams.password; - args << QDir::toNativeSeparators(m_barPackage); - - if (!m_launchProcess) { - m_launchProcess = new QProcess(this); - connect(m_launchProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError())); - connect(m_launchProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput())); - connect(m_launchProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(startFinished(int,QProcess::ExitStatus))); - - m_launchProcess->setEnvironment(m_environment.toStringList()); + if (!BlackBerryDeviceConnectionManager::instance()->isConnected(m_device->id())) { + connect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(deviceConnected()), + this, SLOT(launchApplication())); + connect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(deviceDisconnected(Core::Id)), + this, SLOT(disconnectFromDeviceSignals(Core::Id))); + connect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(connectionOutput(Core::Id,QString)), + this, SLOT(displayConnectionOutput(Core::Id,QString))); + BlackBerryDeviceConnectionManager::instance()->connectDevice(m_device->id()); + } else { + launchApplication(); } - - m_launchProcess->start(m_deployCmd, args); - m_runningStateTimer->start(); - m_running = true; } void BlackBerryApplicationRunner::startLogProcessRunner() @@ -130,6 +120,17 @@ void BlackBerryApplicationRunner::startLogProcessRunner() m_logProcessRunner->start(); } +void BlackBerryApplicationRunner::displayConnectionOutput(Core::Id deviceId, const QString &msg) +{ + if (deviceId != m_device->id()) + return; + + if (msg.contains(QLatin1String("Info:"))) + emit output(msg, Utils::StdOutFormat); + else if (msg.contains(QLatin1String("Error:"))) + emit output(msg, Utils::StdErrFormat); +} + void BlackBerryApplicationRunner::startFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode == 0 && exitStatus == QProcess::NormalExit && m_pid > -1) { @@ -214,6 +215,18 @@ void BlackBerryApplicationRunner::readStandardError() } } +void BlackBerryApplicationRunner::disconnectFromDeviceSignals(Core::Id deviceId) +{ + if (m_device->id() == deviceId) { + disconnect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(deviceConnected()), + this, SLOT(launchApplication())); + disconnect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(deviceDisconnected(Core::Id)), + this, SLOT(disconnectFromDeviceSignals(Core::Id))); + disconnect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(connectionOutput(Core::Id,QString)), + this, SLOT(displayConnectionOutput(Core::Id,QString))); + } +} + void BlackBerryApplicationRunner::setPid(qint64 pid) { m_pid = pid; @@ -224,6 +237,37 @@ void BlackBerryApplicationRunner::setApplicationId(const QString &applicationId) m_appId = applicationId; } +void BlackBerryApplicationRunner::launchApplication() +{ + // If original device connection fails before launching, this method maybe triggered + // if any other device is connected(?) + if (!BlackBerryDeviceConnectionManager::instance()->isConnected(m_device->id())) + return; + + QStringList args; + args << QLatin1String("-launchApp"); + if (m_debugMode) + args << QLatin1String("-debugNative"); + args << QLatin1String("-device") << m_sshParams.host; + if (!m_sshParams.password.isEmpty()) + args << QLatin1String("-password") << m_sshParams.password; + args << QDir::toNativeSeparators(m_barPackage); + + if (!m_launchProcess) { + m_launchProcess = new QProcess(this); + connect(m_launchProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError())); + connect(m_launchProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput())); + connect(m_launchProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(startFinished(int,QProcess::ExitStatus))); + + m_launchProcess->setEnvironment(m_environment.toStringList()); + } + + m_launchProcess->start(m_deployCmd, args); + m_runningStateTimer->start(); + m_running = true; +} + void BlackBerryApplicationRunner::startRunningStateTimer() { if (m_running) diff --git a/src/plugins/qnx/blackberryapplicationrunner.h b/src/plugins/qnx/blackberryapplicationrunner.h index 9f257066d4..3ba06a4785 100644 --- a/src/plugins/qnx/blackberryapplicationrunner.h +++ b/src/plugins/qnx/blackberryapplicationrunner.h @@ -82,6 +82,7 @@ private slots: void readStandardOutput(); void readStandardError(); + void disconnectFromDeviceSignals(Core::Id deviceId); void startRunningStateTimer(); void determineRunningState(); void readRunningStateStandardOutput(); @@ -89,8 +90,11 @@ private slots: void setPid(qint64 pid); void setApplicationId(const QString &applicationId); + void launchApplication(); void startLogProcessRunner(); + void displayConnectionOutput(Core::Id deviceId, const QString &output); + private: void reset(); diff --git a/src/plugins/qnx/blackberryconfiguration.cpp b/src/plugins/qnx/blackberryconfiguration.cpp index 78b01a30d8..cc45468e53 100644 --- a/src/plugins/qnx/blackberryconfiguration.cpp +++ b/src/plugins/qnx/blackberryconfiguration.cpp @@ -45,6 +45,7 @@ #include <qt4projectmanager/qmakekitinformation.h> +#include <debugger/debuggeritemmanager.h> #include <debugger/debuggerkitinformation.h> #include <QFileInfo> diff --git a/src/plugins/qnx/blackberrydebugsupport.cpp b/src/plugins/qnx/blackberrydebugsupport.cpp index e0ae83c181..cbd48c5b4f 100644 --- a/src/plugins/qnx/blackberrydebugsupport.cpp +++ b/src/plugins/qnx/blackberrydebugsupport.cpp @@ -51,8 +51,8 @@ BlackBerryDebugSupport::BlackBerryDebugSupport(BlackBerryRunConfiguration *runCo this, SLOT(handleDebuggerStateChanged(Debugger::DebuggerState))); connect(m_runner, SIGNAL(started()), this, SLOT(handleStarted())); - connect(m_runner, SIGNAL(started()), m_runner, SLOT(checkSlog2Info())); connect(m_runner, SIGNAL(startFailed(QString)), this, SLOT(handleStartFailed(QString))); + connect(m_runner, SIGNAL(started()), m_runner, SLOT(checkSlog2Info())); connect(m_runner, SIGNAL(output(QString,Utils::OutputFormat)), this, SLOT(handleApplicationOutput(QString,Utils::OutputFormat))); diff --git a/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp b/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp index d4011d246b..37d8a199e2 100644 --- a/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp +++ b/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp @@ -191,7 +191,7 @@ void BlackBerryDebugTokenRequestDialog::expandPath() void BlackBerryDebugTokenRequestDialog::debugTokenArrived(int status) { - QString errorString = tr("Failed to request debug token: "); + QString errorString = tr("Failed to request debug token:") + QLatin1Char(' '); switch (status) { case BlackBerryDebugTokenRequester::Success: diff --git a/src/plugins/qnx/blackberrydeviceconfigurationwidget.cpp b/src/plugins/qnx/blackberrydeviceconfigurationwidget.cpp index 76c02a3303..cb762f41de 100644 --- a/src/plugins/qnx/blackberrydeviceconfigurationwidget.cpp +++ b/src/plugins/qnx/blackberrydeviceconfigurationwidget.cpp @@ -165,7 +165,7 @@ void BlackBerryDeviceConfigurationWidget::uploadFinished(int status) { progressDialog->hide(); - QString errorString = tr("Failed to upload debug token: "); + QString errorString = tr("Failed to upload debug token:") + QLatin1Char(' '); switch (status) { case BlackBerryDebugTokenUploader::Success: diff --git a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp index 342a2bd93f..96b4c48687 100644 --- a/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp +++ b/src/plugins/qnx/blackberrydeviceconfigurationwizardpages.cpp @@ -290,7 +290,8 @@ void BlackBerryDeviceConfigurationWizardQueryPage::sshKeysGenerationFailed(const if (m_state != GeneratingSshKey) return; - QString message = tr("Failed generating SSH key needed for securing connection to a device. Error: "); + QString message = tr("Failed generating SSH key needed for securing connection to a device. Error:"); + message += QLatin1Char(' '); message.append(error); setState(Done, message); } @@ -310,7 +311,8 @@ void BlackBerryDeviceConfigurationWizardQueryPage::processSshKeys(const QByteArr if (! BlackBerryDeviceConnectionManager::instance()->hasValidSSHKeys()) { QString error; if (!BlackBerryDeviceConnectionManager::instance()->setSSHKeys(privateKey, publicKey, &error)) { - QString message = tr("Failed saving SSH key needed for securing connection to a device. Error: "); + QString message = tr("Failed saving SSH key needed for securing connection to a device. Error:"); + message += QLatin1Char(' '); message.append(error); setState(Done, message); return; diff --git a/src/plugins/qnx/blackberrydeviceconnection.cpp b/src/plugins/qnx/blackberrydeviceconnection.cpp index 9b80986370..3db96567a5 100644 --- a/src/plugins/qnx/blackberrydeviceconnection.cpp +++ b/src/plugins/qnx/blackberrydeviceconnection.cpp @@ -62,8 +62,7 @@ BlackBerryDeviceConnection::BlackBerryDeviceConnection() : void BlackBerryDeviceConnection::connectDevice(const ProjectExplorer::IDevice::ConstPtr &device) { Utils::Environment env = Utils::Environment::systemEnvironment(); - foreach (const Utils::EnvironmentItem &item, BlackBerryConfigurationManager::instance().defaultQnxEnv()) - env.appendOrSet(item.name, item.value); + env.modify(BlackBerryConfigurationManager::instance().defaultQnxEnv()); m_process->setEnvironment(env.toStringList()); diff --git a/src/plugins/qnx/blackberrydeviceconnectionmanager.cpp b/src/plugins/qnx/blackberrydeviceconnectionmanager.cpp index fa549d70db..ad0c308295 100644 --- a/src/plugins/qnx/blackberrydeviceconnectionmanager.cpp +++ b/src/plugins/qnx/blackberrydeviceconnectionmanager.cpp @@ -278,9 +278,11 @@ void BlackBerryDeviceConnectionManager::handleDeviceDisconnected() QTC_ASSERT(connection, return); QList<Core::Id> disconnectedDevices = m_connections.values(connection); - foreach (Core::Id id, disconnectedDevices) + foreach (Core::Id id, disconnectedDevices) { ProjectExplorer::DeviceManager::instance()->setDeviceState(id, ProjectExplorer::IDevice::DeviceDisconnected); + emit deviceDisconnected(id); + } } void BlackBerryDeviceConnectionManager::handleDeviceAboutToConnect() diff --git a/src/plugins/qnx/blackberrydeviceconnectionmanager.h b/src/plugins/qnx/blackberrydeviceconnectionmanager.h index a211f505e9..b9a5e10909 100644 --- a/src/plugins/qnx/blackberrydeviceconnectionmanager.h +++ b/src/plugins/qnx/blackberrydeviceconnectionmanager.h @@ -69,6 +69,7 @@ signals: void connectionOutput(Core::Id deviceId, const QString &output); void deviceAboutToConnect(Core::Id deviceId); void deviceConnected(); + void deviceDisconnected(Core::Id deviceId); public slots: void connectDevice(Core::Id deviceId); diff --git a/src/plugins/qnx/blackberryruncontrol.cpp b/src/plugins/qnx/blackberryruncontrol.cpp index f372452bc7..564329fa57 100644 --- a/src/plugins/qnx/blackberryruncontrol.cpp +++ b/src/plugins/qnx/blackberryruncontrol.cpp @@ -34,8 +34,6 @@ #include "blackberryrunconfiguration.h" #include "blackberrydeviceconnectionmanager.h" -#include <projectexplorer/target.h> - #include <QIcon> #include <QTimer> @@ -45,7 +43,6 @@ using namespace Qnx::Internal; BlackBerryRunControl::BlackBerryRunControl(BlackBerryRunConfiguration *runConfiguration) : ProjectExplorer::RunControl(runConfiguration, ProjectExplorer::NormalRunMode) { - m_device = BlackBerryDeviceConfiguration::device(runConfiguration->target()->kit()); m_runner = new BlackBerryApplicationRunner(false, runConfiguration, this); connect(m_runner, SIGNAL(started()), this, SIGNAL(started())); @@ -57,7 +54,7 @@ BlackBerryRunControl::BlackBerryRunControl(BlackBerryRunConfiguration *runConfig void BlackBerryRunControl::start() { - checkDeviceConnection(); + m_runner->start(); } ProjectExplorer::RunControl::StopResult BlackBerryRunControl::stop() @@ -79,32 +76,3 @@ void BlackBerryRunControl::handleStartFailed(const QString &message) { appendMessage(message, Utils::StdErrFormat); } - -void BlackBerryRunControl::handleDeviceConnected() -{ - m_runner->start(); -} - -void BlackBerryRunControl::displayConnectionOutput(Core::Id deviceId, const QString &output) -{ - if (deviceId != m_device->id()) - return; - - if (output.contains(QLatin1String("Info:"))) - appendMessage(output, Utils::StdOutFormat); - else if (output.contains(QLatin1String("Error:"))) - appendMessage(output, Utils::StdErrFormat); -} - -void BlackBerryRunControl::checkDeviceConnection() -{ - if (!BlackBerryDeviceConnectionManager::instance()->isConnected(m_device->id())) { - connect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(deviceConnected()), - this, SLOT(handleDeviceConnected())); - connect(BlackBerryDeviceConnectionManager::instance(), SIGNAL(connectionOutput(Core::Id,QString)), - this, SLOT(displayConnectionOutput(Core::Id,QString))); - BlackBerryDeviceConnectionManager::instance()->connectDevice(m_device->id()); - } else { - m_runner->start(); - } -} diff --git a/src/plugins/qnx/blackberryruncontrol.h b/src/plugins/qnx/blackberryruncontrol.h index 787add054b..ab061407d0 100644 --- a/src/plugins/qnx/blackberryruncontrol.h +++ b/src/plugins/qnx/blackberryruncontrol.h @@ -32,8 +32,6 @@ #ifndef QNX_INTERNAL_BLACKBERRYRUNCONTROL_H #define QNX_INTERNAL_BLACKBERRYRUNCONTROL_H -#include "blackberrydeviceconfiguration.h" - #include <projectexplorer/runconfiguration.h> namespace QmakeProjectManager { @@ -60,13 +58,9 @@ public: private slots: void handleStartFailed(const QString &message); - void handleDeviceConnected(); - void displayConnectionOutput(Core::Id deviceId, const QString &output); - void checkDeviceConnection(); private: BlackBerryApplicationRunner *m_runner; - BlackBerryDeviceConfiguration::ConstPtr m_device; }; } // namespace Internal diff --git a/src/plugins/qnx/blackberrysetupwizard.cpp b/src/plugins/qnx/blackberrysetupwizard.cpp index 43cc73a7c0..e5214b0a0f 100644 --- a/src/plugins/qnx/blackberrysetupwizard.cpp +++ b/src/plugins/qnx/blackberrysetupwizard.cpp @@ -176,7 +176,7 @@ void BlackBerrySetupWizard::certificateCreated(int status) void BlackBerrySetupWizard::debugTokenArrived(int status) { - QString errorString = tr("Failed to request debug token: "); + QString errorString = tr("Failed to request debug token:") + QLatin1Char(' '); switch (status) { case BlackBerryDebugTokenRequester::Success: @@ -222,7 +222,7 @@ void BlackBerrySetupWizard::debugTokenArrived(int status) void BlackBerrySetupWizard::uploaderFinished(int status) { - QString errorString = tr("Failed to upload debug token: "); + QString errorString = tr("Failed to upload debug token:") + QLatin1Char(' '); switch (status) { case BlackBerryDebugTokenUploader::Success: diff --git a/src/plugins/qt4projectmanager/librarydetailscontroller.cpp b/src/plugins/qt4projectmanager/librarydetailscontroller.cpp index 7253684966..3f79461f3c 100644 --- a/src/plugins/qt4projectmanager/librarydetailscontroller.cpp +++ b/src/plugins/qt4projectmanager/librarydetailscontroller.cpp @@ -103,7 +103,6 @@ LibraryDetailsController::LibraryDetailsController( } } } - setPlatformsVisible(true); setLinkageGroupVisible(true); setMacLibraryGroupVisible(true); diff --git a/src/plugins/qt4projectmanager/qmakestep.cpp b/src/plugins/qt4projectmanager/qmakestep.cpp index 5331ece972..0980c48982 100644 --- a/src/plugins/qt4projectmanager/qmakestep.cpp +++ b/src/plugins/qt4projectmanager/qmakestep.cpp @@ -166,11 +166,6 @@ QStringList QMakeStep::deducedArguments() ProjectExplorer::Abi targetAbi; if (tc) targetAbi = tc->targetAbi(); - if ((HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost()) - && (targetAbi.osFlavor() == ProjectExplorer::Abi::HarmattanLinuxFlavor - || targetAbi.osFlavor() == ProjectExplorer::Abi::MaemoLinuxFlavor)) { - arguments << QLatin1String("-unix"); - } // explicitly add architecture to CONFIG if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) diff --git a/src/plugins/qt4projectmanager/wizards/qtquickapp.cpp b/src/plugins/qt4projectmanager/wizards/qtquickapp.cpp index b252083f89..5965088f25 100644 --- a/src/plugins/qt4projectmanager/wizards/qtquickapp.cpp +++ b/src/plugins/qt4projectmanager/wizards/qtquickapp.cpp @@ -29,6 +29,9 @@ #include "qtquickapp.h" +#include <utils/qtcassert.h> + +#include <QDebug> #include <QDir> #include <QFile> #include <QTextStream> @@ -113,15 +116,25 @@ QString QtQuickApp::originsRoot() const switch (m_componentSet) { case QtQuickControls10: return templatesRoot() + QLatin1String("qtquick2controls/"); case QtQuick20Components: return templatesRoot() + QLatin1String("qtquick2app/"); - default: break; + case QtQuick10Components: return templatesRoot() + QLatin1String("qtquick1app/"); } - return templatesRoot() + QLatin1String("qtquickapp/"); + qWarning() << "QtQuickApp::originsRoot() - unhandled component set" + << m_componentSet; + return QString(); } QString QtQuickApp::mainWindowClassName() const { - return QLatin1String("QmlApplicationViewer"); + switch (m_componentSet) { + case QtQuickControls10: return QLatin1String("QtQuick2ControlsApplicationViewer"); + case QtQuick20Components: return QLatin1String("QtQuick2ApplicationViewer"); + case QtQuick10Components: return QLatin1String("QtQuick1ApplicationViewer"); + } + + qWarning() << "QtQuickApp::mainWindowClassName() - unhandled component set" + << m_componentSet; + return QString(); } bool QtQuickApp::adaptCurrentMainCppTemplateLine(QString &line) const @@ -174,12 +187,15 @@ bool QtQuickApp::useExistingMainQml() const QString QtQuickApp::appViewerBaseName() const { - if (m_componentSet == QtQuick20Components) { - return QLatin1String("qtquick2applicationviewer"); - } else if (m_componentSet == QtQuickControls10) { - return QLatin1String("qtquick2controlsapplicationviewer"); + switch (m_componentSet) { + case QtQuickControls10: return QLatin1String("qtquick2controlsapplicationviewer"); + case QtQuick20Components: return QLatin1String("qtquick2applicationviewer"); + case QtQuick10Components: return QLatin1String("qtquick1applicationviewer"); } - return QLatin1String("qmlapplicationviewer"); + + qWarning() << "QtQuickApp::appViewerBaseName() - unhandled component set" + << m_componentSet; + return QString(); } QString QtQuickApp::fileName(QtQuickApp::ExtendedFileType type) const diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index ced6d1defe..7e08dc3493 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1475,16 +1475,6 @@ bool BaseQtVersion::isQmlDebuggingSupported(QString *reason) const if (!needsQmlDebuggingLibrary() || hasQmlDebuggingLibrary()) return true; - if (!qtAbis().isEmpty()) { - Abi abi = qtAbis().first(); - if (abi.osFlavor() == Abi::MaemoLinuxFlavor) { - if (reason) - reason->clear(); - // *reason = QCoreApplication::translate("BaseQtVersion", "Qml debugging on device not yet supported."); - return false; - } - } - if (!isValid()) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "Invalid Qt version."); diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index a514b0d3b0..54d4ea1123 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -241,11 +241,8 @@ QString ExamplesWelcomePage::title() const QUrl ExamplesWelcomePage::pageLocation() const { - QString resourcePath = Core::ICore::resourcePath(); -#ifdef Q_OS_WIN // normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows - resourcePath = Utils::normalizePathName(resourcePath); -#endif + const QString resourcePath = Utils::FileUtils::normalizePathName(Core::ICore::resourcePath()); if (m_showExamples) return QUrl::fromLocalFile(resourcePath + QLatin1String("/welcomescreen/examples.qml")); else diff --git a/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp b/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp index 015a2ea6d0..a4b26fef31 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfigurationfactory.cpp @@ -102,7 +102,7 @@ QList<Core::Id> RemoteLinuxRunConfigurationFactory::availableCreationIds(Target QString RemoteLinuxRunConfigurationFactory::displayNameForId(const Core::Id id) const { return QFileInfo(pathFromId(id)).completeBaseName() - + tr(" (on Remote Generic Linux Host)"); + + QLatin1Char(' ') + tr("(on Remote Generic Linux Host)"); } RunConfiguration *RemoteLinuxRunConfigurationFactory::doCreate(Target *parent, const Core::Id id) diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp index bdfb67a787..e3f96e2713 100644 --- a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp @@ -120,7 +120,8 @@ void RemoteLinuxSignalOperation::runnerProcessFinished() if (m_runner->processExitStatus() != QSsh::SshRemoteProcess::NormalExit) { m_errorMessage = m_runner->processErrorString(); } else if (m_runner->processExitCode() != 0) { - m_errorMessage = tr("Exit code is %1. stderr: ").arg(m_runner->processExitCode()) + m_errorMessage = tr("Exit code is %1. stderr:").arg(m_runner->processExitCode()) + + QLatin1Char(' ') + QString::fromLatin1(m_runner->readAllStandardError()); } finish(); diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index b21c709c21..044b2a328d 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -77,6 +77,13 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) d->m_codecs.append(codec); } + // Qt5 doesn't list the system locale (QTBUG-34283), so add it manually + const QString system(QLatin1String("System")); + if (d->m_ui.encodingBox->findText(system) == -1) { + d->m_ui.encodingBox->insertItem(0, system); + d->m_codecs.prepend(QTextCodec::codecForLocale()); + } + connect(d->m_ui.autoIndent, SIGNAL(toggled(bool)), this, SLOT(slotTypingSettingsChanged())); connect(d->m_ui.smartBackspaceBehavior, SIGNAL(currentIndexChanged(int)), diff --git a/src/plugins/valgrind/memcheck/memcheckrunner.cpp b/src/plugins/valgrind/memcheck/memcheckrunner.cpp index 6827f6b47d..91033203f6 100644 --- a/src/plugins/valgrind/memcheck/memcheckrunner.cpp +++ b/src/plugins/valgrind/memcheck/memcheckrunner.cpp @@ -168,14 +168,14 @@ bool MemcheckRunner::start() } bool check = d->xmlServer.listen(hostAddr); - if (!check) emit processErrorReceived( tr("XmlServer on %1: ").arg(ip) + d->xmlServer.errorString(), QProcess::FailedToStart ); + if (!check) emit processErrorReceived( tr("XmlServer on %1:").arg(ip) + QLatin1Char(' ') + d->xmlServer.errorString(), QProcess::FailedToStart ); QTC_ASSERT(check, return false); d->xmlServer.setMaxPendingConnections(1); const quint16 xmlPortNumber = d->xmlServer.serverPort(); connect(&d->xmlServer, SIGNAL(newConnection()), SLOT(xmlSocketConnected())); check = d->logServer.listen(hostAddr); - if (!check) emit processErrorReceived( tr("LogServer on %1: ").arg(ip) + d->logServer.errorString(), QProcess::FailedToStart ); + if (!check) emit processErrorReceived( tr("LogServer on %1:").arg(ip) + QLatin1Char(' ') + d->logServer.errorString(), QProcess::FailedToStart ); QTC_ASSERT(check, return false); d->logServer.setMaxPendingConnections(1); const quint16 logPortNumber = d->logServer.serverPort(); diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 202645a5d4..da1aa21fb3 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -40,6 +40,7 @@ #include <projectexplorer/projectexplorer.h> +#include <utils/fileutils.h> #include <utils/hostosinfo.h> #include <utils/styledbar.h> #include <utils/iwelcomepage.h> @@ -208,22 +209,14 @@ void WelcomeMode::facilitateQml(QQmlEngine * /*engine*/) static QString applicationDirPath() { -#ifdef Q_OS_WIN // normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows - return Utils::normalizePathName(QCoreApplication::applicationDirPath()); -#else - return QCoreApplication::applicationDirPath(); -#endif + return Utils::FileUtils::normalizePathName(QCoreApplication::applicationDirPath()); } static QString resourcePath() { -#ifdef Q_OS_WIN // normalize paths so QML doesn't freak out if it's wrongly capitalized on Windows - return Utils::normalizePathName(Core::ICore::resourcePath()); -#else - return Core::ICore::resourcePath(); -#endif + return Utils::FileUtils::normalizePathName(Core::ICore::resourcePath()); } void WelcomeMode::initPlugins() diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp index 90b131f313..f95755bbdd 100644 --- a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -134,7 +134,7 @@ void CrashHandlerDialog::setApplicationInfo(const QString &signalName) QString revision; #ifdef IDE_REVISION - revision = tr(" from revision %1").arg(QString::fromLatin1(Core::Constants::IDE_REVISION_STR).left(10)); + revision = QLatin1Char(' ') + tr("from revision %1").arg(QString::fromLatin1(Core::Constants::IDE_REVISION_STR).left(10)); #endif const QString versionInformation = tr( "%1 %2%3, built on %4 at %5, based on Qt %6 (%7 bit)\n") |