/*
 * This file is part of the KDE project
 *
 * SPDX-FileCopyrightText: 2013 Shantanu Tushar <shantanu@kde.org>
 * SPDX-FileCopyrightText: 2013 Sujith Haridasan <sujith.h@gmail.com>
 * SPDX-FileCopyrightText: 2013 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * SPDX-License-Identifier: LGPL-2.0-or-later
 *
 */

#include "CQTextDocumentCanvas.h"
#include "CQCanvasController.h"
#include "CQTextDocumentModel.h"
#include "CQTextDocumentNotesModel.h"

#include "gemini/ViewModeSwitchEvent.h"

#include <KWCanvasItem.h>
#include <KWDocument.h>
#include <KWPage.h>
#include <KoCanvasBase.h>
#include <KoColumns.h>
#include <KoDocument.h>
#include <KoDocumentEntry.h>
#include <KoDocumentResourceManager.h>
#include <KoFindText.h>
#include <KoPart.h>
#include <KoPluginLoader.h>
#include <KoPointerEvent.h>
#include <KoProperties.h>
#include <KoSelection.h>
#include <KoShape.h>
#include <KoShapeAnchor.h>
#include <KoShapeContainer.h>
#include <KoShapeRegistry.h>
#include <KoTextEditor.h>
#include <KoToolBase.h>
#include <KoToolManager.h>
#include <KoToolManager_p.h>
#include <KoUnit.h>
#include <KoZoomController.h>
#include <KoZoomHandler.h>
#include <commands/KWShapeCreateCommand.h>

#include <KActionCollection>

#include <QApplication>
#include <QDebug>
#include <QGraphicsWidget>
#include <QMimeDatabase>
#include <QMouseEvent>
#include <QPluginLoader>
#include <QStyleOptionGraphicsItem>
#include <QSvgRenderer>
#include <QTextDocument>
#include <QTextDocumentFragment>
#include <QTextFrame>
#include <QTextLayout>
#include <QUrl>
#include <qurlquery.h>

class CQTextDocumentCanvas::Private
{
public:
    Private()
        : canvas(0)
        , findText(0)
        , documentModel(0)
        , document(0)
        , pageNumber(0)
        , throttleTimer(new QTimer())
        , currentTool(0)
        , notes(0)
        , textEditor(0)
    {
        throttleTimer->setInterval(200);
        throttleTimer->setSingleShot(true);
    }

    KWCanvasItem *canvas;
    QString searchTerm;
    KoFindText *findText;
    CQTextDocumentModel *documentModel;
    KWDocument *document;
    KoPart *part;
    QSize documentSize;
    int pageNumber;
    QPoint currentPoint;
    QObjectList linkTargets;
    QTimer *throttleTimer;
    KoToolBase *currentTool;
    CQTextDocumentNotesModel *notes;
    KoTextEditor *textEditor;

    void updateLinkTargets()
    {
        qDeleteAll(linkTargets);
        linkTargets.clear();

        if (!canvas) {
            return;
        }

        foreach (const KoShape *shape, canvas->shapeManager()->shapes()) {
            if (!shape->hyperLink().isEmpty()) {
                QObject *obj = new QObject(documentModel);
                obj->setProperty("linkRect", shape->boundingRect());
                obj->setProperty("linkTarget", QUrl(shape->hyperLink()));
                linkTargets.append(obj);
            }
        }

        foreach (QTextDocument *text, findText->documents()) {
            QTextBlock block = text->rootFrame()->firstCursorPosition().block();
            for (; block.isValid(); block = block.next()) {
                block.begin();
                QTextBlock::iterator it;
                for (it = block.begin(); !(it.atEnd()); ++it) {
                    QTextFragment fragment = it.fragment();
                    if (fragment.isValid()) {
                        QTextCharFormat format = fragment.charFormat();
                        if (format.isAnchor()) {
                            // This is an anchor, store target and position...
                            QObject *obj = new QObject(documentModel);
                            QRectF rect = getFragmentPosition(block, fragment);
                            KWPage page = document->pageManager()->page(rect.left());
                            rect.translate(page.topMargin(), page.rightMargin());
                            rect = canvas->viewMode()->documentToView(rect, canvas->viewConverter());
                            rect.translate(page.pageNumber() * (page.topMargin() + page.bottomMargin()) + 20, 0);
                            obj->setProperty("linkRect", rect);
                            obj->setProperty("linkTarget", QUrl(format.anchorHref()));
                            linkTargets.append(obj);
                        }
                    }
                }
            }
        }
    }

    QRectF getFragmentPosition(QTextBlock block, QTextFragment fragment)
    {
        // TODO this only produces a position for the first part, if the link spans more than one line...
        // Need to sort that somehow, unfortunately probably by slapping this code into the above function.
        // For now leave it like this, more important things are needed.
        QTextLayout *layout = block.layout();
        QTextLine line = layout->lineForTextPosition(fragment.position() - block.position());
        if (!line.isValid()) {
            // fragment has no valid position and consequently no line...
            return QRectF();
        }
        qreal top = line.position().y();
        qreal bottom = line.position().y() + line.height();
        qreal left = line.cursorToX(fragment.position() - block.position());
        qreal right = line.cursorToX((fragment.position() - block.position()) + fragment.length());
        QRectF fragmentPosition(QPointF(top, left), QPointF(bottom, right));
        return fragmentPosition.adjusted(layout->position().x(), layout->position().y(), 0, 0);
    }

    QList<KoShape *> deepShapeFind(const QList<KoShape *> &shapes)
    {
        QList<KoShape *> allShapes;
        foreach (KoShape *shape, shapes) {
            allShapes.append(shape);
            KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(shape);
            if (container) {
                allShapes.append(deepShapeFind(container->shapes()));
            }
        }
        return allShapes;
    }
    QRectF getCursorPosition(int position)
    {
        QPointF point;
        QTextBlock block = textEditor->document()->findBlock(position);
        QTextLayout *layout = block.layout();
        QTextLine line = layout->lineForTextPosition(position - block.position());
        if (!line.isValid()) {
            // fragment has no valid position and consequently no line...
            return QRectF();
        }
        qreal top = line.position().y();
        qreal left = line.cursorToX(position - block.position());
        point = QPointF(left + layout->position().y(), top + layout->position().x());

        KoShape *shape = canvas->shapeManager()->selection()->firstSelectedShape();
        point += shape->position();
        while (KoShapeContainer *parent = shape->parent()) {
            point += parent->position();
        }

        KWPage page = document->pageManager()->page(point.y());
        //         point += QPointF(page.rightMargin(), page.pageNumber() * page.topMargin()
        //                                            + (page.pageNumber() - 1) * page.bottomMargin());
        //         if (page.pageNumber() > 1)
        //             point += QPointF(0, 20);
        point += QPointF(0, (page.pageNumber() - 1) * (page.topMargin() + 20));
        //        point = canvas->viewConverter()->documentToView(point);

        return canvas->viewConverter()->documentToView(QRectF(point, QSizeF(0, line.height())));
    }
};

CQTextDocumentCanvas::CQTextDocumentCanvas(QQuickItem *parent)
    : CQCanvasBase(parent)
    , d(new Private)
{
    setAcceptedMouseButtons(Qt::LeftButton);
    d->findText = new KoFindText(this);

    connect(d->findText, SIGNAL(updateCanvas()), SLOT(updateCanvas()));
    connect(d->findText, SIGNAL(matchFound(KoFindMatch)), SLOT(findMatchFound(KoFindMatch)));
    connect(d->findText, SIGNAL(noMatchFound()), SLOT(findNoMatchFound()));
    connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController *, int)), SLOT(currentToolChanged(KoCanvasController *, int)));
}

CQTextDocumentCanvas::~CQTextDocumentCanvas()
{
    d->part->removeMainWindow(d->part->currentMainwindow());
    KoToolManager::instance()->removeCanvasController(d->canvas->canvasController());
    delete d;
}

void CQTextDocumentCanvas::openFile(const QString &uri)
{
    Q_EMIT loadingBegun();

    KoDocumentEntry entry;
    const auto metaDatas = KoPluginLoader::pluginLoaders("calligra/parts");
    for (const auto &metaData : metaDatas) {
        if (metaData.fileName().contains(QLatin1String("wordspart"))) {
            entry = KoDocumentEntry(metaData);
            break;
        }
    }

    if (entry.isEmpty()) {
        qWarning("Unable to load Words plugin, aborting!");
        return;
    }

    // QT5TODO: ownership of d->part unclear
    d->part = entry.createKoPart();
    KoDocument *document = d->part->document();
    document->setAutoSave(0);
    document->setCheckAutoSaveFile(false);

    QUrl url(uri);
    if (url.scheme() == "newfile") {
        QUrlQuery query(url);
        KWDocument *doc = qobject_cast<KWDocument *>(document);
        doc->initEmpty();
        KWPageStyle style = doc->pageManager()->defaultPageStyle();
        Q_ASSERT(style.isValid());

        KoColumns columns;
        columns.count = query.queryItemValue("columncount").toInt();
        columns.gapWidth = query.queryItemValue("columngap").toDouble();
        style.setColumns(columns);

        KoPageLayout layout = style.pageLayout();
        layout.format = KoPageFormat::formatFromString(query.queryItemValue("pageformat"));
        layout.orientation = (KoPageFormat::Orientation)query.queryItemValue("pageorientation").toInt();
        layout.height = MM_TO_POINT(query.queryItemValue("height").toDouble());
        layout.width = MM_TO_POINT(query.queryItemValue("width").toDouble());
        if (query.queryItemValue("facingpages").toInt() == 1) {
            layout.bindingSide = MM_TO_POINT(query.queryItemValue("leftmargin").toDouble());
            layout.pageEdge = MM_TO_POINT(query.queryItemValue("rightmargin").toDouble());
            layout.leftMargin = layout.rightMargin = -1;
        } else {
            layout.bindingSide = layout.pageEdge = -1;
            layout.leftMargin = MM_TO_POINT(query.queryItemValue("leftmargin").toDouble());
            layout.rightMargin = MM_TO_POINT(query.queryItemValue("rightmargin").toDouble());
        }
        layout.topMargin = MM_TO_POINT(query.queryItemValue("topmargin").toDouble());
        layout.bottomMargin = MM_TO_POINT(query.queryItemValue("bottommargin").toDouble());
        style.setPageLayout(layout);

        doc->setUnit(KoUnit::fromSymbol(query.queryItemValue("unit")));
        doc->relayout();
    } else if (url.scheme() == "template") {
        qApp->setOverrideCursor(Qt::BusyCursor);
        // Nip away the manually added template:// bit of the uri passed from the caller
        bool ok = document->loadNativeFormat(uri.mid(11));
        document->setModified(false);
        document->undoStack()->clear();

        if (ok) {
            QString mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
            // in case this is a open document template remove the -template from the end
            mimeType.remove(QRegularExpression("-template$"));
            document->setMimeTypeAfterLoading(mimeType);
            document->resetURL();
            document->setEmpty();
        } else {
            document->showLoadingErrorDialog();
            document->initEmpty();
        }
        qApp->restoreOverrideCursor();
    } else {
        document->openUrl(url);
    }

    document->setModified(false);
    qApp->processEvents();

    d->canvas = dynamic_cast<KWCanvasItem *>(d->part->canvasItem(d->part->document()));
    createAndSetCanvasControllerOn(d->canvas);
    createAndSetZoomController(d->canvas);
    updateZoomControllerAccordingToDocument(document);

    d->canvas->resourceManager()->setResource(KoDocumentResourceManager::HandleRadius, 9);
    d->canvas->resourceManager()->setResource(KoDocumentResourceManager::GrabSensitivity, 9);

    QGraphicsWidget *graphicsWidget = dynamic_cast<QGraphicsWidget *>(d->canvas);
    graphicsWidget->setParentItem(this);
    graphicsWidget->installEventFilter(this);
    graphicsWidget->setVisible(true);
    graphicsWidget->setGeometry(x(), y(), width(), height());

    if (d->pageNumber >= 1) {
        gotoPage(d->pageNumber, document);
    }

    QList<QTextDocument *> texts;
    KoFindText::findTextInShapes(d->canvas->shapeManager()->shapes(), texts);
    d->findText->setDocuments(texts);

    d->document = qobject_cast<KWDocument *>(document);
    d->documentModel = new CQTextDocumentModel(this, d->document, d->canvas->shapeManager());
    Q_EMIT documentModelChanged();
    Q_EMIT thumbnailSizeChanged();
    connect(d->documentModel, SIGNAL(thumbnailSizeChanged()), SIGNAL(thumbnailSizeChanged()));

    d->updateLinkTargets();
    Q_EMIT linkTargetsChanged();

    connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(textEditorChanged()));
    connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), SIGNAL(shapeTransparencyChanged()));

    d->notes = new CQTextDocumentNotesModel(this);
    Q_EMIT notesChanged();

    Q_EMIT textEditorChanged();
    Q_EMIT loadingFinished();
}

void CQTextDocumentCanvas::gotoPage(int pageNumber, KoDocument *document)
{
    const KWDocument *kwDoc = static_cast<const KWDocument *>(document);
    KWPage currentTextDocPage = kwDoc->pageManager()->page(pageNumber);

    QRectF rect = d->canvas->viewConverter()->documentToView(currentTextDocPage.rect());
    canvasController()->pan(rect.topLeft().toPoint() - d->canvas->viewConverter()->documentToView(canvasController()->documentOffset()).toPoint());
    alignTopWith(rect.top());
    updateCanvas();
}

int CQTextDocumentCanvas::cameraY() const
{
    return d->currentPoint.y();
}

qreal CQTextDocumentCanvas::pagePosition(int pageIndex)
{
    KWPage page = d->document->pageManager()->page(pageIndex);
    // a very silly heuristic for ensuring the page number changes if we change pages.
    // this means we don't have to glue the canvas and controlleritem together too close,
    // but yes, it does look a bit silly.
    QTimer::singleShot(0, d->throttleTimer, SLOT(stop()));
    QTimer::singleShot(0, this, SIGNAL(currentPageNumberChanged()));
    return d->canvas->viewMode()->documentToView(page.rect().topLeft(), d->canvas->viewConverter()).y();
}

qreal CQTextDocumentCanvas::shapeTransparency() const
{
    if (d->canvas && d->canvas->shapeManager()) {
        KoShape *shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
        if (shape) {
            return shape->transparency();
        }
    }
    return CQCanvasBase::shapeTransparency();
}

void CQTextDocumentCanvas::setShapeTransparency(qreal newTransparency)
{
    if (d->canvas && d->canvas->shapeManager()) {
        KoShape *shape = d->canvas->shapeManager()->selection()->firstSelectedShape();
        if (shape) {
            if (!qFuzzyCompare(1 + shape->transparency(), 1 + newTransparency)) {
                shape->setTransparency(newTransparency);
                CQCanvasBase::setShapeTransparency(newTransparency);
            }
        }
    }
}

QObject *CQTextDocumentCanvas::textEditor()
{
    if (d->canvas) {
        if (d->textEditor) {
            disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
        }
        d->textEditor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
        if (d->textEditor) {
            disconnect(d->textEditor, SIGNAL(cursorPositionChanged()), this, SIGNAL(selectionChanged()));
        }
        Q_EMIT selectionChanged();
        return d->textEditor;
    }
    return 0;
}

bool CQTextDocumentCanvas::hasSelection() const
{
    if (d->textEditor) {
        return d->textEditor->hasSelection();
    }
    return false;
}

QRectF CQTextDocumentCanvas::selectionStartPos() const
{
    if (d->textEditor) {
        return d->getCursorPosition(d->textEditor->selectionStart());
    }
    return QRectF(0, 0, 0, 0);
}

QRectF CQTextDocumentCanvas::selectionEndPos() const
{
    if (d->textEditor) {
        return d->getCursorPosition(d->textEditor->selectionEnd());
    }
    return QRectF(0, 0, 0, 0);
}

QObject *CQTextDocumentCanvas::zoomAction() const
{
    if (zoomController() && zoomController()->zoomAction()) {
        return zoomController()->zoomAction();
    }
    return 0;
}

QSizeF CQTextDocumentCanvas::thumbnailSize() const
{
    if (d->documentModel) {
        return d->documentModel->thumbnailSize();
    }
    return QSizeF();
}

void CQTextDocumentCanvas::setThumbnailSize(const QSizeF &newSize)
{
    if (d->documentModel) {
        d->documentModel->setThumbnailSize(newSize.toSize());
    }
    Q_EMIT thumbnailSizeChanged();
}

void CQTextDocumentCanvas::deselectEverything()
{
    KoTextEditor *editor = KoTextEditor::getTextEditorFromCanvas(d->canvas);
    if (editor) {
        editor->clearSelection();
    }
    d->canvas->shapeManager()->selection()->deselectAll();
    updateCanvas();
}

QObject *CQTextDocumentCanvas::notes() const
{
    return d->notes;
}

