Git commit 2b1c8bec0fd1ff6b929eca638264d0649270af5f by Nathaniel Graham.
Committed on 11/02/2018 at 21:25.
Pushed by ngraham into branch 'master'.

(3/3) add option to quit after save or copy operations

Summary:
Part 3 of 3 for {T7841}

FEATURE: 389773
FIXED-IN: KDE Applications 18.04

We add a checkbox visible on the main UI to quit Spectacle after save or copy 
operations. This yields the following benefits:
- We can remove the "Save & Exit" item from the split button
- Users gain the ability to have spectacle quit after copying the image to the 
clipboard

I tried to make the feature apply to Export operations as well, but that proved 
to be much more complicated and I decided to abandon that for now and do it 
later in a subsequent patch.

Test Plan:
{F5691970}

Tested in KDE Neon:
- With "Quit after Copy or Save" unchecked:
-- Save: image is saved
-- Save As: file save dialog shown, image is saved
-- Copy to Clipboard: message is shown, image is copied to clipboard

- With "Quit after Copy or Save" checked:
-- Save: notification shown, Spectacle quits, image is saved
-- Save As: file save dialog shown, notification shown, Spectacle quits, image 
is saved
-- Copy to Clipboard: image is copied to clipboard (if Klipper is set up to 
accept images), Spectacle quits

Reviewers: #spectacle, rkflx

Reviewed By: rkflx

Subscribers: rkflx

Differential Revision: https://phabricator.kde.org/D10301

M  +11   -8    doc/index.docbook
M  +7    -1    src/ExportManager.cpp
M  +1    -1    src/ExportManager.h
M  +28   -20   src/Gui/KSMainWindow.cpp
M  +0    -1    src/Gui/KSMainWindow.h
M  +8    -5    src/Gui/KSWidget.cpp
M  +1    -0    src/Gui/KSWidget.h
M  +13   -0    src/SpectacleConfig.cpp
M  +3    -0    src/SpectacleConfig.h

https://commits.kde.org/spectacle/2b1c8bec0fd1ff6b929eca638264d0649270af5f

diff --git a/doc/index.docbook b/doc/index.docbook
index 946485f..f0630c3 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -115,7 +115,7 @@
 
                <para>To save a screenshot to the default location, click on 
the arrow portion of the <guibutton>Save As...</guibutton> button and press the 
<guimenuitem>Save </guimenuitem> (<keycombo 
action="simul">&Ctrl;<keycap>S</keycap></keycombo>) button. The new save mode 
will be remembered for next time; this behavior can be configured in 
Spectacle's settings. The default save location and filename can also be 
configured there, as described later.</para>
 
-               <para>To quickly save the image and quit &spectacle;, click on 
the arrow portion of the <guibutton>Save As...</guibutton> button and press the 
<guimenuitem>Save &amp; Exit</guimenuitem> (<keycombo 
action="simul">&Ctrl;<keycap>Q</keycap></keycombo>) item. This saves the image 
as a PNG file in your default Pictures folder, and exits the application 
immediately. As above, this new save mode will be remembered.</para>
+               <para>To quickly save the image and quit &spectacle;, click on 
the checkbox beside <guilabel>Quit after Save or Copy</guilabel>, then click 
the arrow portion of the <guibutton>Save As...</guibutton> button and press the 
<guimenuitem>Save</guimenuitem> (<keycombo 
action="simul">&Ctrl;<keycap>S</keycap></keycombo>) item. This saves the image 
as a PNG file in your default Pictures folder, and exits the application 
immediately. As above, this new save mode will be remembered.</para>
 
                <sect1 id="taking-screenshot">
                        <title>Taking A Screenshot</title>
@@ -146,7 +146,7 @@
                                        <listitem>
                                                <para>The <guilabel>Window 
Under Cursor</guilabel> option takes a screenshot of the window that is under 
the mouse cursor. If the cursor is on top of a popup menu, &spectacle; tries to 
take a screenshot of the menu as well as its parent window.</para>
 
-                                               <para>While this works most of 
the time, in certain cases it may fail to obtain information about the parent 
window. In this case, &spectacle; falls back to old way of capturing the image 
automatically, and captures an image of only the popup menu. You can also force 
the old way of capturing the image by checking the <guilabel>Capture the 
current pop-up only</guilabel> checkbox under <guilabel>Content 
Options</guilabel></para>
+                                               <para>While this works most of 
the time, in certain cases it may fail to obtain information about the parent 
window. In this case, &spectacle; falls back to old way of capturing the image 
automatically, and captures an image of only the popup menu. You can also force 
the old way of capturing the image by checking the <guilabel>Capture the 
current pop-up only</guilabel> checkbox under 
<guilabel>Options</guilabel></para>
                                        </listitem>
                                        <listitem>
                                                <para>The <guilabel>Rectangular 
Region</guilabel> option allows you to select a rectangular region of your 
desktop with your mouse. This region may be spread across different 
outputs.</para>
@@ -161,9 +161,9 @@
                        </sect2>
 
                        <sect2>
-                               <title>Content Options</title>
+                               <title>Options</title>
 
-                               <para>The content options settings allow you to 
select whether the mouse cursor should be included in the screenshots, and 
whether to capture window decorations along with the image of a single 
application window. In <guilabel>Window Under Cursor</guilabel> mode, it also 
allows you to select if &spectacle; shall only capture the image of the current 
popup menu under the cursor, or also include the parent window.</para>
+                               <para>The Options settings allow you to select 
whether the mouse cursor should be included in the screenshots, and whether to 
capture window decorations along with the image of a single application window. 
In <guilabel>Window Under Cursor</guilabel> mode, it also allows you to select 
if &spectacle; shall only capture the image of the current popup menu under the 
cursor, or also include the parent window. Finally, <guilabel>Quit after Save 
or Copy</guilabel> will quit Spectacle after any save or copy operations.</para>
 
                                <itemizedlist>
                                        <listitem>
@@ -175,6 +175,9 @@
                                        <listitem>
                                                <para>The <guilabel>Capture the 
current pop-up only</guilabel> option is only enabled when the <guilabel>Window 
Under Cursor</guilabel> mode is selected in the <guilabel>Area</guilabel> 
combo-box. Checking this option captures only the popup menu under the cursor, 
without its parent window.</para>
                                        </listitem>
+                                       <listitem>
+                                               <para>The <guilabel>Quit after 
Save or Copy</guilabel> option will quit Spectacle after any saving or copying 
operations. Note that a copied screenshot will only be retained if you are 
running a clipboard manager that accepts images. KDE Klipper can be configured 
in this manner by right-clicking on its icon, selecting <guilabel>Configure 
Clipboard...</guilabel>, and unchecking <guilabel>Ignore 
images</guilabel>.</para>
+                                       </listitem>
                                </itemizedlist>
                        </sect2>
                </sect1>
@@ -222,9 +225,9 @@
                                        </listitem>
                                </varlistentry>
                                <varlistentry>
-                                       <term><guibutton>Save &amp; 
Exit</guibutton></term>
+                                       <term><guibutton>Save 
As</guibutton></term>
                                        <listitem>
-                                               <para>Clicking this button 
saves the screenshot as a PNG image in your default Pictures folder and 
immediately exits the application.</para>
+                                               <para>Clicking this button 
saves the screenshot as a PNG image to a location of your choosing. Clicking on 
the arrow on the side will expose the other save mode, 
<guimenuitem>Save</guimenuitem>, which will save the screenshot as a PNG image 
to the standard location (which defaults to your Pictures folder). By default, 
the last-used save mode is remembered for next time.</para>
                                        </listitem>
                                </varlistentry>
                        </variablelist>
@@ -274,7 +277,7 @@
                        </sect2>
                        <sect2>
                        <title>Save</title>
-                       <para>When you use the <guilabel>Save &amp; 
Exit</guilabel> or the <guilabel>Save</guilabel> functions, &spectacle; saves 
the image with a default filename, in your Pictures folder under your home 
folder. The default filename includes the date and time when the image was 
taken.</para>
+                       <para>When you use the <guilabel>Save</guilabel> 
function, &spectacle; saves the image with a default filename, in your Pictures 
folder (which is inside your home folder). The default filename includes the 
date and time when the image was taken.</para>
 
                        <para>The <guilabel>Save</guilabel> page allows you to 
set the default save location and filename. Clicking this option brings up a 
dialog box like the following:
                                <mediaobject>
@@ -290,7 +293,7 @@
                                <varlistentry>
                                        <term><guilabel>Default Save 
Location</guilabel></term>
                                        <listitem>
-                    <para>In the <guilabel>Location</guilabel> text box set 
the folder where you'd like to save your screenshots when you press 
<guibutton>Save</guibutton> or <guibutton>Save &amp; Exit</guibutton>.</para>
+                    <para>In the <guilabel>Location</guilabel> text box set 
the folder where you'd like to save your screenshots when you press 
<guibutton>Save</guibutton>.</para>
                                        </listitem>
                                </varlistentry>
                                <varlistentry>
diff --git a/src/ExportManager.cpp b/src/ExportManager.cpp
index 16ac3dc..8f36a4a 100644
--- a/src/ExportManager.cpp
+++ b/src/ExportManager.cpp
@@ -326,7 +326,7 @@ void ExportManager::doSave(const QUrl &url, bool notify)
     }
 }
 
-void ExportManager::doSaveAs(QWidget *parentWindow)
+bool ExportManager::doSaveAs(QWidget *parentWindow, bool notify)
 {
     QStringList supportedFilters;
     SpectacleConfig *config = SpectacleConfig::instance();
@@ -353,9 +353,15 @@ void ExportManager::doSaveAs(QWidget *parentWindow)
             if (save(saveUrl)) {
                 emit imageSaved(saveUrl);
                 
config->setLastSaveAsLocation(saveUrl.adjusted(QUrl::RemoveFilename));
+
+                if (notify) {
+                    emit forceNotify(saveUrl);
+                }
+                return true;
             }
         }
     }
+    return false;
 }
 
 // misc helpers
diff --git a/src/ExportManager.h b/src/ExportManager.h
index 33e7f13..5b45070 100644
--- a/src/ExportManager.h
+++ b/src/ExportManager.h
@@ -73,7 +73,7 @@ class ExportManager : public QObject
     QUrl tempSave(const QString &mimetype = QStringLiteral("png"));
 
     void doSave(const QUrl &url = QUrl(), bool notify = false);
-    void doSaveAs(QWidget *parentWindow = 0);
+    bool doSaveAs(QWidget *parentWindow = 0, bool notify = false);
     void doCopyToClipboard();
     void doPrint(QPrinter *printer);
 
diff --git a/src/Gui/KSMainWindow.cpp b/src/Gui/KSMainWindow.cpp
index e491cb4..5b3bd1f 100644
--- a/src/Gui/KSMainWindow.cpp
+++ b/src/Gui/KSMainWindow.cpp
@@ -192,6 +192,10 @@ void KSMainWindow::init()
     }
     resize(QSize(DEFAULT_WINDOW_WIDTH, 
DEFAULT_WINDOW_HEIGHT).expandedTo(minimumSize()));
 
+    // Allow Ctrl+Q to quit the app
+    QAction *actionQuit = KStandardAction::quit(qApp, &QApplication::quit, 
this);
+    actionQuit->setShortcut(QKeySequence::Quit);
+    addAction(actionQuit);
 
     // done with the init
 }
