[calligra/progress-bar-reincarnated-kazakov] krita: Added an ability to cancel the currently running strokes!

Dmitry Kazakov dimula73 at gmail.com
Wed Jun 4 20:15:33 UTC 2014


Git commit 71c69adb0e900f9f1bf00778b5fbc6281259fd4a by Dmitry Kazakov.
Committed on 04/06/2014 at 20:15.
Pushed by dkazakov into branch 'progress-bar-reincarnated-kazakov'.

Added an ability to cancel the currently running strokes!

You can either press Esc key or press a red cross button which appears
near the progress bar in the bottom. The currently executing stroke will
be cancelled and all its work will be reverted.

This patch will first go to 'progress-bar-reincarnated-kazakov' branch.
Please test it for stability and usability please!

CCBUG:252071
CCMAIL:kimageshop at kde.org

M  +14   -1    krita/image/kis_image.cc
M  +7    -5    krita/image/kis_image.h
M  +12   -11   krita/image/kis_queues_progress_updater.cpp
M  +0    -1    krita/image/kis_queues_progress_updater.h
M  +5    -0    krita/image/kis_stroke.cpp
M  +1    -0    krita/image/kis_stroke_job.h
M  +28   -0    krita/image/kis_strokes_queue.cpp
M  +2    -0    krita/image/kis_strokes_queue.h
M  +10   -9    krita/image/kis_update_scheduler.cpp
M  +14   -1    krita/image/kis_update_scheduler.h
M  +7    -8    krita/image/tests/kis_queues_progress_updater_test.cpp
M  +36   -0    krita/image/tests/kis_stroke_test.cpp
M  +1    -0    krita/image/tests/kis_stroke_test.h
M  +29   -0    krita/image/tests/kis_strokes_queue_test.cpp
M  +1    -0    krita/image/tests/kis_strokes_queue_test.h
M  +37   -2    krita/image/tests/scheduler_utils.h
M  +2    -0    krita/ui/kis_view2.cpp
M  +2    -23   krita/ui/widgets/kis_progress_widget.cpp
M  +3    -0    krita/ui/widgets/kis_progress_widget.h

http://commits.kde.org/calligra/71c69adb0e900f9f1bf00778b5fbc6281259fd4a

diff --git a/krita/image/kis_image.cc b/krita/image/kis_image.cc
index 9265627..b3a22fc 100644
--- a/krita/image/kis_image.cc
+++ b/krita/image/kis_image.cc
@@ -131,6 +131,8 @@ public:
     KisCompositeProgressProxy *compositeProgressProxy;
 
     bool startProjection;
+
+    bool tryCancelCurrentStrokeAsync();
 };
 
 KisImage::KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace, const QString& name, bool startProjection)
@@ -1462,6 +1464,15 @@ bool KisImage::cancelStroke(KisStrokeId id)
     return result;
 }
 
