Add "..." to buttons which open a dialog
[qt-creator:qt-creator.git] / src / plugins / projectexplorer / devicesupport / devicesettingswidget.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and Digia.  For licensing terms and
13 ** conditions see http://qt.digia.com/licensing.  For further information
14 ** use the contact form at http://qt.digia.com/contact-us.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Digia gives you certain additional
25 ** rights.  These rights are described in the Digia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ****************************************************************************/
29 #include "devicesettingswidget.h"
30 #include "ui_devicesettingswidget.h"
31
32 #include "devicefactoryselectiondialog.h"
33 #include "devicemanager.h"
34 #include "devicemanagermodel.h"
35 #include "deviceprocessesdialog.h"
36 #include "devicetestdialog.h"
37 #include "idevice.h"
38 #include "idevicefactory.h"
39 #include "idevicewidget.h"
40 #include <projectexplorer/projectexplorerconstants.h>
41
42 #include <coreplugin/icore.h>
43 #include <extensionsystem/pluginmanager.h>
44 #include <utils/qtcassert.h>
45
46 #include <QPixmap>
47 #include <QPushButton>
48 #include <QSignalMapper>
49 #include <QTextStream>
50
51 #include <algorithm>
52
53 using namespace Core;
54 using namespace Utils;
55
56 namespace ProjectExplorer {
57 namespace Internal {
58 const char LastDeviceIndexKey[] = "LastDisplayedMaemoDeviceConfig";
59
60 class NameValidator : public QValidator
61 {
62 public:
63     NameValidator(const DeviceManager *deviceManager, QWidget *parent = 0)
64         : QValidator(parent), m_deviceManager(deviceManager)
65     {
66     }
67
68     void setDisplayName(const QString &name) { m_oldName = name; }
69
70     virtual State validate(QString &input, int & /* pos */) const
71     {
72         if (input.trimmed().isEmpty()
73                 || (input != m_oldName && m_deviceManager->hasDevice(input)))
74             return Intermediate;
75         return Acceptable;
76     }
77
78     virtual void fixup(QString &input) const
79     {
80         int dummy = 0;
81         if (validate(input, dummy) != Acceptable)
82             input = m_oldName;
83     }
84
85 private:
86     QString m_oldName;
87     const DeviceManager * const m_deviceManager;
88 };
89
90 DeviceSettingsWidget::DeviceSettingsWidget(QWidget *parent)
91     : QWidget(parent),
92       m_ui(new Ui::DeviceSettingsWidget),
93       m_deviceManager(DeviceManager::cloneInstance()),
94       m_deviceManagerModel(new DeviceManagerModel(m_deviceManager, this)),
95       m_nameValidator(new NameValidator(m_deviceManager, this)),
96       m_additionalActionsMapper(new QSignalMapper(this)),
97       m_configWidget(0)
98 {
99     initGui();
100     connect(m_additionalActionsMapper, SIGNAL(mapped(int)),
101             SLOT(handleAdditionalActionRequest(int)));
102     connect(m_deviceManager, SIGNAL(deviceUpdated(Core::Id)), SLOT(handleDeviceUpdated(Core::Id)));
103 }
104
105 DeviceSettingsWidget::~DeviceSettingsWidget()
106 {
107     DeviceManager::removeClonedInstance();
108     delete m_configWidget;
109     delete m_ui;
110 }
111
112 QString DeviceSettingsWidget::searchKeywords() const
113 {
114     QString rc;
115     QTextStream(&rc) << m_ui->configurationLabel->text()
116         << ' ' << m_ui->deviceNameLabel->text()
117         << ' ' << m_ui->nameLineEdit->text()
118         << ' ' << m_ui->autoDetectionKeyLabel->text();
119     return rc.remove(QLatin1Char('&'));
120 }
121
122 void DeviceSettingsWidget::initGui()
123 {
124     m_ui->setupUi(this);
125     m_ui->configurationComboBox->setModel(m_deviceManagerModel);
126     m_ui->nameLineEdit->setValidator(m_nameValidator);
127
128     bool hasDeviceFactories = false;
129     const QList<IDeviceFactory *> &factories
130         = ExtensionSystem::PluginManager::getObjects<IDeviceFactory>();
131     foreach (const IDeviceFactory *f, factories) {
132         if (f->canCreate()) {
133             hasDeviceFactories = true;
134             break;
135         }
136     }
137     m_ui->addConfigButton->setEnabled(hasDeviceFactories);
138
139     int lastIndex = Core::ICore::settings()
140         ->value(QLatin1String(LastDeviceIndexKey), 0).toInt();
141     if (lastIndex == -1)
142         lastIndex = 0;
143     if (lastIndex < m_ui->configurationComboBox->count())
144         m_ui->configurationComboBox->setCurrentIndex(lastIndex);
145     connect(m_ui->configurationComboBox, SIGNAL(currentIndexChanged(int)),
146         SLOT(currentDeviceChanged(int)));
147     currentDeviceChanged(currentIndex());
148     connect(m_ui->defaultDeviceButton, SIGNAL(clicked()),
149         SLOT(setDefaultDevice()));
150 }
151
152 void DeviceSettingsWidget::addDevice()
153 {
154     DeviceFactorySelectionDialog d;
155     if (d.exec() != QDialog::Accepted)
156         return;
157
158     Core::Id toCreate = d.selectedId();
159     if (!toCreate.isValid())
160         return;
161     IDeviceFactory *factory = IDeviceFactory::find(toCreate);
162     if (!factory)
163         return;
164     IDevice::Ptr device = factory->create(toCreate);
165     if (device.isNull())
166         return;
167
168     m_deviceManager->addDevice(device);
169     m_ui->removeConfigButton->setEnabled(true);
170     m_ui->configurationComboBox->setCurrentIndex(m_deviceManagerModel->indexOf(device));
171     if (device->hasDeviceTester())
172         testDevice();
173 }
174
175 void DeviceSettingsWidget::removeDevice()
176 {
177     m_deviceManager->removeDevice(currentDevice()->id());
178     if (m_deviceManager->deviceCount() == 0)
179         currentDeviceChanged(-1);
180 }
181
182 void DeviceSettingsWidget::displayCurrent()
183 {
184     const IDevice::ConstPtr &current = currentDevice();
185     m_ui->defaultDeviceButton->setEnabled(
186         m_deviceManager->defaultDevice(current->type()) != current);
187     m_ui->osTypeValueLabel->setText(current->displayType());
188     m_ui->autoDetectionValueLabel->setText(current->isAutoDetected()
189             ? tr("Yes (id is \"%1\")").arg(current->id().toString()) : tr("No"));
190     m_nameValidator->setDisplayName(current->displayName());
191     m_ui->deviceStateValueIconLabel->show();
192     switch (current->deviceState()) {
193     case IDevice::DeviceReadyToUse:
194         m_ui->deviceStateValueIconLabel->setPixmap(QPixmap(QLatin1String(":/projectexplorer/images/DeviceReadyToUse.png")));
195         break;
196     case IDevice::DeviceConnected:
197         m_ui->deviceStateValueIconLabel->setPixmap(QPixmap(QLatin1String(":/projectexplorer/images/DeviceConnected.png")));
198         break;
199     case IDevice::DeviceDisconnected:
200         m_ui->deviceStateValueIconLabel->setPixmap(QPixmap(QLatin1String(":/projectexplorer/images/DeviceDisconnected.png")));
201         break;
202     case IDevice::DeviceStateUnknown:
203         m_ui->deviceStateValueIconLabel->hide();
204         break;
205     }
206     m_ui->deviceStateValueTextLabel->setText(current->deviceStateToString());
207
208     m_ui->removeConfigButton->setEnabled(!current->isAutoDetected()
209             || current->deviceState() == IDevice::DeviceDisconnected);
210     fillInValues();
211 }
212
213 void DeviceSettingsWidget::setDeviceInfoWidgetsEnabled(bool enable)
214 {
215     m_ui->configurationLabel->setEnabled(enable);
216     m_ui->configurationComboBox->setEnabled(enable);
217     m_ui->generalGroupBox->setEnabled(enable);
218     m_ui->osSpecificGroupBox->setEnabled(enable);
219 }
220
221 void DeviceSettingsWidget::fillInValues()
222 {
223     const IDevice::ConstPtr &current = currentDevice();
224     m_ui->nameLineEdit->setText(current->displayName());
225 }
226
227 void DeviceSettingsWidget::updateDeviceFromUi()
228 {
229     deviceNameEditingFinished();
230     if (m_configWidget)
231         m_configWidget->updateDeviceFromUi();
232 }
233
234 void DeviceSettingsWidget::saveSettings()
235 {
236     Core::ICore::settings()->setValue(QLatin1String(LastDeviceIndexKey), currentIndex());
237     DeviceManager::replaceInstance();
238 }
239
240 int DeviceSettingsWidget::currentIndex() const
241 {
242     return m_ui->configurationComboBox->currentIndex();
243 }
244
245 IDevice::ConstPtr DeviceSettingsWidget::currentDevice() const
246 {
247     Q_ASSERT(currentIndex() != -1);
248     return m_deviceManagerModel->device(currentIndex());
249 }
250
251 void DeviceSettingsWidget::deviceNameEditingFinished()
252 {
253     if (m_ui->configurationComboBox->count() == 0)
254         return;
255
256     const QString &newName = m_ui->nameLineEdit->text();
257     m_deviceManager->mutableDevice(currentDevice()->id())->setDisplayName(newName);
258     m_nameValidator->setDisplayName(newName);
259     m_deviceManagerModel->updateDevice(currentDevice()->id());
260 }
261
262 void DeviceSettingsWidget::setDefaultDevice()
263 {
264     m_deviceManager->setDefaultDevice(currentDevice()->id());
265     m_ui->defaultDeviceButton->setEnabled(false);
266 }
267
268 void DeviceSettingsWidget::testDevice()
269 {
270     const IDevice::ConstPtr &device = currentDevice();
271     QTC_ASSERT(device && device->hasDeviceTester(), return);
272     DeviceTestDialog dlg(device, this);
273     dlg.exec();
274 }
275
276 void DeviceSettingsWidget::handleDeviceUpdated(Id id)
277 {
278     const int index = m_deviceManagerModel->indexForId(id);
279     if (index == currentIndex())
280         currentDeviceChanged(index);
281 }
282
283 void DeviceSettingsWidget::currentDeviceChanged(int index)
284 {
285     qDeleteAll(m_additionalActionButtons);
286     delete m_configWidget;
287     m_configWidget = 0;
288     m_additionalActionButtons.clear();
289     const IDevice::ConstPtr device = m_deviceManagerModel->device(index);
290     if (device.isNull()) {
291         setDeviceInfoWidgetsEnabled(false);
292         m_ui->removeConfigButton->setEnabled(false);
293         clearDetails();
294         m_ui->defaultDeviceButton->setEnabled(false);
295         return;
296     }
297     setDeviceInfoWidgetsEnabled(true);
298     m_ui->removeConfigButton->setEnabled(true);
299
300     if (device->hasDeviceTester()) {
301         QPushButton * const button = new QPushButton(tr("Test"));
302         m_additionalActionButtons << button;
303         connect(button, SIGNAL(clicked()), SLOT(testDevice()));
304         m_ui->buttonsLayout->insertWidget(m_ui->buttonsLayout->count() - 1, button);
305     }
306
307     if (device->canCreateProcessModel()) {
308         QPushButton * const button = new QPushButton(tr("Show Running Processes..."));
309         m_additionalActionButtons << button;
310         connect(button, SIGNAL(clicked()), SLOT(handleProcessListRequested()));
311         m_ui->buttonsLayout->insertWidget(m_ui->buttonsLayout->count() - 1, button);
312     }
313
314     foreach (const Core::Id actionId, device->actionIds()) {
315         QPushButton * const button = new QPushButton(device->displayNameForActionId(actionId));
316         m_additionalActionButtons << button;
317         connect(button, SIGNAL(clicked()), m_additionalActionsMapper, SLOT(map()));
318         m_additionalActionsMapper->setMapping(button, actionId.uniqueIdentifier());
319         m_ui->buttonsLayout->insertWidget(m_ui->buttonsLayout->count() - 1, button);
320     }
321
322     if (!m_ui->osSpecificGroupBox->layout())
323         new QVBoxLayout(m_ui->osSpecificGroupBox);
324     m_configWidget = m_deviceManager->mutableDevice(device->id())->createWidget();
325     if (m_configWidget)
326         m_ui->osSpecificGroupBox->layout()->addWidget(m_configWidget);
327     displayCurrent();
328 }
329
330 void DeviceSettingsWidget::clearDetails()
331 {
332     m_ui->nameLineEdit->clear();
333     m_ui->osTypeValueLabel->clear();
334     m_ui->autoDetectionValueLabel->clear();
335 }
336
337 void DeviceSettingsWidget::handleAdditionalActionRequest(int actionId)
338 {
339     const IDevice::Ptr device = m_deviceManager->mutableDevice(currentDevice()->id());
340     QTC_ASSERT(device, return);
341     updateDeviceFromUi();
342     device->executeAction(Core::Id::fromUniqueIdentifier(actionId), this);
343
344     // Widget must be set up from scratch, because the action could have changed random attributes.
345     currentDeviceChanged(currentIndex());
346 }
347
348 void DeviceSettingsWidget::handleProcessListRequested()
349 {
350     QTC_ASSERT(currentDevice()->canCreateProcessModel(), return);
351     updateDeviceFromUi();
352     DeviceProcessesDialog dlg;
353     dlg.addCloseButton();
354     dlg.setDevice(currentDevice());
355     dlg.exec();
356 }
357
358 } // namespace Internal
359 } // namespace ProjectExplorer