/*
   SPDX-FileCopyrightText: 2003-2007 Clarence Dang <dang@kde.org>
   SPDX-FileCopyrightText: 2011 Martin Koller <kollix@aon.at>

   SPDX-License-Identifier: BSD-2-Clause
*/

#include "kpMainWindow.h"
#include "kpMainWindowPrivate.h"

#include <QApplication>
#include <QClipboard>
#include <QFontMetrics>
#include <QImage>
#include <QList>
#include <QMenu>
#include <QScreen>
#include <QScrollBar>

#include "kpLogCategories.h"
#include <KActionCollection>
#include <KLocalizedString>
#include <KMessageBox>
#include <KStandardAction>
#include <KXMLGUIFactory>

#include "commands/imagelib/transforms/kpTransformResizeScaleCommand.h"
#include "commands/kpCommandHistory.h"
#include "commands/kpMacroCommand.h"
#include "commands/tools/selection/kpToolSelectionCreateCommand.h"
#include "commands/tools/selection/kpToolSelectionDestroyCommand.h"
#include "commands/tools/selection/text/kpToolTextEnterCommand.h"
#include "commands/tools/selection/text/kpToolTextGiveContentCommand.h"
#include "commands/tools/selection/text/kpToolTextInsertCommand.h"
#include "document/kpDocument.h"
#include "document/kpDocumentSaveOptions.h"
#include "generic/kpSetOverrideCursorSaver.h"
#include "imagelib/kpDocumentMetaInfo.h"
#include "imagelib/transforms/kpTransformCrop.h"
#include "kpViewScrollableContainer.h"
#include "layers/selections/image/kpAbstractImageSelection.h"
#include "layers/selections/image/kpImageSelectionTransparency.h"
#include "layers/selections/image/kpRectangularImageSelection.h"
#include "layers/selections/kpSelectionDrag.h"
#include "layers/selections/text/kpTextSelection.h"
#include "pixmapfx/kpPixmapFX.h"
#include "tools/kpTool.h"
#include "views/kpZoomedView.h"
#include "views/manager/kpViewManager.h"
#include "widgets/toolbars/kpColorToolBar.h"

//---------------------------------------------------------------------

// private
void kpMainWindow::setupEditMenuActions()
{
    KActionCollection *ac = actionCollection();

    // Undo/Redo
    // CONFIG: Need GUI for config history size.
    d->commandHistory = new kpCommandHistory(true /*read config*/, this);

    if (d->configFirstTime) {
        // (so that cfg-file-editing user can modify in the meantime)
        d->commandHistory->writeConfig();
    }

    d->actionCut = KStandardAction::cut(this, SLOT(slotCut()), ac);
    d->actionCopy = KStandardAction::copy(this, SLOT(slotCopy()), ac);
    d->actionPaste = KStandardAction::paste(this, SLOT(slotPaste()), ac);
    d->actionPasteInNewWindow = ac->addAction(QStringLiteral("edit_paste_in_new_window"));
    d->actionPasteInNewWindow->setText(i18n("Paste in &New Window"));
    connect(d->actionPasteInNewWindow, &QAction::triggered, this, &kpMainWindow::slotPasteInNewWindow);
    ac->setDefaultShortcut(d->actionPasteInNewWindow, Qt::CTRL | Qt::SHIFT | Qt::Key_V);

    // d->actionDelete = KStandardAction::clear (this, SLOT (slotDelete()), ac);
    d->actionDelete = ac->addAction(QStringLiteral("edit_clear"));
    d->actionDelete->setText(i18n("&Delete Selection"));
    connect(d->actionDelete, &QAction::triggered, this, &kpMainWindow::slotDelete);

    d->actionSelectAll = KStandardAction::selectAll(this, SLOT(slotSelectAll()), ac);
    d->actionDeselect = KStandardAction::deselect(this, SLOT(slotDeselect()), ac);

    d->actionCopyToFile = ac->addAction(QStringLiteral("edit_copy_to_file"));
    d->actionCopyToFile->setText(i18n("C&opy to File..."));
    connect(d->actionCopyToFile, &QAction::triggered, this, &kpMainWindow::slotCopyToFile);

    d->actionPasteFromFile = ac->addAction(QStringLiteral("edit_paste_from_file"));
    d->actionPasteFromFile->setText(i18n("Paste &From File..."));
    connect(d->actionPasteFromFile, &QAction::triggered, this, &kpMainWindow::slotPasteFromFile);

    d->editMenuDocumentActionsEnabled = false;
    enableEditMenuDocumentActions(false);

    // Paste should always be enabled, as long as there is something to paste
    // (independent of whether we have a document or not)
    connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &kpMainWindow::slotEnablePaste);

    slotEnablePaste();
}

