reformatted to Mozilla code style

This commit is contained in:
Jeremy Borgman
2020-09-04 20:16:33 -05:00
committed by borgmanJeremy
parent c0e2e48db4
commit c8d15205be
176 changed files with 12695 additions and 11269 deletions

View File

@@ -1,89 +1,2 @@
Language: Cpp Language: Cpp
# BasedOnStyle: Google BasedOnStyle: Mozilla
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 2
UseTab: Never

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -24,59 +24,59 @@
namespace color_widgets { namespace color_widgets {
namespace detail { namespace detail {
QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha ) QColor
color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha)
{ {
qreal h1 = hue*6; qreal h1 = hue * 6;
qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1)); qreal x = chroma * (1 - qAbs(std::fmod(h1, 2) - 1));
QColor col; QColor col;
if ( h1 >= 0 && h1 < 1 ) if (h1 >= 0 && h1 < 1)
col = QColor::fromRgbF(chroma,x,0); col = QColor::fromRgbF(chroma, x, 0);
else if ( h1 < 2 ) else if (h1 < 2)
col = QColor::fromRgbF(x,chroma,0); col = QColor::fromRgbF(x, chroma, 0);
else if ( h1 < 3 ) else if (h1 < 3)
col = QColor::fromRgbF(0,chroma,x); col = QColor::fromRgbF(0, chroma, x);
else if ( h1 < 4 ) else if (h1 < 4)
col = QColor::fromRgbF(0,x,chroma); col = QColor::fromRgbF(0, x, chroma);
else if ( h1 < 5 ) else if (h1 < 5)
col = QColor::fromRgbF(x,0,chroma); col = QColor::fromRgbF(x, 0, chroma);
else if ( h1 < 6 ) else if (h1 < 6)
col = QColor::fromRgbF(chroma,0,x); col = QColor::fromRgbF(chroma, 0, x);
qreal m = luma - color_lumaF(col); qreal m = luma - color_lumaF(col);
return QColor::fromRgbF( return QColor::fromRgbF(qBound(0.0, col.redF() + m, 1.0),
qBound(0.0,col.redF()+m,1.0), qBound(0.0, col.greenF() + m, 1.0),
qBound(0.0,col.greenF()+m,1.0), qBound(0.0, col.blueF() + m, 1.0),
qBound(0.0,col.blueF()+m,1.0), alpha);
alpha);
} }
QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha ) QColor
color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha)
{ {
qreal chroma = (1 - qAbs(2*lig-1))*sat; qreal chroma = (1 - qAbs(2 * lig - 1)) * sat;
qreal h1 = hue*6; qreal h1 = hue * 6;
qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1)); qreal x = chroma * (1 - qAbs(std::fmod(h1, 2) - 1));
QColor col; QColor col;
if ( h1 >= 0 && h1 < 1 ) if (h1 >= 0 && h1 < 1)
col = QColor::fromRgbF(chroma,x,0); col = QColor::fromRgbF(chroma, x, 0);
else if ( h1 < 2 ) else if (h1 < 2)
col = QColor::fromRgbF(x,chroma,0); col = QColor::fromRgbF(x, chroma, 0);
else if ( h1 < 3 ) else if (h1 < 3)
col = QColor::fromRgbF(0,chroma,x); col = QColor::fromRgbF(0, chroma, x);
else if ( h1 < 4 ) else if (h1 < 4)
col = QColor::fromRgbF(0,x,chroma); col = QColor::fromRgbF(0, x, chroma);
else if ( h1 < 5 ) else if (h1 < 5)
col = QColor::fromRgbF(x,0,chroma); col = QColor::fromRgbF(x, 0, chroma);
else if ( h1 < 6 ) else if (h1 < 6)
col = QColor::fromRgbF(chroma,0,x); col = QColor::fromRgbF(chroma, 0, x);
qreal m = lig-chroma/2; qreal m = lig - chroma / 2;
return QColor::fromRgbF( return QColor::fromRgbF(qBound(0.0, col.redF() + m, 1.0),
qBound(0.0,col.redF()+m,1.0), qBound(0.0, col.greenF() + m, 1.0),
qBound(0.0,col.greenF()+m,1.0), qBound(0.0, col.blueF() + m, 1.0),
qBound(0.0,col.blueF()+m,1.0), alpha);
alpha);
} }
} // namespace detail } // namespace detail

File diff suppressed because it is too large Load Diff

View File

@@ -22,335 +22,351 @@
#include <cstdlib> #include <cstdlib>
#include <QtCore/QByteArray>
#include <QtCore/QCryptographicHash>
#include <QtCore/QDataStream>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QProcess> #include <QtCore/QProcess>
#include <QtCore/QByteArray>
#include <QtCore/QSemaphore> #include <QtCore/QSemaphore>
#include <QtCore/QSharedMemory> #include <QtCore/QSharedMemory>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QtCore/QCryptographicHash>
#include <QtCore/QDataStream>
#include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <windows.h> #include <lmcons.h>
#include <lmcons.h> #include <windows.h>
#endif #endif
#include "singleapplication.h" #include "singleapplication.h"
#include "singleapplication_p.h" #include "singleapplication_p.h"
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication* q_ptr)
SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr ) : q_ptr( q_ptr ) { : q_ptr(q_ptr)
server = nullptr; {
socket = nullptr; server = nullptr;
socket = nullptr;
} }
SingleApplicationPrivate::~SingleApplicationPrivate() SingleApplicationPrivate::~SingleApplicationPrivate()
{ {
if( socket != nullptr ) { if (socket != nullptr) {
socket->close(); socket->close();
delete socket; delete socket;
} }
memory->lock(); memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data()); InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
if( server != nullptr ) { if (server != nullptr) {
server->close(); server->close();
delete server; delete server;
inst->primary = false; inst->primary = false;
inst->primaryPid = -1; inst->primaryPid = -1;
} }
memory->unlock(); memory->unlock();
delete memory; delete memory;
} }
void SingleApplicationPrivate::genBlockServerName( int timeout ) void
SingleApplicationPrivate::genBlockServerName(int timeout)
{ {
QCryptographicHash appData( QCryptographicHash::Sha256 ); QCryptographicHash appData(QCryptographicHash::Sha256);
appData.addData( "SingleApplication", 17 ); appData.addData("SingleApplication", 17);
appData.addData( SingleApplication::app_t::applicationName().toUtf8() ); appData.addData(SingleApplication::app_t::applicationName().toUtf8());
appData.addData( SingleApplication::app_t::organizationName().toUtf8() ); appData.addData(SingleApplication::app_t::organizationName().toUtf8());
appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() ); appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) { if (!(options & SingleApplication::Mode::ExcludeAppVersion)) {
appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() ); appData.addData(SingleApplication::app_t::applicationVersion().toUtf8());
} }
if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) { if (!(options & SingleApplication::Mode::ExcludeAppPath)) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() ); appData.addData(
SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
#else #else
appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() ); appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
#endif #endif
} }
// User level block requires a user specific data in the hash // User level block requires a user specific data in the hash
if( options & SingleApplication::Mode::User ) { if (options & SingleApplication::Mode::User) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
Q_UNUSED(timeout); Q_UNUSED(timeout);
wchar_t username [ UNLEN + 1 ]; wchar_t username[UNLEN + 1];
// Specifies size of the buffer on input // Specifies size of the buffer on input
DWORD usernameLength = UNLEN + 1; DWORD usernameLength = UNLEN + 1;
if( GetUserNameW( username, &usernameLength ) ) { if (GetUserNameW(username, &usernameLength)) {
appData.addData( QString::fromWCharArray(username).toUtf8() ); appData.addData(QString::fromWCharArray(username).toUtf8());
} else {
appData.addData( QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).join("").toUtf8() );
}
#endif
#ifdef Q_OS_UNIX
QProcess process;
process.start( QStringLiteral("whoami"),QStringList{} );
if( process.waitForFinished( timeout ) &&
process.exitCode() == QProcess::NormalExit) {
appData.addData( process.readLine() );
} else {
appData.addData(
QDir(
QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first()
).absolutePath().toUtf8()
);
}
#endif
}
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
// server naming requirements.
blockServerName = appData.result().toBase64().replace("/", "_");
}
void SingleApplicationPrivate::startPrimary( bool resetMemory )
{
Q_Q(SingleApplication);
#ifdef Q_OS_UNIX
// Handle any further termination signals to ensure the
// QSharedMemory block is deleted even if the process crashes
crashHandler();
#endif
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
QLocalServer::removeServer( blockServerName );
server = new QLocalServer();
// Restrict access to the socket according to the
// SingleApplication::Mode::User flag on User level or no restrictions
if( options & SingleApplication::Mode::User ) {
server->setSocketOptions( QLocalServer::UserAccessOption );
} else { } else {
server->setSocketOptions( QLocalServer::WorldAccessOption ); appData.addData(
QStandardPaths::standardLocations(QStandardPaths::HomeLocation)
.join("")
.toUtf8());
} }
#endif
#ifdef Q_OS_UNIX
QProcess process;
process.start(QStringLiteral("whoami"), QStringList{});
server->listen( blockServerName ); if (process.waitForFinished(timeout) &&
QObject::connect( process.exitCode() == QProcess::NormalExit) {
server, appData.addData(process.readLine());
&QLocalServer::newConnection, } else {
this, appData.addData(
&SingleApplicationPrivate::slotConnectionEstablished QDir(QStandardPaths::standardLocations(QStandardPaths::HomeLocation)
); .first())
.absolutePath()
// Reset the number of connections .toUtf8());
memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
if( resetMemory ) {
inst->secondary = 0;
} }
#endif
}
inst->primary = true; // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
inst->primaryPid = q->applicationPid(); // server naming requirements.
blockServerName = appData.result().toBase64().replace("/", "_");
memory->unlock();
instanceNumber = 0;
} }
void SingleApplicationPrivate::startSecondary() void
SingleApplicationPrivate::startPrimary(bool resetMemory)
{
Q_Q(SingleApplication);
#ifdef Q_OS_UNIX
// Handle any further termination signals to ensure the
// QSharedMemory block is deleted even if the process crashes
crashHandler();
#endif
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
QLocalServer::removeServer(blockServerName);
server = new QLocalServer();
// Restrict access to the socket according to the
// SingleApplication::Mode::User flag on User level or no restrictions
if (options & SingleApplication::Mode::User) {
server->setSocketOptions(QLocalServer::UserAccessOption);
} else {
server->setSocketOptions(QLocalServer::WorldAccessOption);
}
server->listen(blockServerName);
QObject::connect(server,
&QLocalServer::newConnection,
this,
&SingleApplicationPrivate::slotConnectionEstablished);
// Reset the number of connections
memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
if (resetMemory) {
inst->secondary = 0;
}
inst->primary = true;
inst->primaryPid = q->applicationPid();
memory->unlock();
instanceNumber = 0;
}
void
SingleApplicationPrivate::startSecondary()
{ {
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
// Handle any further termination signals to ensure the // Handle any further termination signals to ensure the
// QSharedMemory block is deleted even if the process crashes // QSharedMemory block is deleted even if the process crashes
crashHandler(); crashHandler();
#endif #endif
} }
void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType ) void
SingleApplicationPrivate::connectToPrimary(int msecs,
ConnectionType connectionType)
{ {
// Connect to the Local Server of the Primary Instance if not already // Connect to the Local Server of the Primary Instance if not already
// connected. // connected.
if( socket == nullptr ) { if (socket == nullptr) {
socket = new QLocalSocket(); socket = new QLocalSocket();
} }
// If already connected - we are done; // If already connected - we are done;
if( socket->state() == QLocalSocket::ConnectedState ) if (socket->state() == QLocalSocket::ConnectedState)
return; return;
// If not connect // If not connect
if( socket->state() == QLocalSocket::UnconnectedState || if (socket->state() == QLocalSocket::UnconnectedState ||
socket->state() == QLocalSocket::ClosingState ) { socket->state() == QLocalSocket::ClosingState) {
socket->connectToServer( blockServerName ); socket->connectToServer(blockServerName);
} }
// Wait for being connected // Wait for being connected
if( socket->state() == QLocalSocket::ConnectingState ) { if (socket->state() == QLocalSocket::ConnectingState) {
socket->waitForConnected( msecs ); socket->waitForConnected(msecs);
} }
// Initialisation message according to the SingleApplication protocol // Initialisation message according to the SingleApplication protocol
if( socket->state() == QLocalSocket::ConnectedState ) { if (socket->state() == QLocalSocket::ConnectedState) {
// Notify the parent that a new instance had been started; // Notify the parent that a new instance had been started;
QByteArray initMsg; QByteArray initMsg;
QDataStream writeStream(&initMsg, QIODevice::WriteOnly); QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
writeStream.setVersion(QDataStream::Qt_5_2); writeStream.setVersion(QDataStream::Qt_5_2);
writeStream << blockServerName.toLatin1(); writeStream << blockServerName.toLatin1();
writeStream << static_cast<quint8>(connectionType); writeStream << static_cast<quint8>(connectionType);
writeStream << instanceNumber; writeStream << instanceNumber;
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length())); quint16 checksum =
writeStream << checksum; qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
writeStream << checksum;
socket->write( initMsg ); socket->write(initMsg);
socket->flush(); socket->flush();
socket->waitForBytesWritten( msecs ); socket->waitForBytesWritten(msecs);
} }
} }
qint64 SingleApplicationPrivate::primaryPid() qint64
SingleApplicationPrivate::primaryPid()
{ {
qint64 pid; qint64 pid;
memory->lock(); memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data()); InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
pid = inst->primaryPid; pid = inst->primaryPid;
memory->unlock(); memory->unlock();
return pid; return pid;
} }
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
void SingleApplicationPrivate::crashHandler() void
{ SingleApplicationPrivate::crashHandler()
// Handle any further termination signals to ensure the {
// QSharedMemory block is deleted even if the process crashes // Handle any further termination signals to ensure the
signal( SIGHUP, SingleApplicationPrivate::terminate ); // 1 // QSharedMemory block is deleted even if the process crashes
signal( SIGINT, SingleApplicationPrivate::terminate ); // 2 signal(SIGHUP, SingleApplicationPrivate::terminate); // 1
signal( SIGQUIT, SingleApplicationPrivate::terminate ); // 3 signal(SIGINT, SingleApplicationPrivate::terminate); // 2
signal( SIGILL, SingleApplicationPrivate::terminate ); // 4 signal(SIGQUIT, SingleApplicationPrivate::terminate); // 3
signal( SIGABRT, SingleApplicationPrivate::terminate ); // 6 signal(SIGILL, SingleApplicationPrivate::terminate); // 4
signal( SIGFPE, SingleApplicationPrivate::terminate ); // 8 signal(SIGABRT, SingleApplicationPrivate::terminate); // 6
signal( SIGBUS, SingleApplicationPrivate::terminate ); // 10 signal(SIGFPE, SingleApplicationPrivate::terminate); // 8
signal( SIGSEGV, SingleApplicationPrivate::terminate ); // 11 signal(SIGBUS, SingleApplicationPrivate::terminate); // 10
signal( SIGSYS, SingleApplicationPrivate::terminate ); // 12 signal(SIGSEGV, SingleApplicationPrivate::terminate); // 11
signal( SIGPIPE, SingleApplicationPrivate::terminate ); // 13 signal(SIGSYS, SingleApplicationPrivate::terminate); // 12
signal( SIGALRM, SingleApplicationPrivate::terminate ); // 14 signal(SIGPIPE, SingleApplicationPrivate::terminate); // 13
signal( SIGTERM, SingleApplicationPrivate::terminate ); // 15 signal(SIGALRM, SingleApplicationPrivate::terminate); // 14
signal( SIGXCPU, SingleApplicationPrivate::terminate ); // 24 signal(SIGTERM, SingleApplicationPrivate::terminate); // 15
signal( SIGXFSZ, SingleApplicationPrivate::terminate ); // 25 signal(SIGXCPU, SingleApplicationPrivate::terminate); // 24
} signal(SIGXFSZ, SingleApplicationPrivate::terminate); // 25
}
void SingleApplicationPrivate::terminate( int signum ) void
{ SingleApplicationPrivate::terminate(int signum)
delete ((SingleApplication*)QCoreApplication::instance())->d_ptr; {
::exit( 128 + signum ); delete ((SingleApplication*)QCoreApplication::instance())->d_ptr;
} ::exit(128 + signum);
}
#endif #endif
/** /**
* @brief Executed when a connection has been made to the LocalServer * @brief Executed when a connection has been made to the LocalServer
*/ */
void SingleApplicationPrivate::slotConnectionEstablished() void
SingleApplicationPrivate::slotConnectionEstablished()
{ {
Q_Q(SingleApplication); Q_Q(SingleApplication);
QLocalSocket *nextConnSocket = server->nextPendingConnection(); QLocalSocket* nextConnSocket = server->nextPendingConnection();
quint32 instanceId = 0; quint32 instanceId = 0;
ConnectionType connectionType = InvalidConnection; ConnectionType connectionType = InvalidConnection;
if( nextConnSocket->waitForReadyRead( 100 ) ) { if (nextConnSocket->waitForReadyRead(100)) {
// read all data from message in same order/format as written // read all data from message in same order/format as written
QByteArray msgBytes = nextConnSocket->read(nextConnSocket->bytesAvailable() - static_cast<qint64>(sizeof(quint16))); QByteArray msgBytes = nextConnSocket->read(
QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16)); nextConnSocket->bytesAvailable() - static_cast<qint64>(sizeof(quint16)));
QDataStream readStream(msgBytes); QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16));
readStream.setVersion(QDataStream::Qt_5_2); QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_2);
// server name // server name
QByteArray latin1Name; QByteArray latin1Name;
readStream >> latin1Name; readStream >> latin1Name;
// connectioon type // connectioon type
quint8 connType = InvalidConnection; quint8 connType = InvalidConnection;
readStream >> connType; readStream >> connType;
connectionType = static_cast<ConnectionType>(connType); connectionType = static_cast<ConnectionType>(connType);
// instance id // instance id
readStream >> instanceId; readStream >> instanceId;
// checksum // checksum
quint16 msgChecksum = 0; quint16 msgChecksum = 0;
QDataStream checksumStream(checksumBytes); QDataStream checksumStream(checksumBytes);
checksumStream.setVersion(QDataStream::Qt_5_2); checksumStream.setVersion(QDataStream::Qt_5_2);
checksumStream >> msgChecksum; checksumStream >> msgChecksum;
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length())); const quint16 actualChecksum =
qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length()));
if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { if (readStream.status() != QDataStream::Ok ||
connectionType = InvalidConnection; QLatin1String(latin1Name) != blockServerName ||
} msgChecksum != actualChecksum) {
connectionType = InvalidConnection;
} }
}
if( connectionType == InvalidConnection ) { if (connectionType == InvalidConnection) {
nextConnSocket->close(); nextConnSocket->close();
delete nextConnSocket; delete nextConnSocket;
return; return;
} }
QObject::connect( QObject::connect(nextConnSocket,
nextConnSocket, &QLocalSocket::aboutToClose,
&QLocalSocket::aboutToClose, this,
this, [nextConnSocket, instanceId, this]() {
[nextConnSocket, instanceId, this]() { emit this->slotClientConnectionClosed(nextConnSocket,
emit this->slotClientConnectionClosed( nextConnSocket, instanceId ); instanceId);
} });
);
QObject::connect( QObject::connect(nextConnSocket,
nextConnSocket, &QLocalSocket::readyRead,
&QLocalSocket::readyRead, this,
this, [nextConnSocket, instanceId, this]() {
[nextConnSocket, instanceId, this]() { emit this->slotDataAvailable(nextConnSocket, instanceId);
emit this->slotDataAvailable( nextConnSocket, instanceId ); });
}
);
if( connectionType == NewInstance || ( if (connectionType == NewInstance ||
connectionType == SecondaryInstance && (connectionType == SecondaryInstance &&
options & SingleApplication::Mode::SecondaryNotification options & SingleApplication::Mode::SecondaryNotification)) {
) emit q->instanceStarted();
) { }
emit q->instanceStarted();
}
if( nextConnSocket->bytesAvailable() > 0 ) { if (nextConnSocket->bytesAvailable() > 0) {
emit this->slotDataAvailable( nextConnSocket, instanceId ); emit this->slotDataAvailable(nextConnSocket, instanceId);
} }
} }
void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId ) void
SingleApplicationPrivate::slotDataAvailable(QLocalSocket* dataSocket,
quint32 instanceId)
{ {
Q_Q(SingleApplication); Q_Q(SingleApplication);
emit q->receivedMessage( instanceId, dataSocket->readAll() ); emit q->receivedMessage(instanceId, dataSocket->readAll());
} }
void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId ) void
SingleApplicationPrivate::slotClientConnectionClosed(QLocalSocket* closedSocket,
quint32 instanceId)
{ {
if( closedSocket->bytesAvailable() > 0 ) if (closedSocket->bytesAvailable() > 0)
emit slotDataAvailable( closedSocket, instanceId ); emit slotDataAvailable(closedSocket, instanceId);
closedSocket->deleteLater(); closedSocket->deleteLater();
} }
/** /**
@@ -360,63 +376,69 @@ void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedS
* @param argv * @param argv
* @param {bool} allowSecondaryInstances * @param {bool} allowSecondaryInstances
*/ */
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout ) SingleApplication::SingleApplication(int& argc,
: app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) ) char* argv[],
bool allowSecondary,
Options options,
int timeout)
: app_t(argc, argv)
, d_ptr(new SingleApplicationPrivate(this))
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
// Store the current mode of the program // Store the current mode of the program
d->options = options; d->options = options;
// Generating an application ID used for identifying the shared memory // Generating an application ID used for identifying the shared memory
// block and QLocalServer // block and QLocalServer
d->genBlockServerName( timeout ); d->genBlockServerName(timeout);
// Guarantee thread safe behaviour with a shared memory block. Also by // Guarantee thread safe behaviour with a shared memory block. Also by
// explicitly attaching it and then deleting it we make sure that the // explicitly attaching it and then deleting it we make sure that the
// memory is deleted even if the process had crashed on Unix. // memory is deleted even if the process had crashed on Unix.
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
d->memory = new QSharedMemory( d->blockServerName ); d->memory = new QSharedMemory(d->blockServerName);
d->memory->attach(); d->memory->attach();
delete d->memory; delete d->memory;
#endif #endif
d->memory = new QSharedMemory( d->blockServerName ); d->memory = new QSharedMemory(d->blockServerName);
// Create a shared memory block // Create a shared memory block
if( d->memory->create( sizeof( InstancesInfo ) ) ) { if (d->memory->create(sizeof(InstancesInfo))) {
d->startPrimary( true ); d->startPrimary(true);
return;
} else {
// Attempt to attach to the memory segment
if (d->memory->attach()) {
d->memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(d->memory->data());
if (!inst->primary) {
d->startPrimary(false);
d->memory->unlock();
return; return;
} else { }
// Attempt to attach to the memory segment
if( d->memory->attach() ) {
d->memory->lock();
InstancesInfo* inst = static_cast<InstancesInfo*>(d->memory->data());
if( ! inst->primary ) { // Check if another instance can be started
d->startPrimary( false ); if (allowSecondary) {
d->memory->unlock(); inst->secondary += 1;
return; d->instanceNumber = inst->secondary;
} d->startSecondary();
if (d->options & Mode::SecondaryNotification) {
// Check if another instance can be started d->connectToPrimary(timeout,
if( allowSecondary ) { SingleApplicationPrivate::SecondaryInstance);
inst->secondary += 1;
d->instanceNumber = inst->secondary;
d->startSecondary();
if( d->options & Mode::SecondaryNotification ) {
d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
}
d->memory->unlock();
return;
}
d->memory->unlock();
} }
} d->memory->unlock();
return;
}
d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance ); d->memory->unlock();
delete d; }
::exit( EXIT_SUCCESS ); }
d->connectToPrimary(timeout, SingleApplicationPrivate::NewInstance);
delete d;
::exit(EXIT_SUCCESS);
} }
/** /**
@@ -424,46 +446,52 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda
*/ */
SingleApplication::~SingleApplication() SingleApplication::~SingleApplication()
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
delete d; delete d;
} }
bool SingleApplication::isPrimary() bool
SingleApplication::isPrimary()
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
return d->server != nullptr; return d->server != nullptr;
} }
bool SingleApplication::isSecondary() bool
SingleApplication::isSecondary()
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
return d->server == nullptr; return d->server == nullptr;
} }
quint32 SingleApplication::instanceId() quint32
SingleApplication::instanceId()
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
return d->instanceNumber; return d->instanceNumber;
} }
qint64 SingleApplication::primaryPid() qint64
SingleApplication::primaryPid()
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
return d->primaryPid(); return d->primaryPid();
} }
bool SingleApplication::sendMessage( QByteArray message, int timeout ) bool
SingleApplication::sendMessage(QByteArray message, int timeout)
{ {
Q_D(SingleApplication); Q_D(SingleApplication);
// Nobody to connect to // Nobody to connect to
if( isPrimary() ) return false; if (isPrimary())
return false;
// Make sure the socket is connected // Make sure the socket is connected
d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ); d->connectToPrimary(timeout, SingleApplicationPrivate::Reconnect);
d->socket->write( message ); d->socket->write(message);
bool dataWritten = d->socket->flush(); bool dataWritten = d->socket->flush();
d->socket->waitForBytesWritten( timeout ); d->socket->waitForBytesWritten(timeout);
return dataWritten; return dataWritten;
} }

View File

@@ -27,7 +27,7 @@
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#ifndef QAPPLICATION_CLASS #ifndef QAPPLICATION_CLASS
#define QAPPLICATION_CLASS QCoreApplication #define QAPPLICATION_CLASS QCoreApplication
#endif #endif
#include QT_STRINGIFY(QAPPLICATION_CLASS) #include QT_STRINGIFY(QAPPLICATION_CLASS)
@@ -41,93 +41,98 @@ class SingleApplicationPrivate;
*/ */
class SingleApplication : public QAPPLICATION_CLASS class SingleApplication : public QAPPLICATION_CLASS
{ {
Q_OBJECT Q_OBJECT
typedef QAPPLICATION_CLASS app_t; typedef QAPPLICATION_CLASS app_t;
public: public:
/** /**
* @brief Mode of operation of SingleApplication. * @brief Mode of operation of SingleApplication.
* Whether the block should be user-wide or system-wide and whether the * Whether the block should be user-wide or system-wide and whether the
* primary instance should be notified when a secondary instance had been * primary instance should be notified when a secondary instance had been
* started. * started.
* @note Operating system can restrict the shared memory blocks to the same * @note Operating system can restrict the shared memory blocks to the same
* user, in which case the User/System modes will have no effect and the * user, in which case the User/System modes will have no effect and the
* block will be user wide. * block will be user wide.
* @enum * @enum
*/ */
enum Mode { enum Mode
User = 1 << 0, {
System = 1 << 1, User = 1 << 0,
SecondaryNotification = 1 << 2, System = 1 << 1,
ExcludeAppVersion = 1 << 3, SecondaryNotification = 1 << 2,
ExcludeAppPath = 1 << 4 ExcludeAppVersion = 1 << 3,
}; ExcludeAppPath = 1 << 4
Q_DECLARE_FLAGS(Options, Mode) };
Q_DECLARE_FLAGS(Options, Mode)
/** /**
* @brief Intitializes a SingleApplication instance with argc command line * @brief Intitializes a SingleApplication instance with argc command line
* arguments in argv * arguments in argv
* @arg {int &} argc - Number of arguments in argv * @arg {int &} argc - Number of arguments in argv
* @arg {const char *[]} argv - Supplied command line arguments * @arg {const char *[]} argv - Supplied command line arguments
* @arg {bool} allowSecondary - Whether to start the instance as secondary * @arg {bool} allowSecondary - Whether to start the instance as secondary
* if there is already a primary instance. * if there is already a primary instance.
* @arg {Mode} mode - Whether for the SingleApplication block to be applied * @arg {Mode} mode - Whether for the SingleApplication block to be applied
* User wide or System wide. * User wide or System wide.
* @arg {int} timeout - Timeout to wait in miliseconds. * @arg {int} timeout - Timeout to wait in miliseconds.
* @note argc and argv may be changed as Qt removes arguments that it * @note argc and argv may be changed as Qt removes arguments that it
* recognizes * recognizes
* @note Mode::SecondaryNotification only works if set on both the primary * @note Mode::SecondaryNotification only works if set on both the primary
* instance and the secondary instance. * instance and the secondary instance.
* @note The timeout is just a hint for the maximum time of blocking * @note The timeout is just a hint for the maximum time of blocking
* operations. It does not guarantee that the SingleApplication * operations. It does not guarantee that the SingleApplication
* initialisation will be completed in given time, though is a good hint. * initialisation will be completed in given time, though is a good hint.
* Usually 4*timeout would be the worst case (fail) scenario. * Usually 4*timeout would be the worst case (fail) scenario.
* @see See the corresponding QAPPLICATION_CLASS constructor for reference * @see See the corresponding QAPPLICATION_CLASS constructor for reference
*/ */
explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 ); explicit SingleApplication(int& argc,
~SingleApplication(); char* argv[],
bool allowSecondary = false,
Options options = Mode::User,
int timeout = 100);
~SingleApplication();
/** /**
* @brief Returns if the instance is the primary instance * @brief Returns if the instance is the primary instance
* @returns {bool} * @returns {bool}
*/ */
bool isPrimary(); bool isPrimary();
/** /**
* @brief Returns if the instance is a secondary instance * @brief Returns if the instance is a secondary instance
* @returns {bool} * @returns {bool}
*/ */
bool isSecondary(); bool isSecondary();
/** /**
* @brief Returns a unique identifier for the current instance * @brief Returns a unique identifier for the current instance
* @returns {qint32} * @returns {qint32}
*/ */
quint32 instanceId(); quint32 instanceId();
/** /**
* @brief Returns the process ID (PID) of the primary instance * @brief Returns the process ID (PID) of the primary instance
* @returns {qint64} * @returns {qint64}
*/ */
qint64 primaryPid(); qint64 primaryPid();
/** /**
* @brief Sends a message to the primary instance. Returns true on success. * @brief Sends a message to the primary instance. Returns true on success.
* @param {int} timeout - Timeout for connecting * @param {int} timeout - Timeout for connecting
* @returns {bool} * @returns {bool}
* @note sendMessage() will return false if invoked from the primary * @note sendMessage() will return false if invoked from the primary
* instance. * instance.
*/ */
bool sendMessage( QByteArray message, int timeout = 100 ); bool sendMessage(QByteArray message, int timeout = 100);
Q_SIGNALS: Q_SIGNALS:
void instanceStarted(); void instanceStarted();
void receivedMessage( quint32 instanceId, QByteArray message ); void receivedMessage(quint32 instanceId, QByteArray message);
private: private:
SingleApplicationPrivate *d_ptr; SingleApplicationPrivate* d_ptr;
Q_DECLARE_PRIVATE(SingleApplication) Q_DECLARE_PRIVATE(SingleApplication)
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options) Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)

View File

@@ -32,54 +32,57 @@
#ifndef SINGLEAPPLICATION_P_H #ifndef SINGLEAPPLICATION_P_H
#define SINGLEAPPLICATION_P_H #define SINGLEAPPLICATION_P_H
#include "singleapplication.h"
#include <QtCore/QSharedMemory> #include <QtCore/QSharedMemory>
#include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#include "singleapplication.h"
struct InstancesInfo { struct InstancesInfo
bool primary; {
quint32 secondary; bool primary;
qint64 primaryPid; quint32 secondary;
qint64 primaryPid;
}; };
class SingleApplicationPrivate : public QObject { class SingleApplicationPrivate : public QObject
Q_OBJECT {
Q_OBJECT
public: public:
enum ConnectionType : quint8 { enum ConnectionType : quint8
InvalidConnection = 0, {
NewInstance = 1, InvalidConnection = 0,
SecondaryInstance = 2, NewInstance = 1,
Reconnect = 3 SecondaryInstance = 2,
}; Reconnect = 3
Q_DECLARE_PUBLIC(SingleApplication) };
Q_DECLARE_PUBLIC(SingleApplication)
SingleApplicationPrivate( SingleApplication *q_ptr ); SingleApplicationPrivate(SingleApplication* q_ptr);
~SingleApplicationPrivate(); ~SingleApplicationPrivate();
void genBlockServerName( int msecs ); void genBlockServerName(int msecs);
void startPrimary( bool resetMemory ); void startPrimary(bool resetMemory);
void startSecondary(); void startSecondary();
void connectToPrimary(int msecs, ConnectionType connectionType ); void connectToPrimary(int msecs, ConnectionType connectionType);
qint64 primaryPid(); qint64 primaryPid();
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
void crashHandler(); void crashHandler();
static void terminate( int signum ); static void terminate(int signum);
#endif #endif
QSharedMemory *memory; QSharedMemory* memory;
SingleApplication *q_ptr; SingleApplication* q_ptr;
QLocalSocket *socket; QLocalSocket* socket;
QLocalServer *server; QLocalServer* server;
quint32 instanceNumber; quint32 instanceNumber;
QString blockServerName; QString blockServerName;
SingleApplication::Options options; SingleApplication::Options options;
public Q_SLOTS: public Q_SLOTS:
void slotConnectionEstablished(); void slotConnectionEstablished();
void slotDataAvailable( QLocalSocket*, quint32 ); void slotDataAvailable(QLocalSocket*, quint32);
void slotClientConnectionClosed( QLocalSocket*, quint32 ); void slotClientConnectionClosed(QLocalSocket*, quint32);
}; };
#endif // SINGLEAPPLICATION_P_H #endif // SINGLEAPPLICATION_P_H

View File

@@ -17,38 +17,46 @@
#include "commandargument.h" #include "commandargument.h"
CommandArgument::CommandArgument() { CommandArgument::CommandArgument() {}
} CommandArgument::CommandArgument(const QString& name,
const QString& description)
: m_name(name)
, m_description(description)
{}
CommandArgument::CommandArgument(const QString &name, void
const QString &description) : CommandArgument::setName(const QString& name)
m_name(name), m_description(description)
{ {
m_name = name;
} }
void CommandArgument::setName(const QString &name) { QString
m_name = name; CommandArgument::name() const
{
return m_name;
} }
QString CommandArgument::name() const { void
return m_name; CommandArgument::setDescription(const QString& description)
{
m_description = description;
} }
void CommandArgument::setDescription(const QString &description) { QString
m_description = description; CommandArgument::description() const
{
return m_description;
} }
QString CommandArgument::description() const { bool
return m_description; CommandArgument::isRoot() const
{
return m_name.isEmpty() && m_description.isEmpty();
} }
bool CommandArgument::isRoot() const { bool
return m_name.isEmpty() && m_description.isEmpty(); CommandArgument::operator==(const CommandArgument& arg) const
} {
return m_description == arg.m_description && m_name == arg.m_name;
bool CommandArgument::operator ==(const CommandArgument &arg) const {
return m_description == arg.m_description
&& m_name == arg.m_name;
} }

View File

@@ -19,22 +19,23 @@
#include <QString> #include <QString>
class CommandArgument { class CommandArgument
{
public: public:
CommandArgument(); CommandArgument();
explicit CommandArgument(const QString &name, const QString &description); explicit CommandArgument(const QString& name, const QString& description);
void setName(const QString &name); void setName(const QString& name);
QString name() const; QString name() const;
void setDescription(const QString &description); void setDescription(const QString& description);
QString description() const; QString description() const;
bool isRoot() const; bool isRoot() const;
bool operator ==(const CommandArgument &arg) const; bool operator==(const CommandArgument& arg) const;
private: private:
QString m_name; QString m_name;
QString m_description; QString m_description;
}; };

View File

