diff --git a/CONTRIBUTING b/CONTRIBUTING index 3169ab8..bc16797 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -1,57 +1,57 @@ COMMIT POLICY Everybody is welcome to committing small fixes and one-liners without prior notification to the maintainer, provided that the following rules are followed: 1. Please keep your commits as small and as atomic as possible. 2. Do not push both formatting and code changes in the same commit. 3. Do not fix coding style and code issues in the same commit. For larger commits, please use the Review Board, Bugzilla or send and e-mail to the maintainer. A rule of thumb to check whether your commit is a major commit is if it affects more than 5 lines of code. Break down larger fixes into smaller commits. Even if you push the commits with one "git push", git preserves your commit info. i18n and documentation fixes, however large they are, may be directly committed without prior notification. CODING STYLE -KScreenGenie follows the KDELibs coding style, with a few execptions: +Kapture follows the KDELibs coding style, with a few execptions: 1. In class definitions, access modifiers are aligned along with member declarations, i.e., at one level right. E.g.: class Hello : public QObject { Q_OBJECT public: void function(); } The access modifier ordering is: public, signals, public slots, protected slots, protected, private slots, private. Member variables come at the end, after all member functions. This is not strictly enforced, but is a good rule to follow. 2. Headers are cumulative, i.e., all headers that a particular class requires, are #include-ed in the class's header file, not the .cpp code file. The .cpp code file includes only one header, which is its own .h file. E.g., a class Foo, defined in Foo.h, will have its code in Foo.cpp, and Foo.cpp will #include only a single header Foo.h 3. Member variables follow the format mCamelCase, and not m_camelCase which is more common throughout the rest of the KDE Applications 4. Source files are mixed case, named the same as the class they contain. i.e., SomeClass will be defined in SomeClass.cpp, not someclass.cpp -Happy coding! \ No newline at end of file +Happy coding! diff --git a/src/.reviewboardrc b/src/.reviewboardrc index bad6f18..f711507 100644 --- a/src/.reviewboardrc +++ b/src/.reviewboardrc @@ -1,3 +1,3 @@ REVIEWBOARD_URL = "https://git.reviewboard.kde.org" -REPOSITORY = 'git://anongit.kde.org/kscreengenie' -PEOPLE='bgupta' \ No newline at end of file +REPOSITORY = 'git://anongit.kde.org/kapture' +PEOPLE='bgupta' diff --git a/src/Gui/KSMainWindow.cpp b/src/Gui/KSMainWindow.cpp index 6520bb9..af8bc5b 100644 --- a/src/Gui/KSMainWindow.cpp +++ b/src/Gui/KSMainWindow.cpp @@ -1,236 +1,236 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSMainWindow.h" KSMainWindow::KSMainWindow(bool onClickAvailable, QWidget *parent) : QDialog(parent), mKSWidget(new KSWidget), mDivider(new QFrame), mDialogButtonBox(new QDialogButtonBox), mSendToButton(new QPushButton), mClipboardButton(new QToolButton), mSaveButton(new QToolButton), mSaveMenu(new QMenu), mCopyMessage(new KMessageWidget), mSendToMenu(new KSSendToMenu), mActionCollection(new KActionCollection(this, "KSStandardActions")), mOnClickAvailable(onClickAvailable) { // before we do anything, we need to set a window property // that skips the close/hide window animation on kwin. this - // fixes a ghost image of the kscreengenie window that appears + // fixes a ghost image of the kapture window that appears // on subsequent screenshots taken with the take new screenshot // button // // credits for this goes to Thomas Lübking #ifdef XCB_FOUND if (qApp->platformName() == QStringLiteral("xcb")) { // create a window if we haven't already. note that the QWidget constructor // should already have done this if (winId() == 0) { create(0, true, true); } // do the xcb shenanigans xcb_connection_t *xcbConn = QX11Info::connection(); const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_SKIP_CLOSE_ANIMATION"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(xcbConn, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(xcbConn, atomCookie, nullptr)); if (atom.isNull()) { goto done; } uint32_t value = 1; xcb_change_property(xcbConn, XCB_PROP_MODE_REPLACE, winId(), atom->atom, XCB_ATOM_CARDINAL, 32, 1, &value); } #endif done: QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection); } KSMainWindow::~KSMainWindow() {} // GUI init void KSMainWindow::init() { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); // window properties setMinimumSize(840, 420); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); resize(minimumSize()); QPoint location = guiConfig.readEntry("window-position", QPoint(50, 50)); move(location); // the KSGWidget connect(mKSWidget, &KSWidget::newScreenshotRequest, this, &KSMainWindow::captureScreenshot); connect(mKSWidget, &KSWidget::dragInitiated, this, &KSMainWindow::dragAndDropRequest); // the Button Bar mDialogButtonBox->setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::Discard); KGuiItem::assign(mSendToButton, KGuiItem(i18n("Open With..."))); mSendToButton->setIcon(QIcon::fromTheme("application-x-executable")); mDialogButtonBox->addButton(mSendToButton, QDialogButtonBox::ActionRole); mClipboardButton->setDefaultAction(KStandardAction::copy(this, SLOT(sendToClipboard()), this)); mClipboardButton->setText(i18n("Copy To Clipboard")); mClipboardButton->setToolTip(i18n("Copy the current screenshot image to the clipboard.")); mClipboardButton->setIcon(QIcon::fromTheme("edit-copy")); mClipboardButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); mDialogButtonBox->addButton(mClipboardButton, QDialogButtonBox::ActionRole); mSaveMenu->addAction(KStandardAction::save(this, SIGNAL(save()), this)); mSaveMenu->addAction(KStandardAction::saveAs(this, SIGNAL(saveAsClicked()), this)); mSaveMenu->addAction(KStandardAction::print(this, SLOT(showPrintDialog()), this)); mSaveMenu->addAction(QIcon::fromTheme("applications-system"), i18n("Configure Save Options"), this, SLOT(showSaveConfigDialog())); QAction *saveAndExitAction = new QAction(QIcon::fromTheme("document-save"), i18n("Save &&& Exit"), this); saveAndExitAction->setToolTip(i18n("Save screenshot in your Pictures directory and exit")); saveAndExitAction->setShortcut(QKeySequence(QKeySequence::Quit)); connect(saveAndExitAction, &QAction::triggered, this, &KSMainWindow::saveAndExit); mSaveButton->setDefaultAction(saveAndExitAction); mSaveButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); mSaveButton->setMenu(mSaveMenu); mSaveButton->setPopupMode(QToolButton::MenuButtonPopup); mDialogButtonBox->addButton(mSaveButton, QDialogButtonBox::ActionRole); QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), mDialogButtonBox->button(QDialogButtonBox::Discard)); connect(shortcut, &QShortcut::activated, qApp, &QApplication::quit); connect(mDialogButtonBox->button(QDialogButtonBox::Discard), &QPushButton::clicked, qApp, &QApplication::quit); // the help menu KHelpMenu *helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true); mDialogButtonBox->button(QDialogButtonBox::Help)->setMenu(helpMenu->menu()); // copy-to-clipboard message mCopyMessage->setText(i18n("The screenshot has been copied to the clipboard.")); mCopyMessage->setMessageType(KMessageWidget::Information); mCopyMessage->setIcon(QIcon::fromTheme("dialog-information")); // layouts mDivider->setFrameShape(QFrame::HLine); mDivider->setLineWidth(2); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(mKSWidget); layout->addWidget(mCopyMessage); layout->addWidget(mDivider); layout->addWidget(mDialogButtonBox); mCopyMessage->hide(); // populate our send-to actions connect(mSendToMenu, &KSSendToMenu::sendToServiceRequest, this, &KSMainWindow::sendToKServiceRequest); connect(mSendToMenu, &KSSendToMenu::sendToClipboardRequest, this, &KSMainWindow::sendToClipboardRequest); connect(mSendToMenu, &KSSendToMenu::sendToOpenWithRequest, this, &KSMainWindow::sendToOpenWithRequest); mSendToButton->setMenu(mSendToMenu->menu()); // disable onClick mode if not available on the platform if (!mOnClickAvailable) { mKSWidget->disableOnClick(); } // done with the init } // overrides void KSMainWindow::moveEvent(QMoveEvent *event) { Q_UNUSED(event); - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); guiConfig.writeEntry("window-position", pos()); guiConfig.sync(); } // slots void KSMainWindow::captureScreenshot(ImageGrabber::GrabMode mode, int timeout, bool includePointer, bool includeDecorations) { hide(); emit newScreenshotRequest(mode, timeout, includePointer, includeDecorations); } void KSMainWindow::setScreenshotAndShow(const QPixmap &pixmap) { mKSWidget->setScreenshotPixmap(pixmap); setWindowTitle(i18nc("Unsaved Screenshot", "Unsaved[*]")); setWindowModified(true); KGuiItem::assign(mDialogButtonBox->button(QDialogButtonBox::Discard), KStandardGuiItem::discard()); show(); if (mSendToMenu->menu()->isEmpty()) { QTimer::singleShot(100, mSendToMenu, &KSSendToMenu::populateMenu); } } void KSMainWindow::showPrintDialog() { QPrinter *printer = new QPrinter(QPrinter::HighResolution); QPrintDialog printDialog(printer, this); if (printDialog.exec() == QDialog::Accepted) { emit printRequest(printer); return; } delete printer; } void KSMainWindow::sendToClipboard() { emit sendToClipboardRequest(); mCopyMessage->animatedShow(); QTimer::singleShot(5000, mCopyMessage, &KMessageWidget::animatedHide); } void KSMainWindow::showSaveConfigDialog() { KSSaveConfigDialog saveDialog(this); saveDialog.exec(); } void KSMainWindow::setScreenshotWindowTitle(QUrl location) { setWindowTitle(location.fileName()); setWindowModified(false); KGuiItem::assign(mDialogButtonBox->button(QDialogButtonBox::Discard), KStandardGuiItem::quit()); } diff --git a/src/Gui/KSSaveConfigDialog.cpp b/src/Gui/KSSaveConfigDialog.cpp index bed9f6b..d84d264 100644 --- a/src/Gui/KSSaveConfigDialog.cpp +++ b/src/Gui/KSSaveConfigDialog.cpp @@ -1,141 +1,141 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSSaveConfigDialog.h" KSSaveConfigDialog::KSSaveConfigDialog(QWidget *parent) : QDialog(parent) { // set the window properties first setWindowTitle(i18n("Configure Save Options")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setFixedSize(500, 600); // bring up the configuration reader - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup generalConfig = KConfigGroup(config, "General"); // set up the layout. start with the directory QGroupBox *dirGroup = new QGroupBox(i18n("Default Save Directory")); QVBoxLayout *dirLayout = new QVBoxLayout; dirGroup->setLayout(dirLayout); dirGroup->setStyleSheet("QGroupBox { font-weight: bold; }"); QLabel *dirHelpText = new QLabel; dirHelpText->setWordWrap(true); dirHelpText->setText(i18n("Set the directory where you'd like to save your screenshots when you press " "Save or Save & Exit.")); dirLayout->addWidget(dirHelpText); QHBoxLayout *urlRequesterLayout = new QHBoxLayout; urlRequesterLayout->addWidget(new QLabel(i18n("Location:"))); mUrlRequester = new KUrlRequester; mUrlRequester->setMode(KFile::Directory); const QString path = generalConfig.readPathEntry("default-save-location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); mUrlRequester->setUrl(QUrl::fromUserInput(path)); urlRequesterLayout->addWidget(mUrlRequester); dirLayout->addLayout(urlRequesterLayout); // now the save filename format layout QGroupBox *fmtGroup = new QGroupBox(i18n("Default Save Filename")); QVBoxLayout *fmtLayout = new QVBoxLayout; fmtGroup->setLayout(fmtLayout); fmtGroup->setStyleSheet("QGroupBox { font-weight: bold; }"); const QString helpText = i18n( "

