appmenu.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #include "appmenu.h"
  2. void AppMenuApplet::externalWidgetSetup() {
  3. mExternalWidget = new QPushButton();
  4. mExternalWidget->setFont(mCfgMan->mFont);
  5. mExternalWidget->setObjectName("appMenuButton");
  6. static_cast<QPushButton*>(mExternalWidget)->setFlat(true);
  7. mExternalWidget->setToolTip("List of installed applications");
  8. int appMenuIconSize = mCfgMan->mMenuIconSize;
  9. static_cast<QPushButton*>(mExternalWidget)->setIconSize(
  10. QSize(appMenuIconSize, appMenuIconSize)
  11. );
  12. QString menuIcon = mCfgMan->mMenuIcon;
  13. if (QIcon::hasThemeIcon(menuIcon)) {
  14. static_cast<QPushButton*>(mExternalWidget)->setIcon(
  15. QIcon::fromTheme(menuIcon)
  16. );
  17. }
  18. else {
  19. static_cast<QPushButton*>(mExternalWidget)->setIcon(QIcon(menuIcon));
  20. }
  21. if (mParentPanel->mPanelLayout == Horizontal) {
  22. QString menuText = mCfgMan->mMenuText;
  23. if (!menuText.isEmpty()) {
  24. static_cast<QPushButton*>(mExternalWidget)->setText(
  25. QString(" %1").arg(menuText)
  26. );
  27. }
  28. }
  29. // Make connections
  30. connect(static_cast<QPushButton*>(mExternalWidget),
  31. &QPushButton::clicked, this, [this]() {
  32. if (!mInternalWidget->isVisible()) {
  33. mTabWidget->setCurrentIndex(0);
  34. mSearchBox->clear();
  35. buildMenu(mAppsList, "");
  36. buildFavMenu(mCfgMan, mFavAppsList);
  37. if (mCfgMan->mTransparent) {
  38. setBlurredBackground();
  39. }
  40. mInternalWidget->show();
  41. }
  42. else {
  43. mAppsList->clear();
  44. mFavAppsList->clear();
  45. mInternalWidget->hide();
  46. }
  47. });
  48. }
  49. void AppMenuApplet::internalWidgetSetup() {
  50. mInternalWidget = new QWidget();
  51. // Geometry
  52. QScreen* screen = mParentPanel->mPanelScreen;
  53. int width = 450, height = screen->geometry().height() / 2;
  54. preliminaryInternalWidgetSetup(width, height, true);
  55. mInternalWidget->setObjectName("appMenu");
  56. mInternalWidget->setWindowTitle("plainDE App Menu");
  57. // Main UI
  58. mMainLayout = new QVBoxLayout(mInternalWidget);
  59. mMainLayout->setContentsMargins(4, 4, 4, 4);
  60. mTabWidget = new QTabWidget();
  61. mTabWidget->setFont(mCfgMan->mFont);
  62. mTabWidget->setTabShape((mCfgMan->mUseTriangularTabs) ? QTabWidget::Triangular : QTabWidget::Rounded);
  63. mMainLayout->addWidget(mTabWidget);
  64. // All applications tab UI
  65. mAllAppsTab = new QWidget();
  66. mAllAppsLayout = new QVBoxLayout(mAllAppsTab);
  67. mAllAppsLayout->setContentsMargins(4, 4, 4, 4);
  68. mSearchBox = new QLineEdit();
  69. mSearchBox->setPlaceholderText("🔎 " + tr("Search")); // u+01f50e - magnifier icon
  70. mSearchBox->setClearButtonEnabled(true);
  71. mSearchBox->setFont(mCfgMan->mFont);
  72. mAllAppsLayout->addWidget(mSearchBox);
  73. mAppsList = new QListWidget();
  74. mAppsList->setFont(mCfgMan->mFont);
  75. mAppsList->setStyleSheet("QListView::item:selected { background-color: " + mCfgMan->mAccent + "; color: #ffffff };");
  76. mAllAppsLayout->addWidget(mAppsList);
  77. mTabWidget->addTab(mAllAppsTab, tr("All applications"));
  78. // Favorite apps tab UI
  79. mFavAppsTab = new QWidget();
  80. mFavAppsLayout = new QVBoxLayout(mFavAppsTab);
  81. mFavAppsLayout->setContentsMargins(4, 4, 4, 4);
  82. mFavAppsList = new QListWidget();
  83. mFavAppsList->setFont(mCfgMan->mFont);
  84. mFavAppsList->setStyleSheet("QListView::item:selected { background-color: " + mCfgMan->mAccent + "; color: #ffffff };");
  85. mFavAppsLayout->addWidget(mFavAppsList);
  86. mTabWidget->addTab(mFavAppsTab, tr("Favorite apps"));
  87. // Run tab UI
  88. mRunTab = new QWidget();
  89. mRunLayout = new QVBoxLayout(mRunTab);
  90. mRunLayout->setContentsMargins(4, 4, 4, 4);
  91. mRunLabel = new QLabel(tr("Enter command:"));
  92. mRunLabel->setFont(mCfgMan->mFont);
  93. mRunLayout->addWidget(mRunLabel);
  94. mCmdLineEdit = new QLineEdit();
  95. mCmdLineEdit->setFont(mCfgMan->mFont);
  96. mRunLayout->addWidget(mCmdLineEdit);
  97. mRunPushButton = new QPushButton(tr("Run"));
  98. mRunPushButton->setFont(mCfgMan->mFont);
  99. mRunLayout->addWidget(mRunPushButton);
  100. mRunLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding));
  101. mTabWidget->addTab(mRunTab, tr("Run"));
  102. // Build menus
  103. buildMenu(mAppsList, "");
  104. buildFavMenu(mCfgMan, mFavAppsList);
  105. // Make connections
  106. mAllAppsTab->connect(mSearchBox, &QLineEdit::textEdited, mAllAppsTab,
  107. [this]() {
  108. buildMenu(mAppsList, mSearchBox->text());
  109. });
  110. mAllAppsTab->connect(mAppsList, &QListWidget::itemActivated, mAllAppsTab,
  111. [this]() {
  112. execApp(mExecByItem[mAppsList->selectedItems()[0]]);
  113. });
  114. mFavAppsTab->connect(mFavAppsList, &QListWidget::itemActivated, mFavAppsTab,
  115. [this]() {
  116. execApp(mExecByItem[mFavAppsList->selectedItems()[0]]);
  117. });
  118. mRunTab->connect(mRunPushButton, &QPushButton::clicked, mInternalWidget,
  119. [this]() {
  120. if (!mCmdLineEdit->text().isEmpty()) {
  121. execApp(mCmdLineEdit->text());
  122. mCmdLineEdit->clear();
  123. }
  124. });
  125. }
  126. App AppMenuApplet::readDesktopEntry(QString desktopEntryPath) {
  127. App app;
  128. QString iconPath;
  129. QSettings desktopFileReader(desktopEntryPath, QSettings::IniFormat);
  130. desktopFileReader.sync();
  131. desktopFileReader.beginGroup("Desktop Entry");
  132. if (!desktopFileReader.value("NoDisplay").toBool()) {
  133. app.display = true;
  134. app.displayedName = desktopFileReader.value("Name").toString();
  135. app.exec = desktopFileReader.value("Exec").toString();
  136. iconPath = desktopFileReader.value("Icon").toString();
  137. if (QIcon::hasThemeIcon(iconPath)) {
  138. app.icon = QIcon::fromTheme(iconPath);
  139. }
  140. else {
  141. if (QFile::exists(iconPath)) {
  142. app.icon = QIcon(iconPath);
  143. }
  144. else {
  145. app.icon = QIcon::fromTheme("dialog-question");
  146. }
  147. }
  148. }
  149. else {
  150. app.display = false;
  151. }
  152. desktopFileReader.endGroup();
  153. return app;
  154. }
  155. void AppMenuApplet::execApp(QString exec) {
  156. QObject* parent = mParentPanel->mExecHolder;
  157. QProcess* process = new QProcess(parent);
  158. // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#exec-variables
  159. if (exec[exec.length()-2] == "%") {
  160. exec.chop(2);
  161. }
  162. process->start(exec);
  163. mInternalWidget->hide();
  164. }
  165. void AppMenuApplet::buildMenu(QListWidget* appsList, QString filter) {
  166. QDir appDir("/usr/share/applications");
  167. QStringList desktopEntriesList = appDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
  168. App currentApp;
  169. mExecByItem.clear();
  170. appsList->clear();
  171. for (int i = 0; i < desktopEntriesList.length(); ++i) {
  172. currentApp = readDesktopEntry(appDir.absoluteFilePath(desktopEntriesList[i]));
  173. if (desktopEntriesList[i].endsWith(".desktop")) {
  174. if (currentApp.display) {
  175. if (currentApp.displayedName.contains(filter, Qt::CaseInsensitive)) {
  176. QListWidgetItem* item = new QListWidgetItem(currentApp.displayedName);
  177. if (!currentApp.icon.isNull()) {
  178. item->setIcon(currentApp.icon);
  179. }
  180. else {
  181. item->setIcon(QIcon::fromTheme("dialog-question"));
  182. }
  183. appsList->addItem(item);
  184. mExecByItem[item] = currentApp.exec;
  185. }
  186. }
  187. }
  188. }
  189. QString homeDir = getenv("HOME");
  190. if (QDir(homeDir + "/.local/share/applications").exists()) {
  191. appDir.cd(homeDir + "/.local/share/applications");
  192. desktopEntriesList = appDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
  193. for (int i = 0; i < desktopEntriesList.length(); ++i) {
  194. currentApp = readDesktopEntry(appDir.absoluteFilePath(desktopEntriesList[i]));
  195. if (desktopEntriesList[i].endsWith(".desktop")) {
  196. if (currentApp.display) {
  197. if (currentApp.displayedName.contains(filter, Qt::CaseInsensitive)) {
  198. QListWidgetItem* item = new QListWidgetItem(currentApp.displayedName);
  199. if (!currentApp.icon.isNull()) {
  200. item->setIcon(currentApp.icon);
  201. }
  202. else {
  203. item->setIcon(QIcon::fromTheme("dialog-question"));
  204. }
  205. appsList->addItem(item);
  206. mExecByItem[item] = currentApp.exec;
  207. }
  208. }
  209. }
  210. }
  211. }
  212. appsList->sortItems();
  213. }
  214. void AppMenuApplet::buildFavMenu(ConfigManager* cfgMan, QListWidget* favAppsList) {
  215. favAppsList->clear();
  216. QString homeDir = getenv("HOME");
  217. QDir globalAppDir("/usr/share/applications");
  218. QDir localAppDir(homeDir + "/.local/share/applications");
  219. QStringList globalDesktopEntriesList = globalAppDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
  220. QStringList localDesktopEntriesList = localAppDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
  221. QString desktopEntryPath;
  222. App currentApp;
  223. for (int i = 0; i < cfgMan->mFavApps.count(); ++i) {
  224. QString favDesktopEntry = cfgMan->mFavApps.at(i).toString();
  225. if (globalDesktopEntriesList.contains(favDesktopEntry)) {
  226. desktopEntryPath = globalAppDir.absoluteFilePath(favDesktopEntry);
  227. currentApp = readDesktopEntry(desktopEntryPath);
  228. QListWidgetItem* item = new QListWidgetItem(currentApp.displayedName);
  229. if (!currentApp.icon.isNull()) {
  230. item->setIcon(currentApp.icon);
  231. }
  232. else {
  233. item->setIcon(QIcon::fromTheme("dialog-question"));
  234. }
  235. favAppsList->addItem(item);
  236. mExecByItem[item] = currentApp.exec;
  237. }
  238. else if (localDesktopEntriesList.contains(favDesktopEntry)) {
  239. desktopEntryPath = localAppDir.absoluteFilePath(favDesktopEntry);
  240. currentApp = readDesktopEntry(desktopEntryPath);
  241. QListWidgetItem* item = new QListWidgetItem(currentApp.displayedName);
  242. if (!currentApp.icon.isNull()) {
  243. item->setIcon(currentApp.icon);
  244. }
  245. else {
  246. item->setIcon(QIcon::fromTheme("dialog-question"));
  247. }
  248. favAppsList->addItem(item);
  249. mExecByItem[item] = currentApp.exec;
  250. }
  251. }
  252. favAppsList->sortItems();
  253. }
  254. AppMenuApplet::AppMenuApplet(ConfigManager* cfgMan,
  255. Panel* parentPanel) : StaticApplet(
  256. "org.plainDE.appMenu",
  257. cfgMan,
  258. parentPanel
  259. ) {
  260. }
  261. AppMenuApplet::~AppMenuApplet() {
  262. mInternalWidget->hide();
  263. while (mAppsList->count() > 0) {
  264. delete mAppsList->item(0);
  265. }
  266. while (mFavAppsList->count() > 0) {
  267. delete mFavAppsList->item(0);
  268. }
  269. mExecByItem.clear();
  270. delete mRunPushButton;
  271. delete mCmdLineEdit;
  272. delete mRunLabel;
  273. delete mRunLayout;
  274. delete mRunTab;
  275. delete mFavAppsList;
  276. delete mFavAppsLayout;
  277. delete mFavAppsTab;
  278. delete mAppsList;
  279. delete mSearchBox;
  280. delete mAllAppsLayout;
  281. delete mAllAppsTab;
  282. delete mTabWidget;
  283. delete mMainLayout;
  284. delete mInternalWidget;
  285. delete mExternalWidget;
  286. }