diff --git a/firsttimewizard.cpp b/firsttimewizard.cpp index d4b9ab1..fd67628 100644 --- a/firsttimewizard.cpp +++ b/firsttimewizard.cpp @@ -1,429 +1,439 @@ /* * This file is part of KDevelop project * Copyright 2016 Patrick José Pereira * Copyright 2010 Denis Martinez * Copyright 2010 Martin Peres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "firsttimewizard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "toolkit.h" Q_LOGGING_CATEGORY(FtwIo, "Kdev.embedded.ftw.io") Q_LOGGING_CATEGORY(FtwMsg, "Kdev.embedded.ftw.msg") using namespace KDevelop; #ifdef Q_OS_DARWIN QString FirstTimeWizard::downloadOsUrl = QStringLiteral("macosx"); QString FirstTimeWizard::downloadExtensionUrl = QStringLiteral("zip"); #elif defined(Q_OS_WIN32) || defined(Q_OS_WIN64) QString FirstTimeWizard::downloadOsUrl = QStringLiteral("windows"); QString FirstTimeWizard::downloadExtensionUrl = QStringLiteral("zip"); #else QString FirstTimeWizard::downloadOsUrl = QStringLiteral("linux"); QString FirstTimeWizard::downloadExtensionUrl = QStringLiteral("tar.xz"); #endif #ifdef Q_OS_WIN32 QString FirstTimeWizard::downloadArchUrl = QStringLiteral("32"); #else QString FirstTimeWizard::downloadArchUrl = QStringLiteral("64"); #endif QString FirstTimeWizard::arduinoDownloadUrl = QStringLiteral("https://downloads.arduino.cc/arduino-%0-%1.%2") .arg(QStringLiteral(ARDUINO_SDK_VERSION_NAME)) .arg(downloadOsUrl+downloadArchUrl) .arg(downloadExtensionUrl); FirstTimeWizard::FirstTimeWizard(QWidget *parent) : QWizard(parent), m_mDownloadManager(new QNetworkAccessManager), m_reply(NULL), m_downloadFinished(false), m_installFinished(false), m_avrdudeProcess(new QProcess(parent)), m_format(new KFormat(*new QLocale())) { setupUi(this); downloadStatusLabel->clear(); installStatusLabel->clear(); urlLabel->setTextFormat(Qt::TextFormat::RichText); urlLabel->setText(i18n("

More information at: %1

", QStringLiteral("patrickelectric@gmail.com"))); projectLabel->setText(i18n("Embedded plugin is an unofficial project by Patrick J. Pereira.")); existingInstallButton->setText(existingInstallButton->text()+QStringLiteral("(Arduino SDK " ARDUINO_SDK_MIN_VERSION_NAME " or superior)")); automaticInstallButton->setText(automaticInstallButton->text()+QStringLiteral("(Arduino SDK " ARDUINO_SDK_VERSION_NAME ")")); // Download mode is default automaticInstallButton->setChecked(true); m_downloadRunning = false; // Arduino path - getArduinoPath(); + fetchArduinoPath(); // Sketchbook path - getSketchbookPath(); + fetchSketchbookPath(); //TODO support others OS QString mDownloadOs = QStringLiteral("Linux"); downloadLabel->setText(i18n("Arduino %1 for %2", QStringLiteral(ARDUINO_SDK_VERSION_NAME), mDownloadOs)); connect(arduinoPathButton, &QToolButton::clicked, this, &FirstTimeWizard::chooseArduinoPath); connect(sketchbookPathButton, &QToolButton::clicked, this, &FirstTimeWizard::chooseSketchbookPath); connect(this, &QWizard::currentIdChanged, this, &FirstTimeWizard::validateCurrentId); connect(button(QWizard::CancelButton), &QAbstractButton::clicked, this, &FirstTimeWizard::cancelButtonClicked); m_avrdudeProcess->connect(m_avrdudeProcess, (void (QProcess::*)(int, QProcess::ExitStatus))&QProcess::finished, this, &FirstTimeWizard::avrdudeStderr); m_avrdudeProcess->connect(m_avrdudeProcess, &QProcess::readyReadStandardOutput, this, &FirstTimeWizard::avrdudeStdout); } bool FirstTimeWizard::validateCurrentPage() { switch (currentId()) { case 0: if (existingInstallButton->isChecked() && !Toolkit::instance().isValidArduinoPath(arduinoPathEdit->text())) { return false; } break; case 1: { if (m_downloadFinished && m_installFinished) { return true; } else { download(); } return false; break; } case 2: { KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded"); settings.writeEntry("arduinoFolder", arduinoPathEdit->text()); settings.writeEntry("sketchbookFolder", sketchbookPathEdit->text()); QStringList flags; flags << QStringLiteral("-p") << QStringLiteral("partno") << QStringLiteral("-c") << QStringLiteral("alf"); QString avrdude = arduinoPathEdit->text()+Toolkit::instance().avrdudePath(); qCDebug(FtwMsg) << "Starting.." << avrdude << flags; // Check if file exist to not create a zombie if (QFileInfo(avrdude).exists()) { m_avrdudeProcess->start(avrdude, flags); m_avrdudeProcess->waitForFinished(); } } break; default: break; } return true; } void FirstTimeWizard::download() { button(QWizard::NextButton)->setEnabled(false); if (m_downloadRunning == true && !m_downloadFinished) { return; } else if (m_downloadFinished) { button(QWizard::NextButton)->setEnabled(true); return; } m_downloadRunning = true; downloadProgressBar->setValue(0); const QUrl downloadLink = QUrl(arduinoDownloadUrl); QNetworkRequest request(downloadLink); qCDebug(FtwIo) << "Download :" << arduinoDownloadUrl; request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); m_reply = m_mDownloadManager->get(request); connect(m_reply, &QNetworkReply::downloadProgress, this, &FirstTimeWizard::onDownloadProgress); connect(m_reply, &QNetworkReply::finished, this, &FirstTimeWizard::install); downloadStatusLabel->setText(i18n("Downloading...")); } void FirstTimeWizard::install() { m_downloadFinished = m_reply->isOpen(); qCDebug(FtwIo) << "at install m_downloadFinished" << m_downloadFinished; if (m_downloadFinished) { downloadStatusLabel->setText(i18n("Downloaded")); } else { downloadStatusLabel->setText(i18n("Download cancelled")); return; } // Extract the archive QTemporaryFile archive; bool extractSuccess = archive.open(); QString destinationPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); QDir destinationDir(destinationPath); if (!extractSuccess) { qCDebug(FtwIo) << "Cant open file" << archive.fileName(); } if (!destinationDir.exists()) { qCDebug(FtwIo) << "Destination directory already exists at" << destinationPath; extractSuccess = extractSuccess && destinationDir.mkpath(QStringLiteral(".")); } if (extractSuccess) { installStatusLabel->setText(i18n("Extracting...")); // Write the reply to the temporary file QByteArray buffer; // Create a buffer of 8kB static const int bufferSize = 8192; buffer.resize(bufferSize); qint64 readBytes = m_reply->read(buffer.data(), bufferSize); while (readBytes > 0) { archive.write(buffer.data(), readBytes); readBytes = m_reply->read(buffer.data(), bufferSize); } installStatusLabel->setText(i18n("Extracting... ")+m_format->formatByteSize(readBytes)); archive.seek(0); // Call Ktar to extract KTar extract(archive.fileName()); extract.open(QIODevice::ReadOnly); extractSuccess = extract.directory()->copyTo(destinationPath, true); qCDebug(FtwIo) << "Downloaded file extracted with success ? :" << extractSuccess; qCDebug(FtwIo) << archive.fileName() << "extracted in" << destinationPath; QDir(destinationPath).rename(QStringLiteral("arduino-") + QStringLiteral(ARDUINO_SDK_VERSION_NAME), QStringLiteral("arduino")); destinationPath += QStringLiteral("/arduino"); installStatusLabel->setText(i18n("Extracted")); arduinoPathEdit->setText(destinationPath); m_installFinished = true; } this->button(QWizard::NextButton)->setEnabled(true); } void FirstTimeWizard::cancelButtonClicked(bool state) { Q_UNUSED(state); qCDebug(FtwIo) << "CancelButton clicked"; if (m_reply) { if (m_reply->isRunning()) { m_reply->abort(); } } } void FirstTimeWizard::validateCurrentId(int id) { if (id == 1 && !existingInstallButton->isChecked()) { download(); } } int FirstTimeWizard::nextId() const { if (currentId() == 0 && existingInstallButton->isChecked()) { return 2; } return QWizard::nextId(); } -QString FirstTimeWizard::getArduinoPath() +void FirstTimeWizard::fetchArduinoPath() { + KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded"); + if (settings.hasKey("arduinoFolder")) + { + arduinoPathEdit->setText(settings.readEntry("arduinoFolder")); + existingInstallButton->setChecked(true); + return; + } + // Find Arduino path #ifdef Q_OS_DARWIN #elif defined(Q_OS_WIN32) || defined(Q_OS_WIN64) #else const QString applicationPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); // Paths to search for an existing installation static QStringList defaultArduinoPaths = QStringList() << QDir(applicationPath).filePath(QStringLiteral("arduino-") + QStringLiteral(ARDUINO_SDK_VERSION_NAME)) << QDir(applicationPath).filePath(QStringLiteral("arduino")) << QStringLiteral("/usr/local/share/arduino-") + QStringLiteral(ARDUINO_SDK_VERSION_NAME) << QStringLiteral("/usr/local/share/arduino") << QStringLiteral("/usr/share/arduino-") + QStringLiteral(ARDUINO_SDK_VERSION_NAME) << QStringLiteral("/usr/share/arduino"); #endif foreach (const auto& path, defaultArduinoPaths) { if (Toolkit::instance().isValidArduinoPath(path)) { qCDebug(FtwIo) << "Valid Arduino path at" << path; arduinoPathEdit->setText(path); existingInstallButton->setChecked(true); - return path; } } qCDebug(FtwIo) << "No valid Arduino path"; - return QString(); } -QString FirstTimeWizard::getSketchbookPath() +void FirstTimeWizard::fetchSketchbookPath() { + KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded"); + if (settings.hasKey("sketchbookFolder")) + { + sketchbookPathEdit->setText(settings.readEntry("sketchbookFolder")); + return; + } // Find Sketchbook path QDir sketchbookPath; #ifdef Q_OS_DARWIN #elif defined(Q_OS_WIN32) || defined(Q_OS_WIN64) #else sketchbookPath = QDir(QDir::homePath()).filePath(QStringLiteral("sketchbook")); #endif if (sketchbookPath.exists()) { sketchbookPathEdit->setText(sketchbookPath.absolutePath()); } - - return QString(); } void FirstTimeWizard::chooseArduinoPath() { const QString path = QFileDialog::getExistingDirectory(this, i18n("Find Files"), QDir::currentPath()); if (!path.isEmpty()) { arduinoPathEdit->setText(path); } } void FirstTimeWizard::chooseSketchbookPath() { const QString path = QFileDialog::getExistingDirectory(this, i18n("Find Files"), QDir::currentPath()); if (!path.isEmpty()) { sketchbookPathEdit->setText(path); } } void FirstTimeWizard::onDownloadProgress(qint64 received, qint64 total) { int percent = 0; if (total) { percent = 100 * received / total; } qCDebug(FtwIo) << "Download in Progress" << percent << "%"; qCDebug(FtwIo) << "Download in Progress" << received << "/" << total; downloadStatusLabel->setText(i18n("Downloading... (%1 / %2)", m_format->formatByteSize(received), m_format->formatByteSize(total))); downloadProgressBar->setValue(percent); } void FirstTimeWizard::avrdudeStderr(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) Q_UNUSED(exitStatus) qCDebug(FtwMsg) << "avrdudeStderr"; m_avrdudeProcess->setReadChannel(QProcess::StandardError); QTextStream stream(m_avrdudeProcess); QStringList mcus; while (!stream.atEnd()) { QString mcu = stream.readLine().split(QChar::fromLatin1(' ')).takeLast(); if (mcu.contains(QStringLiteral("AT"))) { mcus.append(mcu.toLower()); } } qCDebug(FtwMsg) << "mcus" << mcus; KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded"); settings.writeEntry("avrdudeMCUList", mcus); } void FirstTimeWizard::avrdudeStdout() { qCDebug(FtwMsg) << "avrdudeStdout"; m_avrdudeProcess->setReadChannel(QProcess::StandardOutput); QTextStream stream(m_avrdudeProcess); while (!stream.atEnd()) { qCDebug(FtwMsg) << "avrdudeStdout" << stream.readLine(); } } FirstTimeWizard::~FirstTimeWizard() { delete m_mDownloadManager; } diff --git a/firsttimewizard.h b/firsttimewizard.h index 1d8c593..a0ad7d2 100644 --- a/firsttimewizard.h +++ b/firsttimewizard.h @@ -1,85 +1,97 @@ /* * This file is part of KDevelop project * Copyright 2016 Patrick José Pereira * Based onde the work Arduide Project of: * Denis Martinez * Martin Peres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once // first time wizard configuration #include #include #include #include "ui_firsttimewizard.h" #include "arduinoversion.h" Q_DECLARE_LOGGING_CATEGORY(FtwIo) Q_DECLARE_LOGGING_CATEGORY(FtwMsg) class QNetworkAccessManager; class QNetworkReply; class KFormat; class FirstTimeWizard : public QWizard, Ui::FirstTimeWizard { Q_OBJECT public: explicit FirstTimeWizard(QWidget *parent = NULL); ~FirstTimeWizard(); QNetworkAccessManager *m_mDownloadManager; QNetworkReply *m_reply; static QString arduinoDownloadUrl; static QString downloadExtensionUrl; static QString downloadArchUrl; static QString downloadOsUrl; bool m_downloadRunning; bool m_downloadFinished; bool m_installFinished; //get mcu list from avrdude QProcess *m_avrdudeProcess; KFormat *m_format; - QString getArduinoPath(); - QString getSketchbookPath(); + /** + * @brief Populate `Arduino Path` field with valid path to a Arduino install. + * + * If a setting exists, it is used, otherwise standard paths are verified + * and if a valid one is found, it is used. + */ + void fetchArduinoPath(); + /** + * @brief Populate `Sketchbook Path` field with valid projects path. + * + * If a setting exists, it is used, otherwise standard paths are verified + * and if a valid one is found, it is used. + */ + void fetchSketchbookPath(); QString downloadAndInstallArduino(); bool validateCurrentPage(); int nextId() const; bool finish(); void onDownloadProgress(qint64 received, qint64 total); void chooseArduinoPath(); void validateCurrentId(int id); void cancelButtonClicked(bool state); void chooseSketchbookPath(); void download(); void install(); void avrdudeStdout(); void avrdudeStderr(int exitCode, QProcess::ExitStatus exitStatus); };