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

0001 /*
0002     File                 : AbstractPart.cpp
0003     Project              : LabPlot
0004     Description          : Base class of Aspects with MDI windows as views.
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2008 Knut Franke <knut.franke@gmx.de>
0007     SPDX-FileCopyrightText: 2012-2024 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "backend/core/AbstractPart.h"
0012 #include "backend/core/Settings.h"
0013 #include "commonfrontend/core/ContentDockWidget.h"
0014 
0015 #include <DockManager.h>
0016 #include <QMenu>
0017 #include <QStyle>
0018 
0019 #include <KLocalizedString>
0020 
0021 /**
0022  * \class AbstractPart
0023  * \brief Base class of Aspects with MDI windows as views (AspectParts).
0024  */
0025 AbstractPart::AbstractPart(const QString& name, AspectType type)
0026     : AbstractAspect(name, type) {
0027 }
0028 
0029 AbstractPart::~AbstractPart() {
0030     if (m_dockWidget)
0031         delete m_dockWidget;
0032 }
0033 
0034 /**
0035  * \fn QWidget *AbstractPart::view() const
0036  * \brief Construct a primary view on me.
0037  *
0038  * The caller receives ownership of the view.
0039  *
0040  * This method may be called multiple times during the life time of a Part, or it might not get
0041  * called at all. Parts must not depend on the existence of a view for their operation.
0042  */
0043 
0044 /**
0045  * \brief Wrap the view() into a PartMdiView.
0046  *
0047  * A new view is only created the first time this method is called;
0048  * after that, a pointer to the pre-existing view is returned.
0049  */
0050 ContentDockWidget* AbstractPart::dockWidget() const {
0051 #ifndef SDK
0052     if (!m_dockWidget) {
0053         m_dockWidget = new ContentDockWidget(const_cast<AbstractPart*>(this));
0054         connect(m_dockWidget, &ads::CDockWidget::closed, [this] {
0055             const bool deleteOnClose = Settings::readDockPosBehaviour() == Settings::DockPosBehaviour::AboveLastActive;
0056             if (deleteOnClose && !m_suppressDeletion) {
0057                 m_dockWidget->dockManager()->removeDockWidget(m_dockWidget);
0058                 m_dockWidget = nullptr;
0059                 deleteView();
0060             }
0061         });
0062     }
0063 #endif
0064     return m_dockWidget;
0065 }
0066 
0067 bool AbstractPart::dockWidgetExists() const {
0068     return m_dockWidget != nullptr;
0069 }
0070 
0071 void AbstractPart::suppressDeletion(bool suppress) {
0072     m_suppressDeletion = suppress;
0073 }
0074 
0075 bool AbstractPart::hasMdiSubWindow() const {
0076     return m_dockWidget;
0077 }
0078 
0079 /*!
0080  * this function is called when PartMdiView, the mdi-subwindow-wrapper of the actual view,
0081  * is closed (=deleted) in MainWindow. Makes sure that the view also gets deleted.
0082  */
0083 void AbstractPart::deleteView() const {
0084     // if the parent is a Workbook or Datapicker, the actual view was already deleted when QTabWidget was deleted.
0085     // here just set the pointer to 0.
0086     auto* parent = parentAspect();
0087     auto type = parent->type();
0088     if (type == AspectType::Workbook || type == AspectType::Datapicker
0089         || (parent->parentAspect() && parent->parentAspect()->type() == AspectType::Datapicker)) {
0090         m_partView = nullptr;
0091         return;
0092     }
0093 
0094     if (m_partView) {
0095         Q_EMIT viewAboutToBeDeleted();
0096         delete m_partView;
0097         m_partView = nullptr;
0098     }
0099 }
0100 
0101 /**
0102  * \brief Return AbstractAspect::createContextMenu() plus operations on the primary view.
0103  */
0104 QMenu* AbstractPart::createContextMenu() {
0105     auto type = this->type();
0106     QMenu* menu;
0107     if (type != AspectType::StatisticsSpreadsheet) {
0108         menu = AbstractAspect::createContextMenu();
0109         menu->addSeparator();
0110     } else
0111         menu = new QMenu();
0112 
0113     // import actions for spreadsheet and matrix
0114     if ((type == AspectType::Spreadsheet || type == AspectType::Matrix) && type != AspectType::LiveDataSource && type != AspectType::MQTTTopic) {
0115         QMenu* subMenu = new QMenu(i18n("Import Data"), menu);
0116         subMenu->addAction(QIcon::fromTheme(QLatin1String("document-import")), i18n("From File..."), this, &AbstractPart::importFromFileRequested);
0117         subMenu->addAction(QIcon::fromTheme(QLatin1String("document-import")),
0118                            i18n("From SQL Database..."),
0119                            this,
0120                            &AbstractPart::importFromSQLDatabaseRequested);
0121         menu->addMenu(subMenu);
0122         menu->addSeparator();
0123     }
0124 
0125     // export/print actions
0126     if (type != AspectType::CantorWorksheet)
0127         menu->addAction(QIcon::fromTheme(QLatin1String("document-export-database")), i18n("Export"), this, &AbstractPart::exportRequested);
0128     menu->addAction(QIcon::fromTheme(QLatin1String("document-print")), i18n("Print"), this, &AbstractPart::printRequested);
0129     menu->addAction(QIcon::fromTheme(QLatin1String("document-print-preview")), i18n("Print Preview"), this, &AbstractPart::printPreviewRequested);
0130     menu->addSeparator();
0131 
0132     // window state related actions
0133     if (m_dockWidget) {
0134         const QStyle* style = m_dockWidget->style();
0135         if (!m_dockWidget->isClosed()) {
0136             auto* action = menu->addAction(i18n("&Close"), [this]() {
0137                 m_dockWidget->toggleView(false);
0138             });
0139             action->setIcon(style->standardIcon(QStyle::SP_TitleBarCloseButton));
0140         } else {
0141             menu->addAction(i18n("Show"), [this]() {
0142                 m_dockWidget->toggleView(true);
0143             });
0144         }
0145     } else {
0146         // if the mdi window was closed, add the "Show" action.
0147         // Don't add it for:
0148         //* children of a workbook, cannot be hidden/minimized
0149         //* data spreadsheets in datapicker curves
0150         auto parentType = parentAspect()->type();
0151         bool disableShow = ((type == AspectType::Spreadsheet || type == AspectType::Matrix) && parentType == AspectType::Workbook)
0152             || (type == AspectType::Spreadsheet && parentType == AspectType::DatapickerCurve);
0153         if (!disableShow) {
0154             menu->addAction(i18n("Show"), [this]() {
0155                 m_dockWidget->toggleView(true);
0156             });
0157         }
0158     }
0159 
0160     return menu;
0161 }
0162 
0163 bool AbstractPart::isDraggable() const {
0164     // TODO: moving workbook children doesn't work at the moment, don't allow to move it for now
0165     if ((type() == AspectType::Spreadsheet || type() == AspectType::Matrix) && parentAspect()->type() == AspectType::Workbook)
0166         return false;
0167     else
0168         return true;
0169 }
0170 
0171 QVector<AspectType> AbstractPart::dropableOn() const {
0172     return QVector<AspectType>{AspectType::Folder, AspectType::Project};
0173 }