@@ -19,384 +19,405 @@
#include <QApplication> #include <QApplication>
#include <QTextStream> #include <QTextStream>
CommandLineParser::CommandLineParser() : CommandLineParser::CommandLineParser()
m_description(qApp->applicationName()) : m_description(qApp->applicationName())
{ {}
}
namespace { namespace {
QTextStream out(stdout); QTextStream out(stdout);
QTextStream err(stderr); QTextStream err(stderr);
auto versionOption = CommandOption({"v", "version"}, auto versionOption =
QStringLiteral("Displays version information")); CommandOption({ "v", "version" },
auto helpOption = CommandOption({"h", "help"}, QStringLiteral("Displays version information"));
QStringLiteral("Displays this help")); auto helpOption =
CommandOption({ "h", "help" }, QStringLiteral("Displays this help"));
QString optionsToString(const QList<CommandOption> &options, QString
const QList<CommandArgument> &arguments) { optionsToString(const QList<CommandOption>& options,
int size = 0; // track the largest size const QList<CommandArgument>& arguments)
QStringList dashedOptionList; {
// save the dashed options and its size in order to print the description int size = 0; // track the largest size
// of every option at the same horizontal character position. QStringList dashedOptionList;
for (auto const &option: options) { // save the dashed options and its size in order to print the description
QStringList dashedOptions = option.dashedNames(); // of every option at the same horizontal character position.
QString joinedDashedOptions = dashedOptions.join(QStringLiteral(", ")); for (auto const& option : options) {
if (!option.valueName().isEmpty()) { QStringList dashedOptions = option.dashedNames();
joinedDashedOptions += QStringLiteral(" <%1>") QString joinedDashedOptions = dashedOptions.join(QStringLiteral(", "));
.arg(option.valueName()); if (!option.valueName().isEmpty()) {
} joinedDashedOptions += QStringLiteral(" <%1>").arg(option.valueName());
if (joinedDashedOptions.length() > size) {
size = joinedDashedOptions.length();
}
dashedOptionList << joinedDashedOptions;
} }
// check the length of the arguments if (joinedDashedOptions.length() > size) {
for (auto const &arg: arguments) { size = joinedDashedOptions.length();
if(arg.name().length() > size)
size = arg.name().length();
} }
// generate the text dashedOptionList << joinedDashedOptions;
QString result; }
if(!dashedOptionList.isEmpty()) { // check the length of the arguments
result += QLatin1String("Options:\n"); for (auto const& arg : arguments) {
QString linePadding = QStringLiteral(" ").repeated(size + 4).prepend("\n"); if (arg.name().length() > size)
for (int i = 0; i < options.length(); ++i) { size = arg.name().length();
result += QStringLiteral(" %1 %2\n") }
.arg(dashedOptionList.at(i).leftJustified(size, ' ')) // generate the text
.arg(options.at(i).description() QString result;
.replace(QLatin1String("\n"), linePadding)); if (!dashedOptionList.isEmpty()) {
} result += QLatin1String("Options:\n");
if (!arguments.isEmpty()) { QString linePadding = QStringLiteral(" ").repeated(size + 4).prepend("\n");
result += QLatin1String("\n"); for (int i = 0; i < options.length(); ++i) {
} result += QStringLiteral(" %1 %2\n")
.arg(dashedOptionList.at(i).leftJustified(size, ' '))
.arg(options.at(i).description().replace(QLatin1String("\n"),
linePadding));
} }
if (!arguments.isEmpty()) { if (!arguments.isEmpty()) {
result += QLatin1String("Arguments:\n"); result += QLatin1String("\n");
} }
for (int i = 0; i < arguments.length(); ++i) { }
result += QStringLiteral(" %1 %2\n") if (!arguments.isEmpty()) {
result += QLatin1String("Arguments:\n");
}
for (int i = 0; i < arguments.length(); ++i) {
result += QStringLiteral(" %1 %2\n")
.arg(arguments.at(i).name().leftJustified(size, ' ')) .arg(arguments.at(i).name().leftJustified(size, ' '))
.arg(arguments.at(i).description()); .arg(arguments.at(i).description());
} }
return result; return result;
} }
} // unnamed namespace } // unnamed namespace
bool CommandLineParser::processArgs(const QStringList &args, bool
QStringList::const_iterator &actualIt, CommandLineParser::processArgs(const QStringList& args,
Node * &actualNode) QStringList::const_iterator& actualIt,
Node*& actualNode)
{ {
QString argument = *actualIt; QString argument = *actualIt;
bool ok = true; bool ok = true;
bool isValidArg = false; bool isValidArg = false;
for (Node &n: actualNode->subNodes) { for (Node& n : actualNode->subNodes) {
if (n.argument.name() == argument) { if (n.argument.name() == argument) {
actualNode = &n; actualNode = &n;
isValidArg = true; isValidArg = true;
break; break;
}
}
if (isValidArg) {
auto nextArg = actualNode->argument;
m_foundArgs.append(nextArg);
// check next is help
++actualIt;
ok = processIfOptionIsHelp(args, actualIt, actualNode);
--actualIt;
} else {
ok = false;
out << QStringLiteral("'%1' is not a valid argument.").arg(argument);
} }
}
if (isValidArg) {
auto nextArg = actualNode->argument;
m_foundArgs.append(nextArg);
// check next is help
++actualIt;
ok = processIfOptionIsHelp(args, actualIt, actualNode);
--actualIt;
} else {
ok = false;
out << QStringLiteral("'%1' is not a valid argument.").arg(argument);
}
return ok;
}
bool
CommandLineParser::processOptions(const QStringList& args,
QStringList::const_iterator& actualIt,
Node* const actualNode)
{
QString arg = *actualIt;
bool ok = true;
// track values
int equalsPos = arg.indexOf(QLatin1String("="));
QString valueStr;
if (equalsPos != -1) {
valueStr = arg.mid(equalsPos + 1); // right
arg = arg.mid(0, equalsPos); // left
}
// check format -x --xx...
bool isDoubleDashed = arg.startsWith(QLatin1String("--"));
ok = isDoubleDashed ? arg.length() > 3 : arg.length() == 2;
if (!ok) {
out << QStringLiteral("the option %1 has a wrong format.").arg(arg);
return ok; return ok;
} }
arg = isDoubleDashed ? arg.remove(0, 2) : arg.remove(0, 1);
bool CommandLineParser::processOptions(const QStringList &args, // get option
QStringList::const_iterator &actualIt, auto endIt = actualNode->options.cend();
Node *const actualNode) auto optionIt = endIt;
{ for (auto i = actualNode->options.cbegin(); i != endIt; ++i) {
QString arg = *actualIt; if ((*i).names().contains(arg)) {
bool ok = true; optionIt = i;
// track values break;
int equalsPos = arg.indexOf(QLatin1String("="));
QString valueStr;
if (equalsPos != -1) {
valueStr = arg.mid(equalsPos +1); // right
arg = arg.mid(0, equalsPos); // left
} }
// check format -x --xx... }
bool isDoubleDashed = arg.startsWith(QLatin1String("--")); if (optionIt == endIt) {
ok = isDoubleDashed ? arg.length() > 3 : QString argName = actualNode->argument.name();
arg.length() == 2;
if (!ok) {
out << QStringLiteral("the option %1 has a wrong format.").arg(arg);
return ok;
}
arg = isDoubleDashed ?
arg.remove(0, 2) :
arg.remove(0, 1);
// get option
auto endIt = actualNode->options.cend();
auto optionIt = endIt;
for (auto i = actualNode->options.cbegin(); i != endIt; ++i) {
if ((*i).names().contains(arg)) {
optionIt = i;
break;
}
}
if (optionIt == endIt) {
QString argName = actualNode->argument.name();
if (argName.isEmpty()) {
argName = qApp->applicationName();
}
out << QStringLiteral("the option '%1' is not a valid option "
"for the argument '%2'.").arg(arg)
.arg(argName);
ok = false;
return ok;
}
// check presence of values
CommandOption option = *optionIt;
bool requiresValue = !(option.valueName().isEmpty());
if (!requiresValue && equalsPos != -1) {
out << QStringLiteral("the option '%1' contains a '=' and it doesn't "
"require a value.").arg(arg);
ok = false;
return ok;
} else if (requiresValue && valueStr.isEmpty()) {
// find in the next
if (actualIt+1 != args.cend()) {
++actualIt;
} else {
out << QStringLiteral("Expected value after the option '%1'.").arg(arg);
ok = false;
return ok;
}
valueStr = *actualIt;
}
// check the value correctness
if (requiresValue) {
ok = option.checkValue(valueStr);
if (!ok) {
QString err = option.errorMsg();
if (!err.endsWith(QLatin1String(".")))
err += QLatin1String(".");
out << err;
return ok;
}
option.setValue(valueStr);
}
m_foundOptions.append(option);
return ok;
}
bool CommandLineParser::parse(const QStringList &args) {
m_foundArgs.clear();
m_foundOptions.clear();
bool ok = true;
Node *actualNode = &m_parseTree;
auto it = ++args.cbegin();
// check version option
QStringList dashedVersion = versionOption.dashedNames();
if (m_withVersion && args.length() > 1 &&
dashedVersion.contains(args.at(1)))
{
if (args.length() == 2) {
printVersion();
m_foundOptions << versionOption;
} else {
out << "Invalid arguments after the version option.";
ok = false;
}
return ok;
}
// check help option
ok = processIfOptionIsHelp(args, it, actualNode);
// process the other args
for (; it != args.cend() && ok; ++it) {
const QString &value = *it;
if (value.startsWith(QLatin1String("-"))) {
ok = processOptions(args, it, actualNode);
} else {
ok = processArgs(args, it, actualNode);
}
}
if (!ok && !m_generalErrorMessage.isEmpty()) {
out << QStringLiteral(" %1\n").arg(m_generalErrorMessage);
}
return ok;
}
CommandOption CommandLineParser::addVersionOption() {
m_withVersion = true;
return versionOption;
}
CommandOption CommandLineParser::addHelpOption() {
m_withHelp = true;
return helpOption;
}
bool CommandLineParser::AddArgument(const CommandArgument &arg,
const CommandArgument &parent)
{
bool res = true;
Node *n = findParent(parent);
if (n == nullptr) {
res = false;
} else {
Node child;
child.argument = arg;
n->subNodes.append(child);
}
return res;
}
bool CommandLineParser::AddOption(const CommandOption &option,
const CommandArgument &parent)
{
bool res = true;
Node *n = findParent(parent);
if (n == nullptr) {
res = false;
} else {
n->options.append(option);
}
return res;
}
bool CommandLineParser::AddOptions(const QList<CommandOption> &options,
const CommandArgument &parent)
{
bool res = true;
for (auto const &option: options) {
if (!AddOption(option, parent)) {
res = false;
break;
}
}
return res;
}
void CommandLineParser::setGeneralErrorMessage(const QString &msg) {
m_generalErrorMessage = msg;
}
void CommandLineParser::setDescription(const QString &description) {
m_description = description;
}
bool CommandLineParser::isSet(const CommandArgument &arg) const {
return m_foundArgs.contains(arg);
}
bool CommandLineParser::isSet(const CommandOption &option) const {
return m_foundOptions.contains(option);
}
QString CommandLineParser::value(const CommandOption &option) const {
QString value = option.value();
for (const CommandOption &fOption: m_foundOptions) {
if (option == fOption) {
value = fOption.value();
break;
}
}
return value;
}
void CommandLineParser::printVersion() {
out << "Flameshot " << qApp->applicationVersion() << "\nCompiled with Qt "
<< static_cast<QString>(QT_VERSION_STR) << "\n";
}
void CommandLineParser::printHelp(QStringList args, const Node *node) {
args.removeLast(); // remove the help, it's always the last
QString helpText;
// add usage info
QString argName = node->argument.name();
if (argName.isEmpty()) { if (argName.isEmpty()) {
argName = qApp->applicationName(); argName = qApp->applicationName();
} }
QString argText = node->subNodes.isEmpty() ? "" : "[arguments]"; out << QStringLiteral("the option '%1' is not a valid option "
helpText += QStringLiteral("Usage: %1 [%2-options] %3\n\n") "for the argument '%2'.")
.arg(args.join(QStringLiteral(" "))) .arg(arg)
.arg(argName).arg(argText); .arg(argName);
// add command options and subarguments ok = false;
QList<CommandArgument> subArgs; return ok;
for (const Node &n: node->subNodes) }
subArgs.append(n.argument); // check presence of values
auto modifiedOptions = node->options; CommandOption option = *optionIt;
if (m_withHelp) bool requiresValue = !(option.valueName().isEmpty());
modifiedOptions << helpOption; if (!requiresValue && equalsPos != -1) {
if (m_withVersion && node == &m_parseTree) { out << QStringLiteral("the option '%1' contains a '=' and it doesn't "
modifiedOptions << versionOption; "require a value.")
} .arg(arg);
helpText += optionsToString(modifiedOptions, subArgs); ok = false;
// print it return ok;
out << helpText; } else if (requiresValue && valueStr.isEmpty()) {
} // find in the next
if (actualIt + 1 != args.cend()) {
CommandLineParser::Node* CommandLineParser::findParent( ++actualIt;
const CommandArgument &parent)
{
if (parent == CommandArgument()) {
return &m_parseTree;
}
//find the parent in the subNodes recursively
Node *res = nullptr;
for (auto i = m_parseTree.subNodes.begin();
i != m_parseTree.subNodes.end(); ++i)
{
res = recursiveParentSearch(parent, *i);
if (res != nullptr) {
break;
}
}
return res;
}
CommandLineParser::Node* CommandLineParser::recursiveParentSearch(
const CommandArgument &parent, Node &node) const
{
Node * res = nullptr;
if (node.argument == parent) {
res = &node;
} else { } else {
for (auto i = node.subNodes.begin(); i != node.subNodes.end(); ++i){ out << QStringLiteral("Expected value after the option '%1'.").arg(arg);
res = recursiveParentSearch(parent, *i); ok = false;
if (res != nullptr) { return ok;
break;
}
}
} }
return res; valueStr = *actualIt;
}
// check the value correctness
if (requiresValue) {
ok = option.checkValue(valueStr);
if (!ok) {
QString err = option.errorMsg();
if (!err.endsWith(QLatin1String(".")))
err += QLatin1String(".");
out << err;
return ok;
}
option.setValue(valueStr);
}
m_foundOptions.append(option);
return ok;
} }
bool CommandLineParser::processIfOptionIsHelp( bool
const QStringList &args, CommandLineParser::parse(const QStringList& args)
QStringList::const_iterator &actualIt,
Node * &actualNode)
{ {
bool ok = true; m_foundArgs.clear();
auto dashedHelpNames = helpOption.dashedNames(); m_foundOptions.clear();
if (m_withHelp && actualIt != args.cend() && bool ok = true;
dashedHelpNames.contains(*actualIt)) Node* actualNode = &m_parseTree;
{ auto it = ++args.cbegin();
if (actualIt+1 == args.cend()) { // check version option
m_foundOptions << helpOption; QStringList dashedVersion = versionOption.dashedNames();
printHelp(args, actualNode); if (m_withVersion && args.length() > 1 &&
actualIt++; dashedVersion.contains(args.at(1))) {
} else { if (args.length() == 2) {
out << "Invalid arguments after the help option."; printVersion();
ok = false; m_foundOptions << versionOption;
} } else {
out << "Invalid arguments after the version option.";
ok = false;
} }
return ok; return ok;
}
// check help option
ok = processIfOptionIsHelp(args, it, actualNode);
// process the other args
for (; it != args.cend() && ok; ++it) {
const QString& value = *it;
if (value.startsWith(QLatin1String("-"))) {
ok = processOptions(args, it, actualNode);
} else {
ok = processArgs(args, it, actualNode);
}
}
if (!ok && !m_generalErrorMessage.isEmpty()) {
out << QStringLiteral(" %1\n").arg(m_generalErrorMessage);
}
return ok;
}
CommandOption
CommandLineParser::addVersionOption()
{
m_withVersion = true;
return versionOption;
}
CommandOption
CommandLineParser::addHelpOption()
{
m_withHelp = true;
return helpOption;
}
bool
CommandLineParser::AddArgument(const CommandArgument& arg,
const CommandArgument& parent)
{
bool res = true;
Node* n = findParent(parent);
if (n == nullptr) {
res = false;
} else {
Node child;
child.argument = arg;
n->subNodes.append(child);
}
return res;
}
bool
CommandLineParser::AddOption(const CommandOption& option,
const CommandArgument& parent)
{
bool res = true;
Node* n = findParent(parent);
if (n == nullptr) {
res = false;
} else {
n->options.append(option);
}
return res;
}
bool
CommandLineParser::AddOptions(const QList<CommandOption>& options,
const CommandArgument& parent)
{
bool res = true;
for (auto const& option : options) {
if (!AddOption(option, parent)) {
res = false;
break;
}
}
return res;
}
void
CommandLineParser::setGeneralErrorMessage(const QString& msg)
{
m_generalErrorMessage = msg;
}
void
CommandLineParser::setDescription(const QString& description)
{
m_description = description;
}
bool
CommandLineParser::isSet(const CommandArgument& arg) const
{
return m_foundArgs.contains(arg);
}
bool
CommandLineParser::isSet(const CommandOption& option) const
{
return m_foundOptions.contains(option);
}
QString
CommandLineParser::value(const CommandOption& option) const
{
QString value = option.value();
for (const CommandOption& fOption : m_foundOptions) {
if (option == fOption) {
value = fOption.value();
break;
}
}
return value;
}
void
CommandLineParser::printVersion()
{
out << "Flameshot " << qApp->applicationVersion() << "\nCompiled with Qt "
<< static_cast<QString>(QT_VERSION_STR) << "\n";
}
void
CommandLineParser::printHelp(QStringList args, const Node* node)
{
args.removeLast(); // remove the help, it's always the last
QString helpText;
// add usage info
QString argName = node->argument.name();
if (argName.isEmpty()) {
argName = qApp->applicationName();
}
QString argText = node->subNodes.isEmpty() ? "" : "[arguments]";
helpText += QStringLiteral("Usage: %1 [%2-options] %3\n\n")
.arg(args.join(QStringLiteral(" ")))
.arg(argName)
.arg(argText);
// add command options and subarguments
QList<CommandArgument> subArgs;
for (const Node& n : node->subNodes)
subArgs.append(n.argument);
auto modifiedOptions = node->options;
if (m_withHelp)
modifiedOptions << helpOption;
if (m_withVersion && node == &m_parseTree) {
modifiedOptions << versionOption;
}
helpText += optionsToString(modifiedOptions, subArgs);
// print it
out << helpText;
}
CommandLineParser::Node*
CommandLineParser::findParent(const CommandArgument& parent)
{
if (parent == CommandArgument()) {
return &m_parseTree;
}
// find the parent in the subNodes recursively
Node* res = nullptr;
for (auto i = m_parseTree.subNodes.begin(); i != m_parseTree.subNodes.end();
++i) {
res = recursiveParentSearch(parent, *i);
if (res != nullptr) {
break;
}
}
return res;
}
CommandLineParser::Node*
CommandLineParser::recursiveParentSearch(const CommandArgument& parent,
Node& node) const
{
Node* res = nullptr;
if (node.argument == parent) {
res = &node;
} else {
for (auto i = node.subNodes.begin(); i != node.subNodes.end(); ++i) {
res = recursiveParentSearch(parent, *i);
if (res != nullptr) {
break;
}
}
}
return res;
}
bool
CommandLineParser::processIfOptionIsHelp(const QStringList& args,
QStringList::const_iterator& actualIt,
Node*& actualNode)
{
bool ok = true;
auto dashedHelpNames = helpOption.dashedNames();
if (m_withHelp && actualIt != args.cend() &&
dashedHelpNames.contains(*actualIt)) {
if (actualIt + 1 == args.cend()) {
m_foundOptions << helpOption;
printHelp(args, actualNode);
actualIt++;
} else {
out << "Invalid arguments after the help option.";
ok = false;
}
}
return ok;
} }

View File

@@ -21,69 +21,72 @@
#include "src/cli/commandoption.h" #include "src/cli/commandoption.h"
#include <QMap> #include <QMap>
class CommandLineParser { class CommandLineParser
{
public: public:
CommandLineParser(); CommandLineParser();
bool parse(const QStringList &args); bool parse(const QStringList& args);
CommandArgument rootArgument() const { return CommandArgument(); } CommandArgument rootArgument() const { return CommandArgument(); }
CommandOption addVersionOption(); CommandOption addVersionOption();
CommandOption addHelpOption(); CommandOption addHelpOption();
bool AddArgument(const CommandArgument &arg, bool AddArgument(const CommandArgument& arg,
const CommandArgument &parent = CommandArgument()); const CommandArgument& parent = CommandArgument());
bool AddOption(const CommandOption &option, bool AddOption(const CommandOption& option,
const CommandArgument &parent = CommandArgument()); const CommandArgument& parent = CommandArgument());
bool AddOptions(const QList<CommandOption> &options, bool AddOptions(const QList<CommandOption>& options,
const CommandArgument &parent = CommandArgument()); const CommandArgument& parent = CommandArgument());
void setGeneralErrorMessage(const QString &msg); void setGeneralErrorMessage(const QString& msg);
void setDescription(const QString &description); void setDescription(const QString& description);
bool isSet(const CommandArgument &arg) const; bool isSet(const CommandArgument& arg) const;
bool isSet(const CommandOption &option) const; bool isSet(const CommandOption& option) const;
QString value(const CommandOption &option) const; QString value(const CommandOption& option) const;
private: private:
bool m_withHelp = false; bool m_withHelp = false;
bool m_withVersion = false; bool m_withVersion = false;
QString m_description; QString m_description;
QString m_generalErrorMessage; QString m_generalErrorMessage;
struct Node { struct Node
explicit Node(const CommandArgument &arg) : argument(arg) {} {
Node() {} explicit Node(const CommandArgument& arg)
bool operator==(const Node &n) const { : argument(arg)
return argument == n.argument && {}
options == n.options && Node() {}
subNodes == n.subNodes; bool operator==(const Node& n) const
} {
CommandArgument argument; return argument == n.argument && options == n.options &&
QList<CommandOption> options; subNodes == n.subNodes;
QList<Node> subNodes; }
}; CommandArgument argument;
QList<CommandOption> options;
QList<Node> subNodes;
};
Node m_parseTree; Node m_parseTree;
QList<CommandOption> m_foundOptions; QList<CommandOption> m_foundOptions;
QList<CommandArgument> m_foundArgs; QList<CommandArgument> m_foundArgs;
// helper functions // helper functions
void printVersion(); void printVersion();
void printHelp(QStringList args, const Node *node); void printHelp(QStringList args, const Node* node);
Node* findParent(const CommandArgument &parent); Node* findParent(const CommandArgument& parent);
Node* recursiveParentSearch(const CommandArgument &parent, Node* recursiveParentSearch(const CommandArgument& parent, Node& node) const;
Node &node) const; bool processIfOptionIsHelp(const QStringList& args,
bool processIfOptionIsHelp(const QStringList &args, QStringList::const_iterator& actualIt,
QStringList::const_iterator &actualIt, Node*& actualNode);
Node * &actualNode); bool processArgs(const QStringList& args,
bool processArgs(const QStringList &args, QStringList::const_iterator& actualIt,
QStringList::const_iterator &actualIt, Node*& actualNode);
Node * &actualNode); bool processOptions(const QStringList& args,
bool processOptions(const QStringList &args, QStringList::const_iterator& actualIt,
QStringList::const_iterator &actualIt, Node* const actualNode);
Node *const actualNode);
}; };

View File

@@ -17,96 +17,124 @@
#include "commandoption.h" #include "commandoption.h"
CommandOption::CommandOption(const QString &name, const QString &description, CommandOption::CommandOption(const QString& name,
const QString &valueName, const QString& description,
const QString &defaultValue) : const QString& valueName,
m_names(name), m_description(description), m_valueName(valueName), const QString& defaultValue)
m_value(defaultValue) : m_names(name)
, m_description(description)
, m_valueName(valueName)
, m_value(defaultValue)
{ {
m_checker = [](QString const&){ return true; }; m_checker = [](QString const&) { return true; };
} }
CommandOption::CommandOption(const QStringList &names, CommandOption::CommandOption(const QStringList& names,
const QString &description, const QString& description,
const QString &valueName, const QString& valueName,
const QString &defaultValue) : const QString& defaultValue)
m_names(names), m_description(description), m_valueName(valueName), : m_names(names)
m_value(defaultValue) , m_description(description)
, m_valueName(valueName)
, m_value(defaultValue)
{ {
m_checker = [](QString const&) -> bool { return true; }; m_checker = [](QString const&) -> bool { return true; };
} }
void CommandOption::setName(const QString &name) { void
m_names = QStringList() << name; CommandOption::setName(const QString& name)
}
void CommandOption::setNames(const QStringList &names) {
m_names = names;
}
QStringList CommandOption::names() const {
return m_names;
}
QStringList CommandOption::dashedNames() const {
QStringList dashedNames;
for (const QString &name: m_names) {
// prepend "-" to single character options, and "--" to the others
QString dashedName = (name.length() == 1) ?
QStringLiteral("-%1").arg(name) :
QStringLiteral("--%1").arg(name);
dashedNames << dashedName;
}
return dashedNames;
}
void CommandOption::setValueName(const QString &name) {
m_valueName = name;
}
QString CommandOption::valueName() const {
return m_valueName;
}
void CommandOption::setValue(const QString &value) {
if (m_valueName.isEmpty()) {
m_valueName = QLatin1String("value");
}
m_value = value;
}
QString CommandOption::value() const {
return m_value;
}
void CommandOption::addChecker(const function<bool (const QString &)> checker,
const QString &errMsg)
{ {
m_checker = checker; m_names = QStringList() << name;
m_errorMsg = errMsg;
} }
bool CommandOption::checkValue(const QString &value) const { void
return m_checker(value); CommandOption::setNames(const QStringList& names)
}
QString CommandOption::description() const
{ {
return m_description; m_names = names;
} }
void CommandOption::setDescription(const QString &description) QStringList
CommandOption::names() const
{ {
m_description = description; return m_names;
} }
QString CommandOption::errorMsg() const { QStringList
return m_errorMsg; CommandOption::dashedNames() const
}
bool CommandOption::operator ==(const CommandOption &option) const
{ {
return m_description == option.m_description QStringList dashedNames;
&& m_names == option.m_names for (const QString& name : m_names) {
&& m_valueName == option.m_valueName; // prepend "-" to single character options, and "--" to the others
QString dashedName = (name.length() == 1)
? QStringLiteral("-%1").arg(name)
: QStringLiteral("--%1").arg(name);
dashedNames << dashedName;
}
return dashedNames;
}
void
CommandOption::setValueName(const QString& name)
{
m_valueName = name;
}
QString
CommandOption::valueName() const
{
return m_valueName;
}
void
CommandOption::setValue(const QString& value)
{
if (m_valueName.isEmpty()) {
m_valueName = QLatin1String("value");
}
m_value = value;
}
QString
CommandOption::value() const
{
return m_value;
}
void
CommandOption::addChecker(const function<bool(const QString&)> checker,
const QString& errMsg)
{
m_checker = checker;
m_errorMsg = errMsg;
}
bool
CommandOption::checkValue(const QString& value) const
{
return m_checker(value);
}
QString
CommandOption::description() const
{
return m_description;
}
void
CommandOption::setDescription(const QString& description)
{
m_description = description;
}
QString
CommandOption::errorMsg() const
{
return m_errorMsg;
}
bool
CommandOption::operator==(const CommandOption& option) const
{
return m_description == option.m_description && m_names == option.m_names &&
m_valueName == option.m_valueName;
} }

View File

@@ -22,43 +22,47 @@
using std::function; using std::function;
class CommandOption { class CommandOption
{
public: public:
CommandOption(const QString &name, const QString &description, CommandOption(const QString& name,
const QString &valueName = QString(), const QString& description,
const QString &defaultValue = QString()); const QString& valueName = QString(),
const QString& defaultValue = QString());
CommandOption(const QStringList &names, const QString &description, CommandOption(const QStringList& names,
const QString &valueName = QString(), const QString& description,
const QString &defaultValue = QString()); const QString& valueName = QString(),
const QString& defaultValue = QString());
void setName(const QString &name); void setName(const QString& name);
void setNames(const QStringList &names); void setNames(const QStringList& names);
QStringList names() const; QStringList names() const;
QStringList dashedNames() const; QStringList dashedNames() const;
void setValueName(const QString &name); void setValueName(const QString& name);
QString valueName() const; QString valueName() const;
void setValue(const QString &value); void setValue(const QString& value);
QString value() const; QString value() const;
void addChecker(const function<bool(QString const&)> checker, const QString &errMsg); void addChecker(const function<bool(QString const&)> checker,
bool checkValue(const QString &value) const; const QString& errMsg);
bool checkValue(const QString& value) const;
QString description() const; QString description() const;
void setDescription(const QString &description); void setDescription(const QString& description);
QString errorMsg() const; QString errorMsg() const;
bool operator==(const CommandOption &option) const; bool operator==(const CommandOption& option) const;
private: private:
QStringList m_names; QStringList m_names;
QString m_description; QString m_description;
QString m_valueName; QString m_valueName;
QString m_value; QString m_value;
function<bool(QString const&)> m_checker; function<bool(QString const&)> m_checker;
QString m_errorMsg; QString m_errorMsg;
}; };

View File

@@ -21,85 +21,97 @@
#include <QListWidgetItem> #include <QListWidgetItem>
#include <algorithm> #include <algorithm>
ButtonListView::ButtonListView(QWidget *parent) : QListWidget(parent) { ButtonListView::ButtonListView(QWidget* parent)
setMouseTracking(true); : QListWidget(parent)
setFlow(QListWidget::TopToBottom); {
initButtonList(); setMouseTracking(true);
updateComponents(); setFlow(QListWidget::TopToBottom);
connect(this, &QListWidget::itemClicked, this, initButtonList();
&ButtonListView::reverseItemCheck); updateComponents();
connect(
this, &QListWidget::itemClicked, this, &ButtonListView::reverseItemCheck);
} }
void ButtonListView::initButtonList() { void
ToolFactory factory; ButtonListView::initButtonList()
auto listTypes = CaptureButton::getIterableButtonTypes(); {
ToolFactory factory;
auto listTypes = CaptureButton::getIterableButtonTypes();
for (const CaptureButton::ButtonType t: listTypes) { for (const CaptureButton::ButtonType t : listTypes) {
CaptureTool *tool = factory.CreateTool(t); CaptureTool* tool = factory.CreateTool(t);
// add element to the local map // add element to the local map
m_buttonTypeByName.insert(tool->name(), t); m_buttonTypeByName.insert(tool->name(), t);
// init the menu option // init the menu option
QListWidgetItem *m_buttonItem = new QListWidgetItem(this); QListWidgetItem* m_buttonItem = new QListWidgetItem(this);
// when the background is lighter than gray, it uses the white icons // when the background is lighter than gray, it uses the white icons
QColor bgColor = this->palette().color(QWidget::backgroundRole()); QColor bgColor = this->palette().color(QWidget::backgroundRole());
m_buttonItem->setIcon(tool->icon(bgColor, false)); m_buttonItem->setIcon(tool->icon(bgColor, false));
m_buttonItem->setFlags(Qt::ItemIsUserCheckable); m_buttonItem->setFlags(Qt::ItemIsUserCheckable);
QColor foregroundColor = this->palette().color(QWidget::foregroundRole()); QColor foregroundColor = this->palette().color(QWidget::foregroundRole());
m_buttonItem->setForeground(foregroundColor); m_buttonItem->setForeground(foregroundColor);
m_buttonItem->setText(tool->name()); m_buttonItem->setText(tool->name());
m_buttonItem->setToolTip(tool->description()); m_buttonItem->setToolTip(tool->description());
tool->deleteLater(); tool->deleteLater();
} }
} }
void ButtonListView::updateActiveButtons(QListWidgetItem *item) { void
CaptureButton::ButtonType bType = m_buttonTypeByName[item->text()]; ButtonListView::updateActiveButtons(QListWidgetItem* item)
if (item->checkState() == Qt::Checked) { {
m_listButtons.append(bType); CaptureButton::ButtonType bType = m_buttonTypeByName[item->text()];
// TODO refactor so we don't need external sorts if (item->checkState() == Qt::Checked) {
using bt = CaptureButton::ButtonType; m_listButtons.append(bType);
std::sort(m_listButtons.begin(), m_listButtons.end(), [](bt a, bt b){ // TODO refactor so we don't need external sorts
return CaptureButton::getPriorityByButton(a) < using bt = CaptureButton::ButtonType;
CaptureButton::getPriorityByButton(b); std::sort(m_listButtons.begin(), m_listButtons.end(), [](bt a, bt b) {
}); return CaptureButton::getPriorityByButton(a) <
CaptureButton::getPriorityByButton(b);
});
} else {
m_listButtons.remove(m_listButtons.indexOf(bType));
}
ConfigHandler().setButtons(m_listButtons);
}
void
ButtonListView::reverseItemCheck(QListWidgetItem* item)
{
if (item->checkState() == Qt::Checked) {
item->setCheckState(Qt::Unchecked);
} else {
item->setCheckState(Qt::Checked);
}
updateActiveButtons(item);
}
void
ButtonListView::selectAll()
{
ConfigHandler().setAllTheButtons();
for (int i = 0; i < this->count(); ++i) {
QListWidgetItem* item = this->item(i);
item->setCheckState(Qt::Checked);
}
}
void
ButtonListView::updateComponents()
{
m_listButtons = ConfigHandler().getButtons();
auto listTypes = CaptureButton::getIterableButtonTypes();
for (int i = 0; i < this->count(); ++i) {
QListWidgetItem* item = this->item(i);
auto elem = static_cast<CaptureButton::ButtonType>(listTypes.at(i));
if (m_listButtons.contains(elem)) {
item->setCheckState(Qt::Checked);
} else { } else {
m_listButtons.remove(m_listButtons.indexOf(bType)); item->setCheckState(Qt::Unchecked);
}
ConfigHandler().setButtons(m_listButtons);
}
void ButtonListView::reverseItemCheck(QListWidgetItem *item){
if (item->checkState() == Qt::Checked) {
item->setCheckState(Qt::Unchecked);
} else {
item->setCheckState(Qt::Checked);
}
updateActiveButtons(item);
}
void ButtonListView::selectAll() {
ConfigHandler().setAllTheButtons();
for(int i = 0; i < this->count(); ++i) {
QListWidgetItem* item = this->item(i);
item->setCheckState(Qt::Checked);
}
}
void ButtonListView::updateComponents() {
m_listButtons = ConfigHandler().getButtons();
auto listTypes = CaptureButton::getIterableButtonTypes();
for(int i = 0; i < this->count(); ++i) {
QListWidgetItem* item = this->item(i);
auto elem = static_cast<CaptureButton::ButtonType>(listTypes.at(i));
if (m_listButtons.contains(elem)) {
item->setCheckState(Qt::Checked);
} else {
item->setCheckState(Qt::Unchecked);
}
} }
}
} }

View File

@@ -20,23 +20,24 @@
#include "src/widgets/capture/capturebutton.h" #include "src/widgets/capture/capturebutton.h"
#include <QListWidget> #include <QListWidget>
class ButtonListView : public QListWidget { class ButtonListView : public QListWidget
{
public: public:
explicit ButtonListView(QWidget *parent= nullptr); explicit ButtonListView(QWidget* parent = nullptr);
public slots: public slots:
void selectAll(); void selectAll();
void updateComponents(); void updateComponents();
private slots: private slots:
void reverseItemCheck(QListWidgetItem *); void reverseItemCheck(QListWidgetItem*);
protected: protected:
void initButtonList(); void initButtonList();
private: private:
QVector<CaptureButton::ButtonType> m_listButtons; QVector<CaptureButton::ButtonType> m_listButtons;
QMap<QString, CaptureButton::ButtonType> m_buttonTypeByName; QMap<QString, CaptureButton::ButtonType> m_buttonTypeByName;
void updateActiveButtons(QListWidgetItem *); void updateActiveButtons(QListWidgetItem*);
}; };

View File

@@ -17,14 +17,18 @@
#include "clickablelabel.h" #include "clickablelabel.h"
ClickableLabel::ClickableLabel(QWidget *parent) : QLabel(parent) { ClickableLabel::ClickableLabel(QWidget* parent)
: QLabel(parent)
{}
ClickableLabel::ClickableLabel(QString s, QWidget* parent)
: QLabel(parent)
{
setText(s);
} }
ClickableLabel::ClickableLabel(QString s, QWidget *parent) : QLabel(parent) { void
setText(s); ClickableLabel::mousePressEvent(QMouseEvent*)
} {
emit clicked();
void ClickableLabel::mousePressEvent(QMouseEvent *) {
emit clicked();
} }

View File

@@ -19,15 +19,16 @@
#include <QLabel> #include <QLabel>
class ClickableLabel : public QLabel { class ClickableLabel : public QLabel
Q_OBJECT {
Q_OBJECT
public: public:
explicit ClickableLabel(QWidget *parent = nullptr); explicit ClickableLabel(QWidget* parent = nullptr);
ClickableLabel(QString s, QWidget *parent = nullptr); ClickableLabel(QString s, QWidget* parent = nullptr);
signals: signals:
void clicked(); void clicked();
private: private:
void mousePressEvent (QMouseEvent *); void mousePressEvent(QMouseEvent*);
}; };

View File

@@ -16,73 +16,81 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "configwindow.h" #include "configwindow.h"
#include "src/utils/colorutils.h"
#include "src/utils/confighandler.h"
#include "src/utils/pathinfo.h"
#include "src/widgets/capture/capturebutton.h"
#include "src/config/geneneralconf.h"
#include "src/config/filenameeditor.h" #include "src/config/filenameeditor.h"
#include "src/config/geneneralconf.h"
#include "src/config/strftimechooserwidget.h" #include "src/config/strftimechooserwidget.h"
#include "src/config/visualseditor.h" #include "src/config/visualseditor.h"
#include "src/utils/colorutils.h"
#include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include <QIcon> #include "src/utils/pathinfo.h"
#include <QVBoxLayout> #include "src/widgets/capture/capturebutton.h"
#include <QLabel>
#include <QKeyEvent>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QIcon>
#include <QKeyEvent>
#include <QLabel>
#include <QVBoxLayout>
// ConfigWindow contains the menus where you can configure the application // ConfigWindow contains the menus where you can configure the application
ConfigWindow::ConfigWindow(QWidget *parent) : QTabWidget(parent) { ConfigWindow::ConfigWindow(QWidget* parent)
setAttribute(Qt::WA_DeleteOnClose); : QTabWidget(parent)
const int size = GlobalValues::buttonBaseSize() * 12; {
setMinimumSize(size, size); setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/app/flameshot.svg")); const int size = GlobalValues::buttonBaseSize() * 12;
setWindowTitle(tr("Configuration")); setMinimumSize(size, size);
setWindowIcon(QIcon(":img/app/flameshot.svg"));
setWindowTitle(tr("Configuration"));
auto changedSlot = [this](QString s){ auto changedSlot = [this](QString s) {
QStringList files = m_configWatcher->files(); QStringList files = m_configWatcher->files();
if (!files.contains(s)) { if (!files.contains(s)) {
this->m_configWatcher->addPath(s); this->m_configWatcher->addPath(s);
}
emit updateChildren();
};
m_configWatcher = new QFileSystemWatcher(this);
m_configWatcher->addPath(ConfigHandler().configFilePath());
connect(m_configWatcher, &QFileSystemWatcher::fileChanged,
this, changedSlot);
QColor background = this->palette().window().color();
bool isDark = ColorUtils::colorIsDark(background);
QString modifier = isDark ? PathInfo::whiteIconPath() :
PathInfo::blackIconPath();
// visuals
m_visuals = new VisualsEditor();
addTab(m_visuals, QIcon(modifier + "graphics.svg"),
tr("Interface"));
// filename
m_filenameEditor = new FileNameEditor();
addTab(m_filenameEditor, QIcon(modifier + "name_edition.svg"),
tr("Filename Editor"));
// general
m_generalConfig = new GeneneralConf();
addTab(m_generalConfig, QIcon(modifier + "config.svg"),
tr("General"));
// connect update sigslots
connect(this, &ConfigWindow::updateChildren,
m_filenameEditor, &FileNameEditor::updateComponents);
connect(this, &ConfigWindow::updateChildren,
m_visuals, &VisualsEditor::updateComponents);
connect(this, &ConfigWindow::updateChildren,
m_generalConfig, &GeneneralConf::updateComponents);
}
void ConfigWindow::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
close();
} }
emit updateChildren();
};
m_configWatcher = new QFileSystemWatcher(this);
m_configWatcher->addPath(ConfigHandler().configFilePath());
connect(m_configWatcher, &QFileSystemWatcher::fileChanged, this, changedSlot);
QColor background = this->palette().window().color();
bool isDark = ColorUtils::colorIsDark(background);
QString modifier =
isDark ? PathInfo::whiteIconPath() : PathInfo::blackIconPath();
// visuals
m_visuals = new VisualsEditor();
addTab(m_visuals, QIcon(modifier + "graphics.svg"), tr("Interface"));
// filename
m_filenameEditor = new FileNameEditor();
addTab(m_filenameEditor,
QIcon(modifier + "name_edition.svg"),
tr("Filename Editor"));
// general
m_generalConfig = new GeneneralConf();
addTab(m_generalConfig, QIcon(modifier + "config.svg"), tr("General"));
// connect update sigslots
connect(this,
&ConfigWindow::updateChildren,
m_filenameEditor,
&FileNameEditor::updateComponents);
connect(this,
&ConfigWindow::updateChildren,
m_visuals,
&VisualsEditor::updateComponents);
connect(this,
&ConfigWindow::updateChildren,
m_generalConfig,
&GeneneralConf::updateComponents);
}
void
ConfigWindow::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Escape) {
close();
}
} }

