forked from qt-creator/qt-creator
Debugger[CDB]: Prompt to set up the Symbol server.
Prompt to set up the public symbol server unless it is already configured or the environment variable exists. Change the dialog to be based on the PathChooser to be able to suggest a non-existent directory. Acked-by: Alessandro Portale <alessandro.portale@nokia.com>
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
#include "cdboptionspage.h"
|
||||
#include "cdboptions.h"
|
||||
#include "cdbexceptionutils.h"
|
||||
#include "cdbsymbolpathlisteditor.h"
|
||||
#include "debuggeragents.h"
|
||||
#include "debuggeruiswitcher.h"
|
||||
#include "debuggermainwindow.h"
|
||||
@@ -59,6 +60,7 @@
|
||||
#include <utils/fancymainwindow.h>
|
||||
#include <texteditor/itexteditor.h>
|
||||
#include <utils/savedaction.h>
|
||||
#include <utils/checkablemessagebox.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QTimer>
|
||||
@@ -347,11 +349,48 @@ void CdbDebugEnginePrivate::checkVersion()
|
||||
}
|
||||
}
|
||||
|
||||
void CdbDebugEngine::startupChecks()
|
||||
{
|
||||
// Check symbol server unless the user has an external/internal setup
|
||||
if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
|
||||
|| CdbOptions::indexOfSymbolServerPath(m_d->m_options->symbolPaths) != -1)
|
||||
return;
|
||||
// Prompt to use Symbol server unless the user checked "No nagging".
|
||||
Core::ICore *core = Core::ICore::instance();
|
||||
const QString nagSymbolServerKey = CdbOptions::settingsGroup() + QLatin1String("/NoPromptSymbolServer");
|
||||
bool noFurtherNagging = core->settings()->value(nagSymbolServerKey, false).toBool();
|
||||
if (noFurtherNagging)
|
||||
return;
|
||||
|
||||
const QString symServUrl = QLatin1String("http://support.microsoft.com/kb/311503");
|
||||
const QString msg = tr("<html><head/><body><p>The debugger is not configured to use the public "
|
||||
"<a href=\"%1\">Microsoft Symbol Server</a>. This is recommended "
|
||||
"for retrieval of the symbols of the operating system libraries.</p>"
|
||||
"<p><i>Note:</i> A fast internet connection is required for this to work smoothly. Also, a delay "
|
||||
"might occur when connecting for the first time.</p>"
|
||||
"<p>Would you like to set it up?</p></br>"
|
||||
"</body></html>").arg(symServUrl);
|
||||
const QDialogButtonBox::StandardButton answer =
|
||||
Utils::CheckableMessageBox::question(core->mainWindow(), tr("Symbol Server"), msg,
|
||||
tr("Do not ask again"), &noFurtherNagging);
|
||||
core->settings()->setValue(nagSymbolServerKey, noFurtherNagging);
|
||||
if (answer == QDialogButtonBox::No)
|
||||
return;
|
||||
// Prompt for path and add it. Synchronize QSetting and debugger.
|
||||
const QString cacheDir = CdbSymbolPathListEditor::promptCacheDirectory(core->mainWindow());
|
||||
if (cacheDir.isEmpty())
|
||||
return;
|
||||
m_d->m_options->symbolPaths.push_back(CdbOptions::symbolServerPath(cacheDir));
|
||||
m_d->m_options->toSettings(core->settings());
|
||||
syncDebuggerPaths();
|
||||
}
|
||||
|
||||
void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
|
||||
{
|
||||
if (debugCDBExecution)
|
||||
qDebug() << "startDebugger" << *sp;
|
||||
CdbCore::BreakPoint::clearNormalizeFileNameCache();
|
||||
startupChecks();
|
||||
setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
|
||||
m_d->checkVersion();
|
||||
if (m_d->m_hDebuggeeProcess) {
|
||||
|
||||
@@ -112,6 +112,7 @@ private slots:
|
||||
void warning(const QString &w);
|
||||
|
||||
private:
|
||||
void startupChecks();
|
||||
void setState(DebuggerState state, const char *func, int line);
|
||||
inline bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
|
||||
void processTerminated(unsigned long exitCode);
|
||||
|
||||
@@ -50,6 +50,11 @@ CdbOptions::CdbOptions() :
|
||||
{
|
||||
}
|
||||
|
||||
QString CdbOptions::settingsGroup()
|
||||
{
|
||||
return QLatin1String(settingsGroupC);
|
||||
}
|
||||
|
||||
void CdbOptions::clear()
|
||||
{
|
||||
enabled = false;
|
||||
@@ -99,5 +104,37 @@ unsigned CdbOptions::compare(const CdbOptions &rhs) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const char symbolServerPrefixC[] = "symsrv*symsrv.dll*";
|
||||
static const char symbolServerPostfixC[] = "*http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
QString CdbOptions::symbolServerPath(const QString &cacheDir)
|
||||
{
|
||||
QString s = QLatin1String(symbolServerPrefixC);
|
||||
s += QDir::toNativeSeparators(cacheDir);
|
||||
s += QLatin1String(symbolServerPostfixC);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool CdbOptions::isSymbolServerPath(const QString &path, QString *cacheDir /* = 0 */)
|
||||
{
|
||||
// Split apart symbol server post/prefixes
|
||||
if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC)))
|
||||
return false;
|
||||
if (cacheDir) {
|
||||
const unsigned prefixLength = qstrlen(symbolServerPrefixC);
|
||||
*cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int CdbOptions::indexOfSymbolServerPath(const QStringList &paths, QString *cacheDir /* = 0 */)
|
||||
{
|
||||
const int count = paths.size();
|
||||
for (int i = 0; i < count; i++)
|
||||
if (CdbOptions::isSymbolServerPath(paths.at(i), cacheDir))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
@@ -54,6 +54,14 @@ public:
|
||||
SymbolOptionsChanged = 0x4 };
|
||||
unsigned compare(const CdbOptions &s) const;
|
||||
|
||||
// Format a symbol server specification with a cache directory
|
||||
static QString symbolServerPath(const QString &cacheDir);
|
||||
// Check whether the path is a symbol server specification and return the cache directory
|
||||
static bool isSymbolServerPath(const QString &symbolPath, QString *cacheDir = 0);
|
||||
static int indexOfSymbolServerPath(const QStringList &symbolPaths, QString *cacheDir = 0);
|
||||
|
||||
static QString settingsGroup();
|
||||
|
||||
bool enabled;
|
||||
QString path;
|
||||
QStringList symbolPaths;
|
||||
|
||||
@@ -28,13 +28,83 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "cdbsymbolpathlisteditor.h"
|
||||
#include "cdboptions.h"
|
||||
|
||||
#include <utils/pathchooser.h>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QDialogButtonBox>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QFormLayout>
|
||||
#include <QtGui/QMessageBox>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) :
|
||||
QDialog(parent), m_chooser(new Utils::PathChooser),
|
||||
m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
|
||||
{
|
||||
setWindowTitle(tr("Select Local Cache Folder"));
|
||||
setModal(true);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout;
|
||||
m_chooser->setExpectedKind(Utils::PathChooser::Directory);
|
||||
m_chooser->setMinimumWidth(400);
|
||||
formLayout->addRow(tr("Path:"), m_chooser);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(formLayout);
|
||||
mainLayout->addWidget(m_buttonBox);
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
}
|
||||
|
||||
void CacheDirectoryDialog::setPath(const QString &p)
|
||||
{
|
||||
m_chooser->setPath(p);
|
||||
}
|
||||
|
||||
QString CacheDirectoryDialog::path() const
|
||||
{
|
||||
return m_chooser->path();
|
||||
}
|
||||
|
||||
void CacheDirectoryDialog::accept()
|
||||
{
|
||||
// Ensure path exists
|
||||
QString cache = path();
|
||||
if (cache.isEmpty())
|
||||
return;
|
||||
QFileInfo fi(cache);
|
||||
// Folder exists - all happy.
|
||||
if (fi.isDir()) {
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
// Does a file of the same name exist?
|
||||
if (fi.exists()) {
|
||||
QMessageBox::warning(this, tr("Already Exists"),
|
||||
tr("A file named '%1' already exists.").arg(cache));
|
||||
return;
|
||||
}
|
||||
// Create
|
||||
QDir root(QDir::root());
|
||||
if (!root.mkpath(cache)) {
|
||||
QMessageBox::warning(this, tr("Cannot Create"),
|
||||
tr("The folder '%1' could not be created.").arg(cache));
|
||||
return;
|
||||
}
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
|
||||
Utils::PathListEditor(parent)
|
||||
{
|
||||
@@ -44,15 +114,20 @@ CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
|
||||
"Requires specifying a local cache directory."));
|
||||
}
|
||||
|
||||
QString CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent)
|
||||
{
|
||||
CacheDirectoryDialog dialog(parent);
|
||||
dialog.setPath(QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache"));
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return QString();
|
||||
return dialog.path();
|
||||
}
|
||||
|
||||
void CdbSymbolPathListEditor::addSymbolServer()
|
||||
{
|
||||
const QString title = tr("Pick a local cache directory");
|
||||
const QString cacheDir = QFileDialog::getExistingDirectory(this, title);
|
||||
if (!cacheDir.isEmpty()) {
|
||||
const QString path = QString::fromLatin1("symsrv*symsrv.dll*%1*http://msdl.microsoft.com/download/symbols").
|
||||
arg(QDir::toNativeSeparators(cacheDir));
|
||||
insertPathAtCursor(path);
|
||||
}
|
||||
const QString cacheDir = promptCacheDirectory(this);
|
||||
if (!cacheDir.isEmpty())
|
||||
insertPathAtCursor(CdbOptions::symbolServerPath(cacheDir));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -32,15 +32,49 @@
|
||||
|
||||
#include <utils/pathlisteditor.h>
|
||||
|
||||
#include <QtGui/QDialog>
|
||||
|
||||
namespace Utils {
|
||||
class PathChooser;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDialogButtonBox;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
// Internal helper dialog prompting for a cache directory
|
||||
// using a PathChooser.
|
||||
// Note that QFileDialog does not offer a way of suggesting
|
||||
// a non-existent folder, which is in turn automatically
|
||||
// created. This is done here (suggest $TEMP\symbolcache
|
||||
// regardless of its existence).
|
||||
|
||||
class CacheDirectoryDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CacheDirectoryDialog(QWidget *parent = 0);
|
||||
|
||||
void setPath(const QString &p);
|
||||
QString path() const;
|
||||
|
||||
virtual void accept();
|
||||
|
||||
private:
|
||||
Utils::PathChooser *m_chooser;
|
||||
QDialogButtonBox *m_buttonBox;
|
||||
};
|
||||
|
||||
class CdbSymbolPathListEditor : public Utils::PathListEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CdbSymbolPathListEditor(QWidget *parent = 0);
|
||||
|
||||
static QString promptCacheDirectory(QWidget *parent);
|
||||
|
||||
private slots:
|
||||
void addSymbolServer();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user