+bool KisImage::KisImagePrivate::tryCancelCurrentStrokeAsync()
+{
+    bool result = false;
+    if (scheduler) {
+        result = scheduler->tryCancelCurrentStrokeAsync();
+    }
+    return result;
+}
+
 void KisImage::requestUndoDuringStroke()
 {
     emit sigUndoDuringStrokeRequested();
@@ -1469,7 +1480,9 @@ void KisImage::requestUndoDuringStroke()
 
 void KisImage::requestStrokeCancellation()
 {
-    emit sigStrokeCancellationRequested();
+    if (!m_d->tryCancelCurrentStrokeAsync()) {
+        emit sigStrokeCancellationRequested();
+    }
 }
 
 void KisImage::requestStrokeEnd()
diff --git a/krita/image/kis_image.h b/krita/image/kis_image.h
index 86e0b37..23f91de 100644
--- a/krita/image/kis_image.h
+++ b/krita/image/kis_image.h
@@ -745,11 +745,13 @@ public slots:
     void requestUndoDuringStroke();
 
     /**
-     * This method is called by the UI (*not* by the creator
-     * of the stroke) when it thinks current stroke should be
-     * cancelled. If the creator of the stroke supports cancelling
-     * of the stroke, it will be notified about the request and
-     * the stroke will be cancelled
+     * This method is called by the UI (*not* by the creator of the
+     * stroke) when it thinks current stroke should be cancelled. If
+     * there is a running stroke that has already been detached from
+     * its creator (ended or cancelled), it will be forcefully
+     * cancelled and reverted. If there is an open stroke present, and
+     * if its creator supports cancelling, it will be notified about
+     * the request and the stroke will be cancelled
      */
     void requestStrokeCancellation();
 
diff --git a/krita/image/kis_queues_progress_updater.cpp b/krita/image/kis_queues_progress_updater.cpp
index ebed9d3..cb5e4ae 100644
--- a/krita/image/kis_queues_progress_updater.cpp
+++ b/krita/image/kis_queues_progress_updater.cpp
@@ -37,8 +37,8 @@ struct KisQueuesProgressUpdater::Private
     QMutex mutex;
     QTimer timer;
 
-    QAtomicInt doneSizeMetric;
     int queueSizeMetric;
+    int initialQueueSizeMetric;
 
     QString jobName;
 
@@ -66,16 +66,17 @@ KisQueuesProgressUpdater::~KisQueuesProgressUpdater()
     delete m_d;
 }
 
-void KisQueuesProgressUpdater::notifyJobDone(int sizeMetric)
-{
-    m_d->doneSizeMetric.fetchAndAddOrdered(sizeMetric);
-}
-
 void KisQueuesProgressUpdater::updateProgress(int queueSizeMetric, const QString &jobName)
 {
     QMutexLocker locker(&m_d->mutex);
     m_d->queueSizeMetric = queueSizeMetric;
-    m_d->jobName = jobName;
+
+    if (jobName != m_d->jobName ||
+        m_d->queueSizeMetric > m_d->initialQueueSizeMetric) {
+
+        m_d->jobName = jobName;
+        m_d->initialQueueSizeMetric = m_d->queueSizeMetric;
+    }
 
     if(m_d->queueSizeMetric && !m_d->timer.isActive()) {
         m_d->trackingStarted = true;
@@ -85,7 +86,7 @@ void KisQueuesProgressUpdater::updateProgress(int queueSizeMetric, const QString
     else if(!m_d->queueSizeMetric && !m_d->timerFiredOnce) {
             m_d->trackingStarted = false;
             m_d->timer.stop();
-            m_d->doneSizeMetric = 0;
+            m_d->initialQueueSizeMetric = 0;
     }
 }
 
@@ -112,12 +113,12 @@ void KisQueuesProgressUpdater::updateProxy()
     if(!m_d->trackingStarted) return;
     m_d->timerFiredOnce = true;
 
-    m_d->progressProxy->setRange(0, m_d->doneSizeMetric + m_d->queueSizeMetric);
-    m_d->progressProxy->setValue(m_d->doneSizeMetric);
+    m_d->progressProxy->setRange(0, m_d->initialQueueSizeMetric);
+    m_d->progressProxy->setValue(m_d->initialQueueSizeMetric - m_d->queueSizeMetric);
     m_d->progressProxy->setFormat(m_d->jobName);
 
     if(!m_d->queueSizeMetric) {
         m_d->timer.stop();
-        m_d->doneSizeMetric = 0;
+        m_d->initialQueueSizeMetric = 0;
     }
 }
diff --git a/krita/image/kis_queues_progress_updater.h b/krita/image/kis_queues_progress_updater.h
index f5db54b..c0f9119 100644
--- a/krita/image/kis_queues_progress_updater.h
+++ b/krita/image/kis_queues_progress_updater.h
@@ -33,7 +33,6 @@ public:
     KisQueuesProgressUpdater(KoProgressProxy *progressProxy);
     ~KisQueuesProgressUpdater();
 
-    void notifyJobDone(int sizeMetric);
     void updateProgress(int queueSizeMetric, const QString &jobName);
     void hide();
 
diff --git a/krita/image/kis_stroke.cpp b/krita/image/kis_stroke.cpp
index 339f76c..8577a69 100644
--- a/krita/image/kis_stroke.cpp
+++ b/krita/image/kis_stroke.cpp
@@ -109,10 +109,15 @@ void KisStroke::endStroke()
  *    the cancel job
  * 4) Initialized, no jobs, finished -- it's too late to cancel
  *    anything