View File

@@ -24,20 +24,21 @@ class GeneneralConf;
class QFileSystemWatcher; class QFileSystemWatcher;
class VisualsEditor; class VisualsEditor;
class ConfigWindow : public QTabWidget { class ConfigWindow : public QTabWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit ConfigWindow(QWidget *parent = nullptr); explicit ConfigWindow(QWidget* parent = nullptr);
signals: signals:
void updateChildren(); void updateChildren();
protected: protected:
void keyPressEvent(QKeyEvent *); void keyPressEvent(QKeyEvent*);
private: private:
FileNameEditor *m_filenameEditor; FileNameEditor* m_filenameEditor;
GeneneralConf *m_generalConfig; GeneneralConf* m_generalConfig;
VisualsEditor *m_visuals; VisualsEditor* m_visuals;
QFileSystemWatcher *m_configWatcher; QFileSystemWatcher* m_configWatcher;
}; };

View File

@@ -17,34 +17,41 @@
#include "extendedslider.h" #include "extendedslider.h"
ExtendedSlider::ExtendedSlider(QWidget *parent) ExtendedSlider::ExtendedSlider(QWidget* parent)
: QSlider(parent) : QSlider(parent)
{ {
connect(this, &ExtendedSlider::valueChanged, connect(
this, &ExtendedSlider::updateTooltip); this, &ExtendedSlider::valueChanged, this, &ExtendedSlider::updateTooltip);
connect(this, &ExtendedSlider::sliderMoved, connect(this, &ExtendedSlider::sliderMoved, this, &ExtendedSlider::fireTimer);
this, &ExtendedSlider::fireTimer); m_timer.setSingleShot(true);
m_timer.setSingleShot(true); connect(
connect(&m_timer, &QTimer::timeout, &m_timer, &QTimer::timeout, this, &ExtendedSlider::modificationsEnded);
this, &ExtendedSlider::modificationsEnded);
} }
int ExtendedSlider::mappedValue(int min, int max) { int
qreal progress = ExtendedSlider::mappedValue(int min, int max)
((value() - minimum())) / static_cast<qreal>(maximum() - minimum()); {
return min + (max - min) * progress; qreal progress =
((value() - minimum())) / static_cast<qreal>(maximum() - minimum());
return min + (max - min) * progress;
} }
void ExtendedSlider::setMapedValue(int min, int val, int max) { void
qreal progress = ((val - min) + 1) / static_cast<qreal>(max - min); ExtendedSlider::setMapedValue(int min, int val, int max)
int value = minimum() + (maximum() - minimum()) * progress; {
setValue(value); qreal progress = ((val - min) + 1) / static_cast<qreal>(max - min);
int value = minimum() + (maximum() - minimum()) * progress;
setValue(value);
} }
void ExtendedSlider::updateTooltip() { void
setToolTip(QString::number(value())+"%"); ExtendedSlider::updateTooltip()
{
setToolTip(QString::number(value()) + "%");
} }
void ExtendedSlider::fireTimer() { void
m_timer.start(500); ExtendedSlider::fireTimer()
{
m_timer.start(500);
} }

View File

@@ -20,21 +20,22 @@
#include <QSlider> #include <QSlider>
#include <QTimer> #include <QTimer>
class ExtendedSlider : public QSlider { class ExtendedSlider : public QSlider
Q_OBJECT {
Q_OBJECT
public: public:
explicit ExtendedSlider(QWidget *parent = nullptr); explicit ExtendedSlider(QWidget* parent = nullptr);
int mappedValue(int min, int max); int mappedValue(int min, int max);
void setMapedValue(int min, int val, int max); void setMapedValue(int min, int val, int max);
signals: signals:
void modificationsEnded(); void modificationsEnded();
private slots: private slots:
void updateTooltip(); void updateTooltip();
void fireTimer(); void fireTimer();
private: private:
QTimer m_timer; QTimer m_timer;
}; };

View File

@@ -16,100 +16,122 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "filenameeditor.h" #include "filenameeditor.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/confighandler.h"
#include "src/config/strftimechooserwidget.h" #include "src/config/strftimechooserwidget.h"
#include <QVBoxLayout> #include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLineEdit>
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include <QPushButton> #include <QPushButton>
#include <QVBoxLayout>
FileNameEditor::FileNameEditor(QWidget *parent) : QWidget(parent) { FileNameEditor::FileNameEditor(QWidget* parent)
initWidgets(); : QWidget(parent)
initLayout(); {
initWidgets();
initLayout();
} }
void FileNameEditor::initLayout() { void
m_layout = new QVBoxLayout(this); FileNameEditor::initLayout()
auto infoLabel = new QLabel(tr("Edit the name of your captures:"), this); {
infoLabel->setFixedHeight(20); m_layout = new QVBoxLayout(this);
m_layout->addWidget(infoLabel); auto infoLabel = new QLabel(tr("Edit the name of your captures:"), this);
m_layout->addWidget(m_helperButtons); infoLabel->setFixedHeight(20);
m_layout->addWidget(new QLabel(tr("Edit:"))); m_layout->addWidget(infoLabel);
m_layout->addWidget(m_nameEditor); m_layout->addWidget(m_helperButtons);
m_layout->addWidget(new QLabel(tr("Preview:"))); m_layout->addWidget(new QLabel(tr("Edit:")));
m_layout->addWidget(m_outputLabel); m_layout->addWidget(m_nameEditor);
m_layout->addWidget(new QLabel(tr("Preview:")));
m_layout->addWidget(m_outputLabel);
QHBoxLayout *horizLayout = new QHBoxLayout(); QHBoxLayout* horizLayout = new QHBoxLayout();
horizLayout->addWidget(m_saveButton); horizLayout->addWidget(m_saveButton);
horizLayout->addWidget(m_resetButton); horizLayout->addWidget(m_resetButton);
horizLayout->addWidget(m_clearButton); horizLayout->addWidget(m_clearButton);
m_layout->addLayout(horizLayout); m_layout->addLayout(horizLayout);
} }
void FileNameEditor::initWidgets() { void
m_nameHandler = new FileNameHandler(this); FileNameEditor::initWidgets()
{
m_nameHandler = new FileNameHandler(this);
// editor // editor
m_nameEditor = new QLineEdit(this); m_nameEditor = new QLineEdit(this);
m_nameEditor->setMaxLength(FileNameHandler::MAX_CHARACTERS); m_nameEditor->setMaxLength(FileNameHandler::MAX_CHARACTERS);
// preview // preview
m_outputLabel = new QLineEdit(this); m_outputLabel = new QLineEdit(this);
m_outputLabel->setDisabled(true); m_outputLabel->setDisabled(true);
QString foreground = this->palette().windowText().color().name(); QString foreground = this->palette().windowText().color().name();
m_outputLabel->setStyleSheet(QStringLiteral("color: %1").arg(foreground)); m_outputLabel->setStyleSheet(QStringLiteral("color: %1").arg(foreground));
QPalette pal = m_outputLabel->palette(); QPalette pal = m_outputLabel->palette();
QColor color = pal.color(QPalette::Disabled, m_outputLabel->backgroundRole()); QColor color = pal.color(QPalette::Disabled, m_outputLabel->backgroundRole());
pal.setColor(QPalette::Active, m_outputLabel->backgroundRole(), color); pal.setColor(QPalette::Active, m_outputLabel->backgroundRole(), color);
m_outputLabel->setPalette(pal); m_outputLabel->setPalette(pal);
connect(m_nameEditor, &QLineEdit::textChanged, this, connect(m_nameEditor,
&FileNameEditor::showParsedPattern); &QLineEdit::textChanged,
updateComponents(); this,
&FileNameEditor::showParsedPattern);
updateComponents();
// helper buttons // helper buttons
m_helperButtons = new StrftimeChooserWidget(this); m_helperButtons = new StrftimeChooserWidget(this);
connect(m_helperButtons, &StrftimeChooserWidget::variableEmitted, connect(m_helperButtons,
this, &FileNameEditor::addToNameEditor); &StrftimeChooserWidget::variableEmitted,
this,
&FileNameEditor::addToNameEditor);
// save // save
m_saveButton = new QPushButton(tr("Save"), this); m_saveButton = new QPushButton(tr("Save"), this);
connect(m_saveButton, &QPushButton::clicked, this, &FileNameEditor::savePattern); connect(
m_saveButton->setToolTip(tr("Saves the pattern")); m_saveButton, &QPushButton::clicked, this, &FileNameEditor::savePattern);
// reset m_saveButton->setToolTip(tr("Saves the pattern"));
m_resetButton = new QPushButton(tr("Reset"), this); // reset
connect(m_resetButton, &QPushButton::clicked, m_resetButton = new QPushButton(tr("Reset"), this);
this, &FileNameEditor::resetName); connect(
m_resetButton->setToolTip(tr("Restores the saved pattern")); m_resetButton, &QPushButton::clicked, this, &FileNameEditor::resetName);
// clear m_resetButton->setToolTip(tr("Restores the saved pattern"));
m_clearButton = new QPushButton(tr("Clear"), this); // clear
connect(m_clearButton, &QPushButton::clicked, this, m_clearButton = new QPushButton(tr("Clear"), this);
[this](){ m_nameEditor->setText(QString()); connect(m_clearButton, &QPushButton::clicked, this, [this]() {
}); m_nameEditor->setText(QString());
m_clearButton->setToolTip(tr("Deletes the name"));} });
m_clearButton->setToolTip(tr("Deletes the name"));
void FileNameEditor::savePattern() {
QString pattern = m_nameEditor->text();
m_nameHandler->setPattern(pattern);
} }
void FileNameEditor::showParsedPattern(const QString &p) { void
QString output = m_nameHandler->parseFilename(p); FileNameEditor::savePattern()
m_outputLabel->setText(output); {
QString pattern = m_nameEditor->text();
m_nameHandler->setPattern(pattern);
} }
void FileNameEditor::resetName() { void
m_nameEditor->setText(ConfigHandler().filenamePatternValue()); FileNameEditor::showParsedPattern(const QString& p)
{
QString output = m_nameHandler->parseFilename(p);
m_outputLabel->setText(output);
} }
void FileNameEditor::addToNameEditor(QString s) { void
m_nameEditor->setText(m_nameEditor->text() + s); FileNameEditor::resetName()
m_nameEditor->setFocus(); {
m_nameEditor->setText(ConfigHandler().filenamePatternValue());
} }
void FileNameEditor::updateComponents() { void
m_nameEditor->setText(ConfigHandler().filenamePatternValue()); FileNameEditor::addToNameEditor(QString s)
m_outputLabel->setText(m_nameHandler->parsedPattern()); {
m_nameEditor->setText(m_nameEditor->text() + s);
m_nameEditor->setFocus();
}
void
FileNameEditor::updateComponents()
{
m_nameEditor->setText(ConfigHandler().filenamePatternValue());
m_outputLabel->setText(m_nameHandler->parsedPattern());
} }

View File

@@ -17,8 +17,8 @@
#pragma once #pragma once
#include <QWidget>
#include <QPointer> #include <QPointer>
#include <QWidget>
class QVBoxLayout; class QVBoxLayout;
class QLineEdit; class QLineEdit;
@@ -26,30 +26,31 @@ class FileNameHandler;
class QPushButton; class QPushButton;
class StrftimeChooserWidget; class StrftimeChooserWidget;
class FileNameEditor : public QWidget { class FileNameEditor : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit FileNameEditor(QWidget *parent = nullptr); explicit FileNameEditor(QWidget* parent = nullptr);
private: private:
QVBoxLayout *m_layout; QVBoxLayout* m_layout;
QLineEdit *m_outputLabel; QLineEdit* m_outputLabel;
QLineEdit *m_nameEditor; QLineEdit* m_nameEditor;
FileNameHandler *m_nameHandler; FileNameHandler* m_nameHandler;
StrftimeChooserWidget *m_helperButtons; StrftimeChooserWidget* m_helperButtons;
QPushButton *m_saveButton; QPushButton* m_saveButton;
QPushButton *m_resetButton; QPushButton* m_resetButton;
QPushButton *m_clearButton; QPushButton* m_clearButton;
void initLayout(); void initLayout();
void initWidgets(); void initWidgets();
public slots: public slots:
void addToNameEditor(QString s); void addToNameEditor(QString s);
void updateComponents(); void updateComponents();
private slots: private slots:
void savePattern(); void savePattern();
void showParsedPattern(const QString &); void showParsedPattern(const QString&);
void resetName(); void resetName();
}; };

View File

@@ -16,224 +16,269 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "geneneralconf.h" #include "geneneralconf.h"
#include "src/utils/confighandler.h"
#include "src/utils/confighandler.h"
#include "src/core/controller.h" #include "src/core/controller.h"
#include <QVBoxLayout> #include "src/utils/confighandler.h"
#include <QHBoxLayout>
#include <QCheckBox> #include <QCheckBox>
#include <QPushButton>
#include <QMessageBox>
#include <QFileDialog>
#include <QFile> #include <QFile>
#include <QTextCodec> #include <QFileDialog>
#include <QGroupBox> #include <QGroupBox>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QTextCodec>
#include <QVBoxLayout>
GeneneralConf::GeneneralConf(QWidget *parent) : QWidget(parent) { GeneneralConf::GeneneralConf(QWidget* parent)
m_layout = new QVBoxLayout(this); : QWidget(parent)
m_layout->setAlignment(Qt::AlignTop);
initShowHelp();
initShowDesktopNotification();
initShowTrayIcon();
initAutostart();
initCloseAfterCapture();
initCopyAndCloseAfterUpload();
// this has to be at the end
initConfingButtons();
updateComponents();
}
void GeneneralConf::updateComponents() {
ConfigHandler config;
m_helpMessage->setChecked(config.showHelpValue());
m_sysNotifications->setChecked(config.desktopNotificationValue());
m_autostart->setChecked(config.startupLaunchValue());
m_closeAfterCapture->setChecked(config.closeAfterScreenshotValue());
m_copyAndCloseAfterUpload->setChecked(config.copyAndCloseAfterUploadEnabled());
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
m_showTray->setChecked(!config.disabledTrayIconValue());
#endif
}
void GeneneralConf::showHelpChanged(bool checked) {
ConfigHandler().setShowHelp(checked);
}
void GeneneralConf::showDesktopNotificationChanged(bool checked) {
ConfigHandler().setDesktopNotification(checked);
}
void GeneneralConf::showTrayIconChanged(bool checked) {
auto controller = Controller::getInstance();
if (checked) {
controller->enableTrayIcon();
} else {
controller->disableTrayIcon();
}
}
void GeneneralConf::autostartChanged(bool checked) {
ConfigHandler().setStartupLaunch(checked);
}
void GeneneralConf::closeAfterCaptureChanged(bool checked) {
ConfigHandler().setCloseAfterScreenshot(checked);
}
void GeneneralConf::importConfiguration() {
QString fileName = QFileDialog::getOpenFileName(this, tr("Import"));
if (fileName.isEmpty()) {
return;
}
QFile file(fileName);
QTextCodec *codec = QTextCodec::codecForLocale();
if (!file.open(QFile::ReadOnly)) {
QMessageBox::about(this, tr("Error"), tr("Unable to read file."));
return;
}
QString text = codec->toUnicode(file.readAll());
file.close();
QFile config(ConfigHandler().configFilePath());
if (!config.open(QFile::WriteOnly)) {
QMessageBox::about(this, tr("Error"), tr("Unable to write file."));
return;
}
config.write(codec->fromUnicode(text));
config.close();
}
void GeneneralConf::exportFileConfiguration() {
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
QStringLiteral("flameshot.conf"));
// Cancel button
if (fileName.isNull()) {
return;
}
QFile targetFile(fileName);
if (targetFile.exists()) {
targetFile.remove();
}
bool ok = QFile::copy(ConfigHandler().configFilePath(), fileName);
if (!ok) {
QMessageBox::about(this, tr("Error"), tr("Unable to write file."));
}
}
void GeneneralConf::resetConfiguration() {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
this, tr("Confirm Reset"),
tr("Are you sure you want to reset the configuration?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
ConfigHandler().setDefaults();
}
}
void GeneneralConf::initShowHelp() {
m_helpMessage = new QCheckBox(tr("Show help message"), this);
ConfigHandler config;
bool checked = config.showHelpValue();
m_helpMessage->setChecked(checked);
m_helpMessage->setToolTip(tr("Show the help message at the beginning "
"in the capture mode."));
m_layout->addWidget(m_helpMessage);
connect(m_helpMessage, &QCheckBox::clicked, this,
&GeneneralConf::showHelpChanged);
}
void GeneneralConf::initShowDesktopNotification() {
m_sysNotifications =
new QCheckBox(tr("Show desktop notifications"), this);
ConfigHandler config;
bool checked = config.desktopNotificationValue();
m_sysNotifications->setChecked(checked);
m_sysNotifications->setToolTip(tr("Show desktop notifications"));
m_layout->addWidget(m_sysNotifications);
connect(m_sysNotifications, &QCheckBox::clicked, this,
&GeneneralConf::showDesktopNotificationChanged);
}
void GeneneralConf::initShowTrayIcon() {
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
m_showTray = new QCheckBox(tr("Show tray icon"), this);
ConfigHandler config;
bool checked = !config.disabledTrayIconValue();
m_showTray->setChecked(checked);
m_showTray->setToolTip(tr("Show the systemtray icon"));
m_layout->addWidget(m_showTray);
connect(m_showTray, &QCheckBox::stateChanged, this,
&GeneneralConf::showTrayIconChanged);
#endif
}
void GeneneralConf::initConfingButtons() {
QHBoxLayout *buttonLayout = new QHBoxLayout();
m_layout->addStretch();
QGroupBox *box = new QGroupBox(tr("Configuration File"));
box->setFlat(true);
box->setLayout(buttonLayout);
m_layout->addWidget(box);
m_exportButton = new QPushButton(tr("Export"));
buttonLayout->addWidget(m_exportButton);
connect(m_exportButton, &QPushButton::clicked, this,
&GeneneralConf::exportFileConfiguration);
m_importButton = new QPushButton(tr("Import"));
buttonLayout->addWidget(m_importButton);
connect(m_importButton, &QPushButton::clicked, this,
&GeneneralConf::importConfiguration);
m_resetButton = new QPushButton(tr("Reset"));
buttonLayout->addWidget(m_resetButton);
connect(m_resetButton, &QPushButton::clicked, this,
&GeneneralConf::resetConfiguration);
}
void GeneneralConf::initAutostart() {
m_autostart =
new QCheckBox(tr("Launch at startup"), this);
ConfigHandler config;
bool checked = config.startupLaunchValue();
m_autostart->setChecked(checked);
m_autostart->setToolTip(tr("Launch Flameshot"));
m_layout->addWidget(m_autostart);
connect(m_autostart, &QCheckBox::clicked, this,
&GeneneralConf::autostartChanged);
}
void GeneneralConf::initCloseAfterCapture() {
m_closeAfterCapture = new QCheckBox(tr("Close after capture"), this);
ConfigHandler config;
bool checked = config.closeAfterScreenshotValue();
m_closeAfterCapture->setChecked(checked);
m_closeAfterCapture->setToolTip(tr("Close after taking a screenshot"));
m_layout->addWidget(m_closeAfterCapture);
connect(m_closeAfterCapture, &QCheckBox::clicked, this,
&GeneneralConf::closeAfterCaptureChanged);
}
void GeneneralConf::initCopyAndCloseAfterUpload()
{ {
m_copyAndCloseAfterUpload = new QCheckBox(tr("Copy URL after upload"), this); m_layout = new QVBoxLayout(this);
ConfigHandler config; m_layout->setAlignment(Qt::AlignTop);
m_copyAndCloseAfterUpload->setChecked(config.copyAndCloseAfterUploadEnabled()); initShowHelp();
m_copyAndCloseAfterUpload->setToolTip(tr("Copy URL and close window after upload")); initShowDesktopNotification();
m_layout->addWidget(m_copyAndCloseAfterUpload); initShowTrayIcon();
initAutostart();
initCloseAfterCapture();
initCopyAndCloseAfterUpload();
connect(m_copyAndCloseAfterUpload, &QCheckBox::clicked, [](bool checked) { // this has to be at the end
ConfigHandler().setCopyAndCloseAfterUploadEnabled(checked); initConfingButtons();
}); updateComponents();
}
void
GeneneralConf::updateComponents()
{
ConfigHandler config;
m_helpMessage->setChecked(config.showHelpValue());
m_sysNotifications->setChecked(config.desktopNotificationValue());
m_autostart->setChecked(config.startupLaunchValue());
m_closeAfterCapture->setChecked(config.closeAfterScreenshotValue());
m_copyAndCloseAfterUpload->setChecked(
config.copyAndCloseAfterUploadEnabled());
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
m_showTray->setChecked(!config.disabledTrayIconValue());
#endif
}
void
GeneneralConf::showHelpChanged(bool checked)
{
ConfigHandler().setShowHelp(checked);
}
void
GeneneralConf::showDesktopNotificationChanged(bool checked)
{
ConfigHandler().setDesktopNotification(checked);
}
void
GeneneralConf::showTrayIconChanged(bool checked)
{
auto controller = Controller::getInstance();
if (checked) {
controller->enableTrayIcon();
} else {
controller->disableTrayIcon();
}
}
void
GeneneralConf::autostartChanged(bool checked)
{
ConfigHandler().setStartupLaunch(checked);
}
void
GeneneralConf::closeAfterCaptureChanged(bool checked)
{
ConfigHandler().setCloseAfterScreenshot(checked);
}
void
GeneneralConf::importConfiguration()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Import"));
if (fileName.isEmpty()) {
return;
}
QFile file(fileName);
QTextCodec* codec = QTextCodec::codecForLocale();
if (!file.open(QFile::ReadOnly)) {
QMessageBox::about(this, tr("Error"), tr("Unable to read file."));
return;
}
QString text = codec->toUnicode(file.readAll());
file.close();
QFile config(ConfigHandler().configFilePath());
if (!config.open(QFile::WriteOnly)) {
QMessageBox::about(this, tr("Error"), tr("Unable to write file."));
return;
}
config.write(codec->fromUnicode(text));
config.close();
}
void
GeneneralConf::exportFileConfiguration()
{
QString fileName = QFileDialog::getSaveFileName(
this, tr("Save File"), QStringLiteral("flameshot.conf"));
// Cancel button
if (fileName.isNull()) {
return;
}
QFile targetFile(fileName);
if (targetFile.exists()) {
targetFile.remove();
}
bool ok = QFile::copy(ConfigHandler().configFilePath(), fileName);
if (!ok) {
QMessageBox::about(this, tr("Error"), tr("Unable to write file."));
}
}
void
GeneneralConf::resetConfiguration()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
this,
tr("Confirm Reset"),
tr("Are you sure you want to reset the configuration?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
ConfigHandler().setDefaults();
}
}
void
GeneneralConf::initShowHelp()
{
m_helpMessage = new QCheckBox(tr("Show help message"), this);
ConfigHandler config;
bool checked = config.showHelpValue();
m_helpMessage->setChecked(checked);
m_helpMessage->setToolTip(tr("Show the help message at the beginning "
"in the capture mode."));
m_layout->addWidget(m_helpMessage);
connect(
m_helpMessage, &QCheckBox::clicked, this, &GeneneralConf::showHelpChanged);
}
void
GeneneralConf::initShowDesktopNotification()
{
m_sysNotifications = new QCheckBox(tr("Show desktop notifications"), this);
ConfigHandler config;
bool checked = config.desktopNotificationValue();
m_sysNotifications->setChecked(checked);
m_sysNotifications->setToolTip(tr("Show desktop notifications"));
m_layout->addWidget(m_sysNotifications);
connect(m_sysNotifications,
&QCheckBox::clicked,
this,
&GeneneralConf::showDesktopNotificationChanged);
}
void
GeneneralConf::initShowTrayIcon()
{
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
m_showTray = new QCheckBox(tr("Show tray icon"), this);
ConfigHandler config;
bool checked = !config.disabledTrayIconValue();
m_showTray->setChecked(checked);
m_showTray->setToolTip(tr("Show the systemtray icon"));
m_layout->addWidget(m_showTray);
connect(m_showTray,
&QCheckBox::stateChanged,
this,
&GeneneralConf::showTrayIconChanged);
#endif
}
void
GeneneralConf::initConfingButtons()
{
QHBoxLayout* buttonLayout = new QHBoxLayout();
m_layout->addStretch();
QGroupBox* box = new QGroupBox(tr("Configuration File"));
box->setFlat(true);
box->setLayout(buttonLayout);
m_layout->addWidget(box);
m_exportButton = new QPushButton(tr("Export"));
buttonLayout->addWidget(m_exportButton);
connect(m_exportButton,
&QPushButton::clicked,
this,
&GeneneralConf::exportFileConfiguration);
m_importButton = new QPushButton(tr("Import"));
buttonLayout->addWidget(m_importButton);
connect(m_importButton,
&QPushButton::clicked,
this,
&GeneneralConf::importConfiguration);
m_resetButton = new QPushButton(tr("Reset"));
buttonLayout->addWidget(m_resetButton);
connect(m_resetButton,
&QPushButton::clicked,
this,
&GeneneralConf::resetConfiguration);
}
void
GeneneralConf::initAutostart()
{
m_autostart = new QCheckBox(tr("Launch at startup"), this);
ConfigHandler config;
bool checked = config.startupLaunchValue();
m_autostart->setChecked(checked);
m_autostart->setToolTip(tr("Launch Flameshot"));
m_layout->addWidget(m_autostart);
connect(
m_autostart, &QCheckBox::clicked, this, &GeneneralConf::autostartChanged);
}
void
GeneneralConf::initCloseAfterCapture()
{
m_closeAfterCapture = new QCheckBox(tr("Close after capture"), this);
ConfigHandler config;
bool checked = config.closeAfterScreenshotValue();
m_closeAfterCapture->setChecked(checked);
m_closeAfterCapture->setToolTip(tr("Close after taking a screenshot"));
m_layout->addWidget(m_closeAfterCapture);
connect(m_closeAfterCapture,
&QCheckBox::clicked,
this,
&GeneneralConf::closeAfterCaptureChanged);
}
void
GeneneralConf::initCopyAndCloseAfterUpload()
{
m_copyAndCloseAfterUpload = new QCheckBox(tr("Copy URL after upload"), this);
ConfigHandler config;
m_copyAndCloseAfterUpload->setChecked(
config.copyAndCloseAfterUploadEnabled());
m_copyAndCloseAfterUpload->setToolTip(
tr("Copy URL and close window after upload"));
m_layout->addWidget(m_copyAndCloseAfterUpload);
connect(m_copyAndCloseAfterUpload, &QCheckBox::clicked, [](bool checked) {
ConfigHandler().setCopyAndCloseAfterUploadEnabled(checked);
});
} }

View File

@@ -23,41 +23,42 @@ class QVBoxLayout;
class QCheckBox; class QCheckBox;
class QPushButton; class QPushButton;
class GeneneralConf : public QWidget { class GeneneralConf : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit GeneneralConf(QWidget *parent = nullptr); explicit GeneneralConf(QWidget* parent = nullptr);
public slots: public slots:
void updateComponents(); void updateComponents();
private slots: private slots:
void showHelpChanged(bool checked); void showHelpChanged(bool checked);
void showDesktopNotificationChanged(bool checked); void showDesktopNotificationChanged(bool checked);
void showTrayIconChanged(bool checked); void showTrayIconChanged(bool checked);
void autostartChanged(bool checked); void autostartChanged(bool checked);
void closeAfterCaptureChanged(bool checked); void closeAfterCaptureChanged(bool checked);
void importConfiguration(); void importConfiguration();
void exportFileConfiguration(); void exportFileConfiguration();
void resetConfiguration(); void resetConfiguration();
private: private:
QVBoxLayout *m_layout; QVBoxLayout* m_layout;
QCheckBox *m_sysNotifications; QCheckBox* m_sysNotifications;
QCheckBox *m_showTray; QCheckBox* m_showTray;
QCheckBox *m_helpMessage; QCheckBox* m_helpMessage;
QCheckBox *m_autostart; QCheckBox* m_autostart;
QCheckBox *m_closeAfterCapture; QCheckBox* m_closeAfterCapture;
QCheckBox *m_copyAndCloseAfterUpload; QCheckBox* m_copyAndCloseAfterUpload;
QPushButton *m_importButton; QPushButton* m_importButton;
QPushButton *m_exportButton; QPushButton* m_exportButton;
QPushButton *m_resetButton; QPushButton* m_resetButton;
void initShowHelp(); void initShowHelp();
void initShowDesktopNotification(); void initShowDesktopNotification();
void initShowTrayIcon(); void initShowTrayIcon();
void initConfingButtons(); void initConfingButtons();
void initAutostart(); void initAutostart();
void initCloseAfterCapture(); void initCloseAfterCapture();
void initCopyAndCloseAfterUpload(); void initCopyAndCloseAfterUpload();
}; };

View File

@@ -16,53 +16,56 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "strftimechooserwidget.h" #include "strftimechooserwidget.h"
#include <QMap>
#include <QGridLayout> #include <QGridLayout>
#include <QMap>
#include <QPushButton> #include <QPushButton>
StrftimeChooserWidget::StrftimeChooserWidget(QWidget *parent) : QWidget(parent) { StrftimeChooserWidget::StrftimeChooserWidget(QWidget* parent)
QGridLayout *layout = new QGridLayout(this); : QWidget(parent)
auto k = m_buttonData.keys(); {
int middle = k.length()/2; QGridLayout* layout = new QGridLayout(this);
// add the buttons in 2 columns (they need to be even) auto k = m_buttonData.keys();
for (int i = 0; i < 2; i++) { int middle = k.length() / 2;
for (int j = 0; j < middle; j++) { // add the buttons in 2 columns (they need to be even)
QString key = k.last(); for (int i = 0; i < 2; i++) {
k.pop_back(); for (int j = 0; j < middle; j++) {
QString variable = m_buttonData.value(key); QString key = k.last();
QPushButton *button = new QPushButton(this); k.pop_back();
button->setText(tr(key.toStdString().data())); QString variable = m_buttonData.value(key);
button->setToolTip(variable); QPushButton* button = new QPushButton(this);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); button->setText(tr(key.toStdString().data()));
button->setMinimumHeight(25); button->setToolTip(variable);
layout->addWidget(button, j, i); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(button, &QPushButton::clicked, button->setMinimumHeight(25);
this, [variable, this](){emit variableEmitted(variable);}); layout->addWidget(button, j, i);
} connect(button, &QPushButton::clicked, this, [variable, this]() {
emit variableEmitted(variable);
});
} }
setLayout(layout); }
setLayout(layout);
} }
QMap<QString, QString> StrftimeChooserWidget::m_buttonData { QMap<QString, QString> StrftimeChooserWidget::m_buttonData{
{ QT_TR_NOOP("Century (00-99)"), "%C"}, { QT_TR_NOOP("Century (00-99)"), "%C" },
{ QT_TR_NOOP("Year (00-99)"), "%y"}, { QT_TR_NOOP("Year (00-99)"), "%y" },
{ QT_TR_NOOP("Year (2000)"), "%Y"}, { QT_TR_NOOP("Year (2000)"), "%Y" },
{ QT_TR_NOOP("Month Name (jan)"), "%b"}, { QT_TR_NOOP("Month Name (jan)"), "%b" },
{ QT_TR_NOOP("Month Name (january)"), "%B"}, { QT_TR_NOOP("Month Name (january)"), "%B" },
{ QT_TR_NOOP("Month (01-12)"), "%m"}, { QT_TR_NOOP("Month (01-12)"), "%m" },
{ QT_TR_NOOP("Week Day (1-7)"), "%u"}, { QT_TR_NOOP("Week Day (1-7)"), "%u" },
{ QT_TR_NOOP("Week (01-53)"), "%V"}, { QT_TR_NOOP("Week (01-53)"), "%V" },
{ QT_TR_NOOP("Day Name (mon)"), "%a"}, { QT_TR_NOOP("Day Name (mon)"), "%a" },
{ QT_TR_NOOP("Day Name (monday)"), "%A"}, { QT_TR_NOOP("Day Name (monday)"), "%A" },
{ QT_TR_NOOP("Day (01-31)"), "%d"}, { QT_TR_NOOP("Day (01-31)"), "%d" },
{ QT_TR_NOOP("Day of Month (1-31)"), "%e"}, { QT_TR_NOOP("Day of Month (1-31)"), "%e" },
{ QT_TR_NOOP("Day (001-366)"), "%j"}, { QT_TR_NOOP("Day (001-366)"), "%j" },
{ QT_TR_NOOP("Time (%H-%M-%S)"), "%T"}, { QT_TR_NOOP("Time (%H-%M-%S)"), "%T" },
{ QT_TR_NOOP("Time (%H-%M)"), "%R"}, { QT_TR_NOOP("Time (%H-%M)"), "%R" },
{ QT_TR_NOOP("Hour (00-23)"), "%H"}, { QT_TR_NOOP("Hour (00-23)"), "%H" },
{ QT_TR_NOOP("Hour (01-12)"), "%I"}, { QT_TR_NOOP("Hour (01-12)"), "%I" },
{ QT_TR_NOOP("Minute (00-59)"), "%M"}, { QT_TR_NOOP("Minute (00-59)"), "%M" },
{ QT_TR_NOOP("Second (00-59)"), "%S"}, { QT_TR_NOOP("Second (00-59)"), "%S" },
{ QT_TR_NOOP("Full Date (%m/%d/%y)"), "%D"}, { QT_TR_NOOP("Full Date (%m/%d/%y)"), "%D" },
{ QT_TR_NOOP("Full Date (%Y-%m-%d)"), "%F"}, { QT_TR_NOOP("Full Date (%Y-%m-%d)"), "%F" },
}; };

