Commit 18382242 authored by Petar Perisin's avatar Petar Perisin Committed by hjk

Attach to unstarted Application

This patch adds a dialog that can be useful in situations where you have
a script-based test tool, that starts executable and executes test on
it.

This dialog allows user to specify executable and to begin watching
process, where dialog simply waits for executable to be started. As soon
as executable is found, QtCreator will attach to it.

also, since script-based test can constantly start-stop executable. as
soon as it is detected that executable is down, another waiting process
starts where dialog waits for executable to come up again.

Change-Id: I3bd62f656d34f8dff5641f6747ec12d97cbae2a4
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent 8d319ce8
......@@ -73,7 +73,8 @@ HEADERS += \
memoryview.h \
localsandexpressionswindow.h \
imageviewer.h \
simplifytype.h
simplifytype.h \
unstartedappwatcherdialog.h
SOURCES += \
basewindow.cpp \
......@@ -129,7 +130,8 @@ SOURCES += \
memoryview.cpp \
localsandexpressionswindow.cpp \
imageviewer.cpp \
simplifytype.cpp
simplifytype.cpp \
unstartedappwatcherdialog.cpp
FORMS += \
localsandexpressionsoptionspage.ui
......
......@@ -92,6 +92,7 @@ QtcPlugin {
"watchutils.cpp", "watchutils.h",
"watchwindow.cpp", "watchwindow.h",
"simplifytype.cpp", "simplifytype.h",
"unstartedappwatcherdialog.cpp", "unstartedappwatcherdialog.h"
]
}
......
......@@ -60,6 +60,7 @@
#include "watchhandler.h"
#include "watchwindow.h"
#include "watchutils.h"
#include "unstartedappwatcherdialog.h"
#include "debuggertooltipmanager.h"
#include "localsandexpressionswindow.h"
#include "loadcoredialog.h"
......@@ -741,6 +742,7 @@ public:
m_threadBox->setCurrentIndex(index);
m_threadBox->blockSignals(state);
}
DebuggerRunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process);
public slots:
void writeSettings()
......@@ -877,6 +879,9 @@ public slots:
void attachToRemoteServer();
void attachToProcess(bool startServerOnly);
void attachToRunningApplication();
void attachToUnstartedApplicationDialog();
void attachToFoundProcess();
void continueOnAttach(Debugger::DebuggerState state);
void attachExternalApplication(ProjectExplorer::RunControl *rc);
void attachToQmlPort();
void startRemoteEngine();
......@@ -1199,6 +1204,7 @@ public:
QAction *m_startAndDebugApplicationAction;
QAction *m_startRemoteServerAction;
QAction *m_attachToRunningApplication;
QAction *m_attachToUnstartedApplication;
QAction *m_attachToQmlPortAction;
QAction *m_attachToRemoteServerAction;
QAction *m_startRemoteCdbAction;
......@@ -1313,6 +1319,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
m_startAndDebugApplicationAction = 0;
m_attachToRemoteServerAction = 0;
m_attachToRunningApplication = 0;
m_attachToUnstartedApplication = 0;
m_attachToQmlPortAction = 0;
m_startRemoteCdbAction = 0;
m_attachToCoreAction = 0;
......@@ -1663,11 +1670,65 @@ void DebuggerPluginPrivate::attachToProcess(bool startServerOnly)
QTC_ASSERT(kit, return);
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return);
DeviceProcessItem process = dlg->currentProcess();
if (device->type() != PE::DESKTOP_DEVICE_TYPE) {
GdbServerStarter *starter = new GdbServerStarter(dlg, startServerOnly);
starter->run();
} else {
attachToRunningProcess(kit, dlg->currentProcess());
}
}
void DebuggerPluginPrivate::attachToUnstartedApplicationDialog()
{
UnstartedAppWatcherDialog *dlg = new UnstartedAppWatcherDialog(mainWindow());
connect(dlg, SIGNAL(finished(int)), dlg, SLOT(deleteLater()));
connect(dlg, SIGNAL(processFound()), this, SLOT(attachToFoundProcess()));
dlg->show();
}
void DebuggerPluginPrivate::attachToFoundProcess()
{
UnstartedAppWatcherDialog *dlg = qobject_cast<UnstartedAppWatcherDialog *>(QObject::sender());
if (!dlg)
return;
DebuggerRunControl *rc = attachToRunningProcess(dlg->currentKit(), dlg->currentProcess());
if (!rc)
return;
if (dlg->hideOnAttach())
connect(rc, SIGNAL(finished()), dlg, SLOT(startWatching()));
if (dlg->continueOnAttach()) {
connect(currentEngine(), SIGNAL(stateChanged(Debugger::DebuggerState)),
this, SLOT(continueOnAttach(Debugger::DebuggerState)));
}
}
void DebuggerPluginPrivate::continueOnAttach(Debugger::DebuggerState state)
{
// wait for state when we can continue
if (state != InferiorStopOk)
return;
// disconnect and continue
disconnect(currentEngine(), SIGNAL(stateChanged(Debugger::DebuggerState)),
this, SLOT(continueOnAttach(Debugger::DebuggerState)));
handleExecContinue();
}
DebuggerRunControl *DebuggerPluginPrivate::attachToRunningProcess(Kit *kit,
DeviceProcessItem process)
{
QTC_ASSERT(kit, return 0);
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return 0);
if (process.pid == 0) {
QMessageBox::warning(ICore::mainWindow(), tr("Warning"),
tr("Cannot attach to process with PID 0"));
return;
return 0;
}
bool isWindows = false;
......@@ -1677,22 +1738,23 @@ void DebuggerPluginPrivate::attachToProcess(bool startServerOnly)
QMessageBox::warning(ICore::mainWindow(), tr("Process Already Under Debugger Control"),
tr("The process %1 is already under the control of a debugger.\n"
"Qt Creator cannot attach to it.").arg(process.pid));
return;
return 0;
}
if (device->type() == PE::DESKTOP_DEVICE_TYPE) {
DebuggerStartParameters sp;
QTC_ASSERT(fillParameters(&sp, kit), return);
sp.attachPID = process.pid;
sp.displayName = tr("Process %1").arg(process.pid);
sp.executable = process.exe;
sp.startMode = AttachExternal;
sp.closeMode = DetachAtClose;
DebuggerRunControlFactory::createAndScheduleRun(sp);
} else {
GdbServerStarter *starter = new GdbServerStarter(dlg, startServerOnly);
starter->run();
if (device->type() != PE::DESKTOP_DEVICE_TYPE) {
QMessageBox::warning(ICore::mainWindow(), tr("Not a Desktop Device Type"),
tr("It is only possible to attach to local running process."));
return 0;
}
DebuggerStartParameters sp;
QTC_ASSERT(fillParameters(&sp, kit), return 0);
sp.attachPID = process.pid;
sp.displayName = tr("Process %1").arg(process.pid);
sp.executable = process.exe;
sp.startMode = AttachExternal;
sp.closeMode = DetachAtClose;
return DebuggerRunControlFactory::createAndScheduleRun(sp);
}
void DebuggerPluginPrivate::attachExternalApplication(RunControl *rc)
......@@ -2140,6 +2202,7 @@ void DebuggerPluginPrivate::setInitialState()
m_attachToCoreAction->setEnabled(true);
m_attachToRemoteServerAction->setEnabled(true);
m_attachToRunningApplication->setEnabled(true);
m_attachToUnstartedApplication->setEnabled(true);
m_detachAction->setEnabled(false);
m_watchAction1->setEnabled(true);
......@@ -2263,6 +2326,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
m_attachToCoreAction->setEnabled(true);
m_attachToRemoteServerAction->setEnabled(true);
m_attachToRunningApplication->setEnabled(true);
m_attachToUnstartedApplication->setEnabled(true);
m_threadBox->setEnabled(state == InferiorStopOk || state == InferiorUnrunnable);
......@@ -2864,6 +2928,10 @@ void DebuggerPluginPrivate::extensionsInitialized()
act->setText(tr("Attach to Running Application..."));
connect(act, SIGNAL(triggered()), SLOT(attachToRunningApplication()));
act = m_attachToUnstartedApplication = new QAction(this);
act->setText(tr("Attach to Unstarted Application..."));
connect(act, SIGNAL(triggered()), SLOT(attachToUnstartedApplicationDialog()));
act = m_attachToQmlPortAction = new QAction(this);
act->setText(tr("Attach to QML Port..."));
connect(act, SIGNAL(triggered()), SLOT(attachToQmlPort()));
......@@ -2911,6 +2979,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
cmd->setDescription(tr("Attach to Running Application"));
mstart->addAction(cmd, Debugger::Constants::G_GENERAL);
cmd = ActionManager::registerAction(m_attachToUnstartedApplication,
"Debugger.AttachToUnstartedProcess", globalcontext);
cmd->setDescription(tr("Attach to Unstarted Application"));
mstart->addAction(cmd, Debugger::Constants::G_GENERAL);
cmd = ActionManager::registerAction(m_startAndDebugApplicationAction,
"Debugger.StartAndDebugApplication", globalcontext);
cmd->setAttribute(Command::CA_Hide);
......
This diff is collapsed.
/****************************************************************************
**
** Copyright (C) 2014 Petar Perisin <petar.perisin@gmail.com>
** 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 UNSTARTEDAPPWATCHERDIALOG_H
#define UNSTARTEDAPPWATCHERDIALOG_H
#include <QDialog>
#include <QTimer>
#include <projectexplorer/devicesupport/deviceprocesslist.h>
QT_BEGIN_NAMESPACE
class QLineEdit;
class QLabel;
class QCheckBox;
QT_END_NAMESPACE
namespace ProjectExplorer {
class KitChooser;
class Kit;
}
namespace Utils { class PathChooser; }
namespace Debugger {
namespace Internal {
enum UnstartedAppWacherState {
InvalidWacherState,
NotWatchingState,
WatchingState,
FoundState
};
class UnstartedAppWatcherDialogPrivate
{
public:
UnstartedAppWatcherDialogPrivate(QWidget *dialog);
void setWaitingState(UnstartedAppWacherState state);
ProjectExplorer::KitChooser *kitChooser;
Utils::PathChooser *pathChooser;
QLabel *waitingLabel;
QCheckBox *hideOnAttachCheckBox;
QCheckBox *continueOnAttachCheckBox;
QPushButton *watchingPushButton;
QPushButton *closePushButton;
};
class UnstartedAppWatcherDialog : public QDialog
{
Q_OBJECT
public:
explicit UnstartedAppWatcherDialog(QWidget *parent = 0);
~UnstartedAppWatcherDialog();
ProjectExplorer::Kit* currentKit() const;
ProjectExplorer::DeviceProcessItem currentProcess() const;
bool hideOnAttach() const;
bool continueOnAttach() const;
public slots:
void selectExecutable();
void startWatching();
void pidFound(const ProjectExplorer::DeviceProcessItem &p);
void startStopWatching(bool start);
void findProcess();
void stopAndCheckExecutable();
signals:
void processFound();
private:
void startStopTimer(bool start);
bool checkExecutableString() const;
UnstartedAppWatcherDialogPrivate *d;
ProjectExplorer::DeviceProcessItem m_process;
QTimer m_timer;
};
} // namespace Internal
} // namespace Debugger
#endif // UNSTARTEDAPPWATCHERDIALOG_H
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