/* This file is part of the KDE project
 * SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net>
 * SPDX-FileCopyrightText: 2008 Fredy Yanardi <fyanardi@gmail.com>
 *
 * SPDX-License-Identifier: LGPL-2.0-or-later
 */

#include "KoPADocumentModel.h"

#include "KoPADocument.h"
#include "KoPAPageBase.h"
#include <KoCanvasBase.h>
#include <KoCanvasController.h>
#include <KoDrag.h>
#include <KoIcon.h>
#include <KoPAOdfPageSaveHelper.h>
#include <KoPAPastePage.h>
#include <KoPageLayout.h>
#include <KoSelection.h>
#include <KoShapeContainer.h>
#include <KoShapeGroup.h>
#include <KoShapeGroupCommand.h>
#include <KoShapeLayer.h>
#include <KoShapeManager.h>
#include <KoShapePainter.h>
#include <KoShapeRenameCommand.h>
#include <KoShapeUngroupCommand.h>
#include <KoToolManager.h>
#include <KoZoomHandler.h>

#include <KLocalizedString>
#include <PageAppDebug.h>

#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <QMimeData>
#include <QPainterPath>

#include "commands/KoPAPageMoveCommand.h"

KoPADocumentModel::KoPADocumentModel(QObject *parent, KoPADocument *document)
    : KoDocumentSectionModel(parent)
    , m_document(nullptr)
    , m_master(false)
    , m_lastContainer(nullptr)
{
    setDocument(document);
}

Qt::DropActions KoPADocumentModel::supportedDragActions() const
{
    return Qt::MoveAction;
}

void KoPADocumentModel::update()
{
    Q_EMIT layoutAboutToBeChanged();
    Q_EMIT layoutChanged();
    if (m_document) {
        dataChanged(index(0, 0), index(m_document->pageCount() - 1, columnCount() - 1));
    }
}

int KoPADocumentModel::rowCount(const QModelIndex &parent) const
{
    if (!m_document) {
        return 0;
    }

    // check if parent is root node
    if (!parent.isValid()) {
        return m_document->pages(m_master).count();
    }

    Q_ASSERT(parent.model() == this);
    Q_ASSERT(parent.internalPointer());

    KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer *>((KoShape *)parent.internalPointer());
    if (!parentShape) {
        return 0;
    }

    return parentShape->shapeCount();
}

int KoPADocumentModel::columnCount(const QModelIndex &) const
{
    return 1;
}

QModelIndex KoPADocumentModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!m_document) {
        return QModelIndex();
    }

    // check if parent is root node
    if (!parent.isValid()) {
        if (row >= 0 && row < m_document->pages(m_master).count()) {
            return createIndex(row, column, m_document->pages(m_master).at(row));
        } else {
            return QModelIndex();
        }
    }

    Q_ASSERT(parent.model() == this);
    Q_ASSERT(parent.internalPointer());

    KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer *>((KoShape *)parent.internalPointer());
    if (!parentShape) {
        return QModelIndex();
    }

    if (row < parentShape->shapeCount()) {
        return createIndex(row, column, childFromIndex(parentShape, row));
    } else {
        return QModelIndex();
    }
}

QModelIndex KoPADocumentModel::parent(const QModelIndex &child) const
{
    // check if child is root node
    if (!child.isValid() || !m_document) {
        return QModelIndex();
    }

    Q_ASSERT(child.model() == this);
    Q_ASSERT(child.internalPointer());

    KoShape *childShape = static_cast<KoShape *>(child.internalPointer());
    if (!childShape) {
        return QModelIndex();
    }

    // get the children's parent shape
    KoShapeContainer *parentShape = childShape->parent();
    if (!parentShape) {
        return QModelIndex();
    }

    // get the grandparent to determine the row of the parent shape
    KoShapeContainer *grandParentShape = parentShape->parent();
    if (!grandParentShape) {
        KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(parentShape);
        return createIndex(m_document->pages(m_master).indexOf(page), 0, parentShape);
    }

    return createIndex(indexFromChild(grandParentShape, parentShape), 0, parentShape);
}

