diff --git a/flameshot.pro b/flameshot.pro
index e37d5c32..7e122a86 100644
--- a/flameshot.pro
+++ b/flameshot.pro
@@ -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
diff --git a/src/capture/workers/launcher/applauncherwidget.cpp b/src/capture/workers/launcher/applauncherwidget.cpp
index 20a5ee28..d11ca10d 100644
--- a/src/capture/workers/launcher/applauncherwidget.cpp
+++ b/src/capture/workers/launcher/applauncherwidget.cpp
@@ -16,12 +16,12 @@
// along with Flameshot. If not, see .
#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
-#include
+#include
#include
#include
#include
@@ -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 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 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) {
diff --git a/src/capture/workers/launcher/applauncherwidget.h b/src/capture/workers/launcher/applauncherwidget.h
index 97646cde..927c0346 100644
--- a/src/capture/workers/launcher/applauncherwidget.h
+++ b/src/capture/workers/launcher/applauncherwidget.h
@@ -18,9 +18,11 @@
#ifndef APPLAUNCHERWIDGET_H
#define APPLAUNCHERWIDGET_H
+#include "src/utils/desktopfileparse.h"
#include
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;
};
diff --git a/src/capture/workers/launcher/launcheritemdelegate.cpp b/src/capture/workers/launcher/launcheritemdelegate.cpp
index 9a88863b..e98aa62b 100644
--- a/src/capture/workers/launcher/launcheritemdelegate.cpp
+++ b/src/capture/workers/launcher/launcheritemdelegate.cpp
@@ -18,12 +18,12 @@
#include "launcheritemdelegate.h"
#include
-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
{
diff --git a/src/capture/workers/launcher/launcheritemdelegate.h b/src/capture/workers/launcher/launcheritemdelegate.h
index 43b11bf7..3d778f0d 100644
--- a/src/capture/workers/launcher/launcheritemdelegate.h
+++ b/src/capture/workers/launcher/launcheritemdelegate.h
@@ -21,11 +21,11 @@
#include "src/utils/desktopfileparse.h"
#include
-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,
diff --git a/src/capture/workers/launcher/moreappswidget.cpp b/src/capture/workers/launcher/moreappswidget.cpp
new file mode 100644
index 00000000..507d85d5
--- /dev/null
+++ b/src/capture/workers/launcher/moreappswidget.cpp
@@ -0,0 +1,111 @@
+#include "moreappswidget.h"
+#include "src/capture/workers/launcher/launcheritemdelegate.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+// 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> appsMap =
+ ctor_parser.getAppsByCategory(categories);
+
+ // Unify multimedia.
+ QList 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 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 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);
+ }
+ }
+}
diff --git a/src/capture/workers/launcher/moreappswidget.h b/src/capture/workers/launcher/moreappswidget.h
new file mode 100644
index 00000000..626d09bc
--- /dev/null
+++ b/src/capture/workers/launcher/moreappswidget.h
@@ -0,0 +1,28 @@
+#ifndef MOREAPPSWIDGET_H
+#define MOREAPPSWIDGET_H
+
+#include "src/utils/desktopfileparse.h"
+#include
+
+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
diff --git a/src/config/configwindow.cpp b/src/config/configwindow.cpp
index c1e197fb..aedb5cb5 100644
--- a/src/config/configwindow.cpp
+++ b/src/config/configwindow.cpp
@@ -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,
diff --git a/src/utils/desktopfileparse.cpp b/src/utils/desktopfileparse.cpp
index 7d02d78f..7843048a 100644
--- a/src/utils/desktopfileparse.cpp
+++ b/src/utils/desktopfileparse.cpp
@@ -17,11 +17,12 @@
#include "desktopfileparse.h"
#include
+#include
#include
#include
#include
-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 DesktopFileParser::getAppsByCategory(const QString &category) {
+ QList res;
+ for (const DesktopAppData &app : m_appList) {
+ if (app.categories.contains(category)) {
+ res.append(app);
+ }
+ }
+ return res;
+}
+
+QMap> DesktopFileParser::getAppsByCategory(
+ const QStringList &categories)
+{
+ QMap> res;
+ for (const DesktopAppData &app : m_appList) {
+ for (const QString &category: categories) {
+ if (app.categories.contains(category)) {
+ res[category].append(app);
+ }
+ }
+ }
+ return res;
}
diff --git a/src/utils/desktopfileparse.h b/src/utils/desktopfileparse.h
index abac73b2..f64fc69d 100644
--- a/src/utils/desktopfileparse.h
+++ b/src/utils/desktopfileparse.h
@@ -19,21 +19,48 @@
#define DESKTOPFILEPARSE_H
#include
+#include
+#include
-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 getAppsByCategory(const QString &category);
+ QMap> getAppsByCategory(
+ const QStringList &categories);
private:
QString m_localeName;
@@ -41,6 +68,8 @@ private:
QString m_localeNameShort;
QString m_localeDescriptionShort;
+ QIcon m_defaultIcon;
+ QList m_appList;
};
#endif // DESKTOPFILEPARSE_H