//---------------------------------------------------------------------

// private
void kpMainWindow::enableEditMenuDocumentActions(bool enable)
{
    // d->actionCut
    // d->actionCopy
    // d->actionPaste
    // d->actionPasteInNewWindow

    // d->actionDelete

    d->actionSelectAll->setEnabled(enable);
    // d->actionDeselect

    d->editMenuDocumentActionsEnabled = enable;

    // d->actionCopyToFile

    // Unlike d->actionPaste, we disable this if there is no document.
    // This is because "File / Open" would do the same thing, if there is
    // no document.
    d->actionPasteFromFile->setEnabled(enable);
}

//---------------------------------------------------------------------

// public
QMenu *kpMainWindow::selectionToolRMBMenu()
{
    return qobject_cast<QMenu *>(guiFactory()->container(QStringLiteral("selectionToolRMBMenu"), this));
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotCut()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotCut() CALLED";
#endif

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    Q_ASSERT(d->document && d->document->selection());

    toolEndShape();

    slotCopy();
    slotDelete();
}

//---------------------------------------------------------------------

static QMimeData *NewTextMimeData(const QString &text)
{
    auto *md = new QMimeData();
    md->setText(text);
    return md;
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotCopy()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopy() CALLED";
#endif

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    Q_ASSERT(d->document && d->document->selection());

    toolEndShape();

    kpAbstractSelection *sel = d->document->selection()->clone();

    if (dynamic_cast<kpTextSelection *>(sel)) {
        auto *textSel = dynamic_cast<kpTextSelection *>(sel);
        if (!textSel->text().isEmpty()) {
            QApplication::clipboard()->setMimeData(::NewTextMimeData(textSel->text()), QClipboard::Clipboard);

            // SYNC: Normally, users highlight text and press CTRL+C.
            //       Highlighting text copies it to the X11 "middle
            //       mouse button" clipboard.  CTRL+C copies it to the
            //       separate, Windows-like "CTRL+V" clipboard.
            //
            //       However, KolourPaint doesn't support highlighting.
            //       So when they press CTRL+C to copy all text, simulate
            //       the highlighting by copying the text to the "middle
            //       mouse button" clipboard.  We don't do this for images
            //       as no one ever middle-mouse-pastes images.
            //
            //       Note that we don't share the QMimeData pointer with
            //       the above in case Qt doesn't expect it.
            //
            //       Once we change KolourPaint to support highlighted text
            //       and CTRL+C to copy only the highlighted text, delete
            //       this code.
            QApplication::clipboard()->setMimeData(::NewTextMimeData(textSel->text()), QClipboard::Selection);
        }
    } else if (dynamic_cast<kpAbstractImageSelection *>(sel)) {
        auto *imageSel = dynamic_cast<kpAbstractImageSelection *>(sel);

        // Transparency doesn't get sent across the aether so nuke it now
        // so that transparency mask doesn't get needlessly recalculated
        // if we ever call sel.setBaseImage().
        imageSel->setTransparency(kpImageSelectionTransparency());

        kpImage rawImage;

        if (imageSel->hasContent()) {
            rawImage = imageSel->baseImage();
        } else {
            rawImage = d->document->getSelectedBaseImage();
        }

        imageSel->setBaseImage(rawImage);

        QApplication::clipboard()->setMimeData(new kpSelectionDrag(*imageSel), QClipboard::Clipboard);
    } else {
        Q_ASSERT(!"Unknown selection type");
    }

    delete sel;
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotEnablePaste()
{
    const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Clipboard);

    // It's faster to test for QMimeData::hasText() first due to the
    // lazy evaluation of the '||' operator.
    const bool shouldEnable = md && (md->hasText() || kpSelectionDrag::canDecode(md));

    d->actionPasteInNewWindow->setEnabled(shouldEnable);
    d->actionPaste->setEnabled(shouldEnable);
}

