File indexing completed on 2024-05-12 16:36:09

0001 /* This file is part of the KDE project
0002    Copyright 2009 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "MapViewModel.h"
0021 
0022 #include "Map.h"
0023 #include "ModelSupport.h"
0024 #include "Sheet.h"
0025 
0026 #include "commands/SheetCommands.h"
0027 
0028 #include "interfaces/ReadWriteTableModel.h"
0029 
0030 #include <KoCanvasBase.h>
0031 #include <KoShapeManager.h>
0032 #include <KoIcon.h>
0033 
0034 #include <kxmlguiclient.h>
0035 
0036 using namespace Calligra::Sheets;
0037 
0038 class MapViewModel::Private
0039 {
0040 public:
0041     Sheet* activeSheet;
0042     KoCanvasBase *canvas;
0043     KXMLGUIClient *xmlGuiClient;
0044     QActionGroup *gotoSheetActionGroup;
0045 };
0046 
0047 
0048 MapViewModel::MapViewModel(Map *map, KoCanvasBase *canvas, KXMLGUIClient *xmlGuiClient)
0049         : MapModel(map)
0050         , d(new Private)
0051 {
0052     d->activeSheet = 0;
0053     d->canvas = canvas;
0054     d->xmlGuiClient = xmlGuiClient;
0055     d->gotoSheetActionGroup = new QActionGroup(this);
0056 
0057     connect(d->gotoSheetActionGroup, SIGNAL(triggered(QAction*)),
0058             this, SLOT(gotoSheetActionTriggered(QAction*)));
0059 
0060     // Add the initial controlled sheets.
0061     const QList<Sheet *> sheets = map->sheetList();
0062     for (int i = 0; i < sheets.count(); ++i) {
0063         addSheet(sheets[i]);
0064     }
0065 }
0066 
0067 MapViewModel::~MapViewModel()
0068 {
0069     delete d;
0070 }
0071 
0072 QVariant MapViewModel::data(const QModelIndex &index, int role) const
0073 {
0074     // We handle only this role; the remaining ones go to the MapModel.
0075     if (role != ActivityRole && role != Qt::CheckStateRole) {
0076         return MapModel::data(index, role);
0077     }
0078     if (!index.isValid()) {
0079         return QVariant();
0080     }
0081     if (index.parent().isValid()) {
0082         return MapModel::data(index, role);
0083     }
0084     if (index.row() >= map()->count()) {
0085         return QVariant();
0086     }
0087     const Sheet* const sheet = map()->sheet(index.row());
0088     return QVariant(sheet == d->activeSheet);
0089 }
0090 
0091 Qt::ItemFlags MapViewModel::flags(const QModelIndex &index) const
0092 {
0093     if (!index.isValid()) {
0094         return Qt::NoItemFlags;
0095     }
0096     // Propagation to sheet model
0097     if (index.parent().isValid()) {
0098         return MapModel::flags(index); // The MapModel takes care of cell indices.
0099     }
0100     if (index.row() >= map()->count()) {
0101         return Qt::NoItemFlags;
0102     }
0103     return MapModel::flags(index) | Qt::ItemIsUserCheckable;
0104 }
0105 
0106 bool MapViewModel::setData(const QModelIndex &index, const QVariant &value, int role)
0107 {
0108     // We handle only this role; the remaining ones go to the MapModel.
0109     if (role != ActivityRole && role != Qt::CheckStateRole) {
0110         return MapModel::setData(index, value, role);
0111     }
0112     if (!index.isValid()) {
0113         return false;
0114     }
0115     if (index.parent().isValid()) {
0116         return MapModel::setData(index, value, role);
0117     }
0118     if (index.row() >= map()->count()) {
0119         return false;
0120     }
0121     Sheet* const sheet(map()->sheet(index.row()));
0122     setActiveSheet(sheet);
0123     return true;
0124 }
0125 
0126 Sheet* MapViewModel::activeSheet() const
0127 {
0128     return d->activeSheet;
0129 }
0130 
0131 void MapViewModel::setActiveSheet(Sheet* sheet)
0132 {
0133     if (d->activeSheet == sheet) {
0134         return;
0135     }
0136     const QList<Sheet*> list = map()->sheetList();
0137     const int oldRow = list.indexOf(d->activeSheet);
0138     const int newRow = list.indexOf(sheet);
0139 
0140     // The sheet may be set to 0 for one exceptional case.
0141     d->activeSheet = sheet;
0142 
0143     if (!sheet) {
0144         return;
0145     }
0146 
0147     // Unhide, if necessary.
0148     if (sheet->isHidden()) {
0149         KUndo2Command* command = new ShowSheetCommand(sheet);
0150         d->canvas->addCommand(command);
0151     }
0152 
0153     // Check the appropriate action of the goto sheet action group.
0154     const QList<QAction *> actions = d->gotoSheetActionGroup->actions();
0155     for (int i = 0; i < actions.count(); ++i) {
0156         if (actions[i]->iconText() == sheet->sheetName()) {
0157             actions[i]->setChecked(true);
0158             break;
0159         }
0160     }
0161 
0162     // Both sheets have to be in the list. If not, there won't be any signals.
0163     if (oldRow == -1 || newRow == -1) {
0164         return;
0165     }
0166     const QModelIndex oldIndex(index(oldRow, 0));
0167     const QModelIndex newIndex(index(newRow, 0));
0168     emit dataChanged(oldIndex, oldIndex);
0169     emit dataChanged(newIndex, newIndex);
0170     emit activeSheetChanged(sheet);
0171 }
0172 
0173 void MapViewModel::addSheet(Sheet *sheet)
0174 {
0175     MapModel::addSheet(sheet);
0176 
0177     connect(sheet, SIGNAL(shapeAdded(Sheet*,KoShape*)),
0178             this, SLOT(addShape(Sheet*,KoShape*)));
0179     connect(sheet, SIGNAL(shapeRemoved(Sheet*,KoShape*)),
0180             this, SLOT(removeShape(Sheet*,KoShape*)));
0181 
0182     if (!d->xmlGuiClient) {
0183         return;
0184     }
0185 
0186     // Update the goto sheet action group
0187     const QString name = sheet->sheetName();
0188     QAction *action = new QAction(koIcon("x-office-spreadsheet"), name, this);
0189     action->setCheckable(true);
0190     action->setToolTip(i18nc("Activate sheet named foo", "Activate %1", name));
0191 
0192     d->gotoSheetActionGroup->addAction(action);
0193 
0194     const QList<QAction *> actions = d->gotoSheetActionGroup->actions();
0195     d->xmlGuiClient->unplugActionList("go_goto_sheet_actionlist");
0196     d->xmlGuiClient->plugActionList("go_goto_sheet_actionlist", actions);
0197 }
0198 
0199 void MapViewModel::removeSheet(Sheet *sheet)
0200 {
0201     MapModel::removeSheet(sheet);
0202 
0203     disconnect(sheet, SIGNAL(shapeAdded(Sheet*,KoShape*)),
0204                this, SLOT(addShape(Sheet*,KoShape*)));
0205     disconnect(sheet, SIGNAL(shapeRemoved(Sheet*,KoShape*)),
0206                this, SLOT(removeShape(Sheet*,KoShape*)));
0207 
0208     if (!d->xmlGuiClient) {
0209         return;
0210     }
0211 
0212     // Update the goto sheet action group
0213     QAction *action = 0;
0214     const QList<QAction *> actions = d->gotoSheetActionGroup->actions();
0215     for (int i = 0; i < actions.count(); ++i) {
0216         if (actions[i]->text() == sheet->sheetName()) {
0217             action = actions[i];
0218             break;
0219         }
0220     }
0221     if (action) {
0222         d->gotoSheetActionGroup->removeAction(action);
0223         const QList<QAction *> actions = d->gotoSheetActionGroup->actions();
0224         d->xmlGuiClient->unplugActionList("go_goto_sheet_actionlist");
0225         d->xmlGuiClient->plugActionList("go_goto_sheet_actionlist", actions);
0226     }
0227 }
0228 
0229 void MapViewModel::addShape(Sheet *sheet, KoShape *shape)
0230 {
0231     if (sheet == d->activeSheet) {
0232         d->canvas->shapeManager()->addShape(shape);
0233     }
0234 }
0235 
0236 void MapViewModel::removeShape(Sheet *sheet, KoShape *shape)
0237 {
0238     if (sheet == d->activeSheet) {
0239         d->canvas->shapeManager()->remove(shape);
0240     }
0241 }
0242 
0243 void MapViewModel::gotoSheetActionTriggered(QAction *action)
0244 {
0245     const QList<QAction *> actions = d->gotoSheetActionGroup->actions();
0246     for (int i = 0; i < actions.count(); ++i) {
0247         if (actions[i]->text() == action->text()) {
0248             Sheet *const sheet = map()->findSheet(action->iconText());
0249             if (sheet) {
0250                 setActiveSheet(sheet);
0251             } else { // should not happen
0252                 d->gotoSheetActionGroup->removeAction(action);
0253             }
0254             break;
0255         }
0256     }
0257 }