+ * 6) Initialized, has jobs, cancelled -- cancelling twice is a permitted
+ *                                        operation, though it does nothing
  */
 
 void KisStroke::cancelStroke()
 {
+    // case 6
+    if (m_isCancelled) return;
+
     if(!m_strokeInitialized) {
         clearQueue();
     }
diff --git a/krita/image/kis_stroke_job.h b/krita/image/kis_stroke_job.h
index 91d459b..eb975fe 100644
--- a/krita/image/kis_stroke_job.h
+++ b/krita/image/kis_stroke_job.h
@@ -59,6 +59,7 @@ private:
     // for testing use only, do not use in real code
     friend QString getJobName(KisStrokeJob *job);
     friend QString getCommandName(KisStrokeJob *job);
+    friend int cancelSeqNo(KisStrokeJob *job);
 
     KisStrokeJobStrategy* testingGetDabStrategy() {
         return m_dabStrategy;
diff --git a/krita/image/kis_strokes_queue.cpp b/krita/image/kis_strokes_queue.cpp
index 389af61..73ec915 100644
--- a/krita/image/kis_strokes_queue.cpp
+++ b/krita/image/kis_strokes_queue.cpp
@@ -95,6 +95,34 @@ bool KisStrokesQueue::cancelStroke(KisStrokeId id)
     return stroke;
 }
 
+bool KisStrokesQueue::tryCancelCurrentStrokeAsync()
+{
+    bool anythingCanceled = false;
+
+    QMutexLocker locker(&m_d->mutex);
+
+    if (!m_d->strokesQueue.isEmpty()) {
+        KisStrokeSP currentStroke = m_d->strokesQueue.head();
+
+        /**
+         * We cancel only ended strokes. This is done to avoid
+         * handling dangling pointers problem (KisStrokeId). The owner
+         * of a stroke will cancel the stroke itself if needed.
+         */
+        if (currentStroke->isEnded()) {
+            currentStroke->cancelStroke();
+            anythingCanceled = true;
+        }
+    }
+
+    /**
+     * NOTE: We do not touch the openedStrokesCounter here since
+     *       we work with closed id's only here
+     */
+
+    return anythingCanceled;
+}
+
 void KisStrokesQueue::processQueue(KisUpdaterContext &updaterContext,
                                    bool externalJobsPending)
 {
diff --git a/krita/image/kis_strokes_queue.h b/krita/image/kis_strokes_queue.h
index e4fae61..db23518 100644
--- a/krita/image/kis_strokes_queue.h
+++ b/krita/image/kis_strokes_queue.h
@@ -39,6 +39,8 @@ public:
     void endStroke(KisStrokeId id);
     bool cancelStroke(KisStrokeId id);
 
+    bool tryCancelCurrentStrokeAsync();
+
     void processQueue(KisUpdaterContext &updaterContext, bool externalJobsPending);
     bool needsExclusiveAccess() const;
     bool isEmpty() const;
diff --git a/krita/image/kis_update_scheduler.cpp b/krita/image/kis_update_scheduler.cpp
index 4a56e44..7af21e4 100644
--- a/krita/image/kis_update_scheduler.cpp
+++ b/krita/image/kis_update_scheduler.cpp
@@ -118,7 +118,11 @@ void KisUpdateScheduler::progressUpdate()
             jobName = "Update";
         }
 
-        int sizeMetric = m_d->strokesQueue->sizeMetric() + m_d->updatesQueue->sizeMetric();
+        int sizeMetric = m_d->strokesQueue->sizeMetric();
+        if (!sizeMetric) {
+            sizeMetric = m_d->updatesQueue->sizeMetric();
+        }
+
         m_d->progressUpdater->updateProgress(sizeMetric, jobName);
     }
     else {
@@ -126,13 +130,6 @@ void KisUpdateScheduler::progressUpdate()
     }
 }
 