//---------------------------------------------------------------------

// private
QRect kpMainWindow::calcUsefulPasteRect(int imageWidth, int imageHeight)
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::calcUsefulPasteRect(" << imageWidth << "," << imageHeight << ")";
#endif
    Q_ASSERT(d->document);

    // TODO: 1st choice is to paste sel near but not overlapping last deselect point

    if (d->mainView && d->scrollView) {
        const QPoint viewTopLeft(d->scrollView->horizontalScrollBar()->value(), d->scrollView->verticalScrollBar()->value());

        const QPoint docTopLeft = d->mainView->transformViewToDoc(viewTopLeft);

        if ((docTopLeft.x() + imageWidth <= d->document->width() && docTopLeft.y() + imageHeight <= d->document->height()) || imageWidth <= docTopLeft.x()
            || imageHeight <= docTopLeft.y()) {
            return {docTopLeft.x(), docTopLeft.y(), imageWidth, imageHeight};
        }
    }

    return {0, 0, imageWidth, imageHeight};
}

//---------------------------------------------------------------------

// private
void kpMainWindow::paste(const kpAbstractSelection &sel, bool forceTopLeft)
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")";
#endif

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    toolEndShape();

    //
    // Make sure we've got a document (esp. with File/Close)
    //

    if (!d->document) {
        auto *newDoc = new kpDocument(sel.width(), sel.height(), documentEnvironment());

        // will also create viewManager
        setDocument(newDoc);
    }

    //
    // Paste as new selection
    //

    const auto *imageSel = dynamic_cast<const kpAbstractImageSelection *>(&sel);

    if (imageSel && imageSel->hasContent() && imageSel->transparency().isTransparent()) {
        d->colorToolBar->flashColorSimilarityToolBarItem();
    }

    kpAbstractSelection *selInUsefulPos = sel.clone();
    if (!forceTopLeft) {
        selInUsefulPos->moveTo(calcUsefulPasteRect(sel.width(), sel.height()).topLeft());
    }
    // TODO: Should use kpCommandHistory::addCreateSelectionCommand(),
    //       as well, to really support pasting selection borders.
    addDeselectFirstCommand(
        new kpToolSelectionCreateCommand(dynamic_cast<kpTextSelection *>(selInUsefulPos) ? i18n("Text: Create Box") : i18n("Selection: Create"),
                                         *selInUsefulPos,
                                         commandEnvironment()));
    delete selInUsefulPos;

#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "sel.size=" << QSize(sel.width(), sel.height()) << " document.size=" << QSize(d->document->width(), d->document->height());
#endif

    // If the selection is bigger than the document, automatically
    // resize the document (with the option of Undo'ing) to fit
    // the selection.
    //
    // No annoying dialog necessary.
    //
    if (sel.width() > d->document->width() || sel.height() > d->document->height()) {
        d->commandHistory->addCommand(new kpTransformResizeScaleCommand(false /*act on doc, not sel*/,
                                                                        qMax(sel.width(), d->document->width()),
                                                                        qMax(sel.height(), d->document->height()),
                                                                        kpTransformResizeScaleCommand::Resize,
                                                                        commandEnvironment()));
    }
}

//---------------------------------------------------------------------