View File

@@ -19,14 +19,15 @@
#include <QWidget> #include <QWidget>
class StrftimeChooserWidget : public QWidget { class StrftimeChooserWidget : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit StrftimeChooserWidget(QWidget *parent = nullptr); explicit StrftimeChooserWidget(QWidget* parent = nullptr);
signals: signals:
void variableEmitted(const QString &); void variableEmitted(const QString&);
private: private:
static QMap<QString, QString> m_buttonData; static QMap<QString, QString> m_buttonData;
}; };

View File

@@ -15,151 +15,176 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "src/utils/confighandler.h"
#include "uicoloreditor.h" #include "uicoloreditor.h"
#include "clickablelabel.h" #include "clickablelabel.h"
#include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include <QHBoxLayout>
#include <QApplication> #include <QApplication>
#include <QVBoxLayout>
#include <QComboBox> #include <QComboBox>
#include <QHBoxLayout>
#include <QMap> #include <QMap>
#include <QSpacerItem> #include <QSpacerItem>
#include <QVBoxLayout>
UIcolorEditor::UIcolorEditor(QWidget *parent) : QGroupBox(parent) { UIcolorEditor::UIcolorEditor(QWidget* parent)
setTitle(tr("UI Color Editor")); : QGroupBox(parent)
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); {
m_hLayout = new QHBoxLayout; setTitle(tr("UI Color Editor"));
m_vLayout = new QVBoxLayout; setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_hLayout = new QHBoxLayout;
m_vLayout = new QVBoxLayout;
const int space = QApplication::fontMetrics().lineSpacing(); const int space = QApplication::fontMetrics().lineSpacing();
m_hLayout->addItem(new QSpacerItem(space, space, QSizePolicy::Expanding)); m_hLayout->addItem(new QSpacerItem(space, space, QSizePolicy::Expanding));
m_vLayout->setAlignment(Qt::AlignVCenter); m_vLayout->setAlignment(Qt::AlignVCenter);
initButtons(); initButtons();
initColorWheel(); initColorWheel();
m_vLayout->addSpacing(space); m_vLayout->addSpacing(space);
m_hLayout->addLayout(m_vLayout); m_hLayout->addLayout(m_vLayout);
m_hLayout->addItem(new QSpacerItem(space, space, QSizePolicy::Expanding)); m_hLayout->addItem(new QSpacerItem(space, space, QSizePolicy::Expanding));
setLayout(m_hLayout); setLayout(m_hLayout);
updateComponents(); updateComponents();
} }
void UIcolorEditor::updateComponents() { void
ConfigHandler config; UIcolorEditor::updateComponents()
m_uiColor = config.uiMainColorValue(); {
m_contrastColor = config.uiContrastColorValue(); ConfigHandler config;
m_buttonContrast->setColor(m_contrastColor); m_uiColor = config.uiMainColorValue();
m_buttonMainColor->setColor(m_uiColor); m_contrastColor = config.uiContrastColorValue();
if (m_lastButtonPressed == m_buttonMainColor) { m_buttonContrast->setColor(m_contrastColor);
m_colorWheel->setColor(m_uiColor); m_buttonMainColor->setColor(m_uiColor);
} else { if (m_lastButtonPressed == m_buttonMainColor) {
m_colorWheel->setColor(m_contrastColor); m_colorWheel->setColor(m_uiColor);
} } else {
m_colorWheel->setColor(m_contrastColor);
}
} }
// updateUIcolor updates the appearance of the buttons // updateUIcolor updates the appearance of the buttons
void UIcolorEditor::updateUIcolor() { void
ConfigHandler config; UIcolorEditor::updateUIcolor()
if (m_lastButtonPressed == m_buttonMainColor) { {
config.setUIMainColor(m_uiColor); ConfigHandler config;
} else { if (m_lastButtonPressed == m_buttonMainColor) {
config.setUIContrastColor(m_contrastColor); config.setUIMainColor(m_uiColor);
} } else {
config.setUIContrastColor(m_contrastColor);
}
} }
// updateLocalColor updates the local button // updateLocalColor updates the local button
void UIcolorEditor::updateLocalColor(const QColor c) { void
if (m_lastButtonPressed == m_buttonMainColor) { UIcolorEditor::updateLocalColor(const QColor c)
m_uiColor = c; {
} else { if (m_lastButtonPressed == m_buttonMainColor) {
m_contrastColor = c; m_uiColor = c;
} } else {
m_lastButtonPressed->setColor(c); m_contrastColor = c;
}
m_lastButtonPressed->setColor(c);
} }
void UIcolorEditor::initColorWheel() { void
m_colorWheel = new color_widgets::ColorWheel(this); UIcolorEditor::initColorWheel()
connect(m_colorWheel, &color_widgets::ColorWheel::mouseReleaseOnColor, this, {
&UIcolorEditor::updateUIcolor); m_colorWheel = new color_widgets::ColorWheel(this);
connect(m_colorWheel, &color_widgets::ColorWheel::colorChanged, this, connect(m_colorWheel,
&UIcolorEditor::updateLocalColor); &color_widgets::ColorWheel::mouseReleaseOnColor,
this,
&UIcolorEditor::updateUIcolor);
connect(m_colorWheel,
&color_widgets::ColorWheel::colorChanged,
this,
&UIcolorEditor::updateLocalColor);
const int size = GlobalValues::buttonBaseSize() * 3; const int size = GlobalValues::buttonBaseSize() * 3;
m_colorWheel->setMinimumSize(size, size); m_colorWheel->setMinimumSize(size, size);
m_colorWheel->setMaximumSize(size*2, size*2); m_colorWheel->setMaximumSize(size * 2, size * 2);
m_colorWheel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_colorWheel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_colorWheel->setToolTip(tr("Change the color moving the selectors and see" m_colorWheel->setToolTip(tr("Change the color moving the selectors and see"
" the changes in the preview buttons.")); " the changes in the preview buttons."));
m_hLayout->addWidget(m_colorWheel); m_hLayout->addWidget(m_colorWheel);
} }
void UIcolorEditor::initButtons() { void
const int extraSize = GlobalValues::buttonBaseSize() / 3; UIcolorEditor::initButtons()
int frameSize = GlobalValues::buttonBaseSize() + extraSize; {
const int extraSize = GlobalValues::buttonBaseSize() / 3;
int frameSize = GlobalValues::buttonBaseSize() + extraSize;
m_vLayout->addWidget(new QLabel(tr("Select a Button to modify it"), this)); m_vLayout->addWidget(new QLabel(tr("Select a Button to modify it"), this));
QGroupBox *frame = new QGroupBox(); QGroupBox* frame = new QGroupBox();
frame->setFixedSize(frameSize, frameSize); frame->setFixedSize(frameSize, frameSize);
m_buttonMainColor = new CaptureButton(m_buttonIconType, frame); m_buttonMainColor = new CaptureButton(m_buttonIconType, frame);
m_buttonMainColor->move(m_buttonMainColor->x() + extraSize/2, m_buttonMainColor->y() + extraSize/2); m_buttonMainColor->move(m_buttonMainColor->x() + extraSize / 2,
QHBoxLayout *h1 = new QHBoxLayout(); m_buttonMainColor->y() + extraSize / 2);
h1->addWidget(frame); QHBoxLayout* h1 = new QHBoxLayout();
m_labelMain = new ClickableLabel(tr("Main Color"), this); h1->addWidget(frame);
h1->addWidget(m_labelMain); m_labelMain = new ClickableLabel(tr("Main Color"), this);
m_vLayout->addLayout(h1); h1->addWidget(m_labelMain);
m_vLayout->addLayout(h1);
m_buttonMainColor->setToolTip(tr("Click on this button to set the edition" m_buttonMainColor->setToolTip(tr("Click on this button to set the edition"
" mode of the main color.")); " mode of the main color."));
QGroupBox *frame2 = new QGroupBox(); QGroupBox* frame2 = new QGroupBox();
m_buttonContrast = new CaptureButton(m_buttonIconType, frame2); m_buttonContrast = new CaptureButton(m_buttonIconType, frame2);
m_buttonContrast->move(m_buttonContrast->x() + extraSize/2, m_buttonContrast->move(m_buttonContrast->x() + extraSize / 2,
m_buttonContrast->y() + extraSize/2); m_buttonContrast->y() + extraSize / 2);
QHBoxLayout *h2 = new QHBoxLayout(); QHBoxLayout* h2 = new QHBoxLayout();
h2->addWidget(frame2); h2->addWidget(frame2);
frame2->setFixedSize(frameSize, frameSize); frame2->setFixedSize(frameSize, frameSize);
m_labelContrast = new ClickableLabel(tr("Contrast Color"), this); m_labelContrast = new ClickableLabel(tr("Contrast Color"), this);
m_labelContrast->setStyleSheet(QStringLiteral("color : gray")); m_labelContrast->setStyleSheet(QStringLiteral("color : gray"));
h2->addWidget(m_labelContrast); h2->addWidget(m_labelContrast);
m_vLayout->addLayout(h2); m_vLayout->addLayout(h2);
m_buttonContrast->setToolTip(tr("Click on this button to set the edition" m_buttonContrast->setToolTip(tr("Click on this button to set the edition"
" mode of the contrast color.")); " mode of the contrast color."));
connect(m_buttonMainColor, &CaptureButton::pressedButton, connect(m_buttonMainColor,
this, &UIcolorEditor::changeLastButton); &CaptureButton::pressedButton,
connect(m_buttonContrast, &CaptureButton::pressedButton, this,
this, &UIcolorEditor::changeLastButton); &UIcolorEditor::changeLastButton);
// clicking the labels changes the button too connect(m_buttonContrast,
connect(m_labelMain, &ClickableLabel::clicked, &CaptureButton::pressedButton,
this, [this]{ changeLastButton(m_buttonMainColor); }); this,
connect(m_labelContrast, &ClickableLabel::clicked, &UIcolorEditor::changeLastButton);
this, [this]{ changeLastButton(m_buttonContrast); }); // clicking the labels changes the button too
m_lastButtonPressed = m_buttonMainColor; connect(m_labelMain, &ClickableLabel::clicked, this, [this] {
changeLastButton(m_buttonMainColor);
});
connect(m_labelContrast, &ClickableLabel::clicked, this, [this] {
changeLastButton(m_buttonContrast);
});
m_lastButtonPressed = m_buttonMainColor;
} }
// visual update for the selected button // visual update for the selected button
void UIcolorEditor::changeLastButton(CaptureButton *b) { void
if (m_lastButtonPressed != b) { UIcolorEditor::changeLastButton(CaptureButton* b)
m_lastButtonPressed = b; {
if (m_lastButtonPressed != b) {
m_lastButtonPressed = b;
QString offStyle(QStringLiteral("QLabel { color : gray; }")); QString offStyle(QStringLiteral("QLabel { color : gray; }"));
if (b == m_buttonMainColor) { if (b == m_buttonMainColor) {
m_colorWheel->setColor(m_uiColor); m_colorWheel->setColor(m_uiColor);
m_labelContrast->setStyleSheet(offStyle); m_labelContrast->setStyleSheet(offStyle);
m_labelMain->setStyleSheet(styleSheet()); m_labelMain->setStyleSheet(styleSheet());
} else { } else {
m_colorWheel->setColor(m_contrastColor); m_colorWheel->setColor(m_contrastColor);
m_labelContrast->setStyleSheet(styleSheet()); m_labelContrast->setStyleSheet(styleSheet());
m_labelMain->setStyleSheet(offStyle); m_labelMain->setStyleSheet(offStyle);
}
b->setIcon(b->icon());
} }
b->setIcon(b->icon());
}
} }

View File

@@ -26,33 +26,35 @@ class QHBoxLayout;
class CaptureButton; class CaptureButton;
class ClickableLabel; class ClickableLabel;
class UIcolorEditor : public QGroupBox { class UIcolorEditor : public QGroupBox
Q_OBJECT {
Q_OBJECT
public: public:
explicit UIcolorEditor(QWidget *parent = nullptr); explicit UIcolorEditor(QWidget* parent = nullptr);
public slots: public slots:
void updateComponents(); void updateComponents();
private slots: private slots:
void updateUIcolor(); void updateUIcolor();
void updateLocalColor(const QColor); void updateLocalColor(const QColor);
void changeLastButton(CaptureButton *); void changeLastButton(CaptureButton*);
private: private:
QColor m_uiColor, m_contrastColor; QColor m_uiColor, m_contrastColor;
CaptureButton *m_buttonMainColor; CaptureButton* m_buttonMainColor;
ClickableLabel *m_labelMain; ClickableLabel* m_labelMain;
CaptureButton *m_buttonContrast; CaptureButton* m_buttonContrast;
ClickableLabel *m_labelContrast; ClickableLabel* m_labelContrast;
CaptureButton *m_lastButtonPressed; CaptureButton* m_lastButtonPressed;
color_widgets::ColorWheel *m_colorWheel; color_widgets::ColorWheel* m_colorWheel;
static const CaptureButton::ButtonType m_buttonIconType = CaptureButton::TYPE_CIRCLE; static const CaptureButton::ButtonType m_buttonIconType =
CaptureButton::TYPE_CIRCLE;
QHBoxLayout *m_hLayout; QHBoxLayout* m_hLayout;
QVBoxLayout *m_vLayout; QVBoxLayout* m_vLayout;
void initColorWheel(); void initColorWheel();
void initButtons(); void initButtons();
}; };

View File

@@ -17,71 +17,85 @@
#include "visualseditor.h" #include "visualseditor.h"
#include "src/config/buttonlistview.h" #include "src/config/buttonlistview.h"
#include "src/config/extendedslider.h"
#include "src/config/uicoloreditor.h" #include "src/config/uicoloreditor.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/config/extendedslider.h" #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout>
VisualsEditor::VisualsEditor(QWidget *parent) : QWidget(parent) { VisualsEditor::VisualsEditor(QWidget* parent)
m_layout= new QVBoxLayout(); : QWidget(parent)
setLayout(m_layout); {
initWidgets(); m_layout = new QVBoxLayout();
setLayout(m_layout);
initWidgets();
} }
void VisualsEditor::updateComponents() { void
m_buttonList->updateComponents(); VisualsEditor::updateComponents()
m_colorEditor->updateComponents(); {
int opacity = ConfigHandler().contrastOpacityValue(); m_buttonList->updateComponents();
m_opacitySlider->setMapedValue(0, opacity, 255); m_colorEditor->updateComponents();
int opacity = ConfigHandler().contrastOpacityValue();
m_opacitySlider->setMapedValue(0, opacity, 255);
} }
void VisualsEditor::initOpacitySlider() { void
m_opacitySlider = new ExtendedSlider(); VisualsEditor::initOpacitySlider()
m_opacitySlider->setFocusPolicy(Qt::NoFocus); {
m_opacitySlider->setOrientation(Qt::Horizontal); m_opacitySlider = new ExtendedSlider();
m_opacitySlider->setRange(0, 100); m_opacitySlider->setFocusPolicy(Qt::NoFocus);
connect(m_opacitySlider, &ExtendedSlider::modificationsEnded, m_opacitySlider->setOrientation(Qt::Horizontal);
this, &VisualsEditor::saveOpacity); m_opacitySlider->setRange(0, 100);
QHBoxLayout *localLayout = new QHBoxLayout(); connect(m_opacitySlider,
localLayout->addWidget(new QLabel(QStringLiteral("0%"))); &ExtendedSlider::modificationsEnded,
localLayout->addWidget(m_opacitySlider); this,
localLayout->addWidget(new QLabel(QStringLiteral("100%"))); &VisualsEditor::saveOpacity);
QHBoxLayout* localLayout = new QHBoxLayout();
localLayout->addWidget(new QLabel(QStringLiteral("0%")));
localLayout->addWidget(m_opacitySlider);
localLayout->addWidget(new QLabel(QStringLiteral("100%")));
QLabel *label = new QLabel(); QLabel* label = new QLabel();
QString labelMsg = tr("Opacity of area outside selection:") + " %1%"; QString labelMsg = tr("Opacity of area outside selection:") + " %1%";
connect(m_opacitySlider, &ExtendedSlider::valueChanged, connect(m_opacitySlider,
this, [labelMsg, label](int val){ &ExtendedSlider::valueChanged,
label->setText(labelMsg.arg(val)); this,
}); [labelMsg, label](int val) { label->setText(labelMsg.arg(val)); });
m_layout->addWidget(label); m_layout->addWidget(label);
m_layout->addLayout(localLayout); m_layout->addLayout(localLayout);
int opacity = ConfigHandler().contrastOpacityValue(); int opacity = ConfigHandler().contrastOpacityValue();
m_opacitySlider->setMapedValue(0, opacity, 255); m_opacitySlider->setMapedValue(0, opacity, 255);
} }
void VisualsEditor::saveOpacity() { void
int value = m_opacitySlider->mappedValue(0, 255); VisualsEditor::saveOpacity()
ConfigHandler().setContrastOpacity(value); {
int value = m_opacitySlider->mappedValue(0, 255);
ConfigHandler().setContrastOpacity(value);
} }
void VisualsEditor::initWidgets() { void
m_colorEditor = new UIcolorEditor(); VisualsEditor::initWidgets()
m_layout->addWidget(m_colorEditor); {
m_colorEditor = new UIcolorEditor();
m_layout->addWidget(m_colorEditor);
initOpacitySlider(); initOpacitySlider();
auto boxButtons = new QGroupBox(); auto boxButtons = new QGroupBox();
boxButtons->setTitle(tr("Button Selection")); boxButtons->setTitle(tr("Button Selection"));
auto listLayout = new QVBoxLayout(boxButtons); auto listLayout = new QVBoxLayout(boxButtons);
m_buttonList = new ButtonListView(); m_buttonList = new ButtonListView();
m_layout->addWidget(boxButtons); m_layout->addWidget(boxButtons);
listLayout->addWidget(m_buttonList); listLayout->addWidget(m_buttonList);
QPushButton* setAllButtons = new QPushButton(tr("Select All")); QPushButton* setAllButtons = new QPushButton(tr("Select All"));
connect(setAllButtons, &QPushButton::clicked, connect(setAllButtons,
m_buttonList, &ButtonListView::selectAll); &QPushButton::clicked,
listLayout->addWidget(setAllButtons); m_buttonList,
&ButtonListView::selectAll);
listLayout->addWidget(setAllButtons);
} }

View File

@@ -24,23 +24,24 @@ class QVBoxLayout;
class ButtonListView; class ButtonListView;
class UIcolorEditor; class UIcolorEditor;
class VisualsEditor : public QWidget { class VisualsEditor : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit VisualsEditor(QWidget *parent = nullptr); explicit VisualsEditor(QWidget* parent = nullptr);
public slots: public slots:
void updateComponents(); void updateComponents();
private slots: private slots:
void saveOpacity(); void saveOpacity();
private: private:
QVBoxLayout *m_layout; QVBoxLayout* m_layout;
ButtonListView *m_buttonList; ButtonListView* m_buttonList;
UIcolorEditor *m_colorEditor; UIcolorEditor* m_colorEditor;
ExtendedSlider *m_opacitySlider; ExtendedSlider* m_opacitySlider;
void initWidgets(); void initWidgets();
void initOpacitySlider(); void initOpacitySlider();
}; };

View File

@@ -17,70 +17,89 @@
#include "capturerequest.h" #include "capturerequest.h"
#include "src/utils/screenshotsaver.h" #include "src/utils/screenshotsaver.h"
#include <QVector>
#include <QDateTime> #include <QDateTime>
#include <QVector>
CaptureRequest::CaptureRequest(CaptureRequest::CaptureMode mode, CaptureRequest::CaptureRequest(CaptureRequest::CaptureMode mode,
const uint delay, const QString &path, const uint delay,
const QVariant &data, const QString& path,
CaptureRequest::ExportTask tasks) : const QVariant& data,
m_mode(mode), m_delay(delay), m_path(path), m_tasks(tasks), CaptureRequest::ExportTask tasks)
m_data(data), m_forcedID(false), m_id(0) : m_mode(mode)
, m_delay(delay)
, m_path(path)
, m_tasks(tasks)
, m_data(data)
, m_forcedID(false)
, m_id(0)
{}
void
CaptureRequest::setStaticID(uint id)
{ {
m_forcedID = true;
m_id = id;
} }
void CaptureRequest::setStaticID(uint id) { uint
m_forcedID = true; CaptureRequest::id() const
m_id = id; {
if (m_forcedID) {
return m_id;
}
uint id = 0;
QVector<uint> v;
v << qHash(m_mode) << qHash(m_delay * QDateTime::currentMSecsSinceEpoch())
<< qHash(m_path) << qHash(m_tasks) << m_data.toInt();
for (uint i : v) {
id ^= i + 0x9e3779b9 + (id << 6) + (id >> 2);
}
return id;
} }
uint CaptureRequest::id() const { CaptureRequest::CaptureMode
if (m_forcedID) { CaptureRequest::captureMode() const
return m_id; {
} return m_mode;
}
uint id = 0;
QVector<uint>v; uint
v << qHash(m_mode) << qHash(m_delay * QDateTime::currentMSecsSinceEpoch()) CaptureRequest::delay() const
<< qHash(m_path) << qHash(m_tasks) << m_data.toInt(); {
for(uint i : v) { return m_delay;
id ^= i + 0x9e3779b9 + (id << 6) + (id >> 2); }
}
return id; QString
} CaptureRequest::path() const
{
CaptureRequest::CaptureMode CaptureRequest::captureMode() const { return m_path;
return m_mode; }
}
QVariant
uint CaptureRequest::delay() const { CaptureRequest::data() const
return m_delay; {
} return m_data;
}
QString CaptureRequest::path() const {
return m_path; void
} CaptureRequest::addTask(CaptureRequest::ExportTask task)
{
QVariant CaptureRequest::data() const { m_tasks |= task;
return m_data; }
}
void
void CaptureRequest::addTask(CaptureRequest::ExportTask task) { CaptureRequest::exportCapture(const QPixmap& p)
m_tasks |= task; {
} if ((m_tasks & ExportTask::FILESYSTEM_SAVE_TASK) != ExportTask::NO_TASK) {
if (m_path.isEmpty()) {
void CaptureRequest::exportCapture(const QPixmap &p) { ScreenshotSaver().saveToFilesystemGUI(p);
if ((m_tasks & ExportTask::FILESYSTEM_SAVE_TASK) != ExportTask::NO_TASK) { } else {
if (m_path.isEmpty()) { ScreenshotSaver().saveToFilesystem(p, m_path);
ScreenshotSaver().saveToFilesystemGUI(p);
} else {
ScreenshotSaver().saveToFilesystem(p, m_path);
}
}
if ((m_tasks & ExportTask::CLIPBOARD_SAVE_TASK) != ExportTask::NO_TASK) {
ScreenshotSaver().saveToClipboard(p);
} }
}
if ((m_tasks & ExportTask::CLIPBOARD_SAVE_TASK) != ExportTask::NO_TASK) {
ScreenshotSaver().saveToClipboard(p);
}
} }

View File

@@ -17,64 +17,72 @@
#pragma once #pragma once
#include <QString>
#include <QPixmap> #include <QPixmap>
#include <QString>
#include <QVariant> #include <QVariant>
class CaptureRequest { class CaptureRequest
{
public: public:
enum CaptureMode { enum CaptureMode
FULLSCREEN_MODE, {
GRAPHICAL_MODE, FULLSCREEN_MODE,
SCREEN_MODE, GRAPHICAL_MODE,
}; SCREEN_MODE,
};
enum ExportTask { enum ExportTask
NO_TASK = 0, {
CLIPBOARD_SAVE_TASK = 1, NO_TASK = 0,
FILESYSTEM_SAVE_TASK = 2, CLIPBOARD_SAVE_TASK = 1,
}; FILESYSTEM_SAVE_TASK = 2,
};
CaptureRequest(CaptureMode mode, CaptureRequest(CaptureMode mode,
const uint delay = 0, const uint delay = 0,
const QString &path = QLatin1String(""), const QString& path = QLatin1String(""),
const QVariant &data = QVariant(), const QVariant& data = QVariant(),
ExportTask tasks = NO_TASK); ExportTask tasks = NO_TASK);
void setStaticID(uint id); void setStaticID(uint id);
uint id() const; uint id() const;
uint delay() const; uint delay() const;
QString path() const; QString path() const;
QVariant data() const; QVariant data() const;
CaptureMode captureMode() const; CaptureMode captureMode() const;
void addTask(ExportTask task); void addTask(ExportTask task);
void exportCapture(const QPixmap &p); void exportCapture(const QPixmap& p);
private: private:
CaptureMode m_mode; CaptureMode m_mode;
uint m_delay; uint m_delay;
QString m_path; QString m_path;
ExportTask m_tasks; ExportTask m_tasks;
QVariant m_data; QVariant m_data;
bool m_forcedID; bool m_forcedID;
uint m_id; uint m_id;
}; };
using eTask = CaptureRequest::ExportTask; using eTask = CaptureRequest::ExportTask;
inline eTask operator|(const eTask &a, const eTask &b) { inline eTask
return static_cast<eTask>(static_cast<int>(a) | static_cast<int>(b)); operator|(const eTask& a, const eTask& b)
{
return static_cast<eTask>(static_cast<int>(a) | static_cast<int>(b));
} }
inline eTask operator&(const eTask &a, const eTask &b) { inline eTask
return static_cast<eTask>(static_cast<int>(a) & static_cast<int>(b)); operator&(const eTask& a, const eTask& b)
{
return static_cast<eTask>(static_cast<int>(a) & static_cast<int>(b));
} }
inline eTask& operator|=(eTask &a, const eTask &b) { inline eTask&
a = static_cast<eTask>(static_cast<int>(a) | static_cast<int>(b)); operator|=(eTask& a, const eTask& b)
return a; {
a = static_cast<eTask>(static_cast<int>(a) | static_cast<int>(b));
return a;
} }

View File

