Now you can choose to open the screenshot with more apps

This commit is contained in:
lupoDharkael
2017-12-11 01:32:51 +01:00
parent d4e3ae4cfd
commit aca1546b1f
10 changed files with 352 additions and 133 deletions

View File

@@ -91,7 +91,8 @@ SOURCES += src/main.cpp\
src/capture/tools/applauncher.cpp \
src/utils/desktopfileparse.cpp \
src/capture/workers/launcher/launcheritemdelegate.cpp \
src/capture/tools/blurtool.cpp
src/capture/tools/blurtool.cpp \
src/capture/workers/launcher/moreappswidget.cpp
HEADERS += \
src/capture/widget/buttonhandler.h \
@@ -147,7 +148,8 @@ HEADERS += \
src/capture/tools/applauncher.h \
src/utils/desktopfileparse.h \
src/capture/workers/launcher/launcheritemdelegate.h \
src/capture/tools/blurtool.h
src/capture/tools/blurtool.h \
src/capture/workers/launcher/moreappswidget.h
RESOURCES += \
graphics.qrc

View File

@@ -16,12 +16,12 @@
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "applauncherwidget.h"
#include "src/utils/desktopfileparse.h"
#include "src/utils/filenamehandler.h"
#include "src/capture/workers/launcher/launcheritemdelegate.h"
#include "src/utils/confighandler.h"
#include "moreappswidget.h"
#include <QDir>
#include <QVector>
#include <QList>
#include <QProcess>
#include <QPixmap>
#include <QListView>
@@ -33,36 +33,22 @@ AppLauncherWidget::AppLauncherWidget(const QPixmap &p, QWidget *parent):
QWidget(parent), m_pixmap(p)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/flameshot.png"));
setWindowTitle(tr("Open With"));
m_keepOpen = ConfigHandler().keepOpenAppLauncherValue();
// In case of wanting to know the default app for a mime:
// xdg-mime query default image/png
QString dir = "/usr/share/applications/";
QString dirLocal = "~/.local/share/applications/";
QDir appsDirLocal(dirLocal);
QDir appsDir(dir);
QString dirLocal = QDir::homePath() + "/.local/share/applications/";
QDir appsDirLocal(dirLocal);
m_parser.processDirectory(appsDirLocal);
QStringList entries = appsDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
QStringList entriesLocal = appsDirLocal.entryList(QDir::NoDotAndDotDot | QDir::Files);
QString dir = "/usr/share/applications/";
QDir appsDir(dir);
m_parser.processDirectory(appsDir);
DesktopFileParse parser;
bool ok;
QList<DesktopAppData> appList;
for (QString file: entries){
DesktopAppData app = parser.parseDesktopFile(dir + file, ok);
if (ok) {
appList.append(app);
}
}
for (QString file: entriesLocal){
DesktopAppData app = parser.parseDesktopFile(dirLocal + file, ok);
if (ok) {
appList.append(app);
}
}
auto layout = new QVBoxLayout(this);
auto *listView = new QListWidget(this);
listView->setItemDelegate(new launcherItemDelegate());
m_layout = new QVBoxLayout(this);
QListWidget *listView = new QListWidget(this);
listView->setItemDelegate(new LauncherItemDelegate());
listView->setViewMode(QListWidget::IconMode);
listView->setResizeMode(QListView::Adjust);
listView->setSpacing(4);
@@ -70,6 +56,11 @@ AppLauncherWidget::AppLauncherWidget(const QPixmap &p, QWidget *parent):
listView->setDragEnabled(false);
listView->setMinimumSize(375, 210);
QList<DesktopAppData> appList = m_parser.getAppsByCategory("Graphics");
appList.append(DesktopAppData(QObject::tr("Other Application"), "", ".",
QIcon::fromTheme("applications-other")
));
for (auto app: appList) {
QListWidgetItem *buttonItem = new QListWidgetItem(listView);
buttonItem->setData(Qt::DecorationRole, app.icon);
@@ -87,23 +78,32 @@ AppLauncherWidget::AppLauncherWidget(const QPixmap &p, QWidget *parent):
m_checkbox = new QCheckBox("Keep open after selection", this);
connect(m_checkbox, &QCheckBox::clicked, this, &AppLauncherWidget::checkboxClicked);
layout->addWidget(listView);
layout->addWidget(m_checkbox);
m_layout->addWidget(listView);
m_layout->addWidget(m_checkbox);
m_checkbox->setChecked(ConfigHandler().keepOpenAppLauncherValue());
}
void AppLauncherWidget::launch(const QModelIndex &index) {
m_tempFile = FileNameHandler().generateAbsolutePath("/tmp") + ".png";
bool ok = m_pixmap.save(m_tempFile);
if (!ok) {
// TO DO
return;
}
QString command = index.data(Qt::UserRole).toString().replace(
QRegExp("(\%.)"), m_tempFile);
QProcess::startDetached(command);
if (!m_keepOpen) {
close();
}
QString command = index.data(Qt::UserRole).toString().replace(
QRegExp("(\%.)"), m_tempFile);
if (command == ".") {
MoreAppsWidget *widget = new MoreAppsWidget(m_pixmap, m_parser);
connect(widget, &MoreAppsWidget::appClicked,
this, &AppLauncherWidget::launch);
m_layout->takeAt(0)->widget()->deleteLater();
m_layout->insertWidget(0, widget);
} else {
m_tempFile = FileNameHandler().generateAbsolutePath("/tmp") + ".png";
bool ok = m_pixmap.save(m_tempFile);
if (!ok) {
// TO DO
return;
}
QProcess::startDetached(command);
}
if (!m_keepOpen) {
close();
}
}
void AppLauncherWidget::checkboxClicked(const bool enabled) {

View File

@@ -18,9 +18,11 @@
#ifndef APPLAUNCHERWIDGET_H
#define APPLAUNCHERWIDGET_H
#include "src/utils/desktopfileparse.h"
#include <QWidget>
class QCheckBox;
class QVBoxLayout;
class AppLauncherWidget: public QWidget
{
@@ -33,10 +35,12 @@ private slots:
void checkboxClicked(const bool enabled);
private:
DesktopFileParser m_parser;
QPixmap m_pixmap;
QString m_tempFile;
bool m_keepOpen;
QCheckBox *m_checkbox;
QVBoxLayout *m_layout;
};

View File

@@ -18,12 +18,12 @@
#include "launcheritemdelegate.h"
#include <QPainter>
launcherItemDelegate::launcherItemDelegate(QObject *parent) :
LauncherItemDelegate::LauncherItemDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
}
void launcherItemDelegate::paint(
void LauncherItemDelegate::paint(
QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
@@ -53,7 +53,7 @@ void launcherItemDelegate::paint(
index.data(Qt::DisplayRole).toString());
}
QSize launcherItemDelegate::sizeHint(
QSize LauncherItemDelegate::sizeHint(
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{

View File

@@ -21,11 +21,11 @@
#include "src/utils/desktopfileparse.h"
#include <QStyledItemDelegate>
class launcherItemDelegate : public QStyledItemDelegate
class LauncherItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit launcherItemDelegate(QObject *parent = nullptr);
explicit LauncherItemDelegate(QObject *parent = nullptr);
void paint(QPainter *painter,
const QStyleOptionViewItem &option,

View File

@@ -0,0 +1,111 @@
#include "moreappswidget.h"
#include "src/capture/workers/launcher/launcheritemdelegate.h"
#include <QPixmap>
#include <QVBoxLayout>
#include <QTabWidget>
#include <QListView>
#include <QListWidgetItem>
#include <QMap>
// implement search, open custom and choose terminal
MoreAppsWidget::MoreAppsWidget(
const QPixmap &pixmap,
const DesktopFileParser &parser,
QWidget *parent) :
QWidget(parent), m_pixmap(pixmap)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowIcon(QIcon(":img/flameshot.png"));
setWindowTitle(tr("Open With"));
DesktopFileParser ctor_parser = std::move(parser);
m_layout = new QVBoxLayout(this);
m_tabs = new QTabWidget;
m_tabs->setIconSize(QSize(30, 30));
m_layout->addWidget(m_tabs);
QStringList categories({"AudioVideo",
"Audio",
"Video",
"Development",
"Graphics",
"Network",
"Office",
"Science",
"Settings",
"System",
"Utility"});
QMap<QString, QList<DesktopAppData>> appsMap =
ctor_parser.getAppsByCategory(categories);
// Unify multimedia.
QList<DesktopAppData> multimediaList;
QStringList multimediaNames;
multimediaNames << "AudioVideo" << "Audio" << "Video";
for (const QString &name : multimediaNames) {
if(!appsMap.contains(name)) {
continue;
}
for (auto i : appsMap[name]) {
if (!multimediaList.contains(i)) {
multimediaList.append(i);
}
}
appsMap.remove(name);
}
appsMap.insert("Multimedia", multimediaList);
QMap<QString, QString> catIconNames({
{ "Multimedia", "applications-multimedia" },
{ "Development","applications-development" },
{ "Graphics", "applications-graphics" },
{ "Network", "preferences-system-network" },
{ "Office", "applications-office" },
{ "Science", "applications-science" },
{ "Settings", "preferences-desktop" },
{ "System", "preferences-system" },
{ "Utility", "applications-utilities" }
});
for (auto const& i : catIconNames.toStdMap()) {
const QString &cat = i.first;
const QString &iconName = i.second;
if (!appsMap.contains(cat)) {
continue;
}
QListWidget *listView = new QListWidget();
listView->setItemDelegate(new LauncherItemDelegate());
listView->setViewMode(QListWidget::IconMode);
listView->setResizeMode(QListView::Adjust);
listView->setSpacing(4);
listView->setFlow(QListView::LeftToRight);
listView->setDragEnabled(false);
listView->setMinimumSize(375, 210);
connect(listView, &QListWidget::clicked,
this, &MoreAppsWidget::appClicked);
QList<DesktopAppData> appList = appsMap[cat];
for (auto app: appList) {
QListWidgetItem *buttonItem = new QListWidgetItem(listView);
buttonItem->setData(Qt::DecorationRole, app.icon);
buttonItem->setData(Qt::DisplayRole, app.name);
buttonItem->setData(Qt::UserRole, app.exec);
QColor foregroundColor =
this->palette().color(QWidget::foregroundRole());
buttonItem->setForeground(foregroundColor);
buttonItem->setIcon(app.icon);
buttonItem->setText(app.name);
buttonItem->setToolTip(app.description);
}
m_tabs->addTab(listView, QIcon::fromTheme(iconName), "");
m_tabs->setTabToolTip(m_tabs->count(), cat);
if (cat == "Graphics") {
m_tabs->setCurrentIndex(m_tabs->count() -1);
}
}
}

View File

@@ -0,0 +1,28 @@
#ifndef MOREAPPSWIDGET_H
#define MOREAPPSWIDGET_H
#include "src/utils/desktopfileparse.h"
#include <QWidget>
class QPixmap;
class QVBoxLayout;
class QTabWidget;
class MoreAppsWidget : public QWidget
{
Q_OBJECT
public:
explicit MoreAppsWidget(const QPixmap &pixmap,
const DesktopFileParser &parser,
QWidget *parent = nullptr);
signals:
void appClicked(const QModelIndex &index);
private:
QPixmap m_pixmap;
QVBoxLayout *m_layout;
QTabWidget *m_tabs;
};
#endif // MOREAPPSWIDGET_H

View File

@@ -73,18 +73,18 @@ ConfigWindow::ConfigWindow(QWidget *parent) : QTabWidget(parent) {
m_buttonList, &ButtonListView::selectAll);
listLayout->addWidget(setAllButtons);
addTab(visuals, tr("Interface"));
setTabIcon(0, QIcon(modifier + "graphics.png"));
addTab(visuals, QIcon(modifier + "graphics.png"),
tr("Interface"));
// filename
m_filenameEditor = new FileNameEditor();
addTab(m_filenameEditor, tr("Filename Editor"));
setTabIcon(1, QIcon(modifier + "name_edition.png"));
addTab(m_filenameEditor, QIcon(modifier + "name_edition.png"),
tr("Filename Editor"));
// general
m_generalConfig = new GeneneralConf();
addTab(m_generalConfig, tr("General"));
setTabIcon(2, QIcon(modifier + "config.png"));
addTab(m_generalConfig, QIcon(modifier + "config.png"),
tr("General"));
// connect update sigslots
connect(this, &ConfigWindow::updateChildren,

View File

@@ -17,11 +17,12 @@
#include "desktopfileparse.h"
#include <QFile>
#include <QDir>
#include <QString>
#include <QTextStream>
#include <QLocale>
DesktopFileParse::DesktopFileParse() {
DesktopFileParser::DesktopFileParser() {
QString locale = QLocale().name();
QString localeShort = QLocale().name().left(2);
m_localeName = QString("Name[%1]").arg(locale);
@@ -29,79 +30,123 @@ DesktopFileParse::DesktopFileParse() {
m_localeNameShort = QString("Name[%1]").arg(localeShort);
m_localeDescriptionShort = QString("Comment[%1]")
.arg(localeShort);
m_defaultIcon = QIcon::fromTheme("application-x-executable");
}
DesktopAppData DesktopFileParse::parseDesktopFile(
const QString &fileName, bool &ok)
DesktopAppData DesktopFileParser::parseDesktopFile(
const QString &fileName, bool &ok) const
{
DesktopAppData res;
ok = true;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
ok = false;
return res;
}
bool nameLocaleSet = false;
bool descriptionLocaleSet = false;
bool isApplication = false;
bool isGraphics = false;
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith("Icon")) {
res.icon = QIcon::fromTheme(
line.mid(line.indexOf("=")+1).trimmed());
}
else if (!nameLocaleSet && line.startsWith("Name")) {
if (line.startsWith(m_localeName) ||
line.startsWith(m_localeNameShort))
{
res.name = line.mid(line.indexOf("=")+1).trimmed();
nameLocaleSet = true;
} else if (line.startsWith("Name=")) {
res.name = line.mid(line.indexOf("=")+1).trimmed();
}
}
else if (!descriptionLocaleSet && line.startsWith("Comment")) {
if (line.startsWith(m_localeDescription) ||
line.startsWith(m_localeDescriptionShort))
{
res.description = line.mid(line.indexOf("=")+1).trimmed();
descriptionLocaleSet = true;
} else if (line.startsWith("Comment=")) {
res.description = line.mid(line.indexOf("=")+1).trimmed();
}
}
else if (line.startsWith("MimeType") &&
!line.contains("image/png"))
{
ok = false;
break;
}
else if (line.startsWith("Exec")) {
if (line.contains("%")) {
res.exec = line.mid(line.indexOf("=")+1)
.trimmed();
} else {
ok = false;
break;
}
}
else if (line.startsWith("Type")) {
if (line.contains("Application")) {
isApplication = true;
}
}
else if (line.startsWith("Categories")) {
if (line.contains("Graphics")) {
isGraphics = true;
}
}
}
file.close();
if (res.exec.isEmpty() || res.name.isEmpty() || !isApplication ||
!isGraphics) {
ok = false;
}
return res;
DesktopAppData res;
ok = true;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
ok = false;
return res;
}
bool nameLocaleSet = false;
bool descriptionLocaleSet = false;
bool isApplication = false;
QTextStream in(&file);
// enter the desktop entry definition
while (!in.atEnd() && in.readLine() != "[Desktop Entry]") {
}
// start parsing
while (!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith("Icon")) {
res.icon = QIcon::fromTheme(
line.mid(line.indexOf("=")+1).trimmed(),
m_defaultIcon);
}
else if (!nameLocaleSet && line.startsWith("Name")) {
if (line.startsWith(m_localeName) ||
line.startsWith(m_localeNameShort))
{
res.name = line.mid(line.indexOf("=")+1).trimmed();
nameLocaleSet = true;
} else if (line.startsWith("Name=")) {
res.name = line.mid(line.indexOf("=")+1).trimmed();
}
}
else if (!descriptionLocaleSet && line.startsWith("Comment")) {
if (line.startsWith(m_localeDescription) ||
line.startsWith(m_localeDescriptionShort))
{
res.description = line.mid(line.indexOf("=")+1).trimmed();
descriptionLocaleSet = true;
} else if (line.startsWith("Comment=")) {
res.description = line.mid(line.indexOf("=")+1).trimmed();
}
}
else if (line.startsWith("Exec")) {
if (line.contains("%")) {
res.exec = line.mid(line.indexOf("=")+1)
.trimmed();
} else {
ok = false;
break;
}
}
else if (line.startsWith("Type")) {
if (line.contains("Application")) {
isApplication = true;
}
}
else if (line.startsWith("Categories")) {
res.categories = line.mid(line.indexOf("=")+1).split(";");
}
else if (line == "NoDisplay=true") {
ok = false;
break;
}
else if (line == "Terminal=true") {
res.showInTerminal = true;
}
// ignore the other entries
else if (line.startsWith("[")) {
break;
}
}
file.close();
if (res.exec.isEmpty() || res.name.isEmpty() || !isApplication) {
ok = false;
}
return res;
}
int DesktopFileParser::processDirectory(const QDir &dir) {
QStringList entries = dir.entryList(QDir::NoDotAndDotDot | QDir::Files);
bool ok;
int length = m_appList.length();
for (QString file: entries){
DesktopAppData app = parseDesktopFile(dir.absoluteFilePath(file), ok);
if (ok) {
m_appList.append(app);
}
}
return m_appList.length() - length;
}
QList<DesktopAppData> DesktopFileParser::getAppsByCategory(const QString &category) {
QList<DesktopAppData> res;
for (const DesktopAppData &app : m_appList) {
if (app.categories.contains(category)) {
res.append(app);
}
}
return res;
}
QMap<QString, QList<DesktopAppData>> DesktopFileParser::getAppsByCategory(
const QStringList &categories)
{
QMap<QString, QList<DesktopAppData>> res;
for (const DesktopAppData &app : m_appList) {
for (const QString &category: categories) {
if (app.categories.contains(category)) {
res[category].append(app);
}
}
}
return res;
}

View File

@@ -19,21 +19,48 @@
#define DESKTOPFILEPARSE_H
#include <QIcon>
#include <QStringList>
#include <QMap>
class QFile;
class QDir;
class QString;
class QTextStream;
struct DesktopAppData {
QIcon icon;
DesktopAppData() = default;
DesktopAppData(
QString name,
QString description,
QString exec,
QIcon icon) :
name(name),
description(description),
exec(exec),
icon(icon),
showInTerminal(false)
{}
bool operator==(const DesktopAppData &other) const {
return name == other.name;
}
QString name;
QString description;
QString exec;
QStringList categories;
QIcon icon;
bool showInTerminal;
};
struct DesktopFileParse {
DesktopFileParse();
DesktopAppData parseDesktopFile(const QString &fileName, bool &ok);
struct DesktopFileParser {
DesktopFileParser();
DesktopAppData parseDesktopFile(const QString &fileName, bool &ok) const;
int processDirectory(const QDir &dir);
QList<DesktopAppData> getAppsByCategory(const QString &category);
QMap<QString, QList<DesktopAppData>> getAppsByCategory(
const QStringList &categories);
private:
QString m_localeName;
@@ -41,6 +68,8 @@ private:
QString m_localeNameShort;
QString m_localeDescriptionShort;
QIcon m_defaultIcon;
QList<DesktopAppData> m_appList;
};
#endif // DESKTOPFILEPARSE_H