// public
void kpMainWindow::pasteText(const QString &text, bool forceNewTextSelection, const QPoint &newTextSelectionTopLeft)
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::pasteText(" << text << ",forceNewTextSelection=" << forceNewTextSelection
                             << ",newTextSelectionTopLeft=" << newTextSelectionTopLeft << ")";
#endif

    if (text.isEmpty()) {
        return;
    }

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    toolEndShape();

    const QStringList textLines = text.split(QLatin1Char('\n'));

    if (!forceNewTextSelection && d->document && d->document->textSelection() && d->commandHistory && d->viewManager) {
#if DEBUG_KP_MAIN_WINDOW && 1
        qCDebug(kpLogMainWindow) << "\treusing existing Text Selection";
#endif

        d->viewManager->setQueueUpdates();

        kpTextSelection *textSel = d->document->textSelection();
        if (!textSel->hasContent()) {
#if DEBUG_KP_MAIN_WINDOW && 1
            qCDebug(kpLogMainWindow) << "\t\tneeds content";
#endif
            commandHistory()->addCreateSelectionCommand(new kpToolSelectionCreateCommand(i18n("Text: Create Box"), *textSel, commandEnvironment()),
                                                        false /*no exec*/);
        }

        kpMacroCommand *macroCmd = new kpMacroCommand(i18n("Text: Paste"), commandEnvironment());
        // (yes, this is the same check as the previous "if")
        if (!textSel->hasContent()) {
            kpCommand *giveContentCmd = new kpToolTextGiveContentCommand(*textSel, QString() /*uninteresting child of macro cmd*/, commandEnvironment());
            giveContentCmd->execute();

            macroCmd->addCommand(giveContentCmd);
        }

        for (int i = 0; i < textLines.size(); i++) {
            if (i > 0) {
                macroCmd->addCommand(new kpToolTextEnterCommand(QString() /*uninteresting child of macroCmd*/,
                                                                d->viewManager->textCursorRow(),
                                                                d->viewManager->textCursorCol(),
                                                                kpToolTextEnterCommand::AddEnterNow,
                                                                commandEnvironment()));
            }

            macroCmd->addCommand(new kpToolTextInsertCommand(QString() /*uninteresting child of macroCmd*/,
                                                             d->viewManager->textCursorRow(),
                                                             d->viewManager->textCursorCol(),
                                                             textLines[i],
                                                             commandEnvironment()));
        }

        d->commandHistory->addCommand(macroCmd, false /*no exec*/);

        d->viewManager->restoreQueueUpdates();
    } else {
#if DEBUG_KP_MAIN_WINDOW && 1
        qCDebug(kpLogMainWindow) << "\tcreating Text Selection";
#endif

        const kpTextStyle ts = textStyle();
        const QFontMetrics fontMetrics = ts.fontMetrics();

        int height = textLines.size() * fontMetrics.height();
        if (textLines.size() >= 1) {
            height += (textLines.size() - 1) * fontMetrics.leading();
        }

        int width = 0;
        for (const QString &str : textLines)
            width = std::max(width, fontMetrics.horizontalAdvance(str));

        // limit the size to avoid memory overflow
        const QSize desktopSize = QApplication::primaryScreen()->virtualSize();
        width = qMin(qMax(desktopSize.width(), d->document ? d->document->width() : 0), width);
        height = qMin(qMax(desktopSize.height(), d->document ? d->document->height() : 0), height);

        const int selWidth = qMax(kpTextSelection::MinimumWidthForTextStyle(ts), width + kpTextSelection::TextBorderSize() * 2);
        const int selHeight = qMax(kpTextSelection::MinimumHeightForTextStyle(ts), height + kpTextSelection::TextBorderSize() * 2);
        kpTextSelection newTextSel(QRect(0, 0, selWidth, selHeight), textLines, ts);

        if (newTextSelectionTopLeft != KP_INVALID_POINT) {
            newTextSel.moveTo(newTextSelectionTopLeft);
            paste(newTextSel, true /*force topLeft*/);
        } else {
            paste(newTextSel);
        }
    }
}

//---------------------------------------------------------------------

// public
void kpMainWindow::pasteTextAt(const QString &text, const QPoint &point, bool allowNewTextSelectionPointShift)
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::pasteTextAt(" << text << ",point=" << point
                             << ",allowNewTextSelectionPointShift=" << allowNewTextSelectionPointShift << ")";
#endif

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    toolEndShape();

    if (d->document && d->document->textSelection() && d->document->textSelection()->pointIsInTextArea(point)) {
        kpTextSelection *textSel = d->document->textSelection();

        int row, col;

        if (textSel->hasContent()) {
            row = textSel->closestTextRowForPoint(point);
            col = textSel->closestTextColForPoint(point);
        } else {
            row = col = 0;
        }

        d->viewManager->setTextCursorPosition(row, col);

        pasteText(text);
    } else {
        QPoint pointToUse = point;

        if (allowNewTextSelectionPointShift) {
            // TODO: In terms of doc pixels, would be inconsistent behaviour
            //       based on zoomLevel of view.
            // pointToUse -= QPoint (-view->selectionResizeHandleAtomicSize (),
            //                       -view->selectionResizeHandleAtomicSize ());
        }

        pasteText(text, true /*force new text selection*/, pointToUse);
    }
}