@@ -16,20 +16,20 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "controller.h" #include "controller.h"
#include "src/widgets/capture/capturewidget.h"
#include "src/utils/confighandler.h"
#include "src/widgets/infowindow.h"
#include "src/config/configwindow.h" #include "src/config/configwindow.h"
#include "src/widgets/capture/capturebutton.h" #include "src/utils/confighandler.h"
#include "src/widgets/capturelauncher.h"
#include "src/utils/systemnotification.h"
#include "src/utils/screengrabber.h" #include "src/utils/screengrabber.h"
#include <QFile> #include "src/utils/systemnotification.h"
#include <QApplication> #include "src/widgets/capture/capturebutton.h"
#include <QSystemTrayIcon> #include "src/widgets/capture/capturewidget.h"
#include "src/widgets/capturelauncher.h"
#include "src/widgets/infowindow.h"
#include <QAction> #include <QAction>
#include <QMenu> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QFile>
#include <QMenu>
#include <QSystemTrayIcon>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "src/core/globalshortcutfilter.h" #include "src/core/globalshortcutfilter.h"
@@ -38,241 +38,280 @@
// Controller is the core component of Flameshot, creates the trayIcon and // Controller is the core component of Flameshot, creates the trayIcon and
// launches the capture widget // launches the capture widget
Controller::Controller() : m_captureWindow(nullptr) { Controller::Controller()
qApp->setQuitOnLastWindowClosed(false); : m_captureWindow(nullptr)
{
qApp->setQuitOnLastWindowClosed(false);
// init tray icon // init tray icon
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
if (!ConfigHandler().disabledTrayIconValue()) { if (!ConfigHandler().disabledTrayIconValue()) {
enableTrayIcon();
}
#elif defined(Q_OS_WIN)
enableTrayIcon(); enableTrayIcon();
}
#elif defined(Q_OS_WIN)
enableTrayIcon();
GlobalShortcutFilter *nativeFilter = new GlobalShortcutFilter(this); GlobalShortcutFilter* nativeFilter = new GlobalShortcutFilter(this);
qApp->installNativeEventFilter(nativeFilter); qApp->installNativeEventFilter(nativeFilter);
connect(nativeFilter, &GlobalShortcutFilter::printPressed, connect(nativeFilter, &GlobalShortcutFilter::printPressed, this, [this]() {
this, [this](){ this->requestCapture(CaptureRequest(CaptureRequest::GRAPHICAL_MODE));
this->requestCapture(CaptureRequest(CaptureRequest::GRAPHICAL_MODE)); });
});
#endif #endif
QString StyleSheet = CaptureButton::globalStyleSheet(); QString StyleSheet = CaptureButton::globalStyleSheet();
qApp->setStyleSheet(StyleSheet); qApp->setStyleSheet(StyleSheet);
} }
Controller *Controller::getInstance() { Controller*
static Controller c; Controller::getInstance()
return &c; {
static Controller c;
return &c;
} }
void Controller::enableExports() { void
connect(this, &Controller::captureTaken, Controller::enableExports()
this, &Controller::handleCaptureTaken); {
connect(this, &Controller::captureFailed, connect(
this, &Controller::handleCaptureFailed); this, &Controller::captureTaken, this, &Controller::handleCaptureTaken);
connect(
this, &Controller::captureFailed, this, &Controller::handleCaptureFailed);
} }
void Controller::requestCapture(const CaptureRequest &request) { void
uint id = request.id(); Controller::requestCapture(const CaptureRequest& request)
m_requestMap.insert(id, request); {
uint id = request.id();
m_requestMap.insert(id, request);
switch (request.captureMode()) { switch (request.captureMode()) {
case CaptureRequest::FULLSCREEN_MODE: case CaptureRequest::FULLSCREEN_MODE:
doLater(request.delay(), this, [this, id](){ doLater(request.delay(), this, [this, id]() {
this->startFullscreenCapture(id); this->startFullscreenCapture(id);
}); });
break; break;
// TODO: Figure out the code path that gets here so the deprated warning can be fixed // TODO: Figure out the code path that gets here so the deprated warning can
// be fixed
case CaptureRequest::SCREEN_MODE: { case CaptureRequest::SCREEN_MODE: {
int &&number = request.data().toInt(); int&& number = request.data().toInt();
doLater(request.delay(), this, [this, id, number](){ doLater(request.delay(), this, [this, id, number]() {
this->startScreenGrab(id, number); this->startScreenGrab(id, number);
}); });
break; break;
} case CaptureRequest::GRAPHICAL_MODE: {
QString &&path = request.path();
doLater(request.delay(), this, [this, id, path](){
this->startVisualCapture(id, path);
});
break;
} default:
emit captureFailed(id);
break;
} }
case CaptureRequest::GRAPHICAL_MODE: {
QString&& path = request.path();
doLater(request.delay(), this, [this, id, path]() {
this->startVisualCapture(id, path);
});
break;
}
default:
emit captureFailed(id);
break;
}
} }
// creation of a new capture in GUI mode // creation of a new capture in GUI mode
void Controller::startVisualCapture(const uint id, const QString &forcedSavePath) { void
if (!m_captureWindow) { Controller::startVisualCapture(const uint id, const QString& forcedSavePath)
QWidget *modalWidget = nullptr; {
do { if (!m_captureWindow) {
modalWidget = qApp->activeModalWidget(); QWidget* modalWidget = nullptr;
if (modalWidget) { do {
modalWidget->close(); modalWidget = qApp->activeModalWidget();
modalWidget->deleteLater(); if (modalWidget) {
} modalWidget->close();
} while (modalWidget); modalWidget->deleteLater();
}
} while (modalWidget);
m_captureWindow = new CaptureWidget(id, forcedSavePath); m_captureWindow = new CaptureWidget(id, forcedSavePath);
//m_captureWindow = new CaptureWidget(id, forcedSavePath, false); // debug // m_captureWindow = new CaptureWidget(id, forcedSavePath, false); // debug
connect(m_captureWindow, &CaptureWidget::captureFailed, connect(m_captureWindow,
this, &Controller::captureFailed); &CaptureWidget::captureFailed,
connect(m_captureWindow, &CaptureWidget::captureTaken, this,
this, &Controller::captureTaken); &Controller::captureFailed);
connect(m_captureWindow,
&CaptureWidget::captureTaken,
this,
&Controller::captureTaken);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
m_captureWindow->show(); m_captureWindow->show();
#else #else
m_captureWindow->showFullScreen(); m_captureWindow->showFullScreen();
//m_captureWindow->show(); // Debug // m_captureWindow->show(); // Debug
#endif #endif
} else { } else {
emit captureFailed(id); emit captureFailed(id);
} }
} }
void Controller::startScreenGrab(const uint id, const int screenNumber) { void
bool ok = true; Controller::startScreenGrab(const uint id, const int screenNumber)
int n = screenNumber; {
bool ok = true;
int n = screenNumber;
if (n < 0) { if (n < 0) {
QPoint globalCursorPos = QCursor::pos(); QPoint globalCursorPos = QCursor::pos();
n = qApp->desktop()->screenNumber(globalCursorPos); n = qApp->desktop()->screenNumber(globalCursorPos);
} }
QPixmap p(ScreenGrabber().grabScreen(n, ok)); QPixmap p(ScreenGrabber().grabScreen(n, ok));
if (ok) { if (ok) {
emit captureTaken(id, p); emit captureTaken(id, p);
} else { } else {
emit captureFailed(id); emit captureFailed(id);
} }
} }
// creation of the configuration window // creation of the configuration window
void Controller::openConfigWindow() { void
if (!m_configWindow) { Controller::openConfigWindow()
m_configWindow = new ConfigWindow(); {
m_configWindow->show(); if (!m_configWindow) {
} m_configWindow = new ConfigWindow();
m_configWindow->show();
}
} }
// creation of the window of information // creation of the window of information
void Controller::openInfoWindow() { void
if (!m_infoWindow) { Controller::openInfoWindow()
m_infoWindow = new InfoWindow(); {
if (!m_infoWindow) {
m_infoWindow = new InfoWindow();
}
}
void
Controller::openLauncherWindow()
{
CaptureLauncher* w = new CaptureLauncher();
w->show();
}
void
Controller::enableTrayIcon()
{
if (m_trayIcon) {
return;
}
ConfigHandler().setDisabledTrayIcon(false);
QAction* captureAction = new QAction(tr("&Take Screenshot"), this);
connect(captureAction, &QAction::triggered, this, [this]() {
// Wait 400 ms to hide the QMenu
doLater(400, this, [this]() { this->startVisualCapture(); });
});
QAction* launcherAction = new QAction(tr("&Open Launcher"), this);
connect(
launcherAction, &QAction::triggered, this, &Controller::openLauncherWindow);
QAction* configAction = new QAction(tr("&Configuration"), this);
connect(
configAction, &QAction::triggered, this, &Controller::openConfigWindow);
QAction* infoAction = new QAction(tr("&Information"), this);
connect(infoAction, &QAction::triggered, this, &Controller::openInfoWindow);
QAction* quitAction = new QAction(tr("&Quit"), this);
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
QMenu* trayIconMenu = new QMenu();
trayIconMenu->addAction(captureAction);
trayIconMenu->addAction(launcherAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(configAction);
trayIconMenu->addAction(infoAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
m_trayIcon = new QSystemTrayIcon();
m_trayIcon->setToolTip(QStringLiteral("Flameshot"));
m_trayIcon->setContextMenu(trayIconMenu);
QIcon trayicon =
QIcon::fromTheme("flameshot-tray", QIcon(":img/app/flameshot.png"));
m_trayIcon->setIcon(trayicon);
auto trayIconActivated = [this](QSystemTrayIcon::ActivationReason r) {
if (r == QSystemTrayIcon::Trigger) {
startVisualCapture();
} }
};
connect(m_trayIcon, &QSystemTrayIcon::activated, this, trayIconActivated);
m_trayIcon->show();
} }
void Controller::openLauncherWindow() { void
CaptureLauncher *w = new CaptureLauncher(); Controller::disableTrayIcon()
w->show(); {
}
void Controller::enableTrayIcon() {
if (m_trayIcon) {
return;
}
ConfigHandler().setDisabledTrayIcon(false);
QAction *captureAction = new QAction(tr("&Take Screenshot"), this);
connect(captureAction, &QAction::triggered, this, [this](){
// Wait 400 ms to hide the QMenu
doLater(400, this, [this](){ this->startVisualCapture(); });
});
QAction *launcherAction = new QAction(tr("&Open Launcher"), this);
connect(launcherAction, &QAction::triggered, this,
&Controller::openLauncherWindow);
QAction *configAction = new QAction(tr("&Configuration"), this);
connect(configAction, &QAction::triggered, this,
&Controller::openConfigWindow);
QAction *infoAction = new QAction(tr("&Information"), this);
connect(infoAction, &QAction::triggered, this,
&Controller::openInfoWindow);
QAction *quitAction = new QAction(tr("&Quit"), this);
connect(quitAction, &QAction::triggered, qApp,
&QCoreApplication::quit);
QMenu *trayIconMenu = new QMenu();
trayIconMenu->addAction(captureAction);
trayIconMenu->addAction(launcherAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(configAction);
trayIconMenu->addAction(infoAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
m_trayIcon = new QSystemTrayIcon();
m_trayIcon->setToolTip(QStringLiteral("Flameshot"));
m_trayIcon->setContextMenu(trayIconMenu);
QIcon trayicon = QIcon::fromTheme("flameshot-tray", QIcon(":img/app/flameshot.png"));
m_trayIcon->setIcon(trayicon);
auto trayIconActivated = [this](QSystemTrayIcon::ActivationReason r){
if (r == QSystemTrayIcon::Trigger) {
startVisualCapture();
}
};
connect(m_trayIcon, &QSystemTrayIcon::activated, this, trayIconActivated);
m_trayIcon->show();
}
void Controller::disableTrayIcon() {
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
if (m_trayIcon) { if (m_trayIcon) {
m_trayIcon->deleteLater(); m_trayIcon->deleteLater();
} }
ConfigHandler().setDisabledTrayIcon(true); ConfigHandler().setDisabledTrayIcon(true);
#endif #endif
} }
void Controller::sendTrayNotification( void
const QString &text, Controller::sendTrayNotification(const QString& text,
const QString &title, const QString& title,
const int timeout) const int timeout)
{ {
if (m_trayIcon) { if (m_trayIcon) {
m_trayIcon->showMessage(title, text, QSystemTrayIcon::Information, timeout); m_trayIcon->showMessage(title, text, QSystemTrayIcon::Information, timeout);
} }
} }
void Controller::updateConfigComponents() { void
if (m_configWindow) { Controller::updateConfigComponents()
m_configWindow->updateChildren(); {
} if (m_configWindow) {
m_configWindow->updateChildren();
}
} }
void Controller::startFullscreenCapture(const uint id) { void
bool ok = true; Controller::startFullscreenCapture(const uint id)
QPixmap p(ScreenGrabber().grabEntireDesktop(ok)); {
if (ok) { bool ok = true;
emit captureTaken(id, p); QPixmap p(ScreenGrabber().grabEntireDesktop(ok));
} else { if (ok) {
emit captureFailed(id); emit captureTaken(id, p);
} } else {
emit captureFailed(id);
}
} }
void Controller::handleCaptureTaken(uint id, QPixmap p) { void
auto it = m_requestMap.find(id); Controller::handleCaptureTaken(uint id, QPixmap p)
if (it != m_requestMap.end()) { {
it.value().exportCapture(p); auto it = m_requestMap.find(id);
m_requestMap.erase(it); if (it != m_requestMap.end()) {
} it.value().exportCapture(p);
if (ConfigHandler().closeAfterScreenshotValue()) { m_requestMap.erase(it);
QApplication::quit(); }
} if (ConfigHandler().closeAfterScreenshotValue()) {
QApplication::quit();
}
} }
void Controller::handleCaptureFailed(uint id) { void
m_requestMap.remove(id); Controller::handleCaptureFailed(uint id)
{
m_requestMap.remove(id);
if (ConfigHandler().closeAfterScreenshotValue()) { if (ConfigHandler().closeAfterScreenshotValue()) {
QApplication::quit(); QApplication::quit();
} }
} }
void Controller::doLater(int msec, QObject *receiver, lambda func) { void
QTimer *timer = new QTimer(receiver); Controller::doLater(int msec, QObject* receiver, lambda func)
QObject::connect(timer, &QTimer::timeout, receiver, {
[timer, func](){ func(); timer->deleteLater(); }); QTimer* timer = new QTimer(receiver);
timer->setInterval(msec); QObject::connect(timer, &QTimer::timeout, receiver, [timer, func]() {
timer->start(); func();
timer->deleteLater();
});
timer->setInterval(msec);
timer->start();
} }

View File

@@ -18,10 +18,10 @@
#pragma once #pragma once
#include "src/core/capturerequest.h" #include "src/core/capturerequest.h"
#include <QObject>
#include <QPointer>
#include <QPixmap>
#include <QMap> #include <QMap>
#include <QObject>
#include <QPixmap>
#include <QPointer>
#include <QTimer> #include <QTimer>
#include <functional> #include <functional>
@@ -32,54 +32,56 @@ class QSystemTrayIcon;
using lambda = std::function<void(void)>; using lambda = std::function<void(void)>;
class Controller : public QObject { class Controller : public QObject
Q_OBJECT {
Q_OBJECT
public: public:
static Controller* getInstance(); static Controller* getInstance();
Controller(const Controller&) = delete; Controller(const Controller&) = delete;
void operator =(const Controller&) = delete; void operator=(const Controller&) = delete;
void enableExports(); void enableExports();
signals: signals:
void captureTaken(uint id, QPixmap p); void captureTaken(uint id, QPixmap p);
void captureFailed(uint id); void captureFailed(uint id);
public slots: public slots:
void requestCapture(const CaptureRequest &request); void requestCapture(const CaptureRequest& request);
void openConfigWindow(); void openConfigWindow();
void openInfoWindow(); void openInfoWindow();
void openLauncherWindow(); void openLauncherWindow();
void enableTrayIcon(); void enableTrayIcon();
void disableTrayIcon(); void disableTrayIcon();
void sendTrayNotification(const QString &text, void sendTrayNotification(
const QString &title = QStringLiteral("Flameshot Info"), const QString& text,
const int timeout = 5000); const QString& title = QStringLiteral("Flameshot Info"),
const int timeout = 5000);
void updateConfigComponents(); void updateConfigComponents();
private slots: private slots:
void startFullscreenCapture(const uint id = 0); void startFullscreenCapture(const uint id = 0);
void startVisualCapture(const uint id = 0, void startVisualCapture(const uint id = 0,
const QString &forcedSavePath = QString()); const QString& forcedSavePath = QString());
void startScreenGrab(const uint id = 0, const int screenNumber = -1); void startScreenGrab(const uint id = 0, const int screenNumber = -1);
void handleCaptureTaken(uint id, QPixmap p); void handleCaptureTaken(uint id, QPixmap p);
void handleCaptureFailed(uint id); void handleCaptureFailed(uint id);
private: private:
Controller(); Controller();
// replace QTimer::singleShot introduced in Qt 5.4 // replace QTimer::singleShot introduced in Qt 5.4
// the actual target Qt version is 5.3 // the actual target Qt version is 5.3
void doLater(int msec, QObject *receiver, lambda func); void doLater(int msec, QObject* receiver, lambda func);
QMap<uint, CaptureRequest> m_requestMap; QMap<uint, CaptureRequest> m_requestMap;
QPointer<CaptureWidget> m_captureWindow; QPointer<CaptureWidget> m_captureWindow;
QPointer<InfoWindow> m_infoWindow; QPointer<InfoWindow> m_infoWindow;
QPointer<ConfigWindow> m_configWindow; QPointer<ConfigWindow> m_configWindow;
QPointer<QSystemTrayIcon> m_trayIcon; QPointer<QSystemTrayIcon> m_trayIcon;
}; };

View File

@@ -16,90 +16,111 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "flameshotdbusadapter.h" #include "flameshotdbusadapter.h"
#include "src/core/controller.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/screengrabber.h" #include "src/utils/screengrabber.h"
#include "src/core/controller.h"
#include "src/utils/screenshotsaver.h" #include "src/utils/screenshotsaver.h"
#include "src/utils/systemnotification.h" #include "src/utils/systemnotification.h"
#include <QBuffer> #include <QBuffer>
FlameshotDBusAdapter::FlameshotDBusAdapter(QObject *parent) FlameshotDBusAdapter::FlameshotDBusAdapter(QObject* parent)
: QDBusAbstractAdaptor(parent) : QDBusAbstractAdaptor(parent)
{ {
auto controller = Controller::getInstance(); auto controller = Controller::getInstance();
connect(controller, &Controller::captureFailed, connect(controller,
this, &FlameshotDBusAdapter::captureFailed); &Controller::captureFailed,
connect(controller, &Controller::captureTaken, this,
this, &FlameshotDBusAdapter::handleCaptureTaken); &FlameshotDBusAdapter::captureFailed);
connect(controller,
&Controller::captureTaken,
this,
&FlameshotDBusAdapter::handleCaptureTaken);
} }
FlameshotDBusAdapter::~FlameshotDBusAdapter() { FlameshotDBusAdapter::~FlameshotDBusAdapter() {}
} void
FlameshotDBusAdapter::graphicCapture(QString path, int delay, uint id)
void FlameshotDBusAdapter::graphicCapture(QString path, int delay, uint id) {
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path);
// if (toClipboard) {
// req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
// }
req.setStaticID(id);
Controller::getInstance()->requestCapture(req);
}
void FlameshotDBusAdapter::fullScreen(
QString path, bool toClipboard, int delay, uint id)
{ {
CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, path); CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, path);
if (toClipboard) { // if (toClipboard) {
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK); // req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
} // }
if (!path.isEmpty()) { req.setStaticID(id);
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK); Controller::getInstance()->requestCapture(req);
}
req.setStaticID(id);
Controller::getInstance()->requestCapture(req);
} }
void FlameshotDBusAdapter::openLauncher() { void
Controller::getInstance()->openLauncherWindow(); FlameshotDBusAdapter::fullScreen(QString path,
} bool toClipboard,
int delay,
void FlameshotDBusAdapter::captureScreen(int number, QString path, uint id)
bool toClipboard, int delay, uint id)
{ {
CaptureRequest req(CaptureRequest::SCREEN_MODE, delay, path, number); CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, path);
if (toClipboard) { if (toClipboard) {
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK); req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
} }
if (!path.isEmpty()) { if (!path.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK); req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
} }
req.setStaticID(id); req.setStaticID(id);
Controller::getInstance()->requestCapture(req); Controller::getInstance()->requestCapture(req);
} }
void FlameshotDBusAdapter::openConfig() { void
Controller::getInstance()->openConfigWindow(); FlameshotDBusAdapter::openLauncher()
{
Controller::getInstance()->openLauncherWindow();
} }
void FlameshotDBusAdapter::trayIconEnabled(bool enabled) { void
auto controller = Controller::getInstance(); FlameshotDBusAdapter::captureScreen(int number,
if (enabled) { QString path,
controller->enableTrayIcon(); bool toClipboard,
} else { int delay,
controller->disableTrayIcon(); uint id)
} {
CaptureRequest req(CaptureRequest::SCREEN_MODE, delay, path, number);
if (toClipboard) {
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
}
if (!path.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
}
req.setStaticID(id);
Controller::getInstance()->requestCapture(req);
} }
void FlameshotDBusAdapter::autostartEnabled(bool enabled) { void
ConfigHandler().setStartupLaunch(enabled); FlameshotDBusAdapter::openConfig()
auto controller = Controller::getInstance(); {
// Autostart is not saved in a .ini file, requires manual update Controller::getInstance()->openConfigWindow();
controller->updateConfigComponents();
} }
void FlameshotDBusAdapter::handleCaptureTaken(uint id, const QPixmap &p) { void
QByteArray byteArray; FlameshotDBusAdapter::trayIconEnabled(bool enabled)
QBuffer buffer(&byteArray); {
p.save(&buffer, "PNG"); auto controller = Controller::getInstance();
emit captureTaken(id, byteArray); if (enabled) {
controller->enableTrayIcon();
} else {
controller->disableTrayIcon();
}
}
void
FlameshotDBusAdapter::autostartEnabled(bool enabled)
{
ConfigHandler().setStartupLaunch(enabled);
auto controller = Controller::getInstance();
// Autostart is not saved in a .ini file, requires manual update
controller->updateConfigComponents();
}
void
FlameshotDBusAdapter::handleCaptureTaken(uint id, const QPixmap& p)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
p.save(&buffer, "PNG");
emit captureTaken(id, byteArray);
} }

View File

@@ -17,30 +17,35 @@
#pragma once #pragma once
#include <QtDBus/QDBusAbstractAdaptor>
#include "src/core/controller.h" #include "src/core/controller.h"
#include <QtDBus/QDBusAbstractAdaptor>
class FlameshotDBusAdapter : public QDBusAbstractAdaptor { class FlameshotDBusAdapter : public QDBusAbstractAdaptor
Q_OBJECT {
Q_CLASSINFO("D-Bus Interface", "org.dharkael.Flameshot") Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.dharkael.Flameshot")
public: public:
explicit FlameshotDBusAdapter(QObject *parent = nullptr); explicit FlameshotDBusAdapter(QObject* parent = nullptr);
virtual ~FlameshotDBusAdapter(); virtual ~FlameshotDBusAdapter();
signals: signals:
void captureTaken(uint id, QByteArray rawImage); void captureTaken(uint id, QByteArray rawImage);
void captureFailed(uint id); void captureFailed(uint id);
public slots: public slots:
Q_NOREPLY void graphicCapture(QString path, int delay, uint id); Q_NOREPLY void graphicCapture(QString path, int delay, uint id);
Q_NOREPLY void fullScreen(QString path, bool toClipboard, int delay, uint id); Q_NOREPLY void fullScreen(QString path, bool toClipboard, int delay, uint id);
Q_NOREPLY void captureScreen(int number, QString path, bool toClipboard, int delay, uint id); Q_NOREPLY void captureScreen(int number,
Q_NOREPLY void openLauncher(); QString path,
Q_NOREPLY void openConfig(); bool toClipboard,
Q_NOREPLY void trayIconEnabled(bool enabled); int delay,
Q_NOREPLY void autostartEnabled(bool enabled); uint id);
Q_NOREPLY void openLauncher();
Q_NOREPLY void openConfig();
Q_NOREPLY void trayIconEnabled(bool enabled);
Q_NOREPLY void autostartEnabled(bool enabled);
private slots: private slots:
void handleCaptureTaken(uint id, const QPixmap &p); void handleCaptureTaken(uint id, const QPixmap& p);
}; };

View File

@@ -19,33 +19,33 @@
#include "src/core/controller.h" #include "src/core/controller.h"
#include <qt_windows.h> #include <qt_windows.h>
GlobalShortcutFilter::GlobalShortcutFilter(QObject *parent) : GlobalShortcutFilter::GlobalShortcutFilter(QObject* parent)
QObject(parent) : QObject(parent)
{ {
// Forced Print Screen // Forced Print Screen
if (RegisterHotKey(NULL, 1, 0, VK_SNAPSHOT)) { if (RegisterHotKey(NULL, 1, 0, VK_SNAPSHOT)) {
// ok // ok
} }
} }
bool GlobalShortcutFilter::nativeEventFilter( bool
const QByteArray &eventType, GlobalShortcutFilter::nativeEventFilter(const QByteArray& eventType,
void *message, void* message,
long *result) long* result)
{ {
Q_UNUSED(eventType); Q_UNUSED(eventType);
Q_UNUSED(result); Q_UNUSED(result);
MSG* msg = static_cast<MSG*>(message); MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_HOTKEY) { if (msg->message == WM_HOTKEY) {
//const quint32 keycode = HIWORD(msg->lParam); // const quint32 keycode = HIWORD(msg->lParam);
//const quint32 modifiers = LOWORD(msg->lParam); // const quint32 modifiers = LOWORD(msg->lParam);
// TODO: this is just a temporal workwrround, proper global // TODO: this is just a temporal workwrround, proper global
// support would need custom shortcuts defined by the user. // support would need custom shortcuts defined by the user.
Controller::getInstance()->requestCapture( Controller::getInstance()->requestCapture(
CaptureRequest(CaptureRequest::GRAPHICAL_MODE)); CaptureRequest(CaptureRequest::GRAPHICAL_MODE));
return true; return true;
} }
return false; return false;
} }

View File

@@ -17,22 +17,27 @@
#pragma once #pragma once
#include <QObject>
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#include <QObject>
class GlobalShortcutFilter : public QObject, public QAbstractNativeEventFilter { class GlobalShortcutFilter
Q_OBJECT : public QObject
, public QAbstractNativeEventFilter
{
Q_OBJECT
public: public:
explicit GlobalShortcutFilter(QObject *parent = nullptr); explicit GlobalShortcutFilter(QObject* parent = nullptr);
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); bool nativeEventFilter(const QByteArray& eventType,
void* message,
long* result);
signals: signals:
void printPressed(); void printPressed();
private: private:
quint32 getNativeModifier(Qt::KeyboardModifiers modifiers); quint32 getNativeModifier(Qt::KeyboardModifiers modifiers);
quint32 nativeKeycode(Qt::Key key); quint32 nativeKeycode(Qt::Key key);
bool registerShortcut(quint32 nativeKey, quint32 nativeMods); bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
}; };

View File