QVariant KoPADocumentModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || !m_document) {
        return QVariant();
    }

    Q_ASSERT(index.model() == this);
    Q_ASSERT(index.internalPointer());

    KoShape *shape = static_cast<KoShape *>(index.internalPointer());

    switch (role) {
    case Qt::DisplayRole: {
        QString name = shape->name();
        if (name.isEmpty()) {
            if (dynamic_cast<KoPAPageBase *>(shape)) {
                if (m_document->pageType() == KoPageApp::Slide) {
                    name = i18n("Slide %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1);
                } else {
                    name = i18n("Page  %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1);
                }
            } else if (dynamic_cast<KoShapeLayer *>(shape)) {
                name = i18n("Layer") + QString(" (%1)").arg(shape->zIndex());
            } else if (dynamic_cast<KoShapeGroup *>(shape)) {
                name = i18n("Group") + QString(" (%1)").arg(shape->zIndex());
            } else {
                name = i18n("Shape") + QString(" (%1)").arg(shape->zIndex());
            }
        }
        return name;
    }
    case Qt::DecorationRole:
        return QVariant(); // return shape->icon();
    case Qt::EditRole:
        return shape->name();
    case Qt::SizeHintRole: {
        auto page = dynamic_cast<KoPAPageBase *>(shape);
        if (page) { // return actual page size for page
            KoPageLayout layout = page->pageLayout();
            return QSize((int)layout.width, (int)layout.height);
        }
        return shape->size();
    }
    case ActiveRole: {
        KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
        KoSelection *selection = canvasController->canvas()->shapeManager()->selection();
        if (!selection) {
            return false;
        }

        /* KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape );
        if ( layer )
            return (layer == selection->activeLayer() );
        else */
        return selection->isSelected(shape);
    }
    case PropertiesRole:
        return QVariant::fromValue(properties(shape));
    case AspectRatioRole: {
        QTransform matrix = shape->absoluteTransformation(nullptr);
        QRectF bbox = matrix.mapRect(shape->outline().boundingRect());
        auto container = dynamic_cast<KoShapeContainer *>(shape);
        if (container) {
            bbox = QRectF();
            const auto shapes = container->shapes();
            for (KoShape *shape : shapes) {
                bbox = bbox.united(shape->outline().boundingRect());
            }
        }
        return qreal(bbox.width()) / bbox.height();
    }
    default:
        if (role >= int(BeginThumbnailRole)) {
            return createThumbnail(shape, QSize(role - int(BeginThumbnailRole), role - int(BeginThumbnailRole)));
        } else {
            return QVariant();
        }
    }
}

Qt::ItemFlags KoPADocumentModel::flags(const QModelIndex &index) const
{
    if (!m_document) {
        return {};
    }

    if (!index.isValid()) {
        return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
    }

    Q_ASSERT(index.model() == this);
    Q_ASSERT(index.internalPointer());

    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable;
    // if ( dynamic_cast<KoShapeContainer*>( (KoShape*)index.internalPointer() ) )
    flags |= Qt::ItemIsDropEnabled;
    return flags;
}

bool KoPADocumentModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || !m_document) {
        return false;
    }

    Q_ASSERT(index.model() == this);
    Q_ASSERT(index.internalPointer());

    auto shape = static_cast<KoShape *>(index.internalPointer());
    switch (role) {
    case Qt::DisplayRole:
    case Qt::EditRole: {
        KUndo2Command *cmd = new KoShapeRenameCommand(shape, value.toString());
        if (dynamic_cast<KoPAPageBase *>(shape)) {
            if (m_document->pageType() == KoPageApp::Slide) {
                cmd->setText(kundo2_i18n("Rename Slide"));
            } else {
                cmd->setText(kundo2_i18n("Rename Page"));
            }
        } else if (dynamic_cast<KoShapeLayer *>(shape)) {
            cmd->setText(kundo2_i18n("Rename Layer"));
        }
        m_document->addCommand(cmd);
    } break;
    case PropertiesRole:
        setProperties(shape, value.value<PropertyList>());
        break;
    case ActiveRole:
        /* if (value.toBool())
        {
            KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController();
            KoSelection * selection = canvasController->canvas()->shapeManager()->selection();

            KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape );
            if ( layer && selection ) {
                selection->setActiveLayer( layer );
            }
        } */
        break;
    default:
        return false;
    }

    Q_EMIT dataChanged(index, index);
    return true;
}

