"Fossies" - the Fresh Open Source Software Archive

Member "labplot-2.8.2/src/backend/cantorWorksheet/CantorWorksheet.cpp" (24 Feb 2021, 12294 Bytes) of package /linux/privat/labplot-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "CantorWorksheet.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.1_vs_2.8.2.

    1 /***************************************************************************
    2     File                 : CantorWorksheet.cpp
    3     Project              : LabPlot
    4     Description          : Aspect providing a Cantor Worksheets for Multiple backends
    5     --------------------------------------------------------------------
    6     Copyright            : (C) 2015 Garvit Khatri (garvitdelhi@gmail.com)
    7     Copyright            : (C) 2016 by Alexander Semke (alexander.semke@web.de)
    8 
    9  ***************************************************************************/
   10 
   11 /***************************************************************************
   12  *                                                                         *
   13  *  This program is free software; you can redistribute it and/or modify   *
   14  *  it under the terms of the GNU General Public License as published by   *
   15  *  the Free Software Foundation; either version 2 of the License, or      *
   16  *  (at your option) any later version.                                    *
   17  *                                                                         *
   18  *  This program is distributed in the hope that it will be useful,        *
   19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
   20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
   21  *  GNU General Public License for more details.                           *
   22  *                                                                         *
   23  *   You should have received a copy of the GNU General Public License     *
   24  *   along with this program; if not, write to the Free Software           *
   25  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
   26  *   Boston, MA  02110-1301  USA                                           *
   27  *                                                                         *
   28  ***************************************************************************/
   29 #include "CantorWorksheet.h"
   30 #include "VariableParser.h"
   31 #include "backend/core/column/Column.h"
   32 #include "backend/core/column/ColumnPrivate.h"
   33 #include "backend/core/Project.h"
   34 #include "commonfrontend/cantorWorksheet/CantorWorksheetView.h"
   35 
   36 #include <cantor/cantorlibs_version.h>
   37 #include "3rdparty/cantor/cantor_part.h"
   38 #include <cantor/worksheetaccess.h>
   39 
   40 #ifdef HAVE_NEW_CANTOR_LIBS
   41 #include <cantor/panelpluginhandler.h>
   42 #include <cantor/panelplugin.h>
   43 #else
   44 #include "3rdparty/cantor/panelpluginhandler.h"
   45 #include "3rdparty/cantor/panelplugin.h"
   46 #endif
   47 
   48 #include <QAction>
   49 #include <QFileInfo>
   50 #include <QModelIndex>
   51 
   52 #include <KLocalizedString>
   53 #include <KMessageBox>
   54 #include <KParts/ReadWritePart>
   55 
   56 CantorWorksheet::CantorWorksheet(const QString &name, bool loading)
   57     : AbstractPart(name, AspectType::CantorWorksheet), m_backendName(name) {
   58 
   59     if (!loading)
   60         init();
   61 }
   62 
   63 /*!
   64     initializes Cantor's part and plugins
   65 */
   66 bool CantorWorksheet::init(QByteArray* content) {
   67     KPluginLoader loader(QLatin1String("cantorpart"));
   68     KPluginFactory* factory = loader.factory();
   69 
   70     if (!factory) {
   71         //we can only get to this here if we open a project having Cantor content and Cantor plugins were not found.
   72         //return false here, a proper error message will be created in load() and propagated further.
   73         WARN("Failed to load Cantor plugin:")
   74         WARN("Cantor Part file name: " << STDSTRING(loader.fileName()))
   75         WARN("  " << STDSTRING(loader.errorString()))
   76         return false;
   77     } else {
   78         m_part = factory->create<KParts::ReadWritePart>(this, QVariantList() << m_backendName << QLatin1String("--noprogress"));
   79         if (!m_part) {
   80             DEBUG("Could not create the Cantor Part.")
   81             return false;
   82         }
   83         m_worksheetAccess = m_part->findChild<Cantor::WorksheetAccessInterface*>(Cantor::WorksheetAccessInterface::Name);
   84 
   85         //load worksheet content if available
   86         if (content)
   87             m_worksheetAccess->loadWorksheetFromByteArray(content);
   88 
   89         connect(m_worksheetAccess, SIGNAL(modified()), this, SLOT(modified()));
   90 
   91         //Cantor's session
   92         m_session = m_worksheetAccess->session();
   93         connect(m_session, SIGNAL(statusChanged(Cantor::Session::Status)), this, SIGNAL(statusChanged(Cantor::Session::Status)));
   94 
   95         //variable model
   96         m_variableModel = m_session->variableDataModel();
   97         connect(m_variableModel, &QAbstractItemModel::dataChanged, this, &CantorWorksheet::dataChanged);
   98         connect(m_variableModel, &QAbstractItemModel::rowsInserted, this, &CantorWorksheet::rowsInserted);
   99         connect(m_variableModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &CantorWorksheet::rowsAboutToBeRemoved);
  100         connect(m_variableModel, &QAbstractItemModel::modelReset, this, &CantorWorksheet::modelReset);
  101 
  102         //available plugins
  103 #ifdef HAVE_NEW_CANTOR_LIBS
  104         auto* handler = new Cantor::PanelPluginHandler(this);
  105         handler->loadPlugins();
  106         m_plugins = handler->activePluginsForSession(m_session, Cantor::PanelPluginHandler::PanelStates());
  107         for (auto* plugin : m_plugins)
  108             plugin->connectToShell(m_part);
  109 #else
  110         auto* handler = m_part->findChild<Cantor::PanelPluginHandler*>(QLatin1String("PanelPluginHandler"));
  111         if (!handler) {
  112             KMessageBox::error(nullptr, i18n("No PanelPluginHandle found for the Cantor Part."));
  113             return false;
  114         }
  115         m_plugins = handler->plugins();
  116 #endif
  117     }
  118 
  119     return true;
  120 }
  121 
  122 //SLots
  123 void CantorWorksheet::dataChanged(const QModelIndex& index) {
  124     const QString& name = m_variableModel->data(m_variableModel->index(index.row(), 0)).toString();
  125     Column* col = child<Column>(name);
  126     if (col) {
  127         // Cantor::DefaultVariableModel::DataRole == 257
  128         QVariant dataValue = m_variableModel->data(m_variableModel->index(index.row(), 1), 257);
  129         if (dataValue.isNull())
  130             dataValue = m_variableModel->data(m_variableModel->index(index.row(), 1));
  131         const QString& value = dataValue.toString();
  132         VariableParser parser(m_backendName, value);
  133         if (parser.isParsed())
  134             col->replaceValues(0, parser.values());
  135     }
  136 
  137 }
  138 
  139 void CantorWorksheet::rowsInserted(const QModelIndex& parent, int first, int last) {
  140     Q_UNUSED(parent)
  141     for (int i = first; i <= last; ++i) {
  142         const QString& name = m_variableModel->data(m_variableModel->index(i, 0)).toString();
  143         QVariant dataValue = m_variableModel->data(m_variableModel->index(i, 1), 257);
  144         if (dataValue.isNull())
  145             dataValue = m_variableModel->data(m_variableModel->index(i, 1));
  146         const QString& value = dataValue.toString();
  147         VariableParser parser(m_backendName, value);
  148         if (parser.isParsed()) {
  149             Column* col = child<Column>(name);
  150             if (col) {
  151                 col->replaceValues(0, parser.values());
  152             } else {
  153                 col = new Column(name, parser.values());
  154                 col->setUndoAware(false);
  155                 addChild(col);
  156 
  157                 //TODO: Cantor currently ignores the order of variables in the worksheets
  158                 //and adds new variables at the last position in the model.
  159                 //Fix this in Cantor and switch to insertChildBefore here later.
  160                 //insertChildBefore(col, child<Column>(i));
  161             }
  162         } else {
  163             //the already existing variable doesn't contain any numerical values -> remove it
  164             Column* col = child<Column>(name);
  165             if (col)
  166                 removeChild(col);
  167         }
  168     }
  169 
  170     project()->setChanged(true);
  171 }
  172 
  173 void CantorWorksheet::modified() {
  174     project()->setChanged(true);
  175 }
  176 
  177 void CantorWorksheet::modelReset() {
  178     for (int i = 0; i < childCount<Column>(); ++i)
  179         child<Column>(i)->remove();
  180 }
  181 
  182 void CantorWorksheet::rowsAboutToBeRemoved(const QModelIndex & parent, int first, int last) {
  183     Q_UNUSED(parent);
  184 
  185     for (int i = first; i <= last; ++i) {
  186         const QString& name = m_variableModel->data(m_variableModel->index(first, 0)).toString();
  187         Column* column = child<Column>(name);
  188         if (column)
  189             column->remove();
  190     }
  191 }
  192 
  193 QList<Cantor::PanelPlugin*> CantorWorksheet::getPlugins() {
  194     return m_plugins;
  195 }
  196 
  197 KParts::ReadWritePart* CantorWorksheet::part() {
  198     return m_part;
  199 }
  200 
  201 QIcon CantorWorksheet::icon() const {
  202     if (m_session)
  203         return QIcon::fromTheme(m_session->backend()->icon());
  204     return QIcon();
  205 }
  206 
  207 QWidget* CantorWorksheet::view() const {
  208     if (!m_partView) {
  209         m_view = new CantorWorksheetView(const_cast<CantorWorksheet*>(this));
  210         m_view->setBaseSize(1500, 1500);
  211         m_partView = m_view;
  212         //  connect(m_view, SIGNAL(statusInfo(QString)), this, SIGNAL(statusInfo(QString)));
  213 
  214         //set the current path in the session to the path of the project file
  215         const Project* project = const_cast<CantorWorksheet*>(this)->project();
  216         const QString& fileName = project->fileName();
  217         if (!fileName.isEmpty()) {
  218             QFileInfo fi(fileName);
  219             m_session->setWorksheetPath(fi.filePath());
  220         }
  221     }
  222     return m_partView;
  223 }
  224 
  225 //! Return a new context menu.
  226 /**
  227  * The caller takes ownership of the menu.
  228  */
  229 QMenu* CantorWorksheet::createContextMenu() {
  230     QMenu* menu = AbstractPart::createContextMenu();
  231     Q_ASSERT(menu);
  232     emit requestProjectContextMenu(menu);
  233     return menu;
  234 }
  235 
  236 QString CantorWorksheet::backendName() {
  237     return this->m_backendName;
  238 }
  239 
  240 //TODO
  241 bool CantorWorksheet::exportView() const {
  242     return false;
  243 }
  244 
  245 bool CantorWorksheet::printView() {
  246     m_part->action("file_print")->trigger();
  247     return true;
  248 }
  249 
  250 bool CantorWorksheet::printPreview() const {
  251     m_part->action("file_print_preview")->trigger();
  252     return true;
  253 }
  254 
  255 //##############################################################################
  256 //##################  Serialization/Deserialization  ###########################
  257 //##############################################################################
  258 
  259 //! Save as XML
  260 void CantorWorksheet::save(QXmlStreamWriter* writer) const{
  261     writer->writeStartElement("cantorWorksheet");
  262     writeBasicAttributes(writer);
  263     writeCommentElement(writer);
  264 
  265     //general
  266     writer->writeStartElement( "general" );
  267     writer->writeAttribute( "backend_name", m_backendName);
  268     //TODO: save worksheet settings
  269     writer->writeEndElement();
  270 
  271     //save the content of Cantor's worksheet
  272     QByteArray content = m_worksheetAccess->saveWorksheetToByteArray();
  273     writer->writeStartElement("worksheet");
  274     writer->writeAttribute("content", content.toBase64());
  275     writer->writeEndElement();
  276 
  277     //save columns(variables)
  278     for (auto* col : children<Column>(ChildIndexFlag::IncludeHidden))
  279         col->save(writer);
  280 
  281     writer->writeEndElement(); // close "cantorWorksheet" section
  282 }
  283 
  284 //! Load from XML
  285 bool CantorWorksheet::load(XmlStreamReader* reader, bool preview) {
  286     //reset the status of the reader differentiating between
  287     //"failed because of the missing CAS" and "failed because of the broken XML"
  288     reader->setFailedCASMissing(false);
  289 
  290     if (!readBasicAttributes(reader))
  291         return false;
  292 
  293     KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
  294     QXmlStreamAttributes attribs;
  295     bool rc = false;
  296 
  297     while (!reader->atEnd()) {
  298         reader->readNext();
  299         if (reader->isEndElement() && reader->name() == "cantorWorksheet")
  300             break;
  301 
  302         if (!reader->isStartElement())
  303             continue;
  304 
  305         if (reader->name() == "comment") {
  306             if (!readCommentElement(reader))
  307                 return false;
  308         } else if (!preview && reader->name() == "general") {
  309             attribs = reader->attributes();
  310 
  311             m_backendName = attribs.value("backend_name").toString().trimmed();
  312             if (m_backendName.isEmpty())
  313                 reader->raiseWarning(attributeWarning.subs("backend_name").toString());
  314         } else if (!preview && reader->name() == "worksheet") {
  315             attribs = reader->attributes();
  316 
  317             QString str = attribs.value("content").toString().trimmed();
  318             if (str.isEmpty())
  319                 reader->raiseWarning(attributeWarning.subs("content").toString());
  320 
  321             QByteArray content = QByteArray::fromBase64(str.toLatin1());
  322             rc = init(&content);
  323             if (!rc) {
  324                 reader->raiseMissingCASWarning(m_backendName);
  325 
  326                 //failed to load this object because of the missing CAS plugin
  327                 //and not because of the broken project XML. Set this flag to
  328                 //handle this case correctly.
  329                 //TODO: we also can fail in the limit in cases where Cantor's content is broken
  330                 //and not because of the missing CAS plugin. This also needs to be treated accrodingly...
  331                 reader->setFailedCASMissing(true);
  332                 return false;
  333             }
  334         } else if (!preview && reader->name() == "column") {
  335             Column* column = new Column(QString());
  336             column->setUndoAware(false);
  337             if (!column->load(reader, preview)) {
  338                 delete column;
  339                 return false;
  340             }
  341             addChild(column);
  342         } else { // unknown element
  343             reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
  344             if (!reader->skipToEndElement()) return false;
  345         }
  346     }
  347 
  348     return true;
  349 }