@@ -15,424 +15,456 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "src/core/controller.h"
#include "singleapplication.h" #include "singleapplication.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/confighandler.h"
#include "src/cli/commandlineparser.h" #include "src/cli/commandlineparser.h"
#include "src/utils/systemnotification.h"
#include "src/utils/pathinfo.h"
#include "src/core/capturerequest.h" #include "src/core/capturerequest.h"
#include "src/core/controller.h"
#include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/pathinfo.h"
#include "src/utils/systemnotification.h"
#include <QApplication> #include <QApplication>
#include <QDir>
#include <QLibraryInfo> #include <QLibraryInfo>
#include <QTranslator>
#include <QTextStream> #include <QTextStream>
#include <QTimer> #include <QTimer>
#include <QDir> #include <QTranslator>
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX) #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
#include "src/core/flameshotdbusadapter.h" #include "src/core/flameshotdbusadapter.h"
#include "src/utils/dbusutils.h" #include "src/utils/dbusutils.h"
#include <QDBusMessage>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusMessage>
#endif #endif
int main(int argc, char *argv[]) { int
// required for the button serialization main(int argc, char* argv[])
// TODO: change to QVector in v1.0 {
qRegisterMetaTypeStreamOperators<QList<int> >("QList<int>"); // required for the button serialization
qApp->setApplicationVersion(static_cast<QString>(APP_VERSION)); // TODO: change to QVector in v1.0
qRegisterMetaTypeStreamOperators<QList<int>>("QList<int>");
qApp->setApplicationVersion(static_cast<QString>(APP_VERSION));
// no arguments, just launch Flameshot // no arguments, just launch Flameshot
if (argc == 1) { if (argc == 1) {
SingleApplication app(argc, argv); SingleApplication app(argc, argv);
QTranslator translator, qtTranslator; QTranslator translator, qtTranslator;
QStringList trPaths = PathInfo::translationsPaths(); QStringList trPaths = PathInfo::translationsPaths();
for (const QString &path: trPaths) { for (const QString& path : trPaths) {
bool match = translator.load(QLocale(), bool match = translator.load(QLocale(),
QStringLiteral("Internationalization"), QStringLiteral("_"), QStringLiteral("Internationalization"),
path); QStringLiteral("_"),
if (match) { path);
break; if (match) {
} break;
} }
qtTranslator.load(QLocale::system(), "qt", "_",
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&translator);
app.installTranslator(&qtTranslator);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
app.setApplicationName(QStringLiteral("flameshot"));
app.setOrganizationName(QStringLiteral("Dharkael"));
auto c = Controller::getInstance();
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
new FlameshotDBusAdapter(c);
QDBusConnection dbus = QDBusConnection::sessionBus();
if (!dbus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
dbus.registerObject(QStringLiteral("/"), c);
dbus.registerService(QStringLiteral("org.dharkael.Flameshot"));
#endif
// Exporting captures must be connected after the dbus interface
// or the dbus signal gets blocked until we end the exports.
c->enableExports();
return app.exec();
} }
#ifndef Q_OS_WIN qtTranslator.load(QLocale::system(),
/*--------------| "qt",
* CLI parsing | "_",
* ------------*/ QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QCoreApplication app(argc, argv);
app.installTranslator(&translator);
app.installTranslator(&qtTranslator);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
app.setApplicationName(QStringLiteral("flameshot")); app.setApplicationName(QStringLiteral("flameshot"));
app.setOrganizationName(QStringLiteral("Dharkael")); app.setOrganizationName(QStringLiteral("Dharkael"));
app.setApplicationVersion(qApp->applicationVersion());
CommandLineParser parser;
// Add description
parser.setDescription(
QStringLiteral("Powerful yet simple to use screenshot software."));
parser.setGeneralErrorMessage(QStringLiteral("See 'flameshot --help'."));
// Arguments
CommandArgument fullArgument(QStringLiteral("full"), QStringLiteral("Capture the entire desktop."));
CommandArgument launcherArgument(QStringLiteral("launcher"), QStringLiteral("Open the capture launcher."));
CommandArgument guiArgument(QStringLiteral("gui"), QStringLiteral("Start a manual capture in GUI mode."));
CommandArgument configArgument(QStringLiteral("config"), QStringLiteral("Configure flameshot."));
CommandArgument screenArgument(QStringLiteral("screen"), QStringLiteral("Capture a single screen."));
// Options auto c = Controller::getInstance();
CommandOption pathOption( #if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
{"p", "path"}, new FlameshotDBusAdapter(c);
QStringLiteral("Path where the capture will be saved"), QDBusConnection dbus = QDBusConnection::sessionBus();
QStringLiteral("path")); if (!dbus.isConnected()) {
CommandOption clipboardOption( SystemNotification().sendMessage(
{"c", "clipboard"}, QObject::tr("Unable to connect via DBus"));
QStringLiteral("Save the capture to the clipboard")); }
CommandOption delayOption( dbus.registerObject(QStringLiteral("/"), c);
{"d", "delay"}, dbus.registerService(QStringLiteral("org.dharkael.Flameshot"));
QStringLiteral("Delay time in milliseconds"), #endif
QStringLiteral("milliseconds")); // Exporting captures must be connected after the dbus interface
CommandOption filenameOption( // or the dbus signal gets blocked until we end the exports.
{"f", "filename"}, c->enableExports();
QStringLiteral("Set the filename pattern"), return app.exec();
QStringLiteral("pattern")); }
CommandOption trayOption(
{"t", "trayicon"},
QStringLiteral("Enable or disable the trayicon"),
QStringLiteral("bool"));
CommandOption autostartOption(
{"a", "autostart"},
QStringLiteral("Enable or disable run at startup"),
QStringLiteral("bool"));
CommandOption showHelpOption(
{"s", "showhelp"},
QStringLiteral("Show the help message in the capture mode"),
QStringLiteral("bool"));
CommandOption mainColorOption(
{"m", "maincolor"},
QStringLiteral("Define the main UI color"),
QStringLiteral("color-code"));
CommandOption contrastColorOption(
{"k", "contrastcolor"},
QStringLiteral("Define the contrast UI color"),
QStringLiteral("color-code"));
CommandOption rawImageOption(
{"r", "raw"},
QStringLiteral("Print raw PNG capture"));
CommandOption screenNumberOption(
{"n", "number"},
QStringLiteral("Define the screen to capture,\ndefault: screen containing the cursor"),
QStringLiteral("Screen number"), QStringLiteral("-1"));
// Add checkers #ifndef Q_OS_WIN
auto colorChecker = [](const QString &colorCode) -> bool { /*--------------|
QColor parsedColor(colorCode); * CLI parsing |
return parsedColor.isValid() && parsedColor.alphaF() == 1.0; * ------------*/
}; QCoreApplication app(argc, argv);
QString colorErr = "Invalid color, " app.setApplicationName(QStringLiteral("flameshot"));
"this flag supports the following formats:\n" app.setOrganizationName(QStringLiteral("Dharkael"));
"- #RGB (each of R, G, and B is a single hex digit)\n" app.setApplicationVersion(qApp->applicationVersion());
"- #RRGGBB\n- #RRRGGGBBB\n" CommandLineParser parser;
"- #RRRRGGGGBBBB\n" // Add description
"- Named colors like 'blue' or 'red'\n" parser.setDescription(
"You may need to escape the '#' sign as in '\\#FFF'"; QStringLiteral("Powerful yet simple to use screenshot software."));
parser.setGeneralErrorMessage(QStringLiteral("See 'flameshot --help'."));
// Arguments
CommandArgument fullArgument(QStringLiteral("full"),
QStringLiteral("Capture the entire desktop."));
CommandArgument launcherArgument(
QStringLiteral("launcher"), QStringLiteral("Open the capture launcher."));
CommandArgument guiArgument(
QStringLiteral("gui"),
QStringLiteral("Start a manual capture in GUI mode."));
CommandArgument configArgument(QStringLiteral("config"),
QStringLiteral("Configure flameshot."));
CommandArgument screenArgument(QStringLiteral("screen"),
QStringLiteral("Capture a single screen."));
const QString delayErr = QStringLiteral("Invalid delay, it must be higher than 0"); // Options
const QString numberErr = QStringLiteral("Invalid screen number, it must be non negative"); CommandOption pathOption(
auto numericChecker = [](const QString &delayValue) -> bool { { "p", "path" },
int value = delayValue.toInt(); QStringLiteral("Path where the capture will be saved"),
return value >= 0; QStringLiteral("path"));
}; CommandOption clipboardOption(
{ "c", "clipboard" }, QStringLiteral("Save the capture to the clipboard"));
CommandOption delayOption({ "d", "delay" },
QStringLiteral("Delay time in milliseconds"),
QStringLiteral("milliseconds"));
CommandOption filenameOption({ "f", "filename" },
QStringLiteral("Set the filename pattern"),
QStringLiteral("pattern"));
CommandOption trayOption({ "t", "trayicon" },
QStringLiteral("Enable or disable the trayicon"),
QStringLiteral("bool"));
CommandOption autostartOption(
{ "a", "autostart" },
QStringLiteral("Enable or disable run at startup"),
QStringLiteral("bool"));
CommandOption showHelpOption(
{ "s", "showhelp" },
QStringLiteral("Show the help message in the capture mode"),
QStringLiteral("bool"));
CommandOption mainColorOption({ "m", "maincolor" },
QStringLiteral("Define the main UI color"),
QStringLiteral("color-code"));
CommandOption contrastColorOption(
{ "k", "contrastcolor" },
QStringLiteral("Define the contrast UI color"),
QStringLiteral("color-code"));
CommandOption rawImageOption({ "r", "raw" },
QStringLiteral("Print raw PNG capture"));
CommandOption screenNumberOption(
{ "n", "number" },
QStringLiteral(
"Define the screen to capture,\ndefault: screen containing the cursor"),
QStringLiteral("Screen number"),
QStringLiteral("-1"));
const QString pathErr = QStringLiteral("Invalid path, it must be a real path in the system"); // Add checkers
auto pathChecker = [pathErr](const QString &pathValue) -> bool { auto colorChecker = [](const QString& colorCode) -> bool {
bool res = QDir(pathValue).exists(); QColor parsedColor(colorCode);
if (!res) { return parsedColor.isValid() && parsedColor.alphaF() == 1.0;
SystemNotification().sendMessage(QObject::tr(pathErr.toLatin1().data())); };
} QString colorErr = "Invalid color, "
return res; "this flag supports the following formats:\n"
}; "- #RGB (each of R, G, and B is a single hex digit)\n"
"- #RRGGBB\n- #RRRGGGBBB\n"
"- #RRRRGGGGBBBB\n"
"- Named colors like 'blue' or 'red'\n"
"You may need to escape the '#' sign as in '\\#FFF'";
const QString booleanErr = QStringLiteral("Invalid value, it must be defined as 'true' or 'false'"); const QString delayErr =
auto booleanChecker = [](const QString &value) -> bool { QStringLiteral("Invalid delay, it must be higher than 0");
return value == QLatin1String("true") || value == QLatin1String("false"); const QString numberErr =
}; QStringLiteral("Invalid screen number, it must be non negative");
auto numericChecker = [](const QString& delayValue) -> bool {
int value = delayValue.toInt();
return value >= 0;
};
contrastColorOption.addChecker(colorChecker, colorErr); const QString pathErr =
mainColorOption.addChecker(colorChecker, colorErr); QStringLiteral("Invalid path, it must be a real path in the system");
delayOption.addChecker(numericChecker, delayErr); auto pathChecker = [pathErr](const QString& pathValue) -> bool {
pathOption.addChecker(pathChecker, pathErr); bool res = QDir(pathValue).exists();
trayOption.addChecker(booleanChecker, booleanErr); if (!res) {
autostartOption.addChecker(booleanChecker, booleanErr); SystemNotification().sendMessage(QObject::tr(pathErr.toLatin1().data()));
showHelpOption.addChecker(booleanChecker, booleanErr); }
screenNumberOption.addChecker(numericChecker, numberErr); return res;
};
// Relationships const QString booleanErr =
parser.AddArgument(guiArgument); QStringLiteral("Invalid value, it must be defined as 'true' or 'false'");
parser.AddArgument(screenArgument); auto booleanChecker = [](const QString& value) -> bool {
parser.AddArgument(fullArgument); return value == QLatin1String("true") || value == QLatin1String("false");
parser.AddArgument(launcherArgument); };
parser.AddArgument(configArgument);
auto helpOption = parser.addHelpOption(); contrastColorOption.addChecker(colorChecker, colorErr);
auto versionOption = parser.addVersionOption(); mainColorOption.addChecker(colorChecker, colorErr);
parser.AddOptions({ pathOption, delayOption, rawImageOption }, guiArgument); delayOption.addChecker(numericChecker, delayErr);
parser.AddOptions({ screenNumberOption, clipboardOption, pathOption, pathOption.addChecker(pathChecker, pathErr);
delayOption, rawImageOption }, trayOption.addChecker(booleanChecker, booleanErr);
screenArgument); autostartOption.addChecker(booleanChecker, booleanErr);
parser.AddOptions({ pathOption, clipboardOption, delayOption, rawImageOption }, showHelpOption.addChecker(booleanChecker, booleanErr);
fullArgument); screenNumberOption.addChecker(numericChecker, numberErr);
parser.AddOptions({ autostartOption, filenameOption, trayOption,
showHelpOption, mainColorOption, contrastColorOption }, // Relationships
configArgument); parser.AddArgument(guiArgument);
// Parse parser.AddArgument(screenArgument);
if (!parser.parse(app.arguments())) { parser.AddArgument(fullArgument);
goto finish; parser.AddArgument(launcherArgument);
parser.AddArgument(configArgument);
auto helpOption = parser.addHelpOption();
auto versionOption = parser.addVersionOption();
parser.AddOptions({ pathOption, delayOption, rawImageOption }, guiArgument);
parser.AddOptions({ screenNumberOption,
clipboardOption,
pathOption,
delayOption,
rawImageOption },
screenArgument);
parser.AddOptions(
{ pathOption, clipboardOption, delayOption, rawImageOption }, fullArgument);
parser.AddOptions({ autostartOption,
filenameOption,
trayOption,
showHelpOption,
mainColorOption,
contrastColorOption },
configArgument);
// Parse
if (!parser.parse(app.arguments())) {
goto finish;
}
// PROCESS DATA
//--------------
if (parser.isSet(helpOption) || parser.isSet(versionOption)) {
} else if (parser.isSet(launcherArgument)) { // LAUNCHER
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("openLauncher"));
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
} else if (parser.isSet(guiArgument)) { // GUI
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool isRaw = parser.isSet(rawImageOption);
DBusUtils dbusUtils;
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, pathValue);
uint id = req.id();
// Send message
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("graphicCapture"));
m << pathValue << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
QTimer t;
t.setInterval(delay + 1000 * 60 * 15); // 15 minutes timeout
QObject::connect(&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} else if (parser.isSet(fullArgument)) { // FULL
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< rawImageOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< clipboardOption.dashedNames().join(QStringLiteral(", ")) << "\n\n";
parser.parse(QStringList() << argv[0] << QStringLiteral("full")
<< QStringLiteral("-h"));
goto finish;
} }
// PROCESS DATA CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, pathValue);
//-------------- if (toClipboard) {
if (parser.isSet(helpOption) || parser.isSet(versionOption)) { req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
} }
else if (parser.isSet(launcherArgument)) { // LAUNCHER if (!pathValue.isEmpty()) {
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"), req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
QStringLiteral("/"), QLatin1String(""), QStringLiteral("openLauncher"));
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
} }
else if (parser.isSet(guiArgument)) { // GUI uint id = req.id();
QString pathValue = parser.value(pathOption); DBusUtils dbusUtils;
int delay = parser.value(delayOption).toInt();
bool isRaw = parser.isSet(rawImageOption);
DBusUtils dbusUtils;
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, pathValue);
uint id = req.id();
// Send message // Send message
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"), QDBusMessage m =
QStringLiteral("/"), QLatin1String(""), QStringLiteral("graphicCapture")); QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
m << pathValue << delay << id; QStringLiteral("/"),
QDBusConnection sessionBus = QDBusConnection::sessionBus(); QLatin1String(""),
dbusUtils.checkDBusConnection(sessionBus); QStringLiteral("fullScreen"));
sessionBus.call(m); m << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) { if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id); dbusUtils.connectPrintCapture(sessionBus, id);
QTimer t; // timeout just in case
t.setInterval(delay + 1000 * 60 * 15); // 15 minutes timeout QTimer t;
QObject::connect(&t, &QTimer::timeout, qApp, t.setInterval(delay + 2000);
&QCoreApplication::quit); QObject::connect(&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start(); t.start();
// wait // wait
return app.exec(); return app.exec();
}
} }
else if (parser.isSet(fullArgument)) { // FULL } else if (parser.isSet(screenArgument)) { // SCREEN
QString pathValue = parser.value(pathOption); QString numberStr = parser.value(screenNumberOption);
int delay = parser.value(delayOption).toInt(); int number =
bool toClipboard = parser.isSet(clipboardOption); numberStr.startsWith(QLatin1String("-")) ? -1 : numberStr.toInt();
bool isRaw = parser.isSet(rawImageOption); QString pathValue = parser.value(pathOption);
// Not a valid command int delay = parser.value(delayOption).toInt();
if (!isRaw && !toClipboard && pathValue.isEmpty()) { bool toClipboard = parser.isSet(clipboardOption);
QTextStream out(stdout); bool isRaw = parser.isSet(rawImageOption);
out << "Invalid format, set where to save the content with one of " // Not a valid command
<< "the following flags:\n " if (!isRaw && !toClipboard && pathValue.isEmpty()) {
<< pathOption.dashedNames().join(QStringLiteral(", ")) << "\n " QTextStream out(stdout);
<< rawImageOption.dashedNames().join(QStringLiteral(", ")) << "\n " out << "Invalid format, set where to save the content with one of "
<< clipboardOption.dashedNames().join(QStringLiteral(", ")) << "\n\n"; << "the following flags:\n "
parser.parse(QStringList() << argv[0] << QStringLiteral("full") << QStringLiteral("-h")); << pathOption.dashedNames().join(QStringLiteral(", ")) << "\n "
goto finish; << rawImageOption.dashedNames().join(QStringLiteral(", ")) << "\n "
} << clipboardOption.dashedNames().join(QStringLiteral(", ")) << "\n\n";
parser.parse(QStringList() << argv[0] << QStringLiteral("screen")
CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, pathValue); << QStringLiteral("-h"));
if (toClipboard) { goto finish;
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
}
if (!pathValue.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
}
uint id = req.id();
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"), QLatin1String(""), QStringLiteral("fullScreen"));
m << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(&t, &QTimer::timeout, qApp,
&QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} }
else if (parser.isSet(screenArgument)) { // SCREEN
QString numberStr = parser.value(screenNumberOption);
int number = numberStr.startsWith(QLatin1String("-")) ? -1 : numberStr.toInt();
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< rawImageOption.dashedNames().join(QStringLiteral(", ")) << "\n "
<< clipboardOption.dashedNames().join(QStringLiteral(", ")) << "\n\n";
parser.parse(QStringList() << argv[0] << QStringLiteral("screen") << QStringLiteral("-h"));
goto finish;
}
CaptureRequest req(CaptureRequest::SCREEN_MODE, CaptureRequest req(CaptureRequest::SCREEN_MODE, delay, pathValue, number);
delay, pathValue, number); if (toClipboard) {
if (toClipboard) { req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
}
if (!pathValue.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
}
uint id = req.id();
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"), QLatin1String(""), QStringLiteral("captureScreen"));
m << number << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(&t, &QTimer::timeout, qApp,
&QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} }
else if (parser.isSet(configArgument)) { // CONFIG if (!pathValue.isEmpty()) {
bool autostart = parser.isSet(autostartOption); req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
bool filename = parser.isSet(filenameOption);
bool tray = parser.isSet(trayOption);
bool help = parser.isSet(showHelpOption);
bool mainColor = parser.isSet(mainColorOption);
bool contrastColor = parser.isSet(contrastColorOption);
bool someFlagSet = (filename || tray || help ||
mainColor || contrastColor);
ConfigHandler config;
if (autostart) {
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"), QLatin1String(""), QStringLiteral("autostartEnabled"));
if (parser.value(autostartOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(autostartOption) == QLatin1String("true")) {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (filename) {
QString newFilename(parser.value(filenameOption));
config.setFilenamePattern(newFilename);
FileNameHandler fh;
QTextStream(stdout)
<< QStringLiteral("The new pattern is '%1'\n"
"Parsed pattern example: %2\n").arg(newFilename)
.arg(fh.parsedPattern());
}
if (tray) {
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"), QLatin1String(""), QStringLiteral("trayIconEnabled"));
if (parser.value(trayOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(trayOption) == QLatin1String("true")) {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (help) {
if (parser.value(showHelpOption) == QLatin1String("false")) {
config.setShowHelp(false);
} else if (parser.value(showHelpOption) == QLatin1String("true")) {
config.setShowHelp(true);
}
}
if (mainColor) {
QString colorCode = parser.value(mainColorOption);
QColor parsedColor(colorCode);
config.setUIMainColor(parsedColor);
}
if (contrastColor) {
QString colorCode = parser.value(contrastColorOption);
QColor parsedColor(colorCode);
config.setUIContrastColor(parsedColor);
}
// Open gui when no options
if (!someFlagSet) {
QDBusMessage m = QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"), QLatin1String(""), QStringLiteral("openConfig"));
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
} }
uint id = req.id();
DBusUtils dbusUtils;
// Send message
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("captureScreen"));
m << number << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(&t, &QTimer::timeout, qApp, &QCoreApplication::quit);
t.start();
// wait
return app.exec();
}
} else if (parser.isSet(configArgument)) { // CONFIG
bool autostart = parser.isSet(autostartOption);
bool filename = parser.isSet(filenameOption);
bool tray = parser.isSet(trayOption);
bool help = parser.isSet(showHelpOption);
bool mainColor = parser.isSet(mainColorOption);
bool contrastColor = parser.isSet(contrastColorOption);
bool someFlagSet = (filename || tray || help || mainColor || contrastColor);
ConfigHandler config;
if (autostart) {
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("autostartEnabled"));
if (parser.value(autostartOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(autostartOption) == QLatin1String("true")) {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (filename) {
QString newFilename(parser.value(filenameOption));
config.setFilenamePattern(newFilename);
FileNameHandler fh;
QTextStream(stdout) << QStringLiteral("The new pattern is '%1'\n"
"Parsed pattern example: %2\n")
.arg(newFilename)
.arg(fh.parsedPattern());
}
if (tray) {
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("trayIconEnabled"));
if (parser.value(trayOption) == QLatin1String("false")) {
m << false;
} else if (parser.value(trayOption) == QLatin1String("true")) {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (help) {
if (parser.value(showHelpOption) == QLatin1String("false")) {
config.setShowHelp(false);
} else if (parser.value(showHelpOption) == QLatin1String("true")) {
config.setShowHelp(true);
}
}
if (mainColor) {
QString colorCode = parser.value(mainColorOption);
QColor parsedColor(colorCode);
config.setUIMainColor(parsedColor);
}
if (contrastColor) {
QString colorCode = parser.value(contrastColorOption);
QColor parsedColor(colorCode);
config.setUIContrastColor(parsedColor);
}
// Open gui when no options
if (!someFlagSet) {
QDBusMessage m =
QDBusMessage::createMethodCall(QStringLiteral("org.dharkael.Flameshot"),
QStringLiteral("/"),
QLatin1String(""),
QStringLiteral("openConfig"));
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
}
finish: finish:
#endif #endif
return 0; return 0;
} }

View File

@@ -17,55 +17,78 @@
#include "abstractactiontool.h" #include "abstractactiontool.h"
AbstractActionTool::AbstractActionTool(QObject *parent) : CaptureTool(parent) { AbstractActionTool::AbstractActionTool(QObject* parent)
: CaptureTool(parent)
{}
} bool
AbstractActionTool::isValid() const
bool AbstractActionTool::isValid() const {
return true;
}
bool AbstractActionTool::isSelectable() const {
return false;
}
bool AbstractActionTool::showMousePreview() const {
return false;
}
void AbstractActionTool::undo(QPixmap &pixmap) {
Q_UNUSED(pixmap);
}
void AbstractActionTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) {
Q_UNUSED(painter);
Q_UNUSED(pixmap);
Q_UNUSED(recordUndo);
}
void AbstractActionTool::paintMousePreview(
QPainter &painter, const CaptureContext &context)
{ {
Q_UNUSED(painter); return true;
Q_UNUSED(context);
} }
void AbstractActionTool::drawEnd(const QPoint &p) { bool
Q_UNUSED(p); AbstractActionTool::isSelectable() const
{
return false;
} }
void AbstractActionTool::drawMove(const QPoint &p) { bool
Q_UNUSED(p); AbstractActionTool::showMousePreview() const
{
return false;
} }
void AbstractActionTool::drawStart(const CaptureContext &context) { void
Q_UNUSED(context); AbstractActionTool::undo(QPixmap& pixmap)
{
Q_UNUSED(pixmap);
} }
void AbstractActionTool::colorChanged(const QColor &c) { void
Q_UNUSED(c); AbstractActionTool::process(QPainter& painter,
const QPixmap& pixmap,
bool recordUndo)
{
Q_UNUSED(painter);
Q_UNUSED(pixmap);
Q_UNUSED(recordUndo);
} }
void AbstractActionTool::thicknessChanged(const int th) { void
Q_UNUSED(th); AbstractActionTool::paintMousePreview(QPainter& painter,
const CaptureContext& context)
{
Q_UNUSED(painter);
Q_UNUSED(context);
}
void
AbstractActionTool::drawEnd(const QPoint& p)
{
Q_UNUSED(p);
}
void
AbstractActionTool::drawMove(const QPoint& p)
{
Q_UNUSED(p);
}
void
AbstractActionTool::drawStart(const CaptureContext& context)
{
Q_UNUSED(context);
}
void
AbstractActionTool::colorChanged(const QColor& c)
{
Q_UNUSED(c);
}
void
AbstractActionTool::thicknessChanged(const int th)
{
Q_UNUSED(th);
} }

View File

@@ -19,23 +19,27 @@
#include "capturetool.h" #include "capturetool.h"
class AbstractActionTool : public CaptureTool { class AbstractActionTool : public CaptureTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit AbstractActionTool(QObject *parent = nullptr); explicit AbstractActionTool(QObject* parent = nullptr);
bool isValid() const override; bool isValid() const override;
bool isSelectable() const override; bool isSelectable() const override;
bool showMousePreview() const override; bool showMousePreview() const override;
void undo(QPixmap &pixmap) override; void undo(QPixmap& pixmap) override;
void process(QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; void process(QPainter& painter,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; const QPixmap& pixmap,
bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawEnd(const QPoint &p) override; void drawEnd(const QPoint& p) override;
void drawMove(const QPoint &p) override; void drawMove(const QPoint& p) override;
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void colorChanged(const QColor &c) override; void colorChanged(const QColor& c) override;
void thicknessChanged(const int th) override; void thicknessChanged(const int th) override;
}; };

View File

@@ -17,68 +17,89 @@
#include "abstractpathtool.h" #include "abstractpathtool.h"
AbstractPathTool::AbstractPathTool(QObject *parent) : AbstractPathTool::AbstractPathTool(QObject* parent)
CaptureTool(parent), m_thickness(0), m_padding(0) : CaptureTool(parent)
, m_thickness(0)
, m_padding(0)
{}
bool
AbstractPathTool::isValid() const
{ {
return m_points.length() > 1;
} }
bool AbstractPathTool::isValid() const { bool
return m_points.length() > 1; AbstractPathTool::closeOnButtonPressed() const
{
return false;
} }
bool AbstractPathTool::closeOnButtonPressed() const { bool
return false; AbstractPathTool::isSelectable() const
{
return true;
} }
bool AbstractPathTool::isSelectable() const { bool
return true; AbstractPathTool::showMousePreview() const
{
return true;
} }
bool AbstractPathTool::showMousePreview() const { void
return true; AbstractPathTool::undo(QPixmap& pixmap)
{
QPainter p(&pixmap);
const int val = m_thickness + m_padding;
QRect area = m_backupArea + QMargins(val, val, val, val);
p.drawPixmap(area.intersected(pixmap.rect()).topLeft(), m_pixmapBackup);
} }
void AbstractPathTool::undo(QPixmap &pixmap) { void
QPainter p(&pixmap); AbstractPathTool::drawEnd(const QPoint& p)
const int val = m_thickness + m_padding; {
QRect area = m_backupArea + QMargins(val, val, val, val); Q_UNUSED(p);
p.drawPixmap(area.intersected(pixmap.rect())
.topLeft(), m_pixmapBackup);
} }
void AbstractPathTool::drawEnd(const QPoint &p) { void
Q_UNUSED(p); AbstractPathTool::drawMove(const QPoint& p)
{
addPoint(p);
} }
void AbstractPathTool::drawMove(const QPoint &p) { void
addPoint(p); AbstractPathTool::colorChanged(const QColor& c)
{
m_color = c;
} }
void AbstractPathTool::colorChanged(const QColor &c) { void
m_color = c; AbstractPathTool::thicknessChanged(const int th)
{
m_thickness = th;
} }
void AbstractPathTool::thicknessChanged(const int th) { void
m_thickness = th; AbstractPathTool::updateBackup(const QPixmap& pixmap)
{
const int val = m_thickness + m_padding;
QRect area = m_backupArea.normalized() + QMargins(val, val, val, val);
m_pixmapBackup = pixmap.copy(area);
} }
void AbstractPathTool::updateBackup(const QPixmap &pixmap) { void
const int val = m_thickness + m_padding; AbstractPathTool::addPoint(const QPoint& point)
QRect area = m_backupArea.normalized() + QMargins(val, val, val, val); {
m_pixmapBackup = pixmap.copy(area); if (m_backupArea.left() > point.x()) {
} m_backupArea.setLeft(point.x());
} else if (m_backupArea.right() < point.x()) {
void AbstractPathTool::addPoint(const QPoint &point) { m_backupArea.setRight(point.x());
if (m_backupArea.left() > point.x()) { }
m_backupArea.setLeft(point.x()); if (m_backupArea.top() > point.y()) {
} else if (m_backupArea.right() < point.x()) { m_backupArea.setTop(point.y());
m_backupArea.setRight(point.x()); } else if (m_backupArea.bottom() < point.y()) {
} m_backupArea.setBottom(point.y());
if (m_backupArea.top() > point.y()) { }
m_backupArea.setTop(point.y()); m_points.append(point);
} else if (m_backupArea.bottom() < point.y()) {
m_backupArea.setBottom(point.y());
}
m_points.append(point);
} }

View File

@@ -19,33 +19,34 @@
#include "capturetool.h" #include "capturetool.h"
class AbstractPathTool : public CaptureTool { class AbstractPathTool : public CaptureTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit AbstractPathTool(QObject *parent = nullptr); explicit AbstractPathTool(QObject* parent = nullptr);
bool isValid() const override; bool isValid() const override;
bool closeOnButtonPressed() const override; bool closeOnButtonPressed() const override;
bool isSelectable() const override; bool isSelectable() const override;
bool showMousePreview() const override; bool showMousePreview() const override;
void undo(QPixmap &pixmap) override; void undo(QPixmap& pixmap) override;
public slots: public slots:
void drawEnd(const QPoint &p) override; void drawEnd(const QPoint& p) override;
void drawMove(const QPoint &p) override; void drawMove(const QPoint& p) override;
void colorChanged(const QColor &c) override; void colorChanged(const QColor& c) override;
void thicknessChanged(const int th) override; void thicknessChanged(const int th) override;
protected: protected:
void updateBackup(const QPixmap &pixmap); void updateBackup(const QPixmap& pixmap);
void addPoint(const QPoint &point); void addPoint(const QPoint& point);
QPixmap m_pixmapBackup; QPixmap m_pixmapBackup;
QRect m_backupArea; QRect m_backupArea;
QColor m_color; QColor m_color;
QVector<QPoint> m_points; QVector<QPoint> m_points;
int m_thickness; int m_thickness;
// use m_padding to extend the area of the backup // use m_padding to extend the area of the backup
int m_padding; int m_padding;
}; };

View File

@@ -23,113 +23,145 @@ namespace {
const double ADJ_UNIT = std::atan(1.0); const double ADJ_UNIT = std::atan(1.0);
const int DIRS_NUMBER = 4; const int DIRS_NUMBER = 4;
enum UNIT { enum UNIT
HORIZ_DIR = 0, {
DIAG1_DIR = 1, HORIZ_DIR = 0,
VERT_DIR = 2, DIAG1_DIR = 1,
DIAG2_DIR = 3 VERT_DIR = 2,
DIAG2_DIR = 3
}; };
const double ADJ_DIAG_UNIT = 2 * ADJ_UNIT; const double ADJ_DIAG_UNIT = 2 * ADJ_UNIT;
const int DIAG_DIRS_NUMBER = 2; const int DIAG_DIRS_NUMBER = 2;
enum DIAG_UNIT { enum DIAG_UNIT
DIR1 = 0, {
DIR2 = 1 DIR1 = 0,
DIR2 = 1
}; };
} }
AbstractTwoPointTool::AbstractTwoPointTool(QObject *parent) : AbstractTwoPointTool::AbstractTwoPointTool(QObject* parent)
CaptureTool(parent), m_thickness(0), m_padding(0) : CaptureTool(parent)
, m_thickness(0)
, m_padding(0)
{}
bool
AbstractTwoPointTool::isValid() const
{ {
return (m_points.first != m_points.second);
} }
bool AbstractTwoPointTool::isValid() const { bool
return (m_points.first != m_points.second); AbstractTwoPointTool::closeOnButtonPressed() const
{
return false;
} }
bool AbstractTwoPointTool::closeOnButtonPressed() const { bool
return false; AbstractTwoPointTool::isSelectable() const
{
return true;
} }
bool AbstractTwoPointTool::isSelectable() const { bool
return true; AbstractTwoPointTool::showMousePreview() const
{
return true;
} }
bool AbstractTwoPointTool::showMousePreview() const { void
return true; AbstractTwoPointTool::undo(QPixmap& pixmap)
{
QPainter p(&pixmap);
p.drawPixmap(backupRect(pixmap.rect()).topLeft(), m_pixmapBackup);
} }
void AbstractTwoPointTool::undo(QPixmap &pixmap) { void
QPainter p(&pixmap); AbstractTwoPointTool::drawEnd(const QPoint& p)
p.drawPixmap(backupRect(pixmap.rect()).topLeft(), m_pixmapBackup); {
Q_UNUSED(p);
} }
void AbstractTwoPointTool::drawEnd(const QPoint &p) { void
Q_UNUSED(p); AbstractTwoPointTool::drawMove(const QPoint& p)
{
m_points.second = p;
} }
void AbstractTwoPointTool::drawMove(const QPoint &p) { void
m_points.second = p; AbstractTwoPointTool::drawMoveWithAdjustment(const QPoint& p)
{
m_points.second = m_points.first + adjustedVector(p - m_points.first);
} }
void AbstractTwoPointTool::drawMoveWithAdjustment(const QPoint &p) { void
m_points.second = m_points.first + adjustedVector(p - m_points.first); AbstractTwoPointTool::colorChanged(const QColor& c)
{
m_color = c;
} }
void AbstractTwoPointTool::colorChanged(const QColor &c) { void
m_color = c; AbstractTwoPointTool::thicknessChanged(const int th)
{
m_thickness = th;
} }
void AbstractTwoPointTool::thicknessChanged(const int th) { void
m_thickness = th; AbstractTwoPointTool::updateBackup(const QPixmap& pixmap)
{
m_pixmapBackup = pixmap.copy(backupRect(pixmap.rect()));
} }
void AbstractTwoPointTool::updateBackup(const QPixmap &pixmap) { QRect
m_pixmapBackup = pixmap.copy(backupRect(pixmap.rect())); AbstractTwoPointTool::backupRect(const QRect& limits) const
{
QRect r = QRect(m_points.first, m_points.second).normalized();
const int val = m_thickness + m_padding;
r += QMargins(val, val, val, val);
return r.intersected(limits);
} }
QRect AbstractTwoPointTool::backupRect(const QRect &limits) const { QPoint
QRect r = QRect(m_points.first, m_points.second).normalized(); AbstractTwoPointTool::adjustedVector(QPoint v) const
const int val = m_thickness + m_padding; {
r += QMargins(val, val, val, val); if (m_supportsOrthogonalAdj && m_supportsDiagonalAdj) {
return r.intersected(limits); int dir =
} (static_cast<int>(round(atan2(-v.y(), v.x()) / ADJ_UNIT)) + DIRS_NUMBER) %
DIRS_NUMBER;
QPoint AbstractTwoPointTool::adjustedVector(QPoint v) const { if (dir == UNIT::HORIZ_DIR) {
if (m_supportsOrthogonalAdj && m_supportsDiagonalAdj) { v.setY(0);
int dir = ( static_cast<int>(round(atan2(-v.y(), v.x()) / ADJ_UNIT)) + DIRS_NUMBER ) % DIRS_NUMBER; } else if (dir == UNIT::VERT_DIR) {
if (dir == UNIT::HORIZ_DIR) { v.setX(0);
v.setY(0); } else if (dir == UNIT::DIAG1_DIR) {
} else if (dir == UNIT::VERT_DIR) { int newX = (v.x() - v.y()) / 2;
v.setX(0); int newY = -newX;
} else if (dir == UNIT::DIAG1_DIR) { v.setX(newX);
int newX = (v.x() - v.y()) / 2; v.setY(newY);
int newY = -newX; } else {
v.setX(newX); int newX = (v.x() + v.y()) / 2;
v.setY(newY); int newY = newX;
} else { v.setX(newX);
int newX = (v.x() + v.y()) / 2; v.setY(newY);
int newY = newX;
v.setX(newX);
v.setY(newY);
}
} else if (m_supportsDiagonalAdj) {
int dir = ( static_cast<int>(round((atan2(-v.y(), v.x()) - ADJ_DIAG_UNIT / 2) / ADJ_DIAG_UNIT))
+ DIAG_DIRS_NUMBER ) % DIAG_DIRS_NUMBER;
if (dir == DIAG_UNIT::DIR1) {
int newX = (v.x() - v.y()) / 2;
int newY = -newX;
v.setX(newX);
v.setY(newY);
} else {
int newX = (v.x() + v.y()) / 2;
int newY = newX;
v.setX(newX);
v.setY(newY);
}
} }
return v; } else if (m_supportsDiagonalAdj) {
int dir = (static_cast<int>(round(
(atan2(-v.y(), v.x()) - ADJ_DIAG_UNIT / 2) / ADJ_DIAG_UNIT)) +
DIAG_DIRS_NUMBER) %
DIAG_DIRS_NUMBER;
if (dir == DIAG_UNIT::DIR1) {
int newX = (v.x() - v.y()) / 2;
int newY = -newX;
v.setX(newX);
v.setY(newY);
} else {
int newX = (v.x() + v.y()) / 2;
int newY = newX;
v.setX(newX);
v.setY(newY);
}
}
return v;
} }

View File

@@ -19,39 +19,40 @@
#include "capturetool.h" #include "capturetool.h"
class AbstractTwoPointTool : public CaptureTool { class AbstractTwoPointTool : public CaptureTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit AbstractTwoPointTool(QObject *parent = nullptr); explicit AbstractTwoPointTool(QObject* parent = nullptr);
bool isValid() const override; bool isValid() const override;
bool closeOnButtonPressed() const override; bool closeOnButtonPressed() const override;
bool isSelectable() const override; bool isSelectable() const override;
bool showMousePreview() const override; bool showMousePreview() const override;
void undo(QPixmap &pixmap) override; void undo(QPixmap& pixmap) override;
public slots: public slots:
void drawEnd(const QPoint &p) override; void drawEnd(const QPoint& p) override;
void drawMove(const QPoint &p) override; void drawMove(const QPoint& p) override;
void drawMoveWithAdjustment(const QPoint &p) override; void drawMoveWithAdjustment(const QPoint& p) override;
void colorChanged(const QColor &c) override; void colorChanged(const QColor& c) override;
void thicknessChanged(const int th) override; void thicknessChanged(const int th) override;
protected: protected:
void updateBackup(const QPixmap &pixmap); void updateBackup(const QPixmap& pixmap);
QRect backupRect(const QRect &limits) const; QRect backupRect(const QRect& limits) const;
QPixmap m_pixmapBackup; QPixmap m_pixmapBackup;
QPair<QPoint, QPoint> m_points; QPair<QPoint, QPoint> m_points;
QColor m_color; QColor m_color;
int m_thickness; int m_thickness;
// use m_padding to extend the area of the backup // use m_padding to extend the area of the backup
int m_padding; int m_padding;
bool m_supportsOrthogonalAdj = false; bool m_supportsOrthogonalAdj = false;
bool m_supportsDiagonalAdj = false; bool m_supportsDiagonalAdj = false;
private: private:
QPoint adjustedVector(QPoint v) const; QPoint adjustedVector(QPoint v) const;
}; };

View File

@@ -24,97 +24,123 @@ namespace {
const int ArrowWidth = 10; const int ArrowWidth = 10;
const int ArrowHeight = 18; const int ArrowHeight = 18;
QPainterPath getArrowHead(QPoint p1, QPoint p2, const int thickness) { QPainterPath
QLineF base(p1, p2); getArrowHead(QPoint p1, QPoint p2, const int thickness)
// Create the vector for the position of the base of the arrowhead {
QLineF temp(QPoint(0,0), p2-p1); QLineF base(p1, p2);
int val = ArrowHeight + thickness*4; // Create the vector for the position of the base of the arrowhead
if (base.length() < val) { QLineF temp(QPoint(0, 0), p2 - p1);
val = (base.length() + thickness*2); int val = ArrowHeight + thickness * 4;
} if (base.length() < val) {
temp.setLength(base.length() + thickness*2 - val); val = (base.length() + thickness * 2);
// Move across the line up to the head }
QPointF bottonTranslation(temp.p2()); temp.setLength(base.length() + thickness * 2 - val);
// Move across the line up to the head
QPointF bottonTranslation(temp.p2());
// Rotate base of the arrowhead // Rotate base of the arrowhead
base.setLength(ArrowWidth + thickness*2); base.setLength(ArrowWidth + thickness * 2);
base.setAngle(base.angle() + 90); base.setAngle(base.angle() + 90);
// Move to the correct point // Move to the correct point
QPointF temp2 = p1 - base.p2(); QPointF temp2 = p1 - base.p2();
// Center it // Center it
QPointF centerTranslation((temp2.x()/2), (temp2.y()/2)); QPointF centerTranslation((temp2.x() / 2), (temp2.y() / 2));
base.translate(bottonTranslation); base.translate(bottonTranslation);
base.translate(centerTranslation); base.translate(centerTranslation);
QPainterPath path; QPainterPath path;
path.moveTo(p2); path.moveTo(p2);
path.lineTo(base.p1()); path.lineTo(base.p1());
path.lineTo(base.p2()); path.lineTo(base.p2());
path.lineTo(p2); path.lineTo(p2);
return path; return path;
} }
// gets a shorter line to prevent overlap in the point of the arrow // gets a shorter line to prevent overlap in the point of the arrow
QLine getShorterLine(QPoint p1, QPoint p2, const int thickness) { QLine
QLineF l(p1, p2); getShorterLine(QPoint p1, QPoint p2, const int thickness)
int val = ArrowHeight + thickness*4; {
if (l.length() < val) { QLineF l(p1, p2);
val = (l.length() + thickness*2); int val = ArrowHeight + thickness * 4;
} if (l.length() < val) {
l.setLength(l.length() + thickness*2 - val); val = (l.length() + thickness * 2);
return l.toLine(); }
l.setLength(l.length() + thickness * 2 - val);
return l.toLine();
} }
} // unnamed namespace } // unnamed namespace
ArrowTool::ArrowTool(QObject *parent) : AbstractTwoPointTool(parent) { ArrowTool::ArrowTool(QObject* parent)
m_padding = ArrowWidth / 2; : AbstractTwoPointTool(parent)
m_supportsOrthogonalAdj = true; {
m_supportsDiagonalAdj = true; m_padding = ArrowWidth / 2;
m_supportsOrthogonalAdj = true;
m_supportsDiagonalAdj = true;
} }
QIcon ArrowTool::icon(const QColor &background, bool inEditor) const { QIcon
Q_UNUSED(inEditor); ArrowTool::icon(const QColor& background, bool inEditor) const
return QIcon(iconPath(background) + "arrow-bottom-left.svg"); {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "arrow-bottom-left.svg");
} }
QString ArrowTool::name() const { QString
return tr("Arrow"); ArrowTool::name() const
{
return tr("Arrow");
} }
QString ArrowTool::nameID() { QString
return QLatin1String(""); ArrowTool::nameID()
{
return QLatin1String("");
} }
QString ArrowTool::description() const { QString
return tr("Set the Arrow as the paint tool"); ArrowTool::description() const
{
return tr("Set the Arrow as the paint tool");
} }
CaptureTool* ArrowTool::copy(QObject *parent) { CaptureTool*
return new ArrowTool(parent); ArrowTool::copy(QObject* parent)
{
return new ArrowTool(parent);
} }
void ArrowTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { ArrowTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
updateBackup(pixmap); {
} if (recordUndo) {
painter.setPen(QPen(m_color, m_thickness)); updateBackup(pixmap);
painter.drawLine(getShorterLine(m_points.first, m_points.second, m_thickness)); }
painter.fillPath(getArrowHead(m_points.first, m_points.second, m_thickness), QBrush(m_color)); painter.setPen(QPen(m_color, m_thickness));
painter.drawLine(
getShorterLine(m_points.first, m_points.second, m_thickness));
painter.fillPath(getArrowHead(m_points.first, m_points.second, m_thickness),
QBrush(m_color));
} }
void ArrowTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness)); ArrowTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
painter.drawLine(context.mousePos, context.mousePos); {
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness));
painter.drawLine(context.mousePos, context.mousePos);
} }
void ArrowTool::drawStart(const CaptureContext &context) { void
m_color = context.color; ArrowTool::drawStart(const CaptureContext& context)
m_thickness = context.thickness + PADDING_VALUE; {
m_points.first = context.mousePos; m_color = context.color;
m_points.second = context.mousePos; m_thickness = context.thickness + PADDING_VALUE;
m_points.first = context.mousePos;
m_points.second = context.mousePos;
} }
void ArrowTool::pressed(const CaptureContext &context) { void
Q_UNUSED(context); ArrowTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
} }

View File

@@ -21,22 +21,25 @@
#include <QPainter> #include <QPainter>
#include <QPainterPath> #include <QPainterPath>
class ArrowTool : public AbstractTwoPointTool { class ArrowTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit ArrowTool(QObject *parent = nullptr); explicit ArrowTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -23,41 +23,59 @@
#include <QImage> #include <QImage>
#include <QPainter> #include <QPainter>
BlurTool::BlurTool(QObject *parent) : AbstractTwoPointTool(parent) {} BlurTool::BlurTool(QObject* parent)
: AbstractTwoPointTool(parent)
{}
QIcon BlurTool::icon(const QColor &background, bool inEditor) const QIcon
BlurTool::icon(const QColor& background, bool inEditor) const
{ {
Q_UNUSED(inEditor); Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "blur.svg"); return QIcon(iconPath(background) + "blur.svg");
} }
QString BlurTool::name() const { return tr("Blur"); } QString
BlurTool::name() const
{
return tr("Blur");
}
QString BlurTool::nameID() { return QLatin1String(""); } QString
BlurTool::nameID()
{
return QLatin1String("");
}
QString BlurTool::description() const QString
BlurTool::description() const
{ {
return tr("Set Blur as the paint tool"); return tr("Set Blur as the paint tool");
} }
CaptureTool *BlurTool::copy(QObject *parent) { return new BlurTool(parent); } CaptureTool*
BlurTool::copy(QObject* parent)
{
return new BlurTool(parent);
}
void write_block(QImage &image, int x_start, int y_start, int pixel_size, void
QRgb block_color) write_block(QImage& image,
int x_start,
int y_start,
int pixel_size,
QRgb block_color)
{ {
assert(x_start + pixel_size < image.width()); assert(x_start + pixel_size < image.width());
assert(y_start + pixel_size < image.height()); assert(y_start + pixel_size < image.height());
for (auto x = x_start; x < x_start + pixel_size; x++) for (auto x = x_start; x < x_start + pixel_size; x++) {
{ for (auto y = y_start; y < y_start + pixel_size; y++) {
for (auto y = y_start; y < y_start + pixel_size; y++)
{
image.setPixel(x, y, block_color); image.setPixel(x, y, block_color);
} }
} }
} }
QRgb calculate_block_averge(QImage &image, int x_start, int y_start, QRgb
int pixel_size) calculate_block_averge(QImage& image, int x_start, int y_start, int pixel_size)
{ {
assert(x_start + pixel_size < image.width()); assert(x_start + pixel_size < image.width());
assert(y_start + pixel_size < image.height()); assert(y_start + pixel_size < image.height());
@@ -66,10 +84,8 @@ QRgb calculate_block_averge(QImage &image, int x_start, int y_start,
int blue_count = 0; int blue_count = 0;
int green_count = 0; int green_count = 0;
int pixel_count = 0; int pixel_count = 0;
for (auto x = x_start; x < x_start + pixel_size; x++) for (auto x = x_start; x < x_start + pixel_size; x++) {
{ for (auto y = y_start; y < y_start + pixel_size; y++) {
for (auto y = y_start; y < y_start + pixel_size; y++)
{
auto pixel = image.pixel(x, y); auto pixel = image.pixel(x, y);
red_count += qRed(pixel); red_count += qRed(pixel);
@@ -78,51 +94,46 @@ QRgb calculate_block_averge(QImage &image, int x_start, int y_start,
pixel_count++; pixel_count++;
} }
} }
return (qRgb(red_count / pixel_count, green_count / pixel_count, return (qRgb(red_count / pixel_count,
green_count / pixel_count,
blue_count / pixel_count)); blue_count / pixel_count));
} }
void BlurTool::process(QPainter &painter, const QPixmap &pixmap, void
bool recordUndo) BlurTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
{ {
if (recordUndo) if (recordUndo) {
{
updateBackup(pixmap); updateBackup(pixmap);
} }
QPoint &p0 = m_points.first; QPoint& p0 = m_points.first;
QPoint &p1 = m_points.second; QPoint& p1 = m_points.second;
auto pixelRatio = pixmap.devicePixelRatio(); auto pixelRatio = pixmap.devicePixelRatio();
QRect selection = QRect(p0, p1).normalized(); QRect selection = QRect(p0, p1).normalized();
QRect selectionScaled = QRect(p0 * pixelRatio, p1 * pixelRatio).normalized(); QRect selectionScaled = QRect(p0 * pixelRatio, p1 * pixelRatio).normalized();
QPixmap *source = new QPixmap(pixmap.copy(selectionScaled)); QPixmap* source = new QPixmap(pixmap.copy(selectionScaled));
QImage original_image{source->toImage()}; QImage original_image{ source->toImage() };
QImage imageResult{source->toImage()}; QImage imageResult{ source->toImage() };
unsigned int pixel_size = m_thickness; unsigned int pixel_size = m_thickness;
if (pixel_size < 1) if (pixel_size < 1) {
{ pixel_size = 1;
pixel_size =1;
} }
const unsigned int width = source->width(); const unsigned int width = source->width();
const unsigned int height = source->height(); const unsigned int height = source->height();
// Don't start pixelating until the region is at least as big as the pixel // Don't start pixelating until the region is at least as big as the pixel
if ((width > pixel_size) && (height > pixel_size)) if ((width > pixel_size) && (height > pixel_size)) {
{ for (unsigned int x = 0; x < (width - pixel_size); x += pixel_size) {
for (unsigned int x = 0; x < (width - pixel_size); x += pixel_size) for (unsigned int y = 0; y < (height - pixel_size); y += pixel_size) {
{
for (unsigned int y = 0; y < (height - pixel_size); y += pixel_size)
{
auto block_color = auto block_color =
calculate_block_averge(original_image, x, y, pixel_size); calculate_block_averge(original_image, x, y, pixel_size);
write_block(imageResult, x, y, pixel_size, block_color); write_block(imageResult, x, y, pixel_size, block_color);
} }
} }
} }
QPixmap result{QPixmap::fromImage(imageResult)}; QPixmap result{ QPixmap::fromImage(imageResult) };
QGraphicsScene scene; QGraphicsScene scene;
scene.addPixmap(result); scene.addPixmap(result);
@@ -130,18 +141,23 @@ void BlurTool::process(QPainter &painter, const QPixmap &pixmap,
scene.render(&painter, selection, QRectF()); scene.render(&painter, selection, QRectF());
} }
void BlurTool::paintMousePreview(QPainter &painter, void
const CaptureContext &context) BlurTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
{ {
Q_UNUSED(context); Q_UNUSED(context);
Q_UNUSED(painter); Q_UNUSED(painter);
} }
void BlurTool::drawStart(const CaptureContext &context) void
BlurTool::drawStart(const CaptureContext& context)
{ {
m_thickness = context.thickness; m_thickness = context.thickness;
m_points.first = context.mousePos; m_points.first = context.mousePos;
m_points.second = context.mousePos; m_points.second = context.mousePos;
} }
void BlurTool::pressed(const CaptureContext &context) { Q_UNUSED(context); } void
BlurTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
}

View File

@@ -19,22 +19,25 @@
#include "src/tools/abstracttwopointtool.h" #include "src/tools/abstracttwopointtool.h"
class BlurTool : public AbstractTwoPointTool { class BlurTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit BlurTool(QObject *parent = nullptr); explicit BlurTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -17,11 +17,12 @@
#include "capturecontext.h" #include "capturecontext.h"
QPixmap CaptureContext::selectedScreenshotArea() const { QPixmap
if (selection.isNull()) { CaptureContext::selectedScreenshotArea() const
return screenshot; {
} else { if (selection.isNull()) {
return screenshot.copy(selection); return screenshot;
} } else {
return screenshot.copy(selection);
}
} }

View File

@@ -17,33 +17,34 @@
#pragma once #pragma once
#include <QRect>
#include <QPoint>
#include <QPixmap>
#include <QPainter> #include <QPainter>
#include <QPixmap>
#include <QPoint>
#include <QRect>
struct CaptureContext { struct CaptureContext
// screenshot with modifications {
QPixmap screenshot; // screenshot with modifications
// unmodified screenshot QPixmap screenshot;
QPixmap origScreenshot; // unmodified screenshot
// Selection area QPixmap origScreenshot;
QRect selection; // Selection area
// Widget dimensions QRect selection;
QRect widgetDimensions; // Widget dimensions
// Selected tool color QRect widgetDimensions;
QColor color; // Selected tool color
// Path where the content has to be saved QColor color;
QString savePath; // Path where the content has to be saved
// Ofset of the capture widget based on the system's screen (top-left) QString savePath;
QPoint widgetOffset; // Ofset of the capture widget based on the system's screen (top-left)
// Mouse position inside the widget QPoint widgetOffset;
QPoint mousePos; // Mouse position inside the widget
// Value of the desired thickness QPoint mousePos;
int thickness; // Value of the desired thickness
int circleCount; int thickness;
// Mode of the capture widget int circleCount;
bool fullscreen; // Mode of the capture widget
bool fullscreen;
QPixmap selectedScreenshotArea() const ; QPixmap selectedScreenshotArea() const;
}; };

View File

@@ -23,131 +23,128 @@
#include <QIcon> #include <QIcon>
#include <QPainter> #include <QPainter>
class CaptureTool : public QObject { class CaptureTool : public QObject
Q_OBJECT {
Q_OBJECT
public: public:
// Request actions on the main widget // Request actions on the main widget
enum Request { enum Request
// Call close() in the editor. {
REQ_CLOSE_GUI, // Call close() in the editor.
// Call hide() in the editor. REQ_CLOSE_GUI,
REQ_HIDE_GUI, // Call hide() in the editor.
// Select the whole screen. REQ_HIDE_GUI,
REQ_SELECT_ALL, // Select the whole screen.
// Disable the selection. REQ_SELECT_ALL,
REQ_HIDE_SELECTION, // Disable the selection.
// Undo the last active modification in the stack. REQ_HIDE_SELECTION,
REQ_UNDO_MODIFICATION, // Undo the last active modification in the stack.
// Redo the next modification in the stack. REQ_UNDO_MODIFICATION,
REQ_REDO_MODIFICATION, // Redo the next modification in the stack.
// Remove all the modifications. REQ_REDO_MODIFICATION,
REQ_CLEAR_MODIFICATIONS, // Remove all the modifications.
// Disable the active tool. REQ_CLEAR_MODIFICATIONS,
REQ_MOVE_MODE, // Disable the active tool.
// Open the color picker under the mouse. REQ_MOVE_MODE,
REQ_SHOW_COLOR_PICKER, // Open the color picker under the mouse.
// Open/Close the side-panel. REQ_SHOW_COLOR_PICKER,
REQ_TOGGLE_SIDEBAR, // Open/Close the side-panel.
// Call update() in the editor. REQ_TOGGLE_SIDEBAR,
REQ_REDRAW, // Call update() in the editor.
// Append this tool to the undo/redo stack REQ_REDRAW,
REQ_APPEND_TO_STACK, // Append this tool to the undo/redo stack
// Notify is the screenshot has been saved. REQ_APPEND_TO_STACK,
REQ_CAPTURE_DONE_OK, // Notify is the screenshot has been saved.
// Instance this->widget()'s widget inside the editor under the mouse. REQ_CAPTURE_DONE_OK,
REQ_ADD_CHILD_WIDGET, // Instance this->widget()'s widget inside the editor under the mouse.
// Instance this->widget()'s widget as a window which closes after REQ_ADD_CHILD_WIDGET,
// closing the editor. // Instance this->widget()'s widget as a window which closes after
REQ_ADD_CHILD_WINDOW, // closing the editor.
// Instance this->widget()'s widget which handles its own lifetime. REQ_ADD_CHILD_WINDOW,
REQ_ADD_EXTERNAL_WIDGETS, // Instance this->widget()'s widget which handles its own lifetime.
REQ_ADD_EXTERNAL_WIDGETS,
REQ_INCREMENT_CIRCLE_COUNT, REQ_INCREMENT_CIRCLE_COUNT,
}; };
explicit CaptureTool(QObject *parent = nullptr) : QObject(parent){} explicit CaptureTool(QObject* parent = nullptr)
: QObject(parent)
{}
// Returns false when the tool is in an inconsistent state and shouldn't // Returns false when the tool is in an inconsistent state and shouldn't
// be included in the tool undo/redo stack. // be included in the tool undo/redo stack.
virtual bool isValid() const = 0; virtual bool isValid() const = 0;
// Close the capture after the process() call if the tool was activated // Close the capture after the process() call if the tool was activated
// from a button press. // from a button press.
virtual bool closeOnButtonPressed() const = 0; virtual bool closeOnButtonPressed() const = 0;
// If the tool keeps active after the selection. // If the tool keeps active after the selection.
virtual bool isSelectable() const = 0; virtual bool isSelectable() const = 0;
// Enable mouse preview. // Enable mouse preview.
virtual bool showMousePreview() const = 0; virtual bool showMousePreview() const = 0;
// The icon of the tool. // The icon of the tool.
// inEditor is true when the icon is requested inside the editor // inEditor is true when the icon is requested inside the editor
// and false otherwise. // and false otherwise.
virtual QIcon icon(const QColor &background, virtual QIcon icon(const QColor& background, bool inEditor) const = 0;
bool inEditor) const = 0; // Name displayed for the tool, this could be translated with tr()
// Name displayed for the tool, this could be translated with tr() virtual QString name() const = 0;
virtual QString name() const = 0; // Codename for the tool, this hsouldn't change as it is used as ID
// Codename for the tool, this hsouldn't change as it is used as ID // for the tool in the internals of Flameshot
// for the tool in the internals of Flameshot static QString nameID();
static QString nameID(); // Short description of the tool.
// Short description of the tool. virtual QString description() const = 0;
virtual QString description() const = 0;
// if the type is TYPE_WIDGET the widget is loaded in the main widget. // if the type is TYPE_WIDGET the widget is loaded in the main widget.
// If the type is TYPE_EXTERNAL_WIDGET it is created outside as an // If the type is TYPE_EXTERNAL_WIDGET it is created outside as an
// individual widget. // individual widget.
virtual QWidget* widget() { virtual QWidget* widget() { return nullptr; }
return nullptr; // When the tool is selected this method is called and the widget is added
} // to the configuration panel inside the main widget.
// When the tool is selected this method is called and the widget is added virtual QWidget* configurationWidget() { return nullptr; }
// to the configuration panel inside the main widget. // Permanent configuration used in the configuration outside of the
virtual QWidget* configurationWidget() { // capture.
return nullptr; virtual QWidget* permanentConfigurationWidget() { return nullptr; }
} // Return a copy of the tool
// Permanent configuration used in the configuration outside of the virtual CaptureTool* copy(QObject* parent = nullptr) = 0;
// capture.
virtual QWidget* permanentConfigurationWidget() {
return nullptr;
}
// Return a copy of the tool
virtual CaptureTool* copy(QObject *parent = nullptr) = 0;
// revert changes // revert changes
virtual void undo(QPixmap &pixmap) = 0; virtual void undo(QPixmap& pixmap) = 0;
// Called every time the tool has to draw // Called every time the tool has to draw
// recordUndo indicates when the tool should save the information // recordUndo indicates when the tool should save the information
// for the undo(), if the value is false calling undo() after // for the undo(), if the value is false calling undo() after
// that process should not modify revert the changes. // that process should not modify revert the changes.
virtual void process(QPainter &painter, virtual void process(QPainter& painter,
const QPixmap &pixmap, const QPixmap& pixmap,
bool recordUndo = false) = 0; bool recordUndo = false) = 0;
// When the tool is selected, this is called when the mouse moves // When the tool is selected, this is called when the mouse moves
virtual void paintMousePreview(QPainter &painter, const CaptureContext &context) = 0; virtual void paintMousePreview(QPainter& painter,
const CaptureContext& context) = 0;
signals: signals:
void requestAction(Request r); void requestAction(Request r);
protected: protected:
QString iconPath(const QColor &c) const { QString iconPath(const QColor& c) const
return ColorUtils::colorIsDark(c) ? {
PathInfo::whiteIconPath() : PathInfo::blackIconPath(); return ColorUtils::colorIsDark(c) ? PathInfo::whiteIconPath()
} : PathInfo::blackIconPath();
}
public slots: public slots:
// On mouse release. // On mouse release.
virtual void drawEnd(const QPoint &p) = 0; virtual void drawEnd(const QPoint& p) = 0;
// Mouse pressed and moving, called once a pixel. // Mouse pressed and moving, called once a pixel.
virtual void drawMove(const QPoint &p) = 0; virtual void drawMove(const QPoint& p) = 0;
// Called when drawMove is needed with an adjustment; // Called when drawMove is needed with an adjustment;
// should be overridden in case an adjustment is applicable. // should be overridden in case an adjustment is applicable.
virtual void drawMoveWithAdjustment(const QPoint &p) { virtual void drawMoveWithAdjustment(const QPoint& p) { drawMove(p); }
drawMove(p); // Called when the tool is activated.
} virtual void drawStart(const CaptureContext& context) = 0;
// Called when the tool is activated. // Called right after pressign the button which activates the tool.
virtual void drawStart(const CaptureContext &context) = 0; virtual void pressed(const CaptureContext& context) = 0;
// Called right after pressign the button which activates the tool. // Called when the color is changed in the editor.
virtual void pressed(const CaptureContext &context) = 0; virtual void colorChanged(const QColor& c) = 0;
// Called when the color is changed in the editor. // Called when the thickness of the tool is updated in the editor.
virtual void colorChanged(const QColor &c) = 0; virtual void thicknessChanged(const int th) = 0;
// Called when the thickness of the tool is updated in the editor.
virtual void thicknessChanged(const int th) = 0;
}; };

View File

@@ -22,50 +22,70 @@ namespace {
#define PADDING_VALUE 2 #define PADDING_VALUE 2
} }
CircleTool::CircleTool(QObject *parent) : AbstractTwoPointTool(parent) { CircleTool::CircleTool(QObject* parent)
m_supportsDiagonalAdj = true; : AbstractTwoPointTool(parent)
{
m_supportsDiagonalAdj = true;
} }
QIcon CircleTool::icon(const QColor &background, bool inEditor) const { QIcon
Q_UNUSED(inEditor); CircleTool::icon(const QColor& background, bool inEditor) const
return QIcon(iconPath(background) + "circle-outline.svg"); {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "circle-outline.svg");
} }
QString CircleTool::name() const { QString
return tr("Circle"); CircleTool::name() const
{
return tr("Circle");
} }
QString CircleTool::nameID() { QString
return QLatin1String(""); CircleTool::nameID()
{
return QLatin1String("");
} }
QString CircleTool::description() const { QString
return tr("Set the Circle as the paint tool"); CircleTool::description() const
{
return tr("Set the Circle as the paint tool");
} }
CaptureTool* CircleTool::copy(QObject *parent) { CaptureTool*
return new CircleTool(parent); CircleTool::copy(QObject* parent)
{
return new CircleTool(parent);
} }
void CircleTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { CircleTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
updateBackup(pixmap); {
} if (recordUndo) {
painter.setPen(QPen(m_color, m_thickness)); updateBackup(pixmap);
painter.drawEllipse(QRect(m_points.first, m_points.second)); }
painter.setPen(QPen(m_color, m_thickness));
painter.drawEllipse(QRect(m_points.first, m_points.second));
} }
void CircleTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness)); CircleTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
painter.drawLine(context.mousePos, context.mousePos); {
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness));
painter.drawLine(context.mousePos, context.mousePos);
} }
void CircleTool::drawStart(const CaptureContext &context) { void
m_color = context.color; CircleTool::drawStart(const CaptureContext& context)
m_thickness = context.thickness + PADDING_VALUE; {
m_points.first = context.mousePos; m_color = context.color;
m_points.second = context.mousePos; m_thickness = context.thickness + PADDING_VALUE;
m_points.first = context.mousePos;
m_points.second = context.mousePos;
} }
void CircleTool::pressed(const CaptureContext &context) { void
Q_UNUSED(context); CircleTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
} }

