/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** 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://www.qt.io/licensing. For further information ** use the contact form at http://www.qt.io/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 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** 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. ** ****************************************************************************/ #include "winrtdevicefactory.h" #include "winrtconstants.h" #include "winrtdevice.h" #include "winrtqtversion.h" #include #include #include #include #include using Core::MessageManager; using ProjectExplorer::DeviceManager; using ProjectExplorer::IDevice; using QtSupport::BaseQtVersion; using QtSupport::QtVersionManager; namespace WinRt { namespace Internal { WinRtDeviceFactory::WinRtDeviceFactory() : m_process(0) , m_initialized(false) { if (allPrerequisitesLoaded()) { onPrerequisitesLoaded(); } else { connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, this, &WinRtDeviceFactory::onPrerequisitesLoaded, Qt::QueuedConnection); connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsLoaded, this, &WinRtDeviceFactory::onPrerequisitesLoaded, Qt::QueuedConnection); } } QString WinRtDeviceFactory::displayNameForId(Core::Id type) const { return WinRtDevice::displayNameForType(type); } QList WinRtDeviceFactory::availableCreationIds() const { return QList() << Constants::WINRT_DEVICE_TYPE_LOCAL << Constants::WINRT_DEVICE_TYPE_PHONE << Constants::WINRT_DEVICE_TYPE_EMULATOR; } IDevice::Ptr WinRtDeviceFactory::create(Core::Id id) const { Q_UNUSED(id); QTC_CHECK(false); return IDevice::Ptr(); } bool WinRtDeviceFactory::canRestore(const QVariantMap &map) const { return availableCreationIds().contains(IDevice::typeFromMap(map)); } IDevice::Ptr WinRtDeviceFactory::restore(const QVariantMap &map) const { const IDevice::Ptr device(new WinRtDevice); device->fromMap(map); return device; } void WinRtDeviceFactory::autoDetect() { MessageManager::write(tr("Running Windows Runtime device detection.")); const QString runnerFilePath = findRunnerFilePath(); if (runnerFilePath.isEmpty()) { MessageManager::write(tr("No winrtrunner.exe found.")); return; } if (!m_process) { m_process = new Utils::QtcProcess(this); connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(onProcessError())); connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(onProcessFinished(int,QProcess::ExitStatus))); } const QString args = QStringLiteral("--list-devices"); m_process->setCommand(runnerFilePath, args); MessageManager::write(runnerFilePath + QLatin1Char(' ') + args); m_process->start(); } void WinRtDeviceFactory::onPrerequisitesLoaded() { if (!allPrerequisitesLoaded() || m_initialized) return; m_initialized = true; disconnect(DeviceManager::instance(), &DeviceManager::devicesLoaded, this, &WinRtDeviceFactory::onPrerequisitesLoaded); disconnect(QtVersionManager::instance(), &QtVersionManager::qtVersionsLoaded, this, &WinRtDeviceFactory::onPrerequisitesLoaded); autoDetect(); connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, this, &WinRtDeviceFactory::autoDetect); } void WinRtDeviceFactory::onProcessError() { MessageManager::write(tr("Error while executing winrtrunner: %1") .arg(m_process->errorString()), MessageManager::Flash); } void WinRtDeviceFactory::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitStatus == QProcess::CrashExit) { // already handled in onProcessError return; } if (exitCode != 0) { MessageManager::write(tr("winrtrunner returned with exit code %1.") .arg(exitCode), MessageManager::Flash); return; } parseRunnerOutput(m_process->readAllStandardOutput()); } bool WinRtDeviceFactory::allPrerequisitesLoaded() { return QtVersionManager::isLoaded() && DeviceManager::instance()->isLoaded(); } QString WinRtDeviceFactory::findRunnerFilePath() const { const QString winRtQtType = QLatin1String(Constants::WINRT_WINRTQT); const QString winPhoneQtType = QLatin1String(Constants::WINRT_WINPHONEQT); const QString winRtRunnerExe = QStringLiteral("/winrtrunner.exe"); QString filePath; BaseQtVersion *qt = 0; foreach (BaseQtVersion *v, QtVersionManager::versions()) { if (!v->isValid() || (v->type() != winRtQtType && v->type() != winPhoneQtType)) continue; if (!qt || qt->qtVersion() < v->qtVersion()) { QFileInfo fi(v->binPath().toString() + winRtRunnerExe); if (fi.isFile() && fi.isExecutable()) { qt = v; filePath = fi.absoluteFilePath(); } } } return filePath; } static int extractDeviceId(QByteArray *line) { int pos = line->indexOf(' '); if (pos < 0) return -1; bool ok; int id = line->left(pos).toInt(&ok); if (!ok) return -1; line->remove(0, pos + 1); return id; } static IDevice::MachineType machineTypeFromLine(const QByteArray &line) { return line.contains("Emulator ") ? IDevice::Emulator : IDevice::Hardware; } /* * The output of "winrtrunner --list-devices" looks like this: * * Available devices: * Appx: * 0 local * Phone: * 0 Device * 1 Emulator 8.1 WVGA 4 inch 512MB * 2 Emulator 8.1 WVGA 4 inch * 3 Emulator 8.1 WXGA 4 inch * 4 Emulator 8.1 720P 4.7 inch * 5 Emulator 8.1 1080P 5.5 inch * 6 Emulator 8.1 1080P 6 inch * 7 WE8.1H Emulator WVGA 512MB * 8 WE8.1H Emulator WVGA * 9 WE8.1H Emulator WXGA * 10 WE8.1H Emulator 720P * 11 WE8.1H Emulator 1080P * Xap: * 0 Device * 1 Emulator WVGA 512MB * 2 Emulator WVGA * 3 Emulator WXGA * 4 Emulator 720P */ void WinRtDeviceFactory::parseRunnerOutput(const QByteArray &output) const { ProjectExplorer::DeviceManager *deviceManager = ProjectExplorer::DeviceManager::instance(); enum State { StartState, AppxState, PhoneState, XapState }; State state = StartState; int numFound = 0; int numSkipped = 0; foreach (QByteArray line, output.split('\n')) { line = line.trimmed(); if (line == "Appx:") { state = AppxState; } else if (line == "Phone:") { state = PhoneState; } else if (line == "Xap:") { state = XapState; } else { const int deviceId = extractDeviceId(&line); if (deviceId < 0) continue; const IDevice::MachineType machineType = machineTypeFromLine(line); Core::Id deviceType; QString name; QString internalName = QStringLiteral("WinRT."); if (state == AppxState) { internalName += QStringLiteral("appx."); deviceType = Constants::WINRT_DEVICE_TYPE_LOCAL; name = tr("Windows Runtime local UI"); } else if (state == PhoneState) { internalName += QStringLiteral("phone."); name = QString::fromLocal8Bit(line); if (machineType == IDevice::Emulator) deviceType = Constants::WINRT_DEVICE_TYPE_EMULATOR; else deviceType = Constants::WINRT_DEVICE_TYPE_PHONE; } else if (state == XapState) { internalName += QStringLiteral("xap."); name = QString::fromLocal8Bit(line); if (machineType == IDevice::Emulator) deviceType = Constants::WINRT_DEVICE_TYPE_EMULATOR; else deviceType = Constants::WINRT_DEVICE_TYPE_PHONE; } internalName += QString::number(deviceId); const Core::Id internalId = Core::Id::fromString(internalName); ++numFound; if (DeviceManager::instance()->find(internalId)) { ++numSkipped; continue; } WinRtDevice *device = new WinRtDevice(deviceType, machineType, internalId, deviceId); device->setDisplayName(name); deviceManager->addDevice(ProjectExplorer::IDevice::ConstPtr(device)); } } QString message = tr("Found %n Windows Runtime devices.", 0, numFound); if (const int numNew = numFound - numSkipped) { message += QLatin1Char(' '); message += tr("%n of them are new.", 0, numNew); } MessageManager::write(message); } } // Internal } // WinRt