File indexing completed on 2024-05-05 17:09:08
0001 /* 0002 * This file is part of the KDE project 0003 * 0004 * Copyright (C) 2013 Shantanu Tushar <shantanu@kde.org> 0005 * Copyright (C) 2013 Arjen Hiemstra <ahiemstra@heimr.nl> 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #include "CQSpreadsheetCanvas.h" 0025 0026 #include <QStyleOptionGraphicsItem> 0027 0028 #include "CQCanvasController.h" 0029 #include <KoPart.h> 0030 #include <KoFindText.h> 0031 #include <KoCanvasBase.h> 0032 #include <KoToolManager.h> 0033 #include <KoZoomController.h> 0034 #include <KoZoomHandler.h> 0035 #include <sheets/part/Doc.h> 0036 #include <sheets/part/CanvasItem.h> 0037 #include <sheets/Map.h> 0038 #include <sheets/Sheet.h> 0039 #include <KoShape.h> 0040 #include <KActionCollection> 0041 #include <QGraphicsWidget> 0042 #include <QTextFrame> 0043 #include <QTextLayout> 0044 0045 class CQSpreadsheetCanvas::Private 0046 { 0047 public: 0048 Private() : canvas(0), document(0), currentSheet(0) { } 0049 0050 Calligra::Sheets::CanvasItem* canvas; 0051 Calligra::Sheets::Doc * document; 0052 0053 int currentSheet; 0054 QObjectList linkTargets; 0055 0056 void updateLinkTargets() 0057 { 0058 qDeleteAll(linkTargets); 0059 linkTargets.clear(); 0060 0061 if (!canvas) { 0062 return; 0063 } 0064 foreach(const KoShape* shape, canvas->activeSheet()->shapes()) { 0065 if (!shape->hyperLink().isEmpty()) { 0066 QObject * obj = new QObject(canvas); 0067 obj->setProperty("linkRect", shape->boundingRect()); 0068 obj->setProperty("linkTarget", QUrl(shape->hyperLink())); 0069 linkTargets.append(obj); 0070 } 0071 } 0072 0073 QList<QTextDocument*> texts; 0074 KoFindText::findTextInShapes(canvas->activeSheet()->shapes(), texts); 0075 foreach(QTextDocument* text, texts) { 0076 QTextBlock block = text->rootFrame()->firstCursorPosition().block(); 0077 for (; block.isValid(); block = block.next()) { 0078 block.begin(); 0079 QTextBlock::iterator it; 0080 for (it = block.begin(); !(it.atEnd()); ++it) { 0081 QTextFragment fragment = it.fragment(); 0082 if (fragment.isValid()) { 0083 QTextCharFormat format = fragment.charFormat(); 0084 if (format.isAnchor()) { 0085 // This is an anchor, store target and position... 0086 QObject * obj = new QObject(canvas); 0087 QRectF rect = getFragmentPosition(block, fragment); 0088 obj->setProperty("linkRect", canvas->viewConverter()->documentToView(rect)); 0089 obj->setProperty("linkTarget", QUrl(format.anchorHref())); 0090 linkTargets.append(obj); 0091 } 0092 } 0093 } 0094 } 0095 } 0096 } 0097 0098 QRectF getFragmentPosition(const QTextBlock& block, const QTextFragment& fragment) 0099 { 0100 // TODO this only produces a position for the first part, if the link spans more than one line... 0101 // Need to sort that somehow, unfortunately probably by slapping this code into the above function. 0102 // For now leave it like this, more important things are needed. 0103 QTextLayout* layout = block.layout(); 0104 QTextLine line = layout->lineForTextPosition(fragment.position() - block.position()); 0105 if (!line.isValid()) { 0106 // fragment has no valid position and consequently no line... 0107 return QRectF(); 0108 } 0109 qreal top = line.position().y(); 0110 qreal bottom = line.position().y() + line.height(); 0111 qreal left = line.cursorToX(fragment.position() - block.position()); 0112 qreal right = line.cursorToX((fragment.position() - block.position()) + fragment.length()); 0113 QRectF fragmentPosition(QPointF(top, left), QPointF(bottom, right)); 0114 return fragmentPosition.adjusted(layout->position().x(), layout->position().y(), 0, 0); 0115 } 0116 }; 0117 0118 CQSpreadsheetCanvas::CQSpreadsheetCanvas(QDeclarativeItem* parent) 0119 : CQCanvasBase(parent), d(new Private) 0120 { 0121 0122 } 0123 0124 CQSpreadsheetCanvas::~CQSpreadsheetCanvas() 0125 { 0126 delete d; 0127 } 0128 0129 int CQSpreadsheetCanvas::currentSheet() const 0130 { 0131 return d->currentSheet; 0132 } 0133 0134 Calligra::Sheets::Map* CQSpreadsheetCanvas::documentMap() const 0135 { 0136 return d->document->map(); 0137 } 0138 0139 QObjectList CQSpreadsheetCanvas::linkTargets() const 0140 { 0141 return d->linkTargets; 0142 } 0143 0144 void CQSpreadsheetCanvas::setCurrentSheet(int sheet) 0145 { 0146 sheet = qBound(0, sheet, d->document->map()->count() - 1); 0147 if (sheet != d->currentSheet) { 0148 d->currentSheet = sheet; 0149 d->canvas->setActiveSheet(d->document->map()->sheet(d->currentSheet)); 0150 emit currentSheetChanged(); 0151 d->updateLinkTargets(); 0152 emit linkTargetsChanged(); 0153 } 0154 } 0155 0156 void CQSpreadsheetCanvas::render(QPainter* painter, const QRectF& target) 0157 { 0158 QStyleOptionGraphicsItem option; 0159 option.exposedRect = target; 0160 option.rect = target.toAlignedRect(); 0161 d->canvas->canvasItem()->paint(painter, &option); 0162 } 0163 0164 void CQSpreadsheetCanvas::openFile(const QString& uri) 0165 { 0166 KService::Ptr service = KService::serviceByDesktopName("sheetspart"); 0167 if (service.isNull()) { 0168 qWarning("Unable to load Sheets plugin, aborting!"); 0169 return; 0170 } 0171 0172 KoPart* part = service->createInstance<KoPart>(); 0173 d->document = static_cast<Calligra::Sheets::Doc*> (part->document()); 0174 d->document->setAutoSave(0); 0175 d->document->setCheckAutoSaveFile(false); 0176 d->document->openUrl (QUrl (uri)); 0177 0178 d->canvas = dynamic_cast<Calligra::Sheets::CanvasItem*> (part->canvasItem(part->document())); 0179 createAndSetCanvasControllerOn(d->canvas); 0180 createAndSetZoomController(d->canvas); 0181 0182 d->canvas->setParentItem(this); 0183 d->canvas->installEventFilter(this); 0184 d->canvas->setVisible(true); 0185 d->canvas->setGeometry(x(), y(), width(), height()); 0186 0187 d->updateLinkTargets(); 0188 emit linkTargetsChanged(); 0189 0190 Calligra::Sheets::Sheet *sheet = d->document->map()->sheet(0); 0191 if (sheet) { 0192 updateDocumentSize(sheet->documentSize().toSize()); 0193 } 0194 } 0195 0196 void CQSpreadsheetCanvas::createAndSetCanvasControllerOn(KoCanvasBase* canvas) 0197 { 0198 //TODO: pass a proper action collection 0199 CQCanvasController *controller = new CQCanvasController(new KActionCollection(this)); 0200 setCanvasController(controller); 0201 controller->setCanvas(canvas); 0202 KoToolManager::instance()->addController (controller); 0203 } 0204 0205 void CQSpreadsheetCanvas::createAndSetZoomController(KoCanvasBase* canvas) 0206 { 0207 KoZoomHandler* zoomHandler = static_cast<KoZoomHandler*> (canvas->viewConverter()); 0208 setZoomController(new KoZoomController(canvasController(), 0209 zoomHandler, 0210 new KActionCollection(this))); 0211 0212 Calligra::Sheets::CanvasItem *canvasItem = dynamic_cast<Calligra::Sheets::CanvasItem*> (canvas); 0213 // update the canvas whenever we scroll, the canvas controller must emit this signal on scrolling/panning 0214 connect (canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), canvasItem, SLOT(setDocumentOffset(QPoint))); 0215 // whenever the size of the document viewed in the canvas changes, inform the zoom controller 0216 connect(canvasItem, SIGNAL(documentSizeChanged(QSize)), SLOT(updateDocumentSize(QSize))); 0217 canvasItem->update(); 0218 } 0219 0220 void CQSpreadsheetCanvas::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) 0221 { 0222 if (d->canvas) { 0223 d->canvas->setGeometry(newGeometry); 0224 } 0225 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); 0226 } 0227 0228 void CQSpreadsheetCanvas::updateDocumentSize(const QSize& size) 0229 { 0230 zoomController()->setDocumentSize(size, false); 0231 }