deviceprocessesdialog.cpp 11.2 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
**
** GNU Lesser General Public License Usage
**
** 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.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

30
31
#include "devicesupport/deviceprocessesdialog.h"
#include "devicesupport/deviceprocesslist.h"
Tobias Hunger's avatar
Tobias Hunger committed
32
33
#include "kitchooser.h"
#include "kitinformation.h"
34

35
36
37
38
39
40
41
42
43
#include <utils/filterlineedit.h>
#include <utils/qtcassert.h>

#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
44
#include <QMessageBox>
45
#include <QPushButton>
46
#include <QSortFilterProxyModel>
47
48
49
50
51
52
53
#include <QSpacerItem>
#include <QTextBrowser>
#include <QTextDocument>
#include <QTreeView>
#include <QVBoxLayout>

using namespace Utils;
54

55
namespace ProjectExplorer {
56
namespace Internal {
57

58
59
60
61
62
63
64
///////////////////////////////////////////////////////////////////////
//
// ProcessListFilterModel
//
///////////////////////////////////////////////////////////////////////

class ProcessListFilterModel : public QSortFilterProxyModel
65
66
{
public:
67
68
    ProcessListFilterModel();
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
69
70
};

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
ProcessListFilterModel::ProcessListFilterModel()
{
    setFilterCaseSensitivity(Qt::CaseInsensitive);
    setDynamicSortFilter(true);
    setFilterKeyColumn(-1);
}

bool ProcessListFilterModel::lessThan(const QModelIndex &left,
    const QModelIndex &right) const
{
    const QString l = sourceModel()->data(left).toString();
    const QString r = sourceModel()->data(right).toString();
    if (left.column() == 0)
        return l.toInt() < r.toInt();
    return l < r;
}

///////////////////////////////////////////////////////////////////////
//
// DeviceProcessesDialogPrivate
//
///////////////////////////////////////////////////////////////////////

class DeviceProcessesDialogPrivate : public QObject
{
    Q_OBJECT

public:
99
    DeviceProcessesDialogPrivate(KitChooser *chooser, QWidget *parent);
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

public slots:
    void setDevice(const IDevice::ConstPtr &device);
    void updateProcessList();
    void updateDevice();
    void killProcess();
    void handleRemoteError(const QString &errorMsg);
    void handleProcessListUpdated();
    void handleProcessKilled();
    void updateButtons();
    DeviceProcess selectedProcess() const;

public:
    QWidget *q;
    DeviceProcessList *processList;
    ProcessListFilterModel proxyModel;
116
    QLabel *kitLabel;
Tobias Hunger's avatar
Tobias Hunger committed
117
    KitChooser *kitChooser;
118
119
120
121
122
123

