File indexing completed on 2024-05-05 17:09:09

0001 /*
0002  * This file is part of the KDE project
0003  *
0004  * Copyright (C) 2013 Shantanu Tushar <shantanu@kde.org>
0005  * Copyright (C) 2013 Sujith Haridasan <sujith.h@gmail.com>
0006  * Copyright (C) 2013 Arjen Hiemstra <ahiemstra@heimr.nl>
0007  *
0008  * This library is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU Library General Public
0010  * License as published by the Free Software Foundation; either
0011  * version 2 of the License, or (at your option) any later version.
0012  *
0013  * This library is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  * Library General Public License for more details.
0017  *
0018  * You should have received a copy of the GNU Library General Public License
0019  * along with this library; see the file COPYING.LIB.  If not, write to
0020  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021  * Boston, MA 02110-1301, USA.
0022  *
0023  */
0024 
0025 #include "CQTextDocumentCanvas.h"
0026 #include "CQCanvasController.h"
0027 #include "CQTextDocumentModel.h"
0028 #include "CQTextDocumentNotesModel.h"
0029 
0030 #include "gemini/ViewModeSwitchEvent.h"
0031 
0032 #include <KoPluginLoader.h>
0033 #include <KoDocumentEntry.h>
0034 #include <KoUnit.h>
0035 #include <KoDocument.h>
0036 #include <KoDocumentResourceManager.h>
0037 #include <KoPart.h>
0038 #include <KoFindText.h>
0039 #include <KoCanvasBase.h>
0040 #include <KoToolManager.h>
0041 #include <KoZoomHandler.h>
0042 #include <KoZoomController.h>
0043 #include <KoShape.h>
0044 #include <KoToolManager_p.h>
0045 #include <KoToolBase.h>
0046 #include <KoPointerEvent.h>
0047 #include <KoSelection.h>
0048 #include <KoShapeRegistry.h>
0049 #include <KoShapeAnchor.h>
0050 #include <KoShapeContainer.h>
0051 #include <KoTextEditor.h>
0052 #include <KoProperties.h>
0053 #include <KoColumns.h>
0054 #include <KWDocument.h>
0055 #include <KWPage.h>
0056 #include <KWCanvasItem.h>
0057 #include <commands/KWShapeCreateCommand.h>
0058 
0059 #include <KActionCollection>
0060 
0061 #include <QPluginLoader>
0062 #include <QMimeDatabase>
0063 #include <QStyleOptionGraphicsItem>
0064 #include <QGraphicsWidget>
0065 #include <QTextDocument>
0066 #include <QTextFrame>
0067 #include <QTextLayout>
0068 #include <QGraphicsSceneMouseEvent>
0069 #include <QTextDocumentFragment>
0070 #include <QSvgRenderer>
0071 #include <QApplication>
0072 #include <QDebug>
0073 
0074 class CQTextDocumentCanvas::Private
0075 {
0076 public:
0077     Private()
0078         : canvas(0),
0079           findText(0),
0080           documentModel(0),
0081           document(0),
0082           pageNumber(0),
0083           throttleTimer(new QTimer()),
0084           currentTool(0),
0085           notes(0),
0086           textEditor(0)
0087     {
0088         throttleTimer->setInterval(200);
0089         throttleTimer->setSingleShot(true);
0090     }
0091 
0092     KWCanvasItem *canvas;
0093     QString searchTerm;
0094     KoFindText *findText;
0095     CQTextDocumentModel *documentModel;
0096     KWDocument* document;
0097     KoPart* part;
0098     QSize documentSize;
0099     int pageNumber;
0100     QPoint currentPoint;
0101     QObjectList linkTargets;
0102     QTimer* throttleTimer;
0103     KoToolBase* currentTool;
0104     CQTextDocumentNotesModel* notes;
0105     KoTextEditor* textEditor;
0106 
0107     void updateLinkTargets()
0108     {
0109         qDeleteAll(linkTargets);
0110         linkTargets.clear();
0111 
0112         if (!canvas) {
0113             return;
0114         }
0115 
0116         foreach(const KoShape* shape, canvas->shapeManager()->shapes()) {
0117             if (!shape->hyperLink().isEmpty()) {
0118                 QObject * obj = new QObject(documentModel);
0119                 obj->setProperty("linkRect", shape->boundingRect());
0120                 obj->setProperty("linkTarget", QUrl(shape->hyperLink()));
0121                 linkTargets.append(obj);
0122             }
0123         }
0124 
0125         foreach(QTextDocument* text, findText->documents()) {
0126             QTextBlock block = text->rootFrame()->firstCursorPosition().block();
0127             for (; block.isValid(); block = block.next()) {
0128                 block.begin();
0129                 QTextBlock::iterator it;
0130                 for (it = block.begin(); !(it.atEnd()); ++it) {
0131                     QTextFragment fragment = it.fragment();
0132                     if (fragment.isValid()) {
0133                         QTextCharFormat format = fragment.charFormat();
0134                         if (format.isAnchor()) {
0135                             // This is an anchor, store target and position...
0136                             QObject * obj = new QObject(documentModel);
0137                             QRectF rect = getFragmentPosition(block, fragment);
0138                             KWPage page = document->pageManager()->page(rect.left());
0139                             rect.translate(page.topMargin(), page.rightMargin());
0140                             rect = canvas->viewMode()->documentToView(rect, canvas->viewConverter());
0141                             rect.translate(page.pageNumber() * (page.topMargin() + page.bottomMargin()) + 20, 0);
0142                             obj->setProperty("linkRect", rect);
0143                             obj->setProperty("linkTarget", QUrl(format.anchorHref()));
0144                             linkTargets.append(obj);
0145                         }
0146                     }
0147                 }
0148             }
0149         }
0150     }
0151 
0152     QRectF getFragmentPosition(QTextBlock block, QTextFragment fragment)
0153     {
0154         // TODO this only produces a position for the first part, if the link spans more than one line...
0155         // Need to sort that somehow, unfortunately probably by slapping this code into the above function.
0156         // For now leave it like this, more important things are needed.
0157         QTextLayout* layout = block.layout();
0158         QTextLine line = layout->lineForTextPosition(fragment.position() - block.position());
0159         if (!line.isValid()) {
0160             // fragment has no valid position and consequently no line...
0161             return QRectF();
0162         }
0163         qreal top = line.position().y();
0164         qreal bottom = line.position().y() + line.height();
0165         qreal left = line.cursorToX(fragment.position() - block.position());
0166         qreal right = line.cursorToX((fragment.position() - block.position()) + fragment.length());
0167         QRectF fragmentPosition(QPointF(top, left), QPointF(bottom, right));
0168         return fragmentPosition.adjusted(layout->position().x(), layout->position().y(), 0, 0);
0169     }
0170 
0171     QList<KoShape*> deepShapeFind(const QList<KoShape*>& shapes)
0172     {
0173         QList<KoShape*> allShapes;
0174         foreach(KoShape* shape, shapes) {
0175             allShapes.append(shape);
0176             KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
0177             if (container) {
0178                 allShapes.append(deepShapeFind(container->shapes()));
0179             }
0180         }
0181         return allShapes;
0182     }
0183     QRectF getCursorPosition(int position)
0184     {
0185         QPointF point;
0186         QTextBlock block = textEditor->document()->findBlock(position);
0187         QTextLayout* layout = block.layout();
0188         QTextLine line = layout->lineForTextPosition(position - block.position());
0189         if (!line.isValid()) {
0190             // fragment has no valid position and consequently no line...
0191             return QRectF();
0192         }
0193         qreal top = line.position().y();
0194         qreal left = line.cursorToX(position - block.position());
0195         point = QPointF(left + layout->position().y(), top + layout->position().x());
0196 
0197         KoShape* shape = canvas->shapeManager()->selection()->firstSelectedShape();
0198         point += shape->position();
0199         while(KoShapeContainer* parent = shape->parent()) {
0200             point += parent->position();
0201         }
0202 
0203         KWPage page = document->pageManager()->page(point.y());
0204 //         point += QPointF(page.rightMargin(), page.pageNumber() * page.topMargin()
0205 //                                            + (page.pageNumber() - 1) * page.bottomMargin());
0206 //         if (page.pageNumber() > 1)
0207 //             point += QPointF(0, 20);
0208         point += QPointF(0, (page.pageNumber() - 1) * (page.topMargin() + 20));
0209 //        point = canvas->viewConverter()->documentToView(point);
0210 
0211         return canvas->viewConverter()->documentToView(QRectF(point, QSizeF(0, line.height())));
0212     }
0213 };
0214 
0215 CQTextDocumentCanvas::CQTextDocumentCanvas(QDeclarativeItem* parent)
0216     : CQCanvasBase(parent), d(new Private)
0217 {
0218     setAcceptedMouseButtons(Qt::LeftButton);
0219     d->findText = new KoFindText(this);
0220 
0221     connect (d->findText, SIGNAL(updateCanvas()), SLOT(updateCanvas()));
0222     connect (d->findText, SIGNAL(matchFound(KoFindMatch)), SLOT(findMatchFound(KoFindMatch)));
0223     connect (d->findText, SIGNAL(noMatchFound()), SLOT(findNoMatchFound()));
0224     connect (KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), SLOT(currentToolChanged(KoCanvasController*,int)));
0225 }
0226 
0227 CQTextDocumentCanvas::~CQTextDocumentCanvas()
0228 {
0229     d->part->removeMainWindow(d->part->currentMainwindow());
0230     KoToolManager::instance()->removeCanvasController(d->canvas->canvasController());
0231     delete d;
0232 }
0233 
0234 void CQTextDocumentCanvas::openFile(const QString& uri)
0235 {
0236     emit loadingBegun();
0237 
0238     KoDocumentEntry entry;
0239     QList<QPluginLoader*> pluginLoaders = KoPluginLoader::pluginLoaders("calligra/parts");
0240     Q_FOREACH (QPluginLoader *loader, pluginLoaders) {
0241         if (loader->fileName().contains(QLatin1String("wordspart"))) {
0242             entry = KoDocumentEntry(loader);
0243             pluginLoaders.removeOne(loader);
0244             break;
0245         }
0246     }
0247     qDeleteAll(pluginLoaders);
0248     if (entry.isEmpty()) {
0249         qWarning("Unable to load Words plugin, aborting!");
0250         return;
0251     }
0252 
0253     // QT5TODO: ownership of d->part unclear
0254     d->part = entry.createKoPart();
0255     KoDocument* document = d->part->document();
0256     document->setAutoSave(0);
0257     document->setCheckAutoSaveFile(false);
0258 
0259     QUrl url(uri);
0260     if (url.scheme() == "newfile") {
0261         KWDocument* doc = qobject_cast<KWDocument*>(document);
0262         doc->initEmpty();
0263         KWPageStyle style = doc->pageManager()->defaultPageStyle();
0264         Q_ASSERT(style.isValid());
0265 
0266         KoColumns columns;
0267         columns.count = url.queryItemValue("columncount").toInt();
0268         columns.gapWidth = url.queryItemValue("columngap").toDouble();
0269         style.setColumns(columns);
0270 
0271         KoPageLayout layout = style.pageLayout();
0272         layout.format = KoPageFormat::formatFromString(url.queryItemValue("pageformat"));
0273         layout.orientation = (KoPageFormat::Orientation)url.queryItemValue("pageorientation").toInt();
0274         layout.height = MM_TO_POINT(url.queryItemValue("height").toDouble());
0275         layout.width = MM_TO_POINT(url.queryItemValue("width").toDouble());
0276         if (url.queryItemValue("facingpages").toInt() == 1) {
0277             layout.bindingSide = MM_TO_POINT(url.queryItemValue("leftmargin").toDouble());
0278             layout.pageEdge = MM_TO_POINT(url.queryItemValue("rightmargin").toDouble());
0279             layout.leftMargin = layout.rightMargin = -1;
0280         }
0281         else {
0282             layout.bindingSide = layout.pageEdge = -1;
0283             layout.leftMargin = MM_TO_POINT(url.queryItemValue("leftmargin").toDouble());
0284             layout.rightMargin = MM_TO_POINT(url.queryItemValue("rightmargin").toDouble());
0285         }
0286         layout.topMargin = MM_TO_POINT(url.queryItemValue("topmargin").toDouble());
0287         layout.bottomMargin = MM_TO_POINT(url.queryItemValue("bottommargin").toDouble());
0288         style.setPageLayout(layout);
0289 
0290         doc->setUnit(KoUnit::fromSymbol(url.queryItemValue("unit")));
0291         doc->relayout();
0292     } else if (url.scheme() == "template") {
0293         qApp->setOverrideCursor(Qt::BusyCursor);
0294         // Nip away the manually added template:// bit of the uri passed from the caller
0295         bool ok = document->loadNativeFormat(uri.mid(11));
0296         document->setModified(false);
0297         document->undoStack()->clear();
0298 
0299         if (ok) {
0300             QString mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
0301             // in case this is a open document template remove the -template from the end
0302             mimeType.remove( QRegExp( "-template$" ) );
0303             document->setMimeTypeAfterLoading(mimeType);
0304             document->resetURL();
0305             document->setEmpty();
0306         } else {
0307             document->showLoadingErrorDialog();
0308             document->initEmpty();
0309         }
0310         qApp->restoreOverrideCursor();
0311     } else {
0312         document->openUrl(url);
0313     }
0314 
0315     document->setModified(false);
0316     qApp->processEvents();
0317 
0318     d->canvas = dynamic_cast<KWCanvasItem*> (d->part->canvasItem(d->part->document()));
0319     createAndSetCanvasControllerOn(d->canvas);
0320     createAndSetZoomController(d->canvas);
0321     updateZoomControllerAccordingToDocument(document);
0322 
0323     d->canvas->resourceManager()->setResource(KoDocumentResourceManager::HandleRadius, 9);
0324     d->canvas->resourceManager()->setResource(KoDocumentResourceManager::GrabSensitivity, 9);
0325 
0326     QGraphicsWidget *graphicsWidget = dynamic_cast<QGraphicsWidget*>(d->canvas);
0327     graphicsWidget->setParentItem(this);
0328     graphicsWidget->installEventFilter(this);
0329     graphicsWidget->setVisible(true);
0330     graphicsWidget->setGeometry(x(), y(), width(), height());
0331 
0332     if (d->pageNumber >= 1) {
0333       gotoPage(d->pageNumber, document);
0334     }
0335 
0336     QList<QTextDocument*> texts;
0337     KoFindText::findTextInShapes(d->canvas->shapeManager()->shapes(), texts);
0338     d->findText->setDocuments(texts);
0339 
0340     d->document = qobject_cast<KWDocument*>(document);
0341     d->documentModel = new CQTextDocumentModel(this, d->document, d->canvas->shapeManager());
0342     emit documentModelChanged();
0343     emit thumbnailSizeChanged();
0344     connect(d->documentModel, SIGNAL(thumbnailSizeChanged()), SIGNAL(thumbnailSizeChanged()));
0345 
0346     d->updateLinkTargets();
0347     emit linkTargetsChanged();
0348 
0349     connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(textEditorChanged()));
0350     connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(shapeTransparencyChanged()));
0351 
0352     d->notes = new CQTextDocumentNotesModel(this);
0353     emit notesChanged();
0354 
0355     emit textEditorChanged();
0356     emit loadingFinished();
0357 }
0358 
0359 void CQTextDocumentCanvas::gotoPage(int pageNumber, KoDocument *document)
0360 {
0361     const KWDocument *kwDoc = static_cast<const KWDocument*>(document);
0362     KWPage currentTextDocPage = kwDoc->pageManager()->page(pageNumber);
0363 
0364     QRectF rect = d->canvas->viewConverter()->documentToView(currentTextDocPage.rect());
0365     canvasController()->pan(rect.topLeft().toPoint() - d->canvas->viewConverter()->documentToView(canvasController()->documentOffset()).toPoint());
0366     alignTopWith(rect.top());
0367     updateCanvas();
0368 }
0369 
0370 int CQTextDocumentCanvas::cameraY() const
0371 {
0372     return d->currentPoint.y();
0373 }
0374 
0375 qreal CQTextDocumentCanvas::pagePosition(int pageIndex)
0376 {
0377     KWPage page = d->document->pageManager()->page(pageIndex);
0378     // a very silly heuristic for ensuring the page number changes if we change pages.
0379     // this means we don't have to glue the canvas and controlleritem together too close,
0380     // but yes, it does look a bit silly.
0381     QTimer::singleShot(0, d->throttleTimer, SLOT(stop()));
0382     QTimer::singleShot(0, this, SIGNAL(currentPageNumberChanged()));
0383     return d->canvas->viewMode()->documentToView(page.rect().topLeft(), d->canvas->viewConverter()).y();
0384 }
0385 
0386 qreal CQTextDocumentCanvas::shapeTransparency() const
0387 {
0388     if (d->canvas && d->canvas->shapeManager()) {
0389         KoShape* shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
0390         if (shape) {
0391             return shape->transparency();
0392         }
0393     }
0394     return CQCanvasBase::shapeTransparency();
0395 }
0396 
0397 void CQTextDocumentCanvas::setShapeTransparency(qreal newTransparency)
0398 {
0399     if (d->canvas && d->canvas->shapeManager()) {
0400         KoShape* shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
0401         if (shape) {
0402             if (!qFuzzyCompare(1 + shape->transparency(), 1 + newTransparency)) {
0403                 shape->setTransparency(newTransparency);
0404                 CQCanvasBase::setShapeTransparency(newTransparency);
0405             }
0406         }
0407     }
0408 }
0409 
0410 QObject* CQTextDocumentCanvas::textEditor()
0411 {
0412     if (d->canvas) {
0413         if (d->textEditor) {
0414             disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
0415         }
0416         d->textEditor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
0417         if (d->textEditor) {
0418             disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
0419         }
0420         emit selectionChanged();
0421         return d->textEditor;
0422     }
0423     return 0;
0424 }
0425 
0426 bool CQTextDocumentCanvas::hasSelection() const
0427 {
0428     if (d->textEditor) {
0429         return d->textEditor->hasSelection();
0430     }
0431     return false;
0432 }
0433 
0434 QRectF CQTextDocumentCanvas::selectionStartPos() const
0435 {
0436     if (d->textEditor) {
0437         return d->getCursorPosition(d->textEditor->selectionStart());
0438     }
0439     return QRectF(0,0,0,0);
0440 }
0441 
0442 QRectF CQTextDocumentCanvas::selectionEndPos() const
0443 {
0444     if (d->textEditor) {
0445         return d->getCursorPosition(d->textEditor->selectionEnd());
0446     }
0447     return QRectF(0,0,0,0);
0448 }
0449 
0450 QObject* CQTextDocumentCanvas::zoomAction() const
0451 {
0452     if (zoomController() && zoomController()->zoomAction()) {
0453         return zoomController()->zoomAction();
0454     }
0455     return 0;
0456 }
0457 
0458 QSizeF CQTextDocumentCanvas::thumbnailSize() const
0459 {
0460     if (d->documentModel) {
0461         return d->documentModel->thumbnailSize();
0462     }
0463     return QSizeF();
0464 }
0465 
0466 void CQTextDocumentCanvas::setThumbnailSize(const QSizeF& newSize)
0467 {
0468     if (d->documentModel) {
0469         d->documentModel->setThumbnailSize(newSize.toSize());
0470     }
0471     emit thumbnailSizeChanged();
0472 }
0473 
0474 void CQTextDocumentCanvas::deselectEverything()
0475 {
0476     KoTextEditor* editor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
0477     if (editor) {
0478         editor->clearSelection();
0479     }
0480     d->canvas->shapeManager()->selection()->deselectAll();
0481     updateCanvas();
0482 }
0483 
0484 QObject* CQTextDocumentCanvas::notes() const
0485 {
0486     return d->notes;
0487 }
0488 
0489 void CQTextDocumentCanvas::addSticker(const QString& imageUrl)
0490 {
0491     QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());
0492    // Prepare a QImage with desired characteristics
0493     QImage image(200, 200, QImage::Format_ARGB32);
0494     image.fill(Qt::transparent);
0495 
0496     // Get QPainter that paints to the image
0497     QPainter painter(&image);
0498     renderer.render(&painter);
0499     painter.end();
0500 
0501     KoProperties* params = new KoProperties();
0502     params->setProperty("qimage", image);
0503     KoShapeFactoryBase* factory = KoShapeRegistry::instance()->get("PictureShape");
0504     if (factory) {
0505         KoShape* shape = factory->createShape(params, d->document->resourceManager());
0506 
0507         QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
0508         KoShapeAnchor *anchor = new KoShapeAnchor(shape);
0509         anchor->setAnchorType(KoShapeAnchor::AnchorPage);
0510         anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
0511         anchor->setVerticalPos(KoShapeAnchor::VFromTop);
0512         anchor->setHorizontalRel(KoShapeAnchor::HPage);
0513         anchor->setVerticalRel(KoShapeAnchor::VPage);
0514         shape->setAnchor(anchor);
0515         shape->setPosition(pos);
0516         shape->scale(0.2, 0.2);
0517 
0518 //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
0519         KoSelection *selection = d->canvas->shapeManager()->selection();
0520         selection->deselectAll();
0521         selection->select(shape);
0522 //        d->canvas->addCommand(cmd);
0523         d->canvas->shapeManager()->addShape(shape);
0524 
0525         d->notes->addEntry("", imageUrl, "Neutral", shape);
0526     }
0527 }
0528 
0529 void CQTextDocumentCanvas::addNote(const QString& text, const QString& color, const QString& imageUrl)
0530 {
0531     QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());
0532 
0533    // Prepare a QImage with desired characteritisc
0534     QImage image(400, 200, QImage::Format_ARGB32);
0535     image.fill(Qt::transparent);
0536 
0537     // Get QPainter that paints to the image
0538     QPainter painter(&image);
0539     painter.setRenderHint(QPainter::Antialiasing, true);
0540     painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
0541     painter.setRenderHint(QPainter::TextAntialiasing, true);
0542 
0543     renderer.render(&painter, image.rect());
0544 
0545     QFont font;
0546     font.setFamily("Permanent Marker");
0547     font.setStyle(QFont::StyleNormal);
0548     font.setPixelSize(40);
0549     painter.setPen(QPen(QColor(color), 0));
0550     painter.setFont(font);
0551     painter.drawText(image.rect().adjusted(10, 10, -20, -20), Qt::AlignCenter | Qt::TextWordWrap, text);
0552     painter.end();
0553 
0554     KoProperties* params = new KoProperties();
0555     params->setProperty("qimage", image);
0556     KoShapeFactoryBase* factory = KoShapeRegistry::instance()->get("PictureShape");
0557     if (factory) {
0558         KoShape* shape = factory->createShape(params, d->document->resourceManager());
0559 
0560         QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
0561         KoShapeAnchor *anchor = new KoShapeAnchor(shape);
0562         anchor->setAnchorType(KoShapeAnchor::AnchorPage);
0563         anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
0564         anchor->setVerticalPos(KoShapeAnchor::VFromTop);
0565         anchor->setHorizontalRel(KoShapeAnchor::HPage);
0566         anchor->setVerticalRel(KoShapeAnchor::VPage);
0567         shape->setAnchor(anchor);
0568         shape->setPosition(pos);
0569         shape->rotate(-15);
0570         shape->scale(0.3, 0.3);
0571 
0572 //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
0573         KoSelection *selection = d->canvas->shapeManager()->selection();
0574         selection->deselectAll();
0575         selection->select(shape);
0576 //        d->canvas->addCommand(cmd);
0577         d->canvas->shapeManager()->addShape(shape);
0578 
0579         d->notes->addEntry(text, "", color, shape);
0580     }
0581 }
0582 
0583 void CQTextDocumentCanvas::setCameraY(int cameraY)
0584 {
0585     d->currentPoint.setY (cameraY);
0586     emit cameraYChanged();
0587 }
0588 
0589 void CQTextDocumentCanvas::alignTopWith(int y)
0590 {
0591     d->currentPoint.setY(y);
0592     emit cameraYChanged();
0593 }
0594 
0595 int CQTextDocumentCanvas::currentPageNumber() const
0596 {
0597     if (d->document && !d->throttleTimer->isActive()) {
0598         // Can't use this at the moment, we sort of don't have the right one, because derp :P
0599         //d->canvas->resourceManager()->resource(KoCanvasResourceManager::CurrentPage).toInt();
0600         d->throttleTimer->start();
0601         const KWDocument *kwDoc = static_cast<const KWDocument*>(d->document);
0602         d->pageNumber = kwDoc->pageManager()->page(d->canvas->viewMode()->viewToDocument(d->canvas->documentOffset(), d->canvas->viewConverter())).pageNumber();
0603     }
0604     return d->pageNumber;
0605 }
0606 
0607 void CQTextDocumentCanvas::setCurrentPageNumber(const int& currentPageNumber)
0608 {
0609     if (d->pageNumber != currentPageNumber) {
0610         gotoPage(currentPageNumber, d->document);
0611     }
0612 }
0613 
0614 void CQTextDocumentCanvas::render(QPainter* painter, const QRectF& target)
0615 {
0616     Q_UNUSED(target)
0617     QStyleOptionGraphicsItem option;
0618     option.exposedRect = QRect(0, 0, width(), height());
0619     option.rect = option.exposedRect.toAlignedRect();
0620     d->canvas->canvasItem()->paint(painter, &option);
0621 }
0622 
0623 bool CQTextDocumentCanvas::event( QEvent* event )
0624 {
0625     switch(static_cast<int>(event->type())) {
0626         case ViewModeSwitchEvent::AboutToSwitchViewModeEvent: {
0627             ViewModeSynchronisationObject* syncObject = static_cast<ViewModeSwitchEvent*>(event)->synchronisationObject();
0628 
0629             if (d->canvas) {
0630                 syncObject->documentOffset = d->canvas->documentOffset();
0631                 syncObject->zoomLevel = zoomController()->zoomAction()->effectiveZoom();
0632                 syncObject->activeToolId = KoToolManager::instance()->activeToolId();
0633                 syncObject->shapes = d->canvas->shapeManager()->shapes();
0634                 syncObject->initialized = true;
0635             }
0636 
0637             return true;
0638         }
0639         case ViewModeSwitchEvent::SwitchedToTouchModeEvent: {
0640             ViewModeSynchronisationObject* syncObject = static_cast<ViewModeSwitchEvent*>(event)->synchronisationObject();
0641 
0642             if (d->canvas && syncObject->initialized) {
0643                 d->canvas->shapeManager()->setShapes(syncObject->shapes);
0644 
0645                 KoToolManager::instance()->switchToolRequested("PageToolFactory_ID");
0646                 qApp->processEvents();
0647 
0648                 zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, syncObject->zoomLevel);
0649 
0650                 qApp->processEvents();
0651                 emit positionShouldChange(syncObject->documentOffset);
0652             }
0653 
0654             return true;
0655         }
0656 //         case KisTabletEvent::TabletPressEx:
0657 //         case KisTabletEvent::TabletReleaseEx:
0658 //             emit interactionStarted();
0659 //             d->canvas->inputManager()->eventFilter(this, event);
0660 //             return true;
0661 //         case KisTabletEvent::TabletMoveEx:
0662 //             d->tabletEventCount++; //Note that this will wraparound at some point; This is intentional.
0663 // #ifdef Q_OS_X11
0664 //             if (d->tabletEventCount % 2 == 0)
0665 // #endif
0666 //                 d->canvas->inputManager()->eventFilter(this, event);
0667 //             return true;
0668         default:
0669             break;
0670     }
0671     return QDeclarativeItem::event( event );
0672 }
0673 
0674 void CQTextDocumentCanvas::currentToolChanged(KoCanvasController* controller, int uniqueToolId)
0675 {
0676     Q_UNUSED(controller)
0677     Q_UNUSED(uniqueToolId)
0678     d->currentTool = qobject_cast<KoToolBase*>(KoToolManager::instance()->toolById(d->canvas, KoToolManager::instance()->activeToolId()));
0679 }
0680 
0681 void CQTextDocumentCanvas::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* e)
0682 {
0683     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
0684     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
0685     d->currentTool->mouseDoubleClickEvent(&pe);
0686     updateCanvas();
0687     emit selectionChanged();
0688     e->setAccepted(me.isAccepted());
0689 }
0690 
0691 void CQTextDocumentCanvas::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
0692 {
0693     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
0694     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
0695     d->currentTool->mouseMoveEvent(&pe);
0696     updateCanvas();
0697     emit selectionChanged();
0698     e->setAccepted(me.isAccepted());
0699 }
0700 
0701 void CQTextDocumentCanvas::mousePressEvent(QGraphicsSceneMouseEvent* e)
0702 {
0703     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
0704     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
0705     d->currentTool->mousePressEvent(&pe);
0706     updateCanvas();
0707     emit selectionChanged();
0708     e->setAccepted(me.isAccepted());
0709 }
0710 
0711 void CQTextDocumentCanvas::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
0712 {
0713     QMouseEvent me(e->type(), e->pos().toPoint(), e->button(), e->buttons(), e->modifiers());
0714     KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
0715     d->currentTool->mouseReleaseEvent(&pe);
0716     updateCanvas();
0717     emit selectionChanged();
0718     e->setAccepted(me.isAccepted());
0719 }
0720 
0721 void CQTextDocumentCanvas::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
0722 {
0723     if (d->canvas) {
0724         QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget*>(d->canvas);
0725         if (widget) {
0726             widget->setGeometry(newGeometry);
0727         }
0728     }
0729     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
0730 }
0731 
0732 void CQTextDocumentCanvas::createAndSetCanvasControllerOn(KoCanvasBase* canvas)
0733 {
0734     //TODO: pass a proper action collection
0735     CQCanvasController *controller = new CQCanvasController(new KActionCollection(this));
0736     setCanvasController(controller);
0737     connect (controller, SIGNAL(documentSizeChanged(QSize)), SLOT(updateDocumentSize(QSize)));
0738     controller->setCanvas(canvas);
0739     KoToolManager::instance()->addController (controller);
0740 }
0741 
0742 void CQTextDocumentCanvas::createAndSetZoomController(KoCanvasBase* canvas)
0743 {
0744     KoZoomHandler* zoomHandler = static_cast<KoZoomHandler*> (canvas->viewConverter());
0745     setZoomController(new KoZoomController(canvasController(), zoomHandler, new KActionCollection(this)));
0746 
0747     KWCanvasItem *kwCanvasItem = static_cast<KWCanvasItem*>(canvas);
0748     connect (kwCanvasItem, SIGNAL(documentSize(QSizeF)), zoomController(), SLOT(setDocumentSize(QSizeF)));
0749     connect (canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SIGNAL(currentPageNumberChanged()));
0750     connect (canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), kwCanvasItem, SLOT(setDocumentOffset(QPoint)));
0751     connect (zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), SIGNAL(zoomActionChanged()));
0752     kwCanvasItem->updateSize();
0753     emit zoomActionChanged();
0754 }
0755 
0756 void CQTextDocumentCanvas::updateZoomControllerAccordingToDocument(const KoDocument* document)
0757 {
0758     const KWDocument *kwDoc = static_cast<const KWDocument*>(document);
0759     zoomController()->setPageSize (kwDoc->pageManager()->begin().rect().size());
0760 }
0761 
0762 QString CQTextDocumentCanvas::searchTerm() const
0763 {
0764     return d->searchTerm;
0765 }
0766 
0767 void CQTextDocumentCanvas::setSearchTerm(const QString& term)
0768 {
0769     d->searchTerm = term;
0770     if (!term.isEmpty()) {
0771         d->findText->find(term);
0772     }
0773     emit searchTermChanged();
0774 }
0775 
0776 void CQTextDocumentCanvas::findMatchFound(const KoFindMatch &match)
0777 {
0778     QTextCursor cursor = match.location().value<QTextCursor>();
0779     d->canvas->canvasItem()->update();
0780 
0781     d->canvas->resourceManager()->setResource (KoText::CurrentTextAnchor, cursor.anchor());
0782     d->canvas->resourceManager()->setResource (KoText::CurrentTextPosition, cursor.position());
0783 }
0784 
0785 void CQTextDocumentCanvas::findNoMatchFound()
0786 {
0787     qDebug() << "Match for " << d->searchTerm << " not found";
0788 }
0789 
0790 void CQTextDocumentCanvas::updateCanvas()
0791 {
0792     KWCanvasItem* kwCanvasItem = dynamic_cast<KWCanvasItem*> (d->canvas);
0793     kwCanvasItem->update();
0794 }
0795 
0796 void CQTextDocumentCanvas::findNext()
0797 {
0798     d->findText->findNext();
0799 }
0800 
0801 void CQTextDocumentCanvas::findPrevious()
0802 {
0803     d->findText->findPrevious();
0804 }
0805 
0806 QObject* CQTextDocumentCanvas::documentModel() const
0807 {
0808     return d->documentModel;
0809 }
0810 
0811 KWDocument* CQTextDocumentCanvas::document() const
0812 {
0813     return d->document;
0814 }
0815 
0816 QObject* CQTextDocumentCanvas::doc() const
0817 {
0818     return d->document;
0819 }
0820 
0821 QObject* CQTextDocumentCanvas::part() const
0822 {
0823     return d->part;
0824 }
0825 
0826 QObjectList CQTextDocumentCanvas::linkTargets() const
0827 {
0828     return d->linkTargets;
0829 }
0830 
0831 QSize CQTextDocumentCanvas::documentSize() const
0832 {
0833     return d->documentSize;
0834 }
0835 
0836 void CQTextDocumentCanvas::updateDocumentSize(const QSize& size)
0837 {
0838     d->documentSize = size;
0839     emit documentSizeChanged();
0840 }