-void KisUpdateScheduler::progressNotifyJobDone()
-{
-    if(m_d->progressUpdater) {
-        m_d->progressUpdater->notifyJobDone(1);
-    }
-}
-
 void KisUpdateScheduler::updateProjection(KisNodeSP node, const QRect& rc, const QRect &cropRect)
 {
     m_d->updatesQueue->addUpdateJob(node, rc, cropRect);
@@ -202,6 +199,11 @@ bool KisUpdateScheduler::cancelStroke(KisStrokeId id)
     return result;
 }
 
+bool KisUpdateScheduler::tryCancelCurrentStrokeAsync()
+{
+    return m_d->strokesQueue->tryCancelCurrentStrokeAsync();
+}
+
 bool KisUpdateScheduler::wrapAroundModeSupported() const
 {
     return m_d->strokesQueue->wrapAroundModeSupported();
@@ -350,7 +352,6 @@ void KisUpdateScheduler::doSomeUsefulWork()
 
 void KisUpdateScheduler::spareThreadAppeared()
 {
-    progressNotifyJobDone();
     processQueues();
 }
 
diff --git a/krita/image/kis_update_scheduler.h b/krita/image/kis_update_scheduler.h
index 332af5a..c04b838 100644
--- a/krita/image/kis_update_scheduler.h
+++ b/krita/image/kis_update_scheduler.h
@@ -130,6 +130,20 @@ public:
     void endStroke(KisStrokeId id);
     bool cancelStroke(KisStrokeId id);
 
+    /**
+     * tryCancelCurrentStrokeAsync() checks whether there is a
+     * *running* stroke (which is being executed at this very moment)
+     * which is not still open by the owner (endStroke() or
+     * cancelStroke() have already been called) and cancels it.
+     *
+     * \return true if some stroke has been found and cancelled
+     *
+     * \note This method is *not* part of KisStrokesFacade! It is too
+     *       low level for KisImage.  In KisImage it is combined with
+     *       more high level requestStrokeCancellation().
+     */
+    bool tryCancelCurrentStrokeAsync();
+
     bool wrapAroundModeSupported() const;
 
 protected:
@@ -150,7 +164,6 @@ private:
     void wakeUpWaitingThreads();
 
     void progressUpdate();
-    void progressNotifyJobDone();
 
 protected:
     struct Private;
diff --git a/krita/image/tests/kis_queues_progress_updater_test.cpp b/krita/image/tests/kis_queues_progress_updater_test.cpp
index 986ad11..f69ba33 100644
--- a/krita/image/tests/kis_queues_progress_updater_test.cpp
+++ b/krita/image/tests/kis_queues_progress_updater_test.cpp
@@ -29,8 +29,8 @@ void KisQueuesProgressUpdaterTest::testSlowProgress()
     TestUtil::TestProgressBar progressProxy;
     KisQueuesProgressUpdater updater(&progressProxy);
 
-    updater.notifyJobDone(100);
     updater.updateProgress(200, "test task");
+    updater.updateProgress(100, "test task");
 
     QTest::qWait(100);
 
@@ -42,18 +42,17 @@ void KisQueuesProgressUpdaterTest::testSlowProgress()
     QTest::qWait(500);
 
     QCOMPARE(progressProxy.min(), 0);
-    QCOMPARE(progressProxy.max(), 300);
+    QCOMPARE(progressProxy.max(), 200);
     QCOMPARE(progressProxy.value(), 100);
     QCOMPARE(progressProxy.format(), QString("test task"));
 
-    updater.notifyJobDone(200);
     updater.updateProgress(0, "test task");
 
     QTest::qWait(500);
 
     QCOMPARE(progressProxy.min(), 0);
-    QCOMPARE(progressProxy.max(), 300);
-    QCOMPARE(progressProxy.value(), 300);
+    QCOMPARE(progressProxy.max(), 200);
+    QCOMPARE(progressProxy.value(), 200);
     QCOMPARE(progressProxy.format(), QString("test task"));
 }
 
