diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 0c59fa470baacdc392dd2003e5b6204c71152b62..c6d669952566589f609e75891b6757c075281fbc 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -40,6 +40,7 @@ #include <coreplugin/icore.h> #include <coreplugin/manhattanstyle.h> +#include <utils/qtcassert.h> #include <projectexplorer/projectexplorer.h> @@ -53,13 +54,90 @@ using namespace ProjectExplorer; namespace Debugger { namespace Internal { +CommonOptionsPageWidget::CommonOptionsPageWidget(const QSharedPointer<Utils::SavedActionSet> &group, QWidget *parent) : + QWidget(parent), m_group(group) +{ + m_ui.setupUi(this); + m_group->clear(); + + m_group->insert(debuggerCore()->action(ListSourceFiles), + m_ui.checkBoxListSourceFiles); + m_group->insert(debuggerCore()->action(UseAlternatingRowColors), + m_ui.checkBoxUseAlternatingRowColors); + m_group->insert(debuggerCore()->action(UseToolTipsInMainEditor), + m_ui.checkBoxUseToolTipsInMainEditor); + m_group->insert(debuggerCore()->action(CloseBuffersOnExit), + m_ui.checkBoxCloseBuffersOnExit); + m_group->insert(debuggerCore()->action(SwitchModeOnExit), + m_ui.checkBoxSwitchModeOnExit); + m_group->insert(debuggerCore()->action(AutoDerefPointers), 0); + m_group->insert(debuggerCore()->action(UseToolTipsInLocalsView), 0); + m_group->insert(debuggerCore()->action(UseToolTipsInBreakpointsView), 0); + m_group->insert(debuggerCore()->action(UseAddressInBreakpointsView), 0); + m_group->insert(debuggerCore()->action(UseAddressInStackView), 0); + m_group->insert(debuggerCore()->action(MaximalStackDepth), + m_ui.spinBoxMaximalStackDepth); + m_group->insert(debuggerCore()->action(ShowStdNamespace), 0); + m_group->insert(debuggerCore()->action(ShowQtNamespace), 0); + m_group->insert(debuggerCore()->action(SortStructMembers), 0); + m_group->insert(debuggerCore()->action(LogTimeStamps), 0); + m_group->insert(debuggerCore()->action(VerboseLog), 0); + m_group->insert(debuggerCore()->action(BreakOnThrow), 0); + m_group->insert(debuggerCore()->action(BreakOnCatch), 0); +#ifdef Q_OS_WIN + Utils::SavedAction *registerAction = debuggerCore()->action(RegisterForPostMortem); + m_group->insert(registerAction, + m_ui.checkBoxRegisterForPostMortem); + connect(registerAction, SIGNAL(toggled(bool)), + m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool))); +#else + m_ui.checkBoxRegisterForPostMortem->setVisible(false); +#endif +} + +QString CommonOptionsPageWidget::searchKeyWords() const +{ + QString rc; + const QLatin1Char sep(' '); + QTextStream(&rc) + << sep << m_ui.checkBoxUseAlternatingRowColors->text() + << sep << m_ui.checkBoxUseToolTipsInMainEditor->text() + << sep << m_ui.checkBoxListSourceFiles->text() +#ifdef Q_OS_WIN + << sep << m_ui.checkBoxRegisterForPostMortem->text() +#endif + << sep << m_ui.checkBoxCloseBuffersOnExit->text() + << sep << m_ui.checkBoxSwitchModeOnExit->text() + << sep << m_ui.labelMaximalStackDepth->text() + ; + rc.remove(QLatin1Char('&')); + return rc; +} + +GlobalDebuggerOptions CommonOptionsPageWidget::globalOptions() const +{ + GlobalDebuggerOptions o; + o.sourcePathMap = m_ui.sourcesMappingWidget->sourcePathMap(); + return o; +} + +void CommonOptionsPageWidget::setGlobalOptions(const GlobalDebuggerOptions &go) +{ + m_ui.sourcesMappingWidget->setSourcePathMap(go.sourcePathMap); +} + /////////////////////////////////////////////////////////////////////// // // CommonOptionsPage // /////////////////////////////////////////////////////////////////////// -CommonOptionsPage::CommonOptionsPage() +CommonOptionsPage::CommonOptionsPage(const QSharedPointer<GlobalDebuggerOptions> &go) : + m_options(go) +{ +} + +CommonOptionsPage::~CommonOptionsPage() { } @@ -88,73 +166,33 @@ QIcon CommonOptionsPage::categoryIcon() const void CommonOptionsPage::apply() { - m_group.apply(ICore::instance()->settings()); + QTC_ASSERT(!m_widget.isNull() && !m_group.isNull(), return; ) + + QSettings *settings = ICore::instance()->settings(); + m_group->apply(settings); + + const GlobalDebuggerOptions newGlobalOptions = m_widget->globalOptions(); + if (newGlobalOptions != *m_options) { + *m_options = newGlobalOptions; + m_options->toSettings(settings); + } } void CommonOptionsPage::finish() { - m_group.finish(); + QTC_ASSERT(!m_group.isNull(), return; ) + m_group->finish(); } QWidget *CommonOptionsPage::createPage(QWidget *parent) { - QWidget *w = new QWidget(parent); - m_ui.setupUi(w); - m_group.clear(); - - m_group.insert(debuggerCore()->action(ListSourceFiles), - m_ui.checkBoxListSourceFiles); - m_group.insert(debuggerCore()->action(UseAlternatingRowColors), - m_ui.checkBoxUseAlternatingRowColors); - m_group.insert(debuggerCore()->action(UseToolTipsInMainEditor), - m_ui.checkBoxUseToolTipsInMainEditor); - m_group.insert(debuggerCore()->action(CloseBuffersOnExit), - m_ui.checkBoxCloseBuffersOnExit); - m_group.insert(debuggerCore()->action(SwitchModeOnExit), - m_ui.checkBoxSwitchModeOnExit); - m_group.insert(debuggerCore()->action(AutoDerefPointers), 0); - m_group.insert(debuggerCore()->action(UseToolTipsInLocalsView), 0); - m_group.insert(debuggerCore()->action(UseToolTipsInBreakpointsView), 0); - m_group.insert(debuggerCore()->action(UseAddressInBreakpointsView), 0); - m_group.insert(debuggerCore()->action(UseAddressInStackView), 0); - m_group.insert(debuggerCore()->action(MaximalStackDepth), - m_ui.spinBoxMaximalStackDepth); - m_group.insert(debuggerCore()->action(ShowStdNamespace), 0); - m_group.insert(debuggerCore()->action(ShowQtNamespace), 0); - m_group.insert(debuggerCore()->action(SortStructMembers), 0); - m_group.insert(debuggerCore()->action(LogTimeStamps), 0); - m_group.insert(debuggerCore()->action(VerboseLog), 0); - m_group.insert(debuggerCore()->action(BreakOnThrow), 0); - m_group.insert(debuggerCore()->action(BreakOnCatch), 0); - m_group.insert(debuggerCore()->action(QtSourcesLocation), - m_ui.qtSourcesChooser); -#ifdef Q_OS_WIN - Utils::SavedAction *registerAction = debuggerCore()->action(RegisterForPostMortem); - m_group.insert(registerAction, - m_ui.checkBoxRegisterForPostMortem); - connect(registerAction, SIGNAL(toggled(bool)), - m_ui.checkBoxRegisterForPostMortem, SLOT(setChecked(bool))); -#endif - - if (m_searchKeywords.isEmpty()) { - QLatin1Char sep(' '); - QTextStream(&m_searchKeywords) - << sep << m_ui.checkBoxUseAlternatingRowColors->text() - << sep << m_ui.checkBoxUseToolTipsInMainEditor->text() - << sep << m_ui.checkBoxListSourceFiles->text() -#ifdef Q_OS_WIN - << sep << m_ui.checkBoxRegisterForPostMortem->text() -#endif - << sep << m_ui.checkBoxCloseBuffersOnExit->text() - << sep << m_ui.checkBoxSwitchModeOnExit->text() - << sep << m_ui.labelMaximalStackDepth->text() - ; - m_searchKeywords.remove(QLatin1Char('&')); - } -#ifndef Q_OS_WIN - m_ui.checkBoxRegisterForPostMortem->setVisible(false); -#endif - return w; + if (m_group.isNull()) + m_group = QSharedPointer<Utils::SavedActionSet>(new Utils::SavedActionSet); + m_widget = new CommonOptionsPageWidget(m_group, parent); + m_widget->setGlobalOptions(*m_options); + if (m_searchKeywords.isEmpty()) + m_searchKeywords = m_widget->searchKeyWords(); + return m_widget; } bool CommonOptionsPage::matches(const QString &s) const diff --git a/src/plugins/debugger/commonoptionspage.h b/src/plugins/debugger/commonoptionspage.h index 491d3a71ae6ec11779447176b302f272a7bfb3f9..65c17cafb1b33f012b36ca2b6dfe5ff89697908d 100644 --- a/src/plugins/debugger/commonoptionspage.h +++ b/src/plugins/debugger/commonoptionspage.h @@ -40,8 +40,13 @@ #include <coreplugin/dialogs/ioptionspage.h> #include <utils/savedaction.h> +#include <QtCore/QSharedPointer> +#include <QtCore/QPointer> +#include <QtGui/QWidget> + namespace Debugger { namespace Internal { +class GlobalDebuggerOptions; /////////////////////////////////////////////////////////////////////// // @@ -49,12 +54,27 @@ namespace Internal { // /////////////////////////////////////////////////////////////////////// +class CommonOptionsPageWidget : public QWidget +{ +public: + explicit CommonOptionsPageWidget(const QSharedPointer<Utils::SavedActionSet> &group, QWidget *parent = 0); + + QString searchKeyWords() const; + GlobalDebuggerOptions globalOptions() const; + void setGlobalOptions(const GlobalDebuggerOptions &go); + +private: + Ui::CommonOptionsPage m_ui; + const QSharedPointer<Utils::SavedActionSet> m_group; +}; + class CommonOptionsPage : public Core::IOptionsPage { Q_OBJECT public: - CommonOptionsPage(); + explicit CommonOptionsPage(const QSharedPointer<GlobalDebuggerOptions> &go); + virtual ~CommonOptionsPage(); // IOptionsPage QString id() const; @@ -68,10 +88,10 @@ public: bool matches(const QString &s) const; private: - typedef QMap<QString, QString> AbiToDebuggerMap; - Ui::CommonOptionsPage m_ui; - Utils::SavedActionSet m_group; + const QSharedPointer<GlobalDebuggerOptions> m_options; + QSharedPointer<Utils::SavedActionSet> m_group; QString m_searchKeywords; + QPointer<CommonOptionsPageWidget> m_widget; }; diff --git a/src/plugins/debugger/commonoptionspage.ui b/src/plugins/debugger/commonoptionspage.ui index 8fb49070122426c6d2a43e299f248c213eb07659..38547eb8a2fbfef8d235fe574a7dea6fce0b25ac 100644 --- a/src/plugins/debugger/commonoptionspage.ui +++ b/src/plugins/debugger/commonoptionspage.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>361</width> + <width>387</width> <height>334</height> </rect> </property> @@ -130,30 +130,7 @@ </widget> </item> <item> - <widget class="QGroupBox" name="sourcesBox"> - <property name="title"> - <string>Sources</string> - </property> - <layout class="QGridLayout" name="sourcesGridLayout"> - <item row="7" column="0"> - <widget class="QLabel" name="labelQtSources"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Qt Sources:</string> - </property> - </widget> - </item> - <item row="7" column="1"> - <widget class="Utils::PathChooser" name="qtSourcesChooser" native="true"> - </widget> - </item> - </layout> - </widget> + <widget class="Debugger::Internal::DebuggerSourcePathMappingWidget" name="sourcesMappingWidget"/> </item> <item> <spacer name="verticalSpacer"> @@ -175,9 +152,10 @@ </widget> <customwidgets> <customwidget> - <class>Utils::PathChooser</class> - <extends>QWidget</extends> - <header location="global">utils/pathchooser.h</header> + <class>Debugger::Internal::DebuggerSourcePathMappingWidget</class> + <extends>QGroupBox</extends> + <header>debuggersourcepathmappingwidget.h</header> + <container>1</container> </customwidget> </customwidgets> <resources/> diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 79a97ee6766568567f2ce8ae086d71e0cc2d4284..99c98c0d708cd7daa75563885f7181f38f914f95 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -62,7 +62,8 @@ HEADERS += breakhandler.h \ watchdelegatewidgets.h \ debuggerruncontrolfactory.h \ debuggertooltipmanager.h \ - debuggertoolchaincombobox.h + debuggertoolchaincombobox.h \ + debuggersourcepathmappingwidget.h SOURCES += breakhandler.cpp \ breakpoint.cpp \ @@ -104,7 +105,8 @@ SOURCES += breakhandler.cpp \ stackframe.cpp \ watchdelegatewidgets.cpp \ debuggertooltipmanager.cpp \ - debuggertoolchaincombobox.cpp + debuggertoolchaincombobox.cpp \ + debuggersourcepathmappingwidget.cpp FORMS += attachexternaldialog.ui \ attachcoredialog.ui \ diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index cd0a1a68d74f6f91a7e0f85088bc9d2f04f52f7e..1818ed4403cd88d02edf60e7695dfc7eb174875d 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -47,10 +47,45 @@ using namespace Utils; static const char debugModeSettingsGroupC[] = "DebugMode"; +static const char sourcePathMappingArrayNameC[] = "SourcePathMappings"; +static const char sourcePathMappingSourceKeyC[] = "Source"; +static const char sourcePathMappingTargetKeyC[] = "Target"; namespace Debugger { namespace Internal { +void GlobalDebuggerOptions::toSettings(QSettings *s) const +{ + s->beginWriteArray(QLatin1String(sourcePathMappingArrayNameC)); + if (!sourcePathMap.isEmpty()) { + const QString sourcePathMappingSourceKey = QLatin1String(sourcePathMappingSourceKeyC); + const QString sourcePathMappingTargetKey = QLatin1String(sourcePathMappingTargetKeyC); + int i = 0; + const SourcePathMap::const_iterator cend = sourcePathMap.constEnd(); + for (SourcePathMap::const_iterator it = sourcePathMap.constBegin(); it != cend; ++it, ++i) { + s->setArrayIndex(i); + s->setValue(sourcePathMappingSourceKey, it.key()); + s->setValue(sourcePathMappingTargetKey, it.value()); + } + } + s->endArray(); +} + +void GlobalDebuggerOptions::fromSettings(QSettings *s) +{ + sourcePathMap.clear(); + if (const int count = s->beginReadArray(QLatin1String(sourcePathMappingArrayNameC))) { + const QString sourcePathMappingSourceKey = QLatin1String(sourcePathMappingSourceKeyC); + const QString sourcePathMappingTargetKey = QLatin1String(sourcePathMappingTargetKeyC); + for (int i = 0; i < count; ++i) { + s->setArrayIndex(i); + sourcePathMap.insert(s->value(sourcePathMappingSourceKey).toString(), + s->value(sourcePathMappingTargetKey).toString()); + } + } + s->endArray(); +} + ////////////////////////////////////////////////////////////////////////// // // DebuggerSettings @@ -400,14 +435,8 @@ DebuggerSettings::DebuggerSettings(QSettings *settings) item->setSettingsKey(debugModeGroup, QLatin1String("WatchdogTimeout")); item->setDefaultValue(20); insertItem(GdbWatchdogTimeout, item); - - item = new SavedAction(this); - item->setSettingsKey(debugModeGroup, QLatin1String("QtSourcesLocation")); - item->setDefaultValue(QString()); - insertItem(QtSourcesLocation, item); } - DebuggerSettings::~DebuggerSettings() { qDeleteAll(m_items); @@ -450,7 +479,7 @@ QString DebuggerSettings::dump() const if (!key.isEmpty()) { const QString current = item->value().toString(); const QString default_ = item->defaultValue().toString(); - ts << '\n' << key << ": " << current + ts << '\n' << key << ": " << current << " (default: " << default_ << ")"; if (current != default_) ts << " ***"; diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index c6c176f2961cd5ae7d63f7dd196ea349f15db271..50ca51a6487e063529323f31206ffadc5b48e20e 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -35,6 +35,7 @@ #define DEBUGGER_ACTIONS_H #include <QtCore/QHash> +#include <QtCore/QMap> QT_BEGIN_NAMESPACE class QSettings; @@ -47,6 +48,22 @@ class SavedAction; namespace Debugger { namespace Internal { +// Global debugger options that are not stored as saved action. +class GlobalDebuggerOptions +{ +public: + typedef QMap<QString, QString> SourcePathMap; + + void toSettings(QSettings *) const; + void fromSettings(QSettings *); + bool equals(const GlobalDebuggerOptions &rhs) const { return sourcePathMap == rhs.sourcePathMap; } + + SourcePathMap sourcePathMap; +}; + +inline bool operator==(const GlobalDebuggerOptions &o1, const GlobalDebuggerOptions &o2) { return o1.equals(o2); } +inline bool operator!=(const GlobalDebuggerOptions &o1, const GlobalDebuggerOptions &o2) { return !o1.equals(o2); } + class DebuggerSettings : public QObject { Q_OBJECT // For tr(). @@ -88,7 +105,6 @@ enum DebuggerActionCode UseDebuggingHelpers, UseCustomDebuggingHelperLocation, CustomDebuggingHelperLocation, - QtSourcesLocation, UseCodeModel, ShowThreadNames, diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index 3cbd1b79078654575b46e31af9b42073344679fe..f684d1512ba828769e7e240d30649a6e2a6895c8 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -39,6 +39,7 @@ #include <projectexplorer/abi.h> #include <QtCore/QObject> +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE class QIcon; @@ -64,6 +65,7 @@ class BreakHandler; class SnapshotHandler; class Symbol; class DebuggerToolTipManager; +class GlobalDebuggerOptions; class DebuggerCore : public QObject { @@ -116,6 +118,7 @@ public: virtual QString stringSetting(int code) const = 0; virtual DebuggerToolTipManager *toolTipManager() const = 0; + virtual QSharedPointer<GlobalDebuggerOptions> globalDebuggerOptions() const = 0; }; // This is the only way to access the global object. diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index a9c919a6e268e30d2fe2845e5cba0f681a79a72c..ce838312fc48cdbcb3603868a3d5d41f7f6426f6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -972,6 +972,7 @@ public slots: unsigned *enabledEngines, QString *errorMessage); DebuggerToolTipManager *toolTipManager() const { return m_toolTipManager; } + virtual QSharedPointer<GlobalDebuggerOptions> globalDebuggerOptions() const { return m_globalDebuggerOptions; } public: DebuggerMainWindow *m_mainWindow; @@ -1053,11 +1054,13 @@ public: DebuggerToolTipManager *m_toolTipManager; CommonOptionsPage *m_commonOptionsPage; DummyEngine *m_dummyEngine; + const QSharedPointer<GlobalDebuggerOptions> m_globalDebuggerOptions; }; DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) : m_toolTipManager(new DebuggerToolTipManager(this)), - m_dummyEngine(0) + m_dummyEngine(0), + m_globalDebuggerOptions(new GlobalDebuggerOptions) { qRegisterMetaType<WatchData>("WatchData"); qRegisterMetaType<ContextData>("ContextData"); @@ -2714,7 +2717,7 @@ void DebuggerPluginPrivate::extensionsInitialized() dock = m_mainWindow->createDockWidget(CppLanguage, localsAndWatchers); dock->setProperty(DOCKWIDGET_DEFAULT_AREA, Qt::RightDockWidgetArea); - m_commonOptionsPage = new CommonOptionsPage; + m_commonOptionsPage = new CommonOptionsPage(m_globalDebuggerOptions); m_plugin->addAutoReleasedObject(m_commonOptionsPage); m_debuggerSettings->readSettings(); @@ -3069,6 +3072,7 @@ void DebuggerPluginPrivate::extensionsInitialized() SLOT(onCurrentProjectChanged(ProjectExplorer::Project*))); QTC_ASSERT(m_coreSettings, /**/); + m_globalDebuggerOptions->fromSettings(m_coreSettings); m_watchersWindow->setVisible(false); m_returnWindow->setVisible(false); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e60059b47cf2c92c7b6e8470f5c0289823397249 --- /dev/null +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -0,0 +1,378 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "debuggersourcepathmappingwidget.h" + +#include <utils/pathchooser.h> +#include <utils/qtcassert.h> + +#include <QtGui/QVBoxLayout> +#include <QtGui/QHBoxLayout> +#include <QtGui/QStandardItemModel> +#include <QtGui/QStandardItem> +#include <QtGui/QTreeView> +#include <QtGui/QLineEdit> +#include <QtGui/QSpacerItem> +#include <QtGui/QPushButton> +#include <QtGui/QFormLayout> +#include <QtGui/QFileDialog> +#include <QtGui/QLabel> + +#include <QtCore/QDir> +#include <QtCore/QPair> + +// Qt's various build paths for unpatched versions. +#if defined(Q_OS_WIN) +static const char* qtBuildPaths[] = { +"C:/qt-greenhouse/Trolltech/Code_less_create_more/Trolltech/Code_less_create_more/Troll/4.6/qt", +"C:/iwmake/build_mingw_opensource", +"C:/ndk_buildrepos/qt-desktop/src"}; +#elif defined(Q_OS_MAC) +static const char* qtBuildPaths[] = {}; +#else +static const char* qtBuildPaths[] = {"/var/tmp/qt-src"}; +#endif + +enum { SourceColumn, TargetColumn, ColumnCount }; + +namespace Debugger { +namespace Internal { + +/*! + \class SourcePathMappingModel + + \brief Model for DebuggerSourcePathMappingWidget. + + Maintains mappings and a dummy placeholder row for adding new mappings. +*/ + +class SourcePathMappingModel : public QStandardItemModel +{ +public: + typedef QPair<QString, QString> Mapping; + typedef DebuggerSourcePathMappingWidget::SourcePathMap SourcePathMap; + + explicit SourcePathMappingModel(QObject *parent); + + SourcePathMap sourcePathMap() const; + void setSourcePathMap(const SourcePathMap&); + + Mapping mappingAt(int row) const; + bool isNewPlaceHolderAt(int row) { return isNewPlaceHolder(rawMappingAt(row)); } + + void addMapping(const QString &source, const QString &target) + { addRawMapping(QDir::toNativeSeparators(source), QDir::toNativeSeparators(target)); } + + void addNewMappingPlaceHolder() + { addRawMapping(m_newSourcePlaceHolder, m_newTargetPlaceHolder); } + + void setSource(int row, const QString &); + void setTarget(int row, const QString &); + +private: + inline bool isNewPlaceHolder(const Mapping &m) const; + inline Mapping rawMappingAt(int row) const; + void addRawMapping(const QString &source, const QString &target); + + const QString m_newSourcePlaceHolder; + const QString m_newTargetPlaceHolder; +}; + +SourcePathMappingModel::SourcePathMappingModel(QObject *parent) : + QStandardItemModel(0, ColumnCount, parent), + m_newSourcePlaceHolder(DebuggerSourcePathMappingWidget::tr("<new source>")), + m_newTargetPlaceHolder(DebuggerSourcePathMappingWidget::tr("<new target>")) +{ + QStringList headers; + headers << DebuggerSourcePathMappingWidget::tr("Source path") << DebuggerSourcePathMappingWidget::tr("Target path"); + setHorizontalHeaderLabels(headers); +} + +SourcePathMappingModel::SourcePathMap SourcePathMappingModel::sourcePathMap() const +{ + SourcePathMap rc; + const int rows = rowCount(); + for (int r = 0; r < rows; r++) { + const QPair<QString, QString> m = mappingAt(r); // Skip placeholders. + if (!m.first.isEmpty() && !m.second.isEmpty()) + rc.insert(m.first, m.second); + } + return rc; +} + +// Check a mapping whether it still contains a placeholder. +bool SourcePathMappingModel::isNewPlaceHolder(const Mapping &m) const +{ + const QLatin1Char lessThan('<'); + const QLatin1Char greaterThan('<'); + return m.first.isEmpty() || m.first.startsWith(lessThan) || m.first.endsWith(greaterThan) + || m.first == m_newSourcePlaceHolder + || m.second.isEmpty() || m.second.startsWith(lessThan) || m.second.endsWith(greaterThan) + || m.second == m_newTargetPlaceHolder; +} + +// Return raw, unfixed mapping +SourcePathMappingModel::Mapping SourcePathMappingModel::rawMappingAt(int row) const +{ + return Mapping(item(row, SourceColumn)->text(), item(row, TargetColumn)->text()); +} + +// Return mapping, empty if it is the place holder. +SourcePathMappingModel::Mapping SourcePathMappingModel::mappingAt(int row) const +{ + const Mapping raw = rawMappingAt(row); + return isNewPlaceHolder(raw) ? Mapping() : Mapping(QDir::cleanPath(raw.first), QDir::cleanPath(raw.second)); +} + +void SourcePathMappingModel::setSourcePathMap(const SourcePathMap &m) +{ + removeRows(0, rowCount()); + const SourcePathMap::const_iterator cend = m.constEnd(); + for (SourcePathMap::const_iterator it = m.constBegin(); it != cend; ++it) + addMapping(it.key(), it.value()); +} + +void SourcePathMappingModel::addRawMapping(const QString &source, const QString &target) +{ + QList<QStandardItem *> items; + QStandardItem *sourceItem = new QStandardItem(source); + sourceItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + QStandardItem *targetItem = new QStandardItem(target); + targetItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); + items << sourceItem << targetItem; + appendRow(items); +} + +void SourcePathMappingModel::setSource(int row, const QString &s) +{ + QStandardItem *sourceItem = item(row, SourceColumn); + QTC_ASSERT(sourceItem, return; ) + sourceItem->setText(s.isEmpty() ? m_newSourcePlaceHolder : QDir::toNativeSeparators(s)); +} + +void SourcePathMappingModel::setTarget(int row, const QString &t) +{ + QStandardItem *targetItem = item(row, TargetColumn); + QTC_ASSERT(targetItem, return; ) + targetItem->setText(t.isEmpty() ? m_newTargetPlaceHolder : QDir::toNativeSeparators(t)); +} + +/*! + \class DebuggerSourcePathMappingWidget + + \brief Widget for maintaining a set of source path mappings for the debugger. + + Path mappings to be applied using source path substitution in gdb. +*/ + +DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent) : + QGroupBox(parent), + m_model(new SourcePathMappingModel(this)), + m_treeView(new QTreeView), + m_addButton(new QPushButton(tr("Add"))), + m_addQtButton(new QPushButton(tr("Add Qt sources..."))), + m_removeButton(new QPushButton(tr("Remove"))), + m_sourceLineEdit(new QLineEdit), + m_targetChooser(new Utils::PathChooser) +{ + setTitle(tr("Source Paths Mapping")); + setToolTip(tr("<html><head/><body><p>Mappings of source file folders to be used in the debugger can be entered here.</p>" + "<p>This is useful when using a copy of the source tree at a location different from the one " + "at which the modules where built, for example, while doing remote debugging.</body></html>")); + // Top list/left part. + m_treeView->setRootIsDecorated(false); + m_treeView->setUniformRowHeights(true); + m_treeView->setSelectionMode(QAbstractItemView::SingleSelection); + m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_treeView->setModel(m_model); + connect(m_treeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), + this, SLOT(slotCurrentRowChanged(QModelIndex,QModelIndex))); + + // Top list/Right part: Buttons. + QVBoxLayout *buttonLayout = new QVBoxLayout; + buttonLayout->addWidget(m_addButton); + buttonLayout->addWidget(m_addQtButton); + m_addQtButton->setVisible(sizeof(qtBuildPaths) > 0); + m_addQtButton->setToolTip(tr("Add a mapping for Qt's source folders when using an unpatched version of Qt.")); + buttonLayout->addWidget(m_removeButton); + connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAdd())); + connect(m_addQtButton, SIGNAL(clicked()), this, SLOT(slotAddQt())); + + connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove())); + buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); + + // Assemble top + QHBoxLayout *treeHLayout = new QHBoxLayout; + treeHLayout->addWidget(m_treeView); + treeHLayout->addLayout(buttonLayout); + + // Edit part + m_targetChooser->setExpectedKind(Utils::PathChooser::ExistingDirectory); + connect(m_sourceLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotEditSourceFieldChanged())); + connect(m_targetChooser, SIGNAL(changed(QString)), this, SLOT(slotEditTargetFieldChanged())); + QFormLayout *editLayout = new QFormLayout; + const QString sourceToolTip = tr("The source path contained in the executable's debug information as reported by the debugger"); + QLabel *editSourceLabel = new QLabel(tr("&Source path:")); + editSourceLabel->setToolTip(sourceToolTip); + m_sourceLineEdit->setToolTip(sourceToolTip); + editSourceLabel->setBuddy(m_sourceLineEdit); + editLayout->addRow(editSourceLabel, m_sourceLineEdit); + + const QString targetToolTip = tr("The actual location of the source tree on the local machine"); + QLabel *editTargetLabel = new QLabel(tr("&Target path:")); + editTargetLabel->setToolTip(targetToolTip); + editTargetLabel->setBuddy(m_targetChooser); + m_targetChooser->setToolTip(targetToolTip); + editLayout->addRow(editTargetLabel, m_targetChooser); + + // Main layout + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(treeHLayout); + mainLayout->addLayout(editLayout); + setLayout(mainLayout); + updateEnabled(); +} + +QString DebuggerSourcePathMappingWidget::editSourceField() const +{ + return QDir::cleanPath(m_sourceLineEdit->text().trimmed()); +} + +QString DebuggerSourcePathMappingWidget::editTargetField() const +{ + return m_targetChooser->path(); +} + +void DebuggerSourcePathMappingWidget::setEditFieldMapping(const QPair<QString, QString> &m) +{ + m_sourceLineEdit->setText(QDir::toNativeSeparators(m.first)); + m_targetChooser->setPath(m.second); +} + +void DebuggerSourcePathMappingWidget::slotCurrentRowChanged(const QModelIndex ¤t,const QModelIndex &) +{ + setEditFieldMapping(current.isValid() ? m_model->mappingAt(current.row()) : QPair<QString, QString>()); + updateEnabled(); +} + +void DebuggerSourcePathMappingWidget::resizeColumns() +{ + m_treeView->resizeColumnToContents(SourceColumn); +} + +void DebuggerSourcePathMappingWidget::updateEnabled() +{ + // Allow for removing the current item. + const int row = currentRow(); + const bool hasCurrent = row >= 0; + m_sourceLineEdit->setEnabled(hasCurrent); + m_targetChooser->setEnabled(hasCurrent); + m_removeButton->setEnabled(hasCurrent); + // Allow for adding only if the current item no longer is the place holder for new items. + const bool canAdd = !hasCurrent || !m_model->isNewPlaceHolderAt(row); + m_addButton->setEnabled(canAdd); + m_addQtButton->setEnabled(canAdd); +} + +DebuggerSourcePathMappingWidget::SourcePathMap DebuggerSourcePathMappingWidget::sourcePathMap() const +{ + return m_model->sourcePathMap(); +} + +void DebuggerSourcePathMappingWidget::setSourcePathMap(const SourcePathMap &m) +{ + m_model->setSourcePathMap(m); + if (!m.isEmpty()) + resizeColumns(); +} + +int DebuggerSourcePathMappingWidget::currentRow() const +{ + const QModelIndex index = m_treeView->selectionModel()->currentIndex(); + return index.isValid() ? index.row() : -1; +} + +void DebuggerSourcePathMappingWidget::setCurrentRow(int r) +{ + m_treeView->selectionModel()->setCurrentIndex(m_model->index(r, 0), + QItemSelectionModel::ClearAndSelect + |QItemSelectionModel::Current + |QItemSelectionModel::Rows); +} + +void DebuggerSourcePathMappingWidget::slotAdd() +{ + m_model->addNewMappingPlaceHolder(); + setCurrentRow(m_model->rowCount() - 1); +} + +void DebuggerSourcePathMappingWidget::slotAddQt() +{ + // Add a mapping for various Qt build locations in case of unpatched builds. + const QString qtSourcesPath = QFileDialog::getExistingDirectory(this, tr("Qt Sources")); + if (qtSourcesPath.isEmpty()) + return; + const size_t buildPathCount = sizeof(qtBuildPaths)/sizeof(const char *); + for (size_t i = 0; i < buildPathCount; i++) + m_model->addMapping(QString::fromLatin1(qtBuildPaths[i]), qtSourcesPath); + resizeColumns(); + setCurrentRow(m_model->rowCount() - 1); +} + +void DebuggerSourcePathMappingWidget::slotRemove() +{ + const int row = currentRow(); + if (row >= 0) + m_model->removeRow(row); +} + +void DebuggerSourcePathMappingWidget::slotEditSourceFieldChanged() +{ + const int row = currentRow(); + if (row >= 0) { + m_model->setSource(row, editSourceField()); + updateEnabled(); + } +} + +void DebuggerSourcePathMappingWidget::slotEditTargetFieldChanged() +{ + const int row = currentRow(); + if (row >= 0) { + m_model->setTarget(row, editTargetField()); + updateEnabled(); + } +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.h b/src/plugins/debugger/debuggersourcepathmappingwidget.h new file mode 100644 index 0000000000000000000000000000000000000000..e611a8631a074400956e6769dc0e4e942cdead97 --- /dev/null +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.h @@ -0,0 +1,100 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef DEBUGGERSOURCEPATHMAPPINGWIDGET_H +#define DEBUGGERSOURCEPATHMAPPINGWIDGET_H + +#include <QtGui/QGroupBox> +#include <QtCore/QMap> +#include <QtCore/QPair> + +QT_BEGIN_NAMESPACE +class QStandardItemModel; +class QTreeView; +class QLineEdit; +class QPushButton; +class QLineEdit; +class QModelIndex; +QT_END_NAMESPACE + +namespace Utils { +class PathChooser; +} + +namespace Debugger { +namespace Internal { +class SourcePathMappingModel; + +class DebuggerSourcePathMappingWidget : public QGroupBox +{ + Q_OBJECT +public: + typedef QMap<QString, QString> SourcePathMap; + + explicit DebuggerSourcePathMappingWidget(QWidget *parent = 0); + + SourcePathMap sourcePathMap() const; + void setSourcePathMap(const SourcePathMap &); + +signals: + +private slots: + void slotAdd(); + void slotAddQt(); + void slotRemove(); + void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &); + void slotEditSourceFieldChanged(); + void slotEditTargetFieldChanged(); + +private: + void resizeColumns(); + void updateEnabled(); + QString editSourceField() const; + QString editTargetField() const; + void setEditFieldMapping(const QPair<QString, QString> &m); + int currentRow() const; + void setCurrentRow(int r); + + SourcePathMappingModel *m_model; + QTreeView *m_treeView; + QPushButton *m_addButton; + QPushButton *m_addQtButton; + QPushButton *m_removeButton; + QLineEdit *m_sourceLineEdit; + Utils::PathChooser *m_targetChooser; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGERSOURCEPATHMAPPINGWIDGET_H diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index de42119ad5d2f660cdd81b477c15ba8cdb12fedb..fde5e421573f0670076ad99347c36b620babc370 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4564,22 +4564,19 @@ void GdbEngine::notifyInferiorSetupFailed() void GdbEngine::handleInferiorPrepared() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - const QByteArray qtInstallPath = - debuggerCore()->action(QtSourcesLocation)->value().toString().toLocal8Bit(); - if (!qtInstallPath.isEmpty()) { - QByteArray qtBuildPath; -#if defined(Q_OS_WIN) - qtBuildPath = "C:/qt-greenhouse/Trolltech/Code_less_create_more/" - "Trolltech/Code_less_create_more/Troll/4.6/qt"; - postCommand("set substitute-path " + qtBuildPath + ' ' + qtInstallPath); - qtBuildPath = "C:/iwmake/build_mingw_opensource"; - postCommand("set substitute-path " + qtBuildPath + ' ' + qtInstallPath); - qtBuildPath = "C:/ndk_buildrepos/qt-desktop/src"; - postCommand("set substitute-path " + qtBuildPath + ' ' + qtInstallPath); -#elif defined(Q_OS_UNIX) && !defined (Q_OS_MAC) - qtBuildPath = "/var/tmp/qt-src"; - postCommand("set substitute-path " + qtBuildPath + ' ' + qtInstallPath); -#endif + + // Apply source path mappings from global options. + const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions(); + if (!globalOptions->sourcePathMap.isEmpty()) { + typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator; + const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd(); + for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) { + QByteArray command = "set substitute-path "; + command += it.key().toLocal8Bit(); + command += ' '; + command += it.value().toLocal8Bit(); + postCommand(command); + } } // Initial attempt to set breakpoints.