Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
124 KB
Referenced Files
None
Subscribers
None
diff --git a/dialogs/optionsdialog.cpp b/dialogs/optionsdialog.cpp
index 9c78e01..6b52f0e 100644
--- a/dialogs/optionsdialog.cpp
+++ b/dialogs/optionsdialog.cpp
@@ -1,889 +1,889 @@
/*
* Copyright (C) 2014 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 <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>
#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"
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent)
{
ui.setupUi(this);
setModal(true);
#if defined(Q_WS_X11)
// 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
QTimer::singleShot(0, this, SLOT(init()));
QTimer::singleShot(1, this, SLOT(loadSettings()));
}
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);
foreach(const QString &key, settings()->allKeys()) {
exportedSettings.setValue(key, settings()->value(key));
}
}
void OptionsDialog::imgurAuthorize()
{ // TODO: Tuck this into Uploader
if (ui.imgurAuthButton->text() == tr("Deauthorize"))
{
ui.imgurAuthUserLabel->setText(tr("<i>none</i>"));
ui.imgurAuthButton->setText(tr("Authorize"));
ui.imgurAlbumComboBox->setEnabled(false);
ui.imgurAlbumComboBox->clear();
ui.imgurAlbumComboBox->addItem(tr("- None -"));
settings()->setValue("upload/imgur/access_token", "");
settings()->setValue("upload/imgur/refresh_token", "");
settings()->setValue("upload/imgur/account_username", "");
settings()->setValue("upload/imgur/expires_in", 0);
return;
}
openUrl("https://api.imgur.com/oauth2/authorize?client_id=3ebe94c791445c1&response_type=pin"); //TODO: get the client-id from somewhere?
bool ok;
QString pin = QInputDialog::getText(this, tr("Imgur Authorization"),
tr("PIN:"), QLineEdit::Normal,
"", &ok);
if (ok) {
QByteArray parameters;
parameters.append(QString("client_id=").toUtf8());
parameters.append(QUrl::toPercentEncoding("3ebe94c791445c1"));
parameters.append(QString("&client_secret=").toUtf8());
parameters.append(QUrl::toPercentEncoding("0546b05d6a80b2092dcea86c57b792c9c9faebf0")); // TODO: TA.png
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::instance()->nam()->post(request, parameters);
connect(reply, SIGNAL(finished()), this, SLOT(imgurToken()));
ui.imgurAuthButton->setText(tr("Authorizing.."));
ui.imgurAuthButton->setEnabled(false);
}
}
void OptionsDialog::imgurToken()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
ui.imgurAuthButton->setEnabled(true);
if (reply->error() != QNetworkReply::NoError) {
QMessageBox::critical(this, tr("Imgur Authorization Error"), tr("There's been an error authorizing your account with Imgur, please try again."));
ui.imgurAuthButton->setText(tr("Authorize"));
return;
}
QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
settings()->setValue("upload/imgur/access_token" , imgurResponse.value("access_token").toString());
settings()->setValue("upload/imgur/refresh_token" , imgurResponse.value("refresh_token").toString());
settings()->setValue("upload/imgur/account_username", imgurResponse.value("account_username").toString());
settings()->setValue("upload/imgur/expires_in" , imgurResponse.value("expires_in").toInt());
ui.imgurAuthUserLabel->setText("<b>" + imgurResponse.value("account_username").toString() + "</b>");
ui.imgurAuthButton->setText(tr("Deauthorize"));
imgurRequestAlbumList();
}
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();
foreach(const QString &key, importedSettings.allKeys()) {
if (settings()->contains(key))
settings()->setValue(key, importedSettings.value(key));
}
loadSettings();
}
void OptionsDialog::imgurRequestAlbumList() {
QString username = settings()->value("upload/imgur/account_username").toString();
if (username.isEmpty()) {
return;
}
ui.imgurAlbumComboBox->clear();
ui.imgurAlbumComboBox->setEnabled(false);
ui.imgurAlbumComboBox->addItem(tr("Loading album data..."));
QNetworkRequest request(QUrl("https://api.imgur.com/3/account/" + username + "/albums/"));
request.setRawHeader("Authorization", QByteArray("Bearer ") + settings()->value("upload/imgur/access_token").toByteArray());
QNetworkReply* reply = Uploader::instance()->nam()->get(request);
connect(reply, SIGNAL(finished()), this, SLOT(imgurAlbumList()));
}
void OptionsDialog::imgurAlbumList() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (reply->error() != QNetworkReply::NoError) {
if (reply->error() == QNetworkReply::ContentOperationNotPermittedError ||
reply->error() == QNetworkReply::AuthenticationRequiredError) {
Uploader::instance()->imgurAuthRefresh();
connect(Uploader::instance(), &Uploader::imgurAuthRefreshed, this, &OptionsDialog::imgurRequestAlbumList);
}
ui.imgurAlbumComboBox->addItem(tr("Loading failed :("));
return;
}
QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
if (imgurResponse["success"].toBool() != true || imgurResponse["status"].toInt() != 200)
return;
QJsonArray albumList = imgurResponse["data"].toArray();
ui.imgurAlbumComboBox->clear();
ui.imgurAlbumComboBox->setEnabled(true);
ui.imgurAlbumComboBox->addItem(tr("- None -"), "");
int settingsIndex = 0;
foreach (const QJsonValue &albumValue, albumList) {
QJsonObject album = albumValue.toObject();
ui.imgurAlbumComboBox->addItem(album["title"].toString(), album["id"].toString());
if (album["id"].toString() == settings()->value("upload/imgur/album").toString())
settingsIndex = ui.imgurAlbumComboBox->count() - 1;
}
ui.imgurAlbumComboBox->setCurrentIndex(settingsIndex);
}
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.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.imgurClipboardCheckBox->setChecked(settings()->value("imgurClipboard", false).toBool());
ui.optiPngCheckBox->setChecked(settings()->value("optipng", true).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_WS_X11)
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.serviceComboBox->setCurrentIndex(settings()->value("service").toInt());
settings()->beginGroup("imgur");
ui.imgurAuthGroupBox->setChecked(!settings()->value("anonymous", false).toBool());
ui.imgurAuthUserLabel->setText(settings()->value("account_username", tr("<i>none</i>")).toString());
if (settings()->value("account_username").toString().isEmpty()) {
ui.imgurAuthUserLabel->setText(tr("<i>none</i>"));
ui.imgurAlbumComboBox->setEnabled(false);
}
else {
ui.imgurAuthButton->setText(tr("Deauthorize"));
ui.imgurAuthUserLabel->setText("<b>" + ui.imgurAuthUserLabel->text() + "</b>");
}
settings()->endGroup();
settings()->endGroup();
QTimer::singleShot(0, this, SLOT(updatePreview()));
QTimer::singleShot(1, this, SLOT(imgurRequestAlbumList()));
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("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("imgurClipboard", ui.imgurClipboardCheckBox->isChecked());
settings()->setValue("optipng", 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()->setValue("hotkey" , ui.screenHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("area");
settings()->setValue("enabled", ui.areaCheckBox->isChecked());
- settings()->setValue("hotkey", ui.areaHotkeyWidget->hotkey());
+ settings()->setValue("hotkey" , ui.areaHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("window");
settings()->setValue("enabled", ui.windowCheckBox->isChecked());
- settings()->setValue("hotkey", ui.windowHotkeyWidget->hotkey());
+ settings()->setValue("hotkey" , ui.windowHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("windowPicker");
settings()->setValue("enabled", ui.windowPickerCheckBox->isChecked());
- settings()->setValue("hotkey", ui.windowPickerHotkeyWidget->hotkey());
+ settings()->setValue("hotkey" , ui.windowPickerHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("open");
settings()->setValue("enabled", ui.openCheckBox->isChecked());
- settings()->setValue("hotkey", ui.openHotkeyWidget->hotkey());
+ settings()->setValue("hotkey" , ui.openHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("directory");
settings()->setValue("enabled", ui.directoryCheckBox->isChecked());
- settings()->setValue("hotkey", ui.directoryHotkeyWidget->hotkey());
+ settings()->setValue("hotkey" , ui.directoryHotkeyWidget->hotkey());
settings()->endGroup();
settings()->endGroup();
settings()->beginGroup("upload");
//settings()->setValue("service", ui.serviceComboBox->currentIndex());
settings()->beginGroup("imgur");
- settings()->setValue("anonymous", !ui.imgurAuthGroupBox->isChecked());
- settings()->setValue("album", ui.imgurAlbumComboBox->property("currentData").toString()); // TODO
+ settings()->setValue("anonymous",!ui.imgurAuthGroupBox->isChecked());
+ settings()->setValue("album" , ui.imgurAlbumComboBox->property("currentData").toString());
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);
}
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)
{
restoreGeometry(settings()->value("geometry/optionsDialog").toByteArray());
}
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
QPalette optionsPalette = ui.optionsScrollArea->palette();
optionsPalette.setColor(QPalette::Window, ui.tabWidget->palette().color(QPalette::Base));
ui.optionsScrollArea->setPalette(optionsPalette);
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, SIGNAL(triggered()), this, SLOT(exportSettings()));
QAction *importAction = new QAction(tr("&Import.."), optionsMenu);
connect(importAction, SIGNAL(triggered()), this, SLOT(importSettings()));
QAction *restoreAction = new QAction(tr("&Restore Defaults"), optionsMenu);
connect(restoreAction, SIGNAL(triggered()), this, SLOT(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()));
setEnabled(false); // We disable the widgets to prevent any user interaction until the settings have loaded.
//
// Connections
//
connect(ui.buttonBox , SIGNAL(clicked(QAbstractButton*)), this , SLOT(dialogButtonClicked(QAbstractButton*)));
connect(ui.buttonBox , SIGNAL(accepted()) , this , SLOT(accepted()));
connect(ui.namingOptionsButton , SIGNAL(clicked()) , this , SLOT(namingOptions()));
connect(ui.prefixLineEdit , SIGNAL(textEdited(QString)) , this , SLOT(updatePreview()));
connect(ui.formatComboBox , SIGNAL(currentIndexChanged(int)) , this , SLOT(updatePreview()));
connect(ui.namingComboBox , SIGNAL(currentIndexChanged(int)) , this , SLOT(updatePreview()));
connect(ui.browsePushButton , SIGNAL(clicked()) , this , SLOT(browse()));
connect(ui.checkUpdatesPushButton , SIGNAL(clicked()) , this , SLOT(checkUpdatesNow()));
connect(ui.historyPushButton , SIGNAL(clicked()) , this , SLOT(viewHistory()));
connect(ui.imgurAuthButton , SIGNAL(clicked()) , this , SLOT(imgurAuthorize()));
connect(ui.screenCheckBox , SIGNAL(toggled(bool)), ui.screenHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.areaCheckBox , SIGNAL(toggled(bool)), ui.areaHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.windowCheckBox , SIGNAL(toggled(bool)), ui.windowHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.windowPickerCheckBox, SIGNAL(toggled(bool)), ui.windowPickerHotkeyWidget, SLOT(setEnabled(bool)));
connect(ui.openCheckBox , SIGNAL(toggled(bool)), ui.openHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.directoryCheckBox , SIGNAL(toggled(bool)), ui.directoryHotkeyWidget, SLOT(setEnabled(bool)));
// "Save as" disables the file target input field.
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.targetLineEdit , SLOT(setDisabled(bool)));
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.browsePushButton , SLOT(setDisabled(bool)));
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.directoryLabel , SLOT(setDisabled(bool)));
connect(ui.startupCheckBox , SIGNAL(toggled(bool)), ui.startupHideCheckBox , SLOT(setEnabled(bool)));
connect(ui.qualitySlider , SIGNAL(valueChanged(int)), ui.qualityValueLabel, SLOT(setNum(int)));
connect(ui.trayCheckBox , SIGNAL(toggled(bool)), ui.messageCheckBox , SLOT(setEnabled(bool)));
// Auto-upload disables the default action button in the previews.
connect(ui.uploadCheckBox , SIGNAL(toggled(bool)), ui.previewDefaultActionLabel , SLOT(setDisabled(bool)));
connect(ui.uploadCheckBox , SIGNAL(toggled(bool)), ui.previewDefaultActionComboBox, SLOT(setDisabled(bool)));
connect(ui.directoryCheckBox , SIGNAL(toggled(bool)), ui.directoryHotkeyWidget, SLOT(setEnabled(bool)));
connect(ui.mainLabel , SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
connect(ui.licenseAboutLabel, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
connect(ui.linksLabel, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
}
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/images/area.big.png b/images/area.big.png
index 5a28332..32e3b6b 100644
Binary files a/images/area.big.png and b/images/area.big.png differ
diff --git a/images/area.png b/images/area.png
index c98b375..f16038a 100644
Binary files a/images/area.png and b/images/area.png differ
diff --git a/images/arrow.left.png b/images/arrow.left.png
index af9f606..80bea53 100644
Binary files a/images/arrow.left.png and b/images/arrow.left.png differ
diff --git a/images/arrow.right.png b/images/arrow.right.png
index 0b60089..1b52cb7 100644
Binary files a/images/arrow.right.png and b/images/arrow.right.png differ
diff --git a/images/configure.png b/images/configure.png
index 62b0c94..f94e3a8 100644
Binary files a/images/configure.png and b/images/configure.png differ
diff --git a/images/folder.png b/images/folder.png
index 853d5e6..0e04635 100644
Binary files a/images/folder.png and b/images/folder.png differ
diff --git a/images/history.png b/images/history.png
index c4f57d5..56bc5dd 100644
Binary files a/images/history.png and b/images/history.png differ
diff --git a/images/imgur.png b/images/imgur.png
index 24dde03..9248157 100644
Binary files a/images/imgur.png and b/images/imgur.png differ
diff --git a/images/inv/area.big.png b/images/inv/area.big.png
index 5e3264b..7cf3f92 100644
Binary files a/images/inv/area.big.png and b/images/inv/area.big.png differ
diff --git a/images/inv/area.png b/images/inv/area.png
index 7d4f106..98ea2ea 100644
Binary files a/images/inv/area.png and b/images/inv/area.png differ
diff --git a/images/inv/arrow.left.png b/images/inv/arrow.left.png
index 77e8f9a..9140465 100644
Binary files a/images/inv/arrow.left.png and b/images/inv/arrow.left.png differ
diff --git a/images/inv/arrow.right.png b/images/inv/arrow.right.png
index 265b6e5..5c0099d 100644
Binary files a/images/inv/arrow.right.png and b/images/inv/arrow.right.png differ
diff --git a/images/inv/configure.png b/images/inv/configure.png
index 3c6c2fd..afd1e41 100644
Binary files a/images/inv/configure.png and b/images/inv/configure.png differ
diff --git a/images/inv/folder.png b/images/inv/folder.png
index 23fb354..cd753e3 100644
Binary files a/images/inv/folder.png and b/images/inv/folder.png differ
diff --git a/images/inv/history.png b/images/inv/history.png
index 3d4394b..42b4954 100644
Binary files a/images/inv/history.png and b/images/inv/history.png differ
diff --git a/images/inv/imgur.png b/images/inv/imgur.png
index 3fa89fc..9fb56d6 100644
Binary files a/images/inv/imgur.png and b/images/inv/imgur.png differ
diff --git a/images/inv/minus.png b/images/inv/minus.png
index c969ac7..80810a6 100644
Binary files a/images/inv/minus.png and b/images/inv/minus.png differ
diff --git a/images/inv/no.big.png b/images/inv/no.big.png
index 36f7cec..4f6ec1d 100644
Binary files a/images/inv/no.big.png and b/images/inv/no.big.png differ
diff --git a/images/inv/no.png b/images/inv/no.png
index c85d9e6..085a54b 100644
Binary files a/images/inv/no.png and b/images/inv/no.png differ
diff --git a/images/inv/pickWindow.big.png b/images/inv/pickWindow.big.png
index 5eb6a63..30cd473 100644
Binary files a/images/inv/pickWindow.big.png and b/images/inv/pickWindow.big.png differ
diff --git a/images/inv/pickWindow.png b/images/inv/pickWindow.png
index 5136291..6174346 100644
Binary files a/images/inv/pickWindow.png and b/images/inv/pickWindow.png differ
diff --git a/images/inv/picker.png b/images/inv/picker.png
index 1a2a839..b4a2503 100644
Binary files a/images/inv/picker.png and b/images/inv/picker.png differ
diff --git a/images/inv/plus.png b/images/inv/plus.png
index 88695f5..76b9fe0 100644
Binary files a/images/inv/plus.png and b/images/inv/plus.png differ
diff --git a/images/inv/preview.png b/images/inv/preview.png
index 301b714..5ca8530 100644
Binary files a/images/inv/preview.png and b/images/inv/preview.png differ
diff --git a/images/inv/screen.big.png b/images/inv/screen.big.png
index 273b5eb..1722557 100644
Binary files a/images/inv/screen.big.png and b/images/inv/screen.big.png differ
diff --git a/images/inv/screen.png b/images/inv/screen.png
index 94b9946..af6b7d1 100644
Binary files a/images/inv/screen.png and b/images/inv/screen.png differ
diff --git a/images/inv/window.png b/images/inv/window.png
index 6664055..06df01b 100644
Binary files a/images/inv/window.png and b/images/inv/window.png differ
diff --git a/images/inv/yes.big.png b/images/inv/yes.big.png
index c9ebb61..7317207 100644
Binary files a/images/inv/yes.big.png and b/images/inv/yes.big.png differ
diff --git a/images/inv/yes.png b/images/inv/yes.png
index 192f0be..0e62e86 100644
Binary files a/images/inv/yes.png and b/images/inv/yes.png differ
diff --git a/images/lightscreen.no.png b/images/lightscreen.no.png
index da7a4c5..0268871 100644
Binary files a/images/lightscreen.no.png and b/images/lightscreen.no.png differ
diff --git a/images/lightscreen.small.png b/images/lightscreen.small.png
index d904615..c53f8b5 100644
Binary files a/images/lightscreen.small.png and b/images/lightscreen.small.png differ
diff --git a/images/lightscreen.yes.png b/images/lightscreen.yes.png
index 3ef8f48..a830c13 100644
Binary files a/images/lightscreen.yes.png and b/images/lightscreen.yes.png differ
diff --git a/images/minus.png b/images/minus.png
index a81c88a..7357cec 100644
Binary files a/images/minus.png and b/images/minus.png differ
diff --git a/images/no.big.png b/images/no.big.png
index 43f994e..dae0dc2 100644
Binary files a/images/no.big.png and b/images/no.big.png differ
diff --git a/images/no.png b/images/no.png
index 77c3ef3..9f84ef8 100644
Binary files a/images/no.png and b/images/no.png differ
diff --git a/images/pickWindow.big.png b/images/pickWindow.big.png
index ee3ef2a..3d01c58 100644
Binary files a/images/pickWindow.big.png and b/images/pickWindow.big.png differ
diff --git a/images/pickWindow.png b/images/pickWindow.png
index 1751712..72d43a2 100644
Binary files a/images/pickWindow.png and b/images/pickWindow.png differ
diff --git a/images/picker.png b/images/picker.png
index 458805d..2d1bfc3 100644
Binary files a/images/picker.png and b/images/picker.png differ
diff --git a/images/plus.png b/images/plus.png
index 53b57e1..8e34043 100644
Binary files a/images/plus.png and b/images/plus.png differ
diff --git a/images/preview.png b/images/preview.png
index 1960aa0..2b6e2ff 100644
Binary files a/images/preview.png and b/images/preview.png differ
diff --git a/images/screen.big.png b/images/screen.big.png
index dd607da..ea4b552 100644
Binary files a/images/screen.big.png and b/images/screen.big.png differ
diff --git a/images/screen.png b/images/screen.png
index f59bb2e..d63f32e 100644
Binary files a/images/screen.png and b/images/screen.png differ
diff --git a/images/window.png b/images/window.png
index 6f3cb61..3b6d5de 100644
Binary files a/images/window.png and b/images/window.png differ
diff --git a/images/yes.big.png b/images/yes.big.png
index 92d19fd..8f0da5f 100644
Binary files a/images/yes.big.png and b/images/yes.big.png differ
diff --git a/images/yes.png b/images/yes.png
index 071d137..a38a781 100644
Binary files a/images/yes.png and b/images/yes.png differ
diff --git a/lightscreen.pro b/lightscreen.pro
index 36d60da..49c8d7f 100644
--- a/lightscreen.pro
+++ b/lightscreen.pro
@@ -1,83 +1,83 @@
TEMPLATE = app
TARGET = lightscreen
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/qtsingleapplication/qtlockedfile.h \
tools/qtsingleapplication/qtsinglecoreapplication.h \
tools/uploader/imageuploader.h \
tools/uploader/imguruploader.h \
tools/uploader/uploader.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/qtsingleapplication/qtlockedfile.cpp \
tools/qtsingleapplication/qtlockedfile_unix.cpp \
tools/qtsingleapplication/qtlockedfile_win.cpp \
tools/qtsingleapplication/qtsinglecoreapplication.cpp \
tools/uploader/imageuploader.cpp \
tools/uploader/imguruploader.cpp \
tools/uploader/uploader.cpp
FORMS += dialogs/historydialog.ui \
dialogs/namingdialog.ui \
dialogs/optionsdialog.ui \
lightscreenwindow.ui
RESOURCES += lightscreen.qrc
RC_FILE += lightscreen.rc
CODECFORSRC = UTF-8
-QT += network core gui sql multimedia winextras
+QT += core gui network sql multimedia winextras
include($$PWD/tools/qxtglobalshortcut/qxtglobalshortcut.pri)
include($$PWD/tools/qtsingleapplication/qtsingleapplication.pri)
windows{
contains(QMAKE_CC, gcc){
LIBS += libgdi32 libgcc libuser32 libole32 libshell32 libshlwapi libcomctl32
QMAKE_CXXFLAGS = -Wextra -Wall -Wpointer-arith
}
contains(QMAKE_CC, cl){
LIBS += gdi32.lib user32.lib ole32.lib shell32.lib shlwapi.lib comctl32.lib
}
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
QMAKE_LFLAGS_CONSOLE = /SUBSYSTEM:CONSOLE,5.01
DEFINES += _ATL_XP_TARGETING
QMAKE_CFLAGS += /D _USING_V110_SDK71
QMAKE_CXXFLAGS += /D _USING_V110_SDK71
}
unix:LIBS += -lX11
OTHER_FILES += TODO.txt
diff --git a/lightscreenwindow.cpp b/lightscreenwindow.cpp
index 033e300..b28f1df 100644
--- a/lightscreenwindow.cpp
+++ b/lightscreenwindow.cpp
@@ -1,1041 +1,1056 @@
/*
* Copyright (C) 2014 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>
#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/qxtglobalshortcut/qxtglobalshortcut.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(-1),
mLastScreenshot()
{
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"));
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
mTaskbarButton = new QWinTaskbarButton(this);
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
setMaximumSize(size());
setMinimumSize(size());
setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint);
// Actions
connect(ui.screenPushButton, SIGNAL(clicked()), this, SLOT(screenshotAction()));
connect(ui.areaPushButton , SIGNAL(clicked()), this, SLOT(areaHotkey()));
connect(ui.windowPushButton, SIGNAL(clicked()), this, SLOT(windowPickerHotkey()));
connect(ui.optionsPushButton, SIGNAL(clicked()), this, SLOT(showOptions()));
connect(ui.folderPushButton , SIGNAL(clicked()), this, SLOT(goToFolder()));
- connect(ui.imgurPushButton, SIGNAL(clicked()), this, SLOT(createUploadMenu()));
-
// Shortcuts
connect(&mScreenShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::screenHotkey);
connect(&mAreaShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::areaHotkey);
connect(&mWindowShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::windowHotkey);
connect(&mWindowPickerShortcut, &QxtGlobalShortcut::activated, this, &LightscreenWindow::windowPickerHotkey);
connect(&mOpenShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::show);
connect(&mDirectoryShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::goToFolder);
// Uploader
connect(Uploader::instance(), SIGNAL(progress(int)), this, SLOT(uploadProgress(int)));
connect(Uploader::instance(), SIGNAL(done(QString, QString, QString)), this, SLOT(showUploaderMessage(QString, QString)));
connect(Uploader::instance(), SIGNAL(error(QString)), this, SLOT(showUploaderError(QString)));
// Manager
connect(ScreenshotManager::instance(), SIGNAL(confirm(Screenshot*)), this, SLOT(preview(Screenshot*)));
connect(ScreenshotManager::instance(), SIGNAL(windowCleanup(Screenshot::Options&)), this, SLOT(cleanup(Screenshot::Options&)));
connect(ScreenshotManager::instance(), SIGNAL(activeCountChange()), this, SLOT(updateStatus()));
if (!settings()->contains("file/format")) {
showOptions(); // There are no options (or the options config is invalid or incomplete)
}
else {
QTimer::singleShot(0 , this, SLOT(applySettings()));
+ QTimer::singleShot(0 , this, SLOT(createUploadMenu()));
QTimer::singleShot(5000, this, SLOT(checkForUpdates()));
}
}
LightscreenWindow::~LightscreenWindow()
{
settings()->setValue("lastScreenshot", mLastScreenshot);
settings()->sync();
- delete mTrayIcon;
}
void LightscreenWindow::action(int mode)
{
if (mode == 4) {
goToFolder();
}
else {
show();
}
}
void LightscreenWindow::areaHotkey()
{
screenshotAction(2);
}
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, SIGNAL(done(bool)), this, SLOT(updaterDone(bool)));
mUpdater->check();
}
void LightscreenWindow::cleanup(Screenshot::Options &options)
{
// Reversing settings
if (settings()->value("options/hide").toBool()) {
#ifndef Q_WS_X11 // 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; }");
QPushButton *enableButton = msgBox.addButton(tr("Hide but enable tray"),
QMessageBox::ActionRole);
QPushButton *enableAndDenotifyButton = msgBox.addButton(tr("Hide and don't warn"),
QMessageBox::ActionRole);
QPushButton *hideButton = msgBox.addButton(tr("Just hide"),
QMessageBox::ActionRole);
QPushButton *abortButton = msgBox.addButton(QMessageBox::Cancel);
Q_UNUSED(abortButton);
msgBox.exec();
if (msgBox.clickedButton() == hideButton) {
return true;
}
else if (msgBox.clickedButton() == enableAndDenotifyButton) {
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()
{
QMenu* imgurMenu = new QMenu(tr("Upload"));
QAction *uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), imgurMenu);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, SIGNAL(triggered()), this, SLOT(uploadLast()));
QAction *cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), imgurMenu);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, SIGNAL(uploading(bool)), cancelAction, SLOT(setEnabled(bool)));
connect(cancelAction, SIGNAL(triggered()), this, SLOT(uploadCancel()));
QAction *historyAction = new QAction(os::icon("view-history"), tr("View &History"), imgurMenu);
connect(historyAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
connect(imgurMenu, SIGNAL(aboutToShow()), this, SLOT(uploadMenuShown()));
ui.imgurPushButton->setMenu(imgurMenu);
- ui.imgurPushButton->showMenu();
}
void LightscreenWindow::goToFolder()
{
#ifdef Q_OS_WIN
if (!mLastScreenshot.isEmpty() && QFile::exists(mLastScreenshot)) {
QProcess::startDetached("explorer /select, \"" + mLastScreenshot +"\"");
}
else {
#endif
QString folder = settings()->value("file/target").toString();
if (folder.isEmpty())
folder = qApp->applicationDirPath();
if (QDir::toNativeSeparators(folder.at(folder.size()-1)) != QDir::separator())
folder.append(QDir::separator());
QDesktopServices::openUrl("file:///"+folder);
#ifdef Q_OS_WIN
}
#endif
}
void LightscreenWindow::messageClicked()
{
if (mLastMessage == 1) {
goToFolder();
}
else if (mLastMessage == 3) {
QTimer::singleShot(0, this, SLOT(showOptions()));
}
else {
QDesktopServices::openUrl(QUrl(Uploader::instance()->lastUrl()));
}
}
void LightscreenWindow::messageReceived(const QString &message)
{
if (message.contains(' ')) {
foreach (QString argument, message.split(' ')) {
messageReceived(argument);
}
}
if (message == "--wake") {
show();
qApp->alert(this, 500);
return;
}
if (message == "--screen")
screenshotAction();
else if (message == "--area")
screenshotAction(2);
else if (message == "--activewindow")
screenshotAction(1);
else if (message == "--pickwindow")
screenshotAction(3);
else if (message == "--folder")
action(4);
else if (message == "--uploadlast")
uploadLast();
else if (message == "--viewhistory")
showHistoryDialog();
+ else if (message == "--options")
+ showOptions();
+ else if (message == "--quit")
+ qApp->quit();
}
void LightscreenWindow::notify(const Screenshot::Result &result)
{
switch (result)
{
case Screenshot::Success:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.yes"));
-#ifdef Q_OS_WIN
- if (mTaskbarButton)
+ if (mTaskbarButton) {
mTaskbarButton->setOverlayIcon(os::icon("yes"));
-#endif
+ }
setWindowTitle(tr("Success!"));
break;
case Screenshot::Fail:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.no"));
setWindowTitle(tr("Failed!"));
-#ifdef Q_OS_WIN
+
if (mTaskbarButton) {
mTaskbarButton->setOverlayIcon(os::icon("no"));
}
-#endif
+
break;
case Screenshot::Cancel:
setWindowTitle(tr("Cancelled!"));
break;
}
QTimer::singleShot(2000, this, SLOT(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"));
-#ifdef Q_OS_WIN
- if (mTaskbarButton)
+ if (mTaskbarButton) {
mTaskbarButton->clearOverlayIcon();
-#endif
+ mTaskbarButton->progress()->setVisible(false);
+ mTaskbarButton->progress()->stop();
+ mTaskbarButton->progress()->reset();
+ }
updateStatus();
}
void LightscreenWindow::screenshotAction(int 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_WS_X11 // 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 < 0) {
mLastMode = mode;
QTimer::singleShot(delayms, this, SLOT(screenshotAction()));
return;
}
else {
mode = mLastMode;
mLastMode = -1;
}
}
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.imgurClipboard = settings()->value("options/imgurClipboard", 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/optipng", false).toBool();
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().toInt());
}
void LightscreenWindow::screenHotkey()
{
screenshotAction(0);
}
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>";
foreach(const QString &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, SLOT(quit()));
}
else if (msgBox.clickedButton() == changeButton) {
showOptions();
}
else if (msgBox.clickedButton() == disableButton) {
foreach(const QString &hotkey, hotkeys) {
settings()->setValue(QString("actions/%1/enabled").arg(hotkey), false);
}
}
}
void LightscreenWindow::showHistoryDialog()
{
HistoryDialog historyDialog(this);
historyDialog.exec();
updateStatus();
}
void LightscreenWindow::showOptions()
{
mScreenShortcut.setEnabled(false);
mAreaShortcut.setEnabled(false);
mWindowShortcut.setEnabled(false);
mWindowPickerShortcut.setEnabled(false);
mOpenShortcut.setEnabled(false);
mDirectoryShortcut.setEnabled(false);
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::Fail);
}
void LightscreenWindow::showUploaderMessage(QString fileName, 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(QSystemTrayIcon::ActivationReason reason)
{
if (reason != QSystemTrayIcon::DoubleClick)
return;
if (isVisible()) {
hide();
}
else {
show();
os::setForegroundWindow(this);
}
}
void LightscreenWindow::updateStatus()
{
int uploadCount = Uploader::instance()->uploading();
int activeCount = ScreenshotManager::instance()->activeCount();
+ if (mTaskbarButton) {
+ mTaskbarButton->progress()->setPaused(true);
+ mTaskbarButton->progress()->setVisible(true);
+ }
+
if (uploadCount > 0) {
setStatus(tr("%1 uploading").arg(uploadCount));
+
+ if (mTaskbarButton) {
+ 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) {
+ else if (activeCount == 1) {
setStatus(tr("processing"));
}
else {
setStatus();
+
+ if (mTaskbarButton) {
+ mTaskbarButton->progress()->hide();
+ }
}
emit uploading(false);
-
-#ifdef Q_OS_WIN
- if (mTaskbarButton) {
- mTaskbarButton->progress()->setVisible(false);
- }
-#endif
}
}
void LightscreenWindow::updaterDone(bool result)
{
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("http://lightscreen.com.ar/whatsnew?from=" + qApp->applicationVersion()));
}
else if (msgBox.clickedButton() == turnOffButton) {
settings()->setValue("options/disableUpdater", true);
}
mUpdater->deleteLater();
}
void LightscreenWindow::upload(const QString &fileName)
{
Uploader::instance()->upload(fileName);
}
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)
{
-#ifdef Q_OS_WIN
if (mTaskbarButton) {
- mTaskbarButton->progress()->setRange(0, 100);
+ 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));
}
}
-#endif
}
void LightscreenWindow::uploadMenuShown()
{
QMenu *imgurMenu = qobject_cast<QMenu*>(sender());
imgurMenu->actions().at(0)->setEnabled(!mLastScreenshot.isEmpty());
}
void LightscreenWindow::windowHotkey()
{
screenshotAction(1);
}
void LightscreenWindow::windowPickerHotkey()
{
screenshotAction(3);
}
void LightscreenWindow::applySettings()
{
- bool tray = settings()->value("options/tray").toBool();
+ bool tray = settings()->value("options/tray", true).toBool();
if (tray && !mTrayIcon) {
createTrayIcon();
- mTrayIcon->show();
+ mTrayIcon->setVisible(true);
}
else if (!tray && mTrayIcon) {
- mTrayIcon->deleteLater();
+ 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()
{
bool screen = mScreenShortcut.setShortcut(settings()->value("actions/screen/hotkey").value<QKeySequence>());
mScreenShortcut.setEnabled(settings()->value("actions/screen/enabled").toBool());
bool area = mAreaShortcut.setShortcut(settings()->value("actions/area/hotkey").value<QKeySequence>());
mAreaShortcut.setEnabled(settings()->value("actions/area/enabled").toBool());
bool window = mWindowShortcut.setShortcut(settings()->value("actions/window/hotkey").value<QKeySequence>());
mWindowShortcut.setEnabled(settings()->value("actions/window/enabled").toBool());
bool windowPicker = mWindowPickerShortcut.setShortcut(settings()->value("actions/windowPicker/hotkey").value<QKeySequence>());
mWindowPickerShortcut.setEnabled(settings()->value("actions/windowPicker/enabled").toBool());
bool open = mOpenShortcut.setShortcut(settings()->value("actions/open/hotkey").value<QKeySequence>());
mOpenShortcut.setEnabled(settings()->value("actions/open/enabled").toBool());
bool directory = mOpenShortcut.setShortcut(settings()->value("actions/directory/hotkey").value<QKeySequence>());
mDirectoryShortcut.setEnabled(settings()->value("actions/directory/enabled").toBool());
QStringList failed;
if (!screen) failed << "screen";
if (!area) failed << "area";
if (!window) failed << "window";
if (!windowPicker) failed << "window picker";
if (!open) failed << "open";
if (!directory) failed << "directory";
if (!failed.isEmpty())
showHotkeyError(failed);
}
void LightscreenWindow::createTrayIcon()
{
mTrayIcon = new QSystemTrayIcon(QIcon(":/icons/lightscreen.small"), this);
updateStatus();
connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason)));
connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
QAction *hideAction = new QAction(QIcon(":/icons/lightscreen.small"), tr("Show&/Hide"), mTrayIcon);
connect(hideAction, SIGNAL(triggered()), this, SLOT(toggleVisibility()));
QAction *screenAction = new QAction(os::icon("screen"), tr("&Screen"), mTrayIcon);
screenAction->setData(QVariant(0));
QAction *windowAction = new QAction(os::icon("window"), tr("Active &Window"), this);
windowAction->setData(QVariant(1));
QAction *windowPickerAction = new QAction(os::icon("pickWindow"), tr("&Pick Window"), this);
windowPickerAction->setData(QVariant(3));
QAction *areaAction = new QAction(os::icon("area"), tr("&Area"), mTrayIcon);
areaAction->setData(QVariant(2));
QActionGroup *screenshotGroup = new QActionGroup(mTrayIcon);
screenshotGroup->addAction(screenAction);
screenshotGroup->addAction(areaAction);
screenshotGroup->addAction(windowAction);
screenshotGroup->addAction(windowPickerAction);
connect(screenshotGroup, SIGNAL(triggered(QAction*)), this, SLOT(screenshotActionTriggered(QAction*)));
// Duplicated for the screenshot button :(
QAction *uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), mTrayIcon);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, SIGNAL(triggered()), this, SLOT(uploadLast()));
QAction *cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), mTrayIcon);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, SIGNAL(uploading(bool)), cancelAction, SLOT(setEnabled(bool)));
connect(cancelAction, SIGNAL(triggered()), this, SLOT(uploadCancel()));
QAction *historyAction = new QAction(os::icon("view-history"), tr("View History"), mTrayIcon);
connect(historyAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
//
QAction *optionsAction = new QAction(os::icon("configure"), tr("View &Options"), mTrayIcon);
connect(optionsAction, SIGNAL(triggered()), this, SLOT(showOptions()));
QAction *goAction = new QAction(os::icon("folder"), tr("&Go to Folder"), mTrayIcon);
connect(goAction, SIGNAL(triggered()), this, SLOT(goToFolder()));
QAction *quitAction = new QAction(tr("&Quit"), mTrayIcon);
connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
QMenu* screenshotMenu = new QMenu(tr("Screenshot"));
screenshotMenu->addAction(screenAction);
screenshotMenu->addAction(areaAction);
screenshotMenu->addAction(windowAction);
screenshotMenu->addAction(windowPickerAction);
// Duplicated for the screenshot button :(
QMenu* imgurMenu = new QMenu(tr("Upload"));
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
QMenu* 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::Hide) {
+ if (event->type() == QEvent::Show)
+ {
+ if (mTaskbarButton) {
+ 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::Show) {
QPoint savedPosition = settings()->value("position").toPoint();
if (!savedPosition.isNull() && qApp->desktop()->availableGeometry().contains(QRect(savedPosition, size())))
move(savedPosition);
}
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 7bdd7f5..11fe735 100644
--- a/lightscreenwindow.h
+++ b/lightscreenwindow.h
@@ -1,127 +1,129 @@
/*
* Copyright (C) 2014 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 "tools/qxtglobalshortcut/qxtglobalshortcut.h"
#include "dialogs/previewdialog.h"
#include "ui_lightscreenwindow.h"
class Updater;
class QSettings;
class QWinTaskbarButton;
class LightscreenWindow : public QMainWindow
{
Q_OBJECT
public:
LightscreenWindow(QWidget *parent = 0);
~LightscreenWindow();
public slots:
void action(int mode = 3);
void areaHotkey();
void checkForUpdates();
void cleanup(Screenshot::Options &options);
void closeToTrayWarning();
bool closingWithoutTray();
void createUploadMenu();
void goToFolder();
void messageClicked();
void messageReceived(const QString &message);
void notify(const Screenshot::Result &result);
void preview(Screenshot* screenshot);
void quit();
void restoreNotification();
void setStatus(QString status = "");
void screenshotAction(int mode = 0);
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(QString fileName, QString url);
void toggleVisibility(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::DoubleClick);
void updateStatus();
void updaterDone(bool result);
void upload(const QString &fileName);
void uploadCancel();
void uploadLast();
void uploadProgress(int progress);
void uploadMenuShown();
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;
int mLastMode;
QString mLastScreenshot;
QPointer<QSystemTrayIcon> mTrayIcon;
QPointer<PreviewDialog> mPreviewDialog;
QPointer<Updater> mUpdater;
Ui::LightscreenWindowClass ui;
QxtGlobalShortcut mScreenShortcut;
QxtGlobalShortcut mAreaShortcut;
QxtGlobalShortcut mWindowShortcut;
QxtGlobalShortcut mWindowPickerShortcut;
QxtGlobalShortcut mOpenShortcut;
QxtGlobalShortcut mDirectoryShortcut;
#ifdef Q_OS_WIN
QPointer<QWinTaskbarButton> mTaskbarButton;
+#else
+ QPointer<QWidget> mTaskBarButton;
#endif
};
#endif // LIGHTSCREENWINDOW_H
diff --git a/main.cpp b/main.cpp
index 808b501..c931da8 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,94 +1,102 @@
/*
* Copyright (C) 2014 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 <QtSingleApplication>
#include "lightscreenwindow.h"
int main(int argc, char *argv[])
{
QtSingleApplication application(argc, argv);
application.setOrganizationName("K");
application.setApplicationName ("Lightscreen");
application.setApplicationVersion("2.1");
application.setQuitOnLastWindowClosed(false);
if (application.isRunning()) {
if (application.arguments().size() > 1) {
QStringList arguments = application.arguments();
arguments.removeFirst();
application.sendMessage(arguments.join(" "));
}
else {
application.sendMessage("--wake");
}
return 0;
}
LightscreenWindow lightscreen;
#ifdef Q_OS_WIN
- // Windows 7 jumplists.
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
QWinJumpList* jumplist = new QWinJumpList(&lightscreen);
+ QColor backgroundColor = qApp->palette("QToolTip").color(QPalette::Background);
+
+ if (QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS10)
+ { // contrast r hard
+ backgroundColor = Qt::black;
+ }
+
QWinJumpListCategory* screenshotCategory = new QWinJumpListCategory("Screenshot");
screenshotCategory->setVisible(true);
- screenshotCategory->addLink(os::icon("screen") , QObject::tr("Screen") , application.applicationFilePath(), QStringList("--screen"));
- screenshotCategory->addLink(os::icon("area") , QObject::tr("Area") , application.applicationFilePath(), QStringList("--area"));
- screenshotCategory->addLink(os::icon("pickWindow"), QObject::tr("Pick Window") , application.applicationFilePath(), QStringList("--pickwindow"));
+ 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"));
QWinJumpListCategory* uploadCategory = new QWinJumpListCategory("Upload");
uploadCategory->setVisible(true);
- uploadCategory->addLink(os::icon("imgur") , QObject::tr("Upload Last") , application.applicationFilePath(), QStringList("--uploadlast"));
- uploadCategory->addLink(os::icon("view-history"), QObject::tr("View History"), application.applicationFilePath(), QStringList("--viewhistory"));
+ 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"));
- QWinJumpListCategory* folderCategory = new QWinJumpListCategory;
- folderCategory->setVisible(true);
- folderCategory->addLink(os::icon("folder"), QObject::tr("Go to Folder") , application.applicationFilePath(), QStringList("--folder"));
+ QWinJumpListCategory* actionsCategory = new QWinJumpListCategory("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(folderCategory);
+ jumplist->addCategory(actionsCategory);
}
#endif
if (application.arguments().size() > 1) {
foreach (QString argument, application.arguments()) {
lightscreen.messageReceived(argument);
}
}
else {
lightscreen.show();
}
QObject::connect(&application, SIGNAL(messageReceived(const QString&)), &lightscreen, SLOT(messageReceived(const QString&)));
QObject::connect(&lightscreen, SIGNAL(finished()), &application, SLOT(quit()));
int result = application.exec();
return result;
}
diff --git a/tools/os.cpp b/tools/os.cpp
index bfdb5b6..62f5d71 100644
--- a/tools/os.cpp
+++ b/tools/os.cpp
@@ -1,417 +1,389 @@
/*
* Copyright (C) 2014 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>
#ifdef Q_OS_WIN
#include <QtWin>
#include <qt_windows.h>
#include <shlobj.h>
#elif defined(Q_WS_X11)
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#endif
#include "os.h"
void os::addToRecentDocuments(QString fileName)
{
#ifdef Q_OS_WIN
- SHAddToRecentDocs (0x00000003, QDir::toNativeSeparators(fileName).utf16());
+ LPCWSTR szFileName = QDir::toNativeSeparators(fileName).toStdWString().c_str();
+ SHARDAPPIDINFO info;
+ IShellItem* item;
+
+ if (SUCCEEDED(SHCreateItemFromParsingName(szFileName, NULL, IID_PPV_ARGS(&item)))) {
+ info.psi = item;
+ info.pszAppID = L"K.Lightscreen"; // our AppID - see above
+
+ SHAddToRecentDocs (SHARD_APPIDINFO, &info);
+ }
#else
Q_UNUSED(fileName)
#endif
}
QPixmap os::cursor()
{
#ifdef Q_OS_WIN
/*
* Taken from: git://github.com/arrai/mumble-record.git > src > mumble > Overlay.cpp
* BSD License.
*/
QPixmap pixmap;
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 = 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);
}
if (info.hbmMask)
::DeleteObject(info.hbmMask);
if (info.hbmColor)
::DeleteObject(info.hbmColor);
}
return pixmap;
#else
return QPixmap();
#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)))
{
std::wstring path(szPath);
return QString::fromWCharArray(path.c_str());
}
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);
if (IsZoomed(hwndId)) {
int margin = GetSystemMetrics(SM_CXSIZEFRAME);
rcWindow.right -= margin;
rcWindow.left += margin;
rcWindow.top += margin;
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_WS_X11)
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).toAscii());
}
#endif
}
QGraphicsEffect* os::shadow(QColor color, int blurRadius, int offset) {
QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect;
shadowEffect->setBlurRadius(blurRadius);
shadowEffect->setOffset(offset);
shadowEffect->setColor(color);
return shadowEffect;
}
-void os::translate(QString language)
+QIcon os::icon(QString name, QColor backgroundColor)
{
- /*
- static QTranslator *translator = 0;
- static QTranslator *translator_qt = 0;
-
- if ((language.compare("English", Qt::CaseInsensitive) == 0
- || language.isEmpty()) && translator) {
- qApp->removeTranslator(translator);
- qApp->removeTranslator(translator_qt);
- QLocale::setDefault(QLocale::c());
- return;
- }
-
- if (translator) {
- delete translator;
- delete translator_qt;
- }
-
- translator = new QTranslator(qApp);
- translator_qt = new QTranslator(qApp);
-
- if (language == "Español")
- QLocale::setDefault(QLocale::Spanish);
-
- if (translator->load(language, ":/translations")) {
- qApp->installTranslator(translator);
- }
-
- if (translator_qt->load(language, ":/translations_qt")) {
- qApp->installTranslator(translator_qt);
- }
- */
-}
-
-QIcon os::icon(QString name)
-{
- static int value = -1;
-
- if (value < 0) {
- value = qApp->desktop()->palette().color(QPalette::Button).value();
- }
+ if (!backgroundColor.isValid())
+ backgroundColor = qApp->palette().color(QPalette::Button);
- if (value > 125) {
+ if (backgroundColor.value() > 125) {
return QIcon(":/icons/" + name);
}
else {
return QIcon(":/icons/inv/" + name);
}
}
#ifdef Q_WS_X11
// 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/os.h b/tools/os.h
index 11753c9..0ff6e5d 100644
--- a/tools/os.h
+++ b/tools/os.h
@@ -1,76 +1,76 @@
/*
* Copyright (C) 2014 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 OS_H_
#define OS_H_
#include <QWidget>
class QPixmap;
class QPoint;
class QString;
class QUrl;
class QGraphicsEffect;
class QIcon;
#if defined(Q_WS_X11)
typedef unsigned long XID;
typedef XID Window;
#endif
namespace os
{
// Adds the filename to the Windows recent document list (useful for Windows 7 jump lists)
void addToRecentDocuments(QString fileName);
// Returns the cursor pixmap in Windows
QPixmap cursor();
// A QTimeLine based effect for a slot (TODO: look at the new effect classes)
void effect(QObject* target, const char* slot, int frames, int duration = 400, const char* cleanup = 0);
// Returns the current users's Documents/My Documents folder
QString getDocumentsPath();
// Returns the pixmap of the given window id.
QPixmap grabWindow(WId winId);
// Set the target window as the foreground window (Windows only)
void setForegroundWindow(QWidget *window);
// Adds lightscreen to the startup list in Windows & Linux (KDE, Gnome and Xfce for now).
void setStartup(bool startup, bool hide);
// Creates a new QGraphicsDropShadowEffect to apply to widgets.
QGraphicsEffect* shadow(QColor color = Qt::black, int blurRadius = 6, int offset = 1);
// Translates the ui to the given language name.
void translate(QString language);
// Returns a QIcon for the given icon name (taking into account color schemes and whatnot).
- QIcon icon(QString name);
+ QIcon icon(QString name, QColor backgroundColor = QColor());
// X11-specific functions for the Window Picker
#if defined(Q_WS_X11)
Window findRealWindow(Window w, int depth = 0);
Window windowUnderCursor(bool includeDecorations = true);
#endif
}
#endif /*OS_H_*/
diff --git a/tools/qtsingleapplication/qtlocalpeer.cpp b/tools/qtsingleapplication/qtlocalpeer.cpp
index 332b064..19914f4 100644
--- a/tools/qtsingleapplication/qtlocalpeer.cpp
+++ b/tools/qtsingleapplication/qtlocalpeer.cpp
@@ -1,203 +1,204 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QTime>
+#include <QDataStream>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qtlockedfile.cpp"
#if defined(Q_OS_WIN)
#include "qtlockedfile_win.cpp"
#else
#include "qtlockedfile_unix.cpp"
#endif
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId)
{
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegExp("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
return false;
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName);
}
#endif
if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2);
if (connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if (!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
void QtLocalPeer::receiveConnection()
{
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
socket->waitForReadyRead();
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
emit messageReceived(message); //### (might take a long time to return)
}
diff --git a/tools/screenshotmanager.cpp b/tools/screenshotmanager.cpp
index 21a4774..9a3647b 100644
--- a/tools/screenshotmanager.cpp
+++ b/tools/screenshotmanager.cpp
@@ -1,212 +1,214 @@
/*
* Copyright (C) 2014 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 <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 = 0) : QObject(parent)
{
if (QFile::exists(qApp->applicationDirPath() + QDir::separator() + "config.ini")) {
mSettings = new QSettings(qApp->applicationDirPath() + QDir::separator() + "config.ini", QSettings::IniFormat);
mPortableMode = true;
mHistoryPath = qApp->applicationDirPath() + QDir::separator();
}
else {
mSettings = new QSettings();
mPortableMode = false;
mHistoryPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator();
}
initHistory();
connect(Uploader::instance(), SIGNAL(done(QString, QString, QString)), this, SLOT(uploadDone(QString, QString, QString)));
}
ScreenshotManager::~ScreenshotManager()
{
delete mSettings;
}
void ScreenshotManager::initHistory()
{
// Creating the SQLite database.
QSqlDatabase history = QSqlDatabase::addDatabase("QSQLITE");
QDir hp(mHistoryPath);
if (!hp.exists())
hp.mkpath(mHistoryPath);
history.setHostName("localhost");
history.setDatabaseName(mHistoryPath + "history.sqlite");
if (history.open()) {
history.exec("CREATE TABLE IF NOT EXISTS history (fileName text, URL text, deleteURL text, time integer)");
}
else {
qCritical() << "Could not open SQLite DB.";
}
}
int ScreenshotManager::activeCount() const
{
return mScreenshots.count();
}
bool ScreenshotManager::portableMode()
{
return mPortableMode;
}
void ScreenshotManager::saveHistory(QString fileName, QString url, QString deleteHash)
{
if (!mSettings->value("/options/history", true).toBool())
return;
QString deleteUrl;
if (!deleteHash.isEmpty())
deleteUrl = "http://imgur.com/delete/" + deleteHash;
QSqlQuery query;
query.prepare("INSERT INTO history (fileName, URL, deleteURL, time) VALUES(?, ?, ?, ?)");
query.addBindValue(fileName);
query.addBindValue(url);
query.addBindValue(deleteUrl);
query.addBindValue(QDateTime::currentMSecsSinceEpoch());
query.exec();
}
void ScreenshotManager::updateHistory(QString fileName, QString url, QString deleteHash)
{
- if (!mSettings->value("/options/history", true).toBool())
+ if (!mSettings->value("/options/history", true).toBool() || url.isEmpty())
return;
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 && !url.isEmpty()) {
- // Makes sure to only update the latest file, in case something weird happened with the files (deleted screenshots, etc). Though that might still happen in some edge cases that I'm too lazy to account for.
+ if (query.record().count() > 0) {
QSqlQuery updateQuery;
updateQuery.prepare("UPDATE history SET URL = ?, deleteURL = ?, time = ? WHERE fileName = ?");
updateQuery.addBindValue(url);
updateQuery.addBindValue("http://imgur.com/delete/" + deleteHash);
updateQuery.addBindValue(QDateTime::currentMSecsSinceEpoch());
updateQuery.addBindValue(fileName);
updateQuery.exec();
}
+ else {
+ saveHistory(fileName, url, deleteHash);
+ }
}
void ScreenshotManager::removeHistory(QString fileName, qint64 time)
{
QSqlQuery removeQuery;
removeQuery.prepare("DELETE FROM history WHERE fileName = ? AND time = ?");
removeQuery.addBindValue(fileName);
removeQuery.addBindValue(time);
removeQuery.exec();
}
void ScreenshotManager::clearHistory()
{
QSqlQuery clearQuery("DROP TABLE history");
clearQuery.exec();
initHistory();
}
//
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, SIGNAL(askConfirmation()), this, SLOT(askConfirmation()));
connect(newScreenshot, SIGNAL(cleanup()) , this, SLOT(cleanup()));
connect(newScreenshot, SIGNAL(finished()) , this, SLOT(finished()));
newScreenshot->take();
}
void ScreenshotManager::uploadDone(QString fileName, QString url, QString deleteHash)
{
foreach (Screenshot* screenshot, 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 = 0;
ScreenshotManager *ScreenshotManager::instance()
{
if (!mInstance)
mInstance = new ScreenshotManager();
return mInstance;
}
diff --git a/tools/uploader/uploader.cpp b/tools/uploader/uploader.cpp
index f1ddcb2..f98973e 100644
--- a/tools/uploader/uploader.cpp
+++ b/tools/uploader/uploader.cpp
@@ -1,204 +1,204 @@
/*
* Copyright (C) 2014 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 <QtNetwork>
#include <QSettings>
Uploader* Uploader::mInstance = 0;
-Uploader::Uploader(QObject *parent) : QObject(parent)
+Uploader::Uploader(QObject *parent) : QObject(parent), mProgress(0)
{
mNetworkAccessManager = new QNetworkAccessManager(this);
}
Uploader *Uploader::instance()
{
if (!mInstance)
mInstance = new Uploader();
return mInstance;
}
int Uploader::progress() const
{
return mProgress;
}
QNetworkAccessManager* Uploader::nam()
{
return mNetworkAccessManager;
}
QString Uploader::lastUrl() const
{
return mLastUrl;
}
void Uploader::cancel()
{
mUploaders.clear();
mProgress = 0;
emit cancelAll();
}
void Uploader::upload(const QString &fileName)
{
if (fileName.isEmpty()) {
return;
}
QVariantHash options;
QSettings *s = ScreenshotManager::instance()->settings();
options["type"] = "imgur";
options["networkManager"].setValue(mNetworkAccessManager);
- options["anonymous"] = s->value("upload/imgur/anonymous", true).toBool();
- options["album"] = s->value("upload/imgur/album", "").toString();
+ options["anonymous"] = s->value("upload/imgur/anonymous", true).toBool();
+ options["album"] = s->value("upload/imgur/album", "").toString();
options["access_token"] = s->value("upload/imgur/access_token", "").toString();
options["refresh_token"] = s->value("upload/imgur/refresh_token", "").toString();
if (options["access_token"].toString().isEmpty() || options["refresh_token"].toString().isEmpty())
{
options["anonymous"] = true;
}
ImgurUploader *uploader = new ImgurUploader(options);
connect(uploader, &ImgurUploader::uploaded , this, &Uploader::uploaded);
connect(uploader, &ImgurUploader::error , this, &Uploader::uploaderError);
connect(uploader, &ImgurUploader::progressChange , this, &Uploader::progressChange);
connect(uploader, &ImgurUploader::needAuthRefresh, this, &Uploader::imgurAuthRefresh);
connect(this , SIGNAL(cancelAll()), uploader, SLOT(cancel()));
uploader->upload(fileName);
mUploaders.append(uploader);
}
void Uploader::uploaded(const QString &file, const QString &url, const QString &deleteHash)
{
mLastUrl = url;
mUploaders.removeAll(qobject_cast<ImageUploader*>(sender()));
if (mUploaders.isEmpty())
mProgress = 0;
sender()->deleteLater();
emit done(file, url, deleteHash);
}
void Uploader::imgurAuthRefresh()
{
for (int i = 0; i < mUploaders.size(); ++i) {
if (mUploaders[i]->options().value("type") == "imgur") {
mUploaders[i]->cancel();
}
}
QByteArray parameters;
parameters.append(QString("refresh_token=").toUtf8());
parameters.append(QUrl::toPercentEncoding(ScreenshotManager::instance()->settings()->value("upload/imgur/refresh_token").toString()));
parameters.append(QString("&client_id=").toUtf8());
parameters.append(QUrl::toPercentEncoding("3ebe94c791445c1"));
parameters.append(QString("&client_secret=").toUtf8());
parameters.append(QUrl::toPercentEncoding("0546b05d6a80b2092dcea86c57b792c9c9faebf0")); // TODO: TA.png
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::instance()->nam()->post(request, parameters);
connect(reply, SIGNAL(finished()), this, SLOT(imgurToken()));
}
void Uploader::imgurToken()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (reply->error() != QNetworkReply::NoError) {
emit error(reply->errorString());
return;
}
QJsonObject imgurResponse = QJsonDocument::fromJson(reply->readAll()).object();
QSettings* s = ScreenshotManager::instance()->settings();
s->setValue("upload/imgur/access_token" , imgurResponse["access_token"].toString());
s->setValue("upload/imgur/refresh_token" , imgurResponse["refresh_token"].toString());
s->setValue("upload/imgur/account_username", imgurResponse["account_username"].toString());
s->setValue("upload/imgur/expires_in" , imgurResponse["expires_in"].toString());
for (int i = 0; i < mUploaders.size(); ++i) {
if (mUploaders[i]->options().value("type") == "imgur") {
mUploaders[i]->options().remove("access_token");
mUploaders[i]->options().remove("refresh_token");
mUploaders[i]->options().insert("access_token" , imgurResponse["access_token"].toString());
mUploaders[i]->options().insert("refresh_token", imgurResponse["refresh_token"].toString());
mUploaders[i]->retry();
}
}
emit imgurAuthRefreshed();
}
void Uploader::uploaderError(ImageUploader::Error code, QString errorString, QString fileName)
{
mUploaders.removeAll(qobject_cast<ImageUploader*>(sender()));
sender()->deleteLater();
mProgress = 0;
if (code != ImageUploader::CancelError) {
if (errorString.isEmpty()) {
emit error(tr("Upload Error ") + code);
}
else {
emit error(errorString);
}
}
emit done(fileName, "", "");
}
int Uploader::uploading()
{
return mUploaders.count();
}
void Uploader::progressChange(int p)
{
if (mUploaders.size() <= 0) {
mProgress = p;
emit progress(p);
return;
}
int totalProgress = 0;
for (int i = 0; i < mUploaders.size(); ++i) {
totalProgress += mUploaders[i]->progress();
}
mProgress = totalProgress / mUploaders.size();
emit progress(mProgress);
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 15, 11:27 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69773
Default Alt Text
(124 KB)

Event Timeline