    QTreeView *procView;
    QTextBrowser *errorText;
    FilterLineEdit *processFilterLineEdit;
    QPushButton *updateListButton;
    QPushButton *killProcessButton;
124
125
    QPushButton *acceptButton;
    QDialogButtonBox *buttonBox;
126
};
127

128
DeviceProcessesDialogPrivate::DeviceProcessesDialogPrivate(KitChooser *chooser, QWidget *parent)
129
130
131
132
133
    : q(parent)
    , kitLabel(new QLabel(DeviceProcessesDialog::tr("Kit:"), parent))
    , kitChooser(chooser)
    , acceptButton(0)
    , buttonBox(new QDialogButtonBox(parent))
134
{
135
136
137
138
    q->setWindowTitle(DeviceProcessesDialog::tr("List of Processes"));
    q->setWindowFlags(q->windowFlags() & ~Qt::WindowContextHelpButtonHint);
    q->setMinimumHeight(500);

139
    processList = 0;
140

141
142
143
    processFilterLineEdit = new FilterLineEdit(q);
    processFilterLineEdit->setPlaceholderText(DeviceProcessesDialog::tr("Filter"));
    processFilterLineEdit->setFocus(Qt::TabFocusReason);
144

145
    kitChooser->populate();
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

    procView = new QTreeView(q);
    procView->setModel(&proxyModel);
    procView->setSelectionBehavior(QAbstractItemView::SelectRows);
    procView->setSelectionMode(QAbstractItemView::SingleSelection);
    procView->setUniformRowHeights(true);
    procView->setRootIsDecorated(false);
    procView->setAlternatingRowColors(true);
    procView->setSortingEnabled(true);
    procView->header()->setDefaultSectionSize(100);
    procView->header()->setStretchLastSection(true);
    procView->sortByColumn(1, Qt::AscendingOrder);

    errorText = new QTextBrowser(q);

    updateListButton = new QPushButton(DeviceProcessesDialog::tr("&Update List"), q);
    killProcessButton = new QPushButton(DeviceProcessesDialog::tr("&Kill Process"), q);

    buttonBox->addButton(updateListButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(killProcessButton, QDialogButtonBox::ActionRole);

    QFormLayout *leftColumn = new QFormLayout();
    leftColumn->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
169
    leftColumn->addRow(kitLabel, kitChooser);
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    leftColumn->addRow(DeviceProcessesDialog::tr("&Filter:"), processFilterLineEdit);

//    QVBoxLayout *rightColumn = new QVBoxLayout();
//    rightColumn->addWidget(updateListButton);
//    rightColumn->addWidget(killProcessButton);
//    rightColumn->addStretch();

//    QHBoxLayout *horizontalLayout = new QHBoxLayout();
//    horizontalLayout->addLayout(leftColumn);
//    horizontalLayout->addLayout(rightColumn);

    QVBoxLayout *mainLayout = new QVBoxLayout(q);
    mainLayout->addLayout(leftColumn);
    mainLayout->addWidget(procView);
    mainLayout->addWidget(errorText);
    mainLayout->addWidget(buttonBox);

//    QFrame *line = new QFrame(this);
//    line->setFrameShape(QFrame::HLine);
//    line->setFrameShadow(QFrame::Sunken);

    connect(processFilterLineEdit, SIGNAL(textChanged(QString)),
        &proxyModel, SLOT(setFilterRegExp(QString)));
    connect(procView->selectionModel(),
194
        SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
195
196
        SLOT(updateButtons()));
    connect(updateListButton, SIGNAL(clicked()), SLOT(updateProcessList()));
Tobias Hunger's avatar
Tobias Hunger committed
197
    connect(kitChooser, SIGNAL(currentIndexChanged(int)), SLOT(updateDevice()));
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    connect(killProcessButton, SIGNAL(clicked()), SLOT(killProcess()));
    connect(&proxyModel, SIGNAL(layoutChanged()), SLOT(handleProcessListUpdated()));
    connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
}

void DeviceProcessesDialogPrivate::setDevice(const IDevice::ConstPtr &device)
{
    delete processList;

    processList = device->createProcessListModel();
    QTC_ASSERT(processList, return);
    proxyModel.setSourceModel(processList);

    connect(processList, SIGNAL(error(QString)),
213
        SLOT(handleRemoteError(QString)));
214
    connect(processList, SIGNAL(processListUpdated()),
215
        SLOT(handleProcessListUpdated()));
216
    connect(processList, SIGNAL(processKilled()),
217
        SLOT(handleProcessKilled()), Qt::QueuedConnection);
218
219

    updateButtons();
220
221
222
    updateProcessList();
}

223
void DeviceProcessesDialogPrivate::handleRemoteError(const QString &errorMsg)
224
{
225
226
227
    QMessageBox::critical(q, tr("Remote Error"), errorMsg);
    updateListButton->setEnabled(true);
    updateButtons();
228
229
}

230
void DeviceProcessesDialogPrivate::handleProcessListUpdated()
231
{
232
233
234
235
    updateListButton->setEnabled(true);
    procView->resizeColumnToContents(0);
    procView->resizeColumnToContents(1);
    updateButtons();
236
237
}

238
void DeviceProcessesDialogPrivate::updateProcessList()
239
{
240
241
242
243
    updateListButton->setEnabled(false);
    killProcessButton->setEnabled(false);
    if (processList)
        processList->update();
244
245
}

246
void DeviceProcessesDialogPrivate::killProcess()
247
{
248
249
250
251
252
253
    const QModelIndexList indexes = procView->selectionModel()->selectedIndexes();
    if (indexes.empty())
        return;
    updateListButton->setEnabled(false);
    killProcessButton->setEnabled(false);
    processList->killProcess(proxyModel.mapToSource(indexes.first()).row());
254
255
}

256
void DeviceProcessesDialogPrivate::updateDevice()
257
{
Tobias Hunger's avatar
Tobias Hunger committed
258
    setDevice(DeviceKitInformation::device(kitChooser->currentKit()));
259
260
}

261
void DeviceProcessesDialogPrivate::handleProcessKilled()
262
263
264
265
{
    updateProcessList();
}

266
void DeviceProcessesDialogPrivate::updateButtons()
267
{
268
269
270
    const bool hasSelection = procView->selectionModel()->hasSelection();
    if (acceptButton)
        acceptButton->setEnabled(hasSelection);
271
272
273
274
275
276
277
278
279
280
    killProcessButton->setEnabled(hasSelection);
    errorText->setVisible(!errorText->document()->isEmpty());
}

DeviceProcess DeviceProcessesDialogPrivate::selectedProcess() const
{
    const QModelIndexList indexes = procView->selectionModel()->selectedIndexes();
    if (indexes.empty())
        return DeviceProcess();
    return processList->at(proxyModel.mapToSource(indexes.first()).row());
281
282
}

283
} // namespace Internal
284
285
286
287
288
289
290

///////////////////////////////////////////////////////////////////////
//
// DeviceProcessesDialog
//
///////////////////////////////////////////////////////////////////////

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/*!
     \class ProjectExplorer::DeviceProcessesDialog

     \brief Shows a list of processes.

     The dialog can be used as a
     \list
     \o Non-modal dialog showing a list of processes: Call addCloseButton()
        to add a 'Close' button.
     \o Modal dialog with an 'Accept' button to select a process: Call
        addAcceptButton() passing the label text. This will create a
        'Cancel' button as well.
     \endlist
*/

306
DeviceProcessesDialog::DeviceProcessesDialog(QWidget *parent)
307
308
309
310
311
312
    : QDialog(parent), d(new Internal::DeviceProcessesDialogPrivate(new KitChooser(this), this))
{
}

DeviceProcessesDialog::DeviceProcessesDialog(KitChooser *chooser, QWidget *parent)
    : QDialog(parent), d(new Internal::DeviceProcessesDialogPrivate(chooser, this))
313
314
315
316
317
318
319
320
{
}

DeviceProcessesDialog::~DeviceProcessesDialog()
{
    delete d;
}

321
322
323
324
325
326
327
328
329
330
331
332
333
334
void DeviceProcessesDialog::addAcceptButton(const QString &label)
{
    d->acceptButton = new QPushButton(label);
    d->buttonBox->addButton(d->acceptButton, QDialogButtonBox::AcceptRole);
    connect(d->procView, SIGNAL(doubleClicked(QModelIndex)),
            d->acceptButton, SLOT(animateClick()));
    d->buttonBox->addButton(QDialogButtonBox::Cancel);
}

void DeviceProcessesDialog::addCloseButton()
{
    d->buttonBox->addButton(QDialogButtonBox::Close);
}

335
336
337
338
339
340
void DeviceProcessesDialog::setKitVisible(bool v)
{
    d->kitLabel->setVisible(v);
    d->kitChooser->setVisible(v);
}

341
342
void DeviceProcessesDialog::setDevice(const IDevice::ConstPtr &device)
{
343
    setKitVisible(false);
344
345
346
347
348
    d->setDevice(device);
}

void DeviceProcessesDialog::showAllDevices()
{
349
    setKitVisible(true);
350
351
352
353
354
355
356
357
    d->updateDevice();
}

DeviceProcess DeviceProcessesDialog::currentProcess() const
{
    return d->selectedProcess();
}

Tobias Hunger's avatar
Tobias Hunger committed
358
KitChooser *DeviceProcessesDialog::kitChooser() const
359
{
Tobias Hunger's avatar
Tobias Hunger committed
360
    return d->kitChooser;
361
362
363
364
365
366
367
368
369
370
371
}

void DeviceProcessesDialog::logMessage(const QString &line)
{
    d->errorText->setVisible(true);
    d->errorText->append(line);
}

} // namespace ProjectExplorer

#include "deviceprocessesdialog.moc"