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