OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt-s60 / s60deployconfigurationwidget.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "s60deployconfigurationwidget.h"
34 #include "s60deployconfiguration.h"
35 #include "s60devicerunconfiguration.h"
36
37 #include "s60runconfigbluetoothstarter.h"
38 #include <symbianutils/bluetoothlistener_gui.h>
39
40 #include <symbianutils/launcher.h>
41 #include <symbianutils/bluetoothlistener.h>
42 #include <symbianutils/symbiandevicemanager.h>
43 #include <codadevice.h>
44
45 #include <coreplugin/helpmanager.h>
46
47 #include "codaruncontrol.h"
48 #include "trkruncontrol.h"
49
50 #include <utils/detailswidget.h>
51 #include <utils/ipaddresslineedit.h>
52 #include <utils/qtcassert.h>
53 #include <utils/pathchooser.h>
54
55 #include <QtCore/QDir>
56 #include <QtCore/QTimer>
57 #include <QtGui/QLabel>
58 #include <QtGui/QLineEdit>
59 #include <QtGui/QComboBox>
60 #include <QtGui/QVBoxLayout>
61 #include <QtGui/QHBoxLayout>
62 #include <QtGui/QFormLayout>
63 #include <QtGui/QToolButton>
64 #include <QtGui/QStyle>
65 #include <QtGui/QApplication>
66 #include <QtGui/QSpacerItem>
67 #include <QtGui/QMessageBox>
68 #include <QtGui/QCheckBox>
69 #include <QtGui/QGroupBox>
70 #include <QtGui/QRadioButton>
71 #include <QtGui/QValidator>
72
73 #include <QtNetwork/QTcpSocket>
74
75 Q_DECLARE_METATYPE(SymbianUtils::SymbianDevice)
76
77 namespace Qt4ProjectManager {
78 namespace Internal {
79
80 const char STARTING_DRIVE_LETTER = 'C';
81 const char LAST_DRIVE_LETTER = 'Z';
82
83 static const quint32 CODA_UID = 0x20021F96;
84 static const quint32 QTMOBILITY_UID = 0x2002AC89;
85
86 QString formatDriveText(const S60DeployConfiguration::DeviceDrive &drive)
87 {
88     char driveLetter = QChar::toUpper(static_cast<ushort>(drive.first));
89     if (drive.second <= 0)
90         return QString("%1:").arg(driveLetter);
91     if (drive.second >= 1024)
92         return QString("%1:%2 MB").arg(driveLetter).arg(drive.second);
93     return QString("%1:%2 kB").arg(driveLetter).arg(drive.second);
94 }
95
96 void startTable(QString &text)
97 {
98     const char startTableC[] = "<html></head><body><table>";
99     if (text.contains(startTableC))
100         return;
101     text.append(startTableC);
102 }
103
104 void finishTable(QString &text)
105 {
106     const char stopTableC[] = "</table></body></html>";
107     text.replace(stopTableC, QLatin1String(""));
108     text.append(stopTableC);
109 }
110
111 void addToTable(QTextStream &stream, const QString &key, const QString &value)
112 {
113     const char tableRowStartC[] = "<tr><td><b>";
114     const char tableRowSeparatorC[] = "</b></td><td>";
115     const char tableRowEndC[] = "</td></tr>";
116     stream << tableRowStartC << key << tableRowSeparatorC << value << tableRowEndC;
117 }
118
119 void addErrorToTable(QTextStream &stream, const QString &key, const QString &value)
120 {
121     const char tableRowStartC[] = "<tr><td><b>";
122     const char tableRowSeparatorC[] = "</b></td><td>";
123     const char tableRowEndC[] = "</td></tr>";
124     const char errorSpanStartC[] = "<span style=\"font-weight:600; color:red; \">";
125     const char errorSpanEndC[] = "</span>";
126     stream << tableRowStartC << errorSpanStartC << key << tableRowSeparatorC << value << errorSpanEndC << tableRowEndC;
127 }
128
129 S60DeployConfigurationWidget::S60DeployConfigurationWidget(QWidget *parent)
130     : ProjectExplorer::DeployConfigurationWidget(parent),
131       m_detailsWidget(new Utils::DetailsWidget),
132       m_serialPortsCombo(new QComboBox),
133       m_sisFileLabel(new QLabel),
134       m_deviceInfoButton(new QToolButton),
135       m_deviceInfoDescriptionLabel(new QLabel(tr("Device:"))),
136       m_deviceInfoLabel(new QLabel),
137       m_installationDriveCombo(new QComboBox()),
138       m_silentInstallCheckBox(new QCheckBox(tr("Silent installation"))),
139       m_serialRadioButton(new QRadioButton(tr("Serial:"))),
140       m_wlanRadioButton(new QRadioButton(tr("WLAN:"))),
141       m_ipAddress(new Utils::IpAddressLineEdit),
142       m_trkRadioButton(new QRadioButton(tr("TRK"))),
143       m_codaRadioButton(new QRadioButton(tr("CODA"))),
144       m_codaInfoLabel(new QLabel(tr("<a href=\"qthelp://com.nokia.qtcreator/doc/creator-developing-symbian.html\">What are the prerequisites?</a>"))),
145       m_codaTimeout(new QTimer(this))
146 {
147 }
148
149 S60DeployConfigurationWidget::~S60DeployConfigurationWidget()
150 {
151 }
152
153 void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc)
154 {
155     m_deployConfiguration = qobject_cast<S60DeployConfiguration *>(dc);
156
157     m_detailsWidget->setState(Utils::DetailsWidget::NoSummary);
158
159     QVBoxLayout *mainBoxLayout = new QVBoxLayout();
160     mainBoxLayout->setMargin(0);
161     setLayout(mainBoxLayout);
162     mainBoxLayout->addWidget(m_detailsWidget);
163     QWidget *detailsContainer = new QWidget;
164     m_detailsWidget->setWidget(detailsContainer);
165
166     QVBoxLayout *detailsBoxLayout = new QVBoxLayout();
167     detailsBoxLayout->setMargin(0);
168     detailsContainer->setLayout(detailsBoxLayout);
169
170     QFormLayout *formLayout = new QFormLayout();
171     formLayout->setMargin(0);
172     detailsBoxLayout->addLayout(formLayout);
173     formLayout->addRow(tr("Installation file:"), m_sisFileLabel);
174
175     // Installation Drive control
176     updateInstallationDrives();
177
178     QHBoxLayout *installationBoxLayout = new QHBoxLayout();
179     m_installationDriveCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
180     connect(m_installationDriveCombo, SIGNAL(activated(int)), this, SLOT(setInstallationDrive(int)));
181     QHBoxLayout *installationDriveHBoxLayout = new QHBoxLayout;
182     installationDriveHBoxLayout->addWidget(m_installationDriveCombo);
183     installationBoxLayout->addLayout(installationDriveHBoxLayout);
184
185     // Non-silent installs are a fallback if one wants to override missing dependencies.
186     m_silentInstallCheckBox->setChecked(m_deployConfiguration->silentInstall());
187     m_silentInstallCheckBox->setToolTip(tr("Silent installation is an installation mode "
188                                            "that does not require user's intervention. "
189                                            "In case it fails the non silent installation is launched."));
190     connect(m_silentInstallCheckBox, SIGNAL(stateChanged(int)), this, SLOT(silentInstallChanged(int)));
191     installationBoxLayout->addWidget(m_silentInstallCheckBox);
192     installationBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
193     formLayout->addRow(tr("Installation drive:"), installationBoxLayout);
194
195     updateSerialDevices();
196     connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(updated()),
197             this, SLOT(updateSerialDevices()));
198
199     //Debug Client
200     QVBoxLayout *debugClientContentVBoxLayout = new QVBoxLayout;
201     debugClientContentVBoxLayout->addWidget(m_codaInfoLabel);
202
203     QHBoxLayout *debugClientHBoxLayout = new QHBoxLayout;
204     debugClientContentVBoxLayout->addLayout(debugClientHBoxLayout);
205
206     QVBoxLayout *debugClientVBoxLayout = new QVBoxLayout;
207     debugClientVBoxLayout->addWidget(m_trkRadioButton);
208     debugClientVBoxLayout->addWidget(m_codaRadioButton);
209
210     debugClientVBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding));
211
212     debugClientHBoxLayout->addLayout(debugClientVBoxLayout);
213
214     debugClientHBoxLayout->addWidget(createCommunicationChannel());
215     debugClientHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
216
217     QGroupBox *debugClientGroupBox = new QGroupBox(tr("Device Agent"));
218     debugClientGroupBox->setLayout(debugClientContentVBoxLayout);
219
220     bool usingTrk = m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection;
221     m_trkRadioButton->setChecked(usingTrk);
222     m_codaRadioButton->setChecked(!usingTrk);
223
224     bool usingTcp = m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationCodaTcpConnection;
225     m_serialRadioButton->setChecked(!usingTcp);
226     m_wlanRadioButton->setChecked(usingTcp);
227
228     connect(m_trkRadioButton, SIGNAL(clicked()), this, SLOT(updateCommunicationChannel()));
229     connect(m_codaRadioButton, SIGNAL(clicked()), this, SLOT(updateCommunicationChannel()));
230     connect(m_codaInfoLabel, SIGNAL(linkActivated(QString)),
231             Core::HelpManager::instance(), SLOT(handleHelpRequest(QString)));
232
233     formLayout->addRow(debugClientGroupBox);
234
235     // Device Info with button. Widgets are enabled in above call to updateSerialDevices()
236     QHBoxLayout *infoHBoxLayout = new QHBoxLayout;
237     m_deviceInfoLabel->setWordWrap(true);
238     m_deviceInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
239     m_deviceInfoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
240     infoHBoxLayout->addWidget(m_deviceInfoLabel);
241     infoHBoxLayout->addWidget(m_deviceInfoButton);
242     m_deviceInfoButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation));
243     m_deviceInfoButton->setToolTip(tr("Queries the device for information"));
244     connect(m_deviceInfoButton, SIGNAL(clicked()), this, SLOT(updateDeviceInfo()));
245     formLayout->addRow(m_deviceInfoDescriptionLabel, infoHBoxLayout);
246     updateTargetInformation();
247     connect(m_deployConfiguration, SIGNAL(targetInformationChanged()),
248             this, SLOT(updateTargetInformation()));
249     connect(m_deployConfiguration, SIGNAL(availableDeviceDrivesChanged()),
250             this, SLOT(updateInstallationDrives()));
251     connect(this, SIGNAL(infoCollected()),
252             this, SLOT(collectingInfoFinished()));
253
254     m_codaTimeout->setSingleShot(true);
255     connect(m_codaTimeout, SIGNAL(timeout()), this, SLOT(codaTimeout()));
256 }
257
258 QWidget *S60DeployConfigurationWidget::createCommunicationChannel()
259 {
260     m_serialPortsCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
261     connect(m_serialPortsCombo, SIGNAL(activated(int)), this, SLOT(setSerialPort(int)));
262     connect(m_serialRadioButton, SIGNAL(clicked()), this, SLOT(updateCommunicationChannel()));
263     connect(m_wlanRadioButton, SIGNAL(clicked()), this, SLOT(updateCommunicationChannel()));
264     connect(m_ipAddress, SIGNAL(validAddressChanged(QString)), this, SLOT(updateWlanAddress(QString)));
265     connect(m_ipAddress, SIGNAL(invalidAddressChanged()), this, SLOT(cleanWlanAddress()));
266
267     QHBoxLayout *serialPortHBoxLayout = new QHBoxLayout;
268     serialPortHBoxLayout->addWidget(new QLabel(tr("Serial port:")));
269     serialPortHBoxLayout->addWidget(m_serialPortsCombo);
270     serialPortHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
271
272 #ifndef Q_OS_WIN
273     // Update device list: on Linux only.
274     QToolButton *updateSerialDevicesButton(new QToolButton);
275     updateSerialDevicesButton->setIcon(qApp->style()->standardIcon(QStyle::SP_BrowserReload));
276     connect(updateSerialDevicesButton, SIGNAL(clicked()),
277             SymbianUtils::SymbianDeviceManager::instance(), SLOT(update()));
278     serialPortHBoxLayout->addWidget(updateSerialDevicesButton);
279 #endif
280
281     QGroupBox *communicationChannelGroupBox = new QGroupBox(tr("Communication Channel"));
282     QGridLayout *communicationChannelGridLayout = new QGridLayout;
283     communicationChannelGridLayout->addWidget(m_serialRadioButton, 0, 0);
284     communicationChannelGridLayout->addWidget(m_wlanRadioButton, 1, 0);
285
286     m_ipAddress->setMinimumWidth(30);
287     m_ipAddress->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
288
289     if(!m_deployConfiguration->deviceAddress().isEmpty())
290         m_ipAddress->setText(QString("%1:%2")
291                              .arg(m_deployConfiguration->deviceAddress())
292                              .arg(m_deployConfiguration->devicePort()));
293
294     QHBoxLayout *wlanChannelLayout = new QHBoxLayout();
295     wlanChannelLayout->addWidget(new QLabel(tr("Address:")));
296     wlanChannelLayout->addWidget(m_ipAddress);
297     wlanChannelLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
298
299     communicationChannelGridLayout->addLayout(serialPortHBoxLayout, 0, 1);
300     communicationChannelGridLayout->addLayout(wlanChannelLayout, 1, 1);
301
302     communicationChannelGroupBox->setLayout(communicationChannelGridLayout);
303
304     updateCommunicationChannelUi();
305
306     return communicationChannelGroupBox;
307 }
308
309 void S60DeployConfigurationWidget::updateInstallationDrives()
310 {
311     m_installationDriveCombo->clear();
312     const QList<S60DeployConfiguration::DeviceDrive> &availableDrives(m_deployConfiguration->availableDeviceDrives());
313     int index = 0;
314     char currentDrive = QChar::toUpper(static_cast<ushort>(m_deployConfiguration->installationDrive()));
315     if (availableDrives.isEmpty()) {
316         for (int i = STARTING_DRIVE_LETTER; i <= LAST_DRIVE_LETTER; ++i) {
317             m_installationDriveCombo->addItem(QString("%1:").arg(static_cast<char>(i)), QChar(i));
318         }
319         index = currentDrive - STARTING_DRIVE_LETTER;
320     } else {
321         for (int i = 0; i < availableDrives.count(); ++i) {
322             const S60DeployConfiguration::DeviceDrive& drive(availableDrives.at(i));
323             char driveLetter = QChar::toUpper(static_cast<ushort>(drive.first));
324             m_installationDriveCombo->addItem(formatDriveText(drive),
325                                               QChar(driveLetter));
326             if (currentDrive == driveLetter)
327                 index = i;
328         }
329     }
330     QTC_ASSERT(index >= 0 && index <= m_installationDriveCombo->count(), return);
331
332     m_installationDriveCombo->setCurrentIndex(index);
333     setInstallationDrive(index);
334 }
335
336 void S60DeployConfigurationWidget::silentInstallChanged(int state)
337 {
338     m_deployConfiguration->setSilentInstall(state == Qt::Checked);
339 }
340
341 void S60DeployConfigurationWidget::updateSerialDevices()
342 {
343     m_serialPortsCombo->clear();
344     const QString previouPortName = m_deployConfiguration->serialPortName();
345     const QList<SymbianUtils::SymbianDevice> devices = SymbianUtils::SymbianDeviceManager::instance()->devices();
346     int newIndex = -1;
347     for (int i = 0; i < devices.size(); ++i) {
348         const SymbianUtils::SymbianDevice &device = devices.at(i);
349         m_serialPortsCombo->addItem(device.friendlyName(), qVariantFromValue(device));
350         if (device.portName() == previouPortName)
351             newIndex = i;
352     }
353
354     if(m_deployConfiguration->communicationChannel()
355             == S60DeployConfiguration::CommunicationCodaTcpConnection) {
356         m_deviceInfoButton->setEnabled(true);
357         return;
358     }
359
360     clearDeviceInfo();
361     // Set new index: prefer to keep old or set to 0, if available.
362     if (newIndex == -1 && !devices.empty())
363         newIndex = 0;
364     m_serialPortsCombo->setCurrentIndex(newIndex);
365     if (newIndex == -1) {
366         m_deviceInfoButton->setEnabled(false);
367         m_deployConfiguration->setSerialPortName(QString());
368     } else {
369         m_deviceInfoButton->setEnabled(true);
370         const QString newPortName = device(newIndex).portName();
371         m_deployConfiguration->setSerialPortName(newPortName);
372     }
373 }
374
375 SymbianUtils::SymbianDevice S60DeployConfigurationWidget::device(int i) const
376 {
377     const QVariant data = m_serialPortsCombo->itemData(i);
378     if (data.isValid() && qVariantCanConvert<SymbianUtils::SymbianDevice>(data))
379         return qVariantValue<SymbianUtils::SymbianDevice>(data);
380     return SymbianUtils::SymbianDevice();
381 }
382
383 SymbianUtils::SymbianDevice S60DeployConfigurationWidget::currentDevice() const
384 {
385     return device(m_serialPortsCombo->currentIndex());
386 }
387
388 void S60DeployConfigurationWidget::updateTargetInformation()
389 {
390     QString package;
391     for (int i = 0; i < m_deployConfiguration->signedPackages().count(); ++i)
392         package += m_deployConfiguration->signedPackages()[i] + QLatin1String("\n");
393     if (!package.isEmpty())
394         package.remove(package.length()-1, 1);
395     m_sisFileLabel->setText(QDir::toNativeSeparators(package));
396 }
397
398 void S60DeployConfigurationWidget::setInstallationDrive(int index)
399 {
400     QTC_ASSERT(index >= 0, return);
401     QTC_ASSERT(index < m_installationDriveCombo->count(), return);
402
403     QChar driveLetter(m_installationDriveCombo->itemData(index).toChar());
404     m_deployConfiguration->setInstallationDrive(driveLetter.toAscii());
405 }
406
407 void S60DeployConfigurationWidget::setSerialPort(int index)
408 {
409     const SymbianUtils::SymbianDevice d = device(index);
410     m_deployConfiguration->setSerialPortName(d.portName());
411     m_deviceInfoButton->setEnabled(index >= 0);
412     clearDeviceInfo();
413 }
414
415 void S60DeployConfigurationWidget::updateCommunicationChannelUi()
416 {
417     S60DeployConfiguration::CommunicationChannel channel = m_deployConfiguration->communicationChannel();
418     if (channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
419         m_trkRadioButton->setChecked(true);
420         m_codaRadioButton->setChecked(false);
421         m_serialRadioButton->setChecked(true);
422         m_wlanRadioButton->setDisabled(true);
423         m_ipAddress->setDisabled(true);
424         m_serialPortsCombo->setDisabled(false);
425         updateSerialDevices();
426     } else {
427         m_trkRadioButton->setChecked(false);
428         m_codaRadioButton->setChecked(true);
429         m_wlanRadioButton->setDisabled(false);
430         if (channel == S60DeployConfiguration::CommunicationCodaTcpConnection) {
431             m_ipAddress->setDisabled(false);
432             m_serialPortsCombo->setDisabled(true);
433             m_deviceInfoButton->setEnabled(true);
434         } else {
435             m_ipAddress->setDisabled(true);
436             m_serialPortsCombo->setDisabled(false);
437             updateSerialDevices();
438         }
439     }
440 }
441
442 void S60DeployConfigurationWidget::updateCommunicationChannel()
443 {
444     if (!m_trkRadioButton->isChecked() && !m_codaRadioButton->isChecked())
445         m_trkRadioButton->setChecked(true);
446
447     if (m_trkRadioButton->isChecked()) {
448         m_serialRadioButton->setChecked(true);
449         m_wlanRadioButton->setDisabled(true);
450         m_ipAddress->setDisabled(true);
451         m_serialPortsCombo->setDisabled(false);
452         m_deployConfiguration->setCommunicationChannel(S60DeployConfiguration::CommunicationTrkSerialConnection);
453         updateSerialDevices();
454     } else if (m_codaRadioButton->isChecked()) {
455         if (!m_wlanRadioButton->isChecked() && !m_serialRadioButton->isChecked())
456             m_serialRadioButton->setChecked(true);
457         m_wlanRadioButton->setDisabled(false);
458
459         if (m_wlanRadioButton->isChecked()) {
460             m_ipAddress->setDisabled(false);
461             m_serialPortsCombo->setDisabled(true);
462             m_deployConfiguration->setCommunicationChannel(S60DeployConfiguration::CommunicationCodaTcpConnection);
463             m_deviceInfoButton->setEnabled(true);
464         } else {
465             m_ipAddress->setDisabled(true);
466             m_serialPortsCombo->setDisabled(false);
467             m_deployConfiguration->setCommunicationChannel(S60DeployConfiguration::CommunicationCodaSerialConnection);
468             updateSerialDevices();
469         }
470     }
471 }
472
473 void S60DeployConfigurationWidget::updateWlanAddress(const QString &address)
474 {
475     QStringList addressList = address.split(QLatin1String(":"), QString::SkipEmptyParts);
476     if (addressList.count() > 0) {
477         m_deployConfiguration->setDeviceAddress(addressList.at(0));
478         if (addressList.count() > 1)
479             m_deployConfiguration->setDevicePort(addressList.at(1));
480         else
481             m_deployConfiguration->setDevicePort(QString());
482     }
483 }
484
485 void S60DeployConfigurationWidget::cleanWlanAddress()
486 {
487     if (!m_deployConfiguration->deviceAddress().isEmpty())
488         m_deployConfiguration->setDeviceAddress(QString());
489
490     if (!m_deployConfiguration->devicePort().isEmpty())
491         m_deployConfiguration->setDevicePort(QString());
492 }
493
494 void S60DeployConfigurationWidget::clearDeviceInfo()
495 {
496     // Restore text & color
497     m_deviceInfoLabel->clear();
498     m_deviceInfoLabel->setStyleSheet(QString());
499 }
500
501 void S60DeployConfigurationWidget::setDeviceInfoLabel(const QString &message, bool isError)
502 {
503     m_deviceInfoLabel->setStyleSheet(isError ?
504                                          QString(QLatin1String("background-color: red;")) :
505                                          QString());
506     m_deviceInfoLabel->setText(message);
507     m_deviceInfoLabel->adjustSize();
508 }
509
510 void S60DeployConfigurationWidget::slotLauncherStateChanged(int s)
511 {
512     switch (s) {
513     case trk::Launcher::WaitingForTrk: {
514         // Entered trk wait state..open message box
515         QMessageBox *mb = TrkRunControl::createTrkWaitingMessageBox(m_infoLauncher->trkServerName(), this);
516         connect(m_infoLauncher, SIGNAL(stateChanged(int)), mb, SLOT(close()));
517         connect(mb, SIGNAL(finished(int)), this, SLOT(slotWaitingForTrkClosed()));
518         mb->open();
519     }
520     break;
521     case trk::Launcher::DeviceDescriptionReceived: // All ok, done
522         setDeviceInfoLabel(m_infoLauncher->deviceDescription());
523         m_deviceInfoButton->setEnabled(true);
524         m_infoLauncher->deleteLater();
525         break;
526     }
527 }
528
529 void S60DeployConfigurationWidget::slotWaitingForTrkClosed()
530 {
531     if (m_infoLauncher && m_infoLauncher->state() == trk::Launcher::WaitingForTrk) {
532         m_infoLauncher->deleteLater();
533         clearDeviceInfo();
534         m_deviceInfoButton->setEnabled(true);
535     }
536 }
537
538 void S60DeployConfigurationWidget::updateDeviceInfo()
539 {
540     setDeviceInfoLabel(tr("Connecting"));
541     if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection) {
542         QTC_ASSERT(!m_infoLauncher, return)
543
544         // Do a launcher run with the ping protocol. Prompt to connect and
545         // go asynchronous afterwards to pop up launch trk box if a timeout occurs.
546         QString message;
547         const SymbianUtils::SymbianDevice commDev = currentDevice();
548         m_infoLauncher = trk::Launcher::acquireFromDeviceManager(commDev.portName(), this, &message);
549         if (!m_infoLauncher) {
550             setDeviceInfoLabel(message, true);
551             return;
552         }
553         connect(m_infoLauncher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
554
555         m_infoLauncher->setSerialFrame(commDev.type() == SymbianUtils::SerialPortCommunication);
556         m_infoLauncher->setTrkServerName(commDev.portName());
557
558         // Prompt user
559         const trk::PromptStartCommunicationResult src =
560                 S60RunConfigBluetoothStarter::startCommunication(m_infoLauncher->trkDevice(),
561                                                                  this, &message);
562         switch (src) {
563         case trk::PromptStartCommunicationConnected:
564             break;
565         case trk::PromptStartCommunicationCanceled:
566             clearDeviceInfo();
567             m_infoLauncher->deleteLater();
568             return;
569         case trk::PromptStartCommunicationError:
570             setDeviceInfoLabel(message, true);
571             m_infoLauncher->deleteLater();
572             return;
573         };
574         if (!m_infoLauncher->startServer(&message)) {
575             setDeviceInfoLabel(message, true);
576             m_infoLauncher->deleteLater();
577             return;
578         }
579         // Wait for either timeout or results
580         m_deviceInfoButton->setEnabled(false);
581     } else if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationCodaSerialConnection) {
582         const SymbianUtils::SymbianDevice commDev = currentDevice();
583         m_codaInfoDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(commDev.portName());
584         if (m_codaInfoDevice.isNull()) {
585             setDeviceInfoLabel(tr("Unable to create CODA connection. Please try again."), true);
586             return;
587         }
588         if (!m_codaInfoDevice->device()->isOpen()) {
589             setDeviceInfoLabel(m_codaInfoDevice->device()->errorString(), true);
590             return;
591         }
592         //TODO error handling - for now just throw the command at coda
593         m_codaInfoDevice->sendSymbianOsDataGetQtVersionCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getQtVersionCommandResult));
594         m_deviceInfoButton->setEnabled(false);
595         m_codaTimeout->start(1000);
596     } else if(m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationCodaTcpConnection) {
597         // collectingInfoFinished, which deletes m_codaDevice, can get called from within a coda callback, so need to use deleteLater
598         m_codaInfoDevice =  QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice, &QObject::deleteLater);
599         connect(m_codaInfoDevice.data(), SIGNAL(tcfEvent(Coda::CodaEvent)), this, SLOT(codaEvent(Coda::CodaEvent)));
600
601         const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
602         m_codaInfoDevice->setDevice(codaSocket);
603         codaSocket->connectToHost(m_deployConfiguration->deviceAddress(),
604                                   m_deployConfiguration->devicePort().toInt());
605         m_deviceInfoButton->setEnabled(false);
606         m_codaTimeout->start(1500);
607     } else
608         setDeviceInfoLabel(tr("Currently there is no information about the device for this connection type."), true);
609 }
610
611 void S60DeployConfigurationWidget::codaEvent(const Coda::CodaEvent &event)
612 {
613     switch (event.type()) {
614     case Coda::CodaEvent::LocatorHello: // Commands accepted now
615         codaIncreaseProgress();
616         m_codaInfoDevice->sendSymbianOsDataGetQtVersionCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getQtVersionCommandResult));
617         break;
618     default:
619         break;
620     }
621 }
622
623 void S60DeployConfigurationWidget::getQtVersionCommandResult(const Coda::CodaCommandResult &result)
624 {
625     m_deviceInfo.clear();
626     if (result.type == Coda::CodaCommandResult::FailReply) {
627         setDeviceInfoLabel(tr("No device information available"), true);
628         SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaInfoDevice);
629         m_deviceInfoButton->setEnabled(true);
630         m_codaTimeout->stop();
631         return;
632     } else if (result.type == Coda::CodaCommandResult::CommandErrorReply){
633         startTable(m_deviceInfo);
634         QTextStream str(&m_deviceInfo);
635         addErrorToTable(str, tr("Qt version: "), tr("Not installed on device"));
636         finishTable(m_deviceInfo);
637     } else {
638         if (result.values.count()) {
639             QHash<QString, QVariant> obj = result.values[0].toVariant().toHash();
640             QString ver = obj.value("qVersion").toString();
641
642             startTable(m_deviceInfo);
643             QTextStream str(&m_deviceInfo);
644             addToTable(str, tr("Qt version:"), ver);
645             QString systemVersion;
646
647             int symVer = obj.value("symbianVersion").toInt();
648             // Ugh why won't QSysInfo define these on non-symbian builds...
649             switch (symVer) {
650             case 10:
651                 systemVersion.append("Symbian OS v9.2");
652                 break;
653             case 20:
654                 systemVersion.append("Symbian OS v9.3");
655                 break;
656             case 30:
657                 systemVersion.append("Symbian OS v9.4 / Symbian^1");
658                 break;
659             case 40:
660                 systemVersion.append("Symbian^2");
661                 break;
662             case 50:
663                 systemVersion.append("Symbian^3");
664                 break;
665             case 60:
666                 systemVersion.append("Symbian^4");
667                 break;
668             default:
669                 systemVersion.append(tr("Unrecognised Symbian version 0x%1").arg(symVer, 0, 16));
670                 break;
671             }
672             systemVersion.append(", ");
673             int s60Ver = obj.value("s60Version").toInt();
674             switch (s60Ver) {
675             case 10:
676                 systemVersion.append("S60 3rd Edition Feature Pack 1");
677                 break;
678             case 20:
679                 systemVersion.append("S60 3rd Edition Feature Pack 2");
680                 break;
681             case 30:
682                 systemVersion.append("S60 5th Edition");
683                 break;
684             case 40:
685                 systemVersion.append("S60 5th Edition Feature Pack 1");
686                 break;
687             case 50:
688                 systemVersion.append("S60 5th Edition Feature Pack 2");
689                 break;
690             default:
691                 systemVersion.append(tr("Unrecognised S60 version 0x%1").arg(symVer, 0, 16));
692                 break;
693             }
694             addToTable(str, tr("OS version:"), systemVersion);
695             finishTable(m_deviceInfo);
696         }
697     }
698     codaIncreaseProgress();
699     m_codaInfoDevice->sendSymbianOsDataGetRomInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getRomInfoResult));
700 }
701
702 void S60DeployConfigurationWidget::getRomInfoResult(const Coda::CodaCommandResult &result)
703 {
704     codaIncreaseProgress();
705     if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
706         startTable(m_deviceInfo);
707         QTextStream str(&m_deviceInfo);
708
709         QVariantHash obj = result.values[0].toVariant().toHash();
710         QString romVersion = obj.value("romVersion", tr("unknown")).toString();
711         romVersion.replace('\n', " "); // The ROM string is split across multiple lines, for some reason.
712         addToTable(str, tr("ROM version:"), romVersion);
713
714         QString pr = obj.value("prInfo").toString();
715         if (pr.length())
716             addToTable(str, tr("Release:"), pr);
717         finishTable(m_deviceInfo);
718     }
719
720     QList<quint32> packagesOfInterest;
721     packagesOfInterest.append(CODA_UID);
722     packagesOfInterest.append(QTMOBILITY_UID);
723     m_codaInfoDevice->sendSymbianInstallGetPackageInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getInstalledPackagesResult), packagesOfInterest);
724 }
725
726 void S60DeployConfigurationWidget::getInstalledPackagesResult(const Coda::CodaCommandResult &result)
727 {
728     codaIncreaseProgress();
729     if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
730         startTable(m_deviceInfo);
731         QTextStream str(&m_deviceInfo);
732
733         QVariantList resultsList = result.values[0].toVariant().toList();
734         foreach (const QVariant& var, resultsList) {
735             QVariantHash obj = var.toHash();
736             bool ok = false;
737             uint uid = obj.value("uid").toString().toUInt(&ok, 16);
738             if (ok) {
739                 bool error = !obj.value("error").isNull();
740                 QString versionString;
741                 if (!error) {
742                     QVariantList version = obj.value("version").toList();
743                     versionString = QString("%1.%2.%3").arg(version[0].toInt())
744                             .arg(version[1].toInt())
745                             .arg(version[2].toInt());
746                 }
747                 switch (uid) {
748                 case CODA_UID: {
749                     if (error) {
750                         // How can coda not be installed? Presumably some UID wrongness...
751                         addErrorToTable(str, tr("CODA version: "), tr("Error reading CODA version"));
752                     } else
753                         addToTable(str, tr("CODA version: "), versionString);
754                 }
755                 break;
756                 case QTMOBILITY_UID: {
757                     if (error)
758                         addErrorToTable(str, tr("QtMobility version: "), tr("Error reading QtMobility version"));
759                     else
760                         addToTable(str, tr("QtMobility version: "), versionString);
761                 }
762                 break;
763                 default: break;
764                 }
765             }
766         }
767         finishTable(m_deviceInfo);
768     }
769
770     QStringList keys;
771     keys << QLatin1String("EDisplayXPixels");
772     keys << QLatin1String("EDisplayYPixels");
773     //keys << "EMemoryRAMFree";
774     m_codaInfoDevice->sendSymbianOsDataGetHalInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getHalResult), keys);
775 }
776
777 void S60DeployConfigurationWidget::getHalResult(const Coda::CodaCommandResult &result)
778 {
779     codaIncreaseProgress();
780     if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
781         QVariantList resultsList = result.values[0].toVariant().toList();
782         int x = 0;
783         int y = 0;
784         foreach (const QVariant& var, resultsList) {
785             QVariantHash obj = var.toHash();
786             if (obj.value("name").toString() == "EDisplayXPixels")
787                 x = obj.value("value").toInt();
788             else if (obj.value("name").toString() == "EDisplayYPixels")
789                 y = obj.value("value").toInt();
790         }
791         if (x && y) {
792             startTable(m_deviceInfo);
793             QTextStream str(&m_deviceInfo);
794             addToTable(str, tr("Screen size:"), QString("%1x%2").arg(x).arg(y));
795             finishTable(m_deviceInfo);
796         }
797     }
798
799     // Done with collecting info
800     emit infoCollected();
801 }
802
803 void S60DeployConfigurationWidget::codaIncreaseProgress()
804 {
805     m_codaTimeout->start();
806     setDeviceInfoLabel(m_deviceInfoLabel->text() + '.');
807 }
808
809 void S60DeployConfigurationWidget::collectingInfoFinished()
810 {
811     m_codaTimeout->stop();
812     emit codaConnected();
813     m_deviceInfoButton->setEnabled(true);
814     setDeviceInfoLabel(m_deviceInfo);
815     SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaInfoDevice);
816 }
817
818 void S60DeployConfigurationWidget::codaTimeout()
819 {
820     QMessageBox *mb = CodaRunControl::createCodaWaitingMessageBox(this);
821     connect(this, SIGNAL(codaConnected()), mb, SLOT(close()));
822     connect(mb, SIGNAL(finished(int)), this, SLOT(codaCanceled()));
823     mb->open();
824 }
825
826 void S60DeployConfigurationWidget::codaCanceled()
827 {
828     clearDeviceInfo();
829     m_deviceInfoButton->setEnabled(true);
830     SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaInfoDevice);
831 }
832
833 } // namespace Internal
834 } // namespace Qt4ProjectManager