File indexing completed on 2024-05-12 03:48:30

0001 /*
0002     File                 : WorkbookView.cpp
0003     Project              : LabPlot
0004     Description          : View class for Workbook
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2015-2020 Alexander Semke <alexander.semke@web.de>
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "WorkbookView.h"
0011 #include "backend/core/AbstractAspect.h"
0012 #include "backend/core/AbstractPart.h"
0013 #include "backend/core/Workbook.h"
0014 #include "backend/lib/macros.h"
0015 #include "backend/matrix/Matrix.h"
0016 #include "backend/spreadsheet/Spreadsheet.h"
0017 
0018 #include <QHBoxLayout>
0019 #include <QMenu>
0020 #include <QTabBar>
0021 #include <QTabWidget>
0022 
0023 #include <KLocalizedString>
0024 
0025 /*!
0026     \class WorkbookView
0027     \brief View class for Workbook
0028 
0029     \ingroup commonfrontend
0030  */
0031 WorkbookView::WorkbookView(Workbook* workbook)
0032     : QWidget()
0033     , m_tabWidget(new QTabWidget(this))
0034     , m_workbook(workbook) {
0035     m_tabWidget->setTabPosition(QTabWidget::South);
0036     m_tabWidget->setTabShape(QTabWidget::Rounded);
0037     //  m_tabWidget->setMovable(true);
0038     m_tabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
0039     m_tabWidget->setMinimumSize(200, 200);
0040 
0041     auto* layout = new QHBoxLayout(this);
0042     layout->setContentsMargins(0, 0, 0, 0);
0043     layout->addWidget(m_tabWidget);
0044 
0045     // add tab for each children view
0046     m_initializing = true;
0047     for (const auto* aspect : m_workbook->children<AbstractAspect>())
0048         handleAspectAdded(aspect);
0049     m_initializing = false;
0050 
0051     // Actions
0052     action_add_spreadsheet = new QAction(QIcon::fromTheme(QStringLiteral("labplot-spreadsheet")), i18n("Spreadsheet"), this);
0053     action_add_matrix = new QAction(QIcon::fromTheme(QStringLiteral("labplot-matrix")), i18n("Matrix"), this);
0054     connect(action_add_spreadsheet, &QAction::triggered, this, &WorkbookView::addSpreadsheet);
0055     connect(action_add_matrix, &QAction::triggered, this, &WorkbookView::addMatrix);
0056 
0057     // SIGNALs/SLOTs
0058     connect(m_workbook, &Workbook::aspectDescriptionChanged, this, &WorkbookView::handleDescriptionChanged);
0059     connect(m_workbook, &Workbook::childAspectAdded, this, &WorkbookView::handleAspectAdded);
0060     connect(m_workbook, &Workbook::childAspectAboutToBeRemoved, this, &WorkbookView::handleAspectAboutToBeRemoved);
0061     connect(m_workbook, &Workbook::requestProjectContextMenu, this, &WorkbookView::createContextMenu);
0062     connect(m_workbook, &Workbook::workbookItemSelected, this, &WorkbookView::itemSelected);
0063 
0064     connect(m_tabWidget, &QTabWidget::currentChanged, this, &WorkbookView::tabChanged);
0065     connect(m_tabWidget, &QTabWidget::customContextMenuRequested, this, &WorkbookView::showTabContextMenu);
0066     //  connect(m_tabWidget->tabBar(), &QTabBar::tabMoved, this, &WorkbookView::tabMoved);
0067 }
0068 
0069 WorkbookView::~WorkbookView() {
0070     // no need to react on currentChanged() in TabWidget when views are deleted
0071     disconnect(m_tabWidget, nullptr, nullptr, nullptr);
0072 
0073     // delete all children views here, its own view will be deleted in ~AbstractPart()
0074     for (const auto* part : m_workbook->children<AbstractPart>())
0075         part->deleteView();
0076 }
0077 
0078 int WorkbookView::currentIndex() const {
0079     return m_tabWidget->currentIndex();
0080 }
0081 
0082 // ##############################################################################
0083 // #########################  Private slots  ####################################
0084 // ##############################################################################
0085 /*!
0086   called when the current tab was changed. Propagates the selection of \c Spreadsheet
0087   or of a \c Matrix object to \c Workbook.
0088 */
0089 void WorkbookView::tabChanged(int index) {
0090     CONDITIONAL_RETURN_NO_LOCK;
0091 
0092     if (index == -1)
0093         return;
0094 
0095     m_workbook->setChildSelectedInView(lastSelectedIndex, false);
0096     m_workbook->setChildSelectedInView(index, true);
0097     lastSelectedIndex = index;
0098 }
0099 
0100 void WorkbookView::tabMoved(int /*from*/, int /*to*/) {
0101     // TODO:
0102     //  AbstractAspect* aspect = m_workbook->child<AbstractAspect>(to);
0103     //  if (aspect) {
0104     //      m_tabMoving = true;
0105     //      AbstractAspect* sibling = m_workbook->child<AbstractAspect>(from);
0106     //      qDebug()<<"insert: " << to << "  " <<  aspect->name() << ",  " << from << "  " << sibling->name();
0107     //      aspect->remove();
0108     //      m_workbook->insertChildBefore(aspect, sibling);
0109     //      qDebug()<<"inserted";
0110     //      m_tabMoving = false;
0111     //  }
0112 }
0113 
0114 void WorkbookView::itemSelected(int index) {
0115     m_tabWidget->setCurrentIndex(index);
0116 }
0117 
0118 /*!
0119  * Populates the menu \c menu with the spreadsheet and spreadsheet view relevant actions.
0120  * The menu is used
0121  *   - as the context menu in WorkbookView
0122  *   - as the "spreadsheet menu" in the main menu-bar (called form MainWin)
0123  *   - as a part of the spreadsheet context menu in project explorer
0124  */
0125 void WorkbookView::createContextMenu(QMenu* menu) const {
0126     Q_ASSERT(menu);
0127 
0128     QAction* firstAction = nullptr;
0129     // if we're populating the context menu for the project explorer, then
0130     // there're already actions available there. Skip the first title-action
0131     // and insert the action at the beginning of the menu.
0132     if (menu->actions().size() > 1)
0133         firstAction = menu->actions().at(1);
0134 
0135     auto* addNewMenu = new QMenu(i18n("Add New"), const_cast<WorkbookView*>(this));
0136     addNewMenu->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0137     addNewMenu->addAction(action_add_spreadsheet);
0138     addNewMenu->addAction(action_add_matrix);
0139     menu->insertMenu(firstAction, addNewMenu);
0140     menu->insertSeparator(firstAction);
0141 }
0142 
0143 void WorkbookView::showTabContextMenu(QPoint point) {
0144     QMenu* menu = nullptr;
0145     auto* aspect = m_workbook->child<AbstractAspect>(m_tabWidget->currentIndex());
0146     auto* spreadsheet = dynamic_cast<Spreadsheet*>(aspect);
0147     if (spreadsheet) {
0148         menu = spreadsheet->createContextMenu();
0149     } else {
0150         Matrix* matrix = dynamic_cast<Matrix*>(aspect);
0151         if (matrix)
0152             menu = matrix->createContextMenu();
0153     }
0154 
0155     if (menu)
0156         menu->exec(m_tabWidget->mapToGlobal(point));
0157 }
0158 
0159 void WorkbookView::addMatrix() {
0160     Matrix* matrix = new Matrix(i18n("Matrix"));
0161     m_workbook->addChild(matrix);
0162 }
0163 
0164 void WorkbookView::addSpreadsheet() {
0165     auto* spreadsheet = new Spreadsheet(i18n("Spreadsheet"));
0166     m_workbook->addChild(spreadsheet);
0167 }
0168 
0169 void WorkbookView::handleDescriptionChanged(const AbstractAspect* aspect) {
0170     int index = m_workbook->indexOfChild<AbstractAspect>(aspect);
0171     if (index != -1 && index < m_tabWidget->count())
0172         m_tabWidget->setTabText(index, aspect->name());
0173 }
0174 
0175 void WorkbookView::handleAspectAdded(const AbstractAspect* aspect) {
0176     const auto* part = dynamic_cast<const AbstractPart*>(aspect);
0177     if (!part)
0178         return;
0179 
0180     int index = m_workbook->indexOfChild<AbstractAspect>(aspect);
0181     m_tabWidget->insertTab(index, part->view(), aspect->name());
0182     m_tabWidget->setCurrentIndex(index);
0183     m_tabWidget->setTabIcon(m_tabWidget->count(), aspect->icon());
0184     this->tabChanged(index);
0185 }
0186 
0187 void WorkbookView::handleAspectAboutToBeRemoved(const AbstractAspect* aspect) {
0188     int index = m_workbook->indexOfChild<AbstractAspect>(aspect);
0189     m_tabWidget->removeTab(index);
0190 }