Commit 709cb294 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

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: default avatarAlessandro Portale <alessandro.portale@nokia.com>
parent e5401e94
......@@ -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();
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment