├── .gitignore ├── screenshots ├── custom.png ├── manjaro-search.png └── manjaro-default.png ├── contents ├── locale │ ├── de │ │ └── LC_MESSAGES │ │ │ └── plasma_applet_p-connor.plasma-drawer.mo │ ├── ro │ │ └── LC_MESSAGES │ │ │ └── plasma_applet_p-connor.plasma-drawer.mo │ ├── ru │ │ └── LC_MESSAGES │ │ │ └── plasma_applet_p-connor.plasma-drawer.mo │ └── uk │ │ └── LC_MESSAGES │ │ └── plasma_applet_p-connor.plasma-drawer.mo ├── ui │ ├── ItemListDelegate.qml │ ├── DrawerTheme.qml │ ├── ActionMenu.qml │ ├── CompactRepresentation.qml │ ├── main.qml │ ├── ConfigSearch.qml │ ├── ItemGridDelegate.qml │ ├── AppsGridView.qml │ ├── ItemListView.qml │ ├── RunnerResultsView.qml │ ├── MenuRepresentation.qml │ ├── ItemGridView.qml │ └── ConfigGeneral.qml ├── config │ ├── config.qml │ └── main.xml └── code │ └── tools.js ├── .github └── ISSUE_TEMPLATE │ ├── question.md │ ├── translation.md │ ├── feature_request.md │ └── bug_report.md ├── Makefile ├── metadata.desktop ├── translate ├── build.sh ├── README.md ├── plasmoidlocaletest.sh ├── template.pot ├── merge.sh ├── uk.po ├── ru.po ├── ro.po └── de.po └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.plasmoid 2 | metadata.json -------------------------------------------------------------------------------- /screenshots/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/screenshots/custom.png -------------------------------------------------------------------------------- /screenshots/manjaro-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/screenshots/manjaro-search.png -------------------------------------------------------------------------------- /screenshots/manjaro-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/screenshots/manjaro-default.png -------------------------------------------------------------------------------- /contents/locale/de/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/contents/locale/de/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo -------------------------------------------------------------------------------- /contents/locale/ro/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/contents/locale/ro/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo -------------------------------------------------------------------------------- /contents/locale/ru/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/contents/locale/ru/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo -------------------------------------------------------------------------------- /contents/locale/uk/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p-connor/plasma-drawer/HEAD/contents/locale/uk/LC_MESSAGES/plasma_applet_p-connor.plasma-drawer.mo -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about this project 4 | title: "[Question] My question" 5 | labels: type:question 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | **Describe your question** 12 | Your question including any additional context 13 | 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/translation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Translation 3 | about: Upload the translations for your language 4 | title: "[Translation] New Language" 5 | labels: type:internationalization 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | **List your translated language** 12 | Your language. 13 | 14 | **Describe any issues you encountered during the translation process** 15 | A clear and concise description of any difficulties you faced or any additional context regarding your translations that you wish me to know about. 16 | 17 | **Attach your translation file below** -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature Request] Title" 5 | labels: type:enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Prerequsites: Install kreadconfig5, kpackagetool6, zip, desktoptojson 2 | # Example usages: 'make install', 'make VERSION=1.0 package' 3 | 4 | DIR = $(shell pwd) 5 | VERSION = $(shell kreadconfig5 --file="$(DIR)/metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Version") 6 | PACKAGE_NAME = plasma-drawer-$(VERSION).plasmoid 7 | 8 | $(PACKAGE_NAME): $(shell find contents -type f) metadata.json README.md 9 | zip -r $(PACKAGE_NAME) contents metadata.json README.md 10 | 11 | # Generate .json metadata file as deprecated .desktop files are easier to work with for translation scripts 12 | metadata.json: metadata.desktop 13 | desktoptojson -i metadata.desktop -o metadata.json 14 | 15 | package: $(PACKAGE_NAME) 16 | 17 | install: $(PACKAGE_NAME) 18 | kpackagetool6 -t Plasma/Applet -i $(PACKAGE_NAME) 19 | 20 | upgrade: $(PACKAGE_NAME) 21 | kpackagetool6 -t Plasma/Applet -u $(PACKAGE_NAME) 22 | 23 | uninstall: 24 | kpackagetool6 -t Plasma/Applet -r p-connor.plasma-drawer 25 | 26 | test: 27 | QT_LOGGING_RULES="qml.debug=true" plasmoidviewer -a ./ 28 | 29 | clean: 30 | rm *.plasmoid metadata.json 31 | -------------------------------------------------------------------------------- /metadata.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Plasma Drawer 3 | Comment=A fullscreen customizable launcher with application directories and krunner-like search 4 | 5 | Type=Service 6 | Icon=start-here-kde 7 | 8 | X-Plasma-API-Minimum-Version=6.0 9 | X-Plasma-Provides=org.kde.plasma.launchermenu 10 | 11 | X-KDE-PluginInfo-Author=Connor Popp 12 | X-KDE-PluginInfo-Email=cmpopp2@gmail.com 13 | X-KDE-PluginInfo-Name=p-connor.plasma-drawer 14 | X-KDE-PluginInfo-Version=2.0.1 15 | X-KDE-PluginInfo-Website=https://github.com/p-connor/plasma-drawer 16 | X-KDE-PluginInfo-Category=Application Launchers 17 | 18 | KPackageStructure=Plasma/Applet 19 | 20 | Name[de]=Plasma Drawer 21 | Name[ro]=Plasma Drawer 22 | Name[ru]=Plasma Drawer 23 | Name[uk]=Plasma Drawer 24 | Comment[de]=Ein konfigurierbarer Fullscreen Launcher mit Anwendungsordnern und einer Krunner-artigen Suche 25 | Comment[ro]=Un launcher pe tot ecranul customizabil cu aplcații, directoare și căutare care arată ca krunner 26 | Comment[ru]=Полноэкранный настраиваемый лаунчер с директориями програм и поиском в стиле KRunner 27 | Comment[uk]=Повноекранний налаштовуваний лаунчер з теками програм та пошуком у стилі KRunner 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Bug] Title" 5 | labels: type:bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Device (please complete the following information, which can be found in the KInfoCenter):** 27 | - Distro: [e.g. KDE Neon] 28 | - KDE Version: [e.g. 5.24.7] 29 | - KDE Frameworks Version: [e.g. 5.92.0] 30 | - Qt Version: [e.g. 5.15.3] 31 | - Kernel Version: [e.g. 5.15.0-58-generic] 32 | - Graphics Platform: [e.g. X11, Wayland] 33 | - Device Type (if relevant): [e.g. Desktop, Tablet, Steam Deck] 34 | 35 | If the bug is performance related, please also include the following: 36 | Processor: [e.g. AMD Ryzen 5 3600x] 37 | Memory: [e.g. 16GB] 38 | Graphics Processor: [e.g. NVIDIA RTX 3060 Ti] 39 | 40 | **Additional context** 41 | Add any other context about the problem here. 42 | -------------------------------------------------------------------------------- /contents/ui/ItemListDelegate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | 3 | import org.kde.plasma.plasmoid 4 | import org.kde.plasma.components 3.0 as PC3 5 | import org.kde.kirigami as Kirigami 6 | import org.kde.kquickcontrolsaddons 7 | 8 | Item { 9 | id: item 10 | 11 | implicitWidth: ListView.view.width 12 | implicitHeight: iconSize * 1.5 13 | 14 | property int iconSize: Kirigami.Units.iconSizes.large 15 | readonly property int sourceIconSize: matchIcon.implicitWidth 16 | 17 | readonly property bool hasActionList: ("hasActionList" in model) && (model.hasActionList == true) 18 | 19 | function getActionList() { 20 | return model.actionList; 21 | } 22 | 23 | Kirigami.Icon { 24 | id: matchIcon 25 | 26 | anchors { 27 | left: parent.left 28 | verticalCenter: parent.verticalCenter 29 | leftMargin: Kirigami.Units.largeSpacing * 1.5 30 | } 31 | 32 | width: item.iconSize 33 | height: width 34 | 35 | animated: false 36 | source: model.decoration 37 | 38 | roundToIconSize: width > Kirigami.Units.iconSizes.huge ? false : true 39 | } 40 | 41 | PC3.Label { 42 | id: matchLabel 43 | 44 | anchors { 45 | left: matchIcon.right 46 | right: parent.right 47 | verticalCenter: parent.verticalCenter 48 | leftMargin: Kirigami.Units.largeSpacing * 1.5 49 | rightMargin: Kirigami.Units.largeSpacing * 1.5 50 | } 51 | 52 | height: parent.height 53 | verticalAlignment: Text.AlignVCenter 54 | elide: Text.ElideRight 55 | wrapMode: Text.Wrap 56 | 57 | text: model.display 58 | color: drawerTheme.textColor 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /contents/config/config.qml: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014 by Eike Hein * 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program; if not, write to the * 16 | * Free Software Foundation, Inc., * 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 18 | ***************************************************************************/ 19 | 20 | import QtQuick 21 | 22 | import org.kde.plasma.configuration 23 | 24 | ConfigModel { 25 | ConfigCategory { 26 | name: i18n("General") 27 | icon: "kde" 28 | source: "ConfigGeneral.qml" 29 | } 30 | ConfigCategory { 31 | name: i18n("Search Plugins") 32 | icon: "search" 33 | source: "ConfigSearch.qml" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contents/ui/DrawerTheme.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | import org.kde.plasma.plasmoid 3 | import org.kde.kirigami as Kirigami 4 | 5 | QtObject { 6 | readonly property bool usingCustomTheme: plasmoid.configuration.backgroundType != 0 7 | readonly property color backgroundColor: usingCustomTheme ? plasmoid.configuration.customBackgroundColor : Kirigami.Theme.backgroundColor 8 | readonly property color textColor: usingCustomTheme ? getReadableTextColor(backgroundColor) : Kirigami.Theme.textColor 9 | readonly property color softTextColor: soften(textColor, 0.225) 10 | readonly property color iconColor: soften(textColor, 0.1) 11 | 12 | function getReadableTextColor(backgroundColor) { 13 | return getPerceivedBrightness(backgroundColor) < .5 ? "#ddd" : "#222"; 14 | } 15 | 16 | // Depending on the brightness of the color, make it brighter or darker by adjustment 17 | function soften(color, adjustment) { 18 | if (getPerceivedBrightness(color) > .5) { 19 | adjustment *= -1; 20 | } 21 | return brighten(color, adjustment); 22 | } 23 | 24 | // Adjust the perceived brightness of a color approximately by adjustment 25 | function brighten(color, adjustment) { 26 | let relG = color.g / color.r; 27 | let relB = color.b / color.r; 28 | let initialBrightness = getPerceivedBrightness(color); 29 | 30 | let newR = Math.sqrt((Math.pow(initialBrightness + adjustment, 2) / (.299 + .587 * Math.pow(relG, 2) + .144 * Math.pow(relB, 2)))); 31 | let newG = newR * relG; 32 | let newB = newR * relB; 33 | 34 | return Qt.rgba(newR, newG, newB, color.a); 35 | } 36 | 37 | // Method retrieved from http://alienryderflex.com/hsp.html 38 | function getPerceivedBrightness(color) { 39 | return Math.sqrt((Math.pow(color.r, 2) * .299) + (Math.pow(color.g, 2) * .587) + (Math.pow(color.b, 2) * .114)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /translate/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Version: 6 3 | 4 | # This script will convert the *.po files to *.mo files, rebuilding the package/contents/locale folder. 5 | # Feature discussion: https://phabricator.kde.org/D5209 6 | # Eg: contents/locale/fr_CA/LC_MESSAGES/plasma_applet_org.kde.plasma.eventcalendar.mo 7 | 8 | DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` 9 | plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` 10 | website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` 11 | bugAddress="$website" 12 | packageRoot=".." # Root of translatable sources 13 | projectName="plasma_applet_${plasmoidName}" # project name 14 | 15 | #--- 16 | if [ -z "$plasmoidName" ]; then 17 | echo "[build] Error: Couldn't read plasmoidName." 18 | exit 19 | fi 20 | 21 | if [ -z "$(which msgfmt)" ]; then 22 | echo "[build] Error: msgfmt command not found. Need to install gettext" 23 | echo "[build] Running 'sudo apt install gettext'" 24 | sudo apt install gettext 25 | echo "[build] gettext installation should be finished. Going back to installing translations." 26 | fi 27 | 28 | #--- 29 | echo "[build] Compiling messages" 30 | 31 | catalogs=`find . -name '*.po' | sort` 32 | for cat in $catalogs; do 33 | echo "$cat" 34 | catLocale=`basename ${cat%.*}` 35 | msgfmt -o "${catLocale}.mo" "$cat" 36 | 37 | installPath="$DIR/../contents/locale/${catLocale}/LC_MESSAGES/${projectName}.mo" 38 | 39 | echo "[build] Install to ${installPath}" 40 | mkdir -p "$(dirname "$installPath")" 41 | mv "${catLocale}.mo" "${installPath}" 42 | done 43 | 44 | echo "[build] Done building messages" 45 | 46 | if [ "$1" = "--restartplasma" ]; then 47 | echo "[build] Restarting plasmashell" 48 | killall plasmashell 49 | kstart5 plasmashell 50 | echo "[build] Done restarting plasmashell" 51 | else 52 | echo "[build] (re)install the plasmoid and restart plasmashell to test." 53 | fi 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Plasma Drawer 2 | A fullscreen customizable launcher with application directories and krunner-like search for KDE Plasma 3 | 4 | ### Screenshots 5 | 6 | ![Custom setup](https://github.com/p-connor/plasma-drawer/blob/main/screenshots/custom.png?raw=true) 7 | 8 | ![Manjaro default setup](https://github.com/p-connor/plasma-drawer/blob/main/screenshots/manjaro-default.png?raw=true) 9 | 10 | ![Krunner-like search](https://github.com/p-connor/plasma-drawer/blob/main/screenshots/manjaro-search.png?raw=true) 11 | 12 | ### Installation 13 | 14 | Download the [latest release](https://github.com/p-connor/plasma-drawer/releases/latest) and run the following command: 15 | 16 | `kpackagetool6 -t Plasma/Applet -i plasma-drawer-VERSION.plasmoid` 17 | 18 | To uninstall, use the following command: 19 | 20 | `kpackagetool6 -t Plasma/Applet -r p-connor.plasma-drawer` 21 | 22 | To upgrade to a newer version: 23 | 24 | `kpackagetool6 -t Plasma/Applet -u plasma-drawer-VERSION.plasmoid` 25 | 26 | ### Usage 27 | 28 | Add the widget to your panel or desktop, then click its icon to open it. 29 | 30 | #### Customizing Apps and Directories 31 | 32 | Right click the widget icon, then select "Edit Applications." Then rearrange or adjust as desired. 33 | The applications in the grid will be arranged left to right, top to bottom. 34 | 35 | **To add an app to the "root" page, drag or copy it out of any folder in the "Edit Applications" menu.** 36 | 37 | #### Customizing Search Plugins 38 | 39 | Right click the icon widget, then select "Configure Plasma Drawer." Then click the "Search Plugins" tab on the left. Enable and re-arrange the plugins according to personal preference. Matches for plugins higher in the list will be prioritized. 40 | 41 | #### Customizing System Actions 42 | 43 | System actions can be individually hidden by right clicking and selecting "Remove action," or disabled entirely in the widget configuration. 44 | The actions can also be rearranged by long pressing and dragging the icon to the desired position. 45 | 46 | ### Internationalization 47 | 48 | If you would like to contribute by adding translations for your language, follow the instructions in the [Translations Readme](translate/README.md). 49 | -------------------------------------------------------------------------------- /translate/README.md: -------------------------------------------------------------------------------- 1 | ## Welcome 2 | 3 | Welcome to the translations readme! If you wish to contribute and add translations for your language, follow the steps below. If the following steps are confusing or if have any questions throughout the process, feel free to reach out to me for support by [adding an issue](https://github.com/p-connor/plasma-drawer/issues/new/choose) on the github repository. I really appreciate your efforts in making Plasma Drawer more accessible to all! 4 | 5 | ## New Translations 6 | 7 | To add a new translation: 8 | 9 | 1. Find your language's 2-letter [ISO 639-1 code](https://en.wikipedia.org/wiki/ISO_639-1_codes) (for example: English is '`en`'). 10 | 11 | Note: If the translations you are adding are specific to a specific country or territory, append the 2-letter [ISO 3166-1 country code](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) to the language code with an underscore (for example, American English would be '`en_US`'). 12 | 13 | You can use the `locale` command to see the current language code your system is using, and `locale -a` to see all currently available locales on your system. 14 | 15 | 2. Copy [`template.pot`](template.pot) to a new file and name it `ll.po`, where `ll` is the locale code you found earlier (for example, '`en_US.po`'). 16 | 3. Edit the file in a text editor and fill out the following fields at the top of the file 17 | 18 | 19 | # FIRST AUTHOR , YEAR. 20 | ... 21 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 22 | "Last-Translator: FULL NAME \n" 23 | "Language-Team: LANGUAGE \n" 24 | "Language: LL\n" 25 | ... 26 | 27 | 4. Then begin translating. For each line `msgid "English Phrase"`, fill in the `msgstr` quotes below with the translated phrase. 28 | 29 | For example, if you were translating from English to Spanish, one phrase would look like this: 30 | 31 | msgid "Applications:" 32 | msgstr "Aplicaciones:" 33 | 34 | 5. Once all phrases are translated, save the file and attach it to a [new github issue](https://github.com/p-connor/plasma-drawer/issues/new/choose). I will review it and add the translation in the next widget update. 35 | 36 | Alternatively, if you're a bit more tech-savvy, you can run merge.sh, build.sh, and plasmoidlocaletest.sh in that order to build the translation and test it. Then [submit a pull request](https://github.com/p-connor/plasma-drawer/compare) in the development branch. 37 | 38 | ## Scripts 39 | 40 | The following scripts were retrieved from [Zren's Widget Library Repository](https://github.com/Zren/plasma-applet-lib/tree/master/package/translate) 41 | 42 | * `sh ./merge.sh` will parse the `i18n()` calls in the `*.qml` files and write it to the `template.pot` file. Then it will merge any changes into the `*.po` language files. 43 | * `sh ./build.sh` will convert the `*.po` files to it's binary `*.mo` version and move it to `contents/locale/...` which will bundle the translations in the `*.plasmoid` without needing the user to manually install them. 44 | * `sh ./plasmoidlocaletest.sh` will run `./build` then `plasmoidviewer` (part of `plasma-sdk`). 45 | 46 | ## Learn More 47 | 48 | * https://develop.kde.org/docs/plasma/widget/translations-i18n/#ki18n 49 | 50 | ## Translation Statuses 51 | | Locale | Lines | % Done| 52 | |----------|---------|-------| 53 | | Template | 82 | | 54 | | de | 82/82 | 100% | 55 | | ro | 70/82 | 85% | 56 | | ru | 71/82 | 86% | 57 | | uk | 71/82 | 86% | 58 | -------------------------------------------------------------------------------- /contents/ui/ActionMenu.qml: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2013 by Aurélien Gâteau * 3 | * Copyright (C) 2014-2015 by Eike Hein * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 19 | ***************************************************************************/ 20 | 21 | import QtQuick 22 | 23 | import org.kde.plasma.extras as PlasmaExtras 24 | 25 | Item { 26 | id: root 27 | 28 | property QtObject menu 29 | property Item visualParent 30 | property variant actionList 31 | property bool opened: menu ? (menu.status !== PlasmaExtras.Menu.Closed) : false 32 | 33 | signal actionClicked(string actionId, variant actionArgument) 34 | signal closed 35 | 36 | onActionListChanged: refreshMenu(); 37 | 38 | onOpenedChanged: { 39 | if (!opened) { 40 | closed(); 41 | } 42 | } 43 | 44 | function open(x, y) { 45 | if (!actionList) { 46 | return; 47 | } 48 | 49 | if (x && y) { 50 | menu.open(x, y); 51 | } else { 52 | menu.open(); 53 | } 54 | } 55 | 56 | function refreshMenu() { 57 | if (menu) { 58 | menu.destroy(); 59 | } 60 | 61 | if (!actionList) { 62 | return; 63 | } 64 | 65 | menu = contextMenuComponent.createObject(root); 66 | 67 | fillMenu(menu, actionList); 68 | } 69 | 70 | function fillMenu(menu, items) { 71 | items.forEach(function(actionItem) { 72 | if (actionItem.subActions) { 73 | // This is a menu 74 | var submenuItem = contextSubmenuItemComponent.createObject( 75 | menu, { "actionItem" : actionItem }); 76 | 77 | fillMenu(submenuItem.submenu, actionItem.subActions); 78 | 79 | } else { 80 | var item = contextMenuItemComponent.createObject( 81 | menu, 82 | { 83 | "actionItem": actionItem, 84 | } 85 | ); 86 | } 87 | }); 88 | 89 | } 90 | 91 | Component { 92 | id: contextMenuComponent 93 | 94 | PlasmaExtras.Menu { 95 | visualParent: root.visualParent 96 | } 97 | } 98 | 99 | Component { 100 | id: contextSubmenuItemComponent 101 | 102 | PlasmaExtras.MenuItem { 103 | id: submenuItem 104 | 105 | property variant actionItem 106 | 107 | text: actionItem.text ? actionItem.text : "" 108 | icon: actionItem.icon ? actionItem.icon : null 109 | 110 | property PlasmaExtras.Menu submenu: PlasmaExtras.Menu { 111 | visualParent: submenuItem.action 112 | } 113 | } 114 | } 115 | 116 | Component { 117 | id: contextMenuItemComponent 118 | 119 | PlasmaExtras.MenuItem { 120 | property variant actionItem 121 | 122 | text : actionItem.text ? actionItem.text : "" 123 | enabled : actionItem.type !== "title" && ("enabled" in actionItem ? actionItem.enabled : true) 124 | separator : actionItem.type === "separator" 125 | section : actionItem.type === "title" 126 | icon : actionItem.icon ? actionItem.icon : null 127 | checkable : actionItem.checkable ? actionItem.checkable : false 128 | checked : actionItem.checked ? actionItem.checked : false 129 | 130 | onClicked: { 131 | root.actionClicked(actionItem.actionId, actionItem.actionArgument); 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /contents/code/tools.js: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2013 by Aurélien Gâteau * 3 | * Copyright (C) 2013-2015 by Eike Hein * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program; if not, write to the * 17 | * Free Software Foundation, Inc., * 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 19 | ***************************************************************************/ 20 | 21 | .pragma library 22 | 23 | const CUSTOM_ACTION_PREFIX = "_plasmaDrawer"; 24 | 25 | function createSystemActionActions(i18n, favoriteModel, favoriteId) { 26 | if (!favoriteId || !favoriteModel) { 27 | return null; 28 | } 29 | 30 | var actions; 31 | 32 | if (favoriteModel.isFavorite(favoriteId)) { 33 | actions = [ 34 | { 35 | text: i18n("Remove action"), 36 | icon: "remove", 37 | actionId: CUSTOM_ACTION_PREFIX + "_favorite_remove" 38 | }, 39 | { 40 | text: i18n("Show all"), 41 | icon: "view-visible", 42 | actionId: CUSTOM_ACTION_PREFIX + "_favorite_reset" 43 | } 44 | ]; 45 | } else if (favoriteModel.maxFavorites === -1 || favoriteModel.count < favoriteModel.maxFavorites) { 46 | actions = [ 47 | { 48 | text: i18n("Add to system actions bar"), 49 | icon: "add", 50 | actionId: CUSTOM_ACTION_PREFIX + "_favorite_add" 51 | } 52 | ]; 53 | } else { 54 | return null; 55 | } 56 | 57 | actions.forEach((action) => action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }); 58 | return actions; 59 | } 60 | 61 | function createMenuEditAction(i18n, processRunner) { 62 | return [ 63 | { 64 | text: i18n("Edit Applications"), 65 | icon: "kmenuedit", 66 | actionId: CUSTOM_ACTION_PREFIX + "_menuedit", 67 | actionArgument: { processRunner: processRunner } 68 | } 69 | ]; 70 | } 71 | 72 | function startsWith(txt, needle) { 73 | return txt.substr(0, needle.length) === needle; 74 | } 75 | 76 | function triggerAction(plasmoid, model, index, actionId, actionArgument) { 77 | 78 | if (startsWith(actionId, CUSTOM_ACTION_PREFIX)) { 79 | return handleCustomAction(actionId, actionArgument); 80 | } 81 | 82 | var closeRequested = model.trigger(index, actionId, actionArgument); 83 | 84 | if (closeRequested) { 85 | plasmoid.expanded = false; 86 | 87 | return true; 88 | } 89 | 90 | return false; 91 | } 92 | 93 | function handleCustomAction(actionId, actionArgument) { 94 | console.log(`Handling custom action ${actionId}`); 95 | 96 | if (actionId === CUSTOM_ACTION_PREFIX + "_menuedit") { 97 | console.log("running menu editor from processRunner"); 98 | actionArgument.processRunner.runMenuEditor(); 99 | return true; 100 | } 101 | 102 | if (actionArgument.favoriteId && actionArgument.favoriteModel) { 103 | var favoriteId = actionArgument.favoriteId; 104 | var favoriteModel = actionArgument.favoriteModel; 105 | 106 | if (actionId === CUSTOM_ACTION_PREFIX + "_favorite_remove") { 107 | favoriteModel.removeFavorite(favoriteId); 108 | } else if (actionId === CUSTOM_ACTION_PREFIX + "_favorite_add") { 109 | favoriteModel.addFavorite(favoriteId); 110 | } else if (actionId == CUSTOM_ACTION_PREFIX + "_favorite_reset") { 111 | favoriteModel.favorites = [ "shutdown", 112 | "reboot", 113 | "logout", 114 | "hibernate", 115 | "suspend", 116 | "save-session", 117 | "lock-screen", 118 | "switch-user" ]; 119 | } 120 | return false; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /contents/ui/CompactRepresentation.qml: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2013-2014 by Eike Hein * 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program; if not, write to the * 16 | * Free Software Foundation, Inc., * 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 18 | ***************************************************************************/ 19 | 20 | import QtQuick 21 | import QtQuick.Layouts 22 | 23 | import org.kde.plasma.plasmoid 24 | import org.kde.plasma.core as PlasmaCore 25 | import org.kde.kirigami as Kirigami 26 | 27 | import org.kde.plasma.private.kicker as Kicker 28 | 29 | Item { 30 | id: root 31 | 32 | readonly property var screenGeometry: plasmoid.screenGeometry 33 | readonly property bool inPanel: (plasmoid.location == PlasmaCore.Types.TopEdge 34 | || plasmoid.location == PlasmaCore.Types.RightEdge 35 | || plasmoid.location == PlasmaCore.Types.BottomEdge 36 | || plasmoid.location == PlasmaCore.Types.LeftEdge) 37 | readonly property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical) 38 | readonly property bool useCustomButtonImage: (plasmoid.configuration.useCustomButtonImage 39 | && plasmoid.configuration.customButtonImage.length != 0) 40 | 41 | readonly property Component dashWindowComponent: Qt.createComponent(Qt.resolvedUrl("./MenuRepresentation.qml"), root) 42 | readonly property Kicker.DashboardWindow dashWindow: dashWindowComponent && dashWindowComponent.status === Component.Ready 43 | ? dashWindowComponent.createObject(root, { visualParent: root }) : null 44 | 45 | Plasmoid.status: dashWindow && dashWindow.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus 46 | 47 | onWidthChanged: updateSizeHints() 48 | onHeightChanged: updateSizeHints() 49 | 50 | function updateSizeHints() { 51 | if (useCustomButtonImage) { 52 | if (vertical) { 53 | const scaledHeight = Math.floor(parent.width * (buttonIcon.implicitHeight / buttonIcon.implicitWidth)); 54 | root.Layout.minimumHeight = scaledHeight; 55 | root.Layout.maximumHeight = scaledHeight; 56 | root.Layout.minimumWidth = -1; 57 | } else { 58 | const scaledWidth = Math.floor(parent.height * (buttonIcon.implicitWidth / buttonIcon.implicitHeight)); 59 | root.Layout.minimumWidth = scaledWidth; 60 | root.Layout.maximumWidth = scaledWidth; 61 | root.Layout.minimumHeight = -1; 62 | } 63 | } else { 64 | root.Layout.minimumWidth = -1; 65 | root.Layout.minimumHeight = -1; 66 | } 67 | } 68 | 69 | Kirigami.Icon { 70 | id: buttonIcon 71 | 72 | anchors.fill: parent 73 | 74 | readonly property double aspectRatio: (vertical ? implicitHeight / implicitWidth 75 | : implicitWidth / implicitHeight) 76 | 77 | source: useCustomButtonImage ? plasmoid.configuration.customButtonImage : plasmoid.configuration.icon 78 | 79 | active: mouseArea.containsMouse 80 | 81 | smooth: true 82 | 83 | // A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it 84 | // to be an icon and round it to the nearest icon size again to avoid scaling artefacts. 85 | roundToIconSize: !useCustomButtonImage || aspectRatio === 1 86 | 87 | onSourceChanged: updateSizeHints() 88 | } 89 | 90 | MouseArea 91 | { 92 | id: mouseArea 93 | 94 | anchors.fill: parent 95 | 96 | activeFocusOnTab: true 97 | hoverEnabled: !root.dashWindow || !root.dashWindow.visible 98 | 99 | Keys.onPressed: function (event) { 100 | switch (event.key) { 101 | case Qt.Key_Space: 102 | case Qt.Key_Enter: 103 | case Qt.Key_Return: 104 | case Qt.Key_Select: 105 | Plasmoid.activated(); 106 | break; 107 | } 108 | } 109 | Accessible.name: Plasmoid.title 110 | Accessible.description: toolTipSubText 111 | Accessible.role: Accessible.Button 112 | 113 | onClicked: { 114 | dashWindow.toggle() 115 | } 116 | } 117 | 118 | Component.onCompleted: { 119 | // dashWindow = Qt.createQmlObject("MenuRepresentation {}", root); 120 | plasmoid.activated.connect(function() { 121 | //<>dashWindow.visible = !dashWindow.visible; 122 | dashWindow.toggle() 123 | }); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /contents/config/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | start-here-kde 12 | 13 | 14 | 15 | false 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 128 25 | 26 | 27 | 28 | 5 29 | 30 | 31 | 32 | false 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | #000000 53 | 54 | 55 | 56 | /home 57 | 58 | 59 | 60 | 70 61 | 62 | 63 | 64 | 65 | true 66 | 67 | 68 | 69 | false 70 | 71 | 72 | 73 | false 74 | 75 | 76 | 77 | 48 78 | 79 | 80 | 81 | 82 | 0 83 | 84 | 85 | 86 | 87 | shutdown,reboot,logout 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 48 101 | 102 | 103 | 104 | false 105 | 106 | 107 | 108 | krunner_services,krunner_systemsettings,krunner_recentdocuments,baloosearch,krunner_placesrunner,locations,krunner_bookmarksrunner,krunner_appstream 109 | 110 | 111 | 112 | 113 | false 114 | 115 | 116 | 117 | 1.0 118 | 119 | 120 | 121 | 122 | false 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /translate/plasmoidlocaletest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Version 9 3 | # Requires plasmoidviewer v5.13.0 4 | 5 | function checkIfLangInstalled { 6 | if [ -x "$(command -v dpkg)" ]; then 7 | dpkg -l ${1} >/dev/null 2>&1 || ( \ 8 | echo -e "${1} not installed.\nInstalling now before continuing.\n" \ 9 | ; sudo apt install ${1} \ 10 | ) || ( \ 11 | echo -e "\nError trying to install ${1}\nPlease run 'sudo apt install ${1}'\n" \ 12 | ; exit 1 \ 13 | ) 14 | elif [ -x "$(command -v pacman)" ]; then 15 | # TODO: run `locale -a` and check if the locale is enabled. 16 | if false; then 17 | # https://wiki.archlinux.org/index.php/Locale 18 | # Uncomment the locale in /etc/locale.gen 19 | # Then run `locale-gen` 20 | echo -e "\nPlease install this locale in System Settings first.\n" 21 | exit 1 22 | else 23 | echo "" 24 | fi 25 | else 26 | echo -e "\nPackage manager not recognized. If the widget is not translated, please install the package '${1}'\n" 27 | fi 28 | } 29 | 30 | langInput="${1}" 31 | lang="" 32 | languagePack="" 33 | 34 | if [[ "$langInput" =~ ":" ]]; then # String contains a colon so assume it's a locale code. 35 | lang="${langInput}" 36 | IFS=: read -r l1 l2 <<< "${lang}" 37 | languagePack="language-pack-${l2}" 38 | fi 39 | 40 | # https://stackoverflow.com/questions/3191664/list-of-all-locales-and-their-short-codes/28357857#28357857 41 | declare -a langArr=( 42 | "af_ZA:af:Afrikaans (South Africa)" 43 | "ak_GH:ak:Akan (Ghana)" 44 | "am_ET:am:Amharic (Ethiopia)" 45 | "ar_EG:ar:Arabic (Egypt)" 46 | "as_IN:as:Assamese (India)" 47 | "az_AZ:az:Azerbaijani (Azerbaijan)" 48 | "be_BY:be:Belarusian (Belarus)" 49 | "bem_ZM:bem:Bemba (Zambia)" 50 | "bg_BG:bg:Bulgarian (Bulgaria)" 51 | "bo_IN:bo:Tibetan (India)" 52 | "bs_BA:bs:Bosnian (Bosnia and Herzegovina)" 53 | "ca_ES:ca:Catalan (Spain)" 54 | "chr_US:ch:Cherokee (United States)" 55 | "cs_CZ:cs:Czech (Czech Republic)" 56 | "cy_GB:cy:Welsh (United Kingdom)" 57 | "da_DK:da:Danish (Denmark)" 58 | "de_DE:de:German (Germany)" 59 | "el_GR:el:Greek (Greece)" 60 | "es_MX:es:Spanish (Mexico)" 61 | "et_EE:et:Estonian (Estonia)" 62 | "eu_ES:eu:Basque (Spain)" 63 | "fa_IR:fa:Persian (Iran)" 64 | "ff_SN:ff:Fulah (Senegal)" 65 | "fi_FI:fi:Finnish (Finland)" 66 | "fo_FO:fo:Faroese (Faroe Islands)" 67 | "fr_CA:fr:French (Canada)" 68 | "ga_IE:ga:Irish (Ireland)" 69 | "gl_ES:gl:Galician (Spain)" 70 | "gu_IN:gu:Gujarati (India)" 71 | "gv_GB:gv:Manx (United Kingdom)" 72 | "ha_NG:ha:Hausa (Nigeria)" 73 | "he_IL:he:Hebrew (Israel)" 74 | "hi_IN:hi:Hindi (India)" 75 | "hr_HR:hr:Croatian (Croatia)" 76 | "hu_HU:hu:Hungarian (Hungary)" 77 | "hy_AM:hy:Armenian (Armenia)" 78 | "id_ID:id:Indonesian (Indonesia)" 79 | "ig_NG:ig:Igbo (Nigeria)" 80 | "is_IS:is:Icelandic (Iceland)" 81 | "it_IT:it:Italian (Italy)" 82 | "ja_JP:ja:Japanese (Japan)" 83 | "ka_GE:ka:Georgian (Georgia)" 84 | "kk_KZ:kk:Kazakh (Kazakhstan)" 85 | "kl_GL:kl:Kalaallisut (Greenland)" 86 | "km_KH:km:Khmer (Cambodia)" 87 | "kn_IN:kn:Kannada (India)" 88 | "ko_KR:ko:Korean (South Korea)" 89 | "ko_KR:ko:Korean (South Korea)" 90 | "lg_UG:lg:Ganda (Uganda)" 91 | "lt_LT:lt:Lithuanian (Lithuania)" 92 | "lv_LV:lv:Latvian (Latvia)" 93 | "mg_MG:mg:Malagasy (Madagascar)" 94 | "mk_MK:mk:Macedonian (Macedonia)" 95 | "ml_IN:ml:Malayalam (India)" 96 | "mr_IN:mr:Marathi (India)" 97 | "ms_MY:ms:Malay (Malaysia)" 98 | "mt_MT:mt:Maltese (Malta)" 99 | "my_MM:my:Burmese (Myanmar [Burma])" 100 | "nb_NO:nb:Norwegian Bokmål (Norway)" 101 | "ne_NP:ne:Nepali (Nepal)" 102 | "nl_NL:nl:Dutch (Netherlands)" 103 | "nn_NO:nn:Norwegian Nynorsk (Norway)" 104 | "om_ET:om:Oromo (Ethiopia)" 105 | "or_IN:or:Oriya (India)" 106 | "pa_PK:pa:Punjabi (Pakistan)" 107 | "pl_PL:pl:Polish (Poland)" 108 | "ps_AF:ps:Pashto (Afghanistan)" 109 | "pt_BR:pt:Portuguese (Brazil)" 110 | "ro_RO:ro:Romanian (Romania)" 111 | "ru_RU:ru:Russian (Russia)" 112 | "rw_RW:rw:Kinyarwanda (Rwanda)" 113 | "si_LK:si:Sinhala (Sri Lanka)" 114 | "sk_SK:sk:Slovak (Slovakia)" 115 | "sl_SI:sl:Slovenian (Slovenia)" 116 | "so_SO:so:Somali (Somalia)" 117 | "sq_AL:sq:Albanian (Albania)" 118 | "sr_RS:sr:Serbian (Serbia)" 119 | "sv_SE:sv:Swedish (Sweden)" 120 | "sw_KE:sw:Swahili (Kenya)" 121 | "ta_IN:ta:Tamil (India)" 122 | "te_IN:te:Telugu (India)" 123 | "th_TH:th:Thai (Thailand)" 124 | "ti_ER:ti:Tigrinya (Eritrea)" 125 | "to_TO:to:Tonga (Tonga)" 126 | "tr_TR:tr:Turkish (Turkey)" 127 | "uk_UA:uk:Ukrainian (Ukraine)" 128 | "ur_IN:ur:Urdu (India)" 129 | "uz_UZ:uz:Uzbek (Uzbekistan)" 130 | "vi_VN:vi:Vietnamese (Vietnam)" 131 | "yo_NG:yo:Yoruba (Nigeria)" 132 | "yo_NG:yo:Yoruba (Nigeria)" 133 | "yue_HK:yu:Cantonese (Hong Kong)" 134 | "zh_CN:zh:Chinese (China)" 135 | "zu_ZA:zu:Zulu (South Africa)" 136 | ) 137 | 138 | for i in "${langArr[@]}"; do 139 | IFS=: read -r l1 l2 l3 <<< "$i" 140 | if [ "$langInput" == "$l2" ]; then 141 | lang="${l1}:${l2}" 142 | languagePack="language-pack-${l2}" 143 | fi 144 | done 145 | 146 | if [ -z "$lang" ]; then 147 | echo "plasmoidlocaletest doesn't recognize the language '$lang'" 148 | echo "Eg:" 149 | scriptcmd='sh ./plasmoidlocaletest' 150 | for i in "${langArr[@]}"; do 151 | IFS=: read -r l1 l2 l3 <<< "$i" 152 | echo " ${scriptcmd} ${l2} | ${l3}" 153 | done 154 | echo "" 155 | echo "Or use a the full locale code:" 156 | echo " ${scriptcmd} ar_EG:ar" 157 | exit 1 158 | fi 159 | 160 | IFS=: read -r l1 l2 <<< "${lang}" 161 | l1="${l1}.UTF-8" 162 | 163 | # Check if language is installed 164 | if [ ! -z "$languagePack" ]; then 165 | if [ "$lang" == "zh_CN:zh" ]; then languagePack="language-pack-zh-hans" 166 | fi 167 | 168 | checkIfLangInstalled "$languagePack" || exit 1 169 | fi 170 | 171 | 172 | echo "LANGUAGE=\"${lang}\"" 173 | echo "LANG=\"${l1}\"" 174 | 175 | scriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 176 | packageDir="${scriptDir}/.." 177 | 178 | # Build local translations for plasmoidviewer 179 | sh "${scriptDir}/build" 180 | 181 | LANGUAGE="${lang}" LANG="${l1}" LC_TIME="${l1}" QML_DISABLE_DISK_CACHE=true plasmoidviewer -a "$packageDir" -l topedge -f horizontal -x 0 -y 0 182 | -------------------------------------------------------------------------------- /contents/ui/main.qml: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014-2015 by Eike Hein * 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program; if not, write to the * 16 | * Free Software Foundation, Inc., * 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 18 | ***************************************************************************/ 19 | 20 | import QtQuick 21 | import QtQuick.Layouts 22 | import org.kde.plasma.plasmoid 23 | 24 | import org.kde.plasma.core as PlasmaCore 25 | import org.kde.ksvg as KSvg 26 | 27 | import org.kde.plasma.private.kicker as Kicker 28 | import org.kde.kitemmodels as KItemModels 29 | 30 | PlasmoidItem { 31 | id: kicker 32 | 33 | // onActiveFocusItemChanged: { 34 | // console.log("activeFocusItem", activeFocusItem); 35 | // } 36 | 37 | anchors.fill: parent 38 | 39 | signal reset 40 | 41 | preferredRepresentation: fullRepresentation 42 | 43 | compactRepresentation: null 44 | fullRepresentation: compactRepresentation 45 | 46 | property Item dragSource: null 47 | 48 | property alias systemFavoritesModel: systemModel.favoritesModel 49 | 50 | function logModelChildren(model, leadingSpace = 0) { 51 | let spacing = Array(leadingSpace + 1).join(" "); 52 | // console.log(model.description); 53 | // console.log(model.data(model.index(0, 0), 0)); 54 | 55 | var count = ("count" in model ? model.count : 1); 56 | 57 | for (let i = 0; i < count; i++) { 58 | let hasChildren = model.data(model.index(i, 0), 0x0107); 59 | 60 | console.log(spacing + `${model.data(model.index(i, 0), 0)} - ` 61 | // + hasChildren ? `(${model.modelForRow(i).count}) - ` : ' - ' 62 | + `${model.data(model.index(i, 0), 0x0101)}, ` 63 | + `Deco: ${model.data(model.index(0, 0), 1)}, ` 64 | + `IsParent: ${model.data(model.index(i, 0), 0x0106)}, ` 65 | + `HasChildren: ${hasChildren}, ` 66 | + `Group: ${model.data(model.index(i, 0), 0x0102)}` 67 | ); 68 | 69 | if (hasChildren || count > 1) { 70 | logModelChildren(model.modelForRow(i), leadingSpace + 2); 71 | continue; 72 | } 73 | } 74 | } 75 | 76 | Component { 77 | id: compactRepresentation 78 | CompactRepresentation {} 79 | } 80 | 81 | Component { 82 | id: menuRepresentation 83 | MenuRepresentation {} 84 | } 85 | 86 | Connections { 87 | target: systemFavoritesModel 88 | 89 | function onCountChanged() { 90 | if (systemFavoritesModel.count == 0) { 91 | plasmoid.configuration.showSystemActions = false; 92 | } 93 | } 94 | 95 | function onFavoritesChanged() { 96 | if (target.count > 0 && target.favorites.toString() != plasmoid.configuration.favoriteSystemActions.toString()) { 97 | plasmoid.configuration.favoriteSystemActions = target.favorites; 98 | } 99 | } 100 | } 101 | 102 | readonly property DrawerTheme drawerTheme: DrawerTheme {} 103 | 104 | readonly property Kicker.AppsModel appsModel: Kicker.AppsModel { 105 | autoPopulate: true 106 | 107 | flat: false 108 | showTopLevelItems: true 109 | sorted: false 110 | showSeparators: false 111 | paginate: false 112 | 113 | appletInterface: kicker 114 | appNameFormat: plasmoid.configuration.appNameFormat 115 | 116 | Component.onCompleted: { 117 | appsModel.refresh(); 118 | } 119 | } 120 | 121 | Kicker.SystemModel { 122 | id: systemModel 123 | 124 | Component.onCompleted: { 125 | systemFavoritesModel.enabled = true; 126 | systemFavoritesModel.maxFavorites = 8; 127 | 128 | // Favorites set on MenuRepresentation visible instead to ensure that system actions are 129 | // available at set time 130 | // systemFavoritesModel.favorites = plasmoid.configuration.favoriteSystemActions; 131 | } 132 | } 133 | 134 | // Kicker.RunnerModel no longer has the deleteWhenEmpty property, which means we must filter 135 | // out the empty results sections ourselves using a wrapper FilterProxyModel 136 | KItemModels.KSortFilterProxyModel { 137 | id: runnerModel 138 | 139 | property alias query: kickerRunnerModel.query 140 | 141 | sourceModel: Kicker.RunnerModel { 142 | id: kickerRunnerModel 143 | appletInterface: kicker 144 | runners: plasmoid.configuration.searchRunners 145 | onCountChanged: { 146 | for (let i = 0; i < count; i++) { 147 | kickerRunnerModel.modelForRow(i).countChanged.connect(runnerModel.invalidateFilter); 148 | } 149 | } 150 | } 151 | 152 | filterRowCallback: (sourceRow, sourceParent) => { 153 | return sourceModel.modelForRow(sourceRow).count > 0; 154 | } 155 | 156 | function modelForRow(proxyRow) { 157 | let sourceRow = runnerModel.mapToSource(runnerModel.index(proxyRow, 0)).row; 158 | return sourceModel.modelForRow(sourceRow); 159 | } 160 | } 161 | 162 | Kicker.DragHelper { 163 | id: dragHelper 164 | } 165 | 166 | Kicker.ProcessRunner { 167 | id: processRunner; 168 | } 169 | 170 | KSvg.FrameSvgItem { 171 | id : highlightItemSvg 172 | 173 | visible: false 174 | 175 | imagePath: "widgets/viewitem" 176 | prefix: "hover" 177 | } 178 | 179 | KSvg.FrameSvgItem { 180 | id : panelSvg 181 | 182 | visible: false 183 | 184 | imagePath: "widgets/panel-background" 185 | } 186 | 187 | function resetDragSource() { 188 | dragSource = null; 189 | } 190 | 191 | Plasmoid.contextualActions: [ 192 | PlasmaCore.Action { 193 | text: i18n("Edit Applications...") 194 | icon.name: "kmenuedit" 195 | onTriggered: processRunner.runMenuEditor() 196 | } 197 | ] 198 | } 199 | -------------------------------------------------------------------------------- /contents/ui/ConfigSearch.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | import QtQuick.Controls 3 | import QtQuick.Layouts 4 | import QtCore 6.3 5 | import QtQuick.Dialogs 6 | 7 | import org.kde.plasma.components as PC3 8 | import org.kde.kcmutils as KCM 9 | import org.kde.config as KConfig 10 | import org.kde.kirigami as Kirigami 11 | 12 | KCM.SimpleKCM { 13 | id: root 14 | 15 | property var cfg_searchRunners: plasmoid.configuration.searchRunners 16 | 17 | // TODO: Find some way to load installed plugins dynamically instead of hard-coding the defaults 18 | readonly property var defaultRunners: [ 19 | { id: "baloosearch", name: i18nc("KRunner Plugin", "File Search") }, 20 | { id: "browserhistory", name: i18nc("KRunner Plugin", "Browser History") }, 21 | { id: "browsertabs", name: i18nc("KRunner Plugin", "Browser Tabs") }, 22 | { id: "calculator", name: i18nc("KRunner Plugin", "Calculator") }, 23 | { id: "helprunner", name: i18nc("KRunner Plugin", "Help Runner") }, 24 | { id: "krunner_appstream", name: i18nc("KRunner Plugin", "Software Center") }, 25 | { id: "krunner_bookmarksrunner", name: i18nc("KRunner Plugin", "Bookmarks") }, 26 | { id: "krunner_charrunner", name: i18nc("KRunner Plugin", "Special Characters") }, 27 | { id: "krunner_dictionary", name: i18nc("KRunner Plugin", "Dictionary") }, 28 | { id: "krunner_katesessions", name: i18nc("KRunner Plugin", "Kate Sessions") }, 29 | { id: "krunner_kill", name: i18nc("KRunner Plugin", "Terminate Applications") }, 30 | { id: "krunner_konsoleprofiles", name: i18nc("KRunner Plugin", "Konsole Profiles") }, 31 | { id: "krunner_kwin", name: i18nc("KRunner Plugin", "KWin") }, 32 | { id: "krunner_placesrunner", name: i18nc("KRunner Plugin", "Places") }, 33 | { id: "krunner_plasma-desktop", name: i18nc("KRunner Plugin", "Plasma Desktop Shell") }, 34 | { id: "krunner_powerdevil", name: i18nc("KRunner Plugin", "Power") }, 35 | { id: "krunner_recentdocuments", name: i18nc("KRunner Plugin", "Recent Files") }, 36 | { id: "krunner_services", name: i18nc("KRunner Plugin", "Applications") }, 37 | { id: "krunner_sessions", name: i18nc("KRunner Plugin", "Desktop Sessions") }, 38 | { id: "krunner_shell", name: i18nc("KRunner Plugin", "Command Line") }, 39 | { id: "krunner_spellcheck", name: i18nc("KRunner Plugin", "Spell Checker") }, 40 | { id: "krunner_systemsettings", name: i18nc("KRunner Plugin", "System Settings") }, 41 | { id: "krunner_webshortcuts", name: i18nc("KRunner Plugin", "Web Search Keywords") }, 42 | { id: "locations", name: i18nc("KRunner Plugin", "Locations") }, 43 | { id: "org.kde.activities2", name: i18nc("KRunner Plugin", "Activities") }, 44 | { id: "org.kde.datetime", name: i18nc("KRunner Plugin", "Date and Time") }, 45 | { id: "unitconverter", name: i18nc("KRunner Plugin", "Unit Converter") }, 46 | { id: "windows", name: i18nc("KRunner Plugin", "Windows") } 47 | ].sort((a, b) => a.name.localeCompare(b.name)) 48 | 49 | function addRunner(runnerId) { 50 | if (runnerId 51 | && !/^\s*$/.test(runnerId) 52 | && !cfg_searchRunners.includes(runnerId) 53 | && cfg_searchRunners.length < 10000) { 54 | cfg_searchRunners = [ ...cfg_searchRunners, runnerId ]; 55 | } 56 | } 57 | 58 | function removeRunner(runnerId) { 59 | if (runnerId) { 60 | cfg_searchRunners = cfg_searchRunners.filter((r) => r !== runnerId); 61 | } 62 | } 63 | 64 | function moveRunner(fromIndex, toIndex) { 65 | if (fromIndex >= 0 && fromIndex < cfg_searchRunners.length && toIndex >= 0) { 66 | let arr = [...cfg_searchRunners]; 67 | let element = arr[fromIndex]; 68 | arr.splice(fromIndex, 1); 69 | arr.splice(toIndex, 0, element); 70 | cfg_searchRunners = arr; 71 | } 72 | } 73 | 74 | Component { 75 | id: delegateComponent 76 | ItemDelegate { 77 | id: listItem 78 | readonly property bool isActive: cfg_searchRunners.includes(modelData) 79 | 80 | contentItem: RowLayout { 81 | Kirigami.ListItemDragHandle { 82 | enabled: isActive 83 | listItem: listItem 84 | listView: runnerListView 85 | property int index: cfg_searchRunners.indexOf(modelData) 86 | property int dropNewIndex 87 | onMoveRequested: (oldIndex, newIndex) => { 88 | dropNewIndex = newIndex; 89 | } 90 | onDropped: () => { 91 | moveRunner(cfg_searchRunners.indexOf(modelData), dropNewIndex); 92 | } 93 | } 94 | Label { 95 | Layout.fillWidth: true 96 | text: defaultRunners.find((m) => m.id === modelData)?.name ?? modelData 97 | } 98 | CheckBox { 99 | checked: isActive 100 | onToggled: { 101 | checked ? addRunner(modelData) : removeRunner(modelData); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | Column { 109 | width: parent.width 110 | 111 | Kirigami.Heading { 112 | text: i18n("Plugin Allowlist") 113 | } 114 | Label { 115 | text: i18n("Note: Selected plugins must also be enabled in System Settings") 116 | font.italic: true 117 | } 118 | Button { 119 | enabled: KConfig.KAuthorized.authorizeControlModule("kcm_plasmasearch") 120 | icon.name: "settings-configure" 121 | text: i18nc("@action:button", "Configure Enabled Search Plugins…") 122 | onClicked: KCM.KCMLauncher.openSystemSettings("kcm_plasmasearch") 123 | } 124 | 125 | Kirigami.Separator { 126 | width: parent.width 127 | } 128 | 129 | ListView { 130 | id: runnerListView 131 | model: cfg_searchRunners.concat(defaultRunners.map((m) => m.id).filter((m) => !cfg_searchRunners.includes(m))) 132 | width: parent.width 133 | height: contentItem.height 134 | interactive: false 135 | 136 | delegate: Loader { 137 | required property var modelData 138 | width: runnerListView.width 139 | sourceComponent: delegateComponent 140 | } 141 | } 142 | 143 | Kirigami.Separator { 144 | width: parent.width 145 | } 146 | 147 | Item { 148 | Kirigami.FormData.isSection: true 149 | } 150 | Kirigami.Heading { 151 | level: 2 152 | text: i18n("Custom Search Plugins") 153 | } 154 | Label { 155 | text: i18n("Add any custom plugins you've installed") 156 | } 157 | RowLayout { 158 | Label { text: i18n("Plugin ID:") } 159 | TextField { 160 | id: insertTextField 161 | Keys.onPressed: (event) => { 162 | if ((event.key == Qt.Key_Enter || event.key == Qt.Key_Return)) { 163 | event.accepted = true; 164 | addRunner(insertTextField.text); 165 | insertTextField.text = ""; 166 | } 167 | } 168 | } 169 | PC3.ToolButton { 170 | icon.name: "edit-add" 171 | onClicked: { 172 | addRunner(insertTextField.text); 173 | insertTextField.text = ""; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /contents/ui/ItemGridDelegate.qml: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2015 by Eike Hein * 3 | * * 4 | * This program is free software; you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation; either version 2 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program; if not, write to the * 16 | * Free Software Foundation, Inc., * 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 18 | ***************************************************************************/ 19 | 20 | import QtQuick 21 | 22 | import org.kde.plasma.plasmoid 23 | import org.kde.plasma.components 3.0 as PC3 24 | import org.kde.kirigami as Kirigami 25 | import org.kde.kquickcontrolsaddons 26 | import Qt5Compat.GraphicalEffects 27 | 28 | import "../code/tools.js" as Tools 29 | 30 | Item { 31 | id: item 32 | 33 | width: GridView.view.cellWidth 34 | height: GridView.view.cellHeight 35 | 36 | property bool showLabel: true 37 | property var iconColorOverride: undefined 38 | property bool forceSymbolicIcons: false 39 | 40 | readonly property bool isDirectory: model.hasChildren ?? false 41 | readonly property var directoryModel: isDirectory ? GridView.view.model.modelForRow(itemIndex) : undefined 42 | 43 | // For this widget, the only favoritable actions should be system actions 44 | readonly property bool isSystemAction: (model.favoriteId 45 | && GridView.view.model.favoritesModel 46 | && GridView.view.model.favoritesModel.enabled) ?? false 47 | 48 | readonly property int itemIndex: model.index 49 | readonly property url url: model.url != undefined ? model.url : "" 50 | property bool pressed: false 51 | 52 | Accessible.role: Accessible.MenuItem 53 | Accessible.name: model.display 54 | 55 | readonly property bool hasActionList: ((("hasActionList" in model) && (model.hasActionList == true)) 56 | || isSystemAction) 57 | 58 | function getActionList() { 59 | return isSystemAction ? Tools.createSystemActionActions(i18n, GridView.view.model.favoritesModel, model.favoriteId) : model.actionList; 60 | } 61 | 62 | // Rectangle{ 63 | // id: box 64 | // height: parent.height // - 10 65 | // width: parent.width // - 10 66 | // anchors.verticalCenter: parent.verticalCenter 67 | // anchors.horizontalCenter: parent.horizontalCenter 68 | // color: "transparent" 69 | // } 70 | 71 | Component { 72 | id: iconComponent 73 | 74 | Item { 75 | anchors.centerIn: parent 76 | Kirigami.Icon { 77 | id: icon 78 | anchors.centerIn: parent 79 | width: parent.width 80 | height: parent.height 81 | animated: false 82 | source: model.decoration + (forceSymbolicIcons ? "-symbolic" : "") 83 | roundToIconSize: width > Kirigami.Units.iconSizes.huge ? false : true 84 | isMask: iconColorOverride !== undefined 85 | color: iconColorOverride ?? "transparent" 86 | } 87 | } 88 | } 89 | 90 | Component { 91 | id: directoryViewComponent 92 | 93 | Rectangle { 94 | id: directoryBackgroundBox 95 | 96 | // anchors.fill: parent 97 | radius: width / 4 98 | //border.color: Kirigami.Theme.textColor 99 | //border.width: 2 100 | color: "#33000005" 101 | 102 | GridView { 103 | id: directoryGridView 104 | 105 | anchors.fill: parent 106 | anchors.margins: parent.width / 10 107 | cellWidth: (width / 2) * 0.9 > Kirigami.Units.iconSizes.small ? width / 2 : width 108 | cellHeight: cellWidth 109 | 110 | // TODO - don't use clip here for performance reasons 111 | clip: true 112 | z: 1 // Make in front of background 113 | interactive: false 114 | 115 | model: directoryModel 116 | delegate: Item { 117 | width: directoryGridView.cellWidth 118 | height: directoryGridView.cellHeight 119 | 120 | Kirigami.Icon { 121 | id: directoryIconItem 122 | 123 | width: parent.width * 0.9 124 | height: parent.height * 0.9 125 | anchors.centerIn: parent 126 | 127 | animated: false 128 | source: model.decoration + (forceSymbolicIcons ? "-symbolic" : "") 129 | roundToIconSize: width > Kirigami.Units.iconSizes.medium ? false : true 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | Rectangle { 137 | id: displayBox 138 | width: iconSize 139 | height: width 140 | y: (item.height / 2) - (height / 2) - (showLabel ? label.height / 2 : 0) 141 | anchors.horizontalCenter: parent.horizontalCenter 142 | // anchors.verticalCenter: parent.verticalCenter - (showLabel ? label.height / 2 : 0) 143 | color:"transparent" 144 | 145 | // Load either icon or directory view 146 | Loader { 147 | id: displayLoader 148 | anchors.fill: parent 149 | sourceComponent: isDirectory && !plasmoid.configuration.useDirectoryIcons ? directoryViewComponent : iconComponent 150 | } 151 | } 152 | 153 | // Rectangle{ 154 | // id: box 155 | // height: parent.height // - 10 156 | // width: parent.width // - 10 157 | // anchors.verticalCenter: box.verticalCenter 158 | // anchors.horizontalCenter: parent.horizontalCenter 159 | // color:"red" 160 | // opacity: 0.4 161 | // // color: "transparent" 162 | // } 163 | 164 | PC3.Label { 165 | id: label 166 | 167 | visible: showLabel 168 | 169 | anchors { 170 | top: displayBox.bottom 171 | topMargin: Kirigami.Units.largeSpacing * 1.5 172 | left: parent.left 173 | leftMargin: highlightItemSvg.margins.left 174 | right: parent.right 175 | rightMargin: highlightItemSvg.margins.right 176 | } 177 | 178 | horizontalAlignment: Text.AlignHCenter 179 | 180 | elide: Text.ElideRight 181 | wrapMode: Text.NoWrap 182 | 183 | text: model.display 184 | color: drawerTheme.textColor 185 | } 186 | 187 | // PC3.Label { 188 | // id: folderArrow 189 | 190 | // visible: isDirectory 191 | 192 | // anchors { 193 | // top: label.bottom 194 | // topMargin: Kirigami.Units.smallSpacing 195 | // left: parent.left 196 | // leftMargin: highlightItemSvg.margins.left 197 | // right: parent.right 198 | // rightMargin: highlightItemSvg.margins.right 199 | // } 200 | 201 | // horizontalAlignment: Text.AlignHCenter 202 | 203 | // elide: Text.ElideRight 204 | // wrapMode: Text.NoWrap 205 | 206 | // text: "^" 207 | // } 208 | } 209 | -------------------------------------------------------------------------------- /translate/template.pot: -------------------------------------------------------------------------------- 1 | # Translation of plasma-drawer in LANGUAGE 2 | # Copyright (C) 2025 3 | # This file is distributed under the same license as the plasma-drawer package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: plasma-drawer\n" 10 | "Report-Msgid-Bugs-To: https://github.com/p-connor/plasma-drawer\n" 11 | "POT-Creation-Date: 2025-01-04 15:55-0600\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: ../metadata.desktop 21 | msgid "Plasma Drawer" 22 | msgstr "" 23 | 24 | #: ../metadata.desktop 25 | msgid "A fullscreen customizable launcher with application directories and krunner-like search" 26 | msgstr "" 27 | 28 | #: ../contents/code/tools.js 29 | msgid "Remove action" 30 | msgstr "" 31 | 32 | #: ../contents/code/tools.js 33 | msgid "Show all" 34 | msgstr "" 35 | 36 | #: ../contents/code/tools.js 37 | msgid "Add to system actions bar" 38 | msgstr "" 39 | 40 | #: ../contents/code/tools.js 41 | msgid "Edit Applications" 42 | msgstr "" 43 | 44 | #: ../contents/config/config.qml 45 | msgid "General" 46 | msgstr "" 47 | 48 | #: ../contents/config/config.qml 49 | msgid "Search Plugins" 50 | msgstr "" 51 | 52 | #: ../contents/ui/ConfigGeneral.qml 53 | msgid "Icon:" 54 | msgstr "" 55 | 56 | #: ../contents/ui/ConfigGeneral.qml 57 | msgctxt "@item:inmenu Open icon chooser dialog" 58 | msgid "Choose…" 59 | msgstr "" 60 | 61 | #: ../contents/ui/ConfigGeneral.qml 62 | msgctxt "@item:inmenu Reset icon to default" 63 | msgid "Clear Icon" 64 | msgstr "" 65 | 66 | #: ../contents/ui/ConfigGeneral.qml 67 | msgid "Background:" 68 | msgstr "" 69 | 70 | #: ../contents/ui/ConfigGeneral.qml 71 | msgid "Use theme color" 72 | msgstr "" 73 | 74 | #: ../contents/ui/ConfigGeneral.qml 75 | msgid "Use custom color" 76 | msgstr "" 77 | 78 | #: ../contents/ui/ConfigGeneral.qml 79 | msgid "Use image" 80 | msgstr "" 81 | 82 | #: ../contents/ui/ConfigGeneral.qml 83 | msgid "Custom Color:" 84 | msgstr "" 85 | 86 | #: ../contents/ui/ConfigGeneral.qml 87 | msgid "Background Color" 88 | msgstr "" 89 | 90 | #: ../contents/ui/ConfigGeneral.qml 91 | msgid "Select Image File" 92 | msgstr "" 93 | 94 | #: ../contents/ui/ConfigGeneral.qml 95 | msgid "Path: " 96 | msgstr "" 97 | 98 | #: ../contents/ui/ConfigGeneral.qml 99 | msgid "None" 100 | msgstr "" 101 | 102 | #: ../contents/ui/ConfigGeneral.qml 103 | msgid "Please choose an image file" 104 | msgstr "" 105 | 106 | #: ../contents/ui/ConfigGeneral.qml 107 | msgid "Image files" 108 | msgstr "" 109 | 110 | #: ../contents/ui/ConfigGeneral.qml 111 | msgid "All files" 112 | msgstr "" 113 | 114 | #: ../contents/ui/ConfigGeneral.qml 115 | msgid "Background opacity:" 116 | msgstr "" 117 | 118 | #: ../contents/ui/ConfigGeneral.qml 119 | msgid "%1%" 120 | msgstr "" 121 | 122 | #: ../contents/ui/ConfigGeneral.qml 123 | msgid "Applications:" 124 | msgstr "" 125 | 126 | #: ../contents/ui/ConfigGeneral.qml 127 | msgid "Max columns in grid:" 128 | msgstr "" 129 | 130 | #: ../contents/ui/ConfigGeneral.qml 131 | msgid "Size of application icons:" 132 | msgstr "" 133 | 134 | #: ../contents/ui/ConfigGeneral.qml 135 | msgid "Use directory icons" 136 | msgstr "" 137 | 138 | #: ../contents/ui/ConfigGeneral.qml 139 | msgid "Search:" 140 | msgstr "" 141 | 142 | #: ../contents/ui/ConfigGeneral.qml 143 | msgid "Show search bar" 144 | msgstr "" 145 | 146 | #: ../contents/ui/ConfigGeneral.qml 147 | msgid "Adaptive search result size" 148 | msgstr "" 149 | 150 | #: ../contents/ui/ConfigGeneral.qml 151 | msgid "Max size of search result icons:" 152 | msgstr "" 153 | 154 | #: ../contents/ui/ConfigGeneral.qml 155 | msgid "Size of search result icons:" 156 | msgstr "" 157 | 158 | #: ../contents/ui/ConfigGeneral.qml 159 | msgid "System Actions:" 160 | msgstr "" 161 | 162 | #: ../contents/ui/ConfigGeneral.qml 163 | msgid "Show system actions" 164 | msgstr "" 165 | 166 | #: ../contents/ui/ConfigGeneral.qml 167 | msgid "Size of system action icons:" 168 | msgstr "" 169 | 170 | #: ../contents/ui/ConfigGeneral.qml 171 | msgid "Show system action labels" 172 | msgstr "" 173 | 174 | #: ../contents/ui/ConfigGeneral.qml 175 | msgid "Use symbolic system action icons" 176 | msgstr "" 177 | 178 | #: ../contents/ui/ConfigGeneral.qml 179 | msgid "Other:" 180 | msgstr "" 181 | 182 | #: ../contents/ui/ConfigGeneral.qml 183 | msgid "Disable animations" 184 | msgstr "" 185 | 186 | #: ../contents/ui/ConfigGeneral.qml 187 | msgid "Animation speed multiplier:" 188 | msgstr "" 189 | 190 | #: ../contents/ui/ConfigGeneral.qml 191 | msgid "Unhide all hidden applications" 192 | msgstr "" 193 | 194 | #: ../contents/ui/ConfigGeneral.qml 195 | msgid "Unhidden!" 196 | msgstr "" 197 | 198 | #: ../contents/ui/ConfigSearch.qml 199 | msgctxt "KRunner Plugin" 200 | msgid "File Search" 201 | msgstr "" 202 | 203 | #: ../contents/ui/ConfigSearch.qml 204 | msgctxt "KRunner Plugin" 205 | msgid "Browser History" 206 | msgstr "" 207 | 208 | #: ../contents/ui/ConfigSearch.qml 209 | msgctxt "KRunner Plugin" 210 | msgid "Browser Tabs" 211 | msgstr "" 212 | 213 | #: ../contents/ui/ConfigSearch.qml 214 | msgctxt "KRunner Plugin" 215 | msgid "Calculator" 216 | msgstr "" 217 | 218 | #: ../contents/ui/ConfigSearch.qml 219 | msgctxt "KRunner Plugin" 220 | msgid "Help Runner" 221 | msgstr "" 222 | 223 | #: ../contents/ui/ConfigSearch.qml 224 | msgctxt "KRunner Plugin" 225 | msgid "Software Center" 226 | msgstr "" 227 | 228 | #: ../contents/ui/ConfigSearch.qml 229 | msgctxt "KRunner Plugin" 230 | msgid "Bookmarks" 231 | msgstr "" 232 | 233 | #: ../contents/ui/ConfigSearch.qml 234 | msgctxt "KRunner Plugin" 235 | msgid "Special Characters" 236 | msgstr "" 237 | 238 | #: ../contents/ui/ConfigSearch.qml 239 | msgctxt "KRunner Plugin" 240 | msgid "Dictionary" 241 | msgstr "" 242 | 243 | #: ../contents/ui/ConfigSearch.qml 244 | msgctxt "KRunner Plugin" 245 | msgid "Kate Sessions" 246 | msgstr "" 247 | 248 | #: ../contents/ui/ConfigSearch.qml 249 | msgctxt "KRunner Plugin" 250 | msgid "Terminate Applications" 251 | msgstr "" 252 | 253 | #: ../contents/ui/ConfigSearch.qml 254 | msgctxt "KRunner Plugin" 255 | msgid "Konsole Profiles" 256 | msgstr "" 257 | 258 | #: ../contents/ui/ConfigSearch.qml 259 | msgctxt "KRunner Plugin" 260 | msgid "KWin" 261 | msgstr "" 262 | 263 | #: ../contents/ui/ConfigSearch.qml 264 | msgctxt "KRunner Plugin" 265 | msgid "Places" 266 | msgstr "" 267 | 268 | #: ../contents/ui/ConfigSearch.qml 269 | msgctxt "KRunner Plugin" 270 | msgid "Plasma Desktop Shell" 271 | msgstr "" 272 | 273 | #: ../contents/ui/ConfigSearch.qml 274 | msgctxt "KRunner Plugin" 275 | msgid "Power" 276 | msgstr "" 277 | 278 | #: ../contents/ui/ConfigSearch.qml 279 | msgctxt "KRunner Plugin" 280 | msgid "Recent Files" 281 | msgstr "" 282 | 283 | #: ../contents/ui/ConfigSearch.qml 284 | msgctxt "KRunner Plugin" 285 | msgid "Applications" 286 | msgstr "" 287 | 288 | #: ../contents/ui/ConfigSearch.qml 289 | msgctxt "KRunner Plugin" 290 | msgid "Desktop Sessions" 291 | msgstr "" 292 | 293 | #: ../contents/ui/ConfigSearch.qml 294 | msgctxt "KRunner Plugin" 295 | msgid "Command Line" 296 | msgstr "" 297 | 298 | #: ../contents/ui/ConfigSearch.qml 299 | msgctxt "KRunner Plugin" 300 | msgid "Spell Checker" 301 | msgstr "" 302 | 303 | #: ../contents/ui/ConfigSearch.qml 304 | msgctxt "KRunner Plugin" 305 | msgid "System Settings" 306 | msgstr "" 307 | 308 | #: ../contents/ui/ConfigSearch.qml 309 | msgctxt "KRunner Plugin" 310 | msgid "Web Search Keywords" 311 | msgstr "" 312 | 313 | #: ../contents/ui/ConfigSearch.qml 314 | msgctxt "KRunner Plugin" 315 | msgid "Locations" 316 | msgstr "" 317 | 318 | #: ../contents/ui/ConfigSearch.qml 319 | msgctxt "KRunner Plugin" 320 | msgid "Activities" 321 | msgstr "" 322 | 323 | #: ../contents/ui/ConfigSearch.qml 324 | msgctxt "KRunner Plugin" 325 | msgid "Date and Time" 326 | msgstr "" 327 | 328 | #: ../contents/ui/ConfigSearch.qml 329 | msgctxt "KRunner Plugin" 330 | msgid "Unit Converter" 331 | msgstr "" 332 | 333 | #: ../contents/ui/ConfigSearch.qml 334 | msgctxt "KRunner Plugin" 335 | msgid "Windows" 336 | msgstr "" 337 | 338 | #: ../contents/ui/ConfigSearch.qml 339 | msgid "Plugin Allowlist" 340 | msgstr "" 341 | 342 | #: ../contents/ui/ConfigSearch.qml 343 | msgid "Note: Selected plugins must also be enabled in System Settings" 344 | msgstr "" 345 | 346 | #: ../contents/ui/ConfigSearch.qml 347 | msgctxt "@action:button" 348 | msgid "Configure Enabled Search Plugins…" 349 | msgstr "" 350 | 351 | #: ../contents/ui/ConfigSearch.qml 352 | msgid "Custom Search Plugins" 353 | msgstr "" 354 | 355 | #: ../contents/ui/ConfigSearch.qml 356 | msgid "Add any custom plugins you've installed" 357 | msgstr "" 358 | 359 | #: ../contents/ui/ConfigSearch.qml 360 | msgid "Plugin ID:" 361 | msgstr "" 362 | 363 | #: ../contents/ui/main.qml 364 | msgid "Edit Applications..." 365 | msgstr "" 366 | 367 | #: ../contents/ui/MenuRepresentation.qml 368 | msgid "Search" 369 | msgstr "" 370 | 371 | #: ../contents/ui/RunnerResultsView.qml 372 | msgid "Show Less" 373 | msgstr "" 374 | 375 | #: ../contents/ui/RunnerResultsView.qml 376 | msgid "Show More" 377 | msgstr "" 378 | -------------------------------------------------------------------------------- /contents/ui/AppsGridView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | import QtQuick.Controls 3 | 4 | import org.kde.plasma.plasmoid 5 | import org.kde.kquickcontrolsaddons 6 | import org.kde.kirigami as Kirigami 7 | 8 | FocusScope { 9 | id: appsGrid 10 | 11 | signal keyNavLeft 12 | signal keyNavRight 13 | signal keyNavUp 14 | signal keyNavDown 15 | 16 | property int iconSize: Kirigami.Units.iconSizes.huge 17 | 18 | // TODO - polish cell sizes for different resolutions 19 | readonly property int cellSizeWidth: (iconSize * 1.5) + Kirigami.Units.gridUnit 20 | + (2 * Kirigami.Units.smallSpacing) 21 | + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, 22 | highlightItemSvg.margins.left + highlightItemSvg.margins.right)) 23 | readonly property int minCellSizeHeight: (cellSizeWidth - (iconSize * .33)) 24 | // cellSizeHeight grows to match the appsGrid height if there is some space left at the bottom 25 | readonly property int cellSizeHeight: minCellSizeHeight + ((height % minCellSizeHeight) / Math.floor(height / minCellSizeHeight)) 26 | 27 | property int numberColumns: 5 28 | property int numberRows: Math.floor(height / cellSizeHeight) 29 | 30 | required property var model 31 | 32 | readonly property var currentItemGrid: stackView.currentItem 33 | readonly property var currentModel: currentItemGrid ? currentItemGrid.model : null //modelStack[modelStackLength - 1] 34 | 35 | readonly property bool isAtRoot: stackView.depth <= 1 36 | 37 | implicitWidth: currentItemGrid.implicitWidth 38 | implicitHeight: currentItemGrid.implicitHeight 39 | 40 | function tryEnterDirectory(directoryIndex) { 41 | let dir = currentModel.modelForRow(directoryIndex); 42 | if (dir && dir.hasChildren && currentItemGrid) { 43 | let origin = Qt.point(0, 0); 44 | let item = currentItemGrid.itemAtIndex(directoryIndex); 45 | if (item) { 46 | origin = Qt.point( (item.x + (cellSizeWidth / 2)) - (currentItemGrid.width / 2), 47 | (item.y + (cellSizeHeight / 2)) - (currentItemGrid.height / 2) - currentItemGrid.contentY ) 48 | } 49 | stackView.push(directoryView, {model: dir, origin: origin}); 50 | } 51 | } 52 | 53 | function tryExitDirectory() { 54 | if (!isAtRoot) { 55 | stackView.pop(); 56 | } 57 | } 58 | 59 | function returnToRootDirectory(doTransition = true) { 60 | if (!isAtRoot) { 61 | // Pops all items up until root 62 | stackView.pop(null, doTransition ? undefined : StackView.ReplaceTransition); 63 | } 64 | } 65 | 66 | function selectFirst() { 67 | if (currentItemGrid && currentItemGrid.count > 0) { 68 | currentItemGrid.trySelect(0, 0); 69 | } 70 | } 71 | 72 | function selectLast() { 73 | if (currentItemGrid && currentItemGrid.count > 0) { 74 | currentItemGrid.trySelect(currentItemGrid.lastRow(), 0); 75 | } 76 | } 77 | 78 | function removeSelection() { 79 | if (currentItemGrid) { 80 | currentItemGrid.currentIndex = -1; 81 | } 82 | } 83 | 84 | // ActionMenu { 85 | // id: actionMenu 86 | // onActionClicked: visualParent.actionTriggered(actionId, actionArgument) 87 | // onClosed: { 88 | // currentItemGrid.currentIndex = -1; 89 | // } 90 | // } 91 | 92 | // I believe StackView requires that the component be defined this way 93 | Component { 94 | id: directoryView 95 | ItemGridView { 96 | property var origin: Qt.point(0, 0) 97 | 98 | // width: appsGrid.numberColumns * cellSizeWidth 99 | // height: appsGrid.numberRows * cellSizeHeight 100 | numberColumns: appsGrid.numberColumns 101 | maxVisibleRows: appsGrid.numberRows 102 | 103 | cellWidth: cellSizeWidth 104 | cellHeight: cellSizeHeight 105 | 106 | 107 | iconSize: appsGrid.iconSize 108 | 109 | model: appsGrid.model 110 | 111 | dragEnabled: false 112 | hoverEnabled: true 113 | 114 | onKeyNavUp: { 115 | currentIndex = -1; 116 | appsGrid.keyNavUp(); 117 | } 118 | onKeyNavDown: { 119 | currentIndex = -1; 120 | appsGrid.keyNavDown(); 121 | } 122 | 123 | Component.onCompleted: { 124 | keyNavLeft.connect(appsGrid.keyNavLeft); 125 | keyNavRight.connect(appsGrid.keyNavRight); 126 | } 127 | } 128 | } 129 | 130 | StackView { 131 | id: stackView 132 | initialItem: directoryView 133 | 134 | implicitWidth: currentItemGrid.implicitWidth 135 | implicitHeight: currentItemGrid.implicitHeight 136 | anchors.top: parent.top 137 | 138 | focus: true 139 | 140 | property var transitionDuration: plasmoid.configuration.disableAnimations ? 0 : Kirigami.Units.veryLongDuration / plasmoid.configuration.animationSpeedMultiplier 141 | 142 | pushEnter: !plasmoid.configuration.disableAnimations ? pushEnterTransition : instantEnterTransition 143 | pushExit: !plasmoid.configuration.disableAnimations ? pushExitTransition : instantExitTransition 144 | popEnter: !plasmoid.configuration.disableAnimations ? popEnterTransition : instantEnterTransition 145 | popExit: !plasmoid.configuration.disableAnimations ? popExitTransition : instantExitTransition 146 | 147 | replaceEnter: instantEnterTransition 148 | replaceExit: instantExitTransition 149 | 150 | Transition { 151 | id: pushEnterTransition 152 | 153 | NumberAnimation { 154 | property: "x"; 155 | from: pushEnterTransition.ViewTransition.item.origin.x 156 | to: 0 157 | duration: stackView.transitionDuration 158 | easing.type: Easing.OutCubic 159 | } 160 | 161 | NumberAnimation { 162 | property: "y" 163 | from: pushEnterTransition.ViewTransition.item.origin.y 164 | to: 0 165 | duration: stackView.transitionDuration 166 | easing.type: Easing.OutCubic 167 | } 168 | 169 | NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: stackView.transitionDuration * .5 } 170 | NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: stackView.transitionDuration; easing.type: Easing.OutCubic } 171 | } 172 | 173 | Transition { 174 | id: pushExitTransition 175 | NumberAnimation { property: "y"; from: 0; to: -(appsGrid.iconSize * .5); duration: stackView.transitionDuration; easing.type: Easing.OutCubic } 176 | NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: stackView.transitionDuration * .5; easing.type: Easing.OutCubic } 177 | NumberAnimation { property: "scale"; from: 1.0; to: 0.8; duration: stackView.transitionDuration * .5; easing.type: Easing.OutCubic } 178 | } 179 | 180 | Transition { 181 | id: popEnterTransition 182 | 183 | SequentialAnimation { 184 | PauseAnimation { duration: stackView.transitionDuration * .2 } 185 | ParallelAnimation { 186 | NumberAnimation { property: "y"; from: -(appsGrid.iconSize * .5); to: 0; duration: stackView.transitionDuration; easing.type: Easing.OutCubic } 187 | NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: stackView.transitionDuration * .5; easing.type: Easing.OutCubic } 188 | NumberAnimation { property: "scale"; from: 0.8; to: 1.0; duration: stackView.transitionDuration; easing.type: Easing.OutCubic } 189 | } 190 | } 191 | } 192 | 193 | Transition { 194 | id: popExitTransition 195 | NumberAnimation { 196 | property: "x" 197 | from: 0 198 | to: popExitTransition.ViewTransition.item.origin.x 199 | duration: stackView.transitionDuration * 1.5 200 | easing.type: Easing.OutCubic 201 | } 202 | 203 | NumberAnimation { 204 | property: "y" 205 | from: 0 206 | to: popExitTransition.ViewTransition.item.origin.y 207 | duration: stackView.transitionDuration * 1.5 208 | easing.type: Easing.OutCubic 209 | } 210 | 211 | NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: stackView.transitionDuration * .75; easing.type: Easing.OutQuint } 212 | NumberAnimation { property: "scale"; from: 1.0; to: 0; duration: stackView.transitionDuration * 1.5; easing.type: Easing.OutCubic } 213 | } 214 | 215 | Transition { 216 | id: instantEnterTransition 217 | 218 | PropertyAction { property: "opacity"; value: 1.0 } 219 | PropertyAction { property: "scale"; value: 1.0 } 220 | } 221 | 222 | Transition { 223 | id: instantExitTransition 224 | 225 | PropertyAction { property: "opacity"; value: 0 } 226 | PropertyAction { property: "scale"; value: 0 } 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /translate/merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Version: 22 3 | 4 | # https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems 5 | # https://techbase.kde.org/Development/Tutorials/Localization/i18n_Build_Systems/Outside_KDE_repositories 6 | # https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh 7 | 8 | DIR=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` 9 | plasmoidName=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Name"` 10 | widgetName="${plasmoidName##*.}" # Strip namespace 11 | website=`kreadconfig5 --file="$DIR/../metadata.desktop" --group="Desktop Entry" --key="X-KDE-PluginInfo-Website"` 12 | bugAddress="$website" 13 | packageRoot=".." # Root of translatable sources 14 | projectName="plasma_applet_${plasmoidName}" # project name 15 | 16 | #--- 17 | if [ -z "$plasmoidName" ]; then 18 | echo "[merge] Error: Couldn't read plasmoidName." 19 | exit 20 | fi 21 | 22 | if [ -z "$(which xgettext)" ]; then 23 | echo "[merge] Error: xgettext command not found. Need to install gettext" 24 | echo "[merge] Running 'sudo apt install gettext'" 25 | sudo apt install gettext 26 | echo "[merge] gettext installation should be finished. Going back to merging translations." 27 | fi 28 | 29 | #--- 30 | echo "[merge] Extracting messages" 31 | potArgs="--from-code=UTF-8 --width=200 --add-location=file" 32 | 33 | # Note: xgettext v0.20.1 (Kubuntu 20.04) and below will attempt to translate Icon, 34 | # so we need to specify Name, GenericName, Comment, and Keywords. 35 | # https://github.com/Zren/plasma-applet-lib/issues/1 36 | # https://savannah.gnu.org/support/?108887 37 | find "${packageRoot}" -name '*.desktop' | sort > "${DIR}/infiles.list" 38 | xgettext \ 39 | ${potArgs} \ 40 | --files-from="${DIR}/infiles.list" \ 41 | --language=Desktop \ 42 | -k -kName -kGenericName -kComment -kKeywords \ 43 | -D "${packageRoot}" \ 44 | -D "${DIR}" \ 45 | -o "template.pot.new" \ 46 | || \ 47 | { echo "[merge] error while calling xgettext. aborting."; exit 1; } 48 | 49 | sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "template.pot.new" 50 | 51 | # See Ki18n's extract-messages.sh for a full example: 52 | # https://invent.kde.org/sysadmin/l10n-scripty/-/blob/master/extract-messages.sh#L25 53 | # The -kN_ and -kaliasLocale keywords are mentioned in the Outside_KDE_repositories wiki. 54 | # We don't need -kN_ since we don't use intltool-extract but might as well keep it. 55 | # I have no idea what -kaliasLocale is used for. Googling aliasLocale found only listed kde1 code. 56 | # We don't need to parse -ki18nd since that'll extract messages from other domains. 57 | find "${packageRoot}" -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.qml' -o -name '*.js' | sort > "${DIR}/infiles.list" 58 | xgettext \ 59 | ${potArgs} \ 60 | --files-from="${DIR}/infiles.list" \ 61 | -C -kde \ 62 | -ci18n \ 63 | -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \ 64 | -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \ 65 | -kxi18n:1 -kxi18nc:1c,2 -kxi18np:1,2 -kxi18ncp:1c,2,3 \ 66 | -kkxi18n:1 -kkxi18nc:1c,2 -kkxi18np:1,2 -kkxi18ncp:1c,2,3 \ 67 | -kI18N_NOOP:1 -kI18NC_NOOP:1c,2 \ 68 | -kI18N_NOOP2:1c,2 -kI18N_NOOP2_NOSTRIP:1c,2 \ 69 | -ktr2i18n:1 -ktr2xi18n:1 \ 70 | -kN_:1 \ 71 | -kaliasLocale \ 72 | --package-name="${widgetName}" \ 73 | --msgid-bugs-address="${bugAddress}" \ 74 | -D "${packageRoot}" \ 75 | -D "${DIR}" \ 76 | --join-existing \ 77 | -o "template.pot.new" \ 78 | || \ 79 | { echo "[merge] error while calling xgettext. aborting."; exit 1; } 80 | 81 | sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in LANGUAGE"'/' "template.pot.new" 82 | sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "template.pot.new" 83 | 84 | if [ -f "template.pot" ]; then 85 | newPotDate=`grep "POT-Creation-Date:" template.pot.new | sed 's/.\{3\}$//'` 86 | oldPotDate=`grep "POT-Creation-Date:" template.pot | sed 's/.\{3\}$//'` 87 | sed -i 's/'"${newPotDate}"'/'"${oldPotDate}"'/' "template.pot.new" 88 | changes=`diff "template.pot" "template.pot.new"` 89 | if [ ! -z "$changes" ]; then 90 | # There's been changes 91 | sed -i 's/'"${oldPotDate}"'/'"${newPotDate}"'/' "template.pot.new" 92 | mv "template.pot.new" "template.pot" 93 | 94 | addedKeys=`echo "$changes" | grep "> msgid" | cut -c 9- | sort` 95 | removedKeys=`echo "$changes" | grep "< msgid" | cut -c 9- | sort` 96 | echo "" 97 | echo "Added Keys:" 98 | echo "$addedKeys" 99 | echo "" 100 | echo "Removed Keys:" 101 | echo "$removedKeys" 102 | echo "" 103 | 104 | else 105 | # No changes 106 | rm "template.pot.new" 107 | fi 108 | else 109 | # template.pot didn't already exist 110 | mv "template.pot.new" "template.pot" 111 | fi 112 | 113 | potMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "template.pot" | grep -c 'msgstr ""')` 114 | echo "| Locale | Lines | % Done|" > "./Status.md" 115 | echo "|----------|---------|-------|" >> "./Status.md" 116 | entryFormat="| %-8s | %7s | %5s |" 117 | templateLine=`perl -e "printf(\"$entryFormat\", \"Template\", \"${potMessageCount}\", \"\")"` 118 | echo "$templateLine" >> "./Status.md" 119 | 120 | rm "${DIR}/infiles.list" 121 | echo "[merge] Done extracting messages" 122 | 123 | #--- 124 | echo "[merge] Merging messages" 125 | catalogs=`find . -name '*.po' | sort` 126 | for cat in $catalogs; do 127 | echo "[merge] $cat" 128 | catLocale=`basename ${cat%.*}` 129 | 130 | widthArg="" 131 | catUsesGenerator=`grep "X-Generator:" "$cat"` 132 | if [ -z "$catUsesGenerator" ]; then 133 | widthArg="--width=400" 134 | fi 135 | 136 | compendiumArg="" 137 | if [ ! -z "$COMPENDIUM_DIR" ]; then 138 | langCode=`basename "${cat%.*}"` 139 | compendiumPath=`realpath "$COMPENDIUM_DIR/compendium-${langCode}.po"` 140 | if [ -f "$compendiumPath" ]; then 141 | echo "compendiumPath=$compendiumPath" 142 | compendiumArg="--compendium=$compendiumPath" 143 | fi 144 | fi 145 | 146 | cp "$cat" "$cat.new" 147 | sed -i 's/"Content-Type: text\/plain; charset=CHARSET\\n"/"Content-Type: text\/plain; charset=UTF-8\\n"/' "$cat.new" 148 | 149 | msgmerge \ 150 | ${widthArg} \ 151 | --add-location=file \ 152 | --no-fuzzy-matching \ 153 | ${compendiumArg} \ 154 | -o "$cat.new" \ 155 | "$cat.new" "${DIR}/template.pot" 156 | 157 | sed -i 's/# SOME DESCRIPTIVE TITLE./'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" 158 | sed -i 's/# Translation of '"${widgetName}"' in LANGUAGE/'"# Translation of ${widgetName} in ${catLocale}"'/' "$cat.new" 159 | sed -i 's/# Copyright (C) YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/'"# Copyright (C) $(date +%Y)"'/' "$cat.new" 160 | 161 | poEmptyMessageCount=`expr $(grep -Pzo 'msgstr ""\n(\n|$)' "$cat.new" | grep -c 'msgstr ""')` 162 | poMessagesDoneCount=`expr $potMessageCount - $poEmptyMessageCount` 163 | poCompletion=`perl -e "printf(\"%d\", $poMessagesDoneCount * 100 / $potMessageCount)"` 164 | poLine=`perl -e "printf(\"$entryFormat\", \"$catLocale\", \"${poMessagesDoneCount}/${potMessageCount}\", \"${poCompletion}%\")"` 165 | echo "$poLine" >> "./Status.md" 166 | 167 | # mv "$cat" "$cat.old" 168 | mv "$cat.new" "$cat" 169 | done 170 | echo "[merge] Done merging messages" 171 | 172 | #--- 173 | echo "[merge] Updating .desktop file" 174 | 175 | # Generate LINGUAS for msgfmt 176 | if [ -f "$DIR/LINGUAS" ]; then 177 | rm "$DIR/LINGUAS" 178 | fi 179 | touch "$DIR/LINGUAS" 180 | for cat in $catalogs; do 181 | catLocale=`basename ${cat%.*}` 182 | echo "${catLocale}" >> "$DIR/LINGUAS" 183 | done 184 | 185 | cp -f "$DIR/../metadata.desktop" "$DIR/template.desktop" 186 | sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/template.desktop" 187 | 188 | msgfmt \ 189 | --desktop \ 190 | --template="$DIR/template.desktop" \ 191 | -d "$DIR/" \ 192 | -o "$DIR/new.desktop" 193 | 194 | # Delete empty msgid messages that used the po header 195 | if [ ! -z "$(grep '^Name=$' "$DIR/new.desktop")" ]; then 196 | echo "[merge] Name in metadata.desktop is empty!" 197 | sed -i '/^Name\[/ d' "$DIR/new.desktop" 198 | fi 199 | if [ ! -z "$(grep '^GenericName=$' "$DIR/new.desktop")" ]; then 200 | echo "[merge] GenericName in metadata.desktop is empty!" 201 | sed -i '/^GenericName\[/ d' "$DIR/new.desktop" 202 | fi 203 | if [ ! -z "$(grep '^Comment=$' "$DIR/new.desktop")" ]; then 204 | echo "[merge] Comment in metadata.desktop is empty!" 205 | sed -i '/^Comment\[/ d' "$DIR/new.desktop" 206 | fi 207 | if [ ! -z "$(grep '^Keywords=$' "$DIR/new.desktop")" ]; then 208 | echo "[merge] Keywords in metadata.desktop is empty!" 209 | sed -i '/^Keywords\[/ d' "$DIR/new.desktop" 210 | fi 211 | 212 | # Place translations at the bottom of the desktop file. 213 | translatedLines=`cat "$DIR/new.desktop" | grep "]="` 214 | if [ ! -z "${translatedLines}" ]; then 215 | sed -i '/^Name\[/ d; /^GenericName\[/ d; /^Comment\[/ d; /^Keywords\[/ d' "$DIR/new.desktop" 216 | if [ "$(tail -c 2 "$DIR/new.desktop" | wc -l)" != "2" ]; then 217 | # Does not end with 2 empty lines, so add an empty line. 218 | echo "" >> "$DIR/new.desktop" 219 | fi 220 | echo "${translatedLines}" >> "$DIR/new.desktop" 221 | fi 222 | 223 | # Cleanup 224 | mv "$DIR/new.desktop" "$DIR/../metadata.desktop" 225 | rm "$DIR/template.desktop" 226 | rm "$DIR/LINGUAS" 227 | 228 | #--- 229 | # Populate README.md 230 | echo "[merge] Updating translate/README.md" 231 | sed -i -E 's`share\/plasma\/plasmoids\/(.+)\/translate`share/plasma/plasmoids/'"${plasmoidName}"'/translate`' ./README.md 232 | if [[ "$website" == *"github.com"* ]]; then 233 | sed -i -E 's`\[new issue\]\(https:\/\/github\.com\/(.+)\/(.+)\/issues\/new\)`[new issue]('"${website}"'/issues/new)`' ./README.md 234 | fi 235 | sed -i '/^|/ d' ./README.md # Remove status table from README 236 | cat ./Status.md >> ./README.md 237 | rm ./Status.md 238 | 239 | echo "[merge] Done" 240 | -------------------------------------------------------------------------------- /translate/uk.po: -------------------------------------------------------------------------------- 1 | # Translation of plasma-drawer in Ukrainian 2 | # Copyright (C) 2023 3 | # This file is distributed under the same license as the plasma-drawer package. 4 | # Mykhailo Stetsiuk , 2023–2024. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: plasma-drawer\n" 10 | "Report-Msgid-Bugs-To: https://github.com/p-connor/plasma-drawer\n" 11 | "POT-Creation-Date: 2025-01-04 15:55-0600\n" 12 | "PO-Revision-Date: 2023-07-24 10:55+0300\n" 13 | "Last-Translator: Mykhailo Stetsiuk \n" 14 | "Language-Team: \n" 15 | "Language: uk\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: ../metadata.desktop 21 | msgid "Plasma Drawer" 22 | msgstr "Plasma Drawer" 23 | 24 | #: ../metadata.desktop 25 | msgid "A fullscreen customizable launcher with application directories and krunner-like search" 26 | msgstr "Повноекранний налаштовуваний лаунчер з теками програм та пошуком у стилі KRunner" 27 | 28 | #: ../contents/code/tools.js 29 | msgid "Remove action" 30 | msgstr "Видалити дію" 31 | 32 | #: ../contents/code/tools.js 33 | msgid "Show all" 34 | msgstr "Показати всі" 35 | 36 | #: ../contents/code/tools.js 37 | msgid "Add to system actions bar" 38 | msgstr "Додати до системних дій" 39 | 40 | #: ../contents/code/tools.js 41 | msgid "Edit Applications" 42 | msgstr "Змінити список програм" 43 | 44 | #: ../contents/config/config.qml 45 | msgid "General" 46 | msgstr "Загальне" 47 | 48 | #: ../contents/config/config.qml 49 | msgid "Search Plugins" 50 | msgstr "" 51 | 52 | #: ../contents/ui/ConfigGeneral.qml 53 | msgid "Icon:" 54 | msgstr "Піктограма:" 55 | 56 | #: ../contents/ui/ConfigGeneral.qml 57 | msgctxt "@item:inmenu Open icon chooser dialog" 58 | msgid "Choose…" 59 | msgstr "Обрати…" 60 | 61 | #: ../contents/ui/ConfigGeneral.qml 62 | msgctxt "@item:inmenu Reset icon to default" 63 | msgid "Clear Icon" 64 | msgstr "Очистити піктограму" 65 | 66 | #: ../contents/ui/ConfigGeneral.qml 67 | msgid "Background:" 68 | msgstr "Тло:" 69 | 70 | #: ../contents/ui/ConfigGeneral.qml 71 | msgid "Use theme color" 72 | msgstr "Використовувати колір теми" 73 | 74 | #: ../contents/ui/ConfigGeneral.qml 75 | msgid "Use custom color" 76 | msgstr "Використовувати власний колір" 77 | 78 | #: ../contents/ui/ConfigGeneral.qml 79 | msgid "Use image" 80 | msgstr "Використовувати зображення" 81 | 82 | #: ../contents/ui/ConfigGeneral.qml 83 | msgid "Custom Color:" 84 | msgstr "Власний колір:" 85 | 86 | #: ../contents/ui/ConfigGeneral.qml 87 | msgid "Background Color" 88 | msgstr "Колір тла" 89 | 90 | #: ../contents/ui/ConfigGeneral.qml 91 | msgid "Select Image File" 92 | msgstr "" 93 | 94 | #: ../contents/ui/ConfigGeneral.qml 95 | msgid "Path: " 96 | msgstr "Шлях: " 97 | 98 | #: ../contents/ui/ConfigGeneral.qml 99 | msgid "None" 100 | msgstr "Немає" 101 | 102 | #: ../contents/ui/ConfigGeneral.qml 103 | msgid "Please choose an image file" 104 | msgstr "" 105 | 106 | #: ../contents/ui/ConfigGeneral.qml 107 | msgid "Image files" 108 | msgstr "" 109 | 110 | #: ../contents/ui/ConfigGeneral.qml 111 | msgid "All files" 112 | msgstr "" 113 | 114 | #: ../contents/ui/ConfigGeneral.qml 115 | msgid "Background opacity:" 116 | msgstr "Непрозорість тла" 117 | 118 | #: ../contents/ui/ConfigGeneral.qml 119 | msgid "%1%" 120 | msgstr "%1%" 121 | 122 | #: ../contents/ui/ConfigGeneral.qml 123 | msgid "Applications:" 124 | msgstr "Програми:" 125 | 126 | #: ../contents/ui/ConfigGeneral.qml 127 | msgid "Max columns in grid:" 128 | msgstr "Максимум стовпців у сітці:" 129 | 130 | #: ../contents/ui/ConfigGeneral.qml 131 | msgid "Size of application icons:" 132 | msgstr "Розмір піктограм програм:" 133 | 134 | #: ../contents/ui/ConfigGeneral.qml 135 | msgid "Use directory icons" 136 | msgstr "Використовувати піктограми для тек" 137 | 138 | #: ../contents/ui/ConfigGeneral.qml 139 | msgid "Search:" 140 | msgstr "Пошук:" 141 | 142 | #: ../contents/ui/ConfigGeneral.qml 143 | msgid "Show search bar" 144 | msgstr "Показувати поле пошуку" 145 | 146 | #: ../contents/ui/ConfigGeneral.qml 147 | msgid "Adaptive search result size" 148 | msgstr "Адаптивний розмір результатів пошуку" 149 | 150 | #: ../contents/ui/ConfigGeneral.qml 151 | msgid "Max size of search result icons:" 152 | msgstr "Максимальний розмір піктограм результатів пошуку" 153 | 154 | #: ../contents/ui/ConfigGeneral.qml 155 | msgid "Size of search result icons:" 156 | msgstr "Розмір піктограм результатів пошуку" 157 | 158 | #: ../contents/ui/ConfigGeneral.qml 159 | msgid "System Actions:" 160 | msgstr "Системні дії:" 161 | 162 | #: ../contents/ui/ConfigGeneral.qml 163 | msgid "Show system actions" 164 | msgstr "Показувати системні дії" 165 | 166 | #: ../contents/ui/ConfigGeneral.qml 167 | msgid "Size of system action icons:" 168 | msgstr "Розмір піктограм системних дій" 169 | 170 | #: ../contents/ui/ConfigGeneral.qml 171 | msgid "Show system action labels" 172 | msgstr "Показувати мітки системних дій" 173 | 174 | #: ../contents/ui/ConfigGeneral.qml 175 | msgid "Use symbolic system action icons" 176 | msgstr "" 177 | 178 | #: ../contents/ui/ConfigGeneral.qml 179 | msgid "Other:" 180 | msgstr "Інше:" 181 | 182 | #: ../contents/ui/ConfigGeneral.qml 183 | msgid "Disable animations" 184 | msgstr "Вимкнути анімації" 185 | 186 | #: ../contents/ui/ConfigGeneral.qml 187 | msgid "Animation speed multiplier:" 188 | msgstr "Множник швидкості анімацій:" 189 | 190 | #: ../contents/ui/ConfigGeneral.qml 191 | msgid "Unhide all hidden applications" 192 | msgstr "Відображати всі приховані програми" 193 | 194 | #: ../contents/ui/ConfigGeneral.qml 195 | msgid "Unhidden!" 196 | msgstr "Показано!" 197 | 198 | #: ../contents/ui/ConfigSearch.qml 199 | msgctxt "KRunner Plugin" 200 | msgid "File Search" 201 | msgstr "Пошук файлів" 202 | 203 | #: ../contents/ui/ConfigSearch.qml 204 | msgctxt "KRunner Plugin" 205 | msgid "Browser History" 206 | msgstr "Журнал навігатора" 207 | 208 | #: ../contents/ui/ConfigSearch.qml 209 | msgctxt "KRunner Plugin" 210 | msgid "Browser Tabs" 211 | msgstr "Вкладки навігатора" 212 | 213 | #: ../contents/ui/ConfigSearch.qml 214 | msgctxt "KRunner Plugin" 215 | msgid "Calculator" 216 | msgstr "Калькулятор" 217 | 218 | #: ../contents/ui/ConfigSearch.qml 219 | msgctxt "KRunner Plugin" 220 | msgid "Help Runner" 221 | msgstr "Засіб надання довідки" 222 | 223 | #: ../contents/ui/ConfigSearch.qml 224 | msgctxt "KRunner Plugin" 225 | msgid "Software Center" 226 | msgstr "Центр програм" 227 | 228 | #: ../contents/ui/ConfigSearch.qml 229 | msgctxt "KRunner Plugin" 230 | msgid "Bookmarks" 231 | msgstr "Закладки" 232 | 233 | #: ../contents/ui/ConfigSearch.qml 234 | msgctxt "KRunner Plugin" 235 | msgid "Special Characters" 236 | msgstr "Спеціальні символи" 237 | 238 | #: ../contents/ui/ConfigSearch.qml 239 | msgctxt "KRunner Plugin" 240 | msgid "Dictionary" 241 | msgstr "Словник" 242 | 243 | #: ../contents/ui/ConfigSearch.qml 244 | msgctxt "KRunner Plugin" 245 | msgid "Kate Sessions" 246 | msgstr "Сеанси Kate" 247 | 248 | #: ../contents/ui/ConfigSearch.qml 249 | msgctxt "KRunner Plugin" 250 | msgid "Terminate Applications" 251 | msgstr "Переривання програм" 252 | 253 | #: ../contents/ui/ConfigSearch.qml 254 | msgctxt "KRunner Plugin" 255 | msgid "Konsole Profiles" 256 | msgstr "Профілі Konsole" 257 | 258 | #: ../contents/ui/ConfigSearch.qml 259 | msgctxt "KRunner Plugin" 260 | msgid "KWin" 261 | msgstr "KWin" 262 | 263 | #: ../contents/ui/ConfigSearch.qml 264 | msgctxt "KRunner Plugin" 265 | msgid "Places" 266 | msgstr "Місця" 267 | 268 | #: ../contents/ui/ConfigSearch.qml 269 | msgctxt "KRunner Plugin" 270 | msgid "Plasma Desktop Shell" 271 | msgstr "Оболонка стільниці Плазми" 272 | 273 | #: ../contents/ui/ConfigSearch.qml 274 | msgctxt "KRunner Plugin" 275 | msgid "Power" 276 | msgstr "Живлення" 277 | 278 | #: ../contents/ui/ConfigSearch.qml 279 | msgctxt "KRunner Plugin" 280 | msgid "Recent Files" 281 | msgstr "Нещодавні файли" 282 | 283 | #: ../contents/ui/ConfigSearch.qml 284 | msgctxt "KRunner Plugin" 285 | msgid "Applications" 286 | msgstr "Програми" 287 | 288 | #: ../contents/ui/ConfigSearch.qml 289 | msgctxt "KRunner Plugin" 290 | msgid "Desktop Sessions" 291 | msgstr "Стільничні сеанси" 292 | 293 | #: ../contents/ui/ConfigSearch.qml 294 | msgctxt "KRunner Plugin" 295 | msgid "Command Line" 296 | msgstr "Командний рядок" 297 | 298 | #: ../contents/ui/ConfigSearch.qml 299 | msgctxt "KRunner Plugin" 300 | msgid "Spell Checker" 301 | msgstr "Перевірка правопису" 302 | 303 | #: ../contents/ui/ConfigSearch.qml 304 | msgctxt "KRunner Plugin" 305 | msgid "System Settings" 306 | msgstr "Системні параметри" 307 | 308 | #: ../contents/ui/ConfigSearch.qml 309 | msgctxt "KRunner Plugin" 310 | msgid "Web Search Keywords" 311 | msgstr "Ключові слова пошуку в інтернеті" 312 | 313 | #: ../contents/ui/ConfigSearch.qml 314 | msgctxt "KRunner Plugin" 315 | msgid "Locations" 316 | msgstr "Адреси" 317 | 318 | #: ../contents/ui/ConfigSearch.qml 319 | msgctxt "KRunner Plugin" 320 | msgid "Activities" 321 | msgstr "Простори дій" 322 | 323 | #: ../contents/ui/ConfigSearch.qml 324 | msgctxt "KRunner Plugin" 325 | msgid "Date and Time" 326 | msgstr "Дата і час" 327 | 328 | #: ../contents/ui/ConfigSearch.qml 329 | msgctxt "KRunner Plugin" 330 | msgid "Unit Converter" 331 | msgstr "Перетворювач одиниць" 332 | 333 | #: ../contents/ui/ConfigSearch.qml 334 | msgctxt "KRunner Plugin" 335 | msgid "Windows" 336 | msgstr "Вікна" 337 | 338 | #: ../contents/ui/ConfigSearch.qml 339 | msgid "Plugin Allowlist" 340 | msgstr "" 341 | 342 | #: ../contents/ui/ConfigSearch.qml 343 | msgid "Note: Selected plugins must also be enabled in System Settings" 344 | msgstr "" 345 | 346 | #: ../contents/ui/ConfigSearch.qml 347 | msgctxt "@action:button" 348 | msgid "Configure Enabled Search Plugins…" 349 | msgstr "Налаштувати увімкнені додатки для пошуку…" 350 | 351 | #: ../contents/ui/ConfigSearch.qml 352 | msgid "Custom Search Plugins" 353 | msgstr "" 354 | 355 | #: ../contents/ui/ConfigSearch.qml 356 | msgid "Add any custom plugins you've installed" 357 | msgstr "" 358 | 359 | #: ../contents/ui/ConfigSearch.qml 360 | msgid "Plugin ID:" 361 | msgstr "" 362 | 363 | #: ../contents/ui/main.qml 364 | msgid "Edit Applications..." 365 | msgstr "Змінити список програм..." 366 | 367 | #: ../contents/ui/MenuRepresentation.qml 368 | msgid "Search" 369 | msgstr "Пошук" 370 | 371 | #: ../contents/ui/RunnerResultsView.qml 372 | msgid "Show Less" 373 | msgstr "Показати менше" 374 | 375 | #: ../contents/ui/RunnerResultsView.qml 376 | msgid "Show More" 377 | msgstr "Показати більше" 378 | 379 | #~ msgid "Use plasma icons" 380 | #~ msgstr "Використовувати піктограми Плазми" 381 | -------------------------------------------------------------------------------- /translate/ru.po: -------------------------------------------------------------------------------- 1 | # Translation of plasma-drawer in Russian 2 | # Copyright (C) 2023 3 | # This file is distributed under the same license as the plasma-drawer package. 4 | # Mykhailo Stetsiuk , 2023–2024. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: plasma-drawer\n" 10 | "Report-Msgid-Bugs-To: https://github.com/p-connor/plasma-drawer\n" 11 | "POT-Creation-Date: 2025-01-04 15:55-0600\n" 12 | "PO-Revision-Date: 2023-07-24 10:55+0300\n" 13 | "Last-Translator: Mykhailo Stetsiuk \n" 14 | "Language-Team: \n" 15 | "Language: ru\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: ../metadata.desktop 21 | msgid "Plasma Drawer" 22 | msgstr "Plasma Drawer" 23 | 24 | #: ../metadata.desktop 25 | msgid "A fullscreen customizable launcher with application directories and krunner-like search" 26 | msgstr "Полноэкранный настраиваемый лаунчер с директориями програм и поиском в стиле KRunner" 27 | 28 | #: ../contents/code/tools.js 29 | msgid "Remove action" 30 | msgstr "Удалить действие" 31 | 32 | #: ../contents/code/tools.js 33 | msgid "Show all" 34 | msgstr "Показать все" 35 | 36 | #: ../contents/code/tools.js 37 | msgid "Add to system actions bar" 38 | msgstr "Добавить к системным действиям" 39 | 40 | #: ../contents/code/tools.js 41 | msgid "Edit Applications" 42 | msgstr "Изменить список программ" 43 | 44 | #: ../contents/config/config.qml 45 | msgid "General" 46 | msgstr "Общее" 47 | 48 | #: ../contents/config/config.qml 49 | msgid "Search Plugins" 50 | msgstr "" 51 | 52 | #: ../contents/ui/ConfigGeneral.qml 53 | msgid "Icon:" 54 | msgstr "Иконка:" 55 | 56 | #: ../contents/ui/ConfigGeneral.qml 57 | msgctxt "@item:inmenu Open icon chooser dialog" 58 | msgid "Choose…" 59 | msgstr "Выбрать…" 60 | 61 | #: ../contents/ui/ConfigGeneral.qml 62 | msgctxt "@item:inmenu Reset icon to default" 63 | msgid "Clear Icon" 64 | msgstr "Очистить иконку" 65 | 66 | #: ../contents/ui/ConfigGeneral.qml 67 | msgid "Background:" 68 | msgstr "Фон:" 69 | 70 | #: ../contents/ui/ConfigGeneral.qml 71 | msgid "Use theme color" 72 | msgstr "Использовать цвет из темы" 73 | 74 | #: ../contents/ui/ConfigGeneral.qml 75 | msgid "Use custom color" 76 | msgstr "Использовать пользовательский цвет" 77 | 78 | #: ../contents/ui/ConfigGeneral.qml 79 | msgid "Use image" 80 | msgstr "Использовать изображение" 81 | 82 | #: ../contents/ui/ConfigGeneral.qml 83 | msgid "Custom Color:" 84 | msgstr "Пользовательский цвет:" 85 | 86 | #: ../contents/ui/ConfigGeneral.qml 87 | msgid "Background Color" 88 | msgstr "Цвет фона" 89 | 90 | #: ../contents/ui/ConfigGeneral.qml 91 | msgid "Select Image File" 92 | msgstr "" 93 | 94 | #: ../contents/ui/ConfigGeneral.qml 95 | msgid "Path: " 96 | msgstr "Путь: " 97 | 98 | #: ../contents/ui/ConfigGeneral.qml 99 | msgid "None" 100 | msgstr "Отсутствует" 101 | 102 | #: ../contents/ui/ConfigGeneral.qml 103 | msgid "Please choose an image file" 104 | msgstr "" 105 | 106 | #: ../contents/ui/ConfigGeneral.qml 107 | msgid "Image files" 108 | msgstr "" 109 | 110 | #: ../contents/ui/ConfigGeneral.qml 111 | msgid "All files" 112 | msgstr "" 113 | 114 | #: ../contents/ui/ConfigGeneral.qml 115 | msgid "Background opacity:" 116 | msgstr "Непрозрачность фона" 117 | 118 | #: ../contents/ui/ConfigGeneral.qml 119 | msgid "%1%" 120 | msgstr "%1%" 121 | 122 | #: ../contents/ui/ConfigGeneral.qml 123 | msgid "Applications:" 124 | msgstr "Программы:" 125 | 126 | #: ../contents/ui/ConfigGeneral.qml 127 | msgid "Max columns in grid:" 128 | msgstr "Максимум столбцов в сетке:" 129 | 130 | #: ../contents/ui/ConfigGeneral.qml 131 | msgid "Size of application icons:" 132 | msgstr "Размер иконок программ:" 133 | 134 | #: ../contents/ui/ConfigGeneral.qml 135 | msgid "Use directory icons" 136 | msgstr "Использовать иконки для директорий" 137 | 138 | #: ../contents/ui/ConfigGeneral.qml 139 | msgid "Search:" 140 | msgstr "Поиск:" 141 | 142 | #: ../contents/ui/ConfigGeneral.qml 143 | msgid "Show search bar" 144 | msgstr "Отображать поле поиска" 145 | 146 | #: ../contents/ui/ConfigGeneral.qml 147 | msgid "Adaptive search result size" 148 | msgstr "Адаптивный размер результатов поиска" 149 | 150 | #: ../contents/ui/ConfigGeneral.qml 151 | msgid "Max size of search result icons:" 152 | msgstr "Максимальный размер иконок результатов поиска" 153 | 154 | #: ../contents/ui/ConfigGeneral.qml 155 | msgid "Size of search result icons:" 156 | msgstr "Размер иконок результатов поиска" 157 | 158 | #: ../contents/ui/ConfigGeneral.qml 159 | msgid "System Actions:" 160 | msgstr "Системные действия:" 161 | 162 | #: ../contents/ui/ConfigGeneral.qml 163 | msgid "Show system actions" 164 | msgstr "Отображать системные действия" 165 | 166 | #: ../contents/ui/ConfigGeneral.qml 167 | msgid "Size of system action icons:" 168 | msgstr "Размер иконок системных действий" 169 | 170 | #: ../contents/ui/ConfigGeneral.qml 171 | msgid "Show system action labels" 172 | msgstr "Отображать метки системных действий" 173 | 174 | #: ../contents/ui/ConfigGeneral.qml 175 | msgid "Use symbolic system action icons" 176 | msgstr "" 177 | 178 | #: ../contents/ui/ConfigGeneral.qml 179 | msgid "Other:" 180 | msgstr "Другое:" 181 | 182 | #: ../contents/ui/ConfigGeneral.qml 183 | msgid "Disable animations" 184 | msgstr "Отключить анимации" 185 | 186 | #: ../contents/ui/ConfigGeneral.qml 187 | msgid "Animation speed multiplier:" 188 | msgstr "Множитель скорости анимаций:" 189 | 190 | #: ../contents/ui/ConfigGeneral.qml 191 | msgid "Unhide all hidden applications" 192 | msgstr "Показать все скрытые программы" 193 | 194 | #: ../contents/ui/ConfigGeneral.qml 195 | msgid "Unhidden!" 196 | msgstr "Показано!" 197 | 198 | #: ../contents/ui/ConfigSearch.qml 199 | msgctxt "KRunner Plugin" 200 | msgid "File Search" 201 | msgstr "Поиск файлов" 202 | 203 | #: ../contents/ui/ConfigSearch.qml 204 | msgctxt "KRunner Plugin" 205 | msgid "Browser History" 206 | msgstr "Журнал браузера" 207 | 208 | #: ../contents/ui/ConfigSearch.qml 209 | msgctxt "KRunner Plugin" 210 | msgid "Browser Tabs" 211 | msgstr "Вкладки браузера" 212 | 213 | #: ../contents/ui/ConfigSearch.qml 214 | msgctxt "KRunner Plugin" 215 | msgid "Calculator" 216 | msgstr "Калькулятор" 217 | 218 | #: ../contents/ui/ConfigSearch.qml 219 | msgctxt "KRunner Plugin" 220 | msgid "Help Runner" 221 | msgstr "Средство поиска справки" 222 | 223 | #: ../contents/ui/ConfigSearch.qml 224 | msgctxt "KRunner Plugin" 225 | msgid "Software Center" 226 | msgstr "Центр программ" 227 | 228 | #: ../contents/ui/ConfigSearch.qml 229 | msgctxt "KRunner Plugin" 230 | msgid "Bookmarks" 231 | msgstr "Закладки" 232 | 233 | #: ../contents/ui/ConfigSearch.qml 234 | msgctxt "KRunner Plugin" 235 | msgid "Special Characters" 236 | msgstr "Специальные символы" 237 | 238 | #: ../contents/ui/ConfigSearch.qml 239 | msgctxt "KRunner Plugin" 240 | msgid "Dictionary" 241 | msgstr "Словарь" 242 | 243 | #: ../contents/ui/ConfigSearch.qml 244 | msgctxt "KRunner Plugin" 245 | msgid "Kate Sessions" 246 | msgstr "Kate: сеансы" 247 | 248 | #: ../contents/ui/ConfigSearch.qml 249 | msgctxt "KRunner Plugin" 250 | msgid "Terminate Applications" 251 | msgstr "Завершение приложений" 252 | 253 | #: ../contents/ui/ConfigSearch.qml 254 | msgctxt "KRunner Plugin" 255 | msgid "Konsole Profiles" 256 | msgstr "Konsole: профили" 257 | 258 | #: ../contents/ui/ConfigSearch.qml 259 | msgctxt "KRunner Plugin" 260 | msgid "KWin" 261 | msgstr "KWin" 262 | 263 | #: ../contents/ui/ConfigSearch.qml 264 | msgctxt "KRunner Plugin" 265 | msgid "Places" 266 | msgstr "Точки входа" 267 | 268 | #: ../contents/ui/ConfigSearch.qml 269 | msgctxt "KRunner Plugin" 270 | msgid "Plasma Desktop Shell" 271 | msgstr "Консоль сценариев Plasma" 272 | 273 | #: ../contents/ui/ConfigSearch.qml 274 | msgctxt "KRunner Plugin" 275 | msgid "Power" 276 | msgstr "Электропитание" 277 | 278 | #: ../contents/ui/ConfigSearch.qml 279 | msgctxt "KRunner Plugin" 280 | msgid "Recent Files" 281 | msgstr "Последние файлы" 282 | 283 | #: ../contents/ui/ConfigSearch.qml 284 | msgctxt "KRunner Plugin" 285 | msgid "Applications" 286 | msgstr "Приложения" 287 | 288 | #: ../contents/ui/ConfigSearch.qml 289 | msgctxt "KRunner Plugin" 290 | msgid "Desktop Sessions" 291 | msgstr "Сеансы" 292 | 293 | #: ../contents/ui/ConfigSearch.qml 294 | msgctxt "KRunner Plugin" 295 | msgid "Command Line" 296 | msgstr "Запуск программ" 297 | 298 | #: ../contents/ui/ConfigSearch.qml 299 | msgctxt "KRunner Plugin" 300 | msgid "Spell Checker" 301 | msgstr "Проверка орфографии" 302 | 303 | #: ../contents/ui/ConfigSearch.qml 304 | msgctxt "KRunner Plugin" 305 | msgid "System Settings" 306 | msgstr "Параметры системы" 307 | 308 | #: ../contents/ui/ConfigSearch.qml 309 | msgctxt "KRunner Plugin" 310 | msgid "Web Search Keywords" 311 | msgstr "Ключевые слова для веб-поиска" 312 | 313 | #: ../contents/ui/ConfigSearch.qml 314 | msgctxt "KRunner Plugin" 315 | msgid "Locations" 316 | msgstr "Расположения" 317 | 318 | #: ../contents/ui/ConfigSearch.qml 319 | msgctxt "KRunner Plugin" 320 | msgid "Activities" 321 | msgstr "Комнаты" 322 | 323 | #: ../contents/ui/ConfigSearch.qml 324 | msgctxt "KRunner Plugin" 325 | msgid "Date and Time" 326 | msgstr "Дата и время" 327 | 328 | #: ../contents/ui/ConfigSearch.qml 329 | msgctxt "KRunner Plugin" 330 | msgid "Unit Converter" 331 | msgstr "Преобразование величин" 332 | 333 | #: ../contents/ui/ConfigSearch.qml 334 | msgctxt "KRunner Plugin" 335 | msgid "Windows" 336 | msgstr "Окна" 337 | 338 | #: ../contents/ui/ConfigSearch.qml 339 | msgid "Plugin Allowlist" 340 | msgstr "" 341 | 342 | #: ../contents/ui/ConfigSearch.qml 343 | msgid "Note: Selected plugins must also be enabled in System Settings" 344 | msgstr "" 345 | 346 | #: ../contents/ui/ConfigSearch.qml 347 | msgctxt "@action:button" 348 | msgid "Configure Enabled Search Plugins…" 349 | msgstr "Настроить активированные плагины для поиска…" 350 | 351 | #: ../contents/ui/ConfigSearch.qml 352 | msgid "Custom Search Plugins" 353 | msgstr "" 354 | 355 | #: ../contents/ui/ConfigSearch.qml 356 | msgid "Add any custom plugins you've installed" 357 | msgstr "" 358 | 359 | #: ../contents/ui/ConfigSearch.qml 360 | msgid "Plugin ID:" 361 | msgstr "" 362 | 363 | #: ../contents/ui/main.qml 364 | msgid "Edit Applications..." 365 | msgstr "Изменить список программ..." 366 | 367 | #: ../contents/ui/MenuRepresentation.qml 368 | msgid "Search" 369 | msgstr "Поиск" 370 | 371 | #: ../contents/ui/RunnerResultsView.qml 372 | msgid "Show Less" 373 | msgstr "Показать меньше" 374 | 375 | #: ../contents/ui/RunnerResultsView.qml 376 | msgid "Show More" 377 | msgstr "Показать больше" 378 | 379 | #~ msgid "Use plasma icons" 380 | #~ msgstr "Использовать иконки Plasma" 381 | -------------------------------------------------------------------------------- /translate/ro.po: -------------------------------------------------------------------------------- 1 | # Translation of PlasmaDrawer in Romanian 2 | # Copyright (C) 2024 3 | # This file is distributed under the same license as the PlasmaDrawer package. 4 | # maxhatei2 , 2024. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PlasmaDrawer\n" 10 | "Report-Msgid-Bugs-To: https://github.com/p-connor/plasma-drawer\n" 11 | "POT-Creation-Date: 2025-01-04 15:55-0600\n" 12 | "PO-Revision-Date: 2024-11-21 20:50+2\n" 13 | "Last-Translator: maxhatei2