View File

@@ -19,22 +19,25 @@
#include "src/tools/abstracttwopointtool.h" #include "src/tools/abstracttwopointtool.h"
class CircleTool : public AbstractTwoPointTool { class CircleTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit CircleTool(QObject *parent = nullptr); explicit CircleTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -21,55 +21,82 @@ namespace {
#define PADDING_VALUE 2 #define PADDING_VALUE 2
} }
CircleCountTool::CircleCountTool(QObject *parent) : AbstractTwoPointTool(parent) { CircleCountTool::CircleCountTool(QObject* parent)
m_count = 0; : AbstractTwoPointTool(parent)
{
m_count = 0;
} }
QIcon CircleCountTool::icon(const QColor &background, bool inEditor) const { QIcon
Q_UNUSED(inEditor); CircleCountTool::icon(const QColor& background, bool inEditor) const
return QIcon(iconPath(background) + "circlecount-outline.svg"); {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "circlecount-outline.svg");
} }
QString CircleCountTool::name() const { QString
return tr("Circle Counter"); CircleCountTool::name() const
{
return tr("Circle Counter");
} }
QString CircleCountTool::nameID() { QString
return QLatin1String(""); CircleCountTool::nameID()
{
return QLatin1String("");
} }
QString CircleCountTool::description() const { QString
return tr("Add an autoincrementing counter bubble"); CircleCountTool::description() const
{
return tr("Add an autoincrementing counter bubble");
} }
CaptureTool* CircleCountTool::copy(QObject *parent) { CaptureTool*
return new CircleCountTool(parent); CircleCountTool::copy(QObject* parent)
{
return new CircleCountTool(parent);
} }
void CircleCountTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { CircleCountTool::process(QPainter& painter,
updateBackup(pixmap); const QPixmap& pixmap,
} bool recordUndo)
painter.setBrush(m_color); {
if (recordUndo) {
updateBackup(pixmap);
}
painter.setBrush(m_color);
int bubble_size=16; int bubble_size = 16;
painter.drawEllipse(m_points.first,bubble_size,bubble_size); painter.drawEllipse(m_points.first, bubble_size, bubble_size);
painter.drawText(QRectF(m_points.first.x()-bubble_size/2, m_points.first.y()-bubble_size/2, bubble_size, bubble_size), Qt::AlignCenter, QString::number(m_count)); painter.drawText(QRectF(m_points.first.x() - bubble_size / 2,
m_points.first.y() - bubble_size / 2,
bubble_size,
bubble_size),
Qt::AlignCenter,
QString::number(m_count));
} }
void CircleCountTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness)); CircleCountTool::paintMousePreview(QPainter& painter,
painter.drawLine(context.mousePos, context.mousePos); const CaptureContext& context)
{
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness));
painter.drawLine(context.mousePos, context.mousePos);
} }
void CircleCountTool::drawStart(const CaptureContext &context) { void
m_color = context.color; CircleCountTool::drawStart(const CaptureContext& context)
m_thickness = context.thickness + PADDING_VALUE; {
m_points.first = context.mousePos; m_color = context.color;
m_count = context.circleCount; m_thickness = context.thickness + PADDING_VALUE;
emit requestAction(REQ_INCREMENT_CIRCLE_COUNT); m_points.first = context.mousePos;
m_count = context.circleCount;
emit requestAction(REQ_INCREMENT_CIRCLE_COUNT);
} }
void CircleCountTool::pressed(const CaptureContext &context) { void
Q_UNUSED(context); CircleCountTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
} }

View File

@@ -19,23 +19,27 @@
#include "src/tools/abstracttwopointtool.h" #include "src/tools/abstracttwopointtool.h"
class CircleCountTool : public AbstractTwoPointTool { class CircleCountTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit CircleCountTool(QObject *parent = nullptr); explicit CircleCountTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject* parent = nullptr) override;
void process(QPainter& painter,
const QPixmap& pixmap,
bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
CaptureTool* copy(QObject *parent = nullptr) override;
void process(
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override;
void paintMousePreview(QPainter &painter, const CaptureContext &context) override;
private: private:
unsigned int m_count; unsigned int m_count;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -19,35 +19,49 @@
#include "src/utils/screenshotsaver.h" #include "src/utils/screenshotsaver.h"
#include <QPainter> #include <QPainter>
CopyTool::CopyTool(QObject *parent) : AbstractActionTool(parent) { CopyTool::CopyTool(QObject* parent)
: AbstractActionTool(parent)
{}
bool
CopyTool::closeOnButtonPressed() const
{
return true;
} }
bool CopyTool::closeOnButtonPressed() const { QIcon
return true; CopyTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "content-copy.svg");
}
QString
CopyTool::name() const
{
return tr("Copy");
} }
QIcon CopyTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); CopyTool::nameID()
return QIcon(iconPath(background) + "content-copy.svg"); {
} return QLatin1String("");
QString CopyTool::name() const {
return tr("Copy");
} }
QString CopyTool::nameID() { QString
return QLatin1String(""); CopyTool::description() const
{
return tr("Copy the selection into the clipboard");
} }
QString CopyTool::description() const { CaptureTool*
return tr("Copy the selection into the clipboard"); CopyTool::copy(QObject* parent)
{
return new CopyTool(parent);
} }
CaptureTool* CopyTool::copy(QObject *parent) { void
return new CopyTool(parent); CopyTool::pressed(const CaptureContext& context)
} {
emit requestAction(REQ_CAPTURE_DONE_OK);
void CopyTool::pressed(const CaptureContext &context) { ScreenshotSaver().saveToClipboard(context.selectedScreenshotArea());
emit requestAction(REQ_CAPTURE_DONE_OK);
ScreenshotSaver().saveToClipboard(context.selectedScreenshotArea());
} }

View File

@@ -19,20 +19,21 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class CopyTool : public AbstractActionTool { class CopyTool : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit CopyTool(QObject *parent = nullptr); explicit CopyTool(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -18,35 +18,49 @@
#include "exittool.h" #include "exittool.h"
#include <QPainter> #include <QPainter>
ExitTool::ExitTool(QObject *parent) : AbstractActionTool(parent) { ExitTool::ExitTool(QObject* parent)
: AbstractActionTool(parent)
{}
bool
ExitTool::closeOnButtonPressed() const
{
return true;
} }
bool ExitTool::closeOnButtonPressed() const { QIcon
return true; ExitTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "close.svg");
}
QString
ExitTool::name() const
{
return tr("Exit");
} }
QIcon ExitTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); ExitTool::nameID()
return QIcon(iconPath(background) + "close.svg"); {
} return QLatin1String("");
QString ExitTool::name() const {
return tr("Exit");
} }
QString ExitTool::nameID() { QString
return QLatin1String(""); ExitTool::description() const
{
return tr("Leave the capture screen");
} }
QString ExitTool::description() const { CaptureTool*
return tr("Leave the capture screen"); ExitTool::copy(QObject* parent)
{
return new ExitTool(parent);
} }
CaptureTool* ExitTool::copy(QObject *parent) { void
return new ExitTool(parent); ExitTool::pressed(const CaptureContext& context)
} {
Q_UNUSED(context);
void ExitTool::pressed(const CaptureContext &context) { emit requestAction(REQ_CLOSE_GUI);
Q_UNUSED(context);
emit requestAction(REQ_CLOSE_GUI);
} }

View File

@@ -19,20 +19,21 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class ExitTool : public AbstractActionTool { class ExitTool : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit ExitTool(QObject *parent = nullptr); explicit ExitTool(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -16,167 +16,194 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "imguruploader.h" #include "imguruploader.h"
#include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h" #include "src/utils/filenamehandler.h"
#include "src/utils/systemnotification.h" #include "src/utils/systemnotification.h"
#include "src/widgets/loadspinner.h"
#include "src/widgets/imagelabel.h" #include "src/widgets/imagelabel.h"
#include "src/widgets/loadspinner.h"
#include "src/widgets/notificationwidget.h" #include "src/widgets/notificationwidget.h"
#include "src/utils/confighandler.h"
#include <QApplication> #include <QApplication>
#include <QBuffer>
#include <QClipboard> #include <QClipboard>
#include <QDesktopServices> #include <QDesktopServices>
#include <QShortcut>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QDrag> #include <QDrag>
#include <QMimeData> #include <QHBoxLayout>
#include <QBuffer>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QLabel>
#include <QMimeData>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QPushButton>
#include <QShortcut>
#include <QTimer>
#include <QUrlQuery>
#include <QVBoxLayout>
ImgurUploader::ImgurUploader(const QPixmap &capture, QWidget *parent) : ImgurUploader::ImgurUploader(const QPixmap& capture, QWidget* parent)
QWidget(parent), m_pixmap(capture) : QWidget(parent)
, m_pixmap(capture)
{ {
setWindowTitle(tr("Upload to Imgur")); setWindowTitle(tr("Upload to Imgur"));
setWindowIcon(QIcon(":img/app/flameshot.svg")); setWindowIcon(QIcon(":img/app/flameshot.svg"));
m_spinner = new LoadSpinner(this); m_spinner = new LoadSpinner(this);
m_spinner->setColor(ConfigHandler().uiMainColorValue()); m_spinner->setColor(ConfigHandler().uiMainColorValue());
m_spinner->start(); m_spinner->start();
m_infoLabel = new QLabel(tr("Uploading Image")); m_infoLabel = new QLabel(tr("Uploading Image"));
m_vLayout = new QVBoxLayout(); m_vLayout = new QVBoxLayout();
setLayout(m_vLayout); setLayout(m_vLayout);
m_vLayout->addWidget(m_spinner, 0, Qt::AlignHCenter); m_vLayout->addWidget(m_spinner, 0, Qt::AlignHCenter);
m_vLayout->addWidget(m_infoLabel); m_vLayout->addWidget(m_infoLabel);
m_NetworkAM = new QNetworkAccessManager(this); m_NetworkAM = new QNetworkAccessManager(this);
connect(m_NetworkAM, &QNetworkAccessManager::finished, this, connect(m_NetworkAM,
&ImgurUploader::handleReply); &QNetworkAccessManager::finished,
this,
&ImgurUploader::handleReply);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
upload(); upload();
// QTimer::singleShot(2000, this, &ImgurUploader::onUploadOk); // testing // QTimer::singleShot(2000, this, &ImgurUploader::onUploadOk); // testing
} }
void ImgurUploader::handleReply(QNetworkReply *reply) { void
m_spinner->deleteLater(); ImgurUploader::handleReply(QNetworkReply* reply)
if (reply->error() == QNetworkReply::NoError) { {
QJsonDocument response = QJsonDocument::fromJson(reply->readAll()); m_spinner->deleteLater();
QJsonObject json = response.object(); if (reply->error() == QNetworkReply::NoError) {
QJsonObject data = json[QStringLiteral("data")].toObject(); QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
m_imageURL.setUrl(data[QStringLiteral("link")].toString()); QJsonObject json = response.object();
m_deleteImageURL.setUrl(QStringLiteral("https://imgur.com/delete/%1").arg( QJsonObject data = json[QStringLiteral("data")].toObject();
data[QStringLiteral("deletehash")].toString())); m_imageURL.setUrl(data[QStringLiteral("link")].toString());
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) { m_deleteImageURL.setUrl(
QApplication::clipboard()->setText(m_imageURL.toString()); QStringLiteral("https://imgur.com/delete/%1")
SystemNotification().sendMessage(QObject::tr("URL copied to clipboard.")); .arg(data[QStringLiteral("deletehash")].toString()));
close(); if (ConfigHandler().copyAndCloseAfterUploadEnabled()) {
} else { QApplication::clipboard()->setText(m_imageURL.toString());
onUploadOk(); SystemNotification().sendMessage(QObject::tr("URL copied to clipboard."));
} close();
} else { } else {
m_infoLabel->setText(reply->errorString()); onUploadOk();
} }
new QShortcut(Qt::Key_Escape, this, SLOT(close())); } else {
m_infoLabel->setText(reply->errorString());
}
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
} }
void ImgurUploader::startDrag() { void
QMimeData *mimeData = new QMimeData; ImgurUploader::startDrag()
mimeData->setUrls(QList<QUrl> { m_imageURL });
mimeData->setImageData(m_pixmap);
QDrag *dragHandler = new QDrag(this);
dragHandler->setMimeData(mimeData);
dragHandler->setPixmap(m_pixmap.scaled(256, 256, Qt::KeepAspectRatioByExpanding,
Qt::SmoothTransformation));
dragHandler->exec();
}
void ImgurUploader::upload() {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_pixmap.save(&buffer, "PNG");
QUrlQuery urlQuery;
urlQuery.addQueryItem(QStringLiteral("title"), QStringLiteral("flameshot_screenshot"));
QString description = FileNameHandler().parsedPattern();
urlQuery.addQueryItem(QStringLiteral("description"), description);
QUrl url(QStringLiteral("https://api.imgur.com/3/image"));
url.setQuery(urlQuery);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/application/x-www-form-urlencoded");
request.setRawHeader("Authorization", QStringLiteral("Client-ID %1").arg(IMGUR_CLIENT_ID).toUtf8());
m_NetworkAM->post(request, byteArray);
}
void ImgurUploader::onUploadOk() {
m_infoLabel->deleteLater();
m_notification = new NotificationWidget();
m_vLayout->addWidget(m_notification);
ImageLabel *imageLabel = new ImageLabel();
imageLabel->setScreenshot(m_pixmap);
imageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(imageLabel, &ImageLabel::dragInitiated, this, &ImgurUploader::startDrag);
m_vLayout->addWidget(imageLabel);
m_hLayout = new QHBoxLayout();
m_vLayout->addLayout(m_hLayout);
m_copyUrlButton = new QPushButton(tr("Copy URL"));
m_openUrlButton = new QPushButton(tr("Open URL"));
m_openDeleteUrlButton = new QPushButton(tr("Delete image"));
m_toClipboardButton = new QPushButton(tr("Image to Clipboard."));
m_hLayout->addWidget(m_copyUrlButton);
m_hLayout->addWidget(m_openUrlButton);
m_hLayout->addWidget(m_openDeleteUrlButton);
m_hLayout->addWidget(m_toClipboardButton);
connect(m_copyUrlButton, &QPushButton::clicked,
this, &ImgurUploader::copyURL);
connect(m_openUrlButton, &QPushButton::clicked,
this, &ImgurUploader::openURL);
connect(m_openDeleteUrlButton, &QPushButton::clicked,
this, &ImgurUploader::openDeleteURL);
connect(m_toClipboardButton, &QPushButton::clicked,
this, &ImgurUploader::copyImage);
}
void ImgurUploader::openURL() {
bool successful = QDesktopServices::openUrl(m_imageURL);
if (!successful) {
m_notification->showMessage(tr("Unable to open the URL."));
}
}
void ImgurUploader::copyURL() {
QApplication::clipboard()->setText(m_imageURL.toString());
m_notification->showMessage(tr("URL copied to clipboard."));
}
void ImgurUploader::openDeleteURL()
{ {
bool successful = QDesktopServices::openUrl(m_deleteImageURL); QMimeData* mimeData = new QMimeData;
if (!successful) { mimeData->setUrls(QList<QUrl>{ m_imageURL });
m_notification->showMessage(tr("Unable to open the URL.")); mimeData->setImageData(m_pixmap);
}
QDrag* dragHandler = new QDrag(this);
dragHandler->setMimeData(mimeData);
dragHandler->setPixmap(m_pixmap.scaled(
256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
dragHandler->exec();
} }
void ImgurUploader::copyImage() { void
QApplication::clipboard()->setPixmap(m_pixmap); ImgurUploader::upload()
m_notification->showMessage(tr("Screenshot copied to clipboard.")); {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_pixmap.save(&buffer, "PNG");
QUrlQuery urlQuery;
urlQuery.addQueryItem(QStringLiteral("title"),
QStringLiteral("flameshot_screenshot"));
QString description = FileNameHandler().parsedPattern();
urlQuery.addQueryItem(QStringLiteral("description"), description);
QUrl url(QStringLiteral("https://api.imgur.com/3/image"));
url.setQuery(urlQuery);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/application/x-www-form-urlencoded");
request.setRawHeader(
"Authorization",
QStringLiteral("Client-ID %1").arg(IMGUR_CLIENT_ID).toUtf8());
m_NetworkAM->post(request, byteArray);
}
void
ImgurUploader::onUploadOk()
{
m_infoLabel->deleteLater();
m_notification = new NotificationWidget();
m_vLayout->addWidget(m_notification);
ImageLabel* imageLabel = new ImageLabel();
imageLabel->setScreenshot(m_pixmap);
imageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(
imageLabel, &ImageLabel::dragInitiated, this, &ImgurUploader::startDrag);
m_vLayout->addWidget(imageLabel);
m_hLayout = new QHBoxLayout();
m_vLayout->addLayout(m_hLayout);
m_copyUrlButton = new QPushButton(tr("Copy URL"));
m_openUrlButton = new QPushButton(tr("Open URL"));
m_openDeleteUrlButton = new QPushButton(tr("Delete image"));
m_toClipboardButton = new QPushButton(tr("Image to Clipboard."));
m_hLayout->addWidget(m_copyUrlButton);
m_hLayout->addWidget(m_openUrlButton);
m_hLayout->addWidget(m_openDeleteUrlButton);
m_hLayout->addWidget(m_toClipboardButton);
connect(
m_copyUrlButton, &QPushButton::clicked, this, &ImgurUploader::copyURL);
connect(
m_openUrlButton, &QPushButton::clicked, this, &ImgurUploader::openURL);
connect(m_openDeleteUrlButton,
&QPushButton::clicked,
this,
&ImgurUploader::openDeleteURL);
connect(m_toClipboardButton,
&QPushButton::clicked,
this,
&ImgurUploader::copyImage);
}
void
ImgurUploader::openURL()
{
bool successful = QDesktopServices::openUrl(m_imageURL);
if (!successful) {
m_notification->showMessage(tr("Unable to open the URL."));
}
}
void
ImgurUploader::copyURL()
{
QApplication::clipboard()->setText(m_imageURL.toString());
m_notification->showMessage(tr("URL copied to clipboard."));
}
void
ImgurUploader::openDeleteURL()
{
bool successful = QDesktopServices::openUrl(m_deleteImageURL);
if (!successful) {
m_notification->showMessage(tr("Unable to open the URL."));
}
}
void
ImgurUploader::copyImage()
{
QApplication::clipboard()->setPixmap(m_pixmap);
m_notification->showMessage(tr("Screenshot copied to clipboard."));
} }

View File

@@ -17,8 +17,8 @@
#pragma once #pragma once
#include <QWidget>
#include <QUrl> #include <QUrl>
#include <QWidget>
class QNetworkReply; class QNetworkReply;
class QNetworkAccessManager; class QNetworkAccessManager;
@@ -30,38 +30,39 @@ class QPushButton;
class QUrl; class QUrl;
class NotificationWidget; class NotificationWidget;
class ImgurUploader : public QWidget { class ImgurUploader : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit ImgurUploader(const QPixmap &capture, QWidget *parent = nullptr); explicit ImgurUploader(const QPixmap& capture, QWidget* parent = nullptr);
private slots: private slots:
void handleReply(QNetworkReply *reply); void handleReply(QNetworkReply* reply);
void startDrag(); void startDrag();
void openURL(); void openURL();
void copyURL(); void copyURL();
void openDeleteURL(); void openDeleteURL();
void copyImage(); void copyImage();
private: private:
QPixmap m_pixmap; QPixmap m_pixmap;
QNetworkAccessManager *m_NetworkAM; QNetworkAccessManager* m_NetworkAM;
QVBoxLayout *m_vLayout; QVBoxLayout* m_vLayout;
QHBoxLayout *m_hLayout; QHBoxLayout* m_hLayout;
// loading // loading
QLabel *m_infoLabel; QLabel* m_infoLabel;
LoadSpinner *m_spinner; LoadSpinner* m_spinner;
// uploaded // uploaded
QPushButton *m_openUrlButton; QPushButton* m_openUrlButton;
QPushButton *m_openDeleteUrlButton; QPushButton* m_openDeleteUrlButton;
QPushButton *m_copyUrlButton; QPushButton* m_copyUrlButton;
QPushButton *m_toClipboardButton; QPushButton* m_toClipboardButton;
QUrl m_imageURL; QUrl m_imageURL;
QUrl m_deleteImageURL; QUrl m_deleteImageURL;
NotificationWidget *m_notification; NotificationWidget* m_notification;
void upload(); void upload();
void onUploadOk(); void onUploadOk();
}; };

View File

@@ -19,40 +19,56 @@
#include "imguruploader.h" #include "imguruploader.h"
#include <QPainter> #include <QPainter>
ImgurUploaderTool::ImgurUploaderTool(QObject *parent) : AbstractActionTool(parent) { ImgurUploaderTool::ImgurUploaderTool(QObject* parent)
: AbstractActionTool(parent)
{}
bool
ImgurUploaderTool::closeOnButtonPressed() const
{
return true;
} }
bool ImgurUploaderTool::closeOnButtonPressed() const { QIcon
return true; ImgurUploaderTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "cloud-upload.svg");
}
QString
ImgurUploaderTool::name() const
{
return tr("Image Uploader");
} }
QIcon ImgurUploaderTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); ImgurUploaderTool::nameID()
return QIcon(iconPath(background) + "cloud-upload.svg"); {
} return QLatin1String("");
QString ImgurUploaderTool::name() const {
return tr("Image Uploader");
} }
QString ImgurUploaderTool::nameID() { QString
return QLatin1String(""); ImgurUploaderTool::description() const
{
return tr("Upload the selection to Imgur");
} }
QString ImgurUploaderTool::description() const { QWidget*
return tr("Upload the selection to Imgur"); ImgurUploaderTool::widget()
{
return new ImgurUploader(capture);
} }
QWidget* ImgurUploaderTool::widget() { CaptureTool*
return new ImgurUploader(capture); ImgurUploaderTool::copy(QObject* parent)
{
return new ImgurUploaderTool(parent);
} }
CaptureTool* ImgurUploaderTool::copy(QObject *parent) { void
return new ImgurUploaderTool(parent); ImgurUploaderTool::pressed(const CaptureContext& context)
} {
capture = context.selectedScreenshotArea();
void ImgurUploaderTool::pressed(const CaptureContext &context) { emit requestAction(REQ_CAPTURE_DONE_OK);
capture = context.selectedScreenshotArea(); emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
emit requestAction(REQ_CAPTURE_DONE_OK);
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
} }

View File

@@ -19,25 +19,26 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class ImgurUploaderTool : public AbstractActionTool { class ImgurUploaderTool : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit ImgurUploaderTool(QObject *parent = nullptr); explicit ImgurUploaderTool(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
QWidget* widget() override; QWidget* widget() override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
private: private:
QPixmap capture; QPixmap capture;
}; };

View File

@@ -18,40 +18,56 @@
#include "applaunchertool.h" #include "applaunchertool.h"
#include "applauncherwidget.h" #include "applauncherwidget.h"
AppLauncher::AppLauncher(QObject *parent) : AbstractActionTool(parent) { AppLauncher::AppLauncher(QObject* parent)
: AbstractActionTool(parent)
{}
bool
AppLauncher::closeOnButtonPressed() const
{
return true;
} }
bool AppLauncher::closeOnButtonPressed() const { QIcon
return true; AppLauncher::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "open_with.svg");
}
QString
AppLauncher::name() const
{
return tr("App Launcher");
} }
QIcon AppLauncher::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); AppLauncher::nameID()
return QIcon(iconPath(background) + "open_with.svg"); {
} return QLatin1String("");
QString AppLauncher::name() const {
return tr("App Launcher");
} }
QString AppLauncher::nameID() { QString
return QLatin1String(""); AppLauncher::description() const
{
return tr("Choose an app to open the capture");
} }
QString AppLauncher::description() const { QWidget*
return tr("Choose an app to open the capture"); AppLauncher::widget()
{
return new AppLauncherWidget(capture);
} }
QWidget* AppLauncher::widget() { CaptureTool*
return new AppLauncherWidget(capture); AppLauncher::copy(QObject* parent)
{
return new AppLauncher(parent);
} }
CaptureTool* AppLauncher::copy(QObject *parent) { void
return new AppLauncher(parent); AppLauncher::pressed(const CaptureContext& context)
} {
capture = context.selectedScreenshotArea();
void AppLauncher::pressed(const CaptureContext &context) { emit requestAction(REQ_CAPTURE_DONE_OK);
capture = context.selectedScreenshotArea(); emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
emit requestAction(REQ_CAPTURE_DONE_OK);
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
} }

View File

@@ -19,25 +19,26 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class AppLauncher : public AbstractActionTool { class AppLauncher : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit AppLauncher(QObject *parent = nullptr); explicit AppLauncher(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
QWidget* widget() override; QWidget* widget() override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
private: private:
QPixmap capture; QPixmap capture;
}; };

View File