@@ -66,8 +65,8 @@ void KisQueuesProgressUpdaterTest::testFastProgress()
     TestUtil::TestProgressBar progressProxy;
     KisQueuesProgressUpdater updater(&progressProxy);
 
-    updater.notifyJobDone(100);
     updater.updateProgress(200, "test task");
+    updater.updateProgress(0, "test task");
 
     QTest::qWait(20);
 
@@ -76,8 +75,8 @@ void KisQueuesProgressUpdaterTest::testFastProgress()
     QCOMPARE(progressProxy.value(), 0);
     QCOMPARE(progressProxy.format(), QString());
 
-    updater.notifyJobDone(100);
     updater.updateProgress(100, "test task");
+    updater.updateProgress(0, "test task");
 
     QTest::qWait(20);
 
@@ -86,7 +85,7 @@ void KisQueuesProgressUpdaterTest::testFastProgress()
     QCOMPARE(progressProxy.value(), 0);
     QCOMPARE(progressProxy.format(), QString());
 
-    updater.notifyJobDone(100);
+    updater.updateProgress(0, "test task");
     updater.updateProgress(0, "test task");
 
     QTest::qWait(20);
diff --git a/krita/image/tests/kis_stroke_test.cpp b/krita/image/tests/kis_stroke_test.cpp
index 2e2decd..2324a96 100644
--- a/krita/image/tests/kis_stroke_test.cpp
+++ b/krita/image/tests/kis_stroke_test.cpp
@@ -154,5 +154,41 @@ void KisStrokeTest::testCancelStrokeCase4()
     QCOMPARE(stroke.isEnded(), true);
 }
 
+void KisStrokeTest::testCancelStrokeCase6()
+{
+    KisStroke stroke(new KisTestingStrokeStrategy());
+    QQueue<KisStrokeJob*> &queue = stroke.testingGetQueue();
+
+    stroke.addJob(0);
+    delete stroke.popOneJob();
+
+    // "initialized, has jobs"
+
+    QCOMPARE(queue.size(), 1);
+    SCOMPARE(getJobName(queue[0]), "dab");
+    QCOMPARE(stroke.isEnded(), false);
+
+    // "cancelled"
+
+    stroke.cancelStroke();
+
+    QCOMPARE(queue.size(), 1);
+    SCOMPARE(getJobName(queue[0]), "cancel");
+    QCOMPARE(stroke.isEnded(), true);
+
+    int seqNo = cancelSeqNo(queue.head());
+
+    // try cancel once more...
+
+    stroke.cancelStroke();
+
+    QCOMPARE(queue.size(), 1);
+    SCOMPARE(getJobName(queue[0]), "cancel");
+    QCOMPARE(stroke.isEnded(), true);
+    QCOMPARE(cancelSeqNo(queue.head()), seqNo);
+
+    stroke.clearQueue();
+}
+
 QTEST_KDEMAIN(KisStrokeTest, NoGUI)
 #include "kis_stroke_test.moc"
diff --git a/krita/image/tests/kis_stroke_test.h b/krita/image/tests/kis_stroke_test.h
index 44d2d05..496ede4 100644
--- a/krita/image/tests/kis_stroke_test.h
+++ b/krita/image/tests/kis_stroke_test.h
@@ -32,6 +32,7 @@ private slots:
     void testCancelStrokeCase2and3();
     void testCancelStrokeCase5();
     void testCancelStrokeCase4();
+    void testCancelStrokeCase6();
 };
 
 #endif /* __KIS_STROKE_TEST_H */
