labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

MQTTTopic.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 File : MQTTTopic.cpp
3 Project : LabPlot
4 Description : Represents a topic of a MQTTSubscription
5 --------------------------------------------------------------------
6 Copyright : (C) 2018 Kovacs Ferencz (kferike98@gmail.com)
7 
8 ***************************************************************************/
9 
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program; if not, write to the Free Software *
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
25 * Boston, MA 02110-1301 USA *
26 * *
27 ***************************************************************************/
29 
35 
36 #include <QMenu>
37 #include <QIcon>
38 #include <QAction>
39 #include <KLocalizedString>
40 
41 /*!
42  \class MQTTTopic
43  \brief Represents a topic of a subscription made in MQTTClient.
44 
45  \ingroup datasources
46 */
47 MQTTTopic::MQTTTopic(const QString& name, MQTTSubscription* subscription, bool loading) :
48  Spreadsheet(name, loading, AspectType::MQTTTopic),
49  m_topicName(name),
50  m_MQTTClient(subscription->mqttClient()),
51  m_filter(new AsciiFilter) {
52 
53  auto mainFilter = m_MQTTClient->filter();
54 
55  m_filter->setAutoModeEnabled(mainFilter->isAutoModeEnabled());
56  if (!mainFilter->isAutoModeEnabled()) {
57  m_filter->setCommentCharacter(mainFilter->commentCharacter());
58  m_filter->setSeparatingCharacter(mainFilter->separatingCharacter());
59  m_filter->setDateTimeFormat(mainFilter->dateTimeFormat());
60  m_filter->setCreateIndexEnabled(mainFilter->createIndexEnabled());
61  m_filter->setCreateTimestampEnabled(mainFilter->createTimestampEnabled());
62  m_filter->setSimplifyWhitespacesEnabled(mainFilter->simplifyWhitespacesEnabled());
63  m_filter->setNaNValueToZero(mainFilter->NaNValueToZeroEnabled());
64  m_filter->setRemoveQuotesEnabled(mainFilter->removeQuotesEnabled());
65  m_filter->setSkipEmptyParts(mainFilter->skipEmptyParts());
66  m_filter->setHeaderEnabled(mainFilter->isHeaderEnabled());
67  QString vectorNames;
68  const QStringList& filterVectorNames = mainFilter->vectorNames();
69  for (int i = 0; i < filterVectorNames.size(); ++i) {
70  vectorNames.append(filterVectorNames.at(i));
71  if (i != vectorNames.size() - 1)
72  vectorNames.append(QLatin1String(" "));
73  }
74 
75  m_filter->setVectorNames(vectorNames);
76  m_filter->setStartRow(mainFilter->startRow());
77  m_filter->setEndRow(mainFilter->endRow());
78  m_filter->setStartColumn(mainFilter->startColumn());
79  m_filter->setEndColumn(mainFilter->endColumn());
80  }
81 
83  qDebug()<<"New MqttTopic: " << m_topicName;
84  initActions();
85 }
86 
88  qDebug()<<"MqttTopic destructor:"<<m_topicName;
89  delete m_filter;
90 }
91 
92 /*!
93  *\brief Sets the MQTTTopic's filter
94  * The ownership of the filter is passed to MQTTTopic.
95  *
96  * \param filter
97  */
99  delete m_filter;
100  m_filter = f;
101 }
102 
103 /*!
104  *\brief Returns the MQTTTopic's filter
105  */
107  return m_filter;
108 }
109 
110 /*!
111  *\brief Returns the MQTTTopic's icon
112  */
113 QIcon MQTTTopic::icon() const {
114  return QIcon::fromTheme("text-plain");
115 }
116 
117 /*!
118  *\brief Adds an action to the MQTTTopic's context menu in the project explorer
119  */
121  QMenu* menu = AbstractPart::createContextMenu();
122 
123  QAction* firstAction = nullptr;
124  // if we're populating the context menu for the project explorer, then
125  //there're already actions available there. Skip the first title-action
126  //and insert the action at the beginning of the menu.
127  if (menu->actions().size() > 1)
128  firstAction = menu->actions().at(1);
129 
130  menu->insertAction(firstAction, m_plotDataAction);
131  menu->insertSeparator(firstAction);
132 
133  return menu;
134 }
135 
136 QWidget* MQTTTopic::view() const {
137  if (!m_partView)
138  m_partView = new SpreadsheetView(const_cast<MQTTTopic*>(this), true);
139  return m_partView;
140 }
141 
142 /*!
143  *\brief Adds a message received by the topic to the message puffer
144  */
145 void MQTTTopic::newMessage(const QString& message) {
146  m_messagePuffer.push_back(message);
147 }
148 
149 /*!
150  *\brief Returns the name of the MQTTTopic
151  */
152 QString MQTTTopic::topicName() const {
153  return m_topicName;
154 }
155 
156 /*!
157  *\brief Initializes the actions of MQTTTopic
158  */
160  m_plotDataAction = new QAction(QIcon::fromTheme("office-chart-line"), i18n("Plot data"), this);
161  connect(m_plotDataAction, &QAction::triggered, this, &MQTTTopic::plotData);
162 }
163 
164 /*!
165  *\brief Returns the MQTTClient the topic belongs to
166  */
168  return m_MQTTClient;
169 }
170 
171 //##############################################################################
172 //################################# SLOTS ####################################
173 //##############################################################################
174 
175 /*!
176  *\brief Plots the data stored in MQTTTopic
177  */
179  auto* dlg = new PlotDataDialog(this);
180  dlg->exec();
181 }
182 
183 /*!
184  *\brief Reads every message from the message puffer
185  */
187  while (!m_messagePuffer.isEmpty()) {
188  qDebug() << "Reading from topic " << m_topicName;
189  const QString tempMessage = m_messagePuffer.takeFirst();
190  m_filter->readMQTTTopic(tempMessage, this);
191  }
192 }
193 
194 //##############################################################################
195 //################## Serialization/Deserialization ###########################
196 //##############################################################################
197 /*!
198  Saves as XML.
199  */
200 void MQTTTopic::save(QXmlStreamWriter* writer) const {
201  writer->writeStartElement("MQTTTopic");
202  writeBasicAttributes(writer);
203  writeCommentElement(writer);
204 
205  //general
206  writer->writeStartElement("general");
207  writer->writeAttribute("topicName", m_topicName);
208  writer->writeAttribute("filterPrepared", QString::number(m_filter->isPrepared()));
209  writer->writeAttribute("filterSeparator", m_filter->separator());
210  writer->writeAttribute("messagePufferSize", QString::number(m_messagePuffer.size()));
211  for (int i = 0; i < m_messagePuffer.count(); ++i)
212  writer->writeAttribute("message"+QString::number(i), m_messagePuffer[i]);
213  writer->writeEndElement();
214 
215  //filter
216  m_filter->save(writer);
217 
218  //Columns
219  for (auto* col : children<Column>(AbstractAspect::ChildIndexFlag::IncludeHidden))
220  col->save(writer);
221 
222  writer->writeEndElement(); //MQTTTopic
223 }
224 
225 /*!
226  Loads from XML.
227 */
228 bool MQTTTopic::load(XmlStreamReader* reader, bool preview) {
230  if (!readBasicAttributes(reader))
231  return false;
232 
233  bool isFilterPrepared = false;
234  QString separator;
235 
236  QString attributeWarning = i18n("Attribute '%1' missing or empty, default value is used");
237  QXmlStreamAttributes attribs;
238  QString str;
239 
240  while (!reader->atEnd()) {
241  reader->readNext();
242  if (reader->isEndElement() && reader->name() == "MQTTTopic")
243  break;
244 
245  if (!reader->isStartElement())
246  continue;
247 
248  if (reader->name() == "comment") {
249  if (!readCommentElement(reader))
250  return false;
251  } else if (reader->name() == "general") {
252  attribs = reader->attributes();
253 
254  str = attribs.value("topicName").toString();
255  if (str.isEmpty())
256  reader->raiseWarning(attributeWarning.arg("'topicName'"));
257  else {
258  m_topicName = str;
259  setName(str);
260  }
261 
262  str = attribs.value("filterPrepared").toString();
263  if (str.isEmpty())
264  reader->raiseWarning(attributeWarning.arg("'filterPrepared'"));
265  else {
266  isFilterPrepared = str.toInt();
267  }
268 
269  str = attribs.value("filterSeparator").toString();
270  if (str.isEmpty())
271  reader->raiseWarning(attributeWarning.arg("'filterSeparator'"));
272  else {
273  separator = str;
274  }
275 
276  int pufferSize = 0;
277  str = attribs.value("messagePufferSize").toString();
278  if (str.isEmpty())
279  reader->raiseWarning(attributeWarning.arg("'messagePufferSize'"));
280  else
281  pufferSize = str.toInt();
282  for (int i = 0; i < pufferSize; ++i) {
283  str = attribs.value("message"+QString::number(i)).toString();
284  if (str.isEmpty())
285  reader->raiseWarning(attributeWarning.arg("'message"+QString::number(i)+'\''));
286  else
287  m_messagePuffer.push_back(str);
288  }
289  } else if (reader->name() == "asciiFilter") {
290  if (!m_filter->load(reader))
291  return false;
292  } else if (reader->name() == "column") {
294  if (!column->load(reader, preview)) {
295  delete column;
296  setColumnCount(0);
297  return false;
298  }
299  addChild(column);
300  } else {// unknown element
301  reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
302  if (!reader->skipToEndElement())
303  return false;
304  }
305  }
306 
307  //prepare filter for reading
308  m_filter->setPreparedForMQTT(isFilterPrepared, this, separator);
309 
310  return !reader->hasError();
311 }
AspectType
bool readCommentElement(XmlStreamReader *)
Load comment from an XML element.
@ IncludeHidden
Include aspects marked as "hidden" in numbering or listing children.
void addChild(AbstractAspect *)
Add the given Aspect to my list of children.
void writeBasicAttributes(QXmlStreamWriter *) const
Save name and creation time to XML.
bool setName(const QString &, bool autoUnique=true)
AbstractAspect::setName sets the name of the abstract aspect.
bool readBasicAttributes(XmlStreamReader *)
Load name and creation time from XML.
void writeCommentElement(QXmlStreamWriter *) const
Save the comment to XML.
QMenu * createContextMenu() override
Return AbstractAspect::createContextMenu() plus operations on the primary view.
QWidget * m_partView
Definition: AbstractPart.h:65
Manages the import/export of data organized as columns (vectors) from/to an ASCII-file.
Definition: AsciiFilter.h:42
void setCommentCharacter(const QString &)
void setEndColumn(const int)
void setHeaderEnabled(const bool)
void setVectorNames(const QString &)
void setRemoveQuotesEnabled(const bool)
void save(QXmlStreamWriter *) const override
void setStartRow(const int)
QString separator() const
int isPrepared()
void setSkipEmptyParts(const bool)
void setStartColumn(const int)
void setSeparatingCharacter(const QString &)
bool load(XmlStreamReader *) override
void setEndRow(const int)
void setAutoModeEnabled(const bool)
void setCreateIndexEnabled(const bool)
void setSimplifyWhitespacesEnabled(const bool)
void setCreateTimestampEnabled(const bool)
void setNaNValueToZero(const bool)
void setDateTimeFormat(const QString &)
Aspect that manages a column.
Definition: Column.h:42
bool load(XmlStreamReader *, bool preview) override
Load the column from XML.
Definition: Column.cpp:1152
The MQTT Client connects to the broker set in ImportFileWidget. It manages the MQTTSubscriptions,...
Definition: MQTTClient.h:48
void readFromTopics()
AsciiFilter * filter() const
Returns the filter of the MQTTClient.
Definition: MQTTClient.cpp:117
Represents a subscription made in a MQTTClient object. It plays a role in managing MQTTTopic objects ...
Represents a topic of a subscription made in MQTTClient.
Definition: MQTTTopic.h:39
MQTTClient * m_MQTTClient
Definition: MQTTTopic.h:64
QString m_topicName
Definition: MQTTTopic.h:63
void plotData()
Plots the data stored in MQTTTopic.
Definition: MQTTTopic.cpp:178
bool load(XmlStreamReader *, bool preview) override
Definition: MQTTTopic.cpp:228
QString topicName() const
Returns the name of the MQTTTopic.
Definition: MQTTTopic.cpp:152
AsciiFilter * filter() const
Returns the MQTTTopic's filter.
Definition: MQTTTopic.cpp:106
MQTTTopic(const QString &name, MQTTSubscription *subscription, bool loading=false)
Definition: MQTTTopic.cpp:47
void initActions()
Initializes the actions of MQTTTopic.
Definition: MQTTTopic.cpp:159
QIcon icon() const override
Returns the MQTTTopic's icon.
Definition: MQTTTopic.cpp:113
void setFilter(AsciiFilter *)
Sets the MQTTTopic's filter The ownership of the filter is passed to MQTTTopic.
Definition: MQTTTopic.cpp:98
void newMessage(const QString &)
Adds a message received by the topic to the message puffer.
Definition: MQTTTopic.cpp:145
QAction * m_plotDataAction
Definition: MQTTTopic.h:67
MQTTClient * mqttClient() const
Returns the MQTTClient the topic belongs to.
Definition: MQTTTopic.cpp:167
~MQTTTopic() override
Definition: MQTTTopic.cpp:87
void save(QXmlStreamWriter *) const override
Definition: MQTTTopic.cpp:200
QVector< QString > m_messagePuffer
Definition: MQTTTopic.h:66
AsciiFilter * m_filter
Definition: MQTTTopic.h:65
void read()
Reads every message from the message puffer.
Definition: MQTTTopic.cpp:186
QMenu * createContextMenu() override
Adds an action to the MQTTTopic's context menu in the project explorer.
Definition: MQTTTopic.cpp:120
QWidget * view() const override
Construct a primary view on me.
Definition: MQTTTopic.cpp:136
Dialog for generating plots for the spreadsheet data.
View class for Spreadsheet.
Aspect providing a spreadsheet table with column logic.
Definition: Spreadsheet.h:40
int columnCount() const
Column * column(int index) const
void removeColumns(int first, int count)
void setColumnCount(int)
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
void raiseWarning(const QString &)
#define i18n(m)
Definition: nsl_common.h:38