1 /*
2  * This file is part of the KDE project
3  *
4  * Copyright (C) 2013 Shantanu Tushar <shantanu@kde.org>
5  * Copyright (C) 2013 Sujith Haridasan <sujith.h@gmail.com>
6  * Copyright (C) 2013 Arjen Hiemstra <ahiemstra@heimr.nl>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "CQTextDocumentCanvas.h"
26 #include "CQCanvasController.h"
27 #include "CQTextDocumentModel.h"
28 #include "CQTextDocumentNotesModel.h"
29 
30 #include "gemini/ViewModeSwitchEvent.h"
31 
32 #include <KoPluginLoader.h>
33 #include <KoDocumentEntry.h>
34 #include <KoUnit.h>
35 #include <KoDocument.h>
36 #include <KoDocumentResourceManager.h>
37 #include <KoPart.h>
38 #include <KoFindText.h>
39 #include <KoCanvasBase.h>
40 #include <KoToolManager.h>
41 #include <KoZoomHandler.h>
42 #include <KoZoomController.h>
43 #include <KoShape.h>
44 #include <KoToolManager_p.h>
45 #include <KoToolBase.h>
46 #include <KoPointerEvent.h>
47 #include <KoSelection.h>
48 #include <KoShapeRegistry.h>
49 #include <KoShapeAnchor.h>
50 #include <KoShapeContainer.h>
51 #include <KoTextEditor.h>
52 #include <KoProperties.h>
53 #include <KoColumns.h>
54 #include <KWDocument.h>
55 #include <KWPage.h>
56 #include <KWCanvasItem.h>
57 #include <commands/KWShapeCreateCommand.h>
58 
59 #include <KActionCollection>
60 
61 #include <QPluginLoader>
62 #include <QMimeDatabase>
63 #include <QStyleOptionGraphicsItem>
64 #include <QGraphicsWidget>
65 #include <QTextDocument>
66 #include <QTextFrame>
67 #include <QTextLayout>
68 #include <QGraphicsSceneMouseEvent>
69 #include <QTextDocumentFragment>
70 #include <QSvgRenderer>
71 #include <QApplication>
72 #include <QDebug>
73 
74 class CQTextDocumentCanvas::Private
75 {
76 public:
Private()77     Private()
78         : canvas(0),
79           findText(0),
80           documentModel(0),
81           document(0),
82           pageNumber(0),
83           throttleTimer(new QTimer()),
84           currentTool(0),
85           notes(0),
86           textEditor(0)
87     {
88         throttleTimer->setInterval(200);
89         throttleTimer->setSingleShot(true);
90     }
91 
92     KWCanvasItem *canvas;
93     QString searchTerm;
94     KoFindText *findText;
95     CQTextDocumentModel *documentModel;
96     KWDocument* document;
97     KoPart* part;
98     QSize documentSize;
99     int pageNumber;
100     QPoint currentPoint;
101     QObjectList linkTargets;
102     QTimer* throttleTimer;
103     KoToolBase* currentTool;
104     CQTextDocumentNotesModel* notes;
105     KoTextEditor* textEditor;
106 
updateLinkTargets()107     void updateLinkTargets()
108     {
109         qDeleteAll(linkTargets);
110         linkTargets.clear();
111 
112         if (!canvas) {
113             return;
114         }
115 
116         foreach(const KoShape* shape, canvas->shapeManager()->shapes()) {
117             if (!shape->hyperLink().isEmpty()) {
118                 QObject * obj = new QObject(documentModel);
119                 obj->setProperty("linkRect", shape->boundingRect());
120                 obj->setProperty("linkTarget", QUrl(shape->hyperLink()));
121                 linkTargets.append(obj);
122             }
123         }
124 
125         foreach(QTextDocument* text, findText->documents()) {
126             QTextBlock block = text->rootFrame()->firstCursorPosition().block();
127             for (; block.isValid(); block = block.next()) {
128                 block.begin();
129                 QTextBlock::iterator it;
130                 for (it = block.begin(); !(it.atEnd()); ++it) {
131                     QTextFragment fragment = it.fragment();
132                     if (fragment.isValid()) {
133                         QTextCharFormat format = fragment.charFormat();
134                         if (format.isAnchor()) {
135                             // This is an anchor, store target and position...
136                             QObject * obj = new QObject(documentModel);
137                             QRectF rect = getFragmentPosition(block, fragment);
138                             KWPage page = document->pageManager()->page(rect.left());
139                             rect.translate(page.topMargin(), page.rightMargin());
140                             rect = canvas->viewMode()->documentToView(rect, canvas->viewConverter());
141                             rect.translate(page.pageNumber() * (page.topMargin() + page.bottomMargin()) + 20, 0);
142                             obj->setProperty("linkRect", rect);
143                             obj->setProperty("linkTarget", QUrl(format.anchorHref()));
144                             linkTargets.append(obj);
145                         }
146                     }
147                 }
148             }
149         }
150     }
151 
getFragmentPosition(QTextBlock block,QTextFragment fragment)152     QRectF getFragmentPosition(QTextBlock block, QTextFragment fragment)
153     {
154         // TODO this only produces a position for the first part, if the link spans more than one line...
155         // Need to sort that somehow, unfortunately probably by slapping this code into the above function.
156         // For now leave it like this, more important things are needed.
157         QTextLayout* layout = block.layout();
158         QTextLine line = layout->lineForTextPosition(fragment.position() - block.position());
159         if (!line.isValid()) {
160             // fragment has no valid position and consequently no line...
161             return QRectF();
162         }
163         qreal top = line.position().y();
164         qreal bottom = line.position().y() + line.height();
165         qreal left = line.cursorToX(fragment.position() - block.position());
166         qreal right = line.cursorToX((fragment.position() - block.position()) + fragment.length());
167         QRectF fragmentPosition(QPointF(top, left), QPointF(bottom, right));
168         return fragmentPosition.adjusted(layout->position().x(), layout->position().y(), 0, 0);
169     }
170 
deepShapeFind(const QList<KoShape * > & shapes)171     QList<KoShape*> deepShapeFind(const QList<KoShape*>& shapes)
172     {
173         QList<KoShape*> allShapes;
174         foreach(KoShape* shape, shapes) {
175             allShapes.append(shape);
176             KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
177             if (container) {
178                 allShapes.append(deepShapeFind(container->shapes()));
179             }
180         }
181         return allShapes;
182     }
getCursorPosition(int position)183     QRectF getCursorPosition(int position)
184     {
185         QPointF point;
186         QTextBlock block = textEditor->document()->findBlock(position);
187         QTextLayout* layout = block.layout();
188         QTextLine line = layout->lineForTextPosition(position - block.position());
189         if (!line.isValid()) {
190             // fragment has no valid position and consequently no line...
191             return QRectF();
192         }
193         qreal top = line.position().y();
194         qreal left = line.cursorToX(position - block.position());
195         point = QPointF(left + layout->position().y(), top + layout->position().x());
196 
197         KoShape* shape = canvas->shapeManager()->selection()->firstSelectedShape();
198         point += shape->position();
199         while(KoShapeContainer* parent = shape->parent()) {
200             point += parent->position();
201         }
202 
203         KWPage page = document->pageManager()->page(point.y());
204 //         point += QPointF(page.rightMargin(), page.pageNumber() * page.topMargin()
205 //                                            + (page.pageNumber() - 1) * page.bottomMargin());
206 //         if (page.pageNumber() > 1)
207 //             point += QPointF(0, 20);
208         point += QPointF(0, (page.pageNumber() - 1) * (page.topMargin() + 20));
209 //        point = canvas->viewConverter()->documentToView(point);
210 
211         return canvas->viewConverter()->documentToView(QRectF(point, QSizeF(0, line.height())));
212     }
213 };
214 
CQTextDocumentCanvas(QDeclarativeItem * parent)215 CQTextDocumentCanvas::CQTextDocumentCanvas(QDeclarativeItem* parent)
216     : CQCanvasBase(parent), d(new Private)
217 {
218     setAcceptedMouseButtons(Qt::LeftButton);
219     d->findText = new KoFindText(this);
220 
221     connect (d->findText, SIGNAL(updateCanvas()), SLOT(updateCanvas()));
222     connect (d->findText, SIGNAL(matchFound(KoFindMatch)), SLOT(findMatchFound(KoFindMatch)));
223     connect (d->findText, SIGNAL(noMatchFound()), SLOT(findNoMatchFound()));
224     connect (KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), SLOT(currentToolChanged(KoCanvasController*,int)));
225 }
226 
~CQTextDocumentCanvas()227 CQTextDocumentCanvas::~CQTextDocumentCanvas()
228 {
229     d->part->removeMainWindow(d->part->currentMainwindow());
230     KoToolManager::instance()->removeCanvasController(d->canvas->canvasController());
231     delete d;
232 }
233 
openFile(const QString & uri)234 void CQTextDocumentCanvas::openFile(const QString& uri)
235 {
236     emit loadingBegun();
237 
238     KoDocumentEntry entry;
239     QList<QPluginLoader*> pluginLoaders = KoPluginLoader::pluginLoaders("calligra/parts");
240     Q_FOREACH (QPluginLoader *loader, pluginLoaders) {
241         if (loader->fileName().contains(QLatin1String("wordspart"))) {
242             entry = KoDocumentEntry(loader);
243             pluginLoaders.removeOne(loader);
244             break;
245         }
246     }
247     qDeleteAll(pluginLoaders);
248     if (entry.isEmpty()) {
249         qWarning("Unable to load Words plugin, aborting!");
250         return;
251     }
252 
253     // QT5TODO: ownership of d->part unclear
254     d->part = entry.createKoPart();
255     KoDocument* document = d->part->document();
256     document->setAutoSave(0);
257     document->setCheckAutoSaveFile(false);
258 
259     QUrl url(uri);
260     if (url.scheme() == "newfile") {
261         KWDocument* doc = qobject_cast<KWDocument*>(document);
262         doc->initEmpty();
263         KWPageStyle style = doc->pageManager()->defaultPageStyle();
264         Q_ASSERT(style.isValid());
265 
266         KoColumns columns;
267         columns.count = url.queryItemValue("columncount").toInt();
268         columns.gapWidth = url.queryItemValue("columngap").toDouble();
269         style.setColumns(columns);
270 
271         KoPageLayout layout = style.pageLayout();
272         layout.format = KoPageFormat::formatFromString(url.queryItemValue("pageformat"));
273         layout.orientation = (KoPageFormat::Orientation)url.queryItemValue("pageorientation").toInt();
274         layout.height = MM_TO_POINT(url.queryItemValue("height").toDouble());
275         layout.width = MM_TO_POINT(url.queryItemValue("width").toDouble());
276         if (url.queryItemValue("facingpages").toInt() == 1) {
277             layout.bindingSide = MM_TO_POINT(url.queryItemValue("leftmargin").toDouble());
278             layout.pageEdge = MM_TO_POINT(url.queryItemValue("rightmargin").toDouble());
279             layout.leftMargin = layout.rightMargin = -1;
280         }
281         else {
282             layout.bindingSide = layout.pageEdge = -1;
283             layout.leftMargin = MM_TO_POINT(url.queryItemValue("leftmargin").toDouble());
284             layout.rightMargin = MM_TO_POINT(url.queryItemValue("rightmargin").toDouble());
285         }
286         layout.topMargin = MM_TO_POINT(url.queryItemValue("topmargin").toDouble());
287         layout.bottomMargin = MM_TO_POINT(url.queryItemValue("bottommargin").toDouble());
288         style.setPageLayout(layout);
289 
290         doc->setUnit(KoUnit::fromSymbol(url.queryItemValue("unit")));
291         doc->relayout();
292     } else if (url.scheme() == "template") {
293         qApp->setOverrideCursor(Qt::BusyCursor);
294         // Nip away the manually added template:// bit of the uri passed from the caller
295         bool ok = document->loadNativeFormat(uri.mid(11));
296         document->setModified(false);
297         document->undoStack()->clear();
298 
299         if (ok) {
300             QString mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
301             // in case this is a open document template remove the -template from the end
302             mimeType.remove( QRegExp( "-template$" ) );
303             document->setMimeTypeAfterLoading(mimeType);
304             document->resetURL();
305             document->setEmpty();
306         } else {
307             document->showLoadingErrorDialog();
308             document->initEmpty();
309         }
310         qApp->restoreOverrideCursor();
311     } else {
312         document->openUrl(url);
313     }
314 
315     document->setModified(false);
316     qApp->processEvents();
317 
318     d->canvas = dynamic_cast<KWCanvasItem*> (d->part->canvasItem(d->part->document()));
319     createAndSetCanvasControllerOn(d->canvas);
320     createAndSetZoomController(d->canvas);
321     updateZoomControllerAccordingToDocument(document);
322 
323     d->canvas->resourceManager()->setResource(KoDocumentResourceManager::HandleRadius, 9);
324     d->canvas->resourceManager()->setResource(KoDocumentResourceManager::GrabSensitivity, 9);
325 
326     QGraphicsWidget *graphicsWidget = dynamic_cast<QGraphicsWidget*>(d->canvas);
327     graphicsWidget->setParentItem(this);
328     graphicsWidget->installEventFilter(this);
329     graphicsWidget->setVisible(true);
330     graphicsWidget->setGeometry(x(), y(), width(), height());
331 
332     if (d->pageNumber >= 1) {
333       gotoPage(d->pageNumber, document);
334     }
335 
336     QList<QTextDocument*> texts;
337     KoFindText::findTextInShapes(d->canvas->shapeManager()->shapes(), texts);
338     d->findText->setDocuments(texts);
339 
340     d->document = qobject_cast<KWDocument*>(document);
341     d->documentModel = new CQTextDocumentModel(this, d->document, d->canvas->shapeManager());
342     emit documentModelChanged();
343     emit thumbnailSizeChanged();
344     connect(d->documentModel, SIGNAL(thumbnailSizeChanged()), SIGNAL(thumbnailSizeChanged()));
345 
346     d->updateLinkTargets();
347     emit linkTargetsChanged();
348 
349     connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(textEditorChanged()));
350     connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(shapeTransparencyChanged()));
351 
352     d->notes = new CQTextDocumentNotesModel(this);
353     emit notesChanged();
354 
355     emit textEditorChanged();
356     emit loadingFinished();
357 }
358 
gotoPage(int pageNumber,KoDocument * document)359 void CQTextDocumentCanvas::gotoPage(int pageNumber, KoDocument *document)
360 {
361     const KWDocument *kwDoc = static_cast<const KWDocument*>(document);
362     KWPage currentTextDocPage = kwDoc->pageManager()->page(pageNumber);
363 
364     QRectF rect = d->canvas->viewConverter()->documentToView(currentTextDocPage.rect());
365     canvasController()->pan(rect.topLeft().toPoint() - d->canvas->viewConverter()->documentToView(canvasController()->documentOffset()).toPoint());
366     alignTopWith(rect.top());
367     updateCanvas();
368 }
369 
cameraY() const370 int CQTextDocumentCanvas::cameraY() const
371 {
372     return d->currentPoint.y();
373 }
374 
pagePosition(int pageIndex)375 qreal CQTextDocumentCanvas::pagePosition(int pageIndex)
376 {
377     KWPage page = d->document->pageManager()->page(pageIndex);
378     // a very silly heuristic for ensuring the page number changes if we change pages.
379     // this means we don't have to glue the canvas and controlleritem together too close,
380     // but yes, it does look a bit silly.
381     QTimer::singleShot(0, d->throttleTimer, SLOT(stop()));
382     QTimer::singleShot(0, this, SIGNAL(currentPageNumberChanged()));
383     return d->canvas->viewMode()->documentToView(page.rect().topLeft(), d->canvas->viewConverter()).y();
384 }
385 
shapeTransparency() const386 qreal CQTextDocumentCanvas::shapeTransparency() const
387 {
388     if (d->canvas && d->canvas->shapeManager()) {
389         KoShape* shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
390         if (shape) {
391             return shape->transparency();
392         }
393     }
394     return CQCanvasBase::shapeTransparency();
395 }
396 
setShapeTransparency(qreal newTransparency)397 void CQTextDocumentCanvas::setShapeTransparency(qreal newTransparency)
398 {
399     if (d->canvas && d->canvas->shapeManager()) {
400         KoShape* shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
401         if (shape) {
402             if (!qFuzzyCompare(1 + shape->transparency(), 1 + newTransparency)) {
403                 shape->setTransparency(newTransparency);
404                 CQCanvasBase::setShapeTransparency(newTransparency);
405             }
406         }
407     }
408 }
409 
textEditor()410 QObject* CQTextDocumentCanvas::textEditor()
411 {
412     if (d->canvas) {
413         if (d->textEditor) {
414             disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
415         }
416         d->textEditor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
417         if (d->textEditor) {
418             disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
419         }
420         emit selectionChanged();
421         return d->textEditor;
422     }
423     return 0;
424 }
425 
hasSelection() const426 bool CQTextDocumentCanvas::hasSelection() const
427 {
428     if (d->textEditor) {
429         return d->textEditor->hasSelection();
430     }
431     return false;
432 }
433 
selectionStartPos() const434 QRectF CQTextDocumentCanvas::selectionStartPos() const
435 {
436     if (d->textEditor) {
437         return d->getCursorPosition(d->textEditor->selectionStart());
438     }
439     return QRectF(0,0,0,0);
440 }
441 
selectionEndPos() const442 QRectF CQTextDocumentCanvas::selectionEndPos() const
443 {
444     if (d->textEditor) {
445         return d->getCursorPosition(d->textEditor->selectionEnd());
446     }
447     return QRectF(0,0,0,0);
448 }
449 
zoomAction() const450 QObject* CQTextDocumentCanvas::zoomAction() const
451 {
452     if (zoomController() && zoomController()->zoomAction()) {
453         return zoomController()->zoomAction();
454     }
455     return 0;
456 }
457 
thumbnailSize() const458 QSizeF CQTextDocumentCanvas::thumbnailSize() const
459 {
460     if (d->documentModel) {
461         return d->documentModel->thumbnailSize();
462     }
463     return QSizeF();
464 }
465 
setThumbnailSize(const QSizeF & newSize)466 void CQTextDocumentCanvas::setThumbnailSize(const QSizeF& newSize)
467 {
468     if (d->documentModel) {
469         d->documentModel->setThumbnailSize(newSize.toSize());
470     }
471     emit thumbnailSizeChanged();
472 }
473 
deselectEverything()474 void CQTextDocumentCanvas::deselectEverything()
475 {
476     KoTextEditor* editor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
477     if (editor) {
478         editor->clearSelection();
479     }
480     d->canvas->shapeManager()->selection()->deselectAll();
481     updateCanvas();
482 }
483 
notes() const484 QObject* CQTextDocumentCanvas::notes() const
485 {
486     return d->notes;
487 }
488 
addSticker(const QString & imageUrl)489 void CQTextDocumentCanvas::addSticker(const QString& imageUrl)
490 {
491     QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());
492    // Prepare a QImage with desired characteristics
493     QImage image(200, 200, QImage::Format_ARGB32);
494     image.fill(Qt::transparent);
495 
496     // Get QPainter that paints to the image
497     QPainter painter(&image);
498     renderer.render(&painter);
499     painter.end();
500 
501     KoProperties* params = new KoProperties();
502     params->setProperty("qimage", image);
503     KoShapeFactoryBase* factory = KoShapeRegistry::instance()->get("PictureShape");
504     if (factory) {
505         KoShape* shape = factory->createShape(params, d->document->resourceManager());
506 
507         QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
508         KoShapeAnchor *anchor = new KoShapeAnchor(shape);
509         anchor->setAnchorType(KoShapeAnchor::AnchorPage);
510         anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
511         anchor->setVerticalPos(KoShapeAnchor::VFromTop);
512         anchor->setHorizontalRel(KoShapeAnchor::HPage);
513         anchor->setVerticalRel(KoShapeAnchor::VPage);
514         shape->setAnchor(anchor);
515         shape->setPosition(pos);
516         shape->scale(0.2, 0.2);
517 
518 //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
519         KoSelection *selection = d->canvas->shapeManager()->selection();
520         selection->deselectAll();
521         selection->select(shape);
522 //        d->canvas->addCommand(cmd);
523         d->canvas->shapeManager()->addShape(shape);
524 
525         d->notes->addEntry("", imageUrl, "Neutral", shape);
526     }
527 }
528 
addNote(const QString & text,const QString & color,const QString & imageUrl)529 void CQTextDocumentCanvas::addNote(const QString& text, const QString& color, const QString& imageUrl)
530 {
531     QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());
532 
533    // Prepare a QImage with desired characteritisc
534     QImage image(400, 200, QImage::Format_ARGB32);
535     image.fill(Qt::transparent);
536 
537     // Get QPainter that paints to the image
538     QPainter painter(&image);
539     painter.setRenderHint(QPainter::Antialiasing, true);
540     painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
541     painter.setRenderHint(QPainter::TextAntialiasing, true);
542 
543     renderer.render(&painter, image.rect());
544 
545     QFont font;
546     font.setFamily("Permanent Marker");
547     font.setStyle(QFont::StyleNormal);
548     font.setPixelSize(40);
549     painter.setPen(QPen(QColor(color), 0));
550     painter.setFont(font);
551     painter.drawText(image.rect().adjusted(10, 10, -20, -20), Qt::AlignCenter | Qt::TextWordWrap, text);
552     painter.end();
553 
554     KoProperties* params = new KoProperties();
555     params->setProperty("qimage", image);
556     KoShapeFactoryBase* factory = KoShapeRegistry::instance()->get("PictureShape");
557     if (factory) {
558         KoShape* shape = factory->createShape(params, d->document->resourceManager());
559 
560         QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
561         KoShapeAnchor *anchor = new KoShapeAnchor(shape);
562         anchor->setAnchorType(KoShapeAnchor::AnchorPage);
563         anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
564         anchor->setVerticalPos(KoShapeAnchor::VFromTop);
565         anchor->setHorizontalRel(KoShapeAnchor::HPage);
566         anchor->setVerticalRel(KoShapeAnchor::VPage);
567         shape->setAnchor(anchor);
568         shape->setPosition(pos);
569         shape->rotate(-15);
570         shape->scale(0.3, 0.3);
571 
572 //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
573         KoSelection *selection = d->canvas->shapeManager()->selection();
574         selection->deselectAll();
575         selection->select(shape);
576 //        d->canvas->addCommand(cmd);
577         d->canvas->shapeManager()->addShape(shape);
578 
579         d->notes->addEntry(text, "", color, shape);
580     }
581 }
582 
setCameraY(int cameraY)583 void CQTextDocumentCanvas::setCameraY(int cameraY)
584 {
585     d->currentPoint.setY (cameraY);
586     emit cameraYChanged();
587 }
588 
alignTopWith(int y)589 void CQTextDocumentCanvas::alignTopWith(int y)
590 {
591     d->currentPoint.setY(y);
592     emit cameraYChanged();
593 }
594 
currentPageNumber() const595 int CQTextDocumentCanvas::currentPageNumber() const
596 {
597     if (d->document && !d->throttleTimer->isActive()) {
598         // Can't use this at the moment, we sort of don't have the right one, because derp :P
599         //d->canvas->resourceManager()->resource(KoCanvasResourceManager::CurrentPage).toInt();
600         d->throttleTimer->start();
601         const KWDocument *kwDoc = static_cast<const KWDocument*>(d->document);
602         d->pageNumber = kwDoc->pageManager()->page(d->canvas->viewMode()->viewToDocument(d->canvas->documentOffset(), d->canvas->viewConverter())).pageNumber();
603     }
604     return d->pageNumber;
605 }
606 
setCurrentPageNumber(const int & currentPageNumber)607 void CQTextDocumentCanvas::setCurrentPageNumber(const int& currentPageNumber)
608 {
609     if (d->pageNumber != currentPageNumber) {
610         gotoPage(currentPageNumber, d->document);
611     }
612 }
613 
render(QPainter * painter,const QRectF & target)614 void CQTextDocumentCanvas::render(QPainter* painter, const QRectF& target)
615 {
616     Q_UNUSED(target)
617     QStyleOptionGraphicsItem option;
618     option.exposedRect = QRect(0, 0, width(), height());
619     option.rect = option.exposedRect.toAlignedRect();
620     d->canvas->canvasItem()->paint(painter, &option);
621 }
622 
event(QEvent * event)623 bool CQTextDocumentCanvas::event( QEvent* event )
624 {
625     switch(static_cast<int>(event->type())) {
626         case ViewModeSwitchEvent::AboutToSwitchViewModeEvent: {
627             ViewModeSynchronisationObject* syncObject = static_cast<ViewModeSwitchEvent*>(event)->synchronisationObject();
628 
629             if (d->canvas) {
630                 syncObject->documentOffset = d->canvas->documentOffset();
631                 syncObject->zoomLevel = zoomController()->zoomAction()->effectiveZoom();
632                 syncObject->activeToolId = KoToolManager::instance()->activeToolId();
633                 syncObject->shapes = d->canvas->shapeManager()->shapes();
634                 syncObject->initialized = true;
635             }
636 
637             return true;
638         }
639         case ViewModeSwitchEvent::SwitchedToTouchModeEvent: {
640             ViewModeSynchronisationObject* syncObject = static_cast<ViewModeSwitchEvent*>(event)->synchronisationObject();
641 
642             if (d->canvas && syncObject->initialized) {
643                 d->canvas->shapeManager()->setShapes(syncObject->shapes);
644 
645                 KoToolManager::instance()->switchToolRequested("PageToolFactory_ID");
646                 qApp->processEvents();
647 
648                 zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, syncObject->zoomLevel);
649 
650                 qApp->processEvents();
651                 emit positionShouldChange(syncObject->documentOffset);
652             }
653 
654             return true;
655         }
656 //         case KisTabletEvent::TabletPressEx:
657 //         case KisTabletEvent::TabletReleaseEx:
658 //             emit interactionStarted();
659 //             d->canvas->inputManager()->eventFilter(this, event);
660 //             return true;
661 //         case KisTabletEvent::TabletMoveEx:
662 //             d->tabletEventCount++; //Note that this will wraparound at some point; This is intentional.
663 // #ifdef Q_OS_X11
664 //             if (d->tabletEventCount % 2 == 0)
665 // #endif
666 //                 d->canvas->inputManager()->eventFilter(this, event);
667 //             return true;
668         default:
669             break;
670     }
671     return QDeclarativeItem::event( event );
672 }
673 
currentToolChanged(KoCanvasController * controller,int uniqueToolId)674 void CQTextDocumentCanvas::currentToolChanged(KoCanvasController* controller, int uniqueToolId)
675 {
676     Q_UNUSED(controller)
677     Q_UNUSED(uniqueToolId)
678     d->currentTool = qobject_cast<KoToolBase*>(KoToolManager::instance()->toolById(d->canvas, KoToolManager::instance()->activeToolId()));
679 }
680 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * e)681 void CQTextDocumentCanvas::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* e)
682 {
683     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
684     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
685     d->currentTool->mouseDoubleClickEvent(&pe);
686     updateCanvas();
687     emit selectionChanged();
688     e->setAccepted(me.isAccepted());
689 }
690 
mouseMoveEvent(QGraphicsSceneMouseEvent * e)691 void CQTextDocumentCanvas::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
692 {
693     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
694     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
695     d->currentTool->mouseMoveEvent(&pe);
696     updateCanvas();
697     emit selectionChanged();
698     e->setAccepted(me.isAccepted());
699 }
700 
mousePressEvent(QGraphicsSceneMouseEvent * e)701 void CQTextDocumentCanvas::mousePressEvent(QGraphicsSceneMouseEvent* e)
702 {
703     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
704     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
705     d->currentTool->mousePressEvent(&pe);
706     updateCanvas();
707     emit selectionChanged();
708     e->setAccepted(me.isAccepted());
709 }
710 
mouseReleaseEvent(QGraphicsSceneMouseEvent * e)711 void CQTextDocumentCanvas::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
712 {
713     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
714     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
715     d->currentTool->mouseReleaseEvent(&pe);
716     updateCanvas();
717     emit selectionChanged();
718     e->setAccepted(me.isAccepted());
719 }
720 
geometryChanged(const QRectF & newGeometry,const QRectF & oldGeometry)721 void CQTextDocumentCanvas::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
722 {
723     if (d->canvas) {
724         QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(d->canvas);
725         if (widget) {
726             widget->setGeometry(newGeometry);
727         }
728     }
729     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
730 }
731 
createAndSetCanvasControllerOn(KoCanvasBase * canvas)732 void CQTextDocumentCanvas::createAndSetCanvasControllerOn(KoCanvasBase* canvas)
733 {
734     //TODO: pass a proper action collection
735     CQCanvasController *controller = new CQCanvasController(new KActionCollection(this));
736     setCanvasController(controller);
737     connect (controller, SIGNAL(documentSizeChanged(QSize)), SLOT(updateDocumentSize(QSize)));
738     controller->setCanvas(canvas);
739     KoToolManager::instance()->addController (controller);
740 }
741 
createAndSetZoomController(KoCanvasBase * canvas)742 void CQTextDocumentCanvas::createAndSetZoomController(KoCanvasBase* canvas)
743 {
744     KoZoomHandler* zoomHandler = static_cast<KoZoomHandler*> (canvas->viewConverter());
745     setZoomController(new KoZoomController(canvasController(), zoomHandler, new KActionCollection(this)));
746 
747     KWCanvasItem *kwCanvasItem = static_cast<KWCanvasItem*>(canvas);
748     connect (kwCanvasItem, SIGNAL(documentSize(QSizeF)), zoomController(), SLOT(setDocumentSize(QSizeF)));
749     connect (canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SIGNAL(currentPageNumberChanged()));
750     connect (canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), kwCanvasItem, SLOT(setDocumentOffset(QPoint)));
751     connect (zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), SIGNAL(zoomActionChanged()));
752     kwCanvasItem->updateSize();
753     emit zoomActionChanged();
754 }
755 
updateZoomControllerAccordingToDocument(const KoDocument * document)756 void CQTextDocumentCanvas::updateZoomControllerAccordingToDocument(const KoDocument* document)
757 {
758     const KWDocument *kwDoc = static_cast<const KWDocument*>(document);
759     zoomController()->setPageSize (kwDoc->pageManager()->begin().rect().size());
760 }
761 
searchTerm() const762 QString CQTextDocumentCanvas::searchTerm() const
763 {
764     return d->searchTerm;
765 }
766 
setSearchTerm(const QString & term)767 void CQTextDocumentCanvas::setSearchTerm(const QString& term)
768 {
769     d->searchTerm = term;
770     if (!term.isEmpty()) {
771         d->findText->find(term);
772     }
773     emit searchTermChanged();
774 }
775 
findMatchFound(const KoFindMatch & match)776 void CQTextDocumentCanvas::findMatchFound(const KoFindMatch &match)
777 {
778     QTextCursor cursor = match.location().value<QTextCursor>();
779     d->canvas->canvasItem()->update();
780 
781     d->canvas->resourceManager()->setResource (KoText::CurrentTextAnchor, cursor.anchor());
782     d->canvas->resourceManager()->setResource (KoText::CurrentTextPosition, cursor.position());
783 }
784 
findNoMatchFound()785 void CQTextDocumentCanvas::findNoMatchFound()
786 {
787     qDebug() << "Match for " << d->searchTerm << " not found";
788 }
789 
updateCanvas()790 void CQTextDocumentCanvas::updateCanvas()
791 {
792     KWCanvasItem* kwCanvasItem = dynamic_cast<KWCanvasItem*> (d->canvas);
793     kwCanvasItem->update();
794 }
795 
findNext()796 void CQTextDocumentCanvas::findNext()
797 {
798     d->findText->findNext();
799 }
800 
findPrevious()801 void CQTextDocumentCanvas::findPrevious()
802 {
803     d->findText->findPrevious();
804 }
805 
documentModel() const806 QObject* CQTextDocumentCanvas::documentModel() const
807 {
808     return d->documentModel;
809 }
810 
document() const811 KWDocument* CQTextDocumentCanvas::document() const
812 {
813     return d->document;
814 }
815 
doc() const816 QObject* CQTextDocumentCanvas::doc() const
817 {
818     return d->document;
819 }
820 
part() const821 QObject* CQTextDocumentCanvas::part() const
822 {
823     return d->part;
824 }
825 
linkTargets() const826 QObjectList CQTextDocumentCanvas::linkTargets() const
827 {
828     return d->linkTargets;
829 }
830 
documentSize() const831 QSize CQTextDocumentCanvas::documentSize() const
832 {
833     return d->documentSize;
834 }
835 
updateDocumentSize(const QSize & size)836 void CQTextDocumentCanvas::updateDocumentSize(const QSize& size)
837 {
838     d->documentSize = size;
839     emit documentSizeChanged();
840 }
841