void CQTextDocumentCanvas::addSticker(const QString &imageUrl)
{
    QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());
    // Prepare a QImage with desired characteristics
    QImage image(200, 200, QImage::Format_ARGB32);
    image.fill(Qt::transparent);

    // Get QPainter that paints to the image
    QPainter painter(&image);
    renderer.render(&painter);
    painter.end();

    KoProperties *params = new KoProperties();
    params->setProperty("qimage", image);
    KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get("PictureShape");
    if (factory) {
        KoShape *shape = factory->createShape(params, d->document->resourceManager());

        QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
        KoShapeAnchor *anchor = new KoShapeAnchor(shape);
        anchor->setAnchorType(KoShapeAnchor::AnchorPage);
        anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
        anchor->setVerticalPos(KoShapeAnchor::VFromTop);
        anchor->setHorizontalRel(KoShapeAnchor::HPage);
        anchor->setVerticalRel(KoShapeAnchor::VPage);
        shape->setAnchor(anchor);
        shape->setPosition(pos);
        shape->scale(0.2, 0.2);

        //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
        KoSelection *selection = d->canvas->shapeManager()->selection();
        selection->deselectAll();
        selection->select(shape);
        //        d->canvas->addCommand(cmd);
        d->canvas->shapeManager()->addShape(shape);

        d->notes->addEntry("", imageUrl, "Neutral", shape);
    }
}

void CQTextDocumentCanvas::addNote(const QString &text, const QString &color, const QString &imageUrl)
{
    QSvgRenderer renderer(QUrl(imageUrl).toLocalFile());

    // Prepare a QImage with desired characteritisc
    QImage image(400, 200, QImage::Format_ARGB32);
    image.fill(Qt::transparent);

    // Get QPainter that paints to the image
    QPainter painter(&image);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.setRenderHint(QPainter::TextAntialiasing, true);

    renderer.render(&painter, image.rect());

    QFont font;
    font.setFamily("Permanent Marker");
    font.setStyle(QFont::StyleNormal);
    font.setPixelSize(40);
    painter.setPen(QPen(QColor(color), 0));
    painter.setFont(font);
    painter.drawText(image.rect().adjusted(10, 10, -20, -20), Qt::AlignCenter | Qt::TextWordWrap, text);
    painter.end();

    KoProperties *params = new KoProperties();
    params->setProperty("qimage", image);
    KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get("PictureShape");
    if (factory) {
        KoShape *shape = factory->createShape(params, d->document->resourceManager());

        QPointF pos = d->canvas->viewToDocument(d->canvas->documentOffset() + QPointF(d->canvas->size().width() / 2, d->canvas->size().height() / 2));
        KoShapeAnchor *anchor = new KoShapeAnchor(shape);
        anchor->setAnchorType(KoShapeAnchor::AnchorPage);
        anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
        anchor->setVerticalPos(KoShapeAnchor::VFromTop);
        anchor->setHorizontalRel(KoShapeAnchor::HPage);
        anchor->setVerticalRel(KoShapeAnchor::VPage);
        shape->setAnchor(anchor);
        shape->setPosition(pos);
        shape->rotate(-15);
        shape->scale(0.3, 0.3);

        //        KWShapeCreateCommand *cmd = new KWShapeCreateCommand(d->document, shape);
        KoSelection *selection = d->canvas->shapeManager()->selection();
        selection->deselectAll();
        selection->select(shape);
        //        d->canvas->addCommand(cmd);
        d->canvas->shapeManager()->addShape(shape);

        d->notes->addEntry(text, "", color, shape);
    }
}

void CQTextDocumentCanvas::setCameraY(int cameraY)
{
    d->currentPoint.setY(cameraY);
    Q_EMIT cameraYChanged();
}

void CQTextDocumentCanvas::alignTopWith(int y)
{
    d->currentPoint.setY(y);
    Q_EMIT cameraYChanged();
}

int CQTextDocumentCanvas::currentPageNumber() const
{
    if (d->document && !d->throttleTimer->isActive()) {
        // Can't use this at the moment, we sort of don't have the right one, because derp :P
        // d->canvas->resourceManager()->resource(KoCanvasResourceManager::CurrentPage).toInt();
        d->throttleTimer->start();
        const KWDocument *kwDoc = static_cast<const KWDocument *>(d->document);
        d->pageNumber = kwDoc->pageManager()->page(d->canvas->viewMode()->viewToDocument(d->canvas->documentOffset(), d->canvas->viewConverter())).pageNumber();
    }
    return d->pageNumber;
}

