File indexing completed on 2024-05-12 03:47:28

0001 /*
0002     File                 : Workbook.h
0003     Project              : LabPlot
0004     Description          : Aspect providing a container for storing data
0005                    in form of spreadsheets and matrices
0006     --------------------------------------------------------------------
0007     SPDX-FileCopyrightText: 2015 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "Workbook.h"
0012 #include "backend/lib/XmlStreamReader.h"
0013 #include "backend/matrix/Matrix.h"
0014 #include "backend/spreadsheet/Spreadsheet.h"
0015 #include "commonfrontend/workbook/WorkbookView.h"
0016 #include "kdefrontend/spreadsheet/ExportSpreadsheetDialog.h"
0017 
0018 #include <KLocalizedString>
0019 #include <QIcon>
0020 
0021 /**
0022  * \class Workbook
0023  * \brief Top-level container for Spreadsheet and Matrix.
0024  * \ingroup backend
0025  */
0026 Workbook::Workbook(const QString& name)
0027     : AbstractPart(name, AspectType::Workbook) {
0028 }
0029 
0030 QIcon Workbook::icon() const {
0031     return QIcon::fromTheme(QLatin1String("labplot-workbook"));
0032 }
0033 
0034 /*!
0035  * Returns a new context menu. The caller takes ownership of the menu.
0036  */
0037 QMenu* Workbook::createContextMenu() {
0038     QMenu* menu = AbstractPart::createContextMenu();
0039     Q_ASSERT(menu);
0040     Q_EMIT requestProjectContextMenu(menu);
0041     return menu;
0042 }
0043 
0044 QWidget* Workbook::view() const {
0045     if (!m_partView) {
0046         m_view = new WorkbookView(const_cast<Workbook*>(this));
0047         m_partView = m_view;
0048         connect(this, &Workbook::viewAboutToBeDeleted, [this]() {
0049             m_view = nullptr;
0050         });
0051     }
0052     return m_partView;
0053 }
0054 
0055 bool Workbook::exportView() const {
0056     Spreadsheet* s = currentSpreadsheet();
0057     bool ret = false;
0058     if (s)
0059         ret = s->exportView();
0060     else {
0061         Matrix* m = currentMatrix();
0062         if (m)
0063             ret = m->exportView();
0064     }
0065     return ret;
0066 }
0067 
0068 bool Workbook::printView() {
0069     Spreadsheet* s = currentSpreadsheet();
0070     bool ret = false;
0071     if (s)
0072         ret = s->printView();
0073     else {
0074         Matrix* m = currentMatrix();
0075         if (m)
0076             ret = m->printView();
0077     }
0078     return ret;
0079 }
0080 
0081 bool Workbook::printPreview() const {
0082     Spreadsheet* s = currentSpreadsheet();
0083     bool ret = false;
0084     if (s)
0085         ret = s->printPreview();
0086     else {
0087         Matrix* m = currentMatrix();
0088         if (m)
0089             ret = m->printPreview();
0090     }
0091     return ret;
0092 }
0093 
0094 Spreadsheet* Workbook::currentSpreadsheet() const {
0095     if (!m_view)
0096         return nullptr;
0097 
0098     int index = m_view->currentIndex();
0099     if (index != -1) {
0100         auto* aspect = child<AbstractAspect>(index);
0101         return dynamic_cast<Spreadsheet*>(aspect);
0102     }
0103     return nullptr;
0104 }
0105 
0106 Matrix* Workbook::currentMatrix() const {
0107     if (!m_view)
0108         return nullptr;
0109 
0110     int index = reinterpret_cast<const WorkbookView*>(m_view)->currentIndex();
0111     if (index != -1) {
0112         auto* aspect = child<AbstractAspect>(index);
0113         return dynamic_cast<Matrix*>(aspect);
0114     }
0115     return nullptr;
0116 }
0117 
0118 /*!
0119     this slot is called when a workbook child is selected in the project explorer.
0120     emits \c workbookItemSelected() to forward this event to the \c WorkbookView
0121     in order to select the corresponding tab.
0122  */
0123 void Workbook::childSelected(const AbstractAspect* aspect) {
0124     int index = indexOfChild<AbstractAspect>(aspect);
0125     Q_EMIT workbookItemSelected(index);
0126 }
0127 
0128 /*!
0129     this slot is called when a worksheet element is deselected in the project explorer.
0130  */
0131 void Workbook::childDeselected(const AbstractAspect*) {
0132 }
0133 
0134 /*!
0135  *  Emits the signal to select or to deselect the workbook item (spreadsheet or matrix) with the index \c index
0136  *  in the project explorer, if \c selected=true or \c selected=false, respectively.
0137  *  The signal is handled in \c AspectTreeModel and forwarded to the tree view in \c ProjectExplorer.
0138  *  This function is called in \c WorkbookView when the current tab was changed
0139  */
0140 void Workbook::setChildSelectedInView(int index, bool selected) {
0141     auto* aspect = child<AbstractAspect>(index);
0142     if (selected) {
0143         Q_EMIT childAspectSelectedInView(aspect);
0144 
0145         // deselect the workbook in the project explorer, if a child (spreadsheet or matrix) was selected.
0146         // prevents unwanted multiple selection with workbook if it was selected before.
0147         Q_EMIT childAspectDeselectedInView(this);
0148     } else {
0149         Q_EMIT childAspectDeselectedInView(aspect);
0150 
0151         // deselect also all children that were potentially selected before (columns of a spreadsheet)
0152         for (auto* child : aspect->children<AbstractAspect>())
0153             Q_EMIT childAspectDeselectedInView(child);
0154     }
0155 }
0156 
0157 QVector<AspectType> Workbook::pasteTypes() const {
0158     return QVector<AspectType>{AspectType::Spreadsheet, AspectType::Matrix};
0159 }
0160 
0161 void Workbook::processDropEvent(const QVector<quintptr>& vec) {
0162     for (auto a : vec) {
0163         auto* aspect = reinterpret_cast<AbstractAspect*>(a);
0164         aspect->reparent(this);
0165     }
0166 }
0167 // ##############################################################################
0168 // ##################  Serialization/Deserialization  ###########################
0169 // ##############################################################################
0170 
0171 //! Save as XML
0172 void Workbook::save(QXmlStreamWriter* writer) const {
0173     writer->writeStartElement(QLatin1String("workbook"));
0174     writeBasicAttributes(writer);
0175     writeCommentElement(writer);
0176 
0177     // serialize all children
0178     for (auto* aspect : children<AbstractAspect>())
0179         aspect->save(writer);
0180 
0181     writer->writeEndElement(); // close "workbook" section
0182 }
0183 
0184 //! Load from XML
0185 bool Workbook::load(XmlStreamReader* reader, bool preview) {
0186     if (!readBasicAttributes(reader))
0187         return false;
0188 
0189     while (!reader->atEnd()) {
0190         reader->readNext();
0191         if (reader->isEndElement() && reader->name() == QLatin1String("workbook"))
0192             break;
0193 
0194         if (!reader->isStartElement())
0195             continue;
0196 
0197         if (reader->name() == QLatin1String("comment")) {
0198             if (!readCommentElement(reader))
0199                 return false;
0200         } else if (reader->name() == QLatin1String("spreadsheet")) {
0201             auto* spreadsheet = new Spreadsheet(QStringLiteral("spreadsheet"), true);
0202             if (!spreadsheet->load(reader, preview)) {
0203                 delete spreadsheet;
0204                 return false;
0205             } else
0206                 addChild(spreadsheet);
0207         } else if (reader->name() == QLatin1String("matrix")) {
0208             auto* matrix = new Matrix(i18n("matrix"), true);
0209             if (!matrix->load(reader, preview)) {
0210                 delete matrix;
0211                 return false;
0212             } else
0213                 addChild(matrix);
0214         } else { // unknown element
0215             reader->raiseWarning(i18n("unknown workbook element '%1'", reader->name().toString()));
0216             if (!reader->skipToEndElement())
0217                 return false;
0218         }
0219     }
0220 
0221     return true;
0222 }