void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view)
{
    KisNodeSP node = view->activeNode();
    if (!node || !node->hasEditablePaintDevice()) return;

    KisSelectionSP selection = view->selection();
    QRect selectedRect = selection ?
                         selection->selectedRect() : view->image()->bounds();
    Q_UNUSED(selectedRect);
    KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice();
    Q_UNUSED(filled);
    bool usePattern = false;
    bool useBgColor = false;

    if (fillSource.contains("pattern")) {
        usePattern = true;
    } else if (fillSource.contains("bg")) {
        useBgColor = true;
    }

    KisProcessingApplicator applicator(view->image(), node,
                                       KisProcessingApplicator::NONE,
                                       KisImageSignalVector() << ModifiedSignal,
                                       kundo2_i18n("Flood Fill Layer"));

    KisResourcesSnapshotSP resources =
        new KisResourcesSnapshot(view->image(), node, 0, view->resourceProvider()->resourceManager());
    if (!fillSource.contains("opacity")) {
        resources->setOpacity(1.0);
    }

    KisProcessingVisitorSP visitor =
        new FillProcessingVisitor(QPoint(0, 0), // start position
                                  selection,
                                  resources,
                                  false, // fast mode
                                  usePattern,
                                  true, // fill only selection,
                                  0, // feathering radius
                                  0, // sizemod
                                  80, // threshold,
                                  false, // unmerged
                                  useBgColor);

    applicator.applyVisitor(visitor,
                            KisStrokeJobData::SEQUENTIAL,
                            KisStrokeJobData::EXCLUSIVE);

    applicator.end();
}
void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view)
{
    KisImageSP image = view->image();
    if (!image) return;

    bool haveShapesSelected = view->selectionManager()->haveShapesSelected();

    if (haveShapesSelected) {
        // XXX: "Add saving of XML data for Cut/Copy of shapes"

        KisImageBarrierLocker locker(image);
        if (willCut) {
            view->canvasBase()->toolProxy()->cut();
        } else {
            view->canvasBase()->toolProxy()->copy();
        }
    } else {
        KisNodeSP node = view->activeNode();
        if (!node) return;

        KisSelectionSP selection = view->selection();
        if (selection.isNull()) return;

        {
            KisImageBarrierLocker locker(image);
            KisPaintDeviceSP dev = node->paintDevice();
            if (!dev) {
                dev = node->projection();
            }

            if (!dev) {
                view->showFloatingMessage(
                    i18nc("floating message when cannot copy from a node",
                          "Cannot copy pixels from this type of layer "),
                    QIcon(), 3000, KisFloatingMessage::Medium);

                return;
            }

            if (dev->exactBounds().isEmpty()) {
                view->showFloatingMessage(
                    i18nc("floating message when copying empty selection",
                          "Selection is empty: no pixels were copied "),
                    QIcon(), 3000, KisFloatingMessage::Medium);

                return;
            }

            ActionHelper::copyFromDevice(view, dev, makeSharpClip);
        }

        if (willCut) {
            KUndo2Command *command = 0;

            if (willCut && node->hasEditablePaintDevice()) {
                struct ClearSelection : public KisTransactionBasedCommand {
                    ClearSelection(KisNodeSP node, KisSelectionSP sel)
                        : m_node(node), m_sel(sel) {}
                    KisNodeSP m_node;
                    KisSelectionSP m_sel;

                    KUndo2Command* paint() {
                        KisSelectionSP cutSelection = m_sel;
                        // Shrinking the cutting area was previously used
                        // for getting seamless cut-paste. Now we use makeSharpClip
                        // instead.
                        // QRect originalRect = cutSelection->selectedExactRect();
                        // static const int preciseSelectionThreshold = 16;
                        //
                        // if (originalRect.width() > preciseSelectionThreshold ||
                        //     originalRect.height() > preciseSelectionThreshold) {
                        //     cutSelection = new KisSelection(*m_sel);
                        //     delete cutSelection->flatten();
                        //
                        //     KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false);
                        //
                        //     QRect processingRect = filter->changeRect(originalRect);
                        //     filter->process(cutSelection->pixelSelection(), processingRect);
                        // }

                        KisTransaction transaction(m_node->paintDevice());
                        m_node->paintDevice()->clearSelection(cutSelection);
                        m_node->setDirty(cutSelection->selectedRect());
                        return transaction.endAndTake();
                    }
                };

                command = new ClearSelection(node, selection);
            }

            KUndo2MagicString actionName = willCut ?
                                           kundo2_i18n("Cut") :
                                           kundo2_i18n("Copy");
            KisProcessingApplicator *ap = beginAction(view, actionName);

            if (command) {
                ap->applyCommand(command,
                                 KisStrokeJobData::SEQUENTIAL,
                                 KisStrokeJobData::NORMAL);
            }

            KisOperationConfiguration config(id());
            config.setProperty("will-cut", willCut);
            endAction(ap, config.toXML());
        }
    }
}