void CQTextDocumentCanvas::setCurrentPageNumber(const int &currentPageNumber)
{
    if (d->pageNumber != currentPageNumber) {
        gotoPage(currentPageNumber, d->document);
    }
}

void CQTextDocumentCanvas::render(QPainter *painter, const QRectF &target)
{
    Q_UNUSED(target)
    QStyleOptionGraphicsItem option;
    option.exposedRect = QRect(0, 0, width(), height());
    option.rect = option.exposedRect.toAlignedRect();
    d->canvas->canvasItem()->paint(painter, &option);
}

bool CQTextDocumentCanvas::event(QEvent *event)
{
    switch (static_cast<int>(event->type())) {
    case ViewModeSwitchEvent::AboutToSwitchViewModeEvent: {
        ViewModeSynchronisationObject *syncObject = static_cast<ViewModeSwitchEvent *>(event)->synchronisationObject();

        if (d->canvas) {
            syncObject->documentOffset = d->canvas->documentOffset();
            syncObject->zoomLevel = zoomController()->zoomAction()->effectiveZoom();
            syncObject->activeToolId = KoToolManager::instance()->activeToolId();
            syncObject->shapes = d->canvas->shapeManager()->shapes();
            syncObject->initialized = true;
        }

        return true;
    }
    case ViewModeSwitchEvent::SwitchedToTouchModeEvent: {
        ViewModeSynchronisationObject *syncObject = static_cast<ViewModeSwitchEvent *>(event)->synchronisationObject();

        if (d->canvas && syncObject->initialized) {
            d->canvas->shapeManager()->setShapes(syncObject->shapes);

            KoToolManager::instance()->switchToolRequested("PageToolFactory_ID");
            qApp->processEvents();

            zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, syncObject->zoomLevel);

            qApp->processEvents();
            Q_EMIT positionShouldChange(syncObject->documentOffset);
        }

        return true;
    }
        //         case KisTabletEvent::TabletPressEx:
        //         case KisTabletEvent::TabletReleaseEx:
        //             Q_EMIT interactionStarted();
        //             d->canvas->inputManager()->eventFilter(this, event);
        //             return true;
        //         case KisTabletEvent::TabletMoveEx:
        //             d->tabletEventCount++; //Note that this will wraparound at some point; This is intentional.
        // #ifdef Q_OS_X11
        //             if (d->tabletEventCount % 2 == 0)
        // #endif
        //                 d->canvas->inputManager()->eventFilter(this, event);
        //             return true;
    default:
        break;
    }
    return QQuickPaintedItem::event(event);
}

void CQTextDocumentCanvas::currentToolChanged(KoCanvasController *controller, int uniqueToolId)
{
    Q_UNUSED(controller)
    Q_UNUSED(uniqueToolId)
    d->currentTool = qobject_cast<KoToolBase *>(KoToolManager::instance()->toolById(d->canvas, KoToolManager::instance()->activeToolId()));
}

void CQTextDocumentCanvas::mouseDoubleClickEvent(QMouseEvent *e)
{
    QMouseEvent me(e->type(), e->position(), e->button(), e->buttons(), e->modifiers());
    KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
    d->currentTool->mouseDoubleClickEvent(&pe);
    updateCanvas();
    Q_EMIT selectionChanged();
    e->setAccepted(me.isAccepted());
}

void CQTextDocumentCanvas::mouseMoveEvent(QMouseEvent *e)
{
    QMouseEvent me(e->type(), e->position(), e->button(), e->buttons(), e->modifiers());
    KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
    d->currentTool->mouseMoveEvent(&pe);
    updateCanvas();
    Q_EMIT selectionChanged();
    e->setAccepted(me.isAccepted());
}

void CQTextDocumentCanvas::mousePressEvent(QMouseEvent *e)
{
    QMouseEvent me(e->type(), e->position(), e->button(), e->buttons(), e->modifiers());
    KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
    d->currentTool->mousePressEvent(&pe);
    updateCanvas();
    Q_EMIT selectionChanged();
    e->setAccepted(me.isAccepted());
}

void CQTextDocumentCanvas::mouseReleaseEvent(QMouseEvent *e)
{
    QMouseEvent me(e->type(), e->position(), e->button(), e->buttons(), e->modifiers());
    KoPointerEvent pe(&me, d->canvas->viewToDocument(e->pos() + d->canvas->documentOffset()));
    d->currentTool->mouseReleaseEvent(&pe);
    updateCanvas();
    Q_EMIT selectionChanged();
    e->setAccepted(me.isAccepted());
}

void CQTextDocumentCanvas::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
{
    if (d->canvas) {
        QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(d->canvas);
        if (widget) {
            widget->setGeometry(newGeometry);
        }
    }
    QQuickPaintedItem::geometryChange(newGeometry, oldGeometry);
}

void CQTextDocumentCanvas::createAndSetCanvasControllerOn(KoCanvasBase *canvas)
{
    // TODO: pass a proper action collection
    CQCanvasController *controller = new CQCanvasController(new KActionCollection(this));
    setCanvasController(controller);
    connect(controller, SIGNAL(documentSizeChanged(QSize)), SLOT(updateDocumentSize(QSize)));
    controller->setCanvas(canvas);
    KoToolManager::instance()->addController(controller);
}

void CQTextDocumentCanvas::createAndSetZoomController(KoCanvasBase *canvas)
{
    KoZoomHandler *zoomHandler = static_cast<KoZoomHandler *>(canvas->viewConverter());
    setZoomController(new KoZoomController(canvasController(), zoomHandler, new KActionCollection(this)));

    KWCanvasItem *kwCanvasItem = static_cast<KWCanvasItem *>(canvas);
    connect(kwCanvasItem, SIGNAL(documentSize(QSizeF)), zoomController(), SLOT(setDocumentSize(QSizeF)));
    connect(canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SIGNAL(currentPageNumberChanged()));
    connect(canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), kwCanvasItem, SLOT(setDocumentOffset(QPoint)));
    connect(zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode, qreal)), SIGNAL(zoomActionChanged()));
    kwCanvasItem->updateSize();
    Q_EMIT zoomActionChanged();
}

void CQTextDocumentCanvas::updateZoomControllerAccordingToDocument(const KoDocument *document)
{
    const KWDocument *kwDoc = static_cast<const KWDocument *>(document);
    zoomController()->setPageSize(kwDoc->pageManager()->begin().rect().size());
}

QString CQTextDocumentCanvas::searchTerm() const
{
    return d->searchTerm;
}

void CQTextDocumentCanvas::setSearchTerm(const QString &term)
{
    d->searchTerm = term;
    if (!term.isEmpty()) {
        d->findText->find(term);
    }
    Q_EMIT searchTermChanged();
}

void CQTextDocumentCanvas::findMatchFound(const KoFindMatch &match)
{
    QTextCursor cursor = match.location().value<QTextCursor>();
    d->canvas->canvasItem()->update();

    d->canvas->resourceManager()->setResource(KoText::CurrentTextAnchor, cursor.anchor());
    d->canvas->resourceManager()->setResource(KoText::CurrentTextPosition, cursor.position());
}

void CQTextDocumentCanvas::findNoMatchFound()
{
    qDebug() << "Match for " << d->searchTerm << " not found";
}

void CQTextDocumentCanvas::updateCanvas()
{
    KWCanvasItem *kwCanvasItem = dynamic_cast<KWCanvasItem *>(d->canvas);
    kwCanvasItem->update();
}

void CQTextDocumentCanvas::findNext()
{
    d->findText->findNext();
}

void CQTextDocumentCanvas::findPrevious()
{
    d->findText->findPrevious();
}

QObject *CQTextDocumentCanvas::documentModel() const
{
    return d->documentModel;
}

KWDocument *CQTextDocumentCanvas::document() const
{
    return d->document;
}

QObject *CQTextDocumentCanvas::doc() const
{
    return d->document;
}

QObject *CQTextDocumentCanvas::part() const
{
    return d->part;
}

QObjectList CQTextDocumentCanvas::linkTargets() const
{
    return d->linkTargets;
}

QSize CQTextDocumentCanvas::documentSize() const
{
    return d->documentSize;
}

void CQTextDocumentCanvas::updateDocumentSize(const QSize &size)
{
    d->documentSize = size;
    Q_EMIT documentSizeChanged();
}