@@ -16,233 +16,253 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "applauncherwidget.h" #include "applauncherwidget.h"
#include "src/utils/filenamehandler.h"
#include "src/tools/launcher/launcheritemdelegate.h" #include "src/tools/launcher/launcheritemdelegate.h"
#include "src/utils/globalvalues.h"
#include "src/utils/confighandler.h" #include "src/utils/confighandler.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/globalvalues.h"
#include "terminallauncher.h" #include "terminallauncher.h"
#include <QDir>
#include <QList>
#include <QProcess>
#include <QPixmap>
#include <QListView>
#include <QTabWidget>
#include <QListWidgetItem>
#include <QHBoxLayout>
#include <QCheckBox> #include <QCheckBox>
#include <QDir>
#include <QHBoxLayout>
#include <QLineEdit> #include <QLineEdit>
#include <QList>
#include <QListView>
#include <QListWidgetItem>
#include <QMessageBox> #include <QMessageBox>
#include <QPixmap>
#include <QProcess>
#include <QTabWidget>
namespace { namespace {
QMap<QString, QString> catIconNames({ QMap<QString, QString> catIconNames(
{ "Multimedia", "applications-multimedia" }, { { "Multimedia", "applications-multimedia" },
{ "Development","applications-development" }, { "Development", "applications-development" },
{ "Graphics", "applications-graphics" }, { "Graphics", "applications-graphics" },
{ "Network", "preferences-system-network" }, { "Network", "preferences-system-network" },
{ "Office", "applications-office" }, { "Office", "applications-office" },
{ "Science", "applications-science" }, { "Science", "applications-science" },
{ "Settings", "preferences-desktop" }, { "Settings", "preferences-desktop" },
{ "System", "preferences-system" }, { "System", "preferences-system" },
{ "Utility", "applications-utilities" } { "Utility", "applications-utilities" } });
});
} }
AppLauncherWidget::AppLauncherWidget(const QPixmap &p, QWidget *parent): AppLauncherWidget::AppLauncherWidget(const QPixmap& p, QWidget* parent)
QWidget(parent), m_pixmap(p) : QWidget(parent)
, m_pixmap(p)
{ {
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/app/flameshot.svg")); setWindowIcon(QIcon(":img/app/flameshot.svg"));
setWindowTitle(tr("Open With")); setWindowTitle(tr("Open With"));
m_keepOpen = ConfigHandler().keepOpenAppLauncherValue(); m_keepOpen = ConfigHandler().keepOpenAppLauncherValue();
QString dirLocal = QDir::homePath() + "/.local/share/applications/"; QString dirLocal = QDir::homePath() + "/.local/share/applications/";
QDir appsDirLocal(dirLocal); QDir appsDirLocal(dirLocal);
m_parser.processDirectory(appsDirLocal); m_parser.processDirectory(appsDirLocal);
QString dir = QStringLiteral("/usr/share/applications/"); QString dir = QStringLiteral("/usr/share/applications/");
QDir appsDir(dir); QDir appsDir(dir);
m_parser.processDirectory(appsDir); m_parser.processDirectory(appsDir);
initAppMap(); initAppMap();
initListWidget(); initListWidget();
m_terminalCheckbox = new QCheckBox(tr("Launch in terminal"), this); m_terminalCheckbox = new QCheckBox(tr("Launch in terminal"), this);
m_keepOpenCheckbox = new QCheckBox(tr("Keep open after selection"), this); m_keepOpenCheckbox = new QCheckBox(tr("Keep open after selection"), this);
m_keepOpenCheckbox->setChecked(ConfigHandler().keepOpenAppLauncherValue()); m_keepOpenCheckbox->setChecked(ConfigHandler().keepOpenAppLauncherValue());
connect(m_keepOpenCheckbox, &QCheckBox::clicked, this, &AppLauncherWidget::checkboxClicked); connect(m_keepOpenCheckbox,
&QCheckBox::clicked,
this,
&AppLauncherWidget::checkboxClicked);
// search items // search items
m_lineEdit = new QLineEdit; m_lineEdit = new QLineEdit;
connect(m_lineEdit, &QLineEdit::textChanged, connect(m_lineEdit,
this, &AppLauncherWidget::searchChanged); &QLineEdit::textChanged,
m_filterList = new QListWidget; this,
&AppLauncherWidget::searchChanged);
m_filterList = new QListWidget;
m_filterList->hide();
configureListView(m_filterList);
connect(
m_filterList, &QListWidget::clicked, this, &AppLauncherWidget::launch);
m_layout = new QVBoxLayout(this);
m_layout->addWidget(m_filterList);
m_layout->addWidget(m_tabWidget);
m_layout->addWidget(m_lineEdit);
m_layout->addWidget(m_keepOpenCheckbox);
m_layout->addWidget(m_terminalCheckbox);
m_lineEdit->setFocus();
}
void
AppLauncherWidget::launch(const QModelIndex& index)
{
if (!QFileInfo(m_tempFile).isReadable()) {
m_tempFile =
FileNameHandler().generateAbsolutePath(QDir::tempPath()) + ".png";
bool ok = m_pixmap.save(m_tempFile);
if (!ok) {
QMessageBox::about(
this, tr("Error"), tr("Unable to write in") + QDir::tempPath());
return;
}
}
QString command = index.data(Qt::UserRole)
.toString()
.replace(QRegExp("(\\%.)"), '"' + m_tempFile + '"');
QString app_name = index.data(Qt::UserRole).toString().split(" ").at(0);
bool inTerminal =
index.data(Qt::UserRole + 1).toBool() || m_terminalCheckbox->isChecked();
if (inTerminal) {
bool ok = TerminalLauncher::launchDetached(command);
if (!ok) {
QMessageBox::about(
this, tr("Error"), tr("Unable to launch in terminal."));
}
} else {
QProcess::startDetached(app_name, { m_tempFile });
}
if (!m_keepOpen) {
close();
}
}
void
AppLauncherWidget::checkboxClicked(const bool enabled)
{
m_keepOpen = enabled;
ConfigHandler().setKeepOpenAppLauncher(enabled);
m_keepOpenCheckbox->setChecked(enabled);
}
void
AppLauncherWidget::searchChanged(const QString& text)
{
if (text.isEmpty()) {
m_filterList->hide(); m_filterList->hide();
configureListView(m_filterList); m_tabWidget->show();
connect(m_filterList, &QListWidget::clicked, this, &AppLauncherWidget::launch); } else {
m_tabWidget->hide();
m_layout = new QVBoxLayout(this); m_filterList->show();
m_layout->addWidget(m_filterList); m_filterList->clear();
m_layout->addWidget(m_tabWidget); QRegExp regexp(text, Qt::CaseInsensitive, QRegExp::Wildcard);
m_layout->addWidget(m_lineEdit); QVector<DesktopAppData> apps;
m_layout->addWidget(m_keepOpenCheckbox);
m_layout->addWidget(m_terminalCheckbox);
m_lineEdit->setFocus();
}
void AppLauncherWidget::launch(const QModelIndex &index) {
if (!QFileInfo(m_tempFile).isReadable()) {
m_tempFile = FileNameHandler().generateAbsolutePath(QDir::tempPath()) + ".png";
bool ok = m_pixmap.save(m_tempFile);
if (!ok) {
QMessageBox::about(this, tr("Error"), tr("Unable to write in")
+ QDir::tempPath());
return;
}
}
QString command = index.data(Qt::UserRole).toString().replace(
QRegExp("(\\%.)"), '"' + m_tempFile + '"');
QString app_name = index.data(Qt::UserRole).toString().split(" ").at(0);
bool inTerminal = index.data(Qt::UserRole+1).toBool() ||
m_terminalCheckbox->isChecked();
if (inTerminal) {
bool ok = TerminalLauncher::launchDetached(command);
if (!ok) {
QMessageBox::about(this, tr("Error"),
tr("Unable to launch in terminal."));
}
} else {
QProcess::startDetached(app_name,{m_tempFile});
}
if (!m_keepOpen) {
close();
}
}
void AppLauncherWidget::checkboxClicked(const bool enabled) {
m_keepOpen = enabled;
ConfigHandler().setKeepOpenAppLauncher(enabled);
m_keepOpenCheckbox->setChecked(enabled);
}
void AppLauncherWidget::searchChanged(const QString &text) {
if (text.isEmpty()) {
m_filterList->hide();
m_tabWidget->show();
} else {
m_tabWidget->hide();
m_filterList->show();
m_filterList->clear();
QRegExp regexp(text, Qt::CaseInsensitive, QRegExp::Wildcard);
QVector<DesktopAppData> apps;
for (auto const& i : catIconNames.toStdMap()) {
const QString &cat = i.first;
if (!m_appsMap.contains(cat)) {
continue;
}
const QVector<DesktopAppData> &appList = m_appsMap[cat];
for (const DesktopAppData &app: appList) {
if (!apps.contains(app) && (app.name.contains(regexp) ||
app.description.contains(regexp) ))
{
apps.append(app);
}
}
}
addAppsToListWidget(m_filterList, apps);
}
}
void AppLauncherWidget::initListWidget() {
m_tabWidget = new QTabWidget;
const int size = GlobalValues::buttonBaseSize();
m_tabWidget->setIconSize(QSize(size, size));
for (auto const& i : catIconNames.toStdMap()) { for (auto const& i : catIconNames.toStdMap()) {
const QString &cat = i.first; const QString& cat = i.first;
const QString &iconName = i.second; if (!m_appsMap.contains(cat)) {
continue;
if (!m_appsMap.contains(cat)) { }
continue; const QVector<DesktopAppData>& appList = m_appsMap[cat];
} for (const DesktopAppData& app : appList) {
if (!apps.contains(app) &&
QListWidget *itemsWidget = new QListWidget(); (app.name.contains(regexp) || app.description.contains(regexp))) {
configureListView(itemsWidget); apps.append(app);
const QVector<DesktopAppData> &appList = m_appsMap[cat];
addAppsToListWidget(itemsWidget, appList);
m_tabWidget->addTab(itemsWidget, QIcon::fromTheme(iconName), QLatin1String(""));
m_tabWidget->setTabToolTip(m_tabWidget->count(), cat);
if (cat == QLatin1String("Graphics")) {
m_tabWidget->setCurrentIndex(m_tabWidget->count() -1);
} }
}
} }
addAppsToListWidget(m_filterList, apps);
}
} }
void AppLauncherWidget::initAppMap() { void
QStringList categories({"AudioVideo", AppLauncherWidget::initListWidget()
"Audio",
"Video",
"Development",
"Graphics",
"Network",
"Office",
"Science",
"Settings",
"System",
"Utility"});
m_appsMap = m_parser.getAppsByCategory(categories);
// Unify multimedia.
QVector<DesktopAppData> multimediaList;
QStringList multimediaNames;
multimediaNames << QStringLiteral("AudioVideo") << QStringLiteral("Audio") << QStringLiteral("Video");
for (const QString &name : multimediaNames) {
if(!m_appsMap.contains(name)) {
continue;
}
for (auto i : m_appsMap[name]) {
if (!multimediaList.contains(i)) {
multimediaList.append(i);
}
}
m_appsMap.remove(name);
}
m_appsMap.insert(QStringLiteral("Multimedia"), multimediaList);
}
void AppLauncherWidget::configureListView(QListWidget *widget) {
widget->setItemDelegate(new LauncherItemDelegate());
widget->setViewMode(QListWidget::IconMode);
widget->setResizeMode(QListView::Adjust);
widget->setSpacing(4);
widget->setFlow(QListView::LeftToRight);
widget->setDragEnabled(false);
widget->setMinimumWidth(GlobalValues::buttonBaseSize() * 11);
connect(widget, &QListWidget::clicked,
this, &AppLauncherWidget::launch);
}
void AppLauncherWidget::addAppsToListWidget(
QListWidget *widget, const QVector<DesktopAppData> &appList)
{ {
for (const DesktopAppData &app: appList) { m_tabWidget = new QTabWidget;
QListWidgetItem *buttonItem = new QListWidgetItem(widget); const int size = GlobalValues::buttonBaseSize();
buttonItem->setData(Qt::DecorationRole, app.icon); m_tabWidget->setIconSize(QSize(size, size));
buttonItem->setData(Qt::DisplayRole, app.name);
buttonItem->setData(Qt::UserRole, app.exec);
buttonItem->setData(Qt::UserRole+1, app.showInTerminal);
QColor foregroundColor =
this->palette().color(QWidget::foregroundRole());
buttonItem->setForeground(foregroundColor);
buttonItem->setIcon(app.icon); for (auto const& i : catIconNames.toStdMap()) {
buttonItem->setText(app.name); const QString& cat = i.first;
buttonItem->setToolTip(app.description); const QString& iconName = i.second;
if (!m_appsMap.contains(cat)) {
continue;
} }
QListWidget* itemsWidget = new QListWidget();
configureListView(itemsWidget);
const QVector<DesktopAppData>& appList = m_appsMap[cat];
addAppsToListWidget(itemsWidget, appList);
m_tabWidget->addTab(
itemsWidget, QIcon::fromTheme(iconName), QLatin1String(""));
m_tabWidget->setTabToolTip(m_tabWidget->count(), cat);
if (cat == QLatin1String("Graphics")) {
m_tabWidget->setCurrentIndex(m_tabWidget->count() - 1);
}
}
}
void
AppLauncherWidget::initAppMap()
{
QStringList categories({ "AudioVideo",
"Audio",
"Video",
"Development",
"Graphics",
"Network",
"Office",
"Science",
"Settings",
"System",
"Utility" });
m_appsMap = m_parser.getAppsByCategory(categories);
// Unify multimedia.
QVector<DesktopAppData> multimediaList;
QStringList multimediaNames;
multimediaNames << QStringLiteral("AudioVideo") << QStringLiteral("Audio")
<< QStringLiteral("Video");
for (const QString& name : multimediaNames) {
if (!m_appsMap.contains(name)) {
continue;
}
for (auto i : m_appsMap[name]) {
if (!multimediaList.contains(i)) {
multimediaList.append(i);
}
}
m_appsMap.remove(name);
}
m_appsMap.insert(QStringLiteral("Multimedia"), multimediaList);
}
void
AppLauncherWidget::configureListView(QListWidget* widget)
{
widget->setItemDelegate(new LauncherItemDelegate());
widget->setViewMode(QListWidget::IconMode);
widget->setResizeMode(QListView::Adjust);
widget->setSpacing(4);
widget->setFlow(QListView::LeftToRight);
widget->setDragEnabled(false);
widget->setMinimumWidth(GlobalValues::buttonBaseSize() * 11);
connect(widget, &QListWidget::clicked, this, &AppLauncherWidget::launch);
}
void
AppLauncherWidget::addAppsToListWidget(QListWidget* widget,
const QVector<DesktopAppData>& appList)
{
for (const DesktopAppData& app : appList) {
QListWidgetItem* buttonItem = new QListWidgetItem(widget);
buttonItem->setData(Qt::DecorationRole, app.icon);
buttonItem->setData(Qt::DisplayRole, app.name);
buttonItem->setData(Qt::UserRole, app.exec);
buttonItem->setData(Qt::UserRole + 1, app.showInTerminal);
QColor foregroundColor = this->palette().color(QWidget::foregroundRole());
buttonItem->setForeground(foregroundColor);
buttonItem->setIcon(app.icon);
buttonItem->setText(app.name);
buttonItem->setToolTip(app.description);
}
} }

View File

@@ -18,8 +18,8 @@
#pragma once #pragma once
#include "src/utils/desktopfileparse.h" #include "src/utils/desktopfileparse.h"
#include <QWidget>
#include <QMap> #include <QMap>
#include <QWidget>
class QTabWidget; class QTabWidget;
class QCheckBox; class QCheckBox;
@@ -27,32 +27,33 @@ class QVBoxLayout;
class QLineEdit; class QLineEdit;
class QListWidget; class QListWidget;
class AppLauncherWidget: public QWidget { class AppLauncherWidget : public QWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit AppLauncherWidget(const QPixmap &p, QWidget *parent = nullptr); explicit AppLauncherWidget(const QPixmap& p, QWidget* parent = nullptr);
private slots: private slots:
void launch(const QModelIndex &index); void launch(const QModelIndex& index);
void checkboxClicked(const bool enabled); void checkboxClicked(const bool enabled);
void searchChanged(const QString &text); void searchChanged(const QString& text);
private: private:
void initListWidget(); void initListWidget();
void initAppMap(); void initAppMap();
void configureListView(QListWidget *widget); void configureListView(QListWidget* widget);
void addAppsToListWidget(QListWidget *widget, void addAppsToListWidget(QListWidget* widget,
const QVector<DesktopAppData> &appList); const QVector<DesktopAppData>& appList);
DesktopFileParser m_parser; DesktopFileParser m_parser;
QPixmap m_pixmap; QPixmap m_pixmap;
QString m_tempFile; QString m_tempFile;
bool m_keepOpen; bool m_keepOpen;
QMap<QString, QVector<DesktopAppData>> m_appsMap; QMap<QString, QVector<DesktopAppData>> m_appsMap;
QCheckBox *m_keepOpenCheckbox; QCheckBox* m_keepOpenCheckbox;
QCheckBox *m_terminalCheckbox; QCheckBox* m_terminalCheckbox;
QVBoxLayout *m_layout; QVBoxLayout* m_layout;
QLineEdit *m_lineEdit; QLineEdit* m_lineEdit;
QListWidget *m_filterList; QListWidget* m_filterList;
QTabWidget *m_tabWidget; QTabWidget* m_tabWidget;
}; };

View File

@@ -19,48 +19,49 @@
#include "src/utils/globalvalues.h" #include "src/utils/globalvalues.h"
#include <QPainter> #include <QPainter>
LauncherItemDelegate::LauncherItemDelegate(QObject *parent) : LauncherItemDelegate::LauncherItemDelegate(QObject* parent)
QStyledItemDelegate(parent) : QStyledItemDelegate(parent)
{}
void
LauncherItemDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{ {
const QRect& rect = option.rect;
if (option.state & (QStyle::State_Selected | QStyle::State_MouseOver)) {
painter->save();
painter->setPen(Qt::transparent);
painter->setBrush(QPalette().highlight());
painter->drawRect(rect.x(), rect.y(), rect.width() - 1, rect.height() - 1);
painter->restore();
}
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
const int iconSide = GlobalValues::buttonBaseSize() * 1.3;
const int halfIcon = iconSide / 2;
const int halfWidth = rect.width() / 2;
const int halfHeight = rect.height() / 2;
QSize size(iconSide, iconSide);
QPixmap pixIcon = icon.pixmap(size).scaled(size, Qt::KeepAspectRatio);
painter->drawPixmap(rect.x() + (halfWidth - halfIcon),
rect.y() + (halfHeight / 2 - halfIcon),
iconSide,
iconSide,
pixIcon);
const QRect textRect(
rect.x(), rect.y() + halfHeight, rect.width(), halfHeight);
painter->drawText(textRect,
Qt::TextWordWrap | Qt::AlignHCenter,
index.data(Qt::DisplayRole).toString());
} }
void LauncherItemDelegate::paint( QSize
QPainter *painter, LauncherItemDelegate::sizeHint(const QStyleOptionViewItem& option,
const QStyleOptionViewItem &option, const QModelIndex& index) const
const QModelIndex &index) const
{ {
const QRect &rect = option.rect; Q_UNUSED(option);
if (option.state & (QStyle::State_Selected | QStyle::State_MouseOver)) { Q_UNUSED(index);
painter->save(); const int size = GlobalValues::buttonBaseSize();
painter->setPen(Qt::transparent); return QSize(size * 3.2, size * 3.7);
painter->setBrush(QPalette().highlight());
painter->drawRect(rect.x(), rect.y(),
rect.width() -1, rect.height() -1);
painter->restore();
}
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
const int iconSide = GlobalValues::buttonBaseSize() * 1.3;
const int halfIcon = iconSide/2;
const int halfWidth = rect.width()/2;
const int halfHeight = rect.height()/2;
QSize size(iconSide, iconSide);
QPixmap pixIcon = icon.pixmap(size).scaled(size, Qt::KeepAspectRatio);
painter->drawPixmap(rect.x() + (halfWidth - halfIcon),
rect.y()+ (halfHeight/2 - halfIcon),
iconSide, iconSide, pixIcon);
const QRect textRect(rect.x(), rect.y() + halfHeight,
rect.width(), halfHeight);
painter->drawText(textRect, Qt::TextWordWrap | Qt::AlignHCenter,
index.data(Qt::DisplayRole).toString());
}
QSize LauncherItemDelegate::sizeHint(
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
const int size = GlobalValues::buttonBaseSize();
return QSize(size * 3.2, size * 3.7);
} }

View File

@@ -20,14 +20,16 @@
#include "src/utils/desktopfileparse.h" #include "src/utils/desktopfileparse.h"
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
class LauncherItemDelegate : public QStyledItemDelegate { class LauncherItemDelegate : public QStyledItemDelegate
Q_OBJECT {
Q_OBJECT
public: public:
explicit LauncherItemDelegate(QObject *parent = nullptr); explicit LauncherItemDelegate(QObject* parent = nullptr);
void paint(QPainter *painter, void paint(QPainter* painter,
const QStyleOptionViewItem &option, const QStyleOptionViewItem& option,
const QModelIndex &index) const; const QModelIndex& index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const;
}; };

View File

@@ -15,40 +15,42 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "openwithprogram.h" #include "openwithprogram.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
#include "src/utils/filenamehandler.h" #include "src/utils/filenamehandler.h"
#include <QDir> #include <QDir>
#include <QMessageBox> #include <QMessageBox>
#include <windows.h>
#include <Shlobj.h> #include <Shlobj.h>
#include <windows.h>
#pragma comment(lib, "Shell32.lib") #pragma comment(lib, "Shell32.lib")
#else #else
#include "src/tools/launcher/applauncherwidget.h" #include "src/tools/launcher/applauncherwidget.h"
#endif #endif
void showOpenWithMenu(const QPixmap &capture) { void
showOpenWithMenu(const QPixmap& capture)
{
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
QString tempFile = QString tempFile =
FileNameHandler().generateAbsolutePath(QDir::tempPath()) + ".png"; FileNameHandler().generateAbsolutePath(QDir::tempPath()) + ".png";
bool ok = capture.save(tempFile); bool ok = capture.save(tempFile);
if (!ok) { if (!ok) {
QMessageBox::about(nullptr, QObject::tr("Error"), QMessageBox::about(nullptr,
QObject::tr("Unable to write in") + QDir::tempPath()); QObject::tr("Error"),
return; QObject::tr("Unable to write in") + QDir::tempPath());
} return;
}
OPENASINFO info; OPENASINFO info;
auto wStringFile = tempFile.replace("/", "\\").toStdWString(); auto wStringFile = tempFile.replace("/", "\\").toStdWString();
info.pcszFile = wStringFile.c_str(); info.pcszFile = wStringFile.c_str();
info.pcszClass = nullptr; info.pcszClass = nullptr;
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC; info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
SHOpenWithDialog(nullptr, &info); SHOpenWithDialog(nullptr, &info);
#else #else
auto w = new AppLauncherWidget(capture); auto w = new AppLauncherWidget(capture);
w->show(); w->show();
#endif #endif
} }

View File

@@ -19,4 +19,5 @@
#include <QPixmap> #include <QPixmap>
void showOpenWithMenu(const QPixmap &capture); void
showOpenWithMenu(const QPixmap& capture);

View File

@@ -16,45 +16,50 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>. // along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "terminallauncher.h" #include "terminallauncher.h"
#include <QProcess>
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QProcess>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include <QStandardPaths>
namespace { namespace {
static const TerminalApp terminalApps[] = { static const TerminalApp terminalApps[] = {
{ "x-terminal-emulator", "-e" }, { "x-terminal-emulator", "-e" },
{ "xfce4-terminal", "-x" }, { "xfce4-terminal", "-x" },
{ "konsole", "-e" }, { "konsole", "-e" },
{ "gnome-terminal", "--" }, { "gnome-terminal", "--" },
{ "terminator", "-e" }, { "terminator", "-e" },
{ "terminology", "-e" }, { "terminology", "-e" },
{ "tilix", "-e" }, { "tilix", "-e" },
{ "xterm", "-e" }, { "xterm", "-e" },
{ "aterm", "-e" }, { "aterm", "-e" },
{ "Eterm", "-e" }, { "Eterm", "-e" },
{ "rxvt", "-e" }, { "rxvt", "-e" },
{ "urxvt", "-e" }, { "urxvt", "-e" },
}; };
} }
TerminalLauncher::TerminalLauncher(QObject *parent) : QObject(parent) { TerminalLauncher::TerminalLauncher(QObject* parent)
} : QObject(parent)
{}
TerminalApp TerminalLauncher::getPreferedTerminal() { TerminalApp
TerminalApp res; TerminalLauncher::getPreferedTerminal()
for (const TerminalApp &app : terminalApps) { {
QString path = QStandardPaths::findExecutable(app.name); TerminalApp res;
if (!path.isEmpty()) { for (const TerminalApp& app : terminalApps) {
res = app; QString path = QStandardPaths::findExecutable(app.name);
break; if (!path.isEmpty()) {
} res = app;
break;
} }
return res; }
return res;
} }
bool TerminalLauncher::launchDetached(const QString &command) { bool
TerminalApp app = getPreferedTerminal(); TerminalLauncher::launchDetached(const QString& command)
QString s = app.name + " " + app.arg + " " + command; {
return QProcess::startDetached(app.name, {app.arg,command}); TerminalApp app = getPreferedTerminal();
QString s = app.name + " " + app.arg + " " + command;
return QProcess::startDetached(app.name, { app.arg, command });
} }

View File

@@ -19,17 +19,20 @@
#include <QObject> #include <QObject>
struct TerminalApp { struct TerminalApp
QString name; {
QString arg; QString name;
QString arg;
}; };
class TerminalLauncher : public QObject { class TerminalLauncher : public QObject
Q_OBJECT {
Q_OBJECT
public: public:
explicit TerminalLauncher(QObject *parent = nullptr); explicit TerminalLauncher(QObject* parent = nullptr);
static bool launchDetached(const QString& command);
static bool launchDetached(const QString &command);
private: private:
static TerminalApp getPreferedTerminal(); static TerminalApp getPreferedTerminal();
}; };

View File

@@ -24,51 +24,71 @@ namespace {
} }
LineTool::LineTool(QObject *parent) : AbstractTwoPointTool(parent) { LineTool::LineTool(QObject* parent)
m_supportsOrthogonalAdj = true; : AbstractTwoPointTool(parent)
m_supportsDiagonalAdj = true; {
m_supportsOrthogonalAdj = true;
m_supportsDiagonalAdj = true;
} }
QIcon LineTool::icon(const QColor &background, bool inEditor) const { QIcon
Q_UNUSED(inEditor); LineTool::icon(const QColor& background, bool inEditor) const
return QIcon(iconPath(background) + "line.svg"); {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "line.svg");
} }
QString LineTool::name() const { QString
return tr("Line"); LineTool::name() const
{
return tr("Line");
} }
QString LineTool::nameID() { QString
return QLatin1String(""); LineTool::nameID()
{
return QLatin1String("");
} }
QString LineTool::description() const { QString
return tr("Set the Line as the paint tool"); LineTool::description() const
{
return tr("Set the Line as the paint tool");
} }
CaptureTool* LineTool::copy(QObject *parent) { CaptureTool*
return new LineTool(parent); LineTool::copy(QObject* parent)
{
return new LineTool(parent);
} }
void LineTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { LineTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
updateBackup(pixmap); {
} if (recordUndo) {
painter.setPen(QPen(m_color, m_thickness)); updateBackup(pixmap);
painter.drawLine(m_points.first, m_points.second); }
painter.setPen(QPen(m_color, m_thickness));
painter.drawLine(m_points.first, m_points.second);
} }
void LineTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness)); LineTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
painter.drawLine(context.mousePos, context.mousePos); {
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness));
painter.drawLine(context.mousePos, context.mousePos);
} }
void LineTool::drawStart(const CaptureContext &context) { void
m_color = context.color; LineTool::drawStart(const CaptureContext& context)
m_thickness = context.thickness + PADDING_VALUE; {
m_points.first = context.mousePos; m_color = context.color;
m_points.second = context.mousePos; m_thickness = context.thickness + PADDING_VALUE;
m_points.first = context.mousePos;
m_points.second = context.mousePos;
} }
void LineTool::pressed(const CaptureContext &context) { void
Q_UNUSED(context); LineTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
} }

View File

@@ -19,22 +19,25 @@
#include "src/tools/abstracttwopointtool.h" #include "src/tools/abstracttwopointtool.h"
class LineTool : public AbstractTwoPointTool { class LineTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit LineTool(QObject *parent = nullptr); explicit LineTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -24,59 +24,81 @@ namespace {
} }
MarkerTool::MarkerTool(QObject *parent) : AbstractTwoPointTool(parent) { MarkerTool::MarkerTool(QObject* parent)
m_supportsOrthogonalAdj = true; : AbstractTwoPointTool(parent)
m_supportsDiagonalAdj = true; {
m_supportsOrthogonalAdj = true;
m_supportsDiagonalAdj = true;
} }
QIcon MarkerTool::icon(const QColor &background, bool inEditor) const { QIcon
Q_UNUSED(inEditor); MarkerTool::icon(const QColor& background, bool inEditor) const
return QIcon(iconPath(background) + "marker.svg"); {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "marker.svg");
} }
QString MarkerTool::name() const { QString
return tr("Marker"); MarkerTool::name() const
{
return tr("Marker");
} }
QString MarkerTool::nameID() { QString
return QLatin1String(""); MarkerTool::nameID()
{
return QLatin1String("");
} }
QString MarkerTool::description() const { QString
return tr("Set the Marker as the paint tool"); MarkerTool::description() const
{
return tr("Set the Marker as the paint tool");
} }
CaptureTool* MarkerTool::copy(QObject *parent) { CaptureTool*
return new MarkerTool(parent); MarkerTool::copy(QObject* parent)
{
return new MarkerTool(parent);
} }
void MarkerTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { MarkerTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
updateBackup(pixmap); {
} if (recordUndo) {
painter.setCompositionMode(QPainter::CompositionMode_Multiply); updateBackup(pixmap);
painter.setOpacity(0.35); }
painter.setPen(QPen(m_color, m_thickness)); painter.setCompositionMode(QPainter::CompositionMode_Multiply);
painter.drawLine(m_points.first, m_points.second); painter.setOpacity(0.35);
painter.setPen(QPen(m_color, m_thickness));
painter.drawLine(m_points.first, m_points.second);
} }
void MarkerTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setCompositionMode(QPainter::CompositionMode_Multiply); MarkerTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
painter.setOpacity(0.35); {
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness)); painter.setCompositionMode(QPainter::CompositionMode_Multiply);
painter.drawLine(context.mousePos, context.mousePos); painter.setOpacity(0.35);
painter.setPen(QPen(context.color, PADDING_VALUE + context.thickness));
painter.drawLine(context.mousePos, context.mousePos);
} }
void MarkerTool::drawStart(const CaptureContext &context) { void
m_color = context.color; MarkerTool::drawStart(const CaptureContext& context)
m_thickness = context.thickness + PADDING_VALUE; {
m_points.first = context.mousePos; m_color = context.color;
m_points.second = context.mousePos; m_thickness = context.thickness + PADDING_VALUE;
m_points.first = context.mousePos;
m_points.second = context.mousePos;
} }
void MarkerTool::pressed(const CaptureContext &context) { void
Q_UNUSED(context); MarkerTool::pressed(const CaptureContext& context)
{
Q_UNUSED(context);
} }
void MarkerTool::thicknessChanged(const int th) { void
m_thickness = th + PADDING_VALUE; MarkerTool::thicknessChanged(const int th)
{
m_thickness = th + PADDING_VALUE;
} }

View File

@@ -19,23 +19,26 @@
#include "src/tools/abstracttwopointtool.h" #include "src/tools/abstracttwopointtool.h"
class MarkerTool : public AbstractTwoPointTool { class MarkerTool : public AbstractTwoPointTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit MarkerTool(QObject *parent = nullptr); explicit MarkerTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
void thicknessChanged(const int th) override; void thicknessChanged(const int th) override;
}; };

View File

@@ -18,35 +18,49 @@
#include "movetool.h" #include "movetool.h"
#include <QPainter> #include <QPainter>
MoveTool::MoveTool(QObject *parent) : AbstractActionTool(parent) { MoveTool::MoveTool(QObject* parent)
: AbstractActionTool(parent)
{}
bool
MoveTool::closeOnButtonPressed() const
{
return false;
} }
bool MoveTool::closeOnButtonPressed() const { QIcon
return false; MoveTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "cursor-move.svg");
}
QString
MoveTool::name() const
{
return tr("Move");
} }
QIcon MoveTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); MoveTool::nameID()
return QIcon(iconPath(background) + "cursor-move.svg"); {
} return QLatin1String("");
QString MoveTool::name() const {
return tr("Move");
} }
QString MoveTool::nameID() { QString
return QLatin1String(""); MoveTool::description() const
{
return tr("Move the selection area");
} }
QString MoveTool::description() const { CaptureTool*
return tr("Move the selection area"); MoveTool::copy(QObject* parent)
{
return new MoveTool(parent);
} }
CaptureTool* MoveTool::copy(QObject *parent) { void
return new MoveTool(parent); MoveTool::pressed(const CaptureContext& context)
} {
Q_UNUSED(context);
void MoveTool::pressed(const CaptureContext &context) { emit requestAction(REQ_MOVE_MODE);
Q_UNUSED(context);
emit requestAction(REQ_MOVE_MODE);
} }

View File

@@ -19,20 +19,21 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class MoveTool : public AbstractActionTool { class MoveTool : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit MoveTool(QObject *parent = nullptr); explicit MoveTool(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -18,51 +18,69 @@
#include "penciltool.h" #include "penciltool.h"
#include <QPainter> #include <QPainter>
PencilTool::PencilTool(QObject *parent) : AbstractPathTool(parent) { PencilTool::PencilTool(QObject* parent)
: AbstractPathTool(parent)
{}
QIcon
PencilTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "pencil.svg");
}
QString
PencilTool::name() const
{
return tr("Pencil");
} }
QIcon PencilTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); PencilTool::nameID()
return QIcon(iconPath(background) + "pencil.svg"); {
} return QLatin1String("");
QString PencilTool::name() const {
return tr("Pencil");
} }
QString PencilTool::nameID() { QString
return QLatin1String(""); PencilTool::description() const
{
return tr("Set the Pencil as the paint tool");
} }
QString PencilTool::description() const { CaptureTool*
return tr("Set the Pencil as the paint tool"); PencilTool::copy(QObject* parent)
{
return new PencilTool(parent);
} }
CaptureTool* PencilTool::copy(QObject *parent) { void
return new PencilTool(parent); PencilTool::process(QPainter& painter, const QPixmap& pixmap, bool recordUndo)
{
if (recordUndo) {
updateBackup(pixmap);
}
painter.setPen(QPen(m_color, m_thickness));
painter.drawPolyline(m_points.data(), m_points.size());
} }
void PencilTool::process(QPainter &painter, const QPixmap &pixmap, bool recordUndo) { void
if (recordUndo) { PencilTool::paintMousePreview(QPainter& painter, const CaptureContext& context)
updateBackup(pixmap); {
} painter.setPen(QPen(context.color, context.thickness + 2));
painter.setPen(QPen(m_color, m_thickness)); painter.drawLine(context.mousePos, context.mousePos);
painter.drawPolyline(m_points.data(), m_points.size());
} }
void PencilTool::paintMousePreview(QPainter &painter, const CaptureContext &context) { void
painter.setPen(QPen(context.color, context.thickness + 2)); PencilTool::drawStart(const CaptureContext& context)
painter.drawLine(context.mousePos, context.mousePos); {
m_color = context.color;
m_thickness = context.thickness + 2;
m_points.append(context.mousePos);
m_backupArea.setTopLeft(context.mousePos);
m_backupArea.setBottomRight(context.mousePos);
} }
void PencilTool::drawStart(const CaptureContext &context) { void
m_color = context.color; PencilTool::pressed(const CaptureContext& context)
m_thickness = context.thickness + 2; {
m_points.append(context.mousePos); Q_UNUSED(context);
m_backupArea.setTopLeft(context.mousePos);
m_backupArea.setBottomRight(context.mousePos);
}
void PencilTool::pressed(const CaptureContext &context) {
Q_UNUSED(context);
} }

View File

@@ -19,23 +19,26 @@
#include "src/tools/abstractpathtool.h" #include "src/tools/abstractpathtool.h"
class PencilTool : public AbstractPathTool { class PencilTool : public AbstractPathTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit PencilTool(QObject *parent = nullptr); explicit PencilTool(QObject* parent = nullptr);
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
void process( void process(QPainter& painter,
QPainter &painter, const QPixmap &pixmap, bool recordUndo = false) override; const QPixmap& pixmap,
void paintMousePreview(QPainter &painter, const CaptureContext &context) override; bool recordUndo = false) override;
void paintMousePreview(QPainter& painter,
const CaptureContext& context) override;
public slots: public slots:
void drawStart(const CaptureContext &context) override; void drawStart(const CaptureContext& context) override;
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
}; };

View File

@@ -18,47 +18,62 @@
#include "pintool.h" #include "pintool.h"
#include "src/tools/pin/pinwidget.h" #include "src/tools/pin/pinwidget.h"
PinTool::PinTool(QObject *parent) : AbstractActionTool(parent) { PinTool::PinTool(QObject* parent)
: AbstractActionTool(parent)
{}
bool
PinTool::closeOnButtonPressed() const
{
return true;
} }
bool PinTool::closeOnButtonPressed() const { QIcon
return true; PinTool::icon(const QColor& background, bool inEditor) const
{
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "pin.svg");
}
QString
PinTool::name() const
{
return tr("Pin Tool");
} }
QIcon PinTool::icon(const QColor &background, bool inEditor) const { QString
Q_UNUSED(inEditor); PinTool::nameID()
return QIcon(iconPath(background) + "pin.svg"); {
} return QLatin1String("");
QString PinTool::name() const {
return tr("Pin Tool");
} }
QString PinTool::nameID() { QString
return QLatin1String(""); PinTool::description() const
{
return tr("Pin image on the desktop");
} }
QString PinTool::description() const { QWidget*
return tr("Pin image on the desktop"); PinTool::widget()
{
PinWidget* w = new PinWidget(m_pixmap);
const int&& m = w->margin();
QRect adjusted_pos = m_geometry + QMargins(m, m, m, m);
w->setGeometry(adjusted_pos);
return w;
} }
QWidget* PinTool::widget() { CaptureTool*
PinWidget *w = new PinWidget(m_pixmap); PinTool::copy(QObject* parent)
const int &&m = w->margin(); {
QRect adjusted_pos = m_geometry + QMargins(m, m, m, m); return new PinTool(parent);
w->setGeometry(adjusted_pos);
return w;
} }
CaptureTool* PinTool::copy(QObject *parent) { void
return new PinTool(parent); PinTool::pressed(const CaptureContext& context)
} {
emit requestAction(REQ_CAPTURE_DONE_OK);
void PinTool::pressed(const CaptureContext &context) { m_geometry = context.selection;
emit requestAction(REQ_CAPTURE_DONE_OK); m_geometry.setTopLeft(m_geometry.topLeft() + context.widgetOffset);
m_geometry = context.selection; m_pixmap = context.selectedScreenshotArea();
m_geometry.setTopLeft(m_geometry.topLeft() + context.widgetOffset); emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
m_pixmap = context.selectedScreenshotArea();
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
} }

27
src/tools/pin/pintool.h Executable file → Normal file
View File

@@ -19,26 +19,27 @@
#include "src/tools/abstractactiontool.h" #include "src/tools/abstractactiontool.h"
class PinTool : public AbstractActionTool { class PinTool : public AbstractActionTool
Q_OBJECT {
Q_OBJECT
public: public:
explicit PinTool(QObject *parent = nullptr); explicit PinTool(QObject* parent = nullptr);
bool closeOnButtonPressed() const; bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override; QIcon icon(const QColor& background, bool inEditor) const override;
QString name() const override; QString name() const override;
static QString nameID(); static QString nameID();
QString description() const override; QString description() const override;
QWidget* widget() override; QWidget* widget() override;
CaptureTool* copy(QObject *parent = nullptr) override; CaptureTool* copy(QObject* parent = nullptr) override;
public slots: public slots:
void pressed(const CaptureContext &context) override; void pressed(const CaptureContext& context) override;
private: private:
QRect m_geometry; QRect m_geometry;
QPixmap m_pixmap; QPixmap m_pixmap;
}; };

Some files were not shown because too many files have changed in this diff Show More