File indexing completed on 2024-04-14 04:29:46

0001 /*
0002  * This file is part of KDevelop project
0003  * Copyright 2016 Patrick José Pereira <patrickelectric@gmail.com>
0004  * Copyright 2009 Andreas Pakulat <apaku@gmx.de>
0005  * Copyright 2010 Aleix Pol Gonzalez <aleixpol@kde.org>
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU Library General Public License as
0009  * published by the Free Software Foundation; either version 2 of the
0010  * License, or (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public
0018  * License along with this program; if not, write to the
0019  * Free Software Foundation, Inc.,
0020  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #include "embeddedlauncher.h"
0024 
0025 #include <interfaces/icore.h>
0026 #include <interfaces/isession.h>
0027 #include <interfaces/iprojectcontroller.h>
0028 #include <interfaces/ilaunchconfiguration.h>
0029 
0030 #include <project/projectmodel.h>
0031 
0032 #include "launcherjob.h"
0033 #include <interfaces/iproject.h>
0034 #include <project/interfaces/iprojectfilemanager.h>
0035 #include <project/interfaces/ibuildsystemmanager.h>
0036 #include <project/interfaces/iprojectbuilder.h>
0037 #include <project/builderjob.h>
0038 #include <interfaces/iruncontroller.h>
0039 #include <interfaces/iuicontroller.h>
0040 #include <util/executecompositejob.h>
0041 
0042 #include <interfaces/iplugincontroller.h>
0043 
0044 #include "executeplugin.h"
0045 #include "toolkit.h"
0046 #include "debug.h"
0047 #include "board.h"
0048 
0049 #include <util/kdevstringhandler.h>
0050 #include <project/projectitemlineedit.h>
0051 #include "projecttargetscombobox.h"
0052 
0053 #include <QDebug>
0054 #include <QIcon>
0055 #include <QMenu>
0056 #include <QPixmap>
0057 #include <QPainter>
0058 #include <QMessageBox>
0059 #include <QItemSelection>
0060 
0061 #include <QStandardPaths>
0062 
0063 #include <KConfigGroup>
0064 #include <KLineEdit>
0065 #include <KLocalizedString>
0066 #include <KShell>
0067 
0068 #include <solid/device.h>
0069 #include <solid/devicenotifier.h>
0070 
0071 #include "firsttimewizard.h"
0072 
0073 using namespace KDevelop;
0074 using namespace Solid;
0075 
0076 Q_LOGGING_CATEGORY(ElMsg, "Kdev.embedded.el.msg")
0077 
0078 QIcon EmbeddedLauncherConfigPage::icon() const
0079 {
0080     return QIcon::fromTheme(QStringLiteral("system-run"));
0081 }
0082 
0083 static KDevelop::ProjectBaseItem* itemForPath(const QStringList& path, KDevelop::ProjectModel* model)
0084 {
0085     return model->itemFromIndex(model->pathToIndex(path));
0086 }
0087 
0088 void EmbeddedLauncherConfigPage::loadFromConfiguration(const KConfigGroup& cfg, KDevelop::IProject* project)
0089 {
0090     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::loadFromConfiguration" << cfg.groupList() << cfg.keyList() << cfg.entryMap();
0091 
0092     bool b = blockSignals(true);
0093     projectTarget->setBaseItem(project ? project->projectItem() : nullptr, true);
0094     projectTarget->setCurrentItemPath(cfg.readEntry(ExecutePlugin::projectTargetEntry, QStringList()));
0095 
0096     QUrl exe = cfg.readEntry(ExecutePlugin::executableEntry, QUrl());
0097     if (!exe.isEmpty() || project)
0098     {
0099         executablePath->setUrl(!exe.isEmpty() ? exe : project->path().toUrl());
0100     }
0101     else
0102     {
0103         KDevelop::IProjectController* pc = KDevelop::ICore::self()->projectController();
0104         if (pc)
0105         {
0106             executablePath->setUrl(pc->projects().isEmpty() ? QUrl() : pc->projects().at(0)->path().toUrl());
0107         }
0108     }
0109 
0110     executableRadio->setChecked(true);
0111     if (!cfg.readEntry(ExecutePlugin::isExecutableEntry, false) && projectTarget->count())
0112     {
0113         projectTargetRadio->setChecked(true);
0114     }
0115 
0116     const QString arg = cfg.readEntry(ExecutePlugin::argumentsEntry, QString());
0117     if (argumentsCombo->findText(arg) == -1 && !arg.isEmpty())
0118     {
0119         argumentsCombo->addItem(arg);
0120     }
0121 
0122     workingDirectory->setUrl(cfg.readEntry(ExecutePlugin::workingDirEntry, QUrl()));
0123     commandCombo->setEditText(cfg.readEntry(ExecutePlugin::commandEntry, commandCombo->itemText(0)));
0124 
0125     const int boardIndex = cfg.readEntry(ExecutePlugin::boardEntry, 0);
0126     const int mcuIndex = cfg.readEntry(ExecutePlugin::mcuEntry, 0);
0127 
0128     qCDebug(ElMsg) << "Board index from cfg" << QString(cfg.readEntry(ExecutePlugin::boardEntry, 0)).toInt() << cfg.readEntry(ExecutePlugin::boardEntry, 0);
0129     qCDebug(ElMsg) << "BoardCombo size" << boardCombo->count();
0130 
0131     const int launcherIndex = cfg.readEntry(ExecutePlugin::launcherIndexEntry, 0);
0132     stackedWidget->setCurrentIndex(launcherIndex);
0133     presetsComboPage1->setCurrentIndex(launcherIndex);
0134     presetsComboPage2->setCurrentIndex(launcherIndex);
0135 
0136     const QString openocdArg = cfg.readEntry(ExecutePlugin::openocdArgEntry, QString());
0137     const QUrl openocdWork = cfg.readEntry(ExecutePlugin::openocdWorkEntry, QUrl());
0138     const QString openocdComm = cfg.readEntry(ExecutePlugin::openocdCommEntry, QString());
0139 
0140     if (!openocdArg.isEmpty())
0141     {
0142         openocdArgumentsCombo->setCurrentText(openocdArg);
0143     }
0144     if (!openocdWork.isEmpty())
0145     {
0146         openocdWorkingDirectory->setUrl(openocdWork);
0147     }
0148     if (!openocdComm.isEmpty())
0149     {
0150         openocdCommand->setCurrentText(openocdComm);
0151     }
0152 
0153     if (boardIndex < boardCombo->count())
0154     {
0155         boardCombo->setCurrentIndex(boardIndex);
0156     }
0157     if (mcuIndex < mcuCombo->count())
0158     {
0159         mcuCombo->setCurrentIndex(mcuIndex);
0160     }
0161 
0162     blockSignals(b);
0163 }
0164 
0165 EmbeddedLauncherConfigPage::EmbeddedLauncherConfigPage(QWidget* parent)
0166     : LaunchConfigurationPage(parent),
0167       m_model(new ArduinoWindowModel(parent))
0168 {
0169     setupUi(this);
0170 
0171     m_boardImgsDir = QDir(QStandardPaths::locate(
0172                               QStandardPaths::GenericDataLocation,
0173                               QLatin1String("kdevembedded/boardsimg"),
0174                               QStandardPaths::LocateDirectory
0175                           ) + QChar::fromLatin1('/'));
0176 
0177     //Set workingdirectory widget to ask for directories rather than files
0178     workingDirectory->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly);
0179 
0180     Solid::DeviceNotifier *devices = Solid::DeviceNotifier::instance();
0181 
0182     Board::instance().update();
0183 
0184     // Populate model
0185     QVector<ArduinoWindowModelStruct> data;
0186     Q_ASSERT(Board::instance().m_boardList.size() == Board::instance().m_boardNameList.size());
0187     for (int i = 0; i < Board::instance().m_boardNameList.size(); i++)
0188         data.push_back(ArduinoWindowModelStruct{Board::instance().m_boardList[i], Board::instance().m_boardNameList[i]});
0189     m_model->populate(data);
0190 
0191     // Start ComboBoxes
0192     boardCombo->clear();
0193     boardCombo->setModel(m_model);
0194     boardComboChanged(boardCombo->currentText());
0195     devicesChanged(QString());
0196 
0197     mcuCombo->setToolTip(mcuTooltip());
0198     interfaceCombo->setToolTip(interfaceTooltip());
0199     baudCombo->setToolTip(baudTooltip());
0200     argumentsCombo->setToolTip(argumentsTooltip());
0201     commandCombo->setToolTip(commandTooltip());
0202 
0203     // Start in the first widget and in the first preset
0204     stackedWidget->setCurrentIndex(0);
0205     presetsComboPage1->setCurrentIndex(0);
0206     presetsComboPage2->setCurrentIndex(0);
0207 
0208 
0209     //connect signals to changed signal
0210     connect(projectTarget, static_cast<void(ProjectTargetsComboBox::*)(const QString&)>(&ProjectTargetsComboBox::currentIndexChanged), this, &EmbeddedLauncherConfigPage::changed);
0211     connect(projectTargetRadio, &QRadioButton::toggled, this, &EmbeddedLauncherConfigPage::changed);
0212     connect(executableRadio, &QRadioButton::toggled, this, &EmbeddedLauncherConfigPage::changed);
0213     connect(executablePath->lineEdit(), &KLineEdit::textEdited, this, &EmbeddedLauncherConfigPage::changed);
0214     connect(executablePath, &KUrlRequester::urlSelected, this, &EmbeddedLauncherConfigPage::changed);
0215     connect(argumentsCombo->lineEdit(), &KLineEdit::textEdited, this, &EmbeddedLauncherConfigPage::changed);
0216     connect(workingDirectory, &KUrlRequester::urlSelected, this, &EmbeddedLauncherConfigPage::changed);
0217     connect(workingDirectory->lineEdit(), &KLineEdit::textEdited, this, &EmbeddedLauncherConfigPage::changed);
0218     connect(boardCombo, &QComboBox::currentTextChanged, this, &EmbeddedLauncherConfigPage::changed);
0219     connect(commandCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &EmbeddedLauncherConfigPage::changed);
0220 
0221     connect(devices, &Solid::DeviceNotifier::deviceAdded, this, &EmbeddedLauncherConfigPage::devicesChanged);
0222     connect(devices, &Solid::DeviceNotifier::deviceRemoved, this, &EmbeddedLauncherConfigPage::devicesChanged);
0223     connect(boardCombo, &QComboBox::currentTextChanged, this,  &EmbeddedLauncherConfigPage::boardComboChanged);
0224     connect(mcuCombo->lineEdit(), &KLineEdit::textEdited, this, &EmbeddedLauncherConfigPage::changed);
0225     connect(mcuCombo, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &EmbeddedLauncherConfigPage::mcuComboChanged);
0226     connect(baudCombo->lineEdit(), &KLineEdit::textEdited, this, &EmbeddedLauncherConfigPage::changed);
0227 
0228     connect(presetsComboPage1, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &EmbeddedLauncherConfigPage::presetsChanged);
0229     connect(presetsComboPage2, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &EmbeddedLauncherConfigPage::presetsChanged);
0230 
0231     KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded");
0232     if (settings.readEntry("arduinoFolder", "").isEmpty())
0233     {
0234         QMessageBox::warning(nullptr, i18n("kdev-embedded"), i18n("Please run the first time wizard."));
0235         FirstTimeWizard *embeddedWindow = new FirstTimeWizard(parent);
0236         embeddedWindow->setAttribute(Qt::WA_DeleteOnClose);
0237         embeddedWindow->show();
0238     }
0239 }
0240 
0241 const QString EmbeddedLauncherConfigPage::mcuTooltip()
0242 {
0243     return i18n("Please add a microcontroller");
0244 }
0245 
0246 const QStringList EmbeddedLauncherConfigPage::mcuList()
0247 {
0248     return Toolkit::instance().avrdudeMcuList();
0249 }
0250 const QString EmbeddedLauncherConfigPage::interfaceTooltip()
0251 {
0252     QString tooltip;
0253     tooltip += i18n("Please connect or select an interface, for example:\n"
0254                     "/dev/ttyUSBx, /dev/ttyACMx, COMx, etc");
0255     return tooltip;
0256 }
0257 
0258 const QString EmbeddedLauncherConfigPage::baudTooltip()
0259 {
0260     QString tooltip;
0261     tooltip += i18n("Please choose or select a baudrate:\n"
0262                     "19200, 57600, 115200, etc");
0263     return tooltip;
0264 }
0265 
0266 const QString EmbeddedLauncherConfigPage::argumentsTooltip()
0267 {
0268     QString tooltip;
0269     tooltip += i18n("Variables to programmer:\n")
0270         += i18n("%avrdudeconf\t- Specify location of configuration file.\n")
0271         += i18n("%mcu\t- Required. Specify AVR device.\n")
0272         += i18n("%interface\t- Specify connection port.\n")
0273         += i18n("%baud\t- Override RS-232 baud rate.\n")
0274         += i18n("%hex\t- Firmware.");
0275     return tooltip;
0276 }
0277 
0278 const QString EmbeddedLauncherConfigPage::commandTooltip()
0279 {
0280     QString tooltip;
0281     tooltip += i18n("%avrdude - Avrdude is a program for downloading code and data to Atmel AVR microcontrollers.");
0282     return tooltip;
0283 }
0284 
0285 void EmbeddedLauncherConfigPage::checkActions(const QItemSelection& selected, const QItemSelection& unselected)
0286 {
0287     Q_UNUSED(unselected);
0288     qCDebug(ElMsg) << "checkActions";
0289     if (!selected.indexes().isEmpty())
0290     {
0291         qCDebug(ElMsg) << "have selection";
0292         Q_ASSERT(selected.indexes().count() == 1);
0293         QModelIndex idx = selected.indexes().at(0);
0294         qCDebug(ElMsg) << "index" << idx;
0295     }
0296 }
0297 
0298 void EmbeddedLauncherConfigPage::selectItemDialog()
0299 {
0300 }
0301 
0302 void EmbeddedLauncherConfigPage::saveToConfiguration(KConfigGroup cfg, KDevelop::IProject* project) const
0303 {
0304     Q_UNUSED(project);
0305 
0306     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::saveToConfiguration" << cfg.config()->groupList();
0307     cfg.writeEntry(ExecutePlugin::isExecutableEntry, executableRadio->isChecked());
0308     cfg.writeEntry(ExecutePlugin::executableEntry, executablePath->text());
0309     cfg.writeEntry(ExecutePlugin::projectTargetEntry, projectTarget->currentItemPath());
0310 
0311     cfg.writeEntry(ExecutePlugin::launcherIndexEntry, stackedWidget->currentIndex());
0312 
0313     cfg.writeEntry(ExecutePlugin::boardEntry, boardCombo->currentIndex());
0314     cfg.writeEntry(ExecutePlugin::mcuEntry, mcuCombo->currentText());
0315     // interface
0316     // interface baud rate
0317     cfg.writeEntry(ExecutePlugin::argumentsEntry, argumentsCombo->currentText());
0318     cfg.writeEntry(ExecutePlugin::workingDirEntry, workingDirectory->url());
0319     cfg.writeEntry(ExecutePlugin::commandEntry, commandCombo->currentText());
0320 
0321     cfg.writeEntry(ExecutePlugin::openocdArgEntry, openocdArgumentsCombo->currentText());
0322     cfg.writeEntry(ExecutePlugin::openocdWorkEntry, openocdWorkingDirectory->url());
0323     cfg.writeEntry(ExecutePlugin::openocdCommEntry, openocdCommand->currentText());
0324 
0325     // Arduino configuration
0326     const KConfigGroup settings = ICore::self()->activeSession()->config()->group("Embedded");
0327     const QString avrdudeConf = Toolkit::instance().avrConfigFile();
0328 
0329     QStringList arduinoConf;
0330     arduinoConf
0331         << m_model->getData(boardCombo->currentIndex()).m_id
0332         << mcuCombo->currentText()
0333         << baudCombo->currentText()
0334         << interfaceCombo->currentText()
0335         << executablePath->text()
0336         << avrdudeConf;
0337     cfg.writeEntry(ExecutePlugin::arduinoEntry, arduinoConf);
0338 
0339     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::saveToConfiguration" << cfg.groupList() << cfg.keyList() << cfg.entryMap();
0340     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::saveToConfiguration" << "arduinoConf" << arduinoConf << m_mcu << m_baud << interfaceCombo->currentText();
0341 }
0342 
0343 QString EmbeddedLauncherConfigPage::title() const
0344 {
0345     return i18n("Configure Embedded Application");
0346 }
0347 
0348 EmbeddedLauncherConfigPage::~EmbeddedLauncherConfigPage()
0349 {
0350 }
0351 
0352 QList< KDevelop::LaunchConfigurationPageFactory* > EmbeddedLauncher::configPages() const
0353 {
0354     return QList<KDevelop::LaunchConfigurationPageFactory*>();
0355 }
0356 
0357 QString EmbeddedLauncher::description() const
0358 {
0359     return i18n("Upload applications to embedded platforms");
0360 }
0361 
0362 QString EmbeddedLauncher::id()
0363 {
0364     return QStringLiteral("EmbeddedLauncher");
0365 }
0366 
0367 QString EmbeddedLauncher::name() const
0368 {
0369     return i18n("Embedded");
0370 }
0371 
0372 EmbeddedLauncher::EmbeddedLauncher()
0373 {
0374 }
0375 
0376 KJob* EmbeddedLauncher::start(const QString& launchMode, KDevelop::ILaunchConfiguration* cfg)
0377 {
0378     qCDebug(ElMsg) << "EmbeddedLauncher::start" << launchMode << cfg->name() << cfg->config().groupList();
0379     Q_ASSERT(cfg);
0380     if (!cfg)
0381     {
0382         return nullptr;
0383     }
0384     if (launchMode == QLatin1String("execute"))
0385     {
0386         IExecutePlugin* iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevembedded-launcher"))->extension<IExecutePlugin>();
0387         Q_ASSERT(iface);
0388 
0389         KJob* depjob = iface->dependencyJob(cfg);
0390         QList<KJob*> l;
0391         if (depjob)
0392         {
0393             l << depjob;
0394         }
0395         l << new LauncherJob(KDevelop::ICore::self()->runController(), cfg);
0396         return new KDevelop::ExecuteCompositeJob(KDevelop::ICore::self()->runController(), l);
0397 
0398     }
0399     qWarning() << "Unknown launch mode " << launchMode << "for config:" << cfg->name();
0400     return nullptr;
0401 }
0402 
0403 QStringList EmbeddedLauncher::supportedModes() const
0404 {
0405     return QStringList() << QStringLiteral("execute");
0406 }
0407 
0408 KDevelop::LaunchConfigurationPage* NativeAppPageFactory::createWidget(QWidget* parent)
0409 {
0410     return new EmbeddedLauncherConfigPage(parent);
0411 }
0412 
0413 NativeAppPageFactory::NativeAppPageFactory()
0414 {
0415 }
0416 
0417 NativeAppConfigType::NativeAppConfigType()
0418 {
0419     factoryList.append(new NativeAppPageFactory());
0420 }
0421 
0422 NativeAppConfigType::~NativeAppConfigType()
0423 {
0424     qDeleteAll(factoryList);
0425     factoryList.clear();
0426 }
0427 
0428 QString NativeAppConfigType::name() const
0429 {
0430     return i18n("Embedded");
0431 }
0432 
0433 
0434 QList<KDevelop::LaunchConfigurationPageFactory*> NativeAppConfigType::configPages() const
0435 {
0436     return factoryList;
0437 }
0438 
0439 QString NativeAppConfigType::id() const
0440 {
0441     return ExecutePlugin::_nativeAppConfigTypeId;
0442 }
0443 
0444 QIcon NativeAppConfigType::icon() const
0445 {
0446     return QIcon::fromTheme(QStringLiteral("application-x-executable"));
0447 }
0448 
0449 bool NativeAppConfigType::canLaunch(KDevelop::ProjectBaseItem* item) const
0450 {
0451     if (item->target() && item->target()->executable())
0452     {
0453         return canLaunch(item->target()->executable()->builtUrl());
0454     }
0455     return false;
0456 }
0457 
0458 bool NativeAppConfigType::canLaunch(const QUrl& file) const
0459 {
0460     return (file.isLocalFile() && QFileInfo(file.toLocalFile()).isExecutable());
0461 }
0462 
0463 void NativeAppConfigType::configureLaunchFromItem(KConfigGroup cfg, KDevelop::ProjectBaseItem* item) const
0464 {
0465     qCDebug(ElMsg) << "EmbeddedLauncher::configureLaunchFromItem" << cfg.config()->groupList();
0466     cfg.writeEntry(ExecutePlugin::isExecutableEntry, false);
0467     KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
0468     cfg.writeEntry(ExecutePlugin::projectTargetEntry, model->pathFromIndex(model->indexFromItem(item)));
0469     cfg.writeEntry(ExecutePlugin::workingDirEntry, item->executable()->builtUrl().adjusted(QUrl::RemoveFilename));
0470     cfg.sync();
0471 }
0472 
0473 void NativeAppConfigType::configureLaunchFromCmdLineArguments(KConfigGroup cfg, const QStringList& args) const
0474 {
0475     qCDebug(ElMsg) << "EmbeddedLauncher::configureLaunchFromCmdLineArguments" << cfg.config()->groupList();
0476     cfg.writeEntry(ExecutePlugin::isExecutableEntry, true);
0477     Q_ASSERT(QFile::exists(args.first()));
0478 
0479     cfg.writeEntry(ExecutePlugin::executableEntry, QUrl::fromLocalFile(args.first()));
0480     QStringList a(args);
0481     a.removeFirst();
0482     cfg.writeEntry(ExecutePlugin::argumentsEntry, KShell::joinArgs(a));
0483     cfg.sync();
0484 }
0485 
0486 QList<KDevelop::ProjectTargetItem*> targetsInFolder(KDevelop::ProjectFolderItem* folder)
0487 {
0488     QList<KDevelop::ProjectTargetItem*> ret;
0489     foreach (KDevelop::ProjectFolderItem* f, folder->folderList())
0490         ret += targetsInFolder(f);
0491 
0492     ret += folder->targetList();
0493     return ret;
0494 }
0495 
0496 bool actionLess(QAction* a, QAction* b)
0497 {
0498     return a->text() < b->text();
0499 }
0500 
0501 bool menuLess(QMenu* a, QMenu* b)
0502 {
0503     return a->title() < b->title();
0504 }
0505 
0506 
0507 QMenu* NativeAppConfigType::launcherSuggestions()
0508 {
0509 
0510     QMenu* ret = new QMenu(i18n("Embedded Binary"));
0511 
0512     KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
0513     QList<KDevelop::IProject*> projects = KDevelop::ICore::self()->projectController()->projects();
0514 
0515     foreach (KDevelop::IProject* project, projects)
0516     {
0517         if (project->projectFileManager()->features() & KDevelop::IProjectFileManager::Targets)
0518         {
0519             QList<KDevelop::ProjectTargetItem*> targets=targetsInFolder(project->projectItem());
0520             QHash<KDevelop::ProjectBaseItem*, QList<QAction*> > targetsContainer;
0521             QMenu* projectMenu = ret->addMenu(QIcon::fromTheme(QStringLiteral("project-development")), project->name());
0522             foreach (KDevelop::ProjectTargetItem* target, targets)
0523             {
0524                 if (target->executable())
0525                 {
0526                     QStringList path = model->pathFromIndex(target->index());
0527                     if (!path.isEmpty())
0528                     {
0529                         QAction* act = new QAction(projectMenu);
0530                         act->setData(KDevelop::joinWithEscaping(path, QChar::fromLatin1('/'),QChar::fromLatin1('\\')));
0531                         act->setProperty("name", target->text());
0532                         path.removeFirst();
0533                         act->setText(path.join(QChar::fromLatin1('/')));
0534                         act->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
0535                         connect(act, &QAction::triggered, this, &NativeAppConfigType::suggestionTriggered);
0536                         targetsContainer[target->parent()].append(act);
0537                     }
0538                 }
0539             }
0540 
0541             QList<QAction*> separateActions;
0542             QList<QMenu*> submenus;
0543             foreach (KDevelop::ProjectBaseItem* folder, targetsContainer.keys())
0544             {
0545                 QList<QAction*> actions = targetsContainer.value(folder);
0546                 if (actions.size()==1 || !folder->parent())
0547                 {
0548                     separateActions += actions.first();
0549                 }
0550                 else
0551                 {
0552                     foreach (QAction* a, actions)
0553                     {
0554                         a->setText(a->property("name").toString());
0555                     }
0556                     QStringList path = model->pathFromIndex(folder->index());
0557                     path.removeFirst();
0558                     QMenu* submenu = new QMenu(path.join(QStringLiteral("/")));
0559                     std::sort(actions.begin(), actions.end(), actionLess);
0560                     submenu->addActions(actions);
0561                     submenus += submenu;
0562                 }
0563             }
0564             std::sort(separateActions.begin(), separateActions.end(), actionLess);
0565             std::sort(submenus.begin(), submenus.end(), menuLess);
0566             foreach (QMenu* m, submenus)
0567                 projectMenu->addMenu(m);
0568             projectMenu->addActions(separateActions);
0569 
0570             projectMenu->setEnabled(!projectMenu->isEmpty());
0571         }
0572     }
0573 
0574     return ret;
0575 }
0576 
0577 void NativeAppConfigType::suggestionTriggered()
0578 {
0579     QAction* action = qobject_cast<QAction*>(sender());
0580     KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel();
0581     KDevelop::ProjectTargetItem* pitem =
0582         dynamic_cast<KDevelop::ProjectTargetItem*>
0583         (itemForPath(KDevelop::splitWithEscaping(action->data().toString(),QChar::fromLatin1('/'),QChar::fromLatin1('\\')), model));
0584     if (pitem)
0585     {
0586         QPair<QString,QString> launcher = qMakePair(launchers().at(0)->supportedModes().at(0), launchers().at(0)->id());
0587         KDevelop::IProject* p = pitem->project();
0588 
0589         KDevelop::ILaunchConfiguration* config = KDevelop::ICore::self()->runController()->createLaunchConfiguration(this, launcher, p, pitem->text());
0590         KConfigGroup cfg = config->config();
0591         qCDebug(ElMsg) << "NativeAppConfigType::suggestionTriggered" << cfg.groupList();
0592         QStringList splitPath = model->pathFromIndex(pitem->index());
0593         cfg.writeEntry(ExecutePlugin::projectTargetEntry, splitPath);
0594         cfg.writeEntry(ExecutePlugin::dependencyActionEntry, "Build");
0595         cfg.sync();
0596 
0597         emit signalAddLaunchConfiguration(config);
0598     }
0599 }
0600 
0601 void EmbeddedLauncherConfigPage::devicesChanged(const QString& udi)
0602 {
0603     Q_UNUSED(udi);
0604     interfaceCombo->clear();
0605     QStringList interface;
0606     // It's necessary to implement a better way to check the interface
0607     auto devices = Solid::Device::allDevices();
0608     //auto devices = Solid::Device::listFromType(Solid::DeviceInterface::Type::Block);
0609 
0610     qCDebug(ElMsg) << "devicesChanged";
0611     foreach (const auto& device, devices)
0612     {
0613         if (device.product() != QStringLiteral("") && device.udi().contains(QStringLiteral("tty")))
0614         {
0615             qCDebug(ElMsg) << "INTERFACE ############ INTERFACE";
0616             qCDebug(ElMsg) << "Description\t:" << device.description();
0617             qCDebug(ElMsg) << "Parent Udi\t:" << device.parentUdi();
0618             qCDebug(ElMsg) << "Product\t:" << device.product();
0619             qCDebug(ElMsg) << "Udi\t:" << device.udi();
0620             qCDebug(ElMsg) << "Vendor\t:" << device.vendor();
0621             qCDebug(ElMsg) << "Icon\t:" << device.icon();
0622             qCDebug(ElMsg) << "Emblems\t:" << device.emblems();
0623             qCDebug(ElMsg) << "Interface\t:" << device.udi().split(QStringLiteral("/")).takeLast();
0624             interface << QString(QStringLiteral("/dev/") + device.udi().split(QStringLiteral("/")).takeLast());
0625         }
0626     }
0627 
0628     interface.removeDuplicates();
0629     interfaceCombo->addItems(interface);
0630 
0631     if (interfaceCombo->count() == 0)
0632     {
0633         interfaceCombo->clear();
0634         interfaceCombo->lineEdit()->setPlaceholderText(i18n("Could not find interface"));
0635     }
0636 }
0637 
0638 void EmbeddedLauncherConfigPage::boardComboChanged(const QString& text)
0639 {
0640     Q_UNUSED(text);
0641     QString id = m_model->getData(boardCombo->currentIndex()).m_id;
0642     Board::instance().m_boards[id].printData();
0643 
0644     m_mcu = Board::instance().m_boards[id].m_bMcu;
0645     m_baud = Board::instance().m_boards[id].m_upSpeed;
0646     m_mcu.removeDuplicates();
0647     m_baud.removeDuplicates();
0648 
0649     mcuCombo->clear();
0650     mcuCombo->addItems(m_mcu);
0651     mcuCombo->insertSeparator(mcuCombo->count());
0652     mcuCombo->addItems(mcuList());
0653     baudCombo->clear();
0654     baudCombo->addItems(m_baud);
0655     qCDebug(ElMsg) << "SIZEOF MCUCOMBO" << sizeof(mcuCombo);
0656     qCDebug(ElMsg) << "SIZEOF BAUDCOMBO" << sizeof(baudCombo);
0657 
0658 
0659     // TODO: select image from board selection
0660     QPixmap pix(QStringLiteral("%1/%2.svg").arg(m_boardImgsDir.absolutePath(), id));
0661     if (pix.isNull())
0662     {
0663         pix = QPixmap(m_boardImgsDir.absolutePath() + QStringLiteral("/arduino.svg"));
0664     }
0665 
0666     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged Pixmap" << pix;
0667 
0668     if (pix.width() > pix.height())
0669     {
0670         qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged Start rotation" << id << pix;
0671         QTransform rotate_disc;
0672         pix = pix.transformed(QTransform().rotate(90));
0673         qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged End rotation" << id << pix;
0674     }
0675 
0676     if (pix.width() > image->width() || pix.height() > image->height())
0677     {
0678         pix = pix.scaled(image->width(), image->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
0679     }
0680 
0681     m_pixBuffer = QPixmap(image->width(), image->height());
0682     QPainter painter(&m_pixBuffer);
0683     painter.fillRect(QRect(0, 0, image->width(), image->height()), palette().background());
0684     painter.drawPixmap(m_pixBuffer.width() / 2 - pix.width() / 2, m_pixBuffer.height() / 2 - pix.height() / 2, pix);
0685     painter.end();
0686 
0687     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged Baord image path" << id << pix;
0688     image->setPixmap(m_pixBuffer);
0689 
0690     mcuComboChanged(0);
0691     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged" << "mcus"  << m_mcu;
0692     qCDebug(ElMsg) << "EmbeddedLauncherConfigPage::boardComboChanged" << image->width() << image->height();
0693 }
0694 
0695 void EmbeddedLauncherConfigPage::mcuComboChanged(int index)
0696 {
0697     if (index < 0)
0698     {
0699         return;
0700     }
0701 
0702     baudCombo->setCurrentIndex(index);
0703 
0704     qCDebug(ElMsg) << "mcuComboBox Index: " << index;
0705     qCDebug(ElMsg) << "mcuComboBox Count: " << mcuCombo->count();
0706 }
0707 
0708 void EmbeddedLauncherConfigPage::presetsChanged(int index)
0709 {
0710     if (index < 0)
0711     {
0712         return;
0713     }
0714 
0715     qCDebug(ElMsg) << "presetsCombo Index: " << index;
0716 
0717     stackedWidget->setCurrentIndex(index);
0718     presetsComboPage1->setCurrentIndex(index);
0719     presetsComboPage2->setCurrentIndex(index);
0720 }