Advertisement
Guest User

Untitled

a guest
Feb 9th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /***************************************************************************
  2. File                 : MQTTSubscriptionWidget.cpp
  3. Project              : LabPlot
  4. Description          : Widget for managing topics and subscribing
  5. --------------------------------------------------------------------
  6. Copyright            : (C) 2019 by Kovacs Ferencz (kferike98@gmail.com)
  7. ***************************************************************************/
  8.  
  9. /***************************************************************************
  10. *                                                                         *
  11. *  This program is free software; you can redistribute it and/or modify   *
  12. *  it under the terms of the GNU General Public License as published by   *
  13. *  the Free Software Foundation; either version 2 of the License, or      *
  14. *  (at your option) any later version.                                    *
  15. *                                                                         *
  16. *  This program is distributed in the hope that it will be useful,        *
  17. *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
  18. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
  19. *  GNU General Public License for more details.                           *
  20. *                                                                         *
  21. *   You should have received a copy of the GNU General Public License     *
  22. *   along with this program; if not, write to the Free Software           *
  23. *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
  24. *   Boston, MA  02110-1301  USA                                           *
  25. *                                                                         *
  26. ***************************************************************************/
  27.  
  28.  
  29. #include "MQTTSubscriptionWidget.h"
  30.  
  31. #ifdef HAVE_MQTT
  32. #include "backend/datasources/MQTTClient.h"
  33. #include "ImportFileWidget.h"
  34. #include "kdefrontend/dockwidgets/LiveDataDock.h"
  35. #include "MQTTHelpers.h"
  36.  
  37. #include <QMqttSubscription>
  38. #include <QMessageBox>
  39. #include <KLocalizedString>
  40. #include <QCompleter>
  41. #include <QTreeWidget>
  42. #include <QTreeWidgetItem>
  43.  
  44.  
  45. /*!
  46.    \class MQTTSubscriptionWidget
  47.    \brief Widget for managing topics and subscribing.
  48.  
  49.    \ingroup kdefrontend
  50. */
  51. MQTTSubscriptionWidget::MQTTSubscriptionWidget( QWidget* parent): QWidget(parent),
  52.     m_parentWidget(parent),
  53.     m_searchTimer(new QTimer(this))
  54. {
  55.     if(dynamic_cast<class ImportFileWidget*>(parent) != nullptr)
  56.         m_parent = MQTTParentWidget::ImportFileWidget;
  57.     else
  58.         m_parent = MQTTParentWidget::LiveDataDock;
  59.  
  60.     ui.setupUi(this);
  61.  
  62.  
  63.     m_searchTimer->setInterval(10000);
  64.     const int size = ui.leTopics->height();
  65.     ui.lTopicSearch->setPixmap( QIcon::fromTheme(QLatin1String("go-next")).pixmap(size, size) );
  66.     ui.lSubscriptionSearch->setPixmap( QIcon::fromTheme(QLatin1String("go-next")).pixmap(size, size) );
  67.     ui.bSubscribe->setIcon(ui.bSubscribe->style()->standardIcon(QStyle::SP_ArrowRight));
  68.     ui.bSubscribe->setToolTip(i18n("Subscribe selected topics"));
  69.     ui.bUnsubscribe->setIcon(ui.bUnsubscribe->style()->standardIcon(QStyle::SP_ArrowLeft));
  70.     ui.bUnsubscribe->setToolTip(i18n("Unsubscribe selected topics"));
  71.  
  72.     QString info = i18n("Enter the name of the topic to navigate to it.");
  73.     ui.lTopicSearch->setToolTip(info);
  74.     ui.leTopics->setToolTip(info);
  75.     ui.lSubscriptionSearch->setToolTip(info);
  76.     ui.leSubscriptions->setToolTip(info);
  77.  
  78.     info = i18n("Set the Quality of Service (QoS) for the subscription to define the guarantee of the message delivery:"
  79.                 "<ul>"
  80.                 "<li>0 - deliver at most once</li>"
  81.                 "<li>1 - deliver at least once</li>"
  82.                 "<li>2 - deliver exactly once</li>"
  83.                 "</ul>");
  84.     ui.cbQos->setToolTip(info);
  85.  
  86.     if(m_parent == MQTTParentWidget::ImportFileWidget) {
  87.         connect(dynamic_cast<class ImportFileWidget*>(m_parentWidget), &ImportFileWidget::newTopic, this, &MQTTSubscriptionWidget::setTopicCompleter);
  88.         connect(dynamic_cast<class ImportFileWidget*>(m_parentWidget), &ImportFileWidget::updateSubscriptionTree, this, &MQTTSubscriptionWidget::updateSubscriptionTree);
  89.         connect(dynamic_cast<class ImportFileWidget*>(m_parentWidget), &ImportFileWidget::MQTTClearTopics, this, &MQTTSubscriptionWidget::clearWidgets);
  90.     } else {
  91.         connect(dynamic_cast<class LiveDataDock*>(m_parentWidget), &LiveDataDock::MQTTClearTopics, this, &MQTTSubscriptionWidget::clearWidgets);
  92.         connect(dynamic_cast<class LiveDataDock*>(m_parentWidget), &LiveDataDock::newTopic, this, &MQTTSubscriptionWidget::setTopicCompleter);
  93.         connect(dynamic_cast<class LiveDataDock*>(m_parentWidget), &LiveDataDock::updateSubscriptionTree, this, &MQTTSubscriptionWidget::updateSubscriptionTree);
  94.     }
  95.  
  96.     connect(ui.bSubscribe,  &QPushButton::clicked, this, &MQTTSubscriptionWidget::mqttSubscribe);
  97.     connect(ui.bUnsubscribe, &QPushButton::clicked, this,&MQTTSubscriptionWidget::mqttUnsubscribe);
  98.  
  99.     connect(m_searchTimer, &QTimer::timeout, this, &MQTTSubscriptionWidget::topicTimeout);
  100.     connect(ui.leTopics, &QLineEdit::textChanged, this, &MQTTSubscriptionWidget::scrollToTopicTreeItem);
  101.     connect(ui.leSubscriptions, &QLineEdit::textChanged, this, &MQTTSubscriptionWidget::scrollToSubsriptionTreeItem);
  102.     connect(ui.twTopics, &QTreeWidget::itemDoubleClicked, this, &MQTTSubscriptionWidget::mqttAvailableTopicDoubleClicked);
  103.     connect(ui.twSubscriptions, &QTreeWidget::itemDoubleClicked, this, &MQTTSubscriptionWidget::mqttSubscribedTopicDoubleClicked);
  104. }
  105.  
  106. MQTTSubscriptionWidget::~MQTTSubscriptionWidget() {
  107.     m_searchTimer->stop();
  108.     delete m_searchTimer;
  109. }
  110.  
  111. void MQTTSubscriptionWidget::setTopicList(QStringList topicList) {
  112.     m_topicList = topicList;
  113. }
  114.  
  115. QStringList MQTTSubscriptionWidget::getTopicList() {
  116.     return m_topicList;
  117. }
  118.  
  119. int MQTTSubscriptionWidget::subscriptionCount() {
  120.     return ui.twSubscriptions->topLevelItemCount();
  121. }
  122.  
  123. QTreeWidgetItem* MQTTSubscriptionWidget::topLevelTopic(int index){
  124.     return ui.twTopics->topLevelItem(index);
  125. }
  126.  
  127. QTreeWidgetItem* MQTTSubscriptionWidget::topLevelSubscription(int index){
  128.     return ui.twSubscriptions->topLevelItem(index);
  129. }
  130.  
  131. void MQTTSubscriptionWidget::addTopic(QTreeWidgetItem* item) {
  132.     ui.twTopics->addTopLevelItem(item);
  133. }
  134.  
  135. int MQTTSubscriptionWidget::topicCount() {
  136.     return ui.twTopics->topLevelItemCount();
  137. }
  138.  
  139. void MQTTSubscriptionWidget::setTopicTreeText(const QString &text) {
  140.     ui.twTopics->headerItem()->setText(0, text);
  141. }
  142.  
  143. void MQTTSubscriptionWidget::makeVisible(bool visible) {
  144.     ui.cbQos->setVisible(visible);
  145.     ui.twTopics->setVisible(visible);
  146.     ui.twSubscriptions->setVisible(visible);
  147.     ui.leTopics->setVisible(visible);
  148.     ui.leSubscriptions->setVisible(visible);
  149.     ui.bSubscribe->setVisible(visible);
  150.     ui.bUnsubscribe->setVisible(visible);
  151.     ui.lTopicSearch->setVisible(visible);
  152.     ui.lSubscriptionSearch->setVisible(visible);
  153. }
  154.  
  155. void MQTTSubscriptionWidget::testSubscribe(QTreeWidgetItem *item) {
  156.     ui.twTopics->setCurrentItem(item);
  157.     mqttSubscribe();
  158. }
  159.  
  160. void MQTTSubscriptionWidget::testUnsubscribe(QTreeWidgetItem *item) {
  161.     ui.twTopics->setCurrentItem(item);
  162.     mqttUnsubscribe();
  163. }
  164.  
  165. /*!
  166.  *\brief Starts unsubscribing from the given topic, and signals to ImportFileWidget for further actions
  167.  *
  168.  * \param topicName the name of a topic we want to unsubscribe from
  169.  */
  170. void MQTTSubscriptionWidget::unsubscribeFromTopic(const QString& topicName) {
  171.     if (topicName.isEmpty())
  172.         return;
  173.  
  174.     QVector<QTreeWidgetItem*> children;
  175.     MQTTHelpers::findSubscriptionLeafChildren(children, ui.twSubscriptions->topLevelItem(0));
  176.  
  177.     //signals for ImportFileWidget
  178.     emit MQTTUnsubscribeFromTopic(topicName, children);
  179.  
  180.     for (int row = 0; row < ui.twSubscriptions->topLevelItemCount(); row++)  {
  181.         if (ui.twSubscriptions->topLevelItem(row)->text(0) == topicName) {
  182.             ui.twSubscriptions->topLevelItem(row)->takeChildren();
  183.             ui.twSubscriptions->takeTopLevelItem(row);
  184.         }
  185.     }
  186. }
  187.  
  188. /*!
  189.  *\brief We search in twSubscriptions for topics that can be represented using + wildcards, then merge them.
  190.  *       We do this until there are no topics to merge
  191.  */
  192. void MQTTSubscriptionWidget::manageCommonLevelSubscriptions() {
  193.     bool foundEqual = false;
  194.  
  195.     do {
  196.         foundEqual = false;
  197.         QMap<QString, QVector<QString>> equalTopicsMap;
  198.         QVector<QString> equalTopics;
  199.  
  200.         //compare the subscriptions present in the TreeWidget
  201.         for (int i = 0; i < ui.twSubscriptions->topLevelItemCount() - 1; ++i) {
  202.             for (int j = i + 1; j < ui.twSubscriptions->topLevelItemCount(); ++j) {
  203.                 QString commonTopic = MQTTHelpers::checkCommonLevel(ui.twSubscriptions->topLevelItem(i)->text(0), ui.twSubscriptions->topLevelItem(j)->text(0));
  204.  
  205.                 //if there is a common topic for the 2 compared topics, we add them to the map (using the common topic as key)
  206.                 if (!commonTopic.isEmpty()) {
  207.                     if (!equalTopicsMap[commonTopic].contains(ui.twSubscriptions->topLevelItem(i)->text(0)))
  208.                         equalTopicsMap[commonTopic].push_back(ui.twSubscriptions->topLevelItem(i)->text(0));
  209.  
  210.                     if (!equalTopicsMap[commonTopic].contains(ui.twSubscriptions->topLevelItem(j)->text(0)))
  211.                         equalTopicsMap[commonTopic].push_back(ui.twSubscriptions->topLevelItem(j)->text(0));
  212.                 }
  213.             }
  214.         }
  215.  
  216.         if (!equalTopicsMap.isEmpty()) {
  217.             DEBUG("Manage common topics");
  218.  
  219.             QVector<QString> commonTopics;
  220.             QMapIterator<QString, QVector<QString>> topics(equalTopicsMap);
  221.  
  222.             //check for every map entry, if the found topics can be merged or not
  223.             while (topics.hasNext()) {
  224.                 topics.next();
  225.  
  226.                 int level = MQTTHelpers::commonLevelIndex(topics.value().last(), topics.value().first());
  227.                 QStringList commonList = topics.value().first().split('/', QString::SkipEmptyParts);
  228.                 QTreeWidgetItem* currentItem = nullptr;
  229.  
  230.                 //search the corresponding item to the common topics first level(root)
  231.                 for (int i = 0; i < ui.twTopics->topLevelItemCount(); ++i) {
  232.                     if (ui.twTopics->topLevelItem(i)->text(0) == commonList.first()) {
  233.                         currentItem = ui.twTopics->topLevelItem(i);
  234.                         break;
  235.                     }
  236.                 }
  237.  
  238.                 if (!currentItem)
  239.                     break;
  240.  
  241.                 //calculate the number of topics the new + wildcard could replace
  242.                 int childCount = MQTTHelpers::checkCommonChildCount(1, level, commonList, currentItem);
  243.                 if (childCount > 0) {
  244.                     //if the number of topics found and the calculated number of topics is equal, the topics can be merged
  245.                     if (topics.value().size() == childCount) {
  246.                         QDEBUG("Found common topic to manage: " << topics.key());
  247.                         foundEqual = true;
  248.                         commonTopics.push_back(topics.key());
  249.                     }
  250.                 }
  251.             }
  252.  
  253.             if (foundEqual) {
  254.                 //if there are more common topics, the topics of which can be merged, we choose the one which has the lowest level new '+' wildcard
  255.                 int lowestLevel = INT_MAX;
  256.                 int topicIdx = -1;
  257.                 for (int i = 0; i < commonTopics.size(); ++i) {
  258.                     int level = MQTTHelpers::commonLevelIndex(equalTopicsMap[commonTopics[i]].first(), commonTopics[i]);
  259.                     if (level < lowestLevel) {
  260.                         topicIdx = i;
  261.                         lowestLevel = level;
  262.                     }
  263.                 }
  264.                 QDEBUG("Manage: " << commonTopics[topicIdx]);
  265.                 equalTopics.append(equalTopicsMap[commonTopics[topicIdx]]);
  266.  
  267.                 //Add the common topic ("merging")
  268.                 QString commonTopic;
  269.                 commonTopic = MQTTHelpers::checkCommonLevel(equalTopics.first(), equalTopics.last());
  270.                 QStringList nameList;
  271.                 nameList.append(commonTopic);
  272.                 QTreeWidgetItem* newTopic = new QTreeWidgetItem(nameList);
  273.                 ui.twSubscriptions->addTopLevelItem(newTopic);
  274.  
  275.                 if(m_parent == MQTTParentWidget::ImportFileWidget)
  276.                     emit makeSubscription(commonTopic, static_cast<quint8> (ui.cbQos->currentText().toUInt()));
  277.  
  278.                 //remove the "merged" topics
  279.                 for (int i = 0; i < equalTopics.size(); ++i) {
  280.                     for (int j = 0; j < ui.twSubscriptions->topLevelItemCount(); ++j) {
  281.                         if (ui.twSubscriptions->topLevelItem(j)->text(0) == equalTopics[i]) {
  282.                             newTopic->addChild(ui.twSubscriptions->takeTopLevelItem(j));
  283.  
  284.                             if(m_parent == MQTTParentWidget::ImportFileWidget) {
  285.                                 unsubscribeFromTopic(equalTopics[i]);
  286.                             }
  287.  
  288.                             break;
  289.                         }
  290.                     }
  291.                 }
  292.  
  293.                 //remove any subscription that the new subscription contains
  294.                 for (int i = 0; i < ui.twSubscriptions->topLevelItemCount(); ++i) {
  295.                     if (MQTTHelpers::checkTopicContains(commonTopic, ui.twSubscriptions->topLevelItem(i)->text(0)) &&
  296.                             commonTopic != ui.twSubscriptions->topLevelItem(i)->text(0) ) {
  297.                         if(m_parent == MQTTParentWidget::ImportFileWidget) {
  298.                             unsubscribeFromTopic(ui.twSubscriptions->topLevelItem(i)->text(0));
  299.                         } else {
  300.                             ui.twSubscriptions->topLevelItem(i)->takeChildren();
  301.                             ui.twSubscriptions->takeTopLevelItem(i);
  302.                         }
  303.                         i--;
  304.                     }
  305.                 }
  306.  
  307.                 if(m_parent == MQTTParentWidget::LiveDataDock)
  308.                     emit makeSubscription(commonTopic, static_cast<quint8> (ui.cbQos->currentText().toUInt()));
  309.             }
  310.         }
  311.     } while (foundEqual);
  312. }
  313.  
  314. /*!
  315.  *\brief Fills twSubscriptions with the subscriptions made by the client
  316.  */
  317. void MQTTSubscriptionWidget::updateSubscriptionTree(const QVector<QString>& mqttSubscriptions) {
  318.     DEBUG("ImportFileWidget::updateSubscriptionTree()");
  319.     ui.twSubscriptions->clear();
  320.  
  321.     for (int i = 0; i < mqttSubscriptions.size(); ++i) {
  322.         QStringList name;
  323.         name.append(mqttSubscriptions[i]);
  324.  
  325.         bool found = false;
  326.         for (int j = 0; j < ui.twSubscriptions->topLevelItemCount(); ++j) {
  327.             if (ui.twSubscriptions->topLevelItem(j)->text(0) == mqttSubscriptions[i]) {
  328.                 found = true;
  329.                 break;
  330.             }
  331.         }
  332.  
  333.         if (!found) {
  334.             //Add the subscription to the tree widget
  335.             QTreeWidgetItem* newItem = new QTreeWidgetItem(name);
  336.             ui.twSubscriptions->addTopLevelItem(newItem);
  337.             name.clear();
  338.             name = mqttSubscriptions[i].split('/', QString::SkipEmptyParts);
  339.  
  340.             //find the corresponding "root" item in twTopics
  341.             QTreeWidgetItem* topic = nullptr;
  342.             for (int j = 0; j < ui.twTopics->topLevelItemCount(); ++j) {
  343.                 if (ui.twTopics->topLevelItem(j)->text(0) == name[0]) {
  344.                     topic = ui.twTopics->topLevelItem(j);
  345.                     break;
  346.                 }
  347.             }
  348.  
  349.             //restore the children of the subscription
  350.             if (topic != nullptr && topic->childCount() > 0) {
  351.                 MQTTHelpers::restoreSubscriptionChildren(topic, newItem, name, 1);
  352.             }
  353.         }
  354.     }
  355.     m_searching = false;
  356. }
  357.  
  358. /************** SLOTS **************************************************************/
  359.  
  360. /*!
  361.  *\brief When a leaf topic is double clicked in the topics tree widget we subscribe on that
  362.  */
  363. void MQTTSubscriptionWidget::mqttAvailableTopicDoubleClicked(QTreeWidgetItem* item, int column) {
  364.     Q_UNUSED(column)
  365.     // Only for leaf topics
  366.     if (item->childCount() == 0)
  367.         mqttSubscribe();
  368. }
  369.  
  370. /*!
  371.  *\brief When a leaf subscription is double clicked in the topics tree widget we unsubscribe
  372.  */
  373. void MQTTSubscriptionWidget::mqttSubscribedTopicDoubleClicked(QTreeWidgetItem* item, int column) {
  374.     Q_UNUSED(column)
  375.     // Only for leaf subscriptions
  376.     if (item->childCount() == 0)
  377.         mqttUnsubscribe();
  378. }
  379.  
  380. /*!
  381.  *\brief called when the subscribe button is pressed
  382.  * subscribes to the topic represented by the current item of twTopics
  383.  */
  384. void MQTTSubscriptionWidget::mqttSubscribe() {
  385.     QTreeWidgetItem* item = ui.twTopics->currentItem();
  386.     if (!item) {
  387.         QMessageBox::warning(this, i18n("Warning"), i18n("You didn't select any item from the Tree Widget"));
  388.         return;
  389.     }
  390.  
  391.     //determine the topic name that the current item represents
  392.     QTreeWidgetItem* tempItem = item;
  393.     QString name = item->text(0);
  394.     if (item->childCount() != 0)
  395.         name.append("/#");
  396.  
  397.     while (tempItem->parent()) {
  398.         tempItem = tempItem->parent();
  399.         name.prepend(tempItem->text(0) + '/');
  400.     }
  401.  
  402.     //check if the subscription already exists
  403.     const QList<QTreeWidgetItem*>& topLevelList = ui.twSubscriptions->findItems(name, Qt::MatchExactly);
  404.     if (topLevelList.isEmpty() || topLevelList.first()->parent() != nullptr) {
  405.         QDEBUG("Subscribe to: " << name);
  406.         bool foundSuperior = false;
  407.  
  408.         for (int i = 0; i < ui.twSubscriptions->topLevelItemCount(); ++i) {
  409.             //if the new subscirptions contains an already existing one, we remove the inferior one
  410.             if (MQTTHelpers::checkTopicContains(name, ui.twSubscriptions->topLevelItem(i)->text(0))
  411.                     && name != ui.twSubscriptions->topLevelItem(i)->text(0)) {
  412.                 if(m_parent == MQTTParentWidget::ImportFileWidget) {
  413.                     unsubscribeFromTopic(ui.twSubscriptions->topLevelItem(i)->text(0));
  414.                 }
  415.                 else {
  416.                     ui.twSubscriptions->topLevelItem(i)->takeChildren();
  417.                     ui.twSubscriptions->takeTopLevelItem(i);
  418.                 }
  419.                 --i;
  420.                 continue;
  421.             }
  422.  
  423.             //if there is a subscription containing the new one we set foundSuperior true
  424.             if (MQTTHelpers::checkTopicContains(ui.twSubscriptions->topLevelItem(i)->text(0), name)
  425.                     && name != ui.twSubscriptions->topLevelItem(i)->text(0)) {
  426.                 foundSuperior = true;
  427.                 QDEBUG("Can't continue subscribing. Found superior for " << name << " : " << ui.twSubscriptions->topLevelItem(i)->text(0));
  428.                 break;
  429.             }
  430.         }
  431.  
  432.         //if there wasn't a superior subscription we can subscribe to the new topic
  433.         if (!foundSuperior) {
  434.             QStringList toplevelName;
  435.             toplevelName.push_back(name);
  436.             QTreeWidgetItem* newTopLevelItem = new QTreeWidgetItem(toplevelName);
  437.             ui.twSubscriptions->addTopLevelItem(newTopLevelItem);
  438.  
  439.             if (name.endsWith('#')) {
  440.                 //adding every topic that the subscription contains to twSubscriptions
  441.                 MQTTHelpers::addSubscriptionChildren(item, newTopLevelItem);
  442.             }
  443.  
  444.             emit makeSubscription(name, static_cast<quint8>(ui.cbQos->currentText().toUInt()));
  445.  
  446.             if (name.endsWith('#')) {
  447.                 //if an already existing subscription contains a topic that the new subscription also contains
  448.                 //we decompose the already existing subscription
  449.                 //by unsubscribing from its topics, that are present in the new subscription as well
  450.                 const QStringList nameList = name.split('/', QString::SkipEmptyParts);
  451.                 const QString& root = nameList.first();
  452.                 QVector<QTreeWidgetItem*> children;
  453.                 for (int i = 0; i < ui.twSubscriptions->topLevelItemCount(); ++i) {
  454.                     if (ui.twSubscriptions->topLevelItem(i)->text(0).startsWith(root)
  455.                             && name != ui.twSubscriptions->topLevelItem(i)->text(0)) {
  456.                         children.clear();
  457.                         //get the "leaf" children of the inspected subscription
  458.                         MQTTHelpers::findSubscriptionLeafChildren(children, ui.twSubscriptions->topLevelItem(i));
  459.                         for (int j = 0; j < children.size(); ++j) {
  460.                             if (MQTTHelpers::checkTopicContains(name, children[j]->text(0))) {
  461.                                 //if the new subscription contains a topic, we unsubscribe from it
  462.                                 if(m_parent == MQTTParentWidget::ImportFileWidget) {
  463.                                     ui.twSubscriptions->setCurrentItem(children[j]);
  464.                                     mqttUnsubscribe();
  465.                                     --i;
  466.                                 } else {
  467.                                     QTreeWidgetItem* unsubscribeItem = children[j];
  468.                                     while (unsubscribeItem->parent() != nullptr) {
  469.                                         for (int i = 0; i < unsubscribeItem->parent()->childCount(); ++i) {
  470.  
  471.                                             if (unsubscribeItem->text(0) != unsubscribeItem->parent()->child(i)->text(0)) {
  472.                                                 //add topic as subscription
  473.  
  474.                                                 emit addBeforeRemoveSubscription(unsubscribeItem->parent()->child(i)->text(0), static_cast<quint8>(ui.cbQos->currentText().toUInt()));
  475.                                                 //also add it to twSubscriptions
  476.                                                 ui.twSubscriptions->addTopLevelItem(unsubscribeItem->parent()->takeChild(i));
  477.                                                 --i;
  478.                                             } else {
  479.                                                 //before we remove the topic, we reparent it to the new subscription
  480.                                                 //so no data is lost
  481.                                                 emit reparentTopic(unsubscribeItem->text(0), name);
  482.                                             }
  483.                                         }
  484.                                         unsubscribeItem = unsubscribeItem->parent();
  485.                                     }
  486.  
  487.                                     qDebug()<<"Remove: "<<unsubscribeItem->text(0);
  488.                                     emit removeMQTTSubscription(unsubscribeItem->text(0));
  489.  
  490.                                     ui.twSubscriptions->takeTopLevelItem(ui.twSubscriptions->indexOfTopLevelItem(unsubscribeItem));
  491.                                 }
  492.                             }
  493.                         }
  494.                     }
  495.                 }
  496.             }
  497.  
  498.  
  499.             //implementalj es ird at liveDataDock addsubscription!!!!!
  500.             manageCommonLevelSubscriptions();
  501.             updateSubscriptionCompleter();
  502.  
  503.             emit enableWill(true);
  504.         } else
  505.             QMessageBox::warning(this, i18n("Warning"), i18n("You already subscribed to a topic containing this one"));
  506.     } else
  507.         QMessageBox::warning(this, i18n("Warning"), i18n("You already subscribed to this topic"));
  508. }
  509.  
  510. /*!
  511.  *\brief Updates the completer for leSubscriptions
  512.  */
  513. void MQTTSubscriptionWidget::updateSubscriptionCompleter() {
  514.     QStringList subscriptionList;
  515.     for (int i = 0; i < ui.twSubscriptions->topLevelItemCount(); ++i)
  516.         subscriptionList.append(ui.twSubscriptions->topLevelItem(i)->text(0));
  517.  
  518.     if (!subscriptionList.isEmpty()) {
  519.         m_subscriptionCompleter = new QCompleter(subscriptionList, this);
  520.         m_subscriptionCompleter->setCompletionMode(QCompleter::PopupCompletion);
  521.         m_subscriptionCompleter->setCaseSensitivity(Qt::CaseSensitive);
  522.         ui.leSubscriptions->setCompleter(m_subscriptionCompleter);
  523.     } else
  524.         ui.leSubscriptions->setCompleter(nullptr);
  525. }
  526.  
  527.  
  528. /*!
  529.  *\brief called when the unsubscribe button is pressed
  530.  * unsubscribes from the topic represented by the current item of twSubscription
  531.  */
  532. void MQTTSubscriptionWidget::mqttUnsubscribe() {
  533.     QTreeWidgetItem* unsubscribeItem = ui.twSubscriptions->currentItem();
  534.     if (!unsubscribeItem) {
  535.         QMessageBox::warning(this, i18n("Warning"), i18n("You didn't select any item from the Tree Widget"));
  536.         return;
  537.     }
  538.  
  539.     QDEBUG("Unsubscribe from: " << unsubscribeItem->text(0));
  540.     //if it is a top level item, meaning a topic that we really subscribed to(not one that belongs to a subscription)
  541.     //we can simply unsubscribe from it
  542.     if (unsubscribeItem->parent() == nullptr)
  543.     {
  544.         if(m_parent == MQTTParentWidget::ImportFileWidget)
  545.             unsubscribeFromTopic(unsubscribeItem->text(0));
  546.         else {
  547.             emit removeMQTTSubscription(unsubscribeItem->text(0));
  548.             ui.twSubscriptions->takeTopLevelItem(ui.twSubscriptions->indexOfTopLevelItem(unsubscribeItem));
  549.         }
  550.     }
  551.  
  552.     //otherwise we remove the selected item, but subscribe to every other topic, that was contained by
  553.     //the selected item's parent subscription(top level item of twSubscriptions)
  554.     else {
  555.         while (unsubscribeItem->parent() != nullptr) {
  556.             for (int i = 0; i < unsubscribeItem->parent()->childCount(); ++i) {
  557.                 if (unsubscribeItem->text(0) != unsubscribeItem->parent()->child(i)->text(0)) {
  558.                     if(m_parent == MQTTParentWidget::ImportFileWidget)
  559.                         emit makeSubscription(unsubscribeItem->parent()->child(i)->text(0), static_cast<quint8>(ui.cbQos->currentText().toUInt()));
  560.                     else {
  561.                         emit addBeforeRemoveSubscription(unsubscribeItem->parent()->child(i)->text(0), static_cast<quint8>(ui.cbQos->currentText().toUInt()));
  562.                     }
  563.  
  564.                     ui.twSubscriptions->addTopLevelItem(unsubscribeItem->parent()->takeChild(i));
  565.                     --i;
  566.                 }
  567.             }
  568.             unsubscribeItem = unsubscribeItem->parent();
  569.         }
  570.  
  571.         if(m_parent == MQTTParentWidget::ImportFileWidget)
  572.             unsubscribeFromTopic(unsubscribeItem->text(0));
  573.         else {
  574.             emit removeMQTTSubscription(unsubscribeItem->text(0));
  575.             ui.twSubscriptions->takeTopLevelItem(ui.twSubscriptions->indexOfTopLevelItem(unsubscribeItem));
  576.         }
  577.  
  578.         //check if any common topics were subscribed, if possible merge them
  579.         manageCommonLevelSubscriptions();
  580.     }
  581.     updateSubscriptionCompleter();
  582.  
  583.     if (ui.twSubscriptions->topLevelItemCount() <= 0)
  584.         emit enableWill(false);
  585. }
  586.  
  587. /*!
  588.  *\brief called when a new topic is added to the tree(twTopics)
  589.  * appends the topic's root to the topicList if it isn't in the list already
  590.  * then sets the completer for leTopics
  591.  */
  592. void MQTTSubscriptionWidget::setTopicCompleter(const QString& topic) {
  593.     if (!m_searching) {
  594.         const QStringList& list = topic.split('/', QString::SkipEmptyParts);
  595.         QString tempTopic;
  596.         if (!list.isEmpty()) {
  597.             tempTopic = list.at(0);
  598.         } else
  599.             tempTopic = topic;
  600.  
  601.         if (!m_topicList.contains(tempTopic)) {
  602.             m_topicList.append(tempTopic);
  603.             m_topicCompleter = new QCompleter(m_topicList, this);
  604.             m_topicCompleter->setCompletionMode(QCompleter::PopupCompletion);
  605.             m_topicCompleter->setCaseSensitivity(Qt::CaseSensitive);
  606.             ui.leTopics->setCompleter(m_topicCompleter);
  607.         }
  608.     }
  609. }
  610.  
  611. /*!
  612.  *\brief called when leTopics' text is changed
  613.  *       if the rootName can be found in twTopics, then we scroll it to the top of the tree widget
  614.  *
  615.  * \param rootName the current text of leTopics
  616.  */
  617. void MQTTSubscriptionWidget::scrollToTopicTreeItem(const QString& rootName) {
  618.     m_searching = true;
  619.     m_searchTimer->start();
  620.  
  621.     int topItemIdx = -1;
  622.     for (int i = 0; i < ui.twTopics->topLevelItemCount(); ++i)
  623.         if (ui.twTopics->topLevelItem(i)->text(0) == rootName) {
  624.             topItemIdx = i;
  625.             break;
  626.         }
  627.  
  628.     if (topItemIdx >= 0)
  629.         ui.twTopics->scrollToItem(ui.twTopics->topLevelItem(topItemIdx), QAbstractItemView::ScrollHint::PositionAtTop);
  630. }
  631.  
  632. /*!
  633.  *\brief called when leSubscriptions' text is changed
  634.  *       if the rootName can be found in twSubscriptions, then we scroll it to the top of the tree widget
  635.  *
  636.  * \param rootName the current text of leSubscriptions
  637.  */
  638. void MQTTSubscriptionWidget::scrollToSubsriptionTreeItem(const QString& rootName) {
  639.     int topItemIdx = -1;
  640.     for (int i = 0; i < ui.twSubscriptions->topLevelItemCount(); ++i)
  641.         if (ui.twSubscriptions->topLevelItem(i)->text(0) == rootName) {
  642.             topItemIdx = i;
  643.             break;
  644.         }
  645.  
  646.     if (topItemIdx >= 0)
  647.         ui.twSubscriptions->scrollToItem(ui.twSubscriptions->topLevelItem(topItemIdx), QAbstractItemView::ScrollHint::PositionAtTop);
  648. }
  649.  
  650. /*!
  651.  *\brief called when 10 seconds passed since the last time the user searched for a certain root in twTopics
  652.  * enables updating the completer for le
  653.  */
  654. void MQTTSubscriptionWidget::topicTimeout() {
  655.     m_searching = false;
  656.     m_searchTimer->stop();
  657. }
  658.  
  659. void MQTTSubscriptionWidget::clearWidgets() {
  660.     ui.twTopics->clear();
  661.     ui.twSubscriptions->clear();
  662.     ui.twTopics->headerItem()->setText(0, i18n("Available"));
  663. }
  664.  
  665. void MQTTSubscriptionWidget::onDisconnect() {
  666.     m_searchTimer->stop();
  667.     m_searching = false;
  668.     delete m_topicCompleter;
  669.     delete m_subscriptionCompleter;
  670. }
  671. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement