Page MenuHomePhabricator (Chris)

No OneTemporary

Size
231 KB
Referenced Files
None
Subscribers
None
diff --git a/dialogs/areadialog.cpp b/dialogs/areadialog.cpp
index 482836b..291ebcc 100644
--- a/dialogs/areadialog.cpp
+++ b/dialogs/areadialog.cpp
@@ -1,736 +1,736 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
******
*
* Based on KDE's KSnapshot regiongrabber.cpp, revision 796531, Copyright 2007 Luca Gugelmann <lucag@student.ethz.ch>
* released under the GNU LGPL <http://www.gnu.org/licenses/old-licenses/library.txt>
*
*/
-#include "areadialog.h"
-#include "../tools/os.h"
-#include "../tools/screenshot.h"
-#include "../tools/screenshotmanager.h"
+#include <dialogs/areadialog.h>
+#include <tools/os.h>
+#include <tools/screenshot.h>
+#include <tools/screenshotmanager.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QSettings>
#include <QTimer>
#include <QToolTip>
#include <QThread>
AreaDialog::AreaDialog(Screenshot *screenshot) :
QDialog(0), mScreenshot(screenshot), mMouseDown(false), mMouseMagnifier(false),
mNewSelection(false), mHandleSize(10), mMouseOverHandle(0),
mShowHelp(true), mGrabbing(false), mOverlayAlpha(1), mAutoclose(false),
mTLHandle(0, 0, mHandleSize, mHandleSize), mTRHandle(0, 0, mHandleSize, mHandleSize),
mBLHandle(0, 0, mHandleSize, mHandleSize), mBRHandle(0, 0, mHandleSize, mHandleSize),
mLHandle(0, 0, mHandleSize, mHandleSize), mTHandle(0, 0, mHandleSize, mHandleSize),
mRHandle(0, 0, mHandleSize, mHandleSize), mBHandle(0, 0, mHandleSize, mHandleSize)
{
mHandles << &mTLHandle << &mTRHandle << &mBLHandle << &mBRHandle
<< &mLHandle << &mTHandle << &mRHandle << &mBHandle;
mMouseOverHandle = 0;
setMouseTracking(true);
setWindowTitle(tr("Lightscreen Area Mode"));
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
setCursor(Qt::CrossCursor);
connect(&mIdleTimer, &QTimer::timeout, this, &AreaDialog::displayHelp);
mIdleTimer.start(2000);
mAutoclose = ScreenshotManager::instance()->settings()->value("options/areaAutoclose").toBool();
if (mAutoclose) {
return; // Avoid creating the accept widget if it's not going to get used.
}
// Creating accept widget:
mAcceptWidget = new QWidget(this);
mAcceptWidget->resize(140, 70);
mAcceptWidget->setWindowOpacity(0.4);
mAcceptWidget->setStyleSheet("QWidget { background: rgba(255, 255, 255, 200); border: 4px solid #232323; padding: 0; } QPushButton { background: transparent; border: none; height: 50px; padding: 5px; } QPushButton:hover { cursor: hand; }");
auto awAcceptButton = new QPushButton(QIcon(":/icons/yes.big"), "", this);
connect(awAcceptButton, &QPushButton::clicked, this, &AreaDialog::grabRect);
awAcceptButton->setCursor(Qt::PointingHandCursor);
awAcceptButton->setIconSize(QSize(48, 48));
auto awRejectButton = new QPushButton(QIcon(":/icons/no.big"), "", this);
connect(awRejectButton, &QPushButton::clicked, this, &AreaDialog::cancel);
awRejectButton->setCursor(Qt::PointingHandCursor);
awRejectButton->setIconSize(QSize(48, 48));
auto awLayout = new QHBoxLayout(this);
awLayout->addWidget(awAcceptButton);
awLayout->addWidget(awRejectButton);
awLayout->setMargin(0);
awLayout->setSpacing(0);
mAcceptWidget->setLayout(awLayout);
mAcceptWidget->setVisible(false);
}
QRect AreaDialog::resultRect() const
{
auto devicePixelRatio = mScreenshot->pixmap().devicePixelRatio();
return QRect(mSelection.left() * devicePixelRatio,
mSelection.top() * devicePixelRatio,
mSelection.width() * devicePixelRatio,
mSelection.height() * devicePixelRatio);
}
void AreaDialog::animationTick(int frame)
{
mOverlayAlpha = frame;
update();
}
void AreaDialog::cancel()
{
reject();
}
void AreaDialog::displayHelp()
{
mShowHelp = true;
update();
}
void AreaDialog::grabRect()
{
QRect r = mSelection.normalized();
if (!r.isNull() && r.isValid()) {
mGrabbing = true;
accept();
}
}
void AreaDialog::keyboardResize()
{
if (mKeyboardSize.contains("x")) {
auto sizeList = mKeyboardSize.split("x");
if (sizeList.count() == 2) {
bool okw = false, okh = false;
QSize size(sizeList.at(0).toInt(&okw), sizeList.at(1).toInt(&okh));
if (okw && okh && size.width() > 0 && size.height() > 0) {
auto oldSize = mSelection.size();
mSelection.setSize(size);
if (rect().contains(mSelection)) {
updateHandles();
} else {
mSelection.setSize(oldSize); // Reverting size
}
}
}
}
mKeyboardSize.clear();
update();
}
void AreaDialog::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Escape) {
if (mKeyboardSize.isEmpty()) {
cancel();
} else {
mKeyboardSize.clear();
update();
}
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (mKeyboardSize.isEmpty()) {
grabRect();
} else {
keyboardResize();
}
} else if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right) {
// Keyboard movement
int adjustMagnitude = 1;
if (e->modifiers() & Qt::ShiftModifier)
adjustMagnitude += 4;
if (e->modifiers() & Qt::ControlModifier)
adjustMagnitude += 4;
if (e->modifiers() & Qt::AltModifier)
adjustMagnitude += 4;
int xAdjust = 0;
int yAdjust = 0;
if (e->key() == Qt::Key_Left)
xAdjust = -(adjustMagnitude);
if (e->key() == Qt::Key_Right)
xAdjust = adjustMagnitude;
if (e->key() == Qt::Key_Up)
yAdjust = -(adjustMagnitude);
if (e->key() == Qt::Key_Down)
yAdjust = adjustMagnitude;
auto adjusted = mSelection.adjusted(xAdjust, yAdjust, xAdjust, yAdjust);
if (rect().contains(adjusted)) {
mSelection = adjusted;
updateHandles();
update();
}
} else if (e->key() == Qt::Key_F5) {
setWindowOpacity(0);
QThread::msleep(200); // Give the window system time to catch up
mScreenshot->refresh();
setWindowOpacity(1);
} else {
if (e->key() == Qt::Key_Backspace && !mKeyboardSize.isEmpty()) {
mKeyboardSize.remove(mKeyboardSize.size()-1, 1);
update();
return;
}
if (e->key() != Qt::Key_X) {
bool ok = false;
int number = e->text().toInt(&ok);
if (!ok || number < 0 || number > qMax<int>(width(), height())) {
e->ignore();
return;
}
} else {
if (mKeyboardSize.contains("x"))
return;
}
mKeyboardSize += e->text();
update();
}
}
void AreaDialog::mouseDoubleClickEvent(QMouseEvent *)
{
grabRect();
}
void AreaDialog::mouseMoveEvent(QMouseEvent *e)
{
mMouseMagnifier = false;
if (mMouseDown) {
mMousePos = e->pos();
if (mNewSelection) {
mSelection = QRect(mDragStartPoint, limitPointToRect(mMousePos, rect())).normalized();
} else if (mMouseOverHandle == 0) {
// Moving the whole selection
QRect r = rect().normalized(), s = mSelectionBeforeDrag.normalized();
QPoint p = s.topLeft() + e->pos() - mDragStartPoint;
r.setBottomRight(r.bottomRight() - QPoint(s.width(), s.height()));
if (!r.isNull() && r.isValid()) {
mSelection.moveTo(limitPointToRect(p, r));
}
} else {
// Dragging a handle
QRect r = mSelectionBeforeDrag;
QPoint offset = e->pos() - mDragStartPoint;
bool symmetryMod = qApp->keyboardModifiers() & Qt::ShiftModifier;
bool aspectRatioMod = qApp->keyboardModifiers() & Qt::ControlModifier;
if (mMouseOverHandle == &mTLHandle || mMouseOverHandle == &mTHandle
|| mMouseOverHandle == &mTRHandle) { // dragging one of the top handles
r.setTop(r.top() + offset.y());
if (symmetryMod) {
r.setBottom(r.bottom() - offset.y());
}
}
if (mMouseOverHandle == &mTLHandle || mMouseOverHandle == &mLHandle
|| mMouseOverHandle == &mBLHandle) { // dragging one of the left handles
r.setLeft(r.left() + offset.x());
if (symmetryMod) {
r.setRight(r.right() - offset.x());
}
}
if (mMouseOverHandle == &mBLHandle || mMouseOverHandle == &mBHandle
|| mMouseOverHandle == &mBRHandle) { // dragging one of the bottom handles
r.setBottom(r.bottom() + offset.y());
if (symmetryMod) {
r.setTop(r.top() - offset.y());
}
}
if (mMouseOverHandle == &mTRHandle || mMouseOverHandle == &mRHandle
|| mMouseOverHandle == &mBRHandle) { // dragging one of the right handles
r.setRight(r.right() + offset.x());
if (symmetryMod) {
r.setLeft(r.left() - offset.x());
}
}
r = r.normalized();
r.setTopLeft(limitPointToRect(r.topLeft(), rect()));
r.setBottomRight(limitPointToRect(r.bottomRight(), rect()));
if (aspectRatioMod) {
if (mMouseOverHandle == &mBLHandle || mMouseOverHandle == &mBRHandle || mMouseOverHandle == &mLHandle || mMouseOverHandle == &mRHandle) {
r.setHeight(r.width());
} else {
r.setWidth(r.height());
}
}
mSelection = r;
}
if (mAcceptWidget) {
QPoint acceptPos = e->pos();
QRect acceptRect = QRect(acceptPos, QSize(120, 70));
// Prevent the widget from overlapping the handles
if (acceptRect.intersects(mTLHandle)) {
acceptPos = mTLHandle.bottomRight() + QPoint(2, 2); // Corner case
}
if (acceptRect.intersects(mBRHandle)) {
acceptPos = mBRHandle.bottomRight();
}
if (acceptRect.intersects(mBHandle)) {
acceptPos = mBHandle.bottomRight();
}
if (acceptRect.intersects(mRHandle)) {
acceptPos = mRHandle.topRight();
}
if (acceptRect.intersects(mTHandle)) {
acceptPos = mTHandle.bottomRight();
}
if ((acceptPos.x() + 120) > mScreenshot->pixmap().rect().width()) {
acceptPos.setX(acceptPos.x() - 120);
}
if ((acceptPos.y() + 70) > mScreenshot->pixmap().rect().height()) {
acceptPos.setY(acceptPos.y() - 70);
}
mAcceptWidget->move(acceptPos);
}
update();
} else {
if (mSelection.isNull()) {
mMouseMagnifier = true;
update();
return;
}
bool found = false;
foreach (QRect *r, mHandles) {
if (r->contains(e->pos())) {
mMouseOverHandle = r;
found = true;
break;
}
}
if (!found) {
mMouseOverHandle = 0;
if (mSelection.contains(e->pos())) {
setCursor(Qt::OpenHandCursor);
} else if (mAcceptWidget && QRect(mAcceptWidget->mapToParent(mAcceptWidget->pos()), QSize(100, 60)).contains(e->pos())) {
setCursor(Qt::PointingHandCursor);
} else {
setCursor(Qt::CrossCursor);
}
} else {
if (mMouseOverHandle == &mTLHandle || mMouseOverHandle == &mBRHandle) {
setCursor(Qt::SizeFDiagCursor);
}
if (mMouseOverHandle == &mTRHandle || mMouseOverHandle == &mBLHandle) {
setCursor(Qt::SizeBDiagCursor);
}
if (mMouseOverHandle == &mLHandle || mMouseOverHandle == &mRHandle) {
setCursor(Qt::SizeHorCursor);
}
if (mMouseOverHandle == &mTHandle || mMouseOverHandle == &mBHandle) {
setCursor(Qt::SizeVerCursor);
}
}
}
}
void AreaDialog::mousePressEvent(QMouseEvent *e)
{
mShowHelp = false;
mIdleTimer.stop();
if (mAcceptWidget) {
mAcceptWidget->hide();
}
if (e->button() == Qt::LeftButton) {
mMouseDown = true;
mDragStartPoint = e->pos();
mSelectionBeforeDrag = mSelection;
if (!mSelection.contains(e->pos())) {
mNewSelection = true;
mSelection = QRect();
mShowHelp = true;
setCursor(Qt::CrossCursor);
} else {
setCursor(Qt::ClosedHandCursor);
}
} else if (e->button() == Qt::RightButton
|| e->button() == Qt::MidButton) {
cancel();
}
update();
}
void AreaDialog::mouseReleaseEvent(QMouseEvent *e)
{
if (mAutoclose) {
grabRect();
}
if (!mSelection.isNull() && mAcceptWidget) {
mAcceptWidget->show();
}
mMouseDown = false;
mNewSelection = false;
mIdleTimer.start();
if (mMouseOverHandle == 0 && mSelection.contains(e->pos())) {
setCursor(Qt::OpenHandCursor);
}
update();
}
void AreaDialog::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
if (mGrabbing) { // grabWindow() should just get the background
return;
}
QPainter painter(this);
QPalette pal = palette();
QFont font = QToolTip::font();
QColor handleColor(85, 160, 188, 220);
QColor overlayColor(0, 0, 0, mOverlayAlpha);
QColor textColor = pal.color(QPalette::Active, QPalette::Text);
QColor textBackgroundColor = pal.color(QPalette::Active, QPalette::Base);
painter.drawPixmap(0, 0, mScreenshot->pixmap());
painter.setFont(font);
QRect r = mSelection.normalized().adjusted(0, 0, -1, -1);
QRegion grey(rect());
grey = grey.subtracted(r);
painter.setPen(handleColor);
painter.setBrush(overlayColor);
painter.setClipRegion(grey);
painter.drawRect(-1, -1, rect().width() + 1, rect().height() + 1);
painter.setClipRect(rect());
painter.setBrush(Qt::NoBrush);
painter.drawRect(r);
if (mShowHelp) {
//Drawing the explanatory text.
QRect helpRect = qApp->desktop()->screenGeometry(qApp->desktop()->primaryScreen());
QString helpTxt = tr("Lightscreen area mode:\nUse your mouse to draw a rectangle to capture.\nPress any key or right click to exit.");
helpRect.setHeight(qRound((float)(helpRect.height() / 10))); // We get a decently sized rect where the text should be drawn (centered)
// We draw the white contrasting background for the text, using the same text and options to get the boundingRect that the text will have.
painter.setPen(QPen(Qt::white));
painter.setBrush(QBrush(QColor(255, 255, 255, 180), Qt::SolidPattern));
QRectF bRect = painter.boundingRect(helpRect, Qt::AlignCenter, helpTxt);
// These four calls provide padding for the rect
bRect.setWidth(bRect.width() + 12);
bRect.setHeight(bRect.height() + 10);
bRect.setX(bRect.x() - 12);
bRect.setY(bRect.y() - 10);
painter.drawRoundedRect(bRect, 8, 8);
// Draw the text:
painter.setPen(QPen(Qt::black));
painter.drawText(helpRect, Qt::AlignCenter, helpTxt);
}
if (!mKeyboardSize.isEmpty()) {
QRect keyboardSizeRect = qApp->desktop()->screenGeometry(qApp->desktop()->primaryScreen());
QFont originalFont = painter.font();
QFont font = originalFont;
font.setPixelSize(16);
font.setBold(true);
painter.setFont(font);
painter.setPen(QPen(Qt::white));
painter.setBrush(QBrush(QColor(255, 255, 255, 180), Qt::SolidPattern));
QRectF textRect = painter.boundingRect(keyboardSizeRect, Qt::AlignLeft, mKeyboardSize);
textRect.setX(textRect.x() + 9);
textRect.setY(textRect.y() + 10);
textRect.setWidth(textRect.width() + 14);
textRect.setHeight(textRect.height() + 12);
painter.drawRect(textRect);
// Left-Right padding
textRect.setX(textRect.x() + 3);
textRect.setWidth(textRect.width() - 2);
painter.setPen(QPen(Qt::black));
painter.drawText(textRect, Qt::AlignCenter, mKeyboardSize, &textRect);
painter.setFont(originalFont); // Reset the font
}
if (!mSelection.isNull()) {
// The grabbed region is everything which is covered by the drawn
// rectangles (border included). This means that there is no 0px
// selection, since a 0px wide rectangle will always be drawn as a line.
QString txt = QString("%1x%2").arg(mSelection.width() == 0 ? 2 : mSelection.width())
.arg(mSelection.height() == 0 ? 2 : mSelection.height());
QRect textRect = painter.boundingRect(rect(), Qt::AlignLeft, txt);
QRect boundingRect = textRect.adjusted(-4, 0, 0, 0);
if (textRect.width() < r.width() - 2 * mHandleSize &&
textRect.height() < r.height() - 2 * mHandleSize &&
(r.width() > 100 && r.height() > 100)) { // center, unsuitable for small selections
boundingRect.moveCenter(r.center());
textRect.moveCenter(r.center());
} else if (r.y() - 3 > textRect.height() &&
r.x() + textRect.width() < rect().right()) { // on top, left aligned
boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3));
textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3));
} else if (r.x() - 3 > textRect.width()) { // left, top aligned
boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()));
textRect.moveTopRight(QPoint(r.x() - 5, r.y()));
} else if (r.bottom() + 3 + textRect.height() < rect().bottom() &&
r.right() > textRect.width()) { // at bottom, right aligned
boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3));
textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3));
} else if (r.right() + textRect.width() + 3 < rect().width()) { // right, bottom aligned
boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()));
textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()));
}
// if the above didn't catch it, you are running on a very tiny screen...
painter.setPen(textColor);
painter.setBrush(textBackgroundColor);
painter.drawRect(boundingRect);
painter.drawText(textRect, txt);
if ((r.height() > mHandleSize * 2 && r.width() > mHandleSize * 2)
|| !mMouseDown) {
updateHandles();
painter.setPen(handleColor);
handleColor.setAlpha(80);
painter.setBrush(handleColor);
painter.drawRects(handleMask().rects());
}
}
if (!mScreenshot->options().magnify) {
return;
}
// Drawing the magnified version
QPoint magStart, magEnd, drawPosition;
QRect newRect;
QRect pixmapRect = mScreenshot->pixmap().rect();
if (mMouseMagnifier) {
drawPosition = mMousePos - QPoint(100, 100);
magStart = mMousePos - QPoint(50, 50);
magEnd = mMousePos + QPoint(50, 50);
newRect = QRect(magStart, magEnd);
} else {
// So pretty.. oh so pretty.
if (mMouseOverHandle == &mTLHandle) {
magStart = mSelection.topLeft();
} else if (mMouseOverHandle == &mTRHandle) {
magStart = mSelection.topRight();
} else if (mMouseOverHandle == &mBLHandle) {
magStart = mSelection.bottomLeft();
} else if (mMouseOverHandle == &mBRHandle) {
magStart = mSelection.bottomRight();
} else if (mMouseOverHandle == &mLHandle) {
magStart = QPoint(mSelection.left(), mSelection.center().y());
} else if (mMouseOverHandle == &mTHandle) {
magStart = QPoint(mSelection.center().x(), mSelection.top());
} else if (mMouseOverHandle == &mRHandle) {
magStart = QPoint(mSelection.right(), mSelection.center().y());
} else if (mMouseOverHandle == &mBHandle) {
magStart = QPoint(mSelection.center().x(), mSelection.bottom());
} else if (mMouseOverHandle == 0) {
magStart = mMousePos;
}
magEnd = magStart;
drawPosition = mSelection.bottomRight();
magStart -= QPoint(48, 48);
magEnd += QPoint(48, 48);
newRect = QRect(magStart, magEnd);
if ((drawPosition.x() + newRect.width() * 2) > pixmapRect.width()) {
drawPosition.setX(drawPosition.x() - newRect.width() * 2);
}
if ((drawPosition.y() + newRect.height() * 2) > pixmapRect.height()) {
drawPosition.setY(drawPosition.y() - newRect.height() * 2);
}
if (drawPosition.y() == mSelection.bottomRight().y() - newRect.height() * 2
&& drawPosition.x() == mSelection.bottomRight().x() - newRect.width() * 2) {
painter.setOpacity(0.7);
}
}
if (!pixmapRect.contains(newRect, true) || drawPosition.x() <= 0 || drawPosition.y() <= 0) {
return;
}
QPixmap magnified = mScreenshot->pixmap().copy(newRect).scaled(QSize(newRect.width() * 2, newRect.height() * 2));
QPainter magPainter(&magnified);
magPainter.setPen(QPen(QBrush(QColor(35, 35, 35)), 2)); // Same border pen
magPainter.drawRect(magnified.rect());
if (!mMouseMagnifier) {
magPainter.setCompositionMode(QPainter::CompositionMode_Exclusion);
magPainter.setPen(QPen(QBrush(QColor(255, 255, 255, 180)), 1));
QRect magRect = magnified.rect();
magPainter.drawLine(QLine(magRect.left(), magRect.width()/2, magRect.right(), magRect.width()/2));
magPainter.drawLine(QLine(magRect.width()/2, 0, magRect.height()/2, magnified.height()));
}
painter.drawPixmap(drawPosition, magnified);
}
void AreaDialog::resizeEvent(QResizeEvent *e)
{
Q_UNUSED(e);
if (mSelection.isNull()) {
return;
}
QRect r = mSelection;
r.setTopLeft(limitPointToRect(r.topLeft(), rect()));
r.setBottomRight(limitPointToRect(r.bottomRight(), rect()));
if (r.width() <= 1 || r.height() <= 1) { //this just results in ugly drawing...
r = QRect();
}
mSelection = r;
}
void AreaDialog::showEvent(QShowEvent *e)
{
Q_UNUSED(e)
QRect geometry = qApp->desktop()->geometry();
if (mScreenshot->options().currentMonitor) {
geometry = qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(QCursor::pos()));
}
resize(geometry.size());
move(geometry.topLeft());
if (mScreenshot->options().animations) {
os::effect(this, SLOT(animationTick(int)), 85, 300);
} else {
animationTick(85);
}
setMouseTracking(true);
}
void AreaDialog::updateHandles()
{
QRect r = mSelection.normalized().adjusted(0, 0, -1, -1);
int s2 = mHandleSize / 2;
mTLHandle.moveTopLeft(r.topLeft());
mTRHandle.moveTopRight(r.topRight());
mBLHandle.moveBottomLeft(r.bottomLeft());
mBRHandle.moveBottomRight(r.bottomRight());
mLHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() / 2 - s2));
mTHandle.moveTopLeft(QPoint(r.x() + r.width() / 2 - s2, r.y()));
mRHandle.moveTopRight(QPoint(r.right(), r.y() + r.height() / 2 - s2));
mBHandle.moveBottomLeft(QPoint(r.x() + r.width() / 2 - s2, r.bottom()));
}
QRegion AreaDialog::handleMask() const
{
// note: not normalized QRects are bad here, since they will not be drawn
QRegion mask;
foreach(QRect * rect, mHandles) mask += QRegion(*rect);
return mask;
}
QPoint AreaDialog::limitPointToRect(const QPoint &p, const QRect &r) const
{
QPoint q;
q.setX(p.x() < r.x() ? r.x() : p.x() < r.right() ? p.x() : r.right());
q.setY(p.y() < r.y() ? r.y() : p.y() < r.bottom() ? p.y() : r.bottom());
return q;
}
diff --git a/dialogs/historydialog.cpp b/dialogs/historydialog.cpp
index 2577c07..1d653c9 100644
--- a/dialogs/historydialog.cpp
+++ b/dialogs/historydialog.cpp
@@ -1,289 +1,289 @@
-#include "historydialog.h"
+#include <dialogs/historydialog.h>
#include "ui_historydialog.h"
-#include "../tools/os.h"
-#include "../tools/uploader/uploader.h"
-#include "../tools/screenshotmanager.h"
+#include <tools/os.h>
+#include <tools/uploader/uploader.h>
+#include <tools/screenshotmanager.h>
#include <QClipboard>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QMenu>
#include <QMessageBox>
#include <QSettings>
#include <QSortFilterProxyModel>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlTableModel>
#include <QUrl>
HistoryDialog::HistoryDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::HistoryDialog),
mModel(Q_NULLPTR),
mFilterModel(Q_NULLPTR)
{
ui->setupUi(this);
ui->filterEdit->setText(tr("Filter.."));
ui->filterEdit->installEventFilter(this);
ui->cancelUploadButton->setIcon(os::icon("no"));
ui->tableView->setEnabled(false);
ui->clearButton->setEnabled(false);
connect(Uploader::instance(), &Uploader::progressChanged, this, &HistoryDialog::uploadProgress);
connect(Uploader::instance(), &Uploader::done , this, &HistoryDialog::refresh);
connect(ui->uploadButton , &QPushButton::clicked, this , &HistoryDialog::upload);
connect(ui->cancelUploadButton, &QPushButton::clicked, Uploader::instance() , &Uploader::cancel);
connect(ui->cancelUploadButton, &QPushButton::clicked, ui->uploadProgressWidget, &QWidget::hide);
connect(ui->clearButton, &QPushButton::clicked, this, &HistoryDialog::clear);
QTimer::singleShot(0, this, &HistoryDialog::init);
}
HistoryDialog::~HistoryDialog()
{
delete ui;
}
void HistoryDialog::clear()
{
if (QMessageBox::question(this,
tr("Clearing the screenshot history"),
tr("Are you sure you want to clear your entire screenshot history?\nThis cannot be undone."),
tr("Clear History"),
tr("Don't Clear")) == 1) {
return;
}
ScreenshotManager::instance()->clearHistory();
mModel->select();
ui->filterEdit->setEnabled(false);
ui->tableView->setEnabled(false);
ui->clearButton->setEnabled(false);
}
void HistoryDialog::contextMenu(const QPoint &point)
{
mContextIndex = ui->tableView->indexAt(point);
QMenu contextMenu(ui->tableView);
QAction copyAction((mContextIndex.column() == 0) ? tr("Copy Path") : tr("Copy URL"), &contextMenu);
connect(&copyAction, &QAction::triggered, this, &HistoryDialog::copy);
contextMenu.addAction(&copyAction);
QAction deleteAction(tr("Delete from imgur.com"), &contextMenu);
QAction locationAction(tr("Open Location"), &contextMenu);
QAction removeAction(tr("Remove history entry"), &contextMenu);
if (mContextIndex.data().toString().isEmpty()) {
copyAction.setEnabled(false);
deleteAction.setEnabled(false);
}
if (mContextIndex.column() == 0) {
connect(&locationAction, &QAction::triggered, this, &HistoryDialog::location);
contextMenu.addAction(&locationAction);
} else {
connect(&deleteAction, &QAction::triggered, this, &HistoryDialog::deleteImage);
contextMenu.addAction(&deleteAction);
}
connect(&removeAction, &QAction::triggered, this, &HistoryDialog::removeHistoryEntry);
contextMenu.addAction(&removeAction);
contextMenu.exec(QCursor::pos());
}
void HistoryDialog::copy()
{
qApp->clipboard()->setText(mContextIndex.data().toString());
}
void HistoryDialog::deleteImage()
{
QDesktopServices::openUrl(mContextIndex.sibling(mContextIndex.row(), 2).data().toString());
}
void HistoryDialog::location()
{
QDesktopServices::openUrl("file:///" + QFileInfo(mContextIndex.data().toString()).absolutePath());
}
void HistoryDialog::removeHistoryEntry()
{
if (mContextIndex.column() == 0) {
// File got right clicked:
ScreenshotManager::instance()->removeHistory(mContextIndex.data().toString(), mContextIndex.sibling(mContextIndex.row(), 3).data().toLongLong());
} else {
// Screenshot URL got right clicked:
ScreenshotManager::instance()->removeHistory(mContextIndex.sibling(mContextIndex.row(), 0).data().toString(), mContextIndex.sibling(mContextIndex.row(), 3).data().toLongLong());
}
refresh();
}
void HistoryDialog::refresh()
{
mModel->select();
}
void HistoryDialog::openUrl(const QModelIndex &index)
{
if (index.column() == 0) {
QDesktopServices::openUrl(QUrl("file:///" + index.data().toString()));
} else {
QDesktopServices::openUrl(index.data().toUrl());
}
}
void HistoryDialog::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
Q_UNUSED(deselected);
if (selected.indexes().count() == 0) {
return;
}
QModelIndex index = selected.indexes().at(0);
QString screenshot;
if (index.column() == 0) {
screenshot = index.data().toString();
} else {
screenshot = ui->tableView->model()->index(index.row(), 0).data().toString();
}
mSelectedScreenshot = screenshot;
ui->uploadButton->setEnabled(QFile::exists(screenshot));
}
void HistoryDialog::upload()
{
Uploader::instance()->upload(mSelectedScreenshot, ScreenshotManager::instance()->settings()->value("options/upload/service", "imgur").toString());
ui->uploadProgressWidget->setVisible(true);
}
void HistoryDialog::uploadProgress(int progress)
{
ui->uploadProgressWidget->setVisible(true);
ui->uploadProgressBar->setValue(progress);
}
void HistoryDialog::init()
{
ScreenshotManager::instance()->initHistory();
if (QSqlDatabase::database().isOpen()) {
setUpdatesEnabled(false);
mModel = new QSqlTableModel(this);
mModel->setTable("history");
mModel->setHeaderData(0, Qt::Horizontal, tr("Screenshot"));
mModel->setHeaderData(1, Qt::Horizontal, tr("URL"));
mModel->select();
mFilterModel = new QSortFilterProxyModel(mModel);
mFilterModel->setSourceModel(mModel);
mFilterModel->setDynamicSortFilter(true);
mFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
mFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mFilterModel->setFilterKeyColumn(-1);
mFilterModel->sort(3, Qt::DescendingOrder);
while (mModel->canFetchMore()) {
mModel->fetchMore();
qApp->processEvents();
}
ui->tableView->setWordWrap(false);
ui->tableView->setModel(mFilterModel);
ui->tableView->hideColumn(2); // No delete hash.
ui->tableView->hideColumn(3); // No timestamp.
ui->tableView->horizontalHeader()->setSectionsClickable(false);
ui->tableView->horizontalHeader()->setSectionsMovable(false);
ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
ui->tableView->verticalHeader()->hide();
ui->tableView->setTextElideMode(Qt::ElideLeft);
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableView->setAlternatingRowColors(true);
ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
ui->tableView->setSortingEnabled(false);
if (ui->tableView->model()->rowCount() > 0) {
ui->tableView->setEnabled(true);
ui->clearButton->setEnabled(true);
ui->filterEdit->setEnabled(true);
}
connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &HistoryDialog::selectionChanged);
connect(ui->tableView, &QTableView::doubleClicked, this, &HistoryDialog::openUrl);
connect(ui->tableView, &QTableView::customContextMenuRequested, this, &HistoryDialog::contextMenu);
setUpdatesEnabled(true);
}
if (Uploader::instance()->progress() > 0) {
ui->uploadProgressBar->setValue(Uploader::instance()->progress());
} else {
ui->uploadProgressWidget->setVisible(false);
}
ui->closeButton->setFocus();
}
bool HistoryDialog::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->filterEdit && mFilterModel) {
if (event->type() == QEvent::FocusIn) {
if (ui->filterEdit->text() == tr("Filter..")) {
ui->filterEdit->setStyleSheet("");
ui->filterEdit->setText("");
mFilterModel->setFilterWildcard("");
mFilterModel->sort(3, Qt::DescendingOrder);
}
} else if (event->type() == QEvent::FocusOut) {
if (ui->filterEdit->text().isEmpty()) {
ui->filterEdit->setStyleSheet("color: palette(mid);");
ui->filterEdit->setText(tr("Filter.."));
mFilterModel->sort(3, Qt::DescendingOrder);
}
} else if (event->type() == QEvent::KeyRelease) {
if (ui->filterEdit->text() != tr("Filter..") && !ui->filterEdit->text().isEmpty()) {
mFilterModel->setFilterWildcard(ui->filterEdit->text());
mFilterModel->sort(3, Qt::DescendingOrder);
} else {
mFilterModel->setFilterWildcard("");
mFilterModel->sort(3, Qt::DescendingOrder);
}
}
}
return QDialog::eventFilter(object, event);
}
bool HistoryDialog::event(QEvent *event)
{
if (event->type() == QEvent::Show) {
restoreGeometry(ScreenshotManager::instance()->settings()->value("geometry/historyDialog").toByteArray());
} else if (event->type() == QEvent::Close) {
ScreenshotManager::instance()->settings()->setValue("geometry/historyDialog", saveGeometry());
}
return QDialog::event(event);
}
diff --git a/dialogs/namingdialog.cpp b/dialogs/namingdialog.cpp
index 8822d9b..a9ed01f 100644
--- a/dialogs/namingdialog.cpp
+++ b/dialogs/namingdialog.cpp
@@ -1,84 +1,84 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include "namingdialog.h"
-#include "../tools/screenshot.h"
-#include "../tools/os.h"
-#include "../tools/screenshotmanager.h"
+#include <dialogs/namingdialog.h>
+#include <tools/screenshot.h>
+#include <tools/os.h>
+#include <tools/screenshotmanager.h>
#include <QDesktopServices>
#include <QKeyEvent>
#include <QSettings>
#include <QUrl>
NamingDialog::NamingDialog(Screenshot::Naming naming, QWidget *parent) :
QDialog(parent)
{
ui.setupUi(this);
setModal(true);
setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
ui.dateFormatComboBox->installEventFilter(this);
// Settings
QSettings *settings = ScreenshotManager::instance()->settings();
ui.flipNamingCheckBox->setChecked(settings->value("options/flip", false).toBool());
ui.dateFormatComboBox->setCurrentIndex(
ui.dateFormatComboBox->findText(settings->value("options/naming/dateFormat", "yyyy-MM-dd").toString())
);
if (ui.dateFormatComboBox->currentIndex() == -1) {
ui.dateFormatComboBox->addItem(settings->value("options/naming/dateFormat", "yyyy-MM-dd").toString());
ui.dateFormatComboBox->setCurrentIndex(ui.dateFormatComboBox->count() - 1);
}
ui.leadingZerosSpinBox->setValue(settings->value("options/naming/leadingZeros", 0).toInt());
// Signals/Slots
connect(ui.buttonBox , &QDialogButtonBox::accepted, this, [&] {
settings->setValue("options/flip" , ui.flipNamingCheckBox->isChecked());
settings->setValue("options/naming/dateFormat" , ui.dateFormatComboBox->currentText());
settings->setValue("options/naming/leadingZeros", ui.leadingZerosSpinBox->value());
});
connect(ui.dateHelpLabel, &QLabel::linkActivated, this, [](const QUrl &url) {
QDesktopServices::openUrl(QUrl(url));
});
// Stack & window size adjustments
ui.stack->setCurrentIndex((int)naming);
ui.stack->currentWidget()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
resize(minimumSizeHint());
}
bool NamingDialog::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::KeyPress
&& object == ui.dateFormatComboBox) {
QKeyEvent *keyEvent = (QKeyEvent *)(event);
if (QRegExp("[?:\\\\/*\"<>|]").exactMatch(keyEvent->text())) {
event->ignore();
return true;
}
}
return QDialog::eventFilter(object, event);
}
diff --git a/dialogs/namingdialog.h b/dialogs/namingdialog.h
index 48c01f3..f549908 100644
--- a/dialogs/namingdialog.h
+++ b/dialogs/namingdialog.h
@@ -1,41 +1,41 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef NAMINGDIALOG_H
#define NAMINGDIALOG_H
+#include <tools/screenshot.h>
#include "ui_namingdialog.h"
-#include "../tools/screenshot.h"
#include <QUrl>
class NamingDialog : public QDialog
{
Q_OBJECT
public:
explicit NamingDialog(Screenshot::Naming naming, QWidget *parent = 0);
protected:
bool eventFilter(QObject *object, QEvent *event);
private:
Ui::NamingDialog ui;
};
#endif // NAMINGDIALOG_H
diff --git a/dialogs/optionsdialog.cpp b/dialogs/optionsdialog.cpp
index ab82c57..406f6a6 100644
--- a/dialogs/optionsdialog.cpp
+++ b/dialogs/optionsdialog.cpp
@@ -1,861 +1,863 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QToolTip>
#include <QCompleter>
#include <QDate>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDirModel>
#include <QFileDialog>
#include <QKeyEvent>
#include <QMessageBox>
#include <QProcess>
#include <QSettings>
#include <QTimer>
#include <QUrl>
#include <QInputDialog>
#include <QMenu>
#include <QAction>
#include <QFutureWatcher>
#include <QtConcurrent>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
-#include "optionsdialog.h"
-#include "namingdialog.h"
-#include "historydialog.h"
-#include "../tools/os.h"
-#include "../tools/screenshot.h"
-#include "../tools/screenshotmanager.h"
-#include "../tools/uploader/uploader.h"
-#include "../updater/updater.h"
+#include <dialogs/optionsdialog.h>
+#include <dialogs/namingdialog.h>
+#include <dialogs/historydialog.h>
+
+#include <tools/os.h>
+#include <tools/screenshot.h>
+#include <tools/screenshotmanager.h>
+#include <tools/uploader/uploader.h>
+
+#include <updater/updater.h>
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent)
{
ui.setupUi(this);
setModal(true);
#if defined(Q_OS_LINUX)
// KDE-specific style tweaks.
if (qApp->style()->objectName() == "oxygen") {
ui.browsePushButton->setMaximumWidth(30);
ui.namingOptionsButton->setMaximumWidth(30);
ui.fileGroupBox->setFlat(false);
ui.startupGroupBox->setFlat(false);
ui.capturesGroupBox->setFlat(false);
ui.controlGroupBox->setFlat(false);
ui.interfaceGroupBox->setFlat(false);
ui.screenshotsGroupBox->setFlat(false);
ui.previewGroupBox->setFlat(false);
ui.updaterGroupBox->setFlat(false);
ui.historyGroupBox->setFlat(false);
ui.clipboardGroupBox->setFlat(false);
ui.optionsTab->layout()->setContentsMargins(0, 0, 6, 0);
ui.aboutTab->layout()->setMargin(8);
}
#endif
setEnabled(false); // We disable the widgets to prevent any user interaction until the settings have loaded.
QMetaObject::invokeMethod(this, "init" , Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "loadSettings", Qt::QueuedConnection);
}
void OptionsDialog::accepted()
{
if (hotkeyCollision()) {
QMessageBox::critical(this, tr("Hotkey conflict"), tr("You have assigned the same hotkeys to more than one action."));
return;
}
if (ui.prefixLineEdit->text().contains(QRegExp("[?:\\\\/*\"<>|]"))) {
QMessageBox::critical(this, tr("Filename character error"), tr("The filename can't contain any of the following characters: ? : \\ / * \" < > |"));
return;
}
if (!ui.fileGroupBox->isChecked() && !ui.clipboardCheckBox->isChecked()) {
QMessageBox::critical(this, tr("Final Destination"), tr("You can't take screenshots unless you enable either file saving or the clipboard."));
return;
}
saveSettings();
accept();
}
void OptionsDialog::checkUpdatesNow()
{
Updater updater;
updater.checkWithFeedback();
}
void OptionsDialog::exportSettings()
{
QString exportFileName = QFileDialog::getSaveFileName(this,
tr("Export Settings"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + "config.ini",
tr("Lightscreen Settings (*.ini)"));
if (exportFileName.isEmpty()) {
return;
}
if (QFile::exists(exportFileName)) {
QFile::remove(exportFileName);
}
QSettings exportedSettings(exportFileName, QSettings::IniFormat);
for (auto key : settings()->allKeys()) {
exportedSettings.setValue(key, settings()->value(key));
}
}
void OptionsDialog::importSettings()
{
QString importFileName = QFileDialog::getOpenFileName(this,
tr("Import Settings"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
tr("Lightscreen Settings (*.ini)"));
QSettings importedSettings(importFileName, QSettings::IniFormat);
saveSettings();
for (auto key : importedSettings.allKeys()) {
if (settings()->contains(key)) {
settings()->setValue(key, importedSettings.value(key));
}
}
loadSettings();
}
void OptionsDialog::loadSettings()
{
settings()->sync();
setUpdatesEnabled(false);
if (!settings()->contains("file/format")) {
// If there are no settings, get rid of the cancel button so that the user is forced to save them
ui.buttonBox->clear();
ui.buttonBox->addButton(QDialogButtonBox::Ok);
}
ui.startupCheckBox->toggle();
ui.trayCheckBox->toggle();
ui.previewAutocloseCheckBox->toggle();
QString targetDefault;
if (ScreenshotManager::instance()->portableMode()) {
targetDefault = tr("Screenshots");
} else {
targetDefault = os::getDocumentsPath() + QDir::separator() + tr("Screenshots");
}
settings()->beginGroup("file");
ui.formatComboBox->setCurrentIndex(settings()->value("format", 1).toInt());
ui.prefixLineEdit->setText(settings()->value("prefix", tr("screenshot.")).toString());
ui.namingComboBox->setCurrentIndex(settings()->value("naming", 0).toInt());
ui.targetLineEdit->setText(settings()->value("target", targetDefault).toString());
ui.fileGroupBox->setChecked(settings()->value("enabled", true).toBool());
settings()->endGroup();
settings()->beginGroup("options");
ui.startupCheckBox->setChecked(settings()->value("startup", false).toBool());
ui.startupHideCheckBox->setChecked(settings()->value("startupHide", true).toBool());
ui.hideCheckBox->setChecked(settings()->value("hide", true).toBool());
ui.delaySpinBox->setValue(settings()->value("delay", 0).toInt());
flipToggled(settings()->value("flip", false).toBool());
ui.trayCheckBox->setChecked(settings()->value("tray", true).toBool());
ui.messageCheckBox->setChecked(settings()->value("message", true).toBool());
ui.qualitySlider->setValue(settings()->value("quality", 100).toInt());
ui.playSoundCheckBox->setChecked(settings()->value("playSound", false).toBool());
ui.updaterCheckBox->setChecked(!settings()->value("disableUpdater", false).toBool());
ui.telemetryCheckBox->setChecked(settings()->value("telemetry", false).toBool());
ui.magnifyCheckBox->setChecked(settings()->value("magnify", false).toBool());
ui.cursorCheckBox->setChecked(settings()->value("cursor", true).toBool());
ui.saveAsCheckBox->setChecked(settings()->value("saveAs", false).toBool());
ui.previewGroupBox->setChecked(settings()->value("preview", false).toBool());
ui.previewSizeSpinBox->setValue(settings()->value("previewSize", 300).toInt());
ui.previewPositionComboBox->setCurrentIndex(settings()->value("previewPosition", 3).toInt());
ui.previewAutocloseCheckBox->setChecked(settings()->value("previewAutoclose", false).toBool());
ui.previewAutocloseTimeSpinBox->setValue(settings()->value("previewAutocloseTime", 15).toInt());
ui.previewAutocloseActionComboBox->setCurrentIndex(settings()->value("previewAutocloseAction", 0).toInt());
ui.previewDefaultActionComboBox->setCurrentIndex(settings()->value("previewDefaultAction", 0).toInt());
ui.areaAutocloseCheckBox->setChecked(settings()->value("areaAutoclose", false).toBool());
// History mode is neat for normal operation but I'll keep it disabled by default on portable mode.
ui.historyCheckBox->setChecked(settings()->value("history", (ScreenshotManager::instance()->portableMode()) ? false : true).toBool());
// Advanced
ui.clipboardCheckBox->setChecked(settings()->value("clipboard", true).toBool());
ui.urlClipboardCheckBox->setChecked(settings()->value("urlClipboard", false).toBool());
ui.optiPngCheckBox->setChecked(settings()->value("optimize", false).toBool());
ui.closeHideCheckBox->setChecked(settings()->value("closeHide", true).toBool());
ui.currentMonitorCheckBox->setChecked(settings()->value("currentMonitor", false).toBool());
ui.replaceCheckBox->setChecked(settings()->value("replace", false).toBool());
ui.uploadCheckBox->setChecked(settings()->value("uploadAuto", false).toBool());
#ifdef Q_OS_WIN
if (!QFile::exists(qApp->applicationDirPath() + QDir::separator() + "optipng.exe")) {
ui.optiPngCheckBox->setEnabled(false);
ui.optiPngLabel->setText("optipng.exe not found");
}
#elif defined(Q_OS_LINUX)
if (!QProcess::startDetached("optipng")) {
ui.optiPngCheckBox->setChecked(false);
ui.optiPngCheckBox->setEnabled(false);
ui.optiPngLabel->setText(tr("Install 'OptiPNG'"));
}
//TODO: Sound cue support on Linux
ui.playSoundCheckBox->setVisible(false);
ui.playSoundCheckBox->setChecked(false);
//TODO: Cursor support on X11
ui.cursorCheckBox->setVisible(false);
ui.cursorCheckBox->setChecked(false);
#endif
settings()->endGroup();
settings()->beginGroup("actions");
// This toggle is for the first run
ui.screenCheckBox->toggle();
ui.areaCheckBox->toggle();
ui.windowCheckBox->toggle();
ui.windowPickerCheckBox->toggle();
ui.openCheckBox->toggle();
ui.directoryCheckBox->toggle();
settings()->beginGroup("screen");
ui.screenCheckBox->setChecked(settings()->value("enabled", true).toBool());
ui.screenHotkeyWidget->setHotkey(settings()->value("hotkey", "Print").toString());
settings()->endGroup();
settings()->beginGroup("area");
ui.areaCheckBox->setChecked(settings()->value("enabled").toBool());
ui.areaHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+Print").toString());
settings()->endGroup();
settings()->beginGroup("window");
ui.windowCheckBox->setChecked(settings()->value("enabled").toBool());
ui.windowHotkeyWidget->setHotkey(settings()->value("hotkey", "Alt+Print").toString());
settings()->endGroup();
settings()->beginGroup("windowPicker");
ui.windowPickerCheckBox->setChecked(settings()->value("enabled").toBool());
ui.windowPickerHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+Alt+Print").toString());
settings()->endGroup();
settings()->beginGroup("open");
ui.openCheckBox->setChecked(settings()->value("enabled").toBool());
ui.openHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+PgUp").toString());
settings()->endGroup();
settings()->beginGroup("directory");
ui.directoryCheckBox->setChecked(settings()->value("enabled").toBool());
ui.directoryHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+PgDown").toString());
settings()->endGroup();
settings()->endGroup();
settings()->beginGroup("upload");
ui.uploadServiceComboBox->setCurrentIndex(settings()->value("service").toInt());
settings()->beginGroup("imgur");
ui.imgurOptions->setUser(settings()->value("account_username", "").toString());
settings()->endGroup();
settings()->beginGroup("pomf");
// TODO: Move to pomfuploader in a more generic way.
QString pomf_url = settings()->value("pomf_url", "").toString();
if (!pomf_url.isEmpty()) {
if (ui.pomfOptions->ui.pomfUrlComboBox->findText(pomf_url, Qt::MatchFixedString) == -1) {
ui.pomfOptions->ui.pomfUrlComboBox->addItem(pomf_url);
}
ui.pomfOptions->ui.pomfUrlComboBox->setCurrentText(settings()->value("pomf_url", "").toString());
ui.pomfOptions->ui.verifyButton->setEnabled(!settings()->value("pomf_url", "").toString().isEmpty());
}
settings()->endGroup();
settings()->endGroup();
QTimer::singleShot(0, this, &OptionsDialog::updatePreview);
setEnabled(true);
setUpdatesEnabled(true);
}
void OptionsDialog::openUrl(QString url)
{
if (url == "#aboutqt") {
qApp->aboutQt();
} else {
QDesktopServices::openUrl(QUrl(url));
}
}
void OptionsDialog::saveSettings()
{
settings()->beginGroup("file");
settings()->setValue("format", ui.formatComboBox->currentIndex());
settings()->setValue("prefix", ui.prefixLineEdit->text());
settings()->setValue("naming", ui.namingComboBox->currentIndex());
settings()->setValue("target", ui.targetLineEdit->text());
settings()->setValue("enabled", ui.fileGroupBox->isChecked());
settings()->endGroup();
settings()->beginGroup("options");
settings()->setValue("startup", ui.startupCheckBox->isChecked());
settings()->setValue("startupHide", ui.startupHideCheckBox->isChecked());
settings()->setValue("hide", ui.hideCheckBox->isChecked());
settings()->setValue("delay", ui.delaySpinBox->value());
settings()->setValue("tray", ui.trayCheckBox->isChecked());
settings()->setValue("message", ui.messageCheckBox->isChecked());
settings()->setValue("quality", ui.qualitySlider->value());
settings()->setValue("playSound", ui.playSoundCheckBox->isChecked());
// This settings is inverted because the first iteration of the Updater did not have a settings but instead relied on the messagebox choice of the user.
settings()->setValue("disableUpdater", !ui.updaterCheckBox->isChecked());
settings()->setValue("telemetry", ui.telemetryCheckBox->isChecked());
settings()->setValue("magnify", ui.magnifyCheckBox->isChecked());
settings()->setValue("cursor", ui.cursorCheckBox->isChecked());
settings()->setValue("saveAs", ui.saveAsCheckBox->isChecked());
settings()->setValue("preview", ui.previewGroupBox->isChecked());
settings()->setValue("previewSize", ui.previewSizeSpinBox->value());
settings()->setValue("previewPosition", ui.previewPositionComboBox->currentIndex());
settings()->setValue("previewAutoclose", ui.previewAutocloseCheckBox->isChecked());
settings()->setValue("previewAutocloseTime", ui.previewAutocloseTimeSpinBox->value());
settings()->setValue("previewAutocloseAction", ui.previewAutocloseActionComboBox->currentIndex());
settings()->setValue("previewDefaultAction", ui.previewDefaultActionComboBox->currentIndex());
settings()->setValue("areaAutoclose", ui.areaAutocloseCheckBox->isChecked());
settings()->setValue("history", ui.historyCheckBox->isChecked());
// Advanced
settings()->setValue("closeHide", ui.closeHideCheckBox->isChecked());
settings()->setValue("clipboard", ui.clipboardCheckBox->isChecked());
settings()->setValue("urlClipboard", ui.urlClipboardCheckBox->isChecked());
settings()->setValue("optimize", ui.optiPngCheckBox->isChecked());
settings()->setValue("currentMonitor", ui.currentMonitorCheckBox->isChecked());
settings()->setValue("replace", ui.replaceCheckBox->isChecked());
//Upload
settings()->setValue("uploadAuto", ui.uploadCheckBox->isChecked());
settings()->endGroup();
settings()->beginGroup("actions");
settings()->beginGroup("screen");
settings()->setValue("enabled", ui.screenCheckBox->isChecked());
settings()->setValue("hotkey" , ui.screenHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("area");
settings()->setValue("enabled", ui.areaCheckBox->isChecked());
settings()->setValue("hotkey" , ui.areaHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("window");
settings()->setValue("enabled", ui.windowCheckBox->isChecked());
settings()->setValue("hotkey" , ui.windowHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("windowPicker");
settings()->setValue("enabled", ui.windowPickerCheckBox->isChecked());
settings()->setValue("hotkey" , ui.windowPickerHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("open");
settings()->setValue("enabled", ui.openCheckBox->isChecked());
settings()->setValue("hotkey" , ui.openHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("directory");
settings()->setValue("enabled", ui.directoryCheckBox->isChecked());
settings()->setValue("hotkey" , ui.directoryHotkeyWidget->hotkey());
settings()->endGroup();
settings()->endGroup();
settings()->beginGroup("upload");
settings()->setValue("service", ui.uploadServiceComboBox->currentIndex());
settings()->beginGroup("imgur");
settings()->setValue("anonymous", settings()->value("account_username").toString().isEmpty());
settings()->setValue("album" , ui.imgurOptions->ui.albumComboBox->property("currentData").toString());
settings()->endGroup();
settings()->beginGroup("pomf");
settings()->setValue("pomf_url", ui.pomfOptions->ui.pomfUrlComboBox->currentText());
settings()->endGroup();
settings()->endGroup();
}
void OptionsDialog::updatePreview()
{
Screenshot::NamingOptions options;
options.naming = (Screenshot::Naming) ui.namingComboBox->currentIndex();
options.flip = settings()->value("options/flip", false).toBool();
options.leadingZeros = settings()->value("options/naming/leadingZeros", 0).toInt();
options.dateFormat = settings()->value("options/naming/dateFormat", "yyyy-MM-dd").toString();
if (ui.fileGroupBox->isChecked()) { // Only change the naming button when file options are enabled.
ui.namingOptionsButton->setDisabled((options.naming == Screenshot::Empty));
}
QString preview = Screenshot::getName(options,
ui.prefixLineEdit->text(),
QDir(ui.targetLineEdit->text()));
preview = QString("%1.%2").arg(preview).arg(ui.formatComboBox->currentText().toLower());
if (preview.length() >= 40) {
preview.truncate(37);
preview.append("...");
}
ui.previewLabel->setText(preview);
ui.qualitySlider->setEnabled(ui.formatComboBox->currentText() != "PNG");
ui.qualityLabel->setEnabled(ui.qualitySlider->isEnabled());
}
void OptionsDialog::viewHistory()
{
HistoryDialog historyDialog(this);
historyDialog.exec();
}
//
bool OptionsDialog::event(QEvent *event)
{
if (event->type() == QEvent::Close || event->type() == QEvent::Hide) {
settings()->setValue("geometry/optionsDialog", saveGeometry());
if (!settings()->contains("file/format")) {
// I'm afraid I can't let you do that, Dave.
event->ignore();
return false;
}
} else if (event->type() == QEvent::Show) {
if (settings()->contains("geometry/optionsDialog")) {
restoreGeometry(settings()->value("geometry/optionsDialog").toByteArray());
} else {
move(QApplication::desktop()->screenGeometry(this).center() - rect().center());
}
}
return QDialog::event(event);
}
#ifdef Q_OS_WIN
// Qt does not send the print screen key as a regular QKeyPress event, so we must use the Windows API
bool OptionsDialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
if (eventType == "windows_generic_MSG") {
MSG *m = static_cast<MSG *>(message);
if ((m->message == WM_KEYUP || m->message == WM_SYSKEYUP) && m->wParam == VK_SNAPSHOT) {
qApp->postEvent(qApp->focusWidget(), new QKeyEvent(QEvent::KeyPress, Qt::Key_Print, qApp->queryKeyboardModifiers()));
}
}
return QDialog::nativeEvent(eventType, message, result);
}
#endif
//
void OptionsDialog::browse()
{
QString fileName = QFileDialog::getExistingDirectory(this,
tr("Select where you want to save the screenshots"),
ui.targetLineEdit->text());
if (fileName.isEmpty()) {
return;
}
ui.targetLineEdit->setText(fileName);
updatePreview();
}
void OptionsDialog::dialogButtonClicked(QAbstractButton *button)
{
if (ui.buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) {
QPushButton *pb = qobject_cast<QPushButton *>(button);
pb->showMenu();
}
}
void OptionsDialog::restoreDefaults()
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen - Restore Default Options"));
msgBox.setText(tr("Restoring the default options will cause you to lose all of your current configuration."));
msgBox.setIcon(QMessageBox::Warning);
msgBox.addButton(tr("Restore"), QMessageBox::ActionRole);
QPushButton *dontRestoreButton = msgBox.addButton(tr("Don't Restore"), QMessageBox::ActionRole);
msgBox.setDefaultButton(dontRestoreButton);
msgBox.exec();
if (msgBox.clickedButton() == dontRestoreButton) {
return;
}
settings()->clear();
loadSettings();
}
void OptionsDialog::flipToggled(bool checked)
{
setUpdatesEnabled(false);
ui.filenameLayout->removeWidget(ui.prefixLineEdit);
ui.filenameLayout->removeWidget(ui.namingComboBox);
if (checked) {
ui.filenameLayout->addWidget(ui.namingComboBox);
ui.filenameLayout->addWidget(ui.prefixLineEdit);
} else {
ui.filenameLayout->addWidget(ui.prefixLineEdit);
ui.filenameLayout->addWidget(ui.namingComboBox);
}
if (ui.prefixLineEdit->text() == tr("screenshot.")
&& checked) {
ui.prefixLineEdit->setText(tr(".screenshot"));
}
if (ui.prefixLineEdit->text() == tr(".screenshot")
&& !checked) {
ui.prefixLineEdit->setText(tr("screenshot."));
}
setUpdatesEnabled(true); // Avoids flicker
}
void OptionsDialog::init()
{
// Make the scroll area share the Tab Widget background color
ui.optionsScrollArea->setStyleSheet("QScrollArea { background-color: transparent; } #scrollAreaWidgetContents { background-color: transparent; }");
ui.browsePushButton->setIcon(os::icon("folder"));
ui.namingOptionsButton->setIcon(os::icon("configure"));
// Export/Import menu .
QMenu *optionsMenu = new QMenu(tr("Options"));
QAction *exportAction = new QAction(tr("&Export.."), optionsMenu);
connect(exportAction, &QAction::triggered, this, &OptionsDialog::exportSettings);
QAction *importAction = new QAction(tr("&Import.."), optionsMenu);
connect(importAction, &QAction::triggered, this, &OptionsDialog::importSettings);
QAction *restoreAction = new QAction(tr("&Restore Defaults"), optionsMenu);
connect(restoreAction, &QAction::triggered, this, &OptionsDialog::restoreDefaults);
optionsMenu->addAction(exportAction);
optionsMenu->addAction(importAction);
optionsMenu->addSeparator();
optionsMenu->addAction(restoreAction);
QPushButton *optionsButton = new QPushButton(tr("Options"), this);
optionsButton->setMenu(optionsMenu);
ui.buttonBox->addButton(optionsButton, QDialogButtonBox::ResetRole);
// Set up the autocomplete for the directory.
QCompleter *completer = new QCompleter(this);
completer->setModel(new QDirModel(QStringList(), QDir::Dirs, QDir::Name, completer));
ui.targetLineEdit->setCompleter(completer);
// HotkeyWidget icons.
ui.screenHotkeyWidget->setIcon(os::icon("screen"));
ui.windowHotkeyWidget->setIcon(os::icon("window"));
ui.windowPickerHotkeyWidget->setIcon(os::icon("pickWindow"));
ui.areaHotkeyWidget->setIcon(os::icon("area"));
ui.openHotkeyWidget->setIcon(QIcon(":/icons/lightscreen.small"));
ui.directoryHotkeyWidget->setIcon(os::icon("folder"));
// Version
ui.versionLabel->setText(tr("Version %1").arg(qApp->applicationVersion()));
ui.uploadSslWarningLabel->setVisible(false);
// Run the SSL check in another thread (slows down dialog startup considerably).
auto futureWatcher = new QFutureWatcher<bool>(this);
connect(futureWatcher, &QFutureWatcher<bool>::finished, futureWatcher, &QFutureWatcher<bool>::deleteLater);
connect(futureWatcher, &QFutureWatcher<bool>::finished, this, [&, futureWatcher] {
ui.uploadSslWarningLabel->setVisible(!futureWatcher->future().result());
});
futureWatcher->setFuture(QtConcurrent::run([]() -> bool { return QSslSocket::supportsSsl(); }));
//
// Connections
//
connect(ui.buttonBox, &QDialogButtonBox::clicked , this, &OptionsDialog::dialogButtonClicked);
connect(ui.buttonBox, &QDialogButtonBox::accepted , this, &OptionsDialog::accepted);
connect(ui.namingOptionsButton, &QPushButton::clicked, this, &OptionsDialog::namingOptions);
connect(ui.prefixLineEdit, &QLineEdit::textEdited, this, &OptionsDialog::updatePreview);
connect(ui.formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OptionsDialog::updatePreview);
connect(ui.namingComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &OptionsDialog::updatePreview);
connect(ui.browsePushButton , &QPushButton::clicked, this, &OptionsDialog::browse);
connect(ui.checkUpdatesPushButton , &QPushButton::clicked, this, &OptionsDialog::checkUpdatesNow);
connect(ui.historyPushButton , &QPushButton::clicked, this, &OptionsDialog::viewHistory);
connect(ui.windowPickerCheckBox, &QCheckBox::toggled, ui.windowPickerHotkeyWidget, &HotkeyWidget::setEnabled);
connect(ui.screenCheckBox , &QCheckBox::toggled, ui.screenHotkeyWidget , &HotkeyWidget::setEnabled);
connect(ui.areaCheckBox , &QCheckBox::toggled, ui.areaHotkeyWidget , &HotkeyWidget::setEnabled);
connect(ui.windowCheckBox , &QCheckBox::toggled, ui.windowHotkeyWidget , &HotkeyWidget::setEnabled);
connect(ui.openCheckBox , &QCheckBox::toggled, ui.openHotkeyWidget , &HotkeyWidget::setEnabled);
connect(ui.directoryCheckBox , &QCheckBox::toggled, ui.directoryHotkeyWidget, &HotkeyWidget::setEnabled);
// "Save as" disables the file target input field.
connect(ui.saveAsCheckBox, &QCheckBox::toggled, [&](bool checked) {
ui.targetLineEdit->setDisabled(checked);
ui.browsePushButton->setDisabled(checked);
ui.directoryLabel->setDisabled(checked);
});
connect(ui.qualitySlider, QOverload<int>::of(&QSlider::valueChanged), ui.qualityValueLabel, QOverload<int>::of(&QLabel::setNum));
connect(ui.startupCheckBox, &QCheckBox::toggled , ui.startupHideCheckBox, &QCheckBox::setEnabled);
connect(ui.trayCheckBox , &QCheckBox::toggled , ui.messageCheckBox , &QCheckBox::setEnabled);
// Auto-upload disables the default action button in the previews.
connect(ui.uploadCheckBox, &QCheckBox::toggled, [&](bool checked) {
ui.previewDefaultActionLabel->setDisabled(checked);
ui.previewDefaultActionComboBox->setDisabled(checked);
ui.directoryHotkeyWidget->setEnabled(checked);
});
auto conflictWarning = [](bool fullConflict, QWidget *w) {
if (fullConflict) {
QToolTip::showText(QCursor::pos(), tr("<font color=\"darkRed\">This setting conflicts with the Screenshot Clipboard setting, which has been disabled.</font>"), w);
} else {
QToolTip::showText(QCursor::pos(), tr("<b>This setting might conflict with the Screenshot Clipboard setting!</b>"), w);
}
};
connect(ui.uploadCheckBox, &QCheckBox::toggled, [&](bool checked) {
if (ui.urlClipboardCheckBox->isChecked() && ui.clipboardCheckBox->isChecked()) {
ui.clipboardGroupBox->setDisabled(checked);
if (checked) {
conflictWarning(true, ui.uploadCheckBox);
}
}
});
connect(ui.urlClipboardCheckBox, &QCheckBox::toggled, [&](bool checked) {
if (ui.uploadCheckBox->isChecked() && ui.clipboardCheckBox->isChecked()) {
ui.clipboardGroupBox->setDisabled(checked);
if (checked) {
conflictWarning(true, ui.urlClipboardCheckBox);
}
} else if (ui.clipboardCheckBox->isChecked()) {
conflictWarning(false, ui.urlClipboardCheckBox);
}
});
connect(ui.mainLabel , &QLabel::linkActivated, this, &OptionsDialog::openUrl);
connect(ui.licenseAboutLabel, &QLabel::linkActivated, this, &OptionsDialog::openUrl);
connect(ui.linksLabel, &QLabel::linkActivated, this, &OptionsDialog::openUrl);
connect(ui.uploadSslWarningLabel,&QLabel::linkActivated, this, &OptionsDialog::openUrl);
connect(ui.tabWidget, &QTabWidget::currentChanged, [&](int index) {
if (index == 2 && ui.uploadServiceStackWidget->currentIndex() == 0 && !ui.imgurOptions->mCurrentUser.isEmpty() && ui.imgurOptions->ui.albumComboBox->count() == 1) {
QTimer::singleShot(20, ui.imgurOptions, &ImgurOptionsWidget::requestAlbumList);
}
});
}
void OptionsDialog::namingOptions()
{
NamingDialog namingDialog((Screenshot::Naming) ui.namingComboBox->currentIndex());
namingDialog.exec();
flipToggled(settings()->value("options/flip").toBool());
updatePreview();
}
//
bool OptionsDialog::hotkeyCollision()
{
// Check for hotkey collision (there's probably a better way to do this...=)
if (ui.screenCheckBox->isChecked()) {
if (ui.screenHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked()) {
return true;
}
if (ui.screenHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked()) {
return true;
}
if (ui.screenHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked()) {
return true;
}
if (ui.screenHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked()) {
return true;
}
if (ui.screenHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked()) {
return true;
}
}
if (ui.areaCheckBox->isChecked()) {
if (ui.areaHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked()) {
return true;
}
if (ui.areaHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked()) {
return true;
}
if (ui.areaHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked()) {
return true;
}
if (ui.areaHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked()) {
return true;
}
if (ui.areaHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked()) {
return true;
}
}
if (ui.windowCheckBox->isChecked()) {
if (ui.windowHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked()) {
return true;
}
if (ui.windowHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked()) {
return true;
}
if (ui.windowHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked()) {
return true;
}
if (ui.windowHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked()) {
return true;
}
if (ui.windowHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked()) {
return true;
}
}
if (ui.openCheckBox->isChecked()) {
if (ui.openHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked()) {
return true;
}
if (ui.openHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked()) {
return true;
}
if (ui.openHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked()) {
return true;
}
if (ui.openHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked()) {
return true;
}
if (ui.openHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked()) {
return true;
}
}
if (ui.directoryCheckBox->isChecked()) {
if (ui.directoryHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked()) {
return true;
}
if (ui.directoryHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked()) {
return true;
}
if (ui.directoryHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked()) {
return true;
}
if (ui.directoryHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked()) {
return true;
}
if (ui.directoryHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked()) {
return true;
}
}
return false;
}
QSettings *OptionsDialog::settings() const
{
return ScreenshotManager::instance()->settings();
}
diff --git a/dialogs/optionsdialog.h b/dialogs/optionsdialog.h
index 458bc09..c4eb66c 100644
--- a/dialogs/optionsdialog.h
+++ b/dialogs/optionsdialog.h
@@ -1,69 +1,69 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef OPTIONSDIALOG_H
#define OPTIONSDIALOG_H
#include <QDialog>
-#include "../updater/updater.h"
+#include <updater/updater.h>
#include "ui_optionsdialog.h"
class QSettings;
class QAbstractButton;
class OptionsDialog : public QDialog
{
Q_OBJECT
public:
OptionsDialog(QWidget *parent = 0);
public slots:
void accepted();
void checkUpdatesNow();
void exportSettings();
void importSettings();
void loadSettings();
void openUrl(QString url);
void restoreDefaults();
void saveSettings();
void updatePreview();
void viewHistory();
protected:
bool event(QEvent *event);
#ifdef Q_OS_WIN
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
private slots:
void browse();
void dialogButtonClicked(QAbstractButton *button);
void flipToggled(bool checked);
void init();
void namingOptions();
private:
bool hotkeyCollision();
QSettings *settings() const;
private:
Ui::OptionsDialog ui;
};
#endif // OPTIONSDIALOG_H
diff --git a/dialogs/previewdialog.cpp b/dialogs/previewdialog.cpp
index 933f3e5..b6ceac5 100644
--- a/dialogs/previewdialog.cpp
+++ b/dialogs/previewdialog.cpp
@@ -1,455 +1,455 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include "previewdialog.h"
-#include "../tools/screenshot.h"
-#include "../tools/screenshotmanager.h"
-#include "../tools/os.h"
+#include <dialogs/previewdialog.h>
+#include <tools/screenshot.h>
+#include <tools/screenshotmanager.h>
+#include <tools/os.h>
#include <QApplication>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDrag>
#include <QGraphicsDropShadowEffect>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QList>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QObject>
#include <QPalette>
#include <QPushButton>
#include <QSettings>
#include <QStackedLayout>
#include <QToolButton>
#include <QUrl>
PreviewDialog::PreviewDialog(QWidget *parent) :
QDialog(parent), mAutoclose(0), mAutocloseAction(0), mAutocloseReset(0), mPosition(0), mSize(0)
{
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
setWindowTitle(tr("Screenshot Preview"));
setContextMenuPolicy(Qt::CustomContextMenu);
auto settings = ScreenshotManager::instance()->settings();
mSize = settings->value("options/previewSize", 300).toInt();
mPosition = settings->value("options/previewPosition", 3).toInt();
if (settings->value("options/previewAutoclose", false).toBool()) {
mAutoclose = settings->value("options/previewAutocloseTime").toInt();
mAutocloseReset = mAutoclose;
mAutocloseAction = settings->value("options/previewAutocloseAction").toInt();
}
auto layout = new QHBoxLayout;
mStack = new QStackedLayout;
connect(mStack, &QStackedLayout::currentChanged, this, &PreviewDialog::indexChanged);
mPrevButton = new QPushButton(os::icon("arrow-left"), "", this);
connect(mPrevButton, &QPushButton::clicked, this, &PreviewDialog::previous);
mNextButton = new QPushButton(os::icon("arrow-right"), "", this);
connect(mNextButton, &QPushButton::clicked, this, &PreviewDialog::next);
mPrevButton->setCursor(Qt::PointingHandCursor);
mPrevButton->setFlat(true);
mPrevButton->setGraphicsEffect(os::shadow(Qt::white));
mPrevButton->setIconSize(QSize(24, 24));
mPrevButton->setVisible(false);
mNextButton->setCursor(Qt::PointingHandCursor);
mNextButton->setFlat(true);
mNextButton->setGraphicsEffect(os::shadow(Qt::white));
mNextButton->setIconSize(QSize(24, 24));
mNextButton->setVisible(false);
layout->addWidget(mPrevButton);
layout->addLayout(mStack);
layout->addWidget(mNextButton);
layout->setMargin(0);
layout->setContentsMargins(6, 6, 6, 6);
mStack->setMargin(0);
setMaximumHeight(mSize);
setLayout(layout);
if (mAutoclose) {
startTimer(1000);
}
auto contextMenu = new QMenu(this);
contextMenu->setTitle(tr("Global Preview Actions"));
contextMenu->addAction(os::icon("yes") , tr("&Save All") , this, &PreviewDialog::acceptAll);
contextMenu->addAction(os::icon("imgur"), tr("&Upload All"), this, &PreviewDialog::uploadAll);
contextMenu->addSeparator();
contextMenu->addAction(os::icon("no") , tr("&Cancel All"), this, &PreviewDialog::rejectAll);
contextMenu->addSeparator();
contextMenu->addAction(os::icon("folder"), tr("Open &Folder"), this, [parent] {
QMetaObject::invokeMethod(parent, "goToFolder");
});
connect(this, &PreviewDialog::customContextMenuRequested, contextMenu, [contextMenu](const QPoint &pos) {
Q_UNUSED(pos)
contextMenu->popup(QCursor::pos());
});
}
void PreviewDialog::add(Screenshot *screenshot)
{
if (!isVisible()) {
show();
}
if (mAutoclose) {
mAutoclose = mAutocloseReset;
}
QLabel *label = new QLabel(this);
label->setGraphicsEffect(os::shadow());
bool smallShot = false;
QSize size = screenshot->pixmap().size();
if (size.width() > mSize || size.height() > mSize) {
size.scale(mSize, mSize, Qt::KeepAspectRatio);
} else {
smallShot = true;
}
QPixmap thumbnail = screenshot->pixmap().scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label->setPixmap(thumbnail);
thumbnail = QPixmap();
label->setAlignment(Qt::AlignCenter);
if (size.height() < 120) {
label->setMinimumHeight(120);
}
if (size.width() < 140) {
label->setMinimumWidth(140);
}
label->resize(size);
QPushButton *discardPushButton = new QPushButton(os::icon("no") , "", label);
QPushButton *enlargePushButton = new QPushButton(os::icon("preview"), "", label);
QToolButton *confirmPushButton = new QToolButton(label);
confirmPushButton->setIconSize(QSize(24, 24));
confirmPushButton->setCursor(Qt::PointingHandCursor);
confirmPushButton->setGraphicsEffect(os::shadow(Qt::white));
if (ScreenshotManager::instance()->settings()->value("options/previewDefaultAction", 0).toInt() == 0
|| ScreenshotManager::instance()->settings()->value("options/uploadAuto").toBool()) {
// Default button, confirm & upload.
confirmPushButton->setIcon(os::icon("yes"));
if (!ScreenshotManager::instance()->settings()->value("options/uploadAuto").toBool()) {
QMenu *confirmMenu = new QMenu(confirmPushButton);
confirmMenu->setObjectName("confirmMenu");
QAction *uploadAction = new QAction(os::icon("imgur"), tr("Upload"), confirmPushButton);
connect(uploadAction, &QAction::triggered, screenshot, &Screenshot::markUpload);
connect(uploadAction, &QAction::triggered, screenshot, [screenshot] { screenshot->confirm(true); });
connect(uploadAction, &QAction::triggered, this, &PreviewDialog::closePreview);
connect(this, &PreviewDialog::uploadAll, uploadAction, &QAction::trigger);
confirmMenu->addAction(uploadAction);
confirmPushButton->setMenu(confirmMenu);
confirmPushButton->setPopupMode(QToolButton::MenuButtonPopup);
}
connect(this, &PreviewDialog::acceptAll, confirmPushButton, &QPushButton::click);
connect(confirmPushButton, &QPushButton::clicked, screenshot, [screenshot] { screenshot->confirm(true); });
connect(confirmPushButton, &QPushButton::clicked, this, &PreviewDialog::closePreview);
} else {
// Reversed button, upload & confirm.
confirmPushButton->setIcon(os::icon("imgur"));
QMenu *confirmMenu = new QMenu(confirmPushButton);
confirmMenu->setObjectName("confirmMenu");
QAction *confirmAction = new QAction(os::icon("yes"), tr("Save"), confirmPushButton);
connect(this, &PreviewDialog::acceptAll, confirmAction, &QAction::trigger);
connect(confirmAction, &QAction::triggered, screenshot, [screenshot] { screenshot->confirm(true); });
connect(confirmAction, &QAction::triggered, this, &PreviewDialog::closePreview);
connect(confirmPushButton, &QPushButton::clicked, screenshot, &Screenshot::markUpload);
connect(confirmPushButton, &QPushButton::clicked, screenshot, [screenshot] { screenshot->confirm(true); });
connect(confirmPushButton, &QPushButton::clicked, this, &PreviewDialog::closePreview);
connect(this, &PreviewDialog::uploadAll, confirmPushButton, &QPushButton::click);
confirmMenu->addAction(confirmAction);
confirmPushButton->setMenu(confirmMenu);
confirmPushButton->setPopupMode(QToolButton::MenuButtonPopup);
}
confirmPushButton->setAutoRaise(true);
confirmPushButton->setVisible(false);
discardPushButton->setIconSize(QSize(24, 24));
discardPushButton->setCursor(Qt::PointingHandCursor);
discardPushButton->setGraphicsEffect(os::shadow(Qt::white));
discardPushButton->setFlat(true);
discardPushButton->setVisible(false);
enlargePushButton->setIconSize(QSize(22, 22));
enlargePushButton->setCursor(Qt::PointingHandCursor);
enlargePushButton->setGraphicsEffect(os::shadow(Qt::white));
enlargePushButton->setFlat(true);
enlargePushButton->setVisible(false);
enlargePushButton->setDisabled(smallShot);
connect(this, &PreviewDialog::rejectAll, discardPushButton, &QPushButton::click);
connect(discardPushButton, &QPushButton::clicked, screenshot, &Screenshot::discard);
connect(discardPushButton, &QPushButton::clicked, this, &PreviewDialog::closePreview);
connect(enlargePushButton, &QPushButton::clicked, this, &PreviewDialog::enlargePreview);
QHBoxLayout *wlayout = new QHBoxLayout;
wlayout->addWidget(confirmPushButton);
wlayout->addStretch();
wlayout->addWidget(enlargePushButton);
wlayout->addStretch();
wlayout->addWidget(discardPushButton);
wlayout->setMargin(0);
QVBoxLayout *wl = new QVBoxLayout;
wl->addStretch();
wl->addLayout(wlayout);
wl->setMargin(0);
label->setLayout(wl);
label->setProperty("screenshotObject", QVariant::fromValue<Screenshot *>(screenshot));
mStack->addWidget(label);
mStack->setCurrentIndex(mStack->count() - 1);
mNextButton->setEnabled(false);
if (mStack->count() >= 2 && !mNextButton->isVisible()) {
mNextButton->setVisible(true);
mPrevButton->setVisible(true);
}
relocate();
}
int PreviewDialog::count() const
{
return mStack->count();
}
//
void PreviewDialog::closePreview()
{
QWidget *widget = mStack->currentWidget();
mStack->removeWidget(widget);
widget->deleteLater();
if (mStack->count() == 0) {
close();
} else {
relocate();
}
}
void PreviewDialog::enlargePreview()
{
Screenshot *screenshot = mStack->currentWidget()->property("screenshotObject").value<Screenshot *>();
if (screenshot) {
QFileInfo info(screenshot->unloadedFileName());
QDesktopServices::openUrl(QUrl(info.absoluteFilePath()));
}
}
void PreviewDialog::indexChanged(int i)
{
if (i == mStack->count() - 1) {
mNextButton->setEnabled(false);
mPrevButton->setEnabled(true);
}
if (i == 0 && mStack->count() > 1) {
mNextButton->setEnabled(true);
mPrevButton->setEnabled(false);
}
if (i != 0 && i != mStack->count() - 1) {
mNextButton->setEnabled(true);
mPrevButton->setEnabled(true);
}
if (mStack->count() < 2) {
mNextButton->setEnabled(false);
mPrevButton->setEnabled(false);
}
if (mStack->widget(i)) {
mStack->widget(i)->setFocus();
}
if (mStack->count() > 1) {
setWindowTitle(tr("Screenshot Preview (%1 of %2)").arg(mStack->currentIndex() + 1).arg(mStack->count()));
} else {
setWindowTitle(tr("Screenshot Preview"));
}
}
void PreviewDialog::next()
{
mStack->setCurrentIndex(mStack->currentIndex() + 1);
relocate();
}
void PreviewDialog::previous()
{
mStack->setCurrentIndex(mStack->currentIndex() - 1);
relocate();
}
void PreviewDialog::relocate()
{
updateGeometry();
resize(minimumSizeHint());
QApplication::sendEvent(this, new QEvent(QEvent::Enter)); // Ensures the buttons are visible.
QPoint where;
switch (mPosition) {
case 0:
where = QApplication::desktop()->availableGeometry(this).topLeft();
break;
case 1:
where = QApplication::desktop()->availableGeometry(this).topRight();
where.setX(where.x() - frameGeometry().width());
break;
case 2:
where = QApplication::desktop()->availableGeometry(this).bottomLeft();
where.setY(where.y() - frameGeometry().height());
break;
case 3:
default:
where = QApplication::desktop()->availableGeometry(this).bottomRight();
where.setX(where.x() - frameGeometry().width());
where.setY(where.y() - frameGeometry().height());
break;
}
move(where);
}
//
bool PreviewDialog::event(QEvent *event)
{
if ((event->type() == QEvent::Enter || event->type() == QEvent::Leave)
&& mStack->currentWidget()) {
for (QObject *child : mStack->currentWidget()->children()) {
QWidget *widget = qobject_cast<QWidget *>(child);
if (widget) {
// Lets avoid disappearing buttons and bail if the menu is open.
QMenu *confirmMenu = widget->findChild<QMenu *>("confirmMenu");
if (confirmMenu && confirmMenu->isVisible()) {
return false;
}
widget->setVisible((event->type() == QEvent::Enter));
}
}
} else if (event->type() == QEvent::Close) {
if (mStack->count() != 0) {
emit rejectAll();
}
deleteLater();
}
return QDialog::event(event);
}
void PreviewDialog::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_UNUSED(event);
enlargePreview();
}
void PreviewDialog::mousePressEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if ((event->pos() - mDragStartPosition).manhattanLength()
< QApplication::startDragDistance())
return;
Screenshot *screenshot = mStack->currentWidget()->property("screenshotObject").value<Screenshot *>();
if (screenshot) {
QFileInfo info(screenshot->unloadedFileName());
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setUrls(QList<QUrl>() << QUrl::fromLocalFile(info.absoluteFilePath()));
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction | Qt::MoveAction);
}
}
void PreviewDialog::mouseMoveEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
mDragStartPosition = event->pos();
}
}
void PreviewDialog::timerEvent(QTimerEvent *event)
{
if (mAutoclose == 0) {
if (mAutocloseAction == 0) {
emit acceptAll();
} else if (mAutocloseAction == 1) {
emit uploadAll();
} else {
emit rejectAll();
}
} else if (mAutoclose < 0) {
killTimer(event->timerId());
} else {
setWindowTitle(tr("Preview: Closing in %1").arg(mAutoclose));
mAutoclose--;
}
}
diff --git a/dialogs/updaterdialog.cpp b/dialogs/updaterdialog.cpp
index 6b5167f..cd27914 100644
--- a/dialogs/updaterdialog.cpp
+++ b/dialogs/updaterdialog.cpp
@@ -1,64 +1,64 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDesktopServices>
#include <QLabel>
#include <QLayout>
#include <QProgressBar>
#include <QUrl>
-#include "updaterdialog.h"
-#include "../tools/os.h"
+#include <dialogs/updaterdialog.h>
+#include <tools/os.h>
UpdaterDialog::UpdaterDialog(QWidget *parent) :
QProgressDialog("", tr("Cancel"), 0, 0, parent)
{
setWindowTitle(tr("Updater - Lightscreen"));
setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
setAutoClose(false);
QProgressBar *bar = new QProgressBar(this);
bar->setTextVisible(false);
bar->setRange(0, 0);
QLabel *label = new QLabel(tr("Checking for updates..."), this);
connect(label, &QLabel::linkActivated, this, &UpdaterDialog::link);
setLabel(label);
setBar(bar);
}
void UpdaterDialog::updateDone(bool result)
{
if (result) {
setLabelText(tr("There's a new version available,<br> please see <a href=\"https://lightscreen.com.ar/whatsnew/%1\">the Lighscreen website</a>.").arg(qApp->applicationVersion()));
} else {
setLabelText(tr("No new versions available."));
}
setMaximum(1);
setCancelButtonText(tr("Close"));
}
void UpdaterDialog::link(QString url)
{
QDesktopServices::openUrl(url);
}
diff --git a/lightscreen.pro b/lightscreen.pro
index e3dfd6e..dfbe2a0 100644
--- a/lightscreen.pro
+++ b/lightscreen.pro
@@ -1,101 +1,103 @@
TEMPLATE = app
TARGET = lightscreen
DEFINES += QT_DEPRECATED_WARNINGS
HEADERS += dialogs/areadialog.h \
dialogs/historydialog.h \
dialogs/namingdialog.h \
dialogs/optionsdialog.h \
dialogs/previewdialog.h \
dialogs/updaterdialog.h \
lightscreenwindow.h \
tools/os.h \
tools/screenshot.h \
tools/screenshotmanager.h \
tools/windowpicker.h \
updater/updater.h \
widgets/hotkeywidget.h \
tools/uploader/imageuploader.h \
tools/uploader/imguruploader.h \
tools/uploader/pomfuploader.h \
tools/uploader/uploader.h \
widgets/imguroptionswidget.h \
widgets/pomfoptionswidget.h
SOURCES += dialogs/areadialog.cpp \
dialogs/historydialog.cpp \
dialogs/namingdialog.cpp \
dialogs/optionsdialog.cpp \
dialogs/previewdialog.cpp \
dialogs/updaterdialog.cpp \
lightscreenwindow.cpp \
main.cpp \
tools/os.cpp \
tools/screenshot.cpp \
tools/screenshotmanager.cpp \
tools/windowpicker.cpp \
updater/updater.cpp \
widgets/hotkeywidget.cpp \
tools/uploader/imageuploader.cpp \
tools/uploader/imguruploader.cpp \
tools/uploader/pomfuploader.cpp \
tools/uploader/uploader.cpp \
widgets/imguroptionswidget.cpp \
widgets/pomfoptionswidget.cpp
FORMS += dialogs/historydialog.ui \
dialogs/namingdialog.ui \
dialogs/optionsdialog.ui \
lightscreenwindow.ui \
widgets/pomfoptionswidget.ui \
widgets/imguroptionswidget.ui
RESOURCES += lightscreen.qrc
CODECFORSRC = UTF-8
+INCLUDEPATH += $$PWD
+CONFIG += c++14
QT += core gui widgets network sql multimedia concurrent
include($$PWD/tools/SingleApplication/singleapplication.pri)
include($$PWD/tools/UGlobalHotkey/uglobalhotkey.pri)
windows {
QT += winextras
RC_ICONS += images/LS.ico
# MinGW
contains(QMAKE_CC, gcc){
LIBS += libgdi32 libgcc libuser32 libole32 libshell32 libshlwapi libcomctl32
QMAKE_CXXFLAGS = -Wextra -Wall -Wpointer-arith
}
# MSVC
contains(QMAKE_CC, cl){
LIBS += gdi32.lib user32.lib ole32.lib shell32.lib shlwapi.lib comctl32.lib
DEFINES += _ATL_XP_TARGETING
QMAKE_CFLAGS += /D _USING_V110_SDK71
QMAKE_CXXFLAGS += /D _USING_V110_SDK71
QMAKE_LFLAGS_WINDOWS += /SUBSYSTEM:WINDOWS,5.01
QMAKE_LFLAGS_WINDOWS += /MANIFESTUAC:level=\'asInvoker\'
QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE,5.01
}
CONFIG += embed_manifest_exe
#QMAKE_CXXFLAGS_DEBUG += /analyze /W3 /wd6326
}
unix:LIBS += -lX11
unix:QT += x11extras
include (version.pri)
OTHER_FILES += TODO.txt
diff --git a/lightscreenwindow.cpp b/lightscreenwindow.cpp
index 0c6df8f..ac83cc5 100644
--- a/lightscreenwindow.cpp
+++ b/lightscreenwindow.cpp
@@ -1,1027 +1,1027 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QDate>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFileInfo>
#include <QKeyEvent>
#include <QMainWindow>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QProcess>
#include <QSettings>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QToolTip>
#include <QUrl>
#include <QSound>
#include <QKeyEvent>
#ifdef Q_OS_WIN
#include <windows.h>
#include <QtWinExtras>
#endif
//
//Lightscreen includes
//
-#include "lightscreenwindow.h"
-#include "dialogs/optionsdialog.h"
-#include "dialogs/previewdialog.h"
-#include "dialogs/historydialog.h"
-
-#include "tools/os.h"
-#include "tools/screenshot.h"
-#include "tools/screenshotmanager.h"
-#include "tools/UGlobalHotkey/uglobalhotkeys.h"
-#include "tools/uploader/uploader.h"
-
-#include "updater/updater.h"
+#include <lightscreenwindow.h>
+#include <dialogs/optionsdialog.h>
+#include <dialogs/previewdialog.h>
+#include <dialogs/historydialog.h>
+
+#include <tools/os.h>
+#include <tools/screenshot.h>
+#include <tools/screenshotmanager.h>
+#include <tools/UGlobalHotkey/uglobalhotkeys.h>
+#include <tools/uploader/uploader.h>
+
+#include <updater/updater.h>
LightscreenWindow::LightscreenWindow(QWidget *parent) :
QMainWindow(parent),
mDoCache(false),
mHideTrigger(false),
mReviveMain(false),
mWasVisible(true),
mLastMessage(0),
mLastMode(Screenshot::None),
mLastScreenshot(),
mHasTaskbarButton(false)
{
ui.setupUi(this);
ui.screenPushButton->setIcon(os::icon("screen.big"));
ui.areaPushButton->setIcon(os::icon("area.big"));
ui.windowPushButton->setIcon(os::icon("pickWindow.big"));
ui.optionsPushButton->setIcon(os::icon("configure"));
ui.folderPushButton->setIcon(os::icon("folder"));
ui.imgurPushButton->setIcon(os::icon("imgur"));
createUploadMenu();
#ifdef Q_OS_WIN
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7) {
mTaskbarButton = new QWinTaskbarButton(this);
mHasTaskbarButton = true;
if (QtWin::isCompositionEnabled()) {
setAttribute(Qt::WA_NoSystemBackground);
QtWin::enableBlurBehindWindow(this);
QtWin::extendFrameIntoClientArea(this, QMargins(-1, -1, -1, -1));
}
}
if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS7) {
ui.centralWidget->setStyleSheet("QPushButton { padding: 2px; border: 1px solid #acacac; background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #eaeaea, stop:1 #e5e5e5);} QPushButton:hover { border: 1px solid #7eb4ea; background-color: #e4f0fc; }");
}
#endif
setMinimumSize(size());
setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
// Actions
connect(ui.screenPushButton, &QPushButton::clicked, this, &LightscreenWindow::screenHotkey);
connect(ui.areaPushButton , &QPushButton::clicked, this, &LightscreenWindow::areaHotkey);
connect(ui.windowPushButton, &QPushButton::clicked, this, &LightscreenWindow::windowPickerHotkey);
connect(ui.optionsPushButton, &QPushButton::clicked, this, &LightscreenWindow::showOptions);
connect(ui.folderPushButton , &QPushButton::clicked, this, &LightscreenWindow::goToFolder);
// Shortcuts
mGlobalHotkeys = new UGlobalHotkeys(this);
connect(mGlobalHotkeys, &UGlobalHotkeys::activated, [&](size_t id) {
action(id);
});
// Uploader
connect(Uploader::instance(), &Uploader::progressChanged, this, &LightscreenWindow::uploadProgress);
connect(Uploader::instance(), &Uploader::done , this, &LightscreenWindow::showUploaderMessage);
connect(Uploader::instance(), &Uploader::error , this, &LightscreenWindow::showUploaderError);
// Manager
connect(ScreenshotManager::instance(), &ScreenshotManager::confirm, this, &LightscreenWindow::preview);
connect(ScreenshotManager::instance(), &ScreenshotManager::windowCleanup, this, &LightscreenWindow::cleanup);
connect(ScreenshotManager::instance(), &ScreenshotManager::activeCountChange, this, &LightscreenWindow::updateStatus);
if (!settings()->contains("file/format")) {
showOptions(); // There are no options (or the options config is invalid or incomplete)
} else {
QTimer::singleShot(0 , this, &LightscreenWindow::applySettings);
QTimer::singleShot(5000, this, &LightscreenWindow::checkForUpdates);
}
}
LightscreenWindow::~LightscreenWindow()
{
settings()->setValue("lastScreenshot", mLastScreenshot);
settings()->sync();
mGlobalHotkeys->unregisterAllHotkeys();
}
void LightscreenWindow::action(int mode)
{
if (mode <= Screenshot::SelectedWindow) {
screenshotAction((Screenshot::Mode)mode);
} else if (mode == ShowMainWindow) {
show();
} else if (mode == OpenScreenshotFolder) {
goToFolder();
} else {
qWarning() << "Unknown hotkey ID: " << mode;
}
}
void LightscreenWindow::areaHotkey()
{
screenshotAction(Screenshot::SelectedArea);
}
void LightscreenWindow::checkForUpdates()
{
if (settings()->value("options/disableUpdater", false).toBool()) {
return;
}
if (settings()->value("lastUpdateCheck").toInt() + 7
> QDate::currentDate().dayOfYear()) {
return; // If 7 days have not passed since the last update check.
}
mUpdater = new Updater(this);
connect(mUpdater, &Updater::done, this, &LightscreenWindow::updaterDone);
mUpdater->check();
}
void LightscreenWindow::cleanup(const Screenshot::Options &options)
{
// Reversing settings
if (settings()->value("options/hide").toBool()) {
#ifndef Q_OS_LINUX // X is not quick enough and the notification ends up everywhere but in the icon
if (settings()->value("options/tray").toBool() && mTrayIcon) {
mTrayIcon->show();
}
#endif
if (mPreviewDialog) {
if (mPreviewDialog->count() <= 1 && mWasVisible) {
show();
}
mPreviewDialog->show();
} else if (mWasVisible) {
show();
}
mHideTrigger = false;
}
if (settings()->value("options/tray").toBool() && mTrayIcon) {
notify(options.result);
if (settings()->value("options/message").toBool() && options.file && !options.upload) {
// This message wll get shown only when messages are enabled and the file won't get another upload pop-up soon.
showScreenshotMessage(options.result, options.fileName);
}
}
if (settings()->value("options/playSound", false).toBool()) {
if (options.result == Screenshot::Success) {
QSound::play("sounds/ls.screenshot.wav");
} else {
#ifdef Q_OS_WIN
QSound::play("afakepathtomakewindowsplaythedefaultsoundtheresprobablyabetterwaybuticantbebothered");
#else
QSound::play("sound/ls.error.wav");
#endif
}
}
updateStatus();
if (options.result != Screenshot::Success) {
return;
}
mLastScreenshot = options.fileName;
}
void LightscreenWindow::closeToTrayWarning()
{
if (!settings()->value("options/closeToTrayWarning", true).toBool()) {
return;
}
mLastMessage = 3;
mTrayIcon->showMessage(tr("Closed to tray"), tr("Lightscreen will keep running, you can disable this in the options menu."));
settings()->setValue("options/closeToTrayWarning", false);
}
bool LightscreenWindow::closingWithoutTray()
{
if (settings()->value("options/disableHideAlert", false).toBool()) {
return false;
}
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(tr("You have chosen to hide Lightscreen when there's no system tray icon, so you will not be able to access the program <b>unless you have selected a hotkey to do so</b>.<br>What do you want to do?"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStyleSheet("QPushButton { padding: 4px 8px; }");
auto enableButton = msgBox.addButton(tr("Hide but enable tray"), QMessageBox::ActionRole);
auto enableQuietButton = msgBox.addButton(tr("Hide and don't warn"), QMessageBox::ActionRole);
auto hideButton = msgBox.addButton(tr("Just hide"), QMessageBox::ActionRole);
auto abortButton = msgBox.addButton(QMessageBox::Cancel);
Q_UNUSED(abortButton);
msgBox.exec();
if (msgBox.clickedButton() == hideButton) {
return true;
} else if (msgBox.clickedButton() == enableQuietButton) {
settings()->setValue("options/disableHideAlert", true);
applySettings();
return true;
} else if (msgBox.clickedButton() == enableButton) {
settings()->setValue("options/tray", true);
applySettings();
return true;
}
return false; // Cancel.
}
void LightscreenWindow::createUploadMenu()
{
auto imgurMenu = new QMenu(tr("Upload"));
auto uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), imgurMenu);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, &QAction::triggered, this, &LightscreenWindow::uploadLast);
auto cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), imgurMenu);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, &LightscreenWindow::uploading, cancelAction, &QAction::setEnabled);
connect(cancelAction, &QAction::triggered, this, &LightscreenWindow::uploadCancel);
auto historyAction = new QAction(os::icon("view-history"), tr("View &History"), imgurMenu);
connect(historyAction, &QAction::triggered, this, &LightscreenWindow::showHistoryDialog);
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
connect(imgurMenu, &QMenu::aboutToShow, this, [&, imgurMenu] {
imgurMenu->actions().at(0)->setEnabled(!mLastScreenshot.isEmpty());
});
ui.imgurPushButton->setMenu(imgurMenu);
}
void LightscreenWindow::goToFolder()
{
#ifdef Q_OS_WIN
if (!mLastScreenshot.isEmpty() && QFile::exists(mLastScreenshot)) {
QProcess::startDetached("explorer /select, \"" + mLastScreenshot + "\"");
} else {
#endif
QDir path(settings()->value("file/target").toString());
// We might want to go to the folder without it having been created by taking a screenshot yet.
if (!path.exists()) {
path.mkpath(path.absolutePath());
}
QDesktopServices::openUrl(QUrl::fromLocalFile(path.absolutePath() + QDir::separator()));
#ifdef Q_OS_WIN
}
#endif
}
void LightscreenWindow::messageClicked()
{
if (mLastMessage == 1) {
goToFolder();
} else if (mLastMessage == 3) {
QTimer::singleShot(0, this, &LightscreenWindow::showOptions);
} else {
QDesktopServices::openUrl(QUrl(Uploader::instance()->lastUrl()));
}
}
void LightscreenWindow::executeArgument(const QString &message)
{
if (message == "--wake") {
show();
os::setForegroundWindow(this);
qApp->alert(this, 2000);
} else if (message == "--screen") {
screenshotAction(Screenshot::WholeScreen);
} else if (message == "--area") {
screenshotAction(Screenshot::SelectedArea);
} else if (message == "--activewindow") {
screenshotAction(Screenshot::ActiveWindow);
} else if (message == "--pickwindow") {
screenshotAction(Screenshot::SelectedWindow);
} else if (message == "--folder") {
action(OpenScreenshotFolder);
} else if (message == "--uploadlast") {
uploadLast();
} else if (message == "--viewhistory") {
showHistoryDialog();
} else if (message == "--options") {
showOptions();
} else if (message == "--quit") {
qApp->quit();
}
}
void LightscreenWindow::executeArguments(const QStringList &arguments)
{
// If we just have the default argument, call "--wake"
if (arguments.count() == 1 && (arguments.at(0) == qApp->arguments().at(0) || arguments.at(0).contains(QFileInfo(qApp->applicationFilePath()).fileName()))) {
executeArgument("--wake");
return;
}
for (auto argument : arguments) {
executeArgument(argument);
}
}
void LightscreenWindow::notify(const Screenshot::Result &result)
{
switch (result) {
case Screenshot::Success:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.yes"));
if (mHasTaskbarButton) {
mTaskbarButton->setOverlayIcon(os::icon("yes"));
}
setWindowTitle(tr("Success!"));
break;
case Screenshot::Failure:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.no"));
setWindowTitle(tr("Failed!"));
if (mHasTaskbarButton) {
mTaskbarButton->setOverlayIcon(os::icon("no"));
}
break;
case Screenshot::Cancel:
setWindowTitle(tr("Cancelled!"));
break;
}
QTimer::singleShot(2000, this, &LightscreenWindow::restoreNotification);
}
void LightscreenWindow::preview(Screenshot *screenshot)
{
if (screenshot->options().preview) {
if (!mPreviewDialog) {
mPreviewDialog = new PreviewDialog(this);
}
mPreviewDialog->add(screenshot);
} else {
screenshot->confirm(true);
}
}
void LightscreenWindow::quit()
{
settings()->setValue("position", pos());
int answer = 0;
QString doing;
if (ScreenshotManager::instance()->activeCount() > 0) {
doing = tr("processing");
}
if (Uploader::instance()->uploading() > 0) {
if (doing.isEmpty()) {
doing = tr("uploading");
} else {
doing = tr("processing and uploading");
}
}
if (!doing.isEmpty()) {
answer = QMessageBox::question(this,
tr("Are you sure you want to quit?"),
tr("Lightscreen is currently %1 screenshots. Are you sure you want to quit?").arg(doing),
tr("Quit"),
tr("Don't Quit"));
}
if (answer == 0) {
emit finished();
}
}
void LightscreenWindow::restoreNotification()
{
if (mTrayIcon) {
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.small"));
}
if (mHasTaskbarButton) {
mTaskbarButton->clearOverlayIcon();
mTaskbarButton->progress()->setVisible(false);
mTaskbarButton->progress()->stop();
mTaskbarButton->progress()->reset();
}
updateStatus();
}
void LightscreenWindow::screenshotAction(Screenshot::Mode mode)
{
int delayms = -1;
bool optionsHide = settings()->value("options/hide").toBool(); // Option cache, used a couple of times.
if (!mHideTrigger) {
mWasVisible = isVisible();
mHideTrigger = true;
}
// Applying pre-screenshot settings
if (optionsHide) {
hide();
#ifndef Q_OS_LINUX // X is not quick enough and the notification ends up everywhere but in the icon
if (mTrayIcon) {
mTrayIcon->hide();
}
#endif
}
// Screenshot delay
delayms = settings()->value("options/delay", 0).toInt();
delayms = delayms * 1000; // Converting the delay to milliseconds.
delayms += 400;
if (optionsHide && mPreviewDialog) {
if (mPreviewDialog->count() >= 1) {
mPreviewDialog->hide();
}
}
// The delayed functions works using the static variable lastMode
// which keeps the argument so a QTimer can call this function again.
if (delayms > 0) {
if (mLastMode == Screenshot::None) {
mLastMode = mode;
QTimer::singleShot(delayms, this, [&] {
screenshotAction(mLastMode);
});
return;
} else {
mode = mLastMode;
mLastMode = Screenshot::None;
}
}
static Screenshot::Options options;
if (!mDoCache) {
// Populating the option object that will then be passed to the screenshot engine (sounds fancy huh?)
options.file = settings()->value("file/enabled").toBool();
options.format = (Screenshot::Format) settings()->value("file/format").toInt();
options.prefix = settings()->value("file/prefix").toString();
QDir dir(settings()->value("file/target").toString());
dir.makeAbsolute();
options.directory = dir;
options.quality = settings()->value("options/quality", 100).toInt();
options.currentMonitor = settings()->value("options/currentMonitor", false).toBool();
options.clipboard = settings()->value("options/clipboard", true).toBool();
options.urlClipboard = settings()->value("options/urlClipboard", false).toBool();
options.preview = settings()->value("options/preview", false).toBool();
options.magnify = settings()->value("options/magnify", false).toBool();
options.cursor = settings()->value("options/cursor", true).toBool();
options.saveAs = settings()->value("options/saveAs", false).toBool();
options.animations = settings()->value("options/animations", true) .toBool();
options.replace = settings()->value("options/replace", false).toBool();
options.upload = settings()->value("options/uploadAuto", false).toBool();
options.optimize = settings()->value("options/optimize", false).toBool();
options.uploadService = Uploader::serviceName(settings()->value("upload/service", 0).toInt());
Screenshot::NamingOptions namingOptions;
namingOptions.naming = (Screenshot::Naming) settings()->value("file/naming").toInt();
namingOptions.leadingZeros = settings()->value("options/naming/leadingZeros", 0).toInt();
namingOptions.flip = settings()->value("options/flip", false).toBool();
namingOptions.dateFormat = settings()->value("options/naming/dateFormat", "yyyy-MM-dd").toString();
options.namingOptions = namingOptions;
mDoCache = true;
}
options.mode = mode;
ScreenshotManager::instance()->take(options);
}
void LightscreenWindow::screenshotActionTriggered(QAction *action)
{
screenshotAction(action->data().value<Screenshot::Mode>());
}
void LightscreenWindow::screenHotkey()
{
screenshotAction(Screenshot::WholeScreen);
}
void LightscreenWindow::showHotkeyError(const QStringList &hotkeys)
{
static bool dontShow = false;
if (dontShow) {
return;
}
QString messageText;
messageText = tr("Some hotkeys could not be registered, they might already be in use");
if (hotkeys.count() > 1) {
messageText += tr("<br>The failed hotkeys are the following:") + "<ul>";
for (auto hotkey : hotkeys) {
messageText += QString("%1%2%3").arg("<li><b>").arg(hotkey).arg("</b></li>");
}
messageText += "</ul>";
} else {
messageText += tr("<br>The failed hotkey is <b>%1</b>").arg(hotkeys[0]);
}
messageText += tr("<br><i>What do you want to do?</i>");
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(messageText);
QPushButton *changeButton = msgBox.addButton(tr("Change") , QMessageBox::ActionRole);
QPushButton *disableButton = msgBox.addButton(tr("Disable"), QMessageBox::ActionRole);
QPushButton *exitButton = msgBox.addButton(tr("Quit") , QMessageBox::ActionRole);
msgBox.exec();
if (msgBox.clickedButton() == exitButton) {
dontShow = true;
QTimer::singleShot(10, this, &LightscreenWindow::quit);
} else if (msgBox.clickedButton() == changeButton) {
showOptions();
} else if (msgBox.clickedButton() == disableButton) {
for (auto hotkey : hotkeys) {
settings()->setValue(QString("actions/%1/enabled").arg(hotkey), false);
}
}
}
void LightscreenWindow::showHistoryDialog()
{
HistoryDialog historyDialog(this);
historyDialog.exec();
updateStatus();
}
void LightscreenWindow::showOptions()
{
mGlobalHotkeys->unregisterAllHotkeys();
QPointer<OptionsDialog> optionsDialog = new OptionsDialog(this);
optionsDialog->exec();
optionsDialog->deleteLater();
applySettings();
}
void LightscreenWindow::showScreenshotMessage(const Screenshot::Result &result, const QString &fileName)
{
if (result == Screenshot::Cancel) {
return;
}
// Showing message.
QString title;
QString message;
if (result == Screenshot::Success) {
title = QFileInfo(fileName).fileName();
if (settings()->value("file/target").toString().isEmpty()) {
message = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
} else {
message = tr("Saved to \"%1\"").arg(settings()->value("file/target").toString());
}
} else {
title = tr("The screenshot was not taken");
message = tr("An error occurred.");
}
mLastMessage = 1;
mTrayIcon->showMessage(title, message);
}
void LightscreenWindow::showUploaderError(const QString &error)
{
mLastMessage = -1;
updateStatus();
if (mTrayIcon && !error.isEmpty() && settings()->value("options/message").toBool()) {
mTrayIcon->showMessage(tr("Upload error"), error);
}
notify(Screenshot::Failure);
}
void LightscreenWindow::showUploaderMessage(const QString &fileName, const QString &url)
{
if (mTrayIcon && settings()->value("options/message").toBool() && !url.isEmpty()) {
QString screenshot = QFileInfo(fileName).fileName();
if (screenshot.startsWith(".lstemp.")) {
screenshot = tr("Screenshot");
}
mLastMessage = 2;
mTrayIcon->showMessage(tr("%1 uploaded").arg(screenshot), tr("Click here to go to %1").arg(url));
}
updateStatus();
}
void LightscreenWindow::toggleVisibility()
{
if (isVisible()) {
hide();
} else {
show();
os::setForegroundWindow(this);
}
}
void LightscreenWindow::updateStatus()
{
int uploadCount = Uploader::instance()->uploading();
int activeCount = ScreenshotManager::instance()->activeCount();
if (mHasTaskbarButton) {
mTaskbarButton->progress()->setPaused(true);
mTaskbarButton->progress()->setVisible(true);
}
if (uploadCount > 0) {
setStatus(tr("%1 uploading").arg(uploadCount));
if (mHasTaskbarButton) {
mTaskbarButton->progress()->setRange(0, 100);
mTaskbarButton->progress()->resume();
}
emit uploading(true);
} else {
if (activeCount > 1) {
setStatus(tr("%1 processing").arg(activeCount));
} else if (activeCount == 1) {
setStatus(tr("processing"));
} else {
setStatus();
if (mHasTaskbarButton) {
mTaskbarButton->progress()->setVisible(false);
}
}
emit uploading(false);
}
}
void LightscreenWindow::updaterDone(bool result)
{
mUpdater->deleteLater();
settings()->setValue("lastUpdateCheck", QDate::currentDate().dayOfYear());
if (!result) {
return;
}
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(tr("There's a new version of Lightscreen available.<br>Would you like to see more information?<br>(<em>You can turn this notification off</em>)"));
msgBox.setIcon(QMessageBox::Information);
QPushButton *yesButton = msgBox.addButton(QMessageBox::Yes);
QPushButton *turnOffButton = msgBox.addButton(tr("Turn Off"), QMessageBox::ActionRole);
QPushButton *remindButton = msgBox.addButton(tr("Remind Me Later"), QMessageBox::RejectRole);
Q_UNUSED(remindButton);
msgBox.exec();
if (msgBox.clickedButton() == yesButton) {
QDesktopServices::openUrl(QUrl("https://lightscreen.com.ar/whatsnew?from=" + qApp->applicationVersion()));
} else if (msgBox.clickedButton() == turnOffButton) {
settings()->setValue("options/disableUpdater", true);
}
}
void LightscreenWindow::upload(const QString &fileName)
{
Uploader::instance()->upload(fileName, Uploader::serviceName(settings()->value("upload/service", 0).toInt()));
}
void LightscreenWindow::uploadCancel()
{
if (Uploader::instance()->uploading() <= 0) {
return;
}
int confirm = QMessageBox::question(this, tr("Upload cancel"), tr("Do you want to cancel all screenshot uploads?"), tr("Cancel"), tr("Don't Cancel"));
if (confirm == 0) {
Uploader::instance()->cancel();
updateStatus();
}
}
void LightscreenWindow::uploadLast()
{
upload(mLastScreenshot);
updateStatus();
}
void LightscreenWindow::uploadProgress(int progress)
{
if (mHasTaskbarButton) {
mTaskbarButton->progress()->setVisible(true);
mTaskbarButton->progress()->setValue(progress);
}
if (isVisible() && progress > 0) {
int uploadCount = Uploader::instance()->uploading();
if (uploadCount > 1) {
setWindowTitle(tr("%1% of %2 uploads - Lightscreen").arg(progress).arg(uploadCount));
} else {
setWindowTitle(tr("%1% - Lightscreen").arg(progress));
}
}
}
void LightscreenWindow::windowHotkey()
{
screenshotAction(Screenshot::ActiveWindow);
}
void LightscreenWindow::windowPickerHotkey()
{
screenshotAction(Screenshot::SelectedWindow);
}
void LightscreenWindow::applySettings()
{
bool tray = settings()->value("options/tray", true).toBool();
if (tray && !mTrayIcon) {
createTrayIcon();
mTrayIcon->setVisible(true);
} else if (!tray && mTrayIcon) {
mTrayIcon->setVisible(false);
}
connectHotkeys();
mDoCache = false;
if (settings()->value("lastScreenshot").isValid() && mLastScreenshot.isEmpty()) {
mLastScreenshot = settings()->value("lastScreenshot").toString();
}
os::setStartup(settings()->value("options/startup").toBool(), settings()->value("options/startupHide").toBool());
}
void LightscreenWindow::connectHotkeys()
{
const QStringList actions = {"screen", "window", "area", "windowPicker", "open", "directory"};
QStringList failed;
size_t id = Screenshot::WholeScreen;
for (auto action : actions) {
if (settings()->value("actions/" + action + "/enabled").toBool()) {
if (!mGlobalHotkeys->registerHotkey(settings()->value("actions/" + action + "/hotkey").toString(), id)) {
failed << action;
}
}
id++;
}
if (!failed.isEmpty()) {
showHotkeyError(failed);
}
}
void LightscreenWindow::createTrayIcon()
{
mTrayIcon = new QSystemTrayIcon(QIcon(":/icons/lightscreen.small"), this);
updateStatus();
connect(mTrayIcon, &QSystemTrayIcon::messageClicked, this, &LightscreenWindow::messageClicked);
connect(mTrayIcon, &QSystemTrayIcon::activated , this, [&](QSystemTrayIcon::ActivationReason reason) {
if (reason != QSystemTrayIcon::DoubleClick) return;
toggleVisibility();
});
auto hideAction = new QAction(QIcon(":/icons/lightscreen.small"), tr("Show&/Hide"), mTrayIcon);
connect(hideAction, &QAction::triggered, this, &LightscreenWindow::toggleVisibility);
auto screenAction = new QAction(os::icon("screen"), tr("&Screen"), mTrayIcon);
screenAction->setData(QVariant::fromValue<Screenshot::Mode>(Screenshot::WholeScreen));
auto windowAction = new QAction(os::icon("window"), tr("Active &Window"), this);
windowAction->setData(QVariant::fromValue<Screenshot::Mode>(Screenshot::ActiveWindow));
auto windowPickerAction = new QAction(os::icon("pickWindow"), tr("&Pick Window"), this);
windowPickerAction->setData(QVariant::fromValue<Screenshot::Mode>(Screenshot::SelectedWindow));
auto areaAction = new QAction(os::icon("area"), tr("&Area"), mTrayIcon);
areaAction->setData(QVariant::fromValue<Screenshot::Mode>(Screenshot::SelectedArea));
auto screenshotGroup = new QActionGroup(mTrayIcon);
screenshotGroup->addAction(screenAction);
screenshotGroup->addAction(areaAction);
screenshotGroup->addAction(windowAction);
screenshotGroup->addAction(windowPickerAction);
connect(screenshotGroup, &QActionGroup::triggered, this, &LightscreenWindow::screenshotActionTriggered);
// Duplicated for the screenshot button :(
auto uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), mTrayIcon);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, &QAction::triggered, this, &LightscreenWindow::uploadLast);
auto cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), mTrayIcon);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, &LightscreenWindow::uploading, cancelAction, &QAction::setEnabled);
connect(cancelAction, &QAction::triggered, this, &LightscreenWindow::uploadCancel);
auto historyAction = new QAction(os::icon("view-history"), tr("View History"), mTrayIcon);
connect(historyAction, &QAction::triggered, this, &LightscreenWindow::showHistoryDialog);
//
auto optionsAction = new QAction(os::icon("configure"), tr("View &Options"), mTrayIcon);
connect(optionsAction, &QAction::triggered, this, &LightscreenWindow::showOptions);
auto goAction = new QAction(os::icon("folder"), tr("&Go to Folder"), mTrayIcon);
connect(goAction, &QAction::triggered, this, &LightscreenWindow::goToFolder);
auto quitAction = new QAction(tr("&Quit"), mTrayIcon);
connect(quitAction, &QAction::triggered, this, &LightscreenWindow::quit);
auto screenshotMenu = new QMenu(tr("Screenshot"));
screenshotMenu->addAction(screenAction);
screenshotMenu->addAction(areaAction);
screenshotMenu->addAction(windowAction);
screenshotMenu->addAction(windowPickerAction);
// Duplicated for the screenshot button :(
auto imgurMenu = new QMenu(tr("Upload"));
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
auto trayIconMenu = new QMenu;
trayIconMenu->addAction(hideAction);
trayIconMenu->addSeparator();
trayIconMenu->addMenu(imgurMenu);
trayIconMenu->addSeparator();
trayIconMenu->addMenu(screenshotMenu);
trayIconMenu->addAction(optionsAction);
trayIconMenu->addAction(goAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
mTrayIcon->setContextMenu(trayIconMenu);
}
void LightscreenWindow::setStatus(QString status)
{
if (status.isEmpty()) {
status = tr("Lightscreen");
} else {
status += tr(" - Lightscreen");
}
if (mTrayIcon) {
mTrayIcon->setToolTip(status);
}
setWindowTitle(status);
}
QSettings *LightscreenWindow::settings() const
{
return ScreenshotManager::instance()->settings();
}
// Event handling
bool LightscreenWindow::event(QEvent *event)
{
if (event->type() == QEvent::Show) {
QPoint savedPosition = settings()->value("position").toPoint();
if (!savedPosition.isNull() && qApp->desktop()->availableGeometry().contains(QRect(savedPosition, size()))) {
move(savedPosition);
}
if (mHasTaskbarButton) {
mTaskbarButton->setWindow(windowHandle());
}
} else if (event->type() == QEvent::Hide) {
settings()->setValue("position", pos());
} else if (event->type() == QEvent::Close) {
if (settings()->value("options/tray").toBool() && settings()->value("options/closeHide").toBool()) {
closeToTrayWarning();
hide();
} else if (settings()->value("options/closeHide").toBool()) {
if (closingWithoutTray()) {
hide();
}
} else {
quit();
}
} else if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
#ifdef Q_WS_MAC
if (keyEvent->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
keyEvent->ignore();
if (isVisible()) {
toggleVisibility();
}
return false;
} else
#endif
if (!keyEvent->modifiers() && keyEvent->key() == Qt::Key_Escape) {
keyEvent->ignore();
if (isVisible()) {
toggleVisibility();
}
return false;
}
} else if (event->type() == QEvent::LanguageChange) {
ui.retranslateUi(this);
resize(minimumSizeHint());
}
return QMainWindow::event(event);
}
diff --git a/lightscreenwindow.h b/lightscreenwindow.h
index 909b653..d830421 100644
--- a/lightscreenwindow.h
+++ b/lightscreenwindow.h
@@ -1,155 +1,155 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef LIGHTSCREENWINDOW_H
#define LIGHTSCREENWINDOW_H
#include <QMainWindow>
#include <QPointer>
#include <QSystemTrayIcon>
-#include "updater/updater.h"
-#include "tools/screenshot.h"
+#include <updater/updater.h>
+#include <tools/screenshot.h>
-#include "dialogs/previewdialog.h"
+#include <dialogs/previewdialog.h>
#include "ui_lightscreenwindow.h"
class Updater;
class QSettings;
class QProgressBar;
class QWinTaskbarButton;
class UGlobalHotkeys;
class LightscreenWindow : public QMainWindow
{
Q_OBJECT
public:
enum Action {
ShowMainWindow = 5,
OpenScreenshotFolder = 6
};
Q_ENUM(Action)
LightscreenWindow(QWidget *parent = 0);
~LightscreenWindow();
public slots:
void action(int mode = 3);
void areaHotkey();
void checkForUpdates();
void cleanup(const Screenshot::Options &options);
void closeToTrayWarning();
bool closingWithoutTray();
void createUploadMenu();
void goToFolder();
void messageClicked();
void executeArgument(const QString &message);
void executeArguments(const QStringList &arguments);
void notify(const Screenshot::Result &result);
void preview(Screenshot *screenshot);
void quit();
void restoreNotification();
void setStatus(QString status = "");
void screenshotAction(Screenshot::Mode mode = Screenshot::None);
void screenshotActionTriggered(QAction *action);
void screenHotkey();
void showHotkeyError(const QStringList &hotkeys);
void showHistoryDialog();
void showOptions();
void showScreenshotMessage(const Screenshot::Result &result, const QString &fileName);
void showUploaderError(const QString &error);
void showUploaderMessage(const QString &fileName, const QString &url);
void toggleVisibility();
void updateStatus();
void updaterDone(bool result);
void upload(const QString &fileName);
void uploadCancel();
void uploadLast();
void uploadProgress(int progress);
void windowHotkey();
void windowPickerHotkey();
private slots:
void applySettings();
signals:
void uploading(bool uploading);
void finished();
private:
void connectHotkeys();
void createTrayIcon();
#ifdef Q_OS_WIN
bool winEvent(MSG *message, long *result);
#endif
// Convenience function
QSettings *settings() const;
protected:
bool event(QEvent *event);
private:
bool mDoCache;
bool mHideTrigger;
bool mReviveMain;
bool mWasVisible;
int mLastMessage;
Screenshot::Mode mLastMode;
QString mLastScreenshot;
QPointer<QSystemTrayIcon> mTrayIcon;
QPointer<PreviewDialog> mPreviewDialog;
QPointer<Updater> mUpdater;
Ui::LightscreenWindowClass ui;
QPointer<UGlobalHotkeys> mGlobalHotkeys;
bool mHasTaskbarButton;
#ifdef Q_OS_WIN
QPointer<QWinTaskbarButton> mTaskbarButton;
#else
class QWinTaskbarProgressDummy
{
public:
void setVisible(bool v) { Q_UNUSED(v) }
void setPaused(bool p) { Q_UNUSED(p) }
void resume() {}
void stop() {}
void reset() {}
void setRange(int m, int m2) { Q_UNUSED(m) Q_UNUSED(m2) }
void setValue(int v) { Q_UNUSED(v) }
};
class QWinTaskbarDummy : public QObject
{
public:
void setOverlayIcon(QIcon i) { Q_UNUSED(i) }
void clearOverlayIcon() {}
QWinTaskbarProgressDummy *progress() { return 0; }
void setWindow(QWindow *w) { Q_UNUSED(w) }
};
QWinTaskbarDummy *mTaskbarButton;
#endif
};
#endif // LIGHTSCREENWINDOW_H
diff --git a/main.cpp b/main.cpp
index 4d62f96..9d963ea 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,93 +1,93 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDesktopWidget>
#include <QLocale>
#ifdef Q_OS_WIN
#include <QtWinExtras>
#endif
-#include "tools/os.h"
+#include <tools/os.h>
#include "tools/SingleApplication/singleapplication.h"
-#include "lightscreenwindow.h"
+#include <lightscreenwindow.h>
int main(int argc, char *argv[])
{
#ifdef QT_DEBUG
qSetMessagePattern("%{message} @%{line}[%{function}()]");
#endif
QApplication::setOrganizationName("K");
QApplication::setApplicationName("Lightscreen");
QApplication::setApplicationVersion(APP_VERSION);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
SingleApplication application(argc, argv);
application.setQuitOnLastWindowClosed(false);
LightscreenWindow lightscreen;
#ifdef Q_OS_WIN
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7) {
auto jumplist = new QWinJumpList(&lightscreen);
QColor backgroundColor = qApp->palette("QToolTip").color(QPalette::Background);
if (QSysInfo::WindowsVersion == QSysInfo::WV_WINDOWS10) {
// contrast r hard
backgroundColor = Qt::black;
}
auto screenshotCategory = new QWinJumpListCategory(QObject::tr("Screenshot"));
screenshotCategory->setVisible(true);
screenshotCategory->addLink(os::icon("screen", backgroundColor), QObject::tr("Screen") , application.applicationFilePath(), QStringList("--screen"));
screenshotCategory->addLink(os::icon("area", backgroundColor), QObject::tr("Area") , application.applicationFilePath(), QStringList("--area"));
screenshotCategory->addLink(os::icon("pickWindow", backgroundColor), QObject::tr("Pick Window"), application.applicationFilePath(), QStringList("--pickwindow"));
auto uploadCategory = new QWinJumpListCategory(QObject::tr("Upload"));
uploadCategory->setVisible(true);
uploadCategory->addLink(os::icon("imgur", backgroundColor), QObject::tr("Upload Last") , application.applicationFilePath(), QStringList("--uploadlast"));
uploadCategory->addLink(os::icon("view-history", backgroundColor), QObject::tr("View History"), application.applicationFilePath(), QStringList("--viewhistory"));
auto actionsCategory = new QWinJumpListCategory(QObject::tr("Actions"));
actionsCategory->setVisible(true);
actionsCategory->addLink(os::icon("configure", backgroundColor), QObject::tr("Options") , application.applicationFilePath(), QStringList("--options"));
actionsCategory->addLink(os::icon("folder", backgroundColor), QObject::tr("Go to Folder") , application.applicationFilePath(), QStringList("--folder"));
actionsCategory->addLink(os::icon("no.big", backgroundColor), QObject::tr("Quit Lightscreen") , application.applicationFilePath(), QStringList("--quit"));
jumplist->addCategory(screenshotCategory);
jumplist->addCategory(uploadCategory);
jumplist->addCategory(actionsCategory);
}
#endif
if (application.arguments().size() > 1) {
lightscreen.executeArguments(application.arguments());
} else {
lightscreen.show();
}
QObject::connect(&application, &SingleApplication::instanceArguments, &lightscreen, &LightscreenWindow::executeArguments);
QObject::connect(&lightscreen, &LightscreenWindow::finished, &application, &SingleApplication::quit);
return application.exec();
}
diff --git a/tools/os.cpp b/tools/os.cpp
index ef9f27b..a3fee12 100644
--- a/tools/os.cpp
+++ b/tools/os.cpp
@@ -1,385 +1,385 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QBitmap>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialog>
#include <QDir>
#include <QGraphicsDropShadowEffect>
#include <QIcon>
#include <QLibrary>
#include <QLocale>
#include <QMessageBox>
#include <QPixmap>
#include <QPointer>
#include <QProcess>
#include <QSettings>
#include <QTextEdit>
#include <QTimeLine>
#include <QTimer>
#include <QUrl>
#include <QWidget>
#include <string>
#include <QMessageBox>
#include <QPainter>
#include <QPair>
#ifdef Q_OS_WIN
#include <QtWin>
#include <qt_windows.h>
#include <ShlObj.h>
// Define for MinGW
#ifndef SM_CXPADDEDBORDER
#define SM_CXPADDEDBORDER 92
#endif
#elif defined(Q_OS_LINUX)
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#endif
-#include "os.h"
+#include <tools/os.h>
QPair<QPixmap, QPoint> os::cursor()
{
#ifdef Q_OS_WIN
/*
* Taken from: git://github.com/arrai/mumble-record.git > src > mumble > Overlay.cpp
* BSD License.
*/
QPixmap pixmap;
QPoint hotspot;
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(cursorInfo);
::GetCursorInfo(&cursorInfo);
HICON cursor = cursorInfo.hCursor;
ICONINFO iconInfo;
::GetIconInfo(cursor, &iconInfo);
ICONINFO info;
ZeroMemory(&info, sizeof(info));
if (::GetIconInfo(cursor, &info)) {
if (info.hbmColor) {
pixmap = QtWin::fromHBITMAP(info.hbmColor, QtWin::HBitmapAlpha);
} else {
QBitmap orig(QtWin::fromHBITMAP(info.hbmMask));
QImage img = orig.toImage();
int h = img.height() / 2;
int w = static_cast<uint>(img.bytesPerLine()) / sizeof(quint32);
QImage out(img.width(), h, QImage::Format_MonoLSB);
QImage outmask(img.width(), h, QImage::Format_MonoLSB);
for (int i = 0; i < h; ++i) {
const quint32 *srcimg = reinterpret_cast<const quint32 *>(img.scanLine(i + h));
const quint32 *srcmask = reinterpret_cast<const quint32 *>(img.scanLine(i));
quint32 *dstimg = reinterpret_cast<quint32 *>(out.scanLine(i));
quint32 *dstmask = reinterpret_cast<quint32 *>(outmask.scanLine(i));
for (int j = 0; j < w; ++j) {
dstmask[j] = srcmask[j];
dstimg[j] = srcimg[j];
}
}
pixmap = QBitmap::fromImage(out, Qt::ColorOnly);
}
hotspot.setX(static_cast<int>(info.xHotspot));
hotspot.setY(static_cast<int>(info.yHotspot));
if (info.hbmMask) {
::DeleteObject(info.hbmMask);
}
if (info.hbmColor) {
::DeleteObject(info.hbmColor);
}
::DeleteObject(cursor);
}
return QPair<QPixmap, QPoint>(pixmap, hotspot);
#else
return QPair<QPixmap, QPoint>(QPixmap(), QPoint());
#endif
}
void os::effect(QObject *target, const char *slot, int frames, int duration, const char *cleanup)
{
QTimeLine *timeLine = new QTimeLine(duration);
timeLine->setFrameRange(0, frames);
timeLine->connect(timeLine, SIGNAL(frameChanged(int)), target, slot);
if (cleanup != 0) {
timeLine->connect(timeLine, SIGNAL(finished()), target, SLOT(cleanup()));
}
timeLine->connect(timeLine, SIGNAL(finished()), timeLine, SLOT(deleteLater()));
timeLine->start();
}
QString os::getDocumentsPath()
{
#ifdef Q_OS_WIN
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_PERSONAL | CSIDL_FLAG_CREATE,
NULL,
0,
szPath))) {
return QString::fromWCharArray(szPath);
}
return QDir::homePath() + QDir::separator() + "My Documents";
#else
return QDir::homePath() + QDir::separator() + "Documents";
#endif
}
QPixmap os::grabWindow(WId winId)
{
#ifdef Q_OS_WIN
RECT rcWindow;
HWND hwndId = (HWND)winId;
GetWindowRect(hwndId, &rcWindow);
int margin = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER) / 2;
rcWindow.right -= margin;
rcWindow.left += margin;
if (IsZoomed(hwndId)) {
rcWindow.top += margin;
} else {
rcWindow.top += GetSystemMetrics(SM_CXPADDEDBORDER);
}
rcWindow.bottom -= margin;
int width, height;
width = rcWindow.right - rcWindow.left;
height = rcWindow.bottom - rcWindow.top;
RECT rcScreen;
GetWindowRect(GetDesktopWindow(), &rcScreen);
RECT rcResult;
UnionRect(&rcResult, &rcWindow, &rcScreen);
QPixmap pixmap;
// Comparing the rects to determine if the window is outside the boundaries of the screen,
// the window DC method has the disadvantage that it does not show Aero glass transparency,
// so we'll avoid it for the screenshots that don't need it.
HDC hdcMem;
HBITMAP hbmCapture;
if (EqualRect(&rcScreen, &rcResult)) {
// Grabbing the window from the Screen DC.
HDC hdcScreen = GetDC(NULL);
BringWindowToTop(hwndId);
hdcMem = CreateCompatibleDC(hdcScreen);
hbmCapture = CreateCompatibleBitmap(hdcScreen, width, height);
SelectObject(hdcMem, hbmCapture);
BitBlt(hdcMem, 0, 0, width, height, hdcScreen, rcWindow.left, rcWindow.top, SRCCOPY);
} else {
// Grabbing the window by its own DC
HDC hdcWindow = GetWindowDC(hwndId);
hdcMem = CreateCompatibleDC(hdcWindow);
hbmCapture = CreateCompatibleBitmap(hdcWindow, width, height);
SelectObject(hdcMem, hbmCapture);
BitBlt(hdcMem, 0, 0, width, height, hdcWindow, 0, 0, SRCCOPY);
}
ReleaseDC(hwndId, hdcMem);
DeleteDC(hdcMem);
pixmap = QtWin::fromHBITMAP(hbmCapture);
DeleteObject(hbmCapture);
return pixmap;
#else
return QPixmap::grabWindow(winId);
#endif
}
void os::setForegroundWindow(QWidget *window)
{
#ifdef Q_OS_WIN
ShowWindow((HWND)window->winId(), SW_RESTORE);
SetForegroundWindow((HWND)window->winId());
#else
Q_UNUSED(window)
#endif
}
void os::setStartup(bool startup, bool hide)
{
QString lightscreen = QDir::toNativeSeparators(qApp->applicationFilePath());
if (hide) {
lightscreen.append(" -h");
}
#ifdef Q_OS_WIN
// Windows startup settings
QSettings init("Microsoft", "Windows");
init.beginGroup("CurrentVersion");
init.beginGroup("Run");
if (startup) {
init.setValue("Lightscreen", lightscreen);
} else {
init.remove("Lightscreen");
}
init.endGroup();
init.endGroup();
#endif
#if defined(Q_OS_LINUX)
QFile desktopFile(QDir::homePath() + "/.config/autostart/lightscreen.desktop");
desktopFile.remove();
if (startup) {
desktopFile.open(QIODevice::WriteOnly);
desktopFile.write(QString("[Desktop Entry]\nExec=%1\nType=Application").arg(lightscreen).toLatin1());
}
#endif
}
QGraphicsEffect *os::shadow(const QColor &color, int blurRadius, int offset)
{
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect;
shadowEffect->setBlurRadius(blurRadius);
shadowEffect->setOffset(offset);
shadowEffect->setColor(color);
return shadowEffect;
}
QIcon os::icon(const QString &name, QColor backgroundColor)
{
if (!backgroundColor.isValid()) {
backgroundColor = qApp->palette().color(QPalette::Button);
}
if (backgroundColor.value() > 125) {
return QIcon(":/icons/" + name);
} else {
return QIcon(":/icons/inv/" + name);
}
}
#ifdef Q_OS_LINUX
// Taken from KSnapshot. Oh KDE, what would I do without you :D
Window os::findRealWindow(Window w, int depth)
{
if (depth > 5) {
return None;
}
static Atom wm_state = XInternAtom(QX11Info::display(), "WM_STATE", False);
Atom type;
int format;
unsigned long nitems, after;
unsigned char *prop;
if (XGetWindowProperty(QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &prop) == Success) {
if (prop != NULL) {
XFree(prop);
}
if (type != None) {
return w;
}
}
Window root, parent;
Window *children;
unsigned int nchildren;
Window ret = None;
if (XQueryTree(QX11Info::display(), w, &root, &parent, &children, &nchildren) != 0) {
for (unsigned int i = 0;
i < nchildren && ret == None;
++i) {
ret = os::findRealWindow(children[ i ], depth + 1);
}
if (children != NULL) {
XFree(children);
}
}
return ret;
}
Window os::windowUnderCursor(bool includeDecorations)
{
Window root;
Window child;
uint mask;
int rootX, rootY, winX, winY;
XQueryPointer(QX11Info::display(), QX11Info::appRootWindow(), &root, &child,
&rootX, &rootY, &winX, &winY, &mask);
if (child == None) {
child = QX11Info::appRootWindow();
}
if (!includeDecorations) {
Window real_child = os::findRealWindow(child);
if (real_child != None) { // test just in case
child = real_child;
}
}
return child;
}
#endif
diff --git a/tools/screenshot.cpp b/tools/screenshot.cpp
index 13a4af6..21e5eba 100644
--- a/tools/screenshot.cpp
+++ b/tools/screenshot.cpp
@@ -1,524 +1,524 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QClipboard>
#include <QDateTime>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QPainter>
#include <QPixmap>
#include <QProcess>
#include <QTextStream>
#include <QScreen>
#include <QStringBuilder>
-#include "windowpicker.h"
-#include "../dialogs/areadialog.h"
-#include "uploader/uploader.h"
-#include "screenshot.h"
-#include "screenshotmanager.h"
+#include <tools/screenshot.h>
+#include <tools/screenshotmanager.h>
+#include <tools/windowpicker.h>
+#include <tools/uploader/uploader.h>
+#include <dialogs/areadialog.h>
-#include "os.h"
+#include <tools/os.h>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#endif
Screenshot::Screenshot(QObject *parent, Screenshot::Options options):
QObject(parent),
mOptions(options),
mPixmapDelay(false),
mUnloaded(false),
mUnloadFilename()
{
if (mOptions.format == Screenshot::PNG) {
mOptions.quality = 80;
}
}
Screenshot::~Screenshot()
{
if (!mUnloadFilename.isEmpty()) {
QFile::remove(mUnloadFilename);
}
}
QString Screenshot::getName(const NamingOptions &options, const QString &prefix, const QDir &directory)
{
QString naming;
int naming_largest = 0;
if (options.flip) {
naming = "%1" % prefix;
} else {
naming = prefix % "%1";
}
switch (options.naming) {
case Screenshot::Numeric: // Numeric
// Iterating through the folder to find the largest numeric naming.
for (auto file : directory.entryList(QDir::Files)) {
if (file.contains(prefix)) {
file.chop(file.size() - file.lastIndexOf("."));
file.remove(prefix);
if (file.toInt() > naming_largest) {
naming_largest = file.toInt();
}
}
}
if (options.leadingZeros > 0) {
//Pretty, huh?
QString format;
QTextStream(&format) << "%0" << (options.leadingZeros + 1) << "d";
naming = naming.arg(QString().sprintf(format.toLatin1(), naming_largest + 1));
} else {
naming = naming.arg(naming_largest + 1);
}
break;
case Screenshot::Date: // Date
naming = naming.arg(QLocale().toString(QDateTime::currentDateTime(), options.dateFormat));
break;
case Screenshot::Timestamp: // Timestamp
naming = naming.arg(QDateTime::currentDateTime().toTime_t());
break;
case Screenshot::Empty:
naming = naming.arg("");
break;
}
return naming;
}
const QString &Screenshot::unloadedFileName()
{
return mUnloadFilename;
}
const Screenshot::Options &Screenshot::options()
{
return mOptions;
}
QPixmap &Screenshot::pixmap()
{
return mPixmap;
}
//
void Screenshot::confirm(bool result)
{
if (result) {
save();
} else {
mOptions.result = Screenshot::Cancel;
emit finished();
}
emit cleanup();
mPixmap = QPixmap();
}
void Screenshot::confirmation()
{
emit askConfirmation();
if (mOptions.file) {
unloadPixmap();
}
}
void Screenshot::discard()
{
confirm(false);
}
void Screenshot::markUpload()
{
mOptions.upload = true;
}
void Screenshot::optimize()
{
QProcess *process = new QProcess(this);
// Delete the QProcess once it's done.
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this , SLOT(optimizationDone()));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), process, SLOT(deleteLater()));
QString optiPNG;
#ifdef Q_OS_UNIX
optiPNG = "optipng";
#else
optiPNG = qApp->applicationDirPath() % QDir::separator() % "optipng.exe";
#endif
if (!QFile::exists(optiPNG)) {
emit optimizationDone();
}
process->start(optiPNG, QStringList() << mOptions.fileName);
if (process->state() == QProcess::NotRunning) {
emit optimizationDone();
process->deleteLater();
}
}
void Screenshot::optimizationDone()
{
if (mOptions.upload) {
upload();
} else {
emit finished();
}
}
void Screenshot::save()
{
QString name = "";
QString fileName = "";
Screenshot::Result result = Screenshot::Failure;
if (mOptions.file && !mOptions.saveAs) {
name = newFileName();
} else if (mOptions.file && mOptions.saveAs) {
name = QFileDialog::getSaveFileName(0, tr("Save as.."), newFileName(), "*" % extension());
}
if (!mOptions.replace && QFile::exists(name % extension())) {
// Ugly? You should see my wife!
int count = 0;
int cunt = 0;
QString naming = QFileInfo(name).fileName();
for (auto file : QFileInfo(name % extension()).dir().entryList(QDir::Files)) {
if (file.contains(naming)) {
file.remove(naming);
file.remove(" (");
file.remove(")");
file.remove(extension());
cunt = file.toInt();
if (cunt > count) {
count = cunt;
}
}
}
name = name % " (" % QString::number(count % 1) % ")";
}
if (mOptions.clipboard && !(mOptions.upload && mOptions.urlClipboard)) {
if (mUnloaded) {
mUnloaded = false;
mPixmap = QPixmap(mUnloadFilename);
}
QApplication::clipboard()->setPixmap(mPixmap, QClipboard::Clipboard);
if (!mOptions.file) {
result = Screenshot::Success;
}
}
if (mOptions.file) {
fileName = name % extension();
if (name.isEmpty()) {
result = Screenshot::Cancel;
} else if (mUnloaded) {
result = (QFile::rename(mUnloadFilename, fileName)) ? Screenshot::Success : Screenshot::Failure;
} else if (mPixmap.save(fileName, 0, mOptions.quality)) {
result = Screenshot::Success;
} else {
result = Screenshot::Failure;
}
}
mOptions.fileName = fileName;
mOptions.result = result;
if (!mOptions.result) {
emit finished();
}
if (mOptions.format == Screenshot::PNG && mOptions.optimize && mOptions.file) {
if (!mOptions.upload) {
ScreenshotManager::instance()->saveHistory(mOptions.fileName);
}
optimize();
} else if (mOptions.upload) {
upload();
} else if (mOptions.file) {
ScreenshotManager::instance()->saveHistory(mOptions.fileName);
emit finished();
} else {
emit finished();
}
}
void Screenshot::setPixmap(const QPixmap &pixmap)
{
mPixmap = pixmap;
if (mPixmap.isNull()) {
emit confirm(false);
} else {
confirmation();
}
}
void Screenshot::take()
{
switch (mOptions.mode) {
case Screenshot::WholeScreen:
wholeScreen();
break;
case Screenshot::SelectedArea:
selectedArea();
break;
case Screenshot::ActiveWindow:
activeWindow();
break;
case Screenshot::SelectedWindow:
selectedWindow();
break;
}
if (mPixmapDelay) {
return;
}
if (mPixmap.isNull()) {
confirm(false);
} else {
confirmation();
}
}
void Screenshot::upload()
{
if (mOptions.file) {
Uploader::instance()->upload(mOptions.fileName, mOptions.uploadService);
} else if (unloadPixmap()) {
Uploader::instance()->upload(mUnloadFilename, mOptions.uploadService);
} else {
emit finished();
}
}
void Screenshot::uploadDone(const QString &url)
{
if (mOptions.urlClipboard && !url.isEmpty()) {
QApplication::clipboard()->setText(url, QClipboard::Clipboard);
}
emit finished();
}
void Screenshot::refresh()
{
grabDesktop();
}
//
void Screenshot::activeWindow()
{
#ifdef Q_OS_WIN
HWND fWindow = GetForegroundWindow();
if (fWindow == NULL) {
return;
}
if (fWindow == GetDesktopWindow()) {
wholeScreen();
return;
}
mPixmap = os::grabWindow((WId)GetForegroundWindow());
#endif
#if defined(Q_OS_LINUX)
Window focus;
int revert;
XGetInputFocus(QX11Info::display(), &focus, &revert);
mPixmap = QPixmap::grabWindow(focus);
#endif
}
const QString Screenshot::extension() const
{
switch (mOptions.format) {
case Screenshot::PNG:
return QStringLiteral(".png");
break;
case Screenshot::BMP:
return QStringLiteral(".bmp");
break;
case Screenshot::WEBP:
return QStringLiteral(".webp");
break;
case Screenshot::JPEG:
return QStringLiteral(".jpg");
break;
}
}
void Screenshot::grabDesktop()
{
QRect geometry;
QPoint cursorPosition = QCursor::pos();
if (mOptions.currentMonitor) {
int currentScreen = qApp->desktop()->screenNumber(cursorPosition);
geometry = qApp->desktop()->screen(currentScreen)->geometry();
cursorPosition = cursorPosition - geometry.topLeft();
} else {
int top = 0;
for (QScreen *screen : QGuiApplication::screens()) {
auto screenRect = screen->geometry();
if (screenRect.top() < 0) {
top += screenRect.top() * -1;
}
if (screenRect.left() < 0) {
cursorPosition.setX(cursorPosition.x() + screenRect.width()); //= localCursorPos + screenRect.normalized().topLeft();
}
geometry = geometry.united(screenRect);
}
cursorPosition.setY(cursorPosition.y() + top);
}
mPixmap = QApplication::primaryScreen()->grabWindow(QApplication::desktop()->winId(), geometry.x(), geometry.y(), geometry.width(), geometry.height());
mPixmap.setDevicePixelRatio(QApplication::desktop()->devicePixelRatio());
if (mOptions.cursor && !mPixmap.isNull()) {
QPainter painter(&mPixmap);
auto cursorInfo = os::cursor();
auto cursorPixmap = cursorInfo.first;
cursorPixmap.setDevicePixelRatio(QApplication::desktop()->devicePixelRatio());
#if 0 // Debug cursor position helper
painter.setBrush(QBrush(Qt::darkRed));
painter.setPen(QPen(QBrush(Qt::red), 5));
QRectF rect;
rect.setSize(QSizeF(100, 100));
rect.moveCenter(cursorPosition);
painter.drawRoundRect(rect, rect.size().height()*2, rect.size().height()*2);
#endif
painter.drawPixmap(cursorPosition-cursorInfo.second, cursorPixmap);
}
}
const QString Screenshot::newFileName() const
{
if (!mOptions.directory.exists()) {
mOptions.directory.mkpath(mOptions.directory.path());
}
QString naming = Screenshot::getName(mOptions.namingOptions, mOptions.prefix, mOptions.directory);
QString path = QDir::toNativeSeparators(mOptions.directory.path());
// Cleanup
if (path.at(path.size() - 1) != QDir::separator() && !path.isEmpty()) {
path.append(QDir::separator());
}
QString fileName;
fileName.append(path);
fileName.append(naming);
return fileName;
}
void Screenshot::selectedArea()
{
grabDesktop();
if (mPixmap.isNull()) {
return;
}
AreaDialog selector(this);
int result = selector.exec();
if (result == QDialog::Accepted) {
mPixmap = mPixmap.copy(selector.resultRect());
} else {
mPixmap = QPixmap();
}
}
void Screenshot::selectedWindow()
{
WindowPicker *windowPicker = new WindowPicker;
mPixmapDelay = true;
connect(windowPicker, SIGNAL(pixmap(QPixmap)), this, SLOT(setPixmap(QPixmap)));
}
bool Screenshot::unloadPixmap()
{
if (mUnloaded) {
return true;
}
// Unloading the pixmap to reduce memory usage during previews
mUnloadFilename = QString("%1/.screenshot.%2%3").arg(mOptions.directory.path()).arg(qrand() * qrand() + QDateTime::currentDateTime().toTime_t()).arg(extension());
mUnloaded = mPixmap.save(mUnloadFilename, 0, mOptions.quality);
if (mUnloaded) {
mPixmap = QPixmap();
}
return mUnloaded;
}
void Screenshot::wholeScreen()
{
grabDesktop();
}
diff --git a/tools/screenshotmanager.cpp b/tools/screenshotmanager.cpp
index bbeaeea..57a0742 100644
--- a/tools/screenshotmanager.cpp
+++ b/tools/screenshotmanager.cpp
@@ -1,233 +1,233 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include "screenshotmanager.h"
-#include "screenshot.h"
-#include "uploader/uploader.h"
+#include <tools/screenshotmanager.h>
+#include <tools/screenshot.h>
+#include <tools/uploader/uploader.h>
#include <QApplication>
#include <QDateTime>
#include <QStandardPaths>
#include <QFile>
#include <QSettings>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlRecord>
ScreenshotManager::ScreenshotManager(QObject *parent) : QObject(parent), mHistoryInitialized(false)
{
if (QFile::exists(qApp->applicationDirPath() + QDir::separator() + "config.ini")) {
mSettings = new QSettings(qApp->applicationDirPath() + QDir::separator() + "config.ini", QSettings::IniFormat, this);
mPortableMode = true;
mHistoryPath = qApp->applicationDirPath() + QDir::separator();
} else {
mSettings = new QSettings(this);
mPortableMode = false;
mHistoryPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator();
}
connect(Uploader::instance(), &Uploader::done, this, &ScreenshotManager::uploadDone);
}
void ScreenshotManager::initHistory()
{
if (mHistoryInitialized) {
return;
}
// Creating the SQLite database.
QSqlDatabase history = QSqlDatabase::addDatabase("QSQLITE");
QDir historyPath(mHistoryPath);
if (!historyPath.exists()) {
historyPath.mkpath(mHistoryPath);
}
history.setHostName("localhost");
history.setDatabaseName(mHistoryPath + "history.sqlite");
if (history.open()) {
QSqlQuery tableQuery;
mHistoryInitialized = tableQuery.exec("CREATE TABLE IF NOT EXISTS history (fileName text, URL text, deleteURL text, time integer)");
history.exec("CREATE INDEX IF NOT EXISTS fileName_index ON history(fileName)");
} else {
qCritical() << "Could not open SQLite DB.";
mHistoryInitialized = false;
}
}
int ScreenshotManager::activeCount() const
{
return mScreenshots.count();
}
bool ScreenshotManager::portableMode()
{
return mPortableMode;
}
void ScreenshotManager::saveHistory(const QString &fileName, const QString &url, const QString &deleteHash)
{
if (!mSettings->value("/options/history", true).toBool()) {
return;
}
if (!mHistoryInitialized) {
initHistory();
}
QString deleteUrl;
if (!deleteHash.isEmpty()) {
deleteUrl = "https://imgur.com/delete/" + deleteHash;
}
QSqlQuery saveHistoryQuery;
saveHistoryQuery.prepare("INSERT INTO history (fileName, URL, deleteURL, time) VALUES(?, ?, ?, ?)");
saveHistoryQuery.addBindValue(fileName);
saveHistoryQuery.addBindValue(url);
saveHistoryQuery.addBindValue(deleteUrl);
saveHistoryQuery.addBindValue(QDateTime::currentMSecsSinceEpoch());
saveHistoryQuery.exec();
}
void ScreenshotManager::updateHistory(const QString &fileName, const QString &url, const QString &deleteHash)
{
if (!mSettings->value("/options/history", true).toBool() || url.isEmpty()) {
return;
}
if (!mHistoryInitialized) {
initHistory();
}
QSqlQuery query;
query.prepare("SELECT fileName FROM history WHERE URL IS NOT EMPTY AND fileName = ?");
query.addBindValue(fileName);
query.exec();
if (query.record().count() > 0) {
QSqlQuery updateQuery;
updateQuery.prepare("UPDATE history SET URL = ?, deleteURL = ?, time = ? WHERE fileName = ?");
updateQuery.addBindValue(url);
updateQuery.addBindValue("https://imgur.com/delete/" + deleteHash);
updateQuery.addBindValue(QDateTime::currentMSecsSinceEpoch());
updateQuery.addBindValue(fileName);
updateQuery.exec();
} else {
saveHistory(fileName, url, deleteHash);
}
}
void ScreenshotManager::removeHistory(const QString &fileName, qint64 time)
{
if (!mHistoryInitialized) {
initHistory();
}
QSqlQuery removeQuery;
removeQuery.prepare("DELETE FROM history WHERE fileName = ? AND time = ?");
removeQuery.addBindValue(fileName);
removeQuery.addBindValue(time);
removeQuery.exec();
}
void ScreenshotManager::clearHistory()
{
if (!mHistoryInitialized) {
initHistory();
}
QSqlQuery deleteQuery("DELETE FROM history");
deleteQuery.exec();
QSqlQuery vacQuery("VACUUM");
vacQuery.exec();
}
//
void ScreenshotManager::askConfirmation()
{
Screenshot *s = qobject_cast<Screenshot *>(sender());
emit confirm(s);
}
void ScreenshotManager::cleanup()
{
Screenshot *screenshot = qobject_cast<Screenshot *>(sender());
emit windowCleanup(screenshot->options());
}
void ScreenshotManager::finished()
{
Screenshot *screenshot = qobject_cast<Screenshot *>(sender());
mScreenshots.removeOne(screenshot);
emit activeCountChange();
screenshot->deleteLater();
}
void ScreenshotManager::take(Screenshot::Options &options)
{
Screenshot *newScreenshot = new Screenshot(this, options);
mScreenshots.append(newScreenshot);
connect(newScreenshot, &Screenshot::askConfirmation, this, &ScreenshotManager::askConfirmation);
connect(newScreenshot, &Screenshot::cleanup , this, &ScreenshotManager::cleanup);
connect(newScreenshot, &Screenshot::finished , this, &ScreenshotManager::finished);
newScreenshot->take();
}
void ScreenshotManager::uploadDone(const QString &fileName, const QString &url, const QString &deleteHash)
{
for (Screenshot *screenshot : qAsConst(mScreenshots)) {
if (screenshot->options().fileName == fileName
|| screenshot->unloadedFileName() == fileName) {
screenshot->uploadDone(url);
if (screenshot->options().file) {
updateHistory(fileName, url, deleteHash);
} else {
saveHistory("", url, deleteHash);
}
return;
}
}
// If we get here, it's because the screenshot upload wasn't on the current screenshot list, which means it's a View History/Upload Later upload.
updateHistory(fileName, url, deleteHash);
}
// Singleton
ScreenshotManager *ScreenshotManager::mInstance = nullptr;
ScreenshotManager *ScreenshotManager::instance()
{
if (!mInstance) {
mInstance = new ScreenshotManager();
}
return mInstance;
}
diff --git a/tools/screenshotmanager.h b/tools/screenshotmanager.h
index 0babc1a..3a9dd5c 100644
--- a/tools/screenshotmanager.h
+++ b/tools/screenshotmanager.h
@@ -1,73 +1,73 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef SCREENSHOTMANAGER_H
#define SCREENSHOTMANAGER_H
#include <QObject>
#include <QList>
-#include "screenshot.h"
+#include <tools/screenshot.h>
class QSettings;
class ScreenshotManager : public QObject
{
Q_OBJECT
public:
enum State {
Idle = 0,
Busy = 1,
Disabled = 2
};
Q_ENUM(State)
ScreenshotManager(QObject *parent = 0);
static ScreenshotManager *instance();
void initHistory();
int activeCount() const;
bool portableMode();
void saveHistory(const QString &fileName, const QString &url = "", const QString &deleteHash = "");
void updateHistory(const QString &fileName, const QString &url, const QString &deleteHash);
void removeHistory(const QString &fileName, qint64 time);
void clearHistory();
QSettings *settings() const { return mSettings; }
public slots:
void askConfirmation();
void cleanup();
void finished();
void take(Screenshot::Options &options);
void uploadDone(const QString &fileName, const QString &url, const QString &deleteHash);
signals:
void confirm(Screenshot *screenshot);
void windowCleanup(const Screenshot::Options &options);
void activeCountChange();
private:
static ScreenshotManager *mInstance;
QList<Screenshot*> mScreenshots;
QSettings *mSettings;
QString mHistoryPath;
bool mPortableMode;
bool mHistoryInitialized;
};
#endif // SCREENSHOTMANAGER_H
diff --git a/tools/uploader/imageuploader.cpp b/tools/uploader/imageuploader.cpp
index d5a8fb0..fd19bbd 100644
--- a/tools/uploader/imageuploader.cpp
+++ b/tools/uploader/imageuploader.cpp
@@ -1,66 +1,66 @@
-#include "imageuploader.h"
-#include "imguruploader.h"
-#include "pomfuploader.h"
+#include <tools/uploader/imageuploader.h>
+#include <tools/uploader/imguruploader.h>
+#include <tools/uploader/pomfuploader.h>
#include <QSettings>
-#include "../screenshotmanager.h"
+#include <tools/screenshotmanager.h>
ImageUploader *ImageUploader::factory(const QString &name)
{
if (name == "imgur") {
return new ImgurUploader;
} else if (name == "pomf") {
return new PomfUploader;
}
return nullptr;
}
QVariantHash ImageUploader::loadSettings(const QString &uploaderType)
{
auto globalSettings = ScreenshotManager::instance()->settings();
globalSettings->beginGroup("upload/" + uploaderType);
auto keys = globalSettings->childKeys();
QVariantHash settings;
for (auto key : qAsConst(keys)) {
settings[key] = globalSettings->value(key);
}
globalSettings->endGroup();
return settings;
}
void ImageUploader::loadSettings()
{
mSettings = loadSettings(mUploaderType);
}
void ImageUploader::saveSettings(const QString &uploaderType, const QVariantHash &settings) {
auto globalSettings = ScreenshotManager::instance()->settings();
globalSettings->beginGroup("upload/" + uploaderType);
for (auto key : settings.keys()) {
globalSettings->setValue(key, settings[key]);
}
globalSettings->endGroup();
}
void ImageUploader::saveSettings()
{
saveSettings(mUploaderType, mSettings);
}
int ImageUploader::progress() const {
return mProgress;
}
void ImageUploader::setProgress(int progress)
{
if (mProgress != progress) {
mProgress = progress;
emit progressChanged(mProgress);
}
}
diff --git a/tools/uploader/imguruploader.cpp b/tools/uploader/imguruploader.cpp
index 213d93e..4023bde 100644
--- a/tools/uploader/imguruploader.cpp
+++ b/tools/uploader/imguruploader.cpp
@@ -1,221 +1,221 @@
-#include "imguruploader.h"
-#include "../uploader/uploader.h"
+#include <tools/uploader/imguruploader.h>
+#include <tools/uploader/uploader.h>
#include <QNetworkAccessManager>
#include <QtNetwork>
#include <QJsonDocument>
#include <QJsonObject>
ImgurUploader::ImgurUploader(QObject *parent) : ImageUploader(parent)
{
mUploaderType = "imgur";
loadSettings();
}
const QString ImgurUploader::clientId()
{
return QString("3ebe94c791445c1");
}
const QString ImgurUploader::clientSecret()
{
return QString("0546b05d6a80b2092dcea86c57b792c9c9faebf0");
}
void ImgurUploader::authorize(const QString &pin, AuthorizationCallback callback)
{
if (pin.isEmpty()) {
callback(false);
return;
}
QByteArray parameters;
parameters.append(QString("client_id=").toUtf8());
parameters.append(QUrl::toPercentEncoding(clientId()));
parameters.append(QString("&client_secret=").toUtf8());
parameters.append(QUrl::toPercentEncoding(clientSecret()));
parameters.append(QString("&grant_type=pin").toUtf8());
parameters.append(QString("&pin=").toUtf8());
parameters.append(QUrl::toPercentEncoding(pin));
QNetworkRequest request(QUrl("https://api.imgur.com/oauth2/token"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = Uploader::network()->post(request, parameters);
authorizationReply(reply, callback);
}
void ImgurUploader::refreshAuthorization(const QString &refresh_token, AuthorizationCallback callback)
{
if (refresh_token.isEmpty()) {
callback(false);
return;
}
QByteArray parameters;
parameters.append(QString("refresh_token=").toUtf8());
parameters.append(QUrl::toPercentEncoding(refresh_token));
parameters.append(QString("&client_id=").toUtf8());
parameters.append(QUrl::toPercentEncoding(clientId()));
parameters.append(QString("&client_secret=").toUtf8());
parameters.append(QUrl::toPercentEncoding(clientSecret()));
parameters.append(QString("&grant_type=refresh_token").toUtf8());
QNetworkRequest request(QUrl("https://api.imgur.com/oauth2/token"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *reply = Uploader::network()->post(request, parameters);
authorizationReply(reply, callback);
}
void ImgurUploader::upload(const QString &fileName)
{
QFile *file = new QFile(fileName);
if (!file->open(QIODevice::ReadOnly)) {
emit error(ImageUploader::FileError, tr("Unable to read screenshot file"), fileName);
file->deleteLater();
return;
}
QNetworkRequest request(QUrl("https://api.imgur.com/3/image"));
request.setRawHeader("Authorization", QString("Client-ID %1").arg(clientId()).toLatin1());
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
if (!mSettings.value("anonymous", true).toBool()) {
request.setRawHeader("Authorization", QByteArray("Bearer ") + mSettings.value("access_token").toByteArray());
if (!mSettings.value("album").toString().isEmpty()) {
QHttpPart albumPart;
albumPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"album\""));
albumPart.setBody(mSettings.value("album").toByteArray());
multiPart->append(albumPart);
}
}
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QMimeDatabase().mimeTypeForFile(fileName, QMimeDatabase::MatchExtension).name());
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image\""));
imagePart.setBodyDevice(file);
file->setParent(multiPart);
multiPart->append(imagePart);
QNetworkReply *reply = Uploader::network()->post(request, multiPart);
reply->setProperty("fileName", fileName);
this->setProperty("fileName", fileName);
multiPart->setParent(reply);
#ifdef Q_OS_WIN
connect(reply, &QNetworkReply::sslErrors, [reply](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
reply->ignoreSslErrors();
}
});
#endif
connect(reply, &QNetworkReply::uploadProgress, this, &ImgurUploader::uploadProgress);
connect(this , &ImgurUploader::cancelRequest, reply, &QNetworkReply::abort);
connect(this , &ImgurUploader::cancelRequest, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, this, &ImgurUploader::finished);
}
void ImgurUploader::retry()
{
loadSettings();
upload(property("fileName").toString());
}
void ImgurUploader::cancel()
{
emit cancelRequest();
}
void ImgurUploader::finished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
reply->deleteLater();
QString fileName = reply->property("fileName").toString();
if (reply->error() != QNetworkReply::NoError) {
if (reply->error() == QNetworkReply::OperationCanceledError) {
emit error(ImageUploader::CancelError, "", fileName);
} else if (reply->error() == QNetworkReply::ContentOperationNotPermittedError ||
reply->error() == QNetworkReply::AuthenticationRequiredError) {
refreshAuthorization(mSettings["refresh_token"].toString(), [&](bool result) {
if (result) {
QTimer::singleShot(50, this, &ImgurUploader::retry);
} else {
cancel();
emit error(ImageUploader::AuthorizationError, tr("Imgur user authentication failed"), fileName);
}
});
} else {
emit error(ImageUploader::NetworkError, reply->errorString(), fileName);
}
return;
}
if (reply->rawHeader("X-RateLimit-Remaining") == "0") {
emit error(ImageUploader::HostError, tr("Imgur upload limit reached"), fileName);
return;
}
QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (imgurResponse.value("success").toBool() == true && imgurResponse.value("status").toInt() == 200) {
QJsonObject imageData = imgurResponse.value("data").toObject();
emit uploaded(fileName, imageData["link"].toString(), imageData["deletehash"].toString());
} else {
emit error(ImageUploader::HostError, tr("Imgur error"), fileName);
}
}
void ImgurUploader::uploadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
float b = (float) bytesReceived / bytesTotal;
int p = qRound(b * 100);
setProgress(p);
}
void ImgurUploader::authorizationReply(QNetworkReply *reply, AuthorizationCallback callback)
{
#ifdef Q_OS_WIN
connect(reply, &QNetworkReply::sslErrors, [reply](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
reply->ignoreSslErrors();
}
});
#endif
connect(reply, &QNetworkReply::finished, [reply, callback] {
reply->deleteLater();
bool authorized = false;
const QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (!imgurResponse.isEmpty() && imgurResponse.contains("access_token")) {
QVariantHash newSettings;
newSettings["access_token"] = imgurResponse.value("access_token").toString();
newSettings["refresh_token"] = imgurResponse.value("refresh_token").toString();
newSettings["account_username"] = imgurResponse.value("account_username").toString();
newSettings["expires_in"] = imgurResponse.value("expires_in").toInt();
ImgurUploader::saveSettings("imgur", newSettings);
authorized = true;
}
callback(authorized);
});
}
diff --git a/tools/uploader/imguruploader.h b/tools/uploader/imguruploader.h
index 4f9dd59..a9e95ce 100644
--- a/tools/uploader/imguruploader.h
+++ b/tools/uploader/imguruploader.h
@@ -1,40 +1,40 @@
#ifndef IMGURUPLOADER_H
#define IMGURUPLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
-#include "imageuploader.h"
+#include <tools/uploader/imageuploader.h>
#include <functional>
class ImgurUploader : public ImageUploader
{
Q_OBJECT
public:
typedef std::function<void(bool)> AuthorizationCallback;
ImgurUploader(QObject *parent = 0);
static const QString clientId();
static const QString clientSecret();
static void authorize(const QString &pin, AuthorizationCallback callback);
static void refreshAuthorization(const QString &refresh_token, AuthorizationCallback callback);
public slots:
void upload(const QString &fileName);
void retry();
void cancel();
private slots:
void finished();
void uploadProgress(qint64 bytesReceived, qint64 bytesTotal);
signals:
void cancelRequest();
private:
static void authorizationReply(QNetworkReply *reply, AuthorizationCallback callback);
};
#endif // IMGURUPLOADER_H
diff --git a/tools/uploader/pomfuploader.cpp b/tools/uploader/pomfuploader.cpp
index 9d42ed2..38dfcb4 100644
--- a/tools/uploader/pomfuploader.cpp
+++ b/tools/uploader/pomfuploader.cpp
@@ -1,142 +1,142 @@
-#include "pomfuploader.h"
-#include "../uploader/uploader.h"
+#include <tools/uploader/pomfuploader.h>
+#include <tools/uploader/uploader.h>
#include <QtNetwork>
#include <QJsonDocument>
#include <QJsonObject>
PomfUploader::PomfUploader(QObject *parent) : ImageUploader(parent)
{
mUploaderType = "pomf";
loadSettings();
}
QNetworkReply* PomfUploader::verify(const QString &url, VerificationCallback callback)
{
QNetworkRequest request(QUrl::fromUserInput(QString("%1/upload.php").arg(url)));
if (!request.url().isValid()) {
callback(false);
return 0;
}
QNetworkReply *reply = Uploader::network()->get(request);
connect(reply, &QNetworkReply::finished, [reply, callback] {
reply->deleteLater();
const QJsonObject pomfResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (!pomfResponse.isEmpty() && pomfResponse.contains("success")) {
callback(true);
} else {
callback(false);
}
});
connect(reply, &QNetworkReply::sslErrors, [reply, callback](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
reply->ignoreSslErrors();
} else {
callback(false);
}
});
return reply;
}
void PomfUploader::upload(const QString &fileName)
{
QString pomfUrl = mSettings["pomf_url"].toString();
if (pomfUrl.isEmpty()) {
emit error(ImageUploader::HostError, tr("Invalid pomf uploader URL!"), fileName);
return;
}
QUrl url = QUrl::fromUserInput(pomfUrl + "/upload.php");
QFile *file = new QFile(fileName);
if (!file->open(QIODevice::ReadOnly)) {
emit error(ImageUploader::FileError, tr("Unable to read screenshot file"), fileName);
file->deleteLater();
return;
}
QNetworkRequest request(url);
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QMimeDatabase().mimeTypeForFile(fileName, QMimeDatabase::MatchExtension).name());
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"files[]\"; filename=\"%1\"").arg(QFileInfo(fileName).fileName()));
imagePart.setBodyDevice(file);
file->setParent(multiPart);
multiPart->append(imagePart);
QNetworkReply *reply = Uploader::network()->post(request, multiPart);
this->setProperty("fileName", fileName);
multiPart->setParent(reply);
connect(this , &PomfUploader::cancelRequest, reply, &QNetworkReply::abort);
connect(this , &PomfUploader::cancelRequest, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::uploadProgress, this, [&](qint64 bytesSent, qint64 bytesTotal) {
float b = (float) bytesSent / bytesTotal;
int p = qRound(b * 100);
setProgress(p);
});
connect(reply, &QNetworkReply::finished, this, [&, reply, fileName] {
const QJsonObject pomfResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (reply->error() != QNetworkReply::NoError && pomfResponse.isEmpty()) {
emit error(ImageUploader::NetworkError, tr("Error reaching uploader"), fileName);
return;
}
if (!pomfResponse.contains("success") || !pomfResponse.contains("files")) {
emit error(ImageUploader::HostError, tr("Invalid response from uploader"), fileName);
return;
}
if (pomfResponse["success"].toBool()) {
emit uploaded(fileName, pomfResponse["files"].toArray().at(0).toObject()["url"].toString(), "");
} else {
QString description;
if (pomfResponse.contains("description")) {
description = pomfResponse["description"].toString();
}
if (description.isEmpty()) {
description = tr("Host error");
}
emit error(ImageUploader::HostError, description, fileName);
}
});
#ifdef Q_OS_WIN
connect(reply, &QNetworkReply::sslErrors, [reply](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
reply->ignoreSslErrors();
}
});
#endif
}
void PomfUploader::retry()
{
upload(property("fileName").toString());
}
void PomfUploader::cancel()
{
emit cancelRequest();
}
diff --git a/tools/uploader/pomfuploader.h b/tools/uploader/pomfuploader.h
index 8563a19..d393cdb 100644
--- a/tools/uploader/pomfuploader.h
+++ b/tools/uploader/pomfuploader.h
@@ -1,27 +1,27 @@
#ifndef POMFUPLOADER_H
#define POMFUPLOADER_H
-#include "imageuploader.h"
+#include <tools/uploader/imageuploader.h>
#include <functional>
class PomfUploader : public ImageUploader
{
Q_OBJECT
public:
PomfUploader(QObject *parent = 0);
typedef std::function<void(bool)> VerificationCallback;
static QNetworkReply* verify(const QString &url, VerificationCallback callback);
public slots:
void upload(const QString &fileName);
void retry();
void cancel();
signals:
void cancelRequest();
};
#endif // POMFUPLOADER_H
diff --git a/tools/uploader/uploader.cpp b/tools/uploader/uploader.cpp
index fc33c05..36b79a9 100644
--- a/tools/uploader/uploader.cpp
+++ b/tools/uploader/uploader.cpp
@@ -1,141 +1,141 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include "uploader.h"
-#include "../screenshotmanager.h"
-#include "imguruploader.h"
+#include <tools/uploader/uploader.h>
+#include <tools/screenshotmanager.h>
+#include <tools/uploader/imguruploader.h>
#include <QtNetwork>
#include <QSettings>
Uploader *Uploader::mInstance = 0;
Uploader::Uploader(QObject *parent) : QObject(parent), mProgress(0)
{
mNetworkAccessManager = new QNetworkAccessManager(this);
}
Uploader *Uploader::instance()
{
if (!mInstance) {
mInstance = new Uploader();
}
return mInstance;
}
QNetworkAccessManager *Uploader::network()
{
return instance()->mNetworkAccessManager;
}
int Uploader::progress() const
{
return mProgress;
}
QString Uploader::serviceName(int index)
{ // TODO: Move somewhere else? Use indexes everywhere? an enum?
switch (index) {
case 1:
return "pomf";
case 0:
default:
return "imgur";
}
}
QString Uploader::lastUrl() const
{
return mLastUrl;
}
void Uploader::cancel()
{
mUploaders.clear();
mProgress = 0;
emit cancelAll();
}
void Uploader::upload(const QString &fileName, const QString &uploadService)
{
if (fileName.isEmpty()) {
return;
}
auto uploader = ImageUploader::factory(uploadService);
connect(uploader, &ImageUploader::progressChanged, this , &Uploader::reportProgress);
connect(this , &Uploader::cancelAll , uploader, &ImageUploader::cancel);
connect(uploader, &ImageUploader::error, [&, uploader](ImageUploader::Error errorCode, const QString &errorString, const QString &fileName) {
mUploaders.removeAll(uploader);
uploader->deleteLater();
mProgress = 0; // TODO: ?
if (errorCode != ImageUploader::CancelError) {
if (errorString.isEmpty()) {
emit error(tr("Upload Error %1").arg(errorCode));
} else {
emit error(errorString);
}
}
emit done(fileName, "", "");
});
connect(uploader, &ImageUploader::uploaded, [&, uploader](const QString &file, const QString &url, const QString &deleteHash) {
mLastUrl = url;
mUploaders.removeAll(uploader);
if (mUploaders.isEmpty()) {
mProgress = 0;
}
uploader->deleteLater();
emit done(file, url, deleteHash);
});
mUploaders.append(uploader);
uploader->upload(fileName);
}
int Uploader::uploading() const
{
return mUploaders.count();
}
void Uploader::reportProgress(int progress)
{
if (mUploaders.size() <= 0) {
mProgress = progress;
emit progressChanged(progress);
return;
}
int totalProgress = 0;
for (int i = 0; i < mUploaders.size(); ++i) {
totalProgress += mUploaders[i]->progress();
}
mProgress = totalProgress / mUploaders.size();
emit progressChanged(mProgress);
}
diff --git a/tools/uploader/uploader.h b/tools/uploader/uploader.h
index 009c90a..c48976e 100644
--- a/tools/uploader/uploader.h
+++ b/tools/uploader/uploader.h
@@ -1,63 +1,64 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef UPLOADER_H
#define UPLOADER_H
#include <QObject>
#include <QtNetwork>
-#include "imageuploader.h"
+
+#include <tools/uploader/imageuploader.h>
class Uploader : public QObject
{
Q_OBJECT
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
Q_PROPERTY(QString lastUrl READ lastUrl)
public:
Uploader(QObject *parent = 0);
static Uploader *instance();
static QNetworkAccessManager *network();
static QString serviceName(int index);
QString lastUrl() const;
int progress() const;
int uploading() const;
public slots:
void cancel();
void upload(const QString &fileName, const QString &uploadService);
void reportProgress(int progressChanged);
signals:
void done(const QString &fileName, const QString &url, const QString &deleteHash);
void error(const QString &errorString);
void progressChanged(int progressChanged);
void cancelAll();
private:
static Uploader *mInstance;
QNetworkAccessManager *mNetworkAccessManager;
int mProgress;
QString mLastUrl;
QList<ImageUploader *> mUploaders;
};
#endif // UPLOADER_H
diff --git a/tools/windowpicker.cpp b/tools/windowpicker.cpp
index 87caa2c..6238f3d 100644
--- a/tools/windowpicker.cpp
+++ b/tools/windowpicker.cpp
@@ -1,304 +1,304 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDesktopWidget>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QRubberBand>
#include <QRubberBand>
#include <QVBoxLayout>
#include <QWidget>
-#include "windowpicker.h"
-#include "os.h"
+#include <tools/windowpicker.h>
+#include <tools/os.h>
#if defined(Q_OS_WIN)
#include <QtWin>
#include <windows.h>
#ifdef _WIN64
#define GCL_HICON GCLP_HICON
#define GCL_HICONSM GCLP_HICONSM
#endif
#elif defined(Q_OS_LINUX)
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#endif
WindowPicker::WindowPicker() : QWidget(0), mCrosshair(":/icons/picker"), mWindowLabel(Q_NULLPTR), mTaken(false), mCurrentWindow(0)
{
#if defined(Q_OS_WIN)
setWindowFlags(Qt::SplashScreen | Qt::WindowStaysOnTopHint);
#elif defined(Q_OS_LINUX)
setWindowFlags(Qt::WindowStaysOnTopHint);
#endif
setWindowTitle(tr("Lightscreen Window Picker"));
setStyleSheet("QWidget { color: #000; } #frame { padding: 7px 10px; border: 4px solid #232323; background-color: rgba(250, 250, 250, 255); }");
QLabel *helpLabel = new QLabel(tr("Grab the window picker by clicking and holding down the mouse button, then drag it to the window of your choice and release it to capture."), this);
helpLabel->setMinimumWidth(400);
helpLabel->setMaximumWidth(400);
helpLabel->setWordWrap(true);
mWindowIcon = new QLabel(this);
mWindowIcon->setMinimumSize(22, 22);
mWindowIcon->setMaximumSize(22, 22);
mWindowIcon->setScaledContents(true);
mWindowLabel = new QLabel(tr(" - Start dragging to select windows"), this);
mWindowLabel->setStyleSheet("font-weight: bold");
mCrosshairLabel = new QLabel(this);
mCrosshairLabel->setAlignment(Qt::AlignHCenter);
mCrosshairLabel->setPixmap(mCrosshair);
QPushButton *closeButton = new QPushButton(tr("Close"));
connect(closeButton, &QPushButton::clicked, this, &WindowPicker::close);
QHBoxLayout *windowLayout = new QHBoxLayout;
windowLayout->addWidget(mWindowIcon);
windowLayout->addWidget(mWindowLabel);
windowLayout->setMargin(0);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(0);
buttonLayout->addWidget(closeButton);
buttonLayout->setMargin(0);
QHBoxLayout *crosshairLayout = new QHBoxLayout;
crosshairLayout->addStretch(0);
crosshairLayout->addWidget(mCrosshairLabel);
crosshairLayout->addStretch(0);
crosshairLayout->setMargin(0);
QVBoxLayout *fl = new QVBoxLayout;
fl->addWidget(helpLabel);
fl->addLayout(windowLayout);
fl->addLayout(crosshairLayout);
fl->addLayout(buttonLayout);
fl->setMargin(0);
QFrame *frame = new QFrame(this);
frame->setObjectName("frame");
frame->setLayout(fl);
QVBoxLayout *l = new QVBoxLayout;
l->setMargin(0);
l->addWidget(frame);
setLayout(l);
resize(sizeHint());
move(QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(QCursor::pos())).center() - QPoint(width() / 2, height() / 2));
show();
}
WindowPicker::~WindowPicker()
{
qApp->restoreOverrideCursor();
}
void WindowPicker::cancel()
{
mWindowIcon->setPixmap(QPixmap());
mCrosshairLabel->setPixmap(mCrosshair);
qApp->restoreOverrideCursor();
}
void WindowPicker::closeEvent(QCloseEvent *)
{
if (!mTaken) {
emit pixmap(QPixmap());
}
qApp->restoreOverrideCursor();
deleteLater();
}
void WindowPicker::mouseMoveEvent(QMouseEvent *event)
{
QString windowName;
#if defined(Q_OS_WIN)
POINT mousePos;
mousePos.x = event->globalX();
mousePos.y = event->globalY();
HWND cWindow = GetAncestor(WindowFromPoint(mousePos), GA_ROOT);
mCurrentWindow = (WId) cWindow;
if (mCurrentWindow == winId()) {
mWindowIcon->setPixmap(QPixmap());
mWindowLabel->setText("");
return;
}
// Text
WCHAR str[60];
HICON icon;
::GetWindowText((HWND)mCurrentWindow, str, 60);
windowName = QString::fromWCharArray(str);
///
// Retrieving the application icon
icon = (HICON)::GetClassLong((HWND)mCurrentWindow, GCL_HICON);
if (icon != NULL) {
mWindowIcon->setPixmap(QtWin::fromHICON(icon));
} else {
mWindowIcon->setPixmap(QPixmap());
}
#elif defined(Q_OS_LINUX)
Window cWindow = os::windowUnderCursor(false);
if (cWindow == mCurrentWindow) {
return;
}
mCurrentWindow = cWindow;
if (mCurrentWindow == winId()) {
mWindowIcon->setPixmap(QPixmap());
mWindowLabel->setText("");
return;
}
// Getting the window name property.
XTextProperty tp;
char **text;
int count;
if (XGetTextProperty(QX11Info::display(), cWindow, &tp, XA_WM_NAME) != 0 && tp.value != NULL) {
if (tp.encoding == XA_STRING) {
windowName = QString::fromLocal8Bit((const char *) tp.value);
} else if (XmbTextPropertyToTextList(QX11Info::display(), &tp, &text, &count) == Success &&
text != NULL && count > 0) {
windowName = QString::fromLocal8Bit(text[0]);
XFreeStringList(text);
}
XFree(tp.value);
}
// Retrieving the _NET_WM_ICON property.
Atom type_ret = None;
unsigned char *data = 0;
int format = 0;
unsigned long n = 0;
unsigned long extra = 0;
int width = 0;
int height = 0;
Atom _net_wm_icon = XInternAtom(QX11Info::display(), "_NET_WM_ICON", False);
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 0, 1, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data) {
width = data[0];
XFree(data);
}
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 1, 1, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data) {
height = data[0];
XFree(data);
}
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 2, width * height, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data) {
QImage img(data, width, height, QImage::Format_ARGB32);
mWindowIcon->setPixmap(QPixmap::fromImage(img));
XFree(data);
} else {
mWindowIcon->setPixmap(QPixmap());
}
#endif
QString windowText;
if (!mWindowIcon->pixmap()) {
windowText = QString(" - %1").arg(windowName);
} else {
windowText = windowName;
}
if (windowText == " - ") {
mWindowLabel->setText("");
return;
}
if (windowText.length() == 62) {
mWindowLabel->setText(windowText + "...");
} else {
mWindowLabel->setText(windowText);
}
}
void WindowPicker::mousePressEvent(QMouseEvent *event)
{
qApp->setOverrideCursor(QCursor(mCrosshair));
mCrosshairLabel->setMinimumWidth(mCrosshairLabel->width());
mCrosshairLabel->setMinimumHeight(mCrosshairLabel->height());
mCrosshairLabel->setPixmap(QPixmap());
QWidget::mousePressEvent(event);
}
void WindowPicker::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
#if defined(Q_OS_WIN)
POINT mousePos;
mousePos.x = event->globalX();
mousePos.y = event->globalY();
HWND nativeWindow = GetAncestor(WindowFromPoint(mousePos), GA_ROOT);
#elif defined(Q_OS_LINUX)
Window nativeWindow = os::windowUnderCursor(false);
#endif
if ((WId)nativeWindow == winId()) {
cancel();
return;
}
mTaken = true;
setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
close();
#ifdef Q_OS_LINUX
emit pixmap(QPixmap::grabWindow(mCurrentWindow));
#else
emit pixmap(os::grabWindow((WId)nativeWindow));
#endif
return;
}
close();
}
diff --git a/updater/updater.cpp b/updater/updater.cpp
index d34757d..a008967 100644
--- a/updater/updater.cpp
+++ b/updater/updater.cpp
@@ -1,98 +1,98 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDate>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QVersionNumber>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSettings>
-#include "updater.h"
-#include "../dialogs/updaterdialog.h"
-#include "../tools/screenshotmanager.h"
+#include <updater/updater.h>
+#include <dialogs/updaterdialog.h>
+#include <tools/screenshotmanager.h>
Updater::Updater(QObject *parent) :
QObject(parent)
{
connect(&mNetwork, &QNetworkAccessManager::finished, this, &Updater::finished);
}
void Updater::check()
{
QNetworkRequest request(QUrl("https://lightscreen.com.ar/version_telemetry"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject telemetryObject;
telemetryObject.insert("version", qApp->applicationVersion());
telemetryObject.insert("manual_check", property("withFeedback").toBool());
telemetryObject.insert("platform", QJsonObject{
{"product_type", QSysInfo::productType()},
{"product_version", QSysInfo::productVersion()},
{"kernel_type", QSysInfo::kernelType()},
{"kernel_version", QSysInfo::kernelVersion()}
});
auto settings = ScreenshotManager::instance()->settings();
if (settings->value("options/telemetry", false).toBool()) {
QJsonObject settingsObject;
const auto keys = settings->allKeys();
for (const auto& key : qAsConst(keys)) {
if (key.contains("token") ||
key.contains("username") ||
key.contains("album") ||
key.contains("lastScreenshot") ||
key.contains("target") ||
key.contains("geometry")) {
continue; // Privacy/useless stuff
}
settingsObject.insert(key, QJsonValue::fromVariant(settings->value(key)));
}
telemetryObject.insert("settings", settingsObject);
}
mNetwork.post(request, QJsonDocument(telemetryObject).toJson());
}
void Updater::checkWithFeedback()
{
UpdaterDialog updaterDialog;
connect(this, &Updater::done, &updaterDialog, &UpdaterDialog::updateDone);
setProperty("withFeedback", true);
check();
updaterDialog.exec();
}
void Updater::finished(QNetworkReply *reply)
{
QByteArray data = reply->readAll();
auto currentVersion = QVersionNumber::fromString(qApp->applicationVersion()).normalized();
auto remoteVersion = QVersionNumber::fromString(QString(data)).normalized();
emit done(remoteVersion > currentVersion);
}
diff --git a/version.pri b/version.pri
index 04ac2ee..42876b7 100644
--- a/version.pri
+++ b/version.pri
@@ -1,7 +1,7 @@
VERSION = 2.5
QMAKE_TARGET_COMPANY = Christian Kaiser
QMAKE_TARGET_PRODUCT = Lightscreen
QMAKE_TARGET_DESCRIPTION = Lightscreen Screenshot Tool
-QMAKE_TARGET_COPYRIGHT = Copyright (C) 2008-2016 Christian Kaiser
+QMAKE_TARGET_COPYRIGHT = Copyright (C) 2008-2018 Christian Kaiser
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
diff --git a/widgets/hotkeywidget.cpp b/widgets/hotkeywidget.cpp
index e33f246..c7aa17c 100644
--- a/widgets/hotkeywidget.cpp
+++ b/widgets/hotkeywidget.cpp
@@ -1,162 +1,162 @@
/*
* Copyright (C) 2017 Christian Kaiser
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QFocusEvent>
#include <QKeyEvent>
#include <QKeySequence>
#include <QStyle>
#include <QTimer>
-#include "hotkeywidget.h"
+#include <widgets/hotkeywidget.h>
HotkeyWidget::HotkeyWidget(QWidget *parent) :
QPushButton(parent), mHotkey(QKeySequence()), mShowingError(false), mKeyboardFocus(false)
{
mDefaultStyleSheet = "text-align: left; padding: 3px 6px;";
setStyleSheet(mDefaultStyleSheet);
setText(tr("Click to select hotkey..."));
setObjectName("HotkeyWidget");
if (qApp->style()->objectName() == "oxygen") {
setMinimumWidth(130);
} else {
setMinimumWidth(110);
}
}
void HotkeyWidget::setHotkey(const QString &hotkeyString)
{
mHotkey = QKeySequence().fromString(hotkeyString, QKeySequence::NativeText);
setHotkeyText();
}
QString HotkeyWidget::hotkey() const
{
return mHotkey.toString(QKeySequence::PortableText);
}
void HotkeyWidget::showError()
{
if (mShowingError) {
return;
}
mShowingError = true;
setStyleSheet(mDefaultStyleSheet + "color: #d90000;");
QTimer::singleShot(1000, this, &HotkeyWidget::hideError);
}
void HotkeyWidget::setHotkeyText()
{
QString hotkeyText = mHotkey.toString(QKeySequence::NativeText);
setText(hotkeyText);
parentWidget()->setFocus();
}
bool HotkeyWidget::event(QEvent *event)
{
if (event->type() == QEvent::LanguageChange) {
setHotkeyText();
} else if (event->type() == QEvent::KeyPress) {
keyPressEvent(static_cast<QKeyEvent *>(event));
return true;
} else if (event->type() == QEvent::FocusIn) {
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
if (focusEvent->reason() != Qt::TabFocusReason) {
setText(tr("Type your hotkey"));
mKeyboardFocus = false;
grabKeyboard();
} else {
mKeyboardFocus = true;
}
} else if (event->type() == QEvent::FocusOut) {
if (text() == tr("Invalid hotkey")) {
emit invalidHotkeyError();
showError();
}
releaseKeyboard();
setHotkeyText(); // Reset the text
} else if ((event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride || event->type() == QEvent::Shortcut) && hasFocus()) {
event->accept();
return true;
}
return QPushButton::event(event);
}
void HotkeyWidget::keyPressEvent(QKeyEvent *event)
{
if (mKeyboardFocus) {
return;
}
if (isModifier(event->key())) {
return;
}
if (!isValid(event->key())) {
setText(tr("Invalid hotkey"));
parentWidget()->setFocus();
return;
}
mHotkey = QKeySequence(event->key() + (event->modifiers() & ~Qt::KeypadModifier));
setHotkeyText();
}
void HotkeyWidget::hideError()
{
setStyleSheet(mDefaultStyleSheet);
mShowingError = false;
}
bool HotkeyWidget::isValid(int key) const
{
switch (key) {
case 0:
case Qt::Key_Escape:
case Qt::Key_unknown:
return false;
}
return !isModifier(key);
}
bool HotkeyWidget::isModifier(int key) const
{
switch (key) {
case Qt::Key_Shift:
case Qt::Key_Control:
case Qt::Key_Meta:
case Qt::Key_Alt:
case Qt::Key_AltGr:
case Qt::Key_Super_L:
case Qt::Key_Super_R:
case Qt::Key_Menu:
return true;
}
return false;
}
diff --git a/widgets/imguroptionswidget.cpp b/widgets/imguroptionswidget.cpp
index 914e4a3..f2543fb 100644
--- a/widgets/imguroptionswidget.cpp
+++ b/widgets/imguroptionswidget.cpp
@@ -1,175 +1,175 @@
#include <QJsonObject>
#include <QInputDialog>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QMessageBox>
-#include "imguroptionswidget.h"
-#include "../uploader/uploader.h"
-#include "../uploader/imguruploader.h"
+#include <widgets/imguroptionswidget.h>
+#include <tools/uploader/uploader.h>
+#include <tools/uploader/imguruploader.h>
-#include "../screenshotmanager.h"
+#include <tools/screenshotmanager.h>
ImgurOptionsWidget::ImgurOptionsWidget(QWidget *parent) : QWidget(parent)
{
ui.setupUi(this);
connect(ui.authButton , &QPushButton::clicked, this, &ImgurOptionsWidget::authorize);
connect(ui.refreshAlbumButton, &QPushButton::clicked, this, &ImgurOptionsWidget::requestAlbumList);
connect(ui.authUserLabel , &QLabel::linkActivated, this, [](const QString & link) {
QDesktopServices::openUrl(link);
});
}
QSettings *ImgurOptionsWidget::settings()
{
return ScreenshotManager::instance()->settings();
}
void ImgurOptionsWidget::setUser(const QString &username)
{
mCurrentUser = username;
setUpdatesEnabled(false);
if (mCurrentUser.isEmpty()) {
ui.authUserLabel->setText(tr("<i>none</i>"));
ui.albumComboBox->setEnabled(false);
ui.refreshAlbumButton->setEnabled(false);
ui.albumComboBox->clear();
ui.albumComboBox->addItem(tr("- None -"));
ui.authButton->setText(tr("Authorize"));
ui.helpLabel->setEnabled(true);
settings()->setValue("access_token", "");
settings()->setValue("refresh_token", "");
settings()->setValue("account_username", "");
settings()->setValue("expires_in", 0);
} else {
ui.authButton->setText(tr("Deauthorize"));
ui.authUserLabel->setText(tr("<b><a href=\"http://%1.imgur.com/all/\">%1</a></b>").arg(username));
ui.refreshAlbumButton->setEnabled(true);
ui.helpLabel->setEnabled(false);
}
setUpdatesEnabled(true);
}
void ImgurOptionsWidget::authorize()
{
if (!mCurrentUser.isEmpty()) {
setUser("");
return;
}
QDesktopServices::openUrl(QUrl("https://api.imgur.com/oauth2/authorize?client_id=" + ImgurUploader::clientId() + "&response_type=pin"));
bool ok;
QString pin = QInputDialog::getText(this, tr("Imgur Authorization"),
tr("Authentication PIN:"), QLineEdit::Normal,
"", &ok);
if (ok) {
ui.authButton->setText(tr("Authorizing.."));
ui.authButton->setEnabled(false);
QPointer<QWidget> guard(parentWidget());
ImgurUploader::authorize(pin, [&, guard](bool result) {
if (guard.isNull()) return;
ui.authButton->setEnabled(true);
if (result) {
setUser(settings()->value("upload/imgur/account_username").toString());
QTimer::singleShot(0, this, &ImgurOptionsWidget::requestAlbumList);
} else {
QMessageBox::critical(this, tr("Imgur Authorization Error"), tr("There's been an error authorizing your account with Imgur, please try again."));
setUser("");
}
});
}
}
void ImgurOptionsWidget::requestAlbumList()
{
if (mCurrentUser.isEmpty()) {
return;
}
ui.refreshAlbumButton->setEnabled(true);
ui.albumComboBox->clear();
ui.albumComboBox->setEnabled(false);
ui.albumComboBox->addItem(tr("Loading album data..."));
QNetworkRequest request(QUrl::fromUserInput("https://api.imgur.com/3/account/" + mCurrentUser + "/albums/"));
request.setRawHeader("Authorization", QByteArray("Bearer ") + settings()->value("upload/imgur/access_token").toByteArray());
QNetworkReply *reply = Uploader::network()->get(request);
QPointer<QWidget> guard(parentWidget());
connect(reply, &QNetworkReply::finished, this, [&, guard, reply] {
if (mCurrentUser.isEmpty() || guard.isNull()) return;
if (reply->error() != QNetworkReply::NoError)
{
if (reply->error() == QNetworkReply::ContentOperationNotPermittedError ||
reply->error() == QNetworkReply::AuthenticationRequiredError) {
ImgurUploader::refreshAuthorization(settings()->value("upload/imgur/refresh_token", "").toString(), [&](bool result) {
if (result) {
QTimer::singleShot(50, this, &ImgurOptionsWidget::requestAlbumList);
} else {
setUser("");
}
});
}
ui.albumComboBox->addItem(tr("Loading failed :("));
return;
}
const QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (imgurResponse["success"].toBool() != true || imgurResponse["status"].toInt() != 200)
{
return;
}
const QJsonArray albumList = imgurResponse["data"].toArray();
setUpdatesEnabled(false);
ui.albumComboBox->clear();
ui.albumComboBox->setEnabled(true);
ui.albumComboBox->addItem(tr("- None -"), "");
ui.refreshAlbumButton->setEnabled(true);
int settingsIndex = 0;
for (auto albumValue : albumList) {
const QJsonObject album = albumValue.toObject();
QString albumVisibleTitle = album["title"].toString();
if (albumVisibleTitle.isEmpty()) {
albumVisibleTitle = tr("untitled");
}
ui.albumComboBox->addItem(albumVisibleTitle, album["id"].toString());
if (album["id"].toString() == settings()->value("upload/imgur/album").toString()) {
settingsIndex = ui.albumComboBox->count() - 1;
}
}
ui.albumComboBox->setCurrentIndex(settingsIndex);
setUpdatesEnabled(true);
});
#ifdef Q_OS_WIN
connect(reply, &QNetworkReply::sslErrors, [reply](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
reply->ignoreSslErrors();
}
});
#endif
}
diff --git a/widgets/pomfoptionswidget.cpp b/widgets/pomfoptionswidget.cpp
index ef511aa..4ffcd2a 100644
--- a/widgets/pomfoptionswidget.cpp
+++ b/widgets/pomfoptionswidget.cpp
@@ -1,144 +1,144 @@
#include <QJsonObject>
#include <QInputDialog>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QMessageBox>
#include <QRegExpValidator>
-#include "pomfoptionswidget.h"
-#include "../uploader/uploader.h"
-#include "../uploader/pomfuploader.h"
+#include <widgets/pomfoptionswidget.h>
+#include <tools/uploader/uploader.h>
+#include <tools/uploader/pomfuploader.h>
-#include "../screenshotmanager.h"
-#include "../os.h"
+#include <tools/screenshotmanager.h>
+#include <tools/os.h>
PomfOptionsWidget::PomfOptionsWidget(QWidget *parent) : QWidget(parent)
{
ui.setupUi(this);
ui.progressIndicatorBar->setVisible(false);
ui.cancelButton->setVisible(false);
connect(ui.verifyButton, &QPushButton::clicked, this, [&]() {
ui.verifyButton->setEnabled(false);
ui.downloadListButton->setEnabled(false);
ui.progressIndicatorBar->setVisible(true);
ui.cancelButton->setVisible(true);
disconnect(ui.cancelButton);
ui.cancelButton->disconnect();
QPointer<QWidget> guard(parentWidget());
QPointer<QNetworkReply> reply = PomfUploader::verify(ui.pomfUrlComboBox->currentText(), [&, guard](bool result) {
if (guard.isNull()) return;
ui.verifyButton->setEnabled(true);
ui.downloadListButton->setEnabled(true);
ui.progressIndicatorBar->setVisible(false);
if (result) {
ui.verifyButton->setText(tr("Valid uploader!"));
ui.verifyButton->setStyleSheet("color: green;");
ui.verifyButton->setIcon(os::icon("yes"));
} else if (ui.cancelButton->isVisible() == true) { // Not cancelled
ui.verifyButton->setStyleSheet("color: red;");
ui.verifyButton->setIcon(os::icon("no"));
ui.verifyButton->setText(tr("Invalid uploader :("));
}
ui.cancelButton->setVisible(false);
});
if (reply) {
connect(ui.cancelButton, &QPushButton::clicked, [&, reply] {
if (reply) {
ui.cancelButton->setVisible(false);
reply->abort();
}
});
}
});
connect(ui.pomfUrlComboBox, &QComboBox::currentTextChanged, [&](const QString &text) {
bool validUrl = false;
if (!text.isEmpty() && (text.startsWith("http://") || text.startsWith("https://"))) { // TODO: Something a bit more complex
validUrl = true;
}
ui.verifyButton->setEnabled(validUrl);
if (ui.verifyButton->styleSheet().count() > 0) {
ui.verifyButton->setStyleSheet("");
ui.verifyButton->setIcon(QIcon());
ui.verifyButton->setText(tr("Verify"));
}
});
connect(ui.helpLabel, &QLabel::linkActivated, this, [&](const QString &url) {
QDesktopServices::openUrl(url);
});
connect(ui.downloadListButton, &QPushButton::clicked, this, [&]() {
ui.verifyButton->setEnabled(false);
ui.downloadListButton->setEnabled(false);
ui.progressIndicatorBar->setVisible(true);
ui.cancelButton->setVisible(true);
disconnect(ui.cancelButton);
ui.cancelButton->disconnect();
QUrl pomfRepoURL = QUrl(ScreenshotManager::instance()->settings()->value("options/upload/pomfRepo").toString());
if (pomfRepoURL.isEmpty()) {
pomfRepoURL = QUrl("https://lightscreen.com.ar/pomf.json");
}
auto pomflistReply = QPointer<QNetworkReply>(Uploader::network()->get(QNetworkRequest(pomfRepoURL)));
QPointer<QWidget> guard(parentWidget());
connect(pomflistReply, &QNetworkReply::finished, [&, guard, pomflistReply] {
if (guard.isNull()) return;
if (pomflistReply.isNull()) return;
ui.verifyButton->setEnabled(true);
ui.downloadListButton->setEnabled(true);
ui.progressIndicatorBar->setVisible(false);
ui.cancelButton->setVisible(false);
if (pomflistReply->error() != QNetworkReply::NoError) {
QMessageBox::warning(parentWidget(), tr("Connection error"), pomflistReply->errorString());
return;
}
auto pomfListData = QJsonDocument::fromJson(pomflistReply->readAll()).object();
if (pomfListData.contains("url")) {
auto urlList = pomfListData["url"].toArray();
for (auto url : qAsConst(urlList)) {
if (ui.pomfUrlComboBox->findText(url.toString(), Qt::MatchExactly) < 0) {
ui.pomfUrlComboBox->addItem(url.toString());
}
}
ui.pomfUrlComboBox->showPopup();
}
});
#ifdef Q_OS_WIN
connect(pomflistReply, &QNetworkReply::sslErrors, [pomflistReply](const QList<QSslError> &errors) {
Q_UNUSED(errors);
if (!pomflistReply.isNull() && QSysInfo::WindowsVersion <= QSysInfo::WV_2003) {
pomflistReply->ignoreSslErrors();
}
});
#endif
connect(ui.cancelButton, &QPushButton::clicked, [&, guard, pomflistReply] {
if (guard.isNull()) return;
if (pomflistReply.isNull()) return;
pomflistReply->abort();
});
});
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Sep 12, 5:28 AM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
42807
Default Alt Text
(231 KB)

Event Timeline