diff --git a/krita/image/tests/kis_strokes_queue_test.cpp b/krita/image/tests/kis_strokes_queue_test.cpp
index 11cb5c0..22062ff 100644
--- a/krita/image/tests/kis_strokes_queue_test.cpp
+++ b/krita/image/tests/kis_strokes_queue_test.cpp
@@ -338,5 +338,34 @@ void KisStrokesQueueTest::testOpenedStrokeCounter()
     queue.processQueue(context, false); context.clear();
 }
 
+void KisStrokesQueueTest::testAsyncCancelWhileOpenedStroke()
+{
+    KisStrokesQueue queue;
+    KisStrokeId id = queue.startStroke(new KisTestingStrokeStrategy("nor_", false));
+    queue.addJob(id, 0);
+    queue.addJob(id, 0);
+    queue.addJob(id, 0);
+
+    // no async cancelling until the stroke is ended by the owner
+    QVERIFY(!queue.tryCancelCurrentStrokeAsync());
+
+    queue.endStroke(id);
+
+    QVERIFY(queue.tryCancelCurrentStrokeAsync());
+
+    bool externalJobsPending = false;
+
+    KisTestableUpdaterContext context(3);
+    QVector<KisUpdateJobItem*> jobs;
+
+    queue.processQueue(context, externalJobsPending);
+
+    // no? really?
+    jobs = context.getJobs();
+    VERIFY_EMPTY(jobs[0]);
+    VERIFY_EMPTY(jobs[1]);
+    VERIFY_EMPTY(jobs[2]);
+}
+
 QTEST_KDEMAIN(KisStrokesQueueTest, NoGUI)
 #include "kis_strokes_queue_test.moc"
diff --git a/krita/image/tests/kis_strokes_queue_test.h b/krita/image/tests/kis_strokes_queue_test.h
index b7fdfb3..a805fe2 100644
--- a/krita/image/tests/kis_strokes_queue_test.h
+++ b/krita/image/tests/kis_strokes_queue_test.h
@@ -34,6 +34,7 @@ private slots:
     void testStrokesOverlapping();
     void testImmediateCancel();
     void testOpenedStrokeCounter();
+    void testAsyncCancelWhileOpenedStroke();
 };
 
 #endif /* __KIS_STROKES_QUEUE_TEST_H */
diff --git a/krita/image/tests/scheduler_utils.h b/krita/image/tests/scheduler_utils.h
index 8d72a53..7a6f31d 100644
--- a/krita/image/tests/scheduler_utils.h
+++ b/krita/image/tests/scheduler_utils.h
@@ -80,7 +80,8 @@ class KisNoopDabStrategy : public KisStrokeJobStrategy
 {
 public:
 KisNoopDabStrategy(QString name)
-        : m_name(name)
+    : m_name(name),
+      m_isMarked(false)
     {}
 
     void run(KisStrokeJobData *data) {
@@ -91,8 +92,17 @@ KisNoopDabStrategy(QString name)
         return m_name;
     }
 
+    void setMarked() {
+        m_isMarked = true;
+    }
+
+    bool isMarked() const {
+        return m_isMarked;
+    }
+
 private:
     QString m_name;
+    bool m_isMarked;
 };
 
 class KisTestingStrokeStrategy : public KisStrokeStrategy
@@ -102,7 +112,8 @@ public:
                              bool exclusive = false,
                              bool inhibitServiceJobs = false)
         : m_prefix(prefix),
-          m_inhibitServiceJobs(inhibitServiceJobs)
+          m_inhibitServiceJobs(inhibitServiceJobs),
+          m_cancelSeqNo(0)
     {
         setExclusive(exclusive);
     }
@@ -126,9 +137,24 @@ public:
         return new KisNoopDabStrategy(m_prefix + "dab");
     }
 