Set a default filename for saved screenshots.

" "

You can use the following placeholders in the filename, which will be replaced " "with actual text when the file is saved:

" "
" "%Y: Year (4 digit)
" "%y: Year (2 digit)
" "%M: Month
" "%D: Day
" "%H: Hour
" "%m: Minute
" "%S: Second" "
" "

You don't need to enter a filetype extension. By default, screenshots are always saved " "as a PNG (Portable Network Graphics) image with a .png extension.

" "

If a file with this name already exists, a serial number will be appended to the filename. " "For example, if the filename is \"Screenshot\", and \"Screenshot.png\" already " "exists, the image will be saved as \"Screenshot-1.png\".

" ); QLabel *fmtHelpText = new QLabel; fmtHelpText->setWordWrap(true); fmtHelpText->setText(helpText); fmtHelpText->setTextFormat(Qt::RichText); fmtLayout->addWidget(fmtHelpText); QHBoxLayout *saveNameLayout = new QHBoxLayout; saveNameLayout->addWidget(new QLabel(i18n("Filename:"))); mSaveNameFormat = new QLineEdit; const QString saveFmt = generalConfig.readEntry("save-filename-format", "Screenshot_%Y%M%D_%H%m%S"); mSaveNameFormat->setText(saveFmt); saveNameLayout->addWidget(mSaveNameFormat); fmtLayout->addLayout(saveNameLayout); // finish up with the main layout QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(dirGroup); mainLayout->addWidget(fmtGroup); mDialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(mDialogButtonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &KSSaveConfigDialog::accept); connect(mDialogButtonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &KSSaveConfigDialog::reject); mainLayout->addWidget(mDialogButtonBox); setLayout(mainLayout); } KSSaveConfigDialog::~KSSaveConfigDialog() {} void KSSaveConfigDialog::accept() { // bring up the configuration reader - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup generalConfig = KConfigGroup(config, "General"); // save the data generalConfig.writePathEntry("default-save-location", mUrlRequester->url().toDisplayString(QUrl::PreferLocalFile)); generalConfig.writeEntry("save-filename-format", mSaveNameFormat->text()); // done emit done(QDialog::Accepted); } diff --git a/src/Gui/KSWidget.cpp b/src/Gui/KSWidget.cpp index 969972a..742278e 100644 --- a/src/Gui/KSWidget.cpp +++ b/src/Gui/KSWidget.cpp @@ -1,231 +1,231 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSWidget.h" KSWidget::KSWidget(QWidget *parent) : QWidget(parent) { // we'll init the widget that holds the image first mImageWidget = new KSImageWidget(this); mImageWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); connect(mImageWidget, &KSImageWidget::dragInitiated, this, &KSWidget::dragInitiated); // the capture mode options first mCaptureModeLabel = new QLabel(this); mCaptureModeLabel->setText(i18n("Capture Mode")); mCaptureArea = new QComboBox(this); mCaptureArea->insertItem(1, i18n("Full Screen (All Monitors)"), ImageGrabber::FullScreen); mCaptureArea->insertItem(2, i18n("Current Screen"), ImageGrabber::CurrentScreen); mCaptureArea->insertItem(3, i18n("Active Window"), ImageGrabber::ActiveWindow); mCaptureArea->insertItem(4, i18n("Window Under Cursor"), ImageGrabber::WindowUnderCursor); mCaptureArea->insertItem(5, i18n("Rectangular Region"), ImageGrabber::RectangularRegion); mCaptureArea->setMinimumWidth(240); connect(mCaptureArea, static_cast(&QComboBox::currentIndexChanged), this, &KSWidget::captureModeChanged); mDelayMsec = new QDoubleSpinBox(this); mDelayMsec->setDecimals(1); mDelayMsec->setSingleStep(1.0); mDelayMsec->setMinimum(0.0); mDelayMsec->setMaximum(999.9); mDelayMsec->setSuffix(i18n(" seconds")); mDelayMsec->setMinimumWidth(160); connect(mDelayMsec, static_cast(&QDoubleSpinBox::valueChanged), this, &KSWidget::captureDelayChanged); mCaptureOnClick = new QCheckBox(this); mCaptureOnClick->setText(i18n("On Click")); mCaptureOnClick->setToolTip(i18n("Wait for a mouse click before capturing the screenshot image")); connect(mCaptureOnClick, &QCheckBox::stateChanged, this, &KSWidget::onClickStateChanged); connect(mCaptureOnClick, &QCheckBox::stateChanged, this, &KSWidget::checkboxStatesChanged); mDelayLayout = new QHBoxLayout; mDelayLayout->addWidget(mDelayMsec); mDelayLayout->addWidget(mCaptureOnClick); mCaptureModeForm = new QFormLayout; mCaptureModeForm->addRow(i18n("Area:"), mCaptureArea); mCaptureModeForm->addRow(i18n("Delay:"), mDelayLayout); mCaptureModeForm->setContentsMargins(24, 0, 0, 0); // the content options (mouse pointer, window decorations) mContentOptionsLabel = new QLabel(this); mContentOptionsLabel->setText(i18n("Content Options")); mMousePointer = new QCheckBox(this); mMousePointer->setText(i18n("Include mouse pointer")); mMousePointer->setToolTip(i18n("Show the mouse cursor in the screeenshot image")); connect(mMousePointer, &QCheckBox::stateChanged, this, &KSWidget::checkboxStatesChanged); mWindowDecorations = new QCheckBox(this); mWindowDecorations->setText(i18n("Include window titlebar and borders")); mWindowDecorations->setToolTip(i18n("Show the window title bar, the minimize/maximize/close buttons, and the window border")); mWindowDecorations->setEnabled(false); connect(mWindowDecorations, &QCheckBox::stateChanged, this, &KSWidget::checkboxStatesChanged); mCaptureTransientOnly = new QCheckBox(this); mCaptureTransientOnly->setText(i18n("Capture the current pop-up only")); mCaptureTransientOnly->setToolTip(i18n("Capture only the current pop-up window (like a menu, tooltip etc). " "If this is not enabled, the pop-up is captured along with the parent window")); mCaptureTransientOnly->setEnabled(false); connect(mCaptureTransientOnly, &QCheckBox::stateChanged, this, &KSWidget::checkboxStatesChanged); mContentOptionsForm = new QVBoxLayout; mContentOptionsForm->addWidget(mMousePointer); mContentOptionsForm->addWidget(mWindowDecorations); mContentOptionsForm->addWidget(mCaptureTransientOnly); mContentOptionsForm->setSpacing(16); mContentOptionsForm->setContentsMargins(24, 0, 0, 0); // the take new screenshot button mTakeScreenshotButton = new QPushButton(this); mTakeScreenshotButton->setText(i18n("Take New Screenshot")); mTakeScreenshotButton->setIcon(QIcon::fromTheme("ksnapshot")); mTakeScreenshotButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mTakeScreenshotButton->setFocus(); connect(mTakeScreenshotButton, &QPushButton::clicked, this, &KSWidget::newScreenshotClicked); QShortcut *shortcut = new QShortcut(QKeySequence(QKeySequence::New), mTakeScreenshotButton); auto clickFunc = [&]() { mTakeScreenshotButton->animateClick(100); QTimer::singleShot(100, mTakeScreenshotButton, &QPushButton::click); }; connect(shortcut, &QShortcut::activated, clickFunc); // finally, finish up the layouts 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); mRightLayout->setContentsMargins(20, 0, 0, 10); mMainLayout = new QGridLayout(this); mMainLayout->addWidget(mImageWidget, 0, 0, 1, 1); mMainLayout->addLayout(mRightLayout, 0, 1, 1, 1); mMainLayout->setColumnMinimumWidth(0, 400); mMainLayout->setColumnMinimumWidth(1, 400); // and read in the saved checkbox states and capture mode indices - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); mMousePointer->setChecked(guiConfig.readEntry("includePointer", true)); mWindowDecorations->setChecked(guiConfig.readEntry("includeDecorations", true)); mCaptureOnClick->setChecked(guiConfig.readEntry("waitCaptureOnClick", false)); mCaptureTransientOnly->setChecked(guiConfig.readEntry("transientOnly", false)); mCaptureArea->setCurrentIndex(guiConfig.readEntry("captureModeIndex", 0)); mDelayMsec->setValue(guiConfig.readEntry("captureDelay", (qreal)0)); // done } // public slots void KSWidget::setScreenshotPixmap(const QPixmap &pixmap) { mImageWidget->setScreenshot(pixmap); } void KSWidget::disableOnClick() { mCaptureOnClick->setEnabled(false); mDelayMsec->setEnabled(true); } // private slots void KSWidget::newScreenshotClicked() { int delay = mCaptureOnClick->isChecked() ? -1 : (mDelayMsec->value() * 1000); ImageGrabber::GrabMode mode = static_cast(mCaptureArea->currentData().toInt()); if (mode == ImageGrabber::WindowUnderCursor && !(mCaptureTransientOnly->isChecked())) { mode = ImageGrabber::TransientWithParent; } emit newScreenshotRequest(mode, delay, mMousePointer->isChecked(), mWindowDecorations->isChecked()); } void KSWidget::checkboxStatesChanged(int state) { Q_UNUSED(state); - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); guiConfig.writeEntry("includePointer", mMousePointer->isChecked()); guiConfig.writeEntry("includeDecorations", mWindowDecorations->isChecked()); guiConfig.writeEntry("waitCaptureOnClick", mCaptureOnClick->isChecked()); guiConfig.writeEntry("transientOnly", mCaptureTransientOnly->isChecked()); guiConfig.sync(); } void KSWidget::onClickStateChanged(int state) { if (state == Qt::Checked) { mDelayMsec->setEnabled(false); } else if (state == Qt::Unchecked) { mDelayMsec->setEnabled(true); } } void KSWidget::captureModeChanged(int index) { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); guiConfig.writeEntry("captureModeIndex", index); guiConfig.sync(); ImageGrabber::GrabMode mode = static_cast(mCaptureArea->itemData(index).toInt()); switch (mode) { case ImageGrabber::WindowUnderCursor: mWindowDecorations->setEnabled(true); mCaptureTransientOnly->setEnabled(true); break; case ImageGrabber::ActiveWindow: mWindowDecorations->setEnabled(true); mCaptureTransientOnly->setEnabled(false); break; default: mWindowDecorations->setEnabled(false); mCaptureTransientOnly->setEnabled(false); } } void KSWidget::captureDelayChanged(qreal value) { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); guiConfig.writeEntry("captureDelay", value); guiConfig.sync(); } diff --git a/src/KSCore.cpp b/src/KSCore.cpp index a6f9241..8a41059 100644 --- a/src/KSCore.cpp +++ b/src/KSCore.cpp @@ -1,569 +1,569 @@ /* * Copyright (C) 2015 Boudhayan Gupta * * Includes code from ksnapshot.cpp, part of KSnapshot. Copyright notices * reproduced below: * * Copyright (C) 1997-2008 Richard J. Moore * Copyright (C) 2000 Matthias Ettrich * Copyright (C) 2002 Aaron J. Seigo * Copyright (C) 2003 Nadeem Hasan * Copyright (C) 2004 Bernd Brandstetter * Copyright (C) 2006 Urs Wolfer * Copyright (C) 2010 Martin Gräßlin * Copyright (C) 2010, 2011 Pau Garcia i Quiles * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSCore.h" KSCore::KSCore(bool backgroundMode, ImageGrabber::GrabMode grabMode, QString &saveFileName, qint64 delayMsec, bool sendToClipboard, bool notifyOnGrab, QObject *parent) : QObject(parent), mBackgroundMode(backgroundMode), mNotify(notifyOnGrab), mOverwriteOnSave(true), mBackgroundSendToClipboard(sendToClipboard), mLocalPixmap(QPixmap()), mImageGrabber(nullptr), mMainWindow(nullptr) { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup guiConfig(config, "GuiConfig"); if (!(saveFileName.isEmpty() || saveFileName.isNull())) { if (QDir::isRelativePath(saveFileName)) { saveFileName = QDir::current().absoluteFilePath(saveFileName); } setFilename(saveFileName); } #ifdef XCB_FOUND if (qApp->platformName() == QStringLiteral("xcb")) { mImageGrabber = new X11ImageGrabber; } #endif if (!mImageGrabber) { mImageGrabber = new DummyImageGrabber; } mImageGrabber->setGrabMode(grabMode); mImageGrabber->setCapturePointer(guiConfig.readEntry("includePointer", true)); mImageGrabber->setCaptureDecorations(guiConfig.readEntry("includeDecorations", true)); if ((!(mImageGrabber->onClickGrabSupported())) && (delayMsec < 0)) { delayMsec = 0; } connect(this, &KSCore::errorMessage, this, &KSCore::showErrorMessage); connect(mImageGrabber, &ImageGrabber::pixmapChanged, this, &KSCore::screenshotUpdated); connect(mImageGrabber, &ImageGrabber::imageGrabFailed, this, &KSCore::screenshotFailed); if (backgroundMode) { int msec = (KWindowSystem::compositingActive() ? 200 : 50) + delayMsec; QTimer::singleShot(msec, mImageGrabber, &ImageGrabber::doImageGrab); return; } // if we aren't in background mode, this would be a good time to // init the gui mMainWindow = new KSMainWindow(mImageGrabber->onClickGrabSupported()); connect(mMainWindow, &KSMainWindow::newScreenshotRequest, this, &KSCore::takeNewScreenshot); connect(mMainWindow, &KSMainWindow::save, this, &KSCore::doGuiSave); connect(mMainWindow, &KSMainWindow::saveAndExit, this, &KSCore::doAutoSave); connect(mMainWindow, &KSMainWindow::saveAsClicked, this, &KSCore::doGuiSaveAs); connect(mMainWindow, &KSMainWindow::sendToKServiceRequest, this, &KSCore::doSendToService); connect(mMainWindow, &KSMainWindow::sendToOpenWithRequest, this, &KSCore::doSendToOpenWith); connect(mMainWindow, &KSMainWindow::sendToClipboardRequest, this, &KSCore::doSendToClipboard); connect(mMainWindow, &KSMainWindow::dragAndDropRequest, this, &KSCore::doStartDragAndDrop); connect(mMainWindow, &KSMainWindow::printRequest, this, &KSCore::doPrint); connect(this, &KSCore::imageSaved, mMainWindow, &KSMainWindow::setScreenshotWindowTitle); QMetaObject::invokeMethod(mImageGrabber, "doImageGrab", Qt::QueuedConnection); } KSCore::~KSCore() { if (mMainWindow) { delete mMainWindow; } } // Q_PROPERTY stuff QString KSCore::filename() const { return mFileNameString; } void KSCore::setFilename(const QString &filename) { mFileNameString = filename; mFileNameUrl = QUrl::fromUserInput(filename); } ImageGrabber::GrabMode KSCore::grabMode() const { return mImageGrabber->grabMode(); } void KSCore::setGrabMode(const ImageGrabber::GrabMode &grabMode) { mImageGrabber->setGrabMode(grabMode); } bool KSCore::overwriteOnSave() const { return mOverwriteOnSave; } void KSCore::setOverwriteOnSave(const bool &overwrite) { mOverwriteOnSave = overwrite; } QString KSCore::saveLocation() const { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup generalConfig = KConfigGroup(config, "General"); QString savePath = generalConfig.readPathEntry( "default-save-location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); if (savePath.isEmpty() || savePath.isNull()) { savePath = QDir::homePath(); } savePath = QDir::cleanPath(savePath); QDir savePathDir(savePath); if (!(savePathDir.exists())) { savePathDir.mkpath("."); generalConfig.writePathEntry("last-saved-to", savePath); } return savePath; } void KSCore::setSaveLocation(const QString &savePath) { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup generalConfig = KConfigGroup(config, "General"); generalConfig.writePathEntry("last-saved-to", savePath); } // Slots void KSCore::takeNewScreenshot(const ImageGrabber::GrabMode &mode, const int &timeout, const bool &includePointer, const bool &includeDecorations) { mImageGrabber->setGrabMode(mode); mImageGrabber->setCapturePointer(includePointer); mImageGrabber->setCaptureDecorations(includeDecorations); if (timeout < 0) { mImageGrabber->doOnClickGrab(); return; } // when compositing is enabled, we need to give it enough time for the window // to disappear and all the effects are complete before we take the shot. there's // no way of knowing how long the disappearing effects take, but as per default // settings (and unless the user has set an extremely slow effect), 200 // milliseconds is a good amount of wait time. const int msec = KWindowSystem::compositingActive() ? 200 : 50; QTimer::singleShot(timeout + msec, mImageGrabber, &ImageGrabber::doImageGrab); } void KSCore::showErrorMessage(const QString &errString) { qDebug() << "ERROR: " << errString; if (!mBackgroundMode) { KMessageBox::error(0, errString); } } void KSCore::screenshotUpdated(const QPixmap &pixmap) { mLocalPixmap = pixmap; if (mBackgroundMode) { if (mBackgroundSendToClipboard) { qApp->clipboard()->setPixmap(pixmap); qDebug() << i18n("Copied image to clipboard"); } else { doAutoSave(); } } else { mMainWindow->setScreenshotAndShow(pixmap); tempFileSave(); } } void KSCore::screenshotFailed() { if (mBackgroundMode) { qDebug() << i18n("Screenshot capture canceled or failed"); emit allDone(); return; } mMainWindow->show(); } void KSCore::doGuiSave() { if (mLocalPixmap.isNull()) { emit errorMessage(i18n("Cannot save an empty screenshot image.")); return; } QUrl savePath = getAutosaveFilename(); if (doSave(savePath)) { emit imageSaved(savePath); } } void KSCore::doAutoSave() { if (mLocalPixmap.isNull()) { emit errorMessage(i18n("Cannot save an empty screenshot image.")); return; } QUrl savePath; if (mBackgroundMode && mFileNameUrl.isValid() && mFileNameUrl.isLocalFile()) { savePath = mFileNameUrl; } else { savePath = getAutosaveFilename(); } if (doSave(savePath)) { QDir dir(savePath.path()); dir.cdUp(); setSaveLocation(dir.absolutePath()); if (mBackgroundMode && mNotify) { KNotification *notify = new KNotification("newScreenshotSaved"); notify->setText(i18n("A new screenshot was captured and saved to %1", savePath.toLocalFile())); notify->setPixmap(QIcon::fromTheme("ksnapshot").pixmap(QSize(32, 32))); notify->sendEvent(); // unfortunately we can't quit just yet, emitting allDone right away // quits the application before the notification DBus message gets sent. // a token timeout seems to fix this though. Any better ideas? QTimer::singleShot(50, this, &KSCore::allDone); } else { emit allDone(); } return; } } void KSCore::doStartDragAndDrop() { QMimeData *mimeData = new QMimeData; mimeData->setUrls(QList { getTempSaveFilename() }); mimeData->setImageData(mLocalPixmap); mimeData->setData("application/x-kde-suggestedfilename", QFile::encodeName(makeAutosaveFilename() + ".png")); QDrag *dragHandler = new QDrag(this); dragHandler->setMimeData(mimeData); dragHandler->setPixmap(mLocalPixmap.scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); dragHandler->start(); dragHandler->deleteLater(); } void KSCore::doPrint(QPrinter *printer) { QPainter painter; if (!(painter.begin(printer))) { emit errorMessage(i18n("Printing failed. The printer failed to initialize.")); delete printer; return; } QRect devRect(0, 0, printer->width(), printer->height()); QPixmap pixmap = mLocalPixmap.scaled(devRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); QRect srcRect = pixmap.rect(); srcRect.moveCenter(devRect.center()); painter.drawPixmap(srcRect.topLeft(), pixmap); painter.end(); delete printer; return; } void KSCore::doGuiSaveAs() { QString selectedFilter; QStringList supportedFilters; QMimeDatabase db; const QUrl autoSavePath = getAutosaveFilename(); const QMimeType mimeTypeForFilename = db.mimeTypeForUrl(autoSavePath); for (auto mimeTypeName: QImageWriter::supportedMimeTypes()) { QMimeType mimetype = db.mimeTypeForName(mimeTypeName); if (mimetype.preferredSuffix() != "") { QString filterString = mimetype.comment() + " (*." + mimetype.preferredSuffix() + ")"; qDebug() << filterString; supportedFilters.append(filterString); if (mimetype == mimeTypeForFilename) { selectedFilter = supportedFilters.last(); } } } QFileDialog dialog(mMainWindow); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setFileMode(QFileDialog::AnyFile); dialog.setNameFilters(supportedFilters); dialog.selectNameFilter(selectedFilter); dialog.setDirectoryUrl(autoSavePath); if (dialog.exec() == QFileDialog::Accepted) { const QUrl saveUrl = dialog.selectedUrls().first(); if (saveUrl.isValid()) { if (doSave(saveUrl)) { emit imageSaved(saveUrl); } } } } void KSCore::doSendToService(KService::Ptr service) { QUrl tempFile; QList tempFileList; tempFile = getTempSaveFilename(); if (!tempFile.isValid()) { emit errorMessage(i18n("Cannot send screenshot to the application")); return; } tempFileList.append(tempFile); KRun::runService(*service, tempFileList, mMainWindow, true); } void KSCore::doSendToOpenWith() { QUrl tempFile; QList tempFileList; tempFile = getTempSaveFilename(); if (!tempFile.isValid()) { emit errorMessage(i18n("Cannot send screenshot to the application")); return; } tempFileList.append(tempFile); KRun::displayOpenWithDialog(tempFileList, mMainWindow, true); } void KSCore::doSendToClipboard() { QApplication::clipboard()->setPixmap(mLocalPixmap); } // Private QUrl KSCore::getAutosaveFilename() { const QString baseDir = saveLocation(); const QDir baseDirPath(baseDir); const QString filename = makeAutosaveFilename(); const QString fullpath = autoIncrementFilename(baseDirPath.filePath(filename), "png"); const QUrl fileNameUrl = QUrl::fromUserInput(fullpath); if (fileNameUrl.isValid()) { return fileNameUrl; } else { return QUrl(); } } QString KSCore::makeAutosaveFilename() { - KSharedConfigPtr config = KSharedConfig::openConfig("kscreengenierc"); + KSharedConfigPtr config = KSharedConfig::openConfig("kapturerc"); KConfigGroup generalConfig = KConfigGroup(config, "General"); const QDateTime timestamp = QDateTime::currentDateTime(); QString baseName = generalConfig.readEntry("save-filename-format", "Screenshot_%Y%M%D_%H%m%S"); return baseName.replace("%Y", timestamp.toString("yyyy")) .replace("%y", timestamp.toString("yy")) .replace("%M", timestamp.toString("MM")) .replace("%D", timestamp.toString("dd")) .replace("%H", timestamp.toString("hh")) .replace("%m", timestamp.toString("mm")) .replace("%S", timestamp.toString("ss")); } QString KSCore::autoIncrementFilename(const QString &baseName, const QString &extension) { if (!(isFileExists(QUrl::fromUserInput(baseName + '.' + extension)))) { return baseName + '.' + extension; } QString fileNameFmt(baseName + "-%1." + extension); for (quint64 i = 1; i < std::numeric_limits::max(); i++) { if (!(isFileExists(QUrl::fromUserInput(fileNameFmt.arg(i))))) { return fileNameFmt.arg(i); } } // unlikely this will ever happen, but just in case we've run // out of numbers return fileNameFmt.arg("OVERFLOW-" + (qrand() % 10000)); } QString KSCore::makeSaveMimetype(const QUrl &url) { QMimeDatabase mimedb; QString type = mimedb.mimeTypeForUrl(url).preferredSuffix(); if (type.isEmpty()) { return QString("png"); } return type; } bool KSCore::writeImage(QIODevice *device, const QByteArray &format) { QImageWriter imageWriter(device, format); if (!(imageWriter.canWrite())) { emit errorMessage(i18n("QImageWriter cannot write image: ") + imageWriter.errorString()); return false; } return imageWriter.write(mLocalPixmap.toImage()); } bool KSCore::localSave(const QUrl &url, const QString &mimetype) { QFile outputFile(url.toLocalFile()); outputFile.open(QFile::WriteOnly); if(!writeImage(&outputFile, mimetype.toLatin1())) { emit errorMessage(i18n("Cannot save screenshot. Error while writing file.")); return false; } return true; } bool KSCore::remoteSave(const QUrl &url, const QString &mimetype) { QTemporaryFile tmpFile; if (tmpFile.open()) { if(!writeImage(&tmpFile, mimetype.toLatin1())) { emit errorMessage(i18n("Cannot save screenshot. Error while writing temporary local file.")); return false; } KIO::FileCopyJob *uploadJob = KIO::file_copy(QUrl::fromLocalFile(tmpFile.fileName()), url); uploadJob->exec(); if (uploadJob->error() != KJob::NoError) { emit errorMessage(i18n("Unable to save image. Could not upload file to remote location.")); return false; } return true; } return false; } QUrl KSCore::getTempSaveFilename() const { QDir tempDir = QDir::temp(); return QUrl::fromLocalFile(tempDir.absoluteFilePath("KSTempScreenshot.png")); } bool KSCore::tempFileSave() { if (!(mLocalPixmap.isNull())) { const QUrl savePath = getTempSaveFilename(); if (localSave(savePath, "png")) { return QFile::setPermissions(savePath.toLocalFile(), QFile::ReadUser | QFile::WriteUser); } } return false; } QUrl KSCore::tempFileSave(const QString &mimetype) { QTemporaryFile tmpFile; tmpFile.setAutoRemove(false); if (tmpFile.open()) { if(!writeImage(&tmpFile, mimetype.toLatin1())) { emit errorMessage(i18n("Cannot save screenshot. Error while writing temporary local file.")); return QUrl(); } return QUrl::fromLocalFile(tmpFile.fileName()); } return QUrl(); } bool KSCore::doSave(const QUrl &url) { if (!(url.isValid())) { emit errorMessage(i18n("Cannot save screenshot. The save filename is invalid.")); return false; } if (isFileExists(url) && (mOverwriteOnSave == false)) { emit errorMessage((i18n("Cannot save screenshot. The file already exists."))); return false; } QString mimetype = makeSaveMimetype(url); if (url.isLocalFile()) { return localSave(url, mimetype); } return remoteSave(url, mimetype); } bool KSCore::isFileExists(const QUrl &url) { if (!(url.isValid())) { return false; } KIO::StatJob * existsJob = KIO::stat(url, KIO::StatJob::DestinationSide, 0); existsJob->exec(); return (existsJob->error() == KJob::NoError); } diff --git a/src/KipiInterface/KSGKipiImageCollectionShared.cpp b/src/KipiInterface/KSGKipiImageCollectionShared.cpp index fcc820b..b617a17 100644 --- a/src/KipiInterface/KSGKipiImageCollectionShared.cpp +++ b/src/KipiInterface/KSGKipiImageCollectionShared.cpp @@ -1,40 +1,40 @@ /* * Copyright (C) 2015 Boudhayan Gupta * Copyright (C) 2010 Pau Garcia i Quiles * Essentially a rip-off of code for Kamoso by: * Copyright (C) 2008-2009 by Aleix Pol * Copyright (C) 2008-2009 by Alex Fiestas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSGKipiImageCollectionShared.h" KSGKipiImageCollectionShared::KSGKipiImageCollectionShared() {} KSGKipiImageCollectionShared::~KSGKipiImageCollectionShared() {} -QString KSGKipiImageCollectionShared::name() { return "KScreenGenie"; } +QString KSGKipiImageCollectionShared::name() { return "Kapture"; } QString KSGKipiImageCollectionShared::comment() { return QString(); } QString KSGKipiImageCollectionShared::uploadRootName() { return "/"; } QUrl KSGKipiImageCollectionShared::uploadRoot() { return QUrl(uploadRootName()); } bool KSGKipiImageCollectionShared::isDirectory() { return false; } QList KSGKipiImageCollectionShared::images() { QDir tempDir = QDir::temp(); QString tempFile = tempDir.absoluteFilePath("KSTempScreenshot.png"); return QList({ QUrl::fromLocalFile(tempFile) }); } diff --git a/src/KipiInterface/KSGKipiInfoShared.cpp b/src/KipiInterface/KSGKipiInfoShared.cpp index 81a80e3..f66485e 100644 --- a/src/KipiInterface/KSGKipiInfoShared.cpp +++ b/src/KipiInterface/KSGKipiInfoShared.cpp @@ -1,39 +1,39 @@ /* * Copyright (C) 2010 Pau Garcia i Quiles * Essentially a rip-off of code for Kamoso by: * Copyright (C) 2008-2009 by Aleix Pol * Copyright (C) 2008-2009 by Alex Fiestas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KSGKipiInfoShared.h" KSGKipiInfoShared::KSGKipiInfoShared(KIPI::Interface *interface, const QUrl &url) : KIPI::ImageInfoShared(interface, url) {} KSGKipiInfoShared::~KSGKipiInfoShared() {} // no-op functions void KSGKipiInfoShared::delAttributes(const QStringList &) {} void KSGKipiInfoShared::addAttributes(const QMap< QString, QVariant > &) {} void KSGKipiInfoShared::clearAttributes() {} QMap KSGKipiInfoShared::attributes() { return QMap(); } void KSGKipiInfoShared::setDescription(const QString &) {} -QString KSGKipiInfoShared::description() { return i18n("Taken with KScreenGenie"); } +QString KSGKipiInfoShared::description() { return i18n("Taken with Kapture"); }