diff --git a/src/backend/cantorWorksheet/CantorWorksheet.cpp b/src/backend/cantorWorksheet/CantorWorksheet.cpp index 6fa927e6c..912ca062b 100644 --- a/src/backend/cantorWorksheet/CantorWorksheet.cpp +++ b/src/backend/cantorWorksheet/CantorWorksheet.cpp @@ -1,326 +1,326 @@ /*************************************************************************** File : CantorWorksheet.cpp Project : LabPlot Description : Aspect providing a Cantor Worksheets for Multiple backends -------------------------------------------------------------------- Copyright : (C) 2015 Garvit Khatri (garvitdelhi@gmail.com) Copyright : (C) 2016 by Alexander Semke (alexander.semke@web.de) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU 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 "CantorWorksheet.h" #include "VariableParser.h" #include "backend/core/column/Column.h" #include "backend/core/column/ColumnPrivate.h" #include "backend/core/Project.h" #include "commonfrontend/cantorWorksheet/CantorWorksheetView.h" #include #include #include #include #include #include #include "cantor/cantor_part.h" #include #include #include CantorWorksheet::CantorWorksheet(const QString &name, bool loading) : AbstractPart(name, AspectType::CantorWorksheet), m_backendName(name) { if (!loading) init(); } /*! initializes Cantor's part and plugins */ bool CantorWorksheet::init(QByteArray* content) { KPluginFactory* factory = KPluginLoader(QLatin1String("libcantorpart")).factory(); if (factory) { m_part = factory->create(this, QVariantList() << m_backendName << QLatin1String("--noprogress")); if (!m_part) { qDebug() << "Could not create the Cantor Part."; return false; } m_worksheetAccess = m_part->findChild(Cantor::WorksheetAccessInterface::Name); //load worksheet content if available if (content) m_worksheetAccess->loadWorksheetFromByteArray(content); connect(m_worksheetAccess, SIGNAL(modified()), this, SLOT(modified())); //Cantor's session m_session = m_worksheetAccess->session(); connect(m_session, SIGNAL(statusChanged(Cantor::Session::Status)), this, SIGNAL(statusChanged(Cantor::Session::Status))); //variable model #ifndef OLD_CANTORLIBS_VERSION m_variableModel = m_session->variableDataModel(); #else m_variableModel = m_session->variableModel(); #endif - connect(m_variableModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(dataChanged(QModelIndex))); - connect(m_variableModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int))); - connect(m_variableModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); - connect(m_variableModel, SIGNAL(modelReset()), this, SLOT(modelReset())); + connect(m_variableModel, &QAbstractItemModel::dataChanged, this, &CantorWorksheet::dataChanged); + connect(m_variableModel, &QAbstractItemModel::rowsInserted, this, &CantorWorksheet::rowsInserted); + connect(m_variableModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &CantorWorksheet::rowsAboutToBeRemoved); + connect(m_variableModel, &QAbstractItemModel::modelReset, this, &CantorWorksheet::modelReset); //available plugins auto* handler = m_part->findChild(QLatin1String("PanelPluginHandler")); if (!handler) { KMessageBox::error(view(), i18n("no PanelPluginHandle found for the Cantor Part.")); return false; } m_plugins = handler->plugins(); } else { //we can only get to this here if we open a project having Cantor content and Cantor plugins were not found. //return false here, a proper error message will be created in load() and propagated further. DEBUG("Failed to load cantor plugin"); return false; } return true; } //SLots void CantorWorksheet::dataChanged(const QModelIndex& index) { const QString& name = m_variableModel->data(m_variableModel->index(index.row(), 0)).toString(); Column* col = child(name); if (col) { // Cantor::DefaultVariableModel::DataRole == 257 QVariant dataValue = m_variableModel->data(m_variableModel->index(index.row(), 1), 257); if (dataValue.isNull()) dataValue = m_variableModel->data(m_variableModel->index(index.row(), 1)); const QString& value = dataValue.toString(); auto* parser = new VariableParser(m_backendName, value); if (parser->isParsed()) col->replaceValues(0, parser->values()); } } void CantorWorksheet::rowsInserted(const QModelIndex& parent, int first, int last) { Q_UNUSED(parent) for (int i = first; i <= last; ++i) { const QString& name = m_variableModel->data(m_variableModel->index(i, 0)).toString(); QVariant dataValue = m_variableModel->data(m_variableModel->index(i, 1), 257); if (dataValue.isNull()) dataValue = m_variableModel->data(m_variableModel->index(i, 1)); const QString& value = dataValue.toString(); auto* parser = new VariableParser(m_backendName, value); if (parser->isParsed()) { Column* col = child(name); if (col) { col->replaceValues(0, parser->values()); } else { col = new Column(name, parser->values()); col->setUndoAware(false); addChild(col); //TODO: Cantor currently ignores the order of variables in the worksheets //and adds new variables at the last position in the model. //Fix this in Cantor and switch to insertChildBefore here later. //insertChildBefore(col, child(i)); } } else { //the already existing variable doesn't contain any numerical values -> remove it Column* col = child(name); if (col) removeChild(col); } delete(parser); } project()->setChanged(true); } void CantorWorksheet::modified() { project()->setChanged(true); } void CantorWorksheet::modelReset() { for (int i = 0; i < childCount(); ++i) child(i)->remove(); } void CantorWorksheet::rowsAboutToBeRemoved(const QModelIndex & parent, int first, int last) { Q_UNUSED(parent); #ifndef OLD_CANTORLIBS_VERSION for (int i = first; i <= last; ++i) { const QString& name = m_variableModel->data(m_variableModel->index(first, 0)).toString(); Column* column = child(name); if (column) column->remove(); } #else Q_UNUSED(first); Q_UNUSED(last); //TODO: Old Cantor removes rows from the model even when the variable was changed only. //We don't want this behaviour since this removes the columns from the datasource in the curve. return; #endif } QList CantorWorksheet::getPlugins() { return m_plugins; } KParts::ReadWritePart* CantorWorksheet::part() { return m_part; } QIcon CantorWorksheet::icon() const { if (m_session) return QIcon::fromTheme(m_session->backend()->icon()); return QIcon(); } QWidget* CantorWorksheet::view() const { if (!m_partView) { m_view = new CantorWorksheetView(const_cast(this)); m_view->setBaseSize(1500, 1500); m_partView = m_view; // connect(m_view, SIGNAL(statusInfo(QString)), this, SIGNAL(statusInfo(QString))); } return m_partView; } //! Return a new context menu. /** * The caller takes ownership of the menu. */ QMenu* CantorWorksheet::createContextMenu() { QMenu* menu = AbstractPart::createContextMenu(); Q_ASSERT(menu); emit requestProjectContextMenu(menu); return menu; } QString CantorWorksheet::backendName() { return this->m_backendName; } //TODO bool CantorWorksheet::exportView() const { return false; } bool CantorWorksheet::printView() { m_part->action("file_print")->trigger(); return true; } bool CantorWorksheet::printPreview() const { m_part->action("file_print_preview")->trigger(); return true; } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## //! Save as XML void CantorWorksheet::save(QXmlStreamWriter* writer) const{ writer->writeStartElement("cantorWorksheet"); writeBasicAttributes(writer); writeCommentElement(writer); //general writer->writeStartElement( "general" ); writer->writeAttribute( "backend_name", m_backendName); //TODO: save worksheet settings writer->writeEndElement(); //save the content of Cantor's worksheet QByteArray content = m_worksheetAccess->saveWorksheetToByteArray(); writer->writeStartElement("worksheet"); writer->writeAttribute("content", content.toBase64()); writer->writeEndElement(); //save columns(variables) for (auto* col : children(IncludeHidden)) col->save(writer); writer->writeEndElement(); // close "cantorWorksheet" section } //! Load from XML bool CantorWorksheet::load(XmlStreamReader* reader, bool preview) { if (!readBasicAttributes(reader)) return false; KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); QXmlStreamAttributes attribs; QString str; bool rc = false; while (!reader->atEnd()) { reader->readNext(); if (reader->isEndElement() && reader->name() == "cantorWorksheet") break; if (!reader->isStartElement()) continue; if (reader->name() == "comment") { if (!readCommentElement(reader)) return false; } else if (!preview && reader->name() == "general") { attribs = reader->attributes(); m_backendName = attribs.value("backend_name").toString().trimmed(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("backend_name").toString()); } else if (!preview && reader->name() == "worksheet") { attribs = reader->attributes(); str = attribs.value("content").toString().trimmed(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.subs("content").toString()); QByteArray content = QByteArray::fromBase64(str.toLatin1()); rc = init(&content); if (!rc) { QString msg = i18n("This project has Cantor content but no Cantor plugins were found. Please check your installation. The project will be closed."); reader->raiseError(msg); return false; } } else if (!preview && reader->name() == "column") { Column* column = new Column(QString()); column->setUndoAware(false); if (!column->load(reader, preview)) { delete column; return false; } addChild(column); } else { // unknown element reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); if (!reader->skipToEndElement()) return false; } } return true; } diff --git a/src/backend/datasources/MQTTTopic.cpp b/src/backend/datasources/MQTTTopic.cpp index 9fe31ab9d..d6f2dffb5 100644 --- a/src/backend/datasources/MQTTTopic.cpp +++ b/src/backend/datasources/MQTTTopic.cpp @@ -1,314 +1,314 @@ /*************************************************************************** File : MQTTTopic.cpp Project : LabPlot Description : Represents a topic of a MQTTSubscription -------------------------------------------------------------------- Copyright : (C) 2018 Kovacs Ferencz (kferike98@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU 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 "backend/datasources/MQTTTopic.h" #ifdef HAVE_MQTT #include "backend/datasources/MQTTSubscription.h" #include "backend/datasources/MQTTClient.h" #include "kdefrontend/spreadsheet/PlotDataDialog.h" #include "commonfrontend/spreadsheet/SpreadsheetView.h" #include "backend/datasources/filters/AsciiFilter.h" #include #include #include #include #include #include /*! \class MQTTTopic \brief Represents a topic of a subscription made in MQTTClient. \ingroup datasources */ MQTTTopic::MQTTTopic(const QString& name, MQTTSubscription* subscription, bool loading) : Spreadsheet(name, loading, AspectType::MQTTTopic), m_topicName(name), m_MQTTClient(subscription->mqttClient()), m_filter(new AsciiFilter) { auto mainFilter = m_MQTTClient->filter(); m_filter->setAutoModeEnabled(mainFilter->isAutoModeEnabled()); if (!mainFilter->isAutoModeEnabled()) { m_filter->setCommentCharacter(mainFilter->commentCharacter()); m_filter->setSeparatingCharacter(mainFilter->separatingCharacter()); m_filter->setDateTimeFormat(mainFilter->dateTimeFormat()); m_filter->setCreateIndexEnabled(mainFilter->createIndexEnabled()); m_filter->setSimplifyWhitespacesEnabled(mainFilter->simplifyWhitespacesEnabled()); m_filter->setNaNValueToZero(mainFilter->NaNValueToZeroEnabled()); m_filter->setRemoveQuotesEnabled(mainFilter->removeQuotesEnabled()); m_filter->setSkipEmptyParts(mainFilter->skipEmptyParts()); m_filter->setHeaderEnabled(mainFilter->isHeaderEnabled()); QString vectorNames; const QStringList& filterVectorNames = mainFilter->vectorNames(); for (int i = 0; i < filterVectorNames.size(); ++i) { vectorNames.append(filterVectorNames.at(i)); if (i != vectorNames.size() - 1) vectorNames.append(QLatin1String(" ")); } m_filter->setVectorNames(vectorNames); m_filter->setStartRow(mainFilter->startRow()); m_filter->setEndRow(mainFilter->endRow()); m_filter->setStartColumn(mainFilter->startColumn()); m_filter->setEndColumn(mainFilter->endColumn()); } connect(m_MQTTClient, &MQTTClient::readFromTopics, this, &MQTTTopic::read); qDebug()<<"New MqttTopic: " << m_topicName; initActions(); } MQTTTopic::~MQTTTopic() { qDebug()<<"MqttTopic destructor:"<actions().size() > 1) firstAction = menu->actions().at(1); menu->insertAction(firstAction, m_plotDataAction); menu->insertSeparator(firstAction); return menu; } QWidget* MQTTTopic::view() const { if (!m_partView) m_partView = new SpreadsheetView(const_cast(this), true); return m_partView; } /*! *\brief Adds a message received by the topic to the message puffer */ void MQTTTopic::newMessage(const QString& message) { m_messagePuffer.push_back(message); } /*! *\brief Returns the name of the MQTTTopic */ QString MQTTTopic::topicName() const { return m_topicName; } /*! *\brief Initializes the actions of MQTTTopic */ void MQTTTopic::initActions() { m_plotDataAction = new QAction(QIcon::fromTheme("office-chart-line"), i18n("Plot data"), this); connect(m_plotDataAction, &QAction::triggered, this, &MQTTTopic::plotData); } /*! *\brief Returns the MQTTClient the topic belongs to */ MQTTClient *MQTTTopic::mqttClient() const { return m_MQTTClient; } //############################################################################## //################################# SLOTS #################################### //############################################################################## /*! *\brief Plots the data stored in MQTTTopic */ void MQTTTopic::plotData() { PlotDataDialog* dlg = new PlotDataDialog(this); dlg->exec(); } /*! *\brief Reads every message from the message puffer */ void MQTTTopic::read() { while (!m_messagePuffer.isEmpty()) { qDebug() << "Reading from topic " << m_topicName; const QString tempMessage = m_messagePuffer.takeFirst(); m_filter->readMQTTTopic(tempMessage, this); } } //############################################################################## //################## Serialization/Deserialization ########################### //############################################################################## /*! Saves as XML. */ void MQTTTopic::save(QXmlStreamWriter* writer) const { writer->writeStartElement("MQTTTopic"); writeBasicAttributes(writer); writeCommentElement(writer); //general writer->writeStartElement("general"); writer->writeAttribute("topicName", m_topicName); writer->writeAttribute("filterPrepared", QString::number(m_filter->isPrepared())); writer->writeAttribute("filterSeparator", m_filter->separator()); writer->writeAttribute("messagePufferSize", QString::number(m_messagePuffer.size())); for (int i = 0; i < m_messagePuffer.count(); ++i) writer->writeAttribute("message"+QString::number(i), m_messagePuffer[i]); writer->writeEndElement(); //filter m_filter->save(writer); //Columns for (auto* col : children(IncludeHidden)) col->save(writer); writer->writeEndElement(); //MQTTTopic } /*! Loads from XML. */ bool MQTTTopic::load(XmlStreamReader* reader, bool preview) { removeColumns(0, columnCount()); if (!readBasicAttributes(reader)) return false; bool isFilterPrepared = false; QString separator; QString attributeWarning = i18n("Attribute '%1' missing or empty, default value is used"); QXmlStreamAttributes attribs; QString str; while (!reader->atEnd()) { reader->readNext(); if (reader->isEndElement() && reader->name() == "MQTTTopic") break; if (!reader->isStartElement()) continue; if (reader->name() == "comment") { if (!readCommentElement(reader)) return false; } else if (reader->name() == "general") { attribs = reader->attributes(); str = attribs.value("topicName").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.arg("'topicName'")); else { m_topicName = str; setName(str); } str = attribs.value("filterPrepared").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.arg("'filterPrepared'")); else { isFilterPrepared = str.toInt(); } str = attribs.value("filterSeparator").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.arg("'filterSeparator'")); else { separator = str; } int pufferSize = 0; str = attribs.value("messagePufferSize").toString(); if (str.isEmpty()) reader->raiseWarning(attributeWarning.arg("'messagePufferSize'")); else pufferSize = str.toInt(); for (int i = 0; i < pufferSize; ++i) { str = attribs.value("message"+QString::number(i)).toString(); if (str.isEmpty()) - reader->raiseWarning(attributeWarning.arg("'message"+QString::number(i)+''')); + reader->raiseWarning(attributeWarning.arg("'message"+QString::number(i)+'\'')); else m_messagePuffer.push_back(str); } } else if (reader->name() == "asciiFilter") { if (!m_filter->load(reader)) return false; } else if (reader->name() == "column") { Column* column = new Column(QString(), AbstractColumn::Text); if (!column->load(reader, preview)) { delete column; setColumnCount(0); return false; } addChild(column); } else {// unknown element reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); if (!reader->skipToEndElement()) return false; } } //prepare filter for reading m_filter->setPreparedForMQTT(isFilterPrepared, this, separator); return !reader->hasError(); } #endif diff --git a/src/kdefrontend/dockwidgets/BaseDock.h b/src/kdefrontend/dockwidgets/BaseDock.h index f8ed8b0dd..286666b8f 100644 --- a/src/kdefrontend/dockwidgets/BaseDock.h +++ b/src/kdefrontend/dockwidgets/BaseDock.h @@ -1,56 +1,56 @@ /*************************************************************************** File : BaseDock.h Project : LabPlot Description : Base dock widget -------------------------------------------------------------------- Copyright : (C) 2019 Martin Marmsoler (martin.marmsoler@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU 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 * * * ***************************************************************************/ #ifndef BASEDOCK #define BASEDOCK #include #include class AbstractAspect; class BaseDock : public QWidget { Q_OBJECT public: - BaseDock(QWidget* parent); + explicit BaseDock(QWidget* parent); ~BaseDock(); protected: bool m_initializing{false}; QLineEdit* m_leName{nullptr}; QLineEdit* m_leComment{nullptr}; AbstractAspect* m_aspect{nullptr}; QList m_aspects; protected slots: void nameChanged(); void commentChanged(); }; #endif