+    class CancelData : public KisStrokeJobData
+    {
+    public:
+        CancelData(int seqNo) : m_seqNo(seqNo) {}
+        int seqNo() const { return m_seqNo; }
+
+    private:
+        int m_seqNo;
+    };
+
+    KisStrokeJobData* createCancelData() {
+        return new CancelData(m_cancelSeqNo++);
+    }
+
 private:
     QString m_prefix;
     bool m_inhibitServiceJobs;
+    int m_cancelSeqNo;
 };
 
 inline QString getJobName(KisStrokeJob *job) {
@@ -139,4 +165,13 @@ inline QString getJobName(KisStrokeJob *job) {
     return pointer->name();
 }
 
+inline int cancelSeqNo(KisStrokeJob *job) {
+    KisTestingStrokeStrategy::CancelData *pointer =
+        dynamic_cast<KisTestingStrokeStrategy::CancelData*>
+        (job->testingGetDabData());
+    Q_ASSERT(pointer);
+
+    return pointer->seqNo();
+}
+
 #endif /* __SCHEDULER_UTILS_H */
diff --git a/krita/ui/kis_view2.cpp b/krita/ui/kis_view2.cpp
index 38722d9..6797296 100644
--- a/krita/ui/kis_view2.cpp
+++ b/krita/ui/kis_view2.cpp
@@ -909,6 +909,8 @@ void KisView2::slotLoadingFinished()
      * of displaying the status of the global strokes queue
      */
     image()->compositeProgressProxy()->addProxy(m_d->statusBar->progress()->progressProxy());
+    connect(m_d->statusBar->progress(), SIGNAL(sigCancellationRequested()),
+            image(), SLOT(requestStrokeCancellation()));
 
     m_d->canvas->initializeImage();
 
diff --git a/krita/ui/widgets/kis_progress_widget.cpp b/krita/ui/widgets/kis_progress_widget.cpp
index 8b3b3a8..e6cf62c 100644
--- a/krita/ui/widgets/kis_progress_widget.cpp
+++ b/krita/ui/widgets/kis_progress_widget.cpp
@@ -31,32 +31,11 @@
 
 #include <kis_progress_updater.h>
 
-class EscapeButton : public QToolButton
-{
-
-public:
-
-    EscapeButton(QWidget* parent)
-            : QToolButton(parent) {
-    }
-
-    void keyReleaseEvent(QKeyEvent *e) {
-        /**
-         * FIXME: this shotcut doesn't work, because it is
-         * overridden somewhere
-         */
-        if (e->key() == Qt::Key_Escape) {
-            emit clicked();
-        }
-    }
-
-};
-
 KisProgressWidget::KisProgressWidget(QWidget* parent)
         : QWidget(parent)
 {
     QHBoxLayout* layout = new QHBoxLayout(this);
-    m_cancelButton = new EscapeButton(this);
+    m_cancelButton = new QToolButton(this);
     m_cancelButton->setIcon(koIcon("process-stop"));
 
     QSizePolicy sizePolicy = m_cancelButton->sizePolicy();
@@ -80,7 +59,6 @@ KisProgressWidget::KisProgressWidget(QWidget* parent)
 
 KisProgressWidget::~KisProgressWidget()
 {
-    cancel();
 }
 
 KoProgressProxy* KisProgressWidget::progressProxy()
@@ -93,6 +71,7 @@ void KisProgressWidget::cancel()
     foreach(KoProgressUpdater* updater, m_activeUpdaters) {
         updater->cancel();
     }
+    emit sigCancellationRequested();
 }
 
 void KisProgressWidget::correctVisibility(int progressValue)
diff --git a/krita/ui/widgets/kis_progress_widget.h b/krita/ui/widgets/kis_progress_widget.h
index 09e3e81..9f77df4 100644
--- a/krita/ui/widgets/kis_progress_widget.h
+++ b/krita/ui/widgets/kis_progress_widget.h
@@ -64,6 +64,9 @@ public slots:
     void cancel();
     void correctVisibility(int progressValue);
 
+signals:
+    void sigCancellationRequested();
+
 private:
 
     QToolButton* m_cancelButton;


More information about the kimageshop mailing list