//---------------------------------------------------------------------
// public slot

void kpMainWindow::slotPaste()
{
    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    toolEndShape();

    const QMimeData *mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);

    kpAbstractImageSelection *sel = kpSelectionDrag::decode(mimeData);
    if (sel) {
        sel->setTransparency(imageSelectionTransparency());
        paste(*sel);
        delete sel;
    } else if (mimeData->hasText()) {
        pasteText(mimeData->text());
    } else {
        kpSetOverrideCursorSaver cursorSaver(Qt::ArrowCursor);

        KMessageBox::error(this,
                           i18n("<qt>KolourPaint cannot paste the contents of"
                                " the clipboard as it has an unknown format.</qt>"),
                           i18n("Cannot Paste"));
    }
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotPasteInNewWindow()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteInNewWindow() CALLED";
#endif

    kpSetOverrideCursorSaver cursorSaver(Qt::WaitCursor);

    toolEndShape();

    //
    // Pasting must ensure that:
    //
    // Requirement 1. the document is the same size as the image to be pasted.
    // Requirement 2. transparent pixels in the image must remain as transparent.
    //

    auto *win = new kpMainWindow(nullptr /*no document*/);
    win->show();

    // Make "Edit / Paste in New Window" always paste white pixels as white.
    // Don't let selection transparency get in the way and paste them as
    // transparent.
    kpImageSelectionTransparency transparency = win->imageSelectionTransparency();
    if (transparency.isTransparent()) {
#if DEBUG_KP_MAIN_WINDOW && 1
        qCDebug(kpLogMainWindow) << "\tchanging image selection transparency to opaque";
#endif
        transparency.setOpaque();
        // Since we are setting selection transparency programmatically
        // -- as opposed to in response to user input -- this will not
        // affect the selection transparency tool option widget's "last used"
        // config setting.
        win->setImageSelectionTransparency(transparency);
    }

    // (this handles Requirement 1. above)
    win->slotPaste();

    // if slotPaste could not decode clipboard data, no document was created
    if (win->document()) {
        // (this handles Requirement 2. above;
        //  slotDeselect() is not enough unless the document is filled with the
        //  transparent color in advance)
        win->slotCrop();
    }
}

//---------------------------------------------------------------------

// public slot
void kpMainWindow::slotDelete()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotDelete() CALLED";
#endif
    if (!d->actionDelete->isEnabled()) {
#if DEBUG_KP_MAIN_WINDOW && 1
        qCDebug(kpLogMainWindow) << "\taction not enabled - was probably called from kpTool::keyPressEvent()";
#endif
        return;
    }

    Q_ASSERT(d->document && d->document->selection());

    toolEndShape();

    addImageOrSelectionCommand(new kpToolSelectionDestroyCommand(d->document->textSelection() ? i18n("Text: Delete Box")
                                                                                              : // not to be confused with i18n ("Text: Delete")
                                                                     i18n("Selection: Delete"),
                                                                 false /*no push onto doc*/,
                                                                 commandEnvironment()));
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotSelectAll()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotSelectAll() CALLED";
#endif
    Q_ASSERT(d->document);

    toolEndShape();

    if (d->document->selection()) {
        slotDeselect();
    }

    // just the border - don't actually pull image from doc yet
    d->document->setSelection(kpRectangularImageSelection(d->document->rect(), imageSelectionTransparency()));

    if (tool()) {
        tool()->somethingBelowTheCursorChanged();
    }
}

//---------------------------------------------------------------------

// private
void kpMainWindow::addDeselectFirstCommand(kpCommand *cmd)
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::addDeselectFirstCommand(" << cmd << ")";
#endif

    kpAbstractSelection *sel = d->document->selection();