@@ -220,10 +224,6 @@ void KSMainWindow::buildSaveMenu()
     // get our actions in order
     QAction *actionSave = KStandardAction::save(this, &KSMainWindow::save, 
this);
     QAction *actionSaveAs = KStandardAction::saveAs(this, 
&KSMainWindow::saveAs, this);
-    QAction *actionSaveExit = new 
QAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save &&& 
Exit"), this);
-    actionSaveExit->setToolTip(i18n("Save screenshot in your Pictures 
directory and exit"));
-    actionSaveExit->setShortcut(QKeySequence(QKeySequence::Quit));
-    connect(actionSaveExit, &QAction::triggered, this, 
&KSMainWindow::saveAndExit);
 
     // static or dynamic
     SpectacleConfig *cfgManager = SpectacleConfig::instance();
@@ -234,17 +234,10 @@ void KSMainWindow::buildSaveMenu()
     case 0:
     default:
         mSaveButton->setDefaultAction(actionSaveAs);
-        mSaveMenu->addAction(actionSaveExit);
         mSaveMenu->addAction(actionSave);
         break;
     case 1:
         mSaveButton->setDefaultAction(actionSave);
-        mSaveMenu->addAction(actionSaveExit);
-        mSaveMenu->addAction(actionSaveAs);
-        break;
-    case 2:
-        mSaveButton->setDefaultAction(actionSaveExit);
-        mSaveMenu->addAction(actionSave);
         mSaveMenu->addAction(actionSaveAs);
         break;
     }
@@ -318,6 +311,12 @@ void KSMainWindow::sendToClipboard()
 {
     ExportManager::instance()->doCopyToClipboard();
 
+    if (SpectacleConfig::instance()->quitAfterSaveOrCopyChecked()) {
+        qApp->setQuitOnLastWindowClosed(false);
+        hide();
+        QTimer::singleShot(250, qApp, &QApplication::quit);
+    }
+
     mMessageWidget->setMessageType(KMessageWidget::Information);
     mMessageWidget->setText(i18n("The screenshot has been copied to the 
clipboard."));
     
mMessageWidget->setIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
@@ -342,20 +341,29 @@ void KSMainWindow::save()
 {
     SpectacleConfig::instance()->setLastUsedSaveMode(1);
     buildSaveMenu();
-    ExportManager::instance()->doSave();
+
+    if (SpectacleConfig::instance()->quitAfterSaveOrCopyChecked()) {
+        ExportManager::instance()->doSave(QUrl(), true);
+        qApp->setQuitOnLastWindowClosed(false);
+        hide();
+    }
+    else {
+        ExportManager::instance()->doSave();
+    }
 }
 
 void KSMainWindow::saveAs()
 {
     SpectacleConfig::instance()->setLastUsedSaveMode(0);
     buildSaveMenu();
-    ExportManager::instance()->doSaveAs(this);
-}
 
-void KSMainWindow::saveAndExit()
-{
-    SpectacleConfig::instance()->setLastUsedSaveMode(2);
-    qApp->setQuitOnLastWindowClosed(false);
-    ExportManager::instance()->doSave(QUrl(), true);
-    hide();
+    if (SpectacleConfig::instance()->quitAfterSaveOrCopyChecked()) {
+        if (ExportManager::instance()->doSaveAs(this, true)) {
+            qApp->setQuitOnLastWindowClosed(false);
+            hide();
+        }
+    }
+    else {
+        ExportManager::instance()->doSaveAs(this, false);
+    }
 }
diff --git a/src/Gui/KSMainWindow.h b/src/Gui/KSMainWindow.h
index ab78f31..b51c9a9 100644
--- a/src/Gui/KSMainWindow.h
+++ b/src/Gui/KSMainWindow.h
@@ -52,7 +52,6 @@ class KSMainWindow : public QDialog
     void buildSaveMenu();
     void save();
     void saveAs();
-    void saveAndExit();
     int windowWidth(const QPixmap &pixmap) const;
 
     public slots:
diff --git a/src/Gui/KSWidget.cpp b/src/Gui/KSWidget.cpp
index 28612ec..81382c8 100644
--- a/src/Gui/KSWidget.cpp
+++ b/src/Gui/KSWidget.cpp
@@ -87,10 +87,10 @@ KSWidget::KSWidget(QWidget *parent) :
     mCaptureModeForm->addRow(i18n("Delay:"), mDelayLayout);
     mCaptureModeForm->setContentsMargins(24, 0, 0, 0);
 
-    // the content options (mouse pointer, window decorations)
+    // options (mouse pointer, window decorations, quit after saving or 
copying)
 
     mContentOptionsLabel = new QLabel(this);
-    mContentOptionsLabel->setText(i18n("<b>Content Options</b>"));
+    mContentOptionsLabel->setText(i18n("<b>Options</b>"));
 
     mMousePointer = new QCheckBox(i18n("Include mouse pointer"), this);
     mMousePointer->setToolTip(i18n("Show the mouse cursor in the screenshot 
image"));
@@ -107,11 +107,15 @@ KSWidget::KSWidget(QWidget *parent) :
     mCaptureTransientOnly->setEnabled(false);
     connect(mCaptureTransientOnly, &QCheckBox::clicked, configManager, 
&SpectacleConfig::setCaptureTransientWindowOnlyChecked);
 
+    mQuitAfterSaveOrCopy = new QCheckBox(i18n("Quit after Save or Copy"), 
this);
+    mQuitAfterSaveOrCopy->setToolTip(i18n("Quit Spectacle after saving or 
copying the image"));
+    connect(mQuitAfterSaveOrCopy, &QCheckBox::clicked, configManager, 
&SpectacleConfig::setQuitAfterSaveOrCopyChecked);
+
     mContentOptionsForm = new QVBoxLayout;
     mContentOptionsForm->addWidget(mMousePointer);
     mContentOptionsForm->addWidget(mWindowDecorations);
     mContentOptionsForm->addWidget(mCaptureTransientOnly);
-    mContentOptionsForm->setSpacing(16);
+    mContentOptionsForm->addWidget(mQuitAfterSaveOrCopy);
     mContentOptionsForm->setContentsMargins(24, 0, 0, 0);
 
     // the take a new screenshot button
@@ -134,11 +138,9 @@ KSWidget::KSWidget(QWidget *parent) :
     mRightLayout = new QVBoxLayout;
     mRightLayout->addStretch(1);
     mRightLayout->addWidget(mCaptureModeLabel);
-    mRightLayout->addSpacing(10);
     mRightLayout->addLayout(mCaptureModeForm);
     mRightLayout->addStretch(1);
     mRightLayout->addWidget(mContentOptionsLabel);
-    mRightLayout->addSpacing(10);
     mRightLayout->addLayout(mContentOptionsForm);
     mRightLayout->addStretch(10);
     mRightLayout->addWidget(mTakeScreenshotButton, 1, Qt::AlignHCenter);
@@ -156,6 +158,7 @@ KSWidget::KSWidget(QWidget *parent) :
     mWindowDecorations->setChecked    
(configManager->includeDecorationsChecked());
     mCaptureOnClick->setChecked       (configManager->onClickChecked());
     mCaptureTransientOnly->setChecked 
(configManager->captureTransientWindowOnlyChecked());
+    mQuitAfterSaveOrCopy->setChecked  
(configManager->quitAfterSaveOrCopyChecked());
     mCaptureArea->setCurrentIndex     (configManager->captureMode());
     mDelayMsec->setValue              (configManager->captureDelay());
 
diff --git a/src/Gui/KSWidget.h b/src/Gui/KSWidget.h
index 11998af..733c87a 100644
--- a/src/Gui/KSWidget.h
+++ b/src/Gui/KSWidget.h
@@ -78,6 +78,7 @@ class KSWidget : public QWidget
     QCheckBox     *mMousePointer;
     QCheckBox     *mWindowDecorations;
     QCheckBox     *mCaptureTransientOnly;
+    QCheckBox     *mQuitAfterSaveOrCopy;
     QLabel        *mCaptureModeLabel;
     QLabel        *mContentOptionsLabel;
 };
diff --git a/src/SpectacleConfig.cpp b/src/SpectacleConfig.cpp
index 89be2f6..e3b82b0 100644
--- a/src/SpectacleConfig.cpp
+++ b/src/SpectacleConfig.cpp
@@ -117,6 +117,19 @@ void 
SpectacleConfig::setCaptureTransientWindowOnlyChecked(bool enabled)
     mGuiConfig.sync();
 }
 
+// quit after saving, copying, or exporting the image
+
+bool SpectacleConfig::quitAfterSaveOrCopyChecked() const
+{
+    return mGuiConfig.readEntry(QStringLiteral("quitAfterSaveCopyExport"), 
false);
+}
+
+void SpectacleConfig::setQuitAfterSaveOrCopyChecked(bool enabled)
+{
+    mGuiConfig.writeEntry(QStringLiteral("quitAfterSaveCopyExport"), enabled);
+    mGuiConfig.sync();
+}
+
 // capture delay
 
 qreal SpectacleConfig::captureDelay() const
diff --git a/src/SpectacleConfig.h b/src/SpectacleConfig.h
index 2a3bfb7..d033005 100644
--- a/src/SpectacleConfig.h
+++ b/src/SpectacleConfig.h
@@ -67,6 +67,9 @@ class SpectacleConfig : public QObject
     bool captureTransientWindowOnlyChecked() const;
     void setCaptureTransientWindowOnlyChecked(bool enabled);
 
+    bool quitAfterSaveOrCopyChecked() const;
+    void setQuitAfterSaveOrCopyChecked(bool enabled);
+
     qreal captureDelay() const;
     void setCaptureDelay(qreal delay);
 

Reply via email to