KoDocumentSectionModel::PropertyList KoPADocumentModel::properties(KoShape *shape) const
{
    PropertyList l;

    if (auto page = dynamic_cast<KoPAPageBase *>(shape)) {
        // The idea is to display the page-number so users know what page-number/slide-number
        // the shape has also in the case the slide has a name (in which case it's not named
        // "Slide [slide-number]" any longer.
        // Maybe we should better use KoTextPage::visiblePageNumber here?
        l << Property(i18n("Slide"), QString::number(m_document->pageIndex(page) + 1));
    }

    l << Property(i18n("Visible"), koIcon("layer-visible-on"), koIcon("layer-visible-off"), shape->isVisible());
    l << Property(i18n("Locked"), koIcon("object-locked"), koIcon("object-unlocked"), shape->isGeometryProtected());
    return l;
}

void KoPADocumentModel::setProperties(KoShape *shape, const PropertyList &properties)
{
    bool oldVisibleState = shape->isVisible();
    bool oldLockedState = shape->isGeometryProtected();

    shape->setVisible(properties.at(0).state.toBool());
    shape->setGeometryProtected(properties.at(1).state.toBool());

    if ((oldVisibleState != shape->isVisible()) || (oldLockedState != shape->isGeometryProtected())) {
        shape->update();
    }
}

QImage KoPADocumentModel::createThumbnail(KoShape *shape, const QSize &thumbSize) const
{
    QSize size(thumbSize.width(), thumbSize.height());
    KoShapePainter shapePainter;

    KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(shape);
    if (page) { // We create a thumbnail with actual width / height ratio for page
        KoZoomHandler zoomHandler;
        KoPageLayout layout = page->pageLayout();
        qreal ratio = (zoomHandler.resolutionX() * layout.width) / (zoomHandler.resolutionY() * layout.height);
        if (ratio > 1) {
            size.setHeight(size.width() / ratio);
        } else {
            size.setWidth(size.height() * ratio);
        }
        QPixmap pixmap = m_document->pageThumbnail(page, size);
        return pixmap.toImage();
    }

    QList<KoShape *> shapes;
    KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(shape);
    if (container) {
        shapes = container->shapes();
    }
    shapes.append(shape);

    shapePainter.setShapes(shapes);

    QImage thumb(size, QImage::Format_RGB32);
    // draw the background of the thumbnail
    thumb.fill(QColor(Qt::white).rgb());
    shapePainter.paint(thumb);

    return thumb;
}

KoShape *KoPADocumentModel::childFromIndex(KoShapeContainer *parent, int row) const
{
    return parent->shapes().at(row);
}

int KoPADocumentModel::indexFromChild(KoShapeContainer *parent, KoShape *child) const
{
    if (!m_document) {
        return 0;
    }

    return parent->shapes().indexOf(child);
}

Qt::DropActions KoPADocumentModel::supportedDropActions() const
{
    return Qt::MoveAction | Qt::CopyAction;
}

QStringList KoPADocumentModel::mimeTypes() const
{
    QStringList types;
    types << QLatin1String("application/x-kopalayermodeldatalist");
    return types;
}

QMimeData *KoPADocumentModel::mimeData(const QModelIndexList &indexes) const
{
    // check if there is data to encode
    if (!indexes.count()) {
        return nullptr;
    }

    // check if we support a format
    QStringList types = mimeTypes();
    if (types.isEmpty()) {
        return nullptr;
    }

    QMimeData *data = new QMimeData();
    QString format = types[0];
    QByteArray encoded;
    QDataStream stream(&encoded, QIODevice::WriteOnly);

    // encode the data
    QModelIndexList::ConstIterator it = indexes.begin();
    for (; it != indexes.end(); ++it) {
        stream << QVariant::fromValue(qulonglong(it->internalPointer()));
    }

    data->setData(format, encoded);
    return data;
}

bool KoPADocumentModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    Q_UNUSED(row);
    Q_UNUSED(column);

    // check if the action is supported
    if (!data || action != Qt::MoveAction) {
        return false;
    }
    // check if the format is supported
    QStringList types = mimeTypes();
    if (types.isEmpty()) {
        return false;
    }
    QString format = types[0];
    if (!data->hasFormat(format)) {
        return false;
    }

    QByteArray encoded = data->data(format);
    QDataStream stream(&encoded, QIODevice::ReadOnly);
    QList<KoShape *> shapes;

    // decode the data
    while (!stream.atEnd()) {
        QVariant v;
        stream >> v;
        shapes.append(static_cast<KoShape *>((void *)v.value<qulonglong>()));
    }

    QList<KoShape *> toplevelShapes;
    QList<KoShapeLayer *> layers;
    QList<KoPAPageBase *> pages;
    // remove shapes having its parent in the list
    // and separate the layers
    foreach (KoShape *shape, shapes) {
        // check whether the selection contains page
        // by the UI rules, the selection should contains page only
        KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(shape);
        if (page) {
            pages.append(page);
            continue;
        }

        KoShapeContainer *parentShape = shape->parent();
        bool hasParentInList = false;
        while (parentShape) {
            if (shapes.contains(parentShape)) {
                hasParentInList = true;
                break;
            }
            parentShape = parentShape->parent();
        }
        if (hasParentInList) {
            continue;
        }

        KoShapeLayer *layer = dynamic_cast<KoShapeLayer *>(shape);
        if (layer) {
            layers.append(layer);
        } else {
            toplevelShapes.append(shape);
        }
    }

    // dropping to root, only page(s) is allowed
    if (!parent.isValid()) {
        if (!pages.isEmpty()) {
            if (row < 0) {
                return false;
            }
            KoPAPageBase *after = (row != 0) ? m_document->pageByIndex(row - 1, false) : nullptr;
            debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping page(s) as root, moving page(s)";
            return doDrop(pages, after, action);
        } else {
            debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping non-page as root, returning false";
            return false;
        }
    } else if (parent.isValid() && !pages.isEmpty()) {
        if (parent.row() < 0) {
            return false;
        }
        KoPAPageBase *after;
        if ((m_document->pageIndex(pages.first()) - 1) == parent.row()) {
            after = (parent.row() != 0) ? m_document->pageByIndex(parent.row() - 1, false) : nullptr;
        } else {
            after = (parent.row() > -1) ? m_document->pageByIndex(parent.row(), false) : nullptr;
        }
        return doDrop(pages, after, action);
    }

    KoShape *shape = static_cast<KoShape *>(parent.internalPointer());
    KoShapeContainer *container = dynamic_cast<KoShapeContainer *>(shape);
    if (container) {
        KoShapeGroup *group = dynamic_cast<KoShapeGroup *>(container);
        if (group) {
            debugPageApp << "KoPADocumentModel::dropMimeData parent = group";
            if (!toplevelShapes.count()) {
                return false;
            }

            Q_EMIT layoutAboutToBeChanged();
            beginInsertRows(parent, group->shapeCount(), group->shapeCount() + toplevelShapes.count());

            KUndo2Command *cmd = new KUndo2Command();
            cmd->setText(kundo2_i18n("Reparent shapes"));

            foreach (KoShape *shape, toplevelShapes) {
                new KoShapeUngroupCommand(shape->parent(), QList<KoShape *>() << shape, QList<KoShape *>(), cmd);
            }

            new KoShapeGroupCommand(group, toplevelShapes, cmd);
            KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
            canvasController->canvas()->addCommand(cmd);

            endInsertRows();
            Q_EMIT layoutChanged();
        } else {
            debugPageApp << "KoPADocumentModel::dropMimeData parent = container";
            if (toplevelShapes.count()) {
                Q_EMIT layoutAboutToBeChanged();
                beginInsertRows(parent, container->shapeCount(), container->shapeCount() + toplevelShapes.count());

                KUndo2Command *cmd = new KUndo2Command();
                cmd->setText(kundo2_i18n("Reparent shapes"));

                QList<bool> clipped;
                QList<bool> inheritsTransform;
                foreach (KoShape *shape, toplevelShapes) {
                    if (!shape->parent()) {
                        clipped.append(false);
                        inheritsTransform.append(false);
                        continue;
                    }

                    clipped.append(shape->parent()->isClipped(shape));
                    inheritsTransform.append(shape->parent()->inheritsTransform(shape));
                    new KoShapeUngroupCommand(shape->parent(), QList<KoShape *>() << shape, QList<KoShape *>(), cmd);
                }
                // shapes are dropped on a container, so add them to the container
                new KoShapeGroupCommand(container, toplevelShapes, clipped, inheritsTransform, cmd);
                KoCanvasController *canvasController = KoToolManager::instance()->activeCanvasController();
                canvasController->canvas()->addCommand(cmd);

                endInsertRows();
                Q_EMIT layoutChanged();
            } else if (layers.count()) {
                KoShapeLayer *layer = dynamic_cast<KoShapeLayer *>(container);
                if (!layer) {
                    return false;
                }

                // TODO layers are dropped on a layer, so change layer ordering
                return false;
            }
        }
    } else {
        debugPageApp << "KoPADocumentModel::dropMimeData parent = shape";
        if (!toplevelShapes.count()) {
            return false;
        }

        // TODO shapes are dropped on a shape, reorder them
        return false;
    }

    return true;
}

QModelIndex KoPADocumentModel::parentIndexFromShape(const KoShape *child)
{
    if (!m_document) {
        return QModelIndex();
    }

    // check if child shape is a layer, and return invalid model index if it is
    const KoShapeLayer *childlayer = dynamic_cast<const KoShapeLayer *>(child);
    if (childlayer) {
        return QModelIndex();
    }

    // get the children's parent shape
    KoShapeContainer *parentShape = child->parent();
    if (!parentShape) {
        return QModelIndex();
    }

    // check if the parent is a layer
    KoShapeLayer *parentLayer = dynamic_cast<KoShapeLayer *>(parentShape);

    if (parentLayer) {
        KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(parentLayer->parent());
        if (page) {
            return createIndex(m_document->pages(m_master).count() - 1 - m_document->pages(m_master).indexOf(page), 0, parentLayer);
        }
    }
    // get the grandparent to determine the row of the parent shape
    KoShapeContainer *grandParentShape = parentShape->parent();
    if (!grandParentShape) {
        return QModelIndex();
    }

    return createIndex(indexFromChild(grandParentShape, parentShape), 0, parentShape);
}

void KoPADocumentModel::setDocument(KoPADocument *document)
{
    if (m_document == document) {
        return;
    }

    if (m_document) {
        disconnect(m_document, &KoPADocument::pageAdded, this, &KoPADocumentModel::update);
        disconnect(m_document, QOverload<KoPAPageBase *, int>::of(&KoPADocument::pageRemoved), this, &KoPADocumentModel::update);
        disconnect(m_document, &KoPADocument::update, this, &KoPADocumentModel::update);
        disconnect(m_document, &KoPADocument::shapeAdded, this, &KoPADocumentModel::update);
        disconnect(m_document, &KoPADocument::shapeRemoved, this, &KoPADocumentModel::update);
    }

    beginResetModel();
    m_document = document;
    endResetModel();

    if (m_document) {
        connect(m_document, &KoPADocument::pageAdded, this, &KoPADocumentModel::update);
        connect(m_document, QOverload<KoPAPageBase *, int>::of(&KoPADocument::pageRemoved), this, &KoPADocumentModel::update);
        connect(m_document, &KoPADocument::update, this, &KoPADocumentModel::update);
        connect(m_document, &KoPADocument::shapeAdded, this, &KoPADocumentModel::update);
        connect(m_document, &KoPADocument::shapeRemoved, this, &KoPADocumentModel::update);
    }
}

void KoPADocumentModel::setMasterMode(bool master)
{
    m_master = master;
    update(); // Rebuild the model
}

bool KoPADocumentModel::doDrop(QList<KoPAPageBase *> pages, KoPAPageBase *pageAfter, Qt::DropAction action)
{
    Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
    bool enableMove = true;

    foreach (KoPAPageBase *page, pages) {
        if (!m_document->pages(false).contains(page)) {
            KoPAPageBase *newPage = page;
            pages.replace(pages.indexOf(page), newPage);
            enableMove = false;
            break;
        }
    }

    if (((modifiers & Qt::ControlModifier) == 0) && ((modifiers & Qt::ShiftModifier) == 0)) {
        QMenu popup;
        QString seq = QKeySequence(Qt::ShiftModifier).toString();
        seq.chop(1);
        QAction *popupMoveAction = new QAction(i18n("&Move Here") + '\t' + seq, this);
        popupMoveAction->setIcon(koIconFallback("edit-move", "go-jump"));
        seq = QKeySequence(Qt::ControlModifier).toString();
        seq.chop(1);
        QAction *popupCopyAction = new QAction(i18n("&Copy Here") + '\t' + seq, this);
        popupCopyAction->setIcon(koIcon("edit-copy"));
        seq = QKeySequence(Qt::ControlModifier | Qt::ShiftModifier).toString();
        seq.chop(1);
        QAction *popupCancelAction = new QAction(i18n("C&ancel") + '\t' + QKeySequence(Qt::Key_Escape).toString(), this);
        popupCancelAction->setIcon(koIcon("process-stop"));

        if (enableMove) {
            popup.addAction(popupMoveAction);
        }
        popup.addAction(popupCopyAction);
        popup.addSeparator();
        popup.addAction(popupCancelAction);

        QAction *result = popup.exec(QCursor::pos());

        if (result == popupCopyAction) {
            action = Qt::CopyAction;
        } else if (result == popupMoveAction) {
            action = Qt::MoveAction;
        } else {
            return false;
        }
    } else if ((modifiers & Qt::ControlModifier) != 0) {
        action = Qt::CopyAction;
    } else if ((modifiers & Qt::ShiftModifier) != 0) {
        action = Qt::MoveAction;
    } else {
        return false;
    }

    switch (action) {
    case Qt::MoveAction: {
        KoPAPageMoveCommand *command = new KoPAPageMoveCommand(m_document, pages, pageAfter);
        m_document->addCommand(command);
        if ((m_document->pageIndex(pageAfter) + pages.count()) < m_document->pageCount()) {
            Q_EMIT requestPageSelection(m_document->pageIndex(pageAfter) + 1, pages.count());
        }
        return true;
    }
    case Qt::CopyAction: {
        // Copy Pages
        KoPAOdfPageSaveHelper saveHelper(m_document, pages);
        KoDrag drag;
        drag.setOdf(KoOdf::mimeType(m_document->documentType()), saveHelper);
        drag.addToClipboard();
        // Paste Pages
        const QMimeData *data = QApplication::clipboard()->mimeData();
        static const KoOdf::DocumentType documentTypes[] = {KoOdf::Graphics, KoOdf::Presentation};

        for (unsigned int i = 0; i < sizeof(documentTypes) / sizeof(KoOdf::DocumentType); ++i) {
            if (data->hasFormat(KoOdf::mimeType(documentTypes[i]))) {
                KoPAPastePage paste(m_document, pageAfter);
                paste.paste(documentTypes[i], data);
                break;
            }
        }
        Q_EMIT requestPageSelection(m_document->pageIndex(pageAfter) + 1, sizeof(documentTypes) / sizeof(KoOdf::DocumentType) - 1);
        return true;
    }
    default:
        qDebug("Unknown action: %d ", (int)action);
        return false;
    }
    return false;
}