#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "\tsel=" << sel;
#endif

    if (sel) {
        // if you just dragged out something with no action then
        // forget the drag
        if (!sel->hasContent()) {
#if DEBUG_KP_MAIN_WINDOW && 1
            qCDebug(kpLogMainWindow) << "\tjust a fresh border - was nop - delete";
#endif
            d->document->selectionDelete();
            if (tool()) {
                tool()->somethingBelowTheCursorChanged();
            }

            if (cmd) {
                d->commandHistory->addCommand(cmd);
            }
        } else {
#if DEBUG_KP_MAIN_WINDOW && 1
            qCDebug(kpLogMainWindow) << "\treal selection with image - push onto doc cmd";
#endif
            kpCommand *deselectCommand =
                new kpToolSelectionDestroyCommand(dynamic_cast<kpTextSelection *>(sel) ? i18n("Text: Finish") : i18n("Selection: Deselect"),
                                                  true /*push onto document*/,
                                                  commandEnvironment());

            if (cmd) {
                kpMacroCommand *macroCmd = new kpMacroCommand(cmd->name(), commandEnvironment());
                macroCmd->addCommand(deselectCommand);
                macroCmd->addCommand(cmd);
                d->commandHistory->addCommand(macroCmd);
            } else {
                d->commandHistory->addCommand(deselectCommand);
            }
        }
    } else {
        if (cmd) {
            d->commandHistory->addCommand(cmd);
        }
    }
}

//---------------------------------------------------------------------

// public slot
void kpMainWindow::slotDeselect()
{
#if DEBUG_KP_MAIN_WINDOW && 1
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotDeselect() CALLED";
#endif
    Q_ASSERT(d->document && d->document->selection());

    toolEndShape();

    addDeselectFirstCommand(nullptr);
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotCopyToFile()
{
#if DEBUG_KP_MAIN_WINDOW
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotCopyToFile()";
#endif

    toolEndShape();

    if (!d->document->selection()) {
        return;
    }

    kpImage imageToSave;

    if (d->document->imageSelection()) {
        kpAbstractImageSelection *imageSel = d->document->imageSelection();
        if (!imageSel->hasContent()) {
            // Not a floating selection - user has just selected a region;
            // haven't pulled it off yet so probably don't expect and can't
            // visualize selection transparency so give opaque, not transparent
            // image.
            imageToSave = d->document->getSelectedBaseImage();
        } else {
            imageToSave = imageSel->transparentImage();
        }
    } else if (d->document->textSelection()) {
        imageToSave = d->document->textSelection()->approximateImage();
    } else {
        Q_ASSERT(!"Unknown selection type");
    }

    kpDocumentSaveOptions chosenSaveOptions;
    bool allowLossyPrompt;
    QUrl chosenURL = askForSaveURL(i18nc("@title:window", "Copy to File"),
                                   d->lastCopyToURL.url(),
                                   imageToSave,
                                   d->lastCopyToSaveOptions,
                                   kpDocumentMetaInfo(),
                                   QLatin1String(kpSettingsGroupEditCopyTo),
                                   false /*allow remote files*/,
                                   &chosenSaveOptions,
                                   d->copyToFirstTime,
                                   &allowLossyPrompt);

    if (chosenURL.isEmpty()) {
        return;
    }

    if (!kpDocument::savePixmapToFile(imageToSave, chosenURL, chosenSaveOptions, kpDocumentMetaInfo(), allowLossyPrompt, this)) {
        return;
    }

    addRecentURL(chosenURL);

    d->lastCopyToURL = chosenURL;
    d->lastCopyToSaveOptions = chosenSaveOptions;

    d->copyToFirstTime = false;
}

//---------------------------------------------------------------------

// private slot
void kpMainWindow::slotPasteFromFile()
{
#if DEBUG_KP_MAIN_WINDOW
    qCDebug(kpLogMainWindow) << "kpMainWindow::slotPasteFromFile()";
#endif

    toolEndShape();

    QList<QUrl> urls = askForOpenURLs(i18nc("@title:window", "Paste From File"), false /*only 1 URL*/);

    if (urls.count() != 1) {
        return;
    }

    QUrl url = urls.first();

    kpImage image = kpDocument::getPixmapFromFile(url, false /*show error message if it doesn't exist*/, this);

    if (image.isNull()) {
        return;
    }

    addRecentURL(url);

    paste(kpRectangularImageSelection(QRect(0, 0, image.width(), image.height()), image, imageSelectionTransparency()));
}

//---------------------------------------------------------------------
