Very early KDE 6 release.

This commit is contained in:
wackyideas 2024-08-09 03:20:25 +02:00
parent 7cc4ccabbc
commit 686046d4f7
6272 changed files with 140920 additions and 529657 deletions

View file

@ -0,0 +1,35 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.configuration 2.0
ConfigModel {
property bool isFolder: (Plasmoid.pluginName === "org.kde.plasma.folder")
ConfigCategory {
name: i18n("Location")
icon: "inode-directory"
source: "ConfigLocation.qml"
visible: isFolder
}
ConfigCategory {
name: i18n("Icons")
icon: "preferences-desktop-icons"
source: "ConfigIcons.qml"
visible: isFolder
}
ConfigCategory {
name: i18n("Filter")
icon: "preferences-desktop-filter"
source: "ConfigFilter.qml"
visible: isFolder
}
}

View file

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="General">
<entry name="icon" type="String">
<label>The name of the custom icon to use for the compact representation (e.g. on a small panel) of the Folder View applet. Only used if useCustomIcon is true.</label>
<default>folder-symbolic</default>
</entry>
<entry name="useCustomIcon" type="Bool">
<label>Whether to use a custom icon for the compact representation (e.g. on a small panel) of the Folder View Applet.</label>
<default>false</default>
</entry>
<entry name="ItemsGeometries" type="String" hidden="true">
<label>Encoded geometries of items (resource categories).</label>
</entry>
<entry name="ToolBoxButtonState" type="String">
<label>Position state of the toolbox button.</label>
<default></default>
</entry>
<entry name="ToolBoxButtonX" type="int">
<label>X coordinate of the toolbox.</label>
</entry>
<entry name="ToolBoxButtonY" type="int">
<label>Y coordinate of the toolbox.</label>
</entry>
<entry name="FirstStartup" type="Bool" hidden="true">
<label>First time the containment starts?</label>
<default>true</default>
</entry>
<entry name="positions" type="StringList" hidden="true">
<default></default>
</entry>
<entry name="url" type="String">
<label>URL of the file system location being shown.</label>
<default>desktop:/</default>
</entry>
<entry name="labelMode" type="Int">
<label>How to show the Folder View label: 0 = No label, 1 = Friendly version of path relative to closest Places entry, 2 = Full path, 3 = Custom title</label>
<default>1</default>
</entry>
<entry name="labelText" type="String">
<label>Custom text for the Folder View label. Only used if labelMode is 3.</label>
<default></default>
</entry>
<entry name="arrangement" type="Int">
<label>How Folder View icons are arranged: 0 = Rows, 1 = Columns</label>
<default>0</default>
</entry>
<entry name="alignment" type="Int">
<label>How Folder View icons are aligned: 0 = Left, 1 = Right</label>
<default>0</default>
</entry>
<entry name="locked" type="Bool">
<label>Whether Folder View icons are locked or not. Only used when serving as containment.</label>
<default>false</default>
</entry>
<entry name="sortMode" type="Int">
<label>How Folder View icons are sorted: 0 = Unsorted, 1 = Name, 2 = Size, 3 = Type, 4 = Date</label>
<default>0</default>
</entry>
<entry name="sortDesc" type="Bool">
<label>Whether to sort Folder View icons descending instead of ascending.</label>
<default>false</default>
</entry>
<entry name="sortDirsFirst" type="Bool">
<label>Whether to sort folders before files in Folder View.</label>
<default>true</default>
</entry>
<entry name="toolTips" type="Bool">
<label>Whether to show info tooltips when hovering Folder View icons.</label>
<default>false</default>
</entry>
<entry name="selectionMarkers" type="Bool">
<label>Whether to show selection markers when hovering Folder View icons.</label>
<default>true</default>
</entry>
<entry name="renameInline" type="Bool">
<label>Whether to initiate inline renaming when clicking on the text of an already-selected item, while using the systemwide double-click mode.</label>
<default>true</default>
</entry>
<entry name="popups" type="Bool">
<label>Whether to show a popup preview window for Folder View icons for folders.</label>
<default>false</default>
</entry>
<entry name="previews" type="Bool">
<label>Whether to show preview thumbnails in Folder View.</label>
<default>true</default>
</entry>
<entry name="previewPlugins" type="StringList">
<label>List of ids of the thumbnail preview plugins to use in Folder View. If empty, uses a default set of thumbnailers (cf. KIO::PreviewJob::defaultPlugins)</label>
<default></default>
</entry>
<entry name="viewMode" type="Int">
<label>The Folder View view mode (used only by the widget full representation): 0 = Grid, 1 = List</label>
<default>0</default>
</entry>
<entry name="iconSize" type="Int">
<label>The icon size to use for Folder View icons. 0 = 22px (smallMedium); 1 = 32px (medium); 2 = 48px (large); 3 = 64px (huge); 4 = 96px (large * 2); 5 = 128px (enormous); 6 = 256px (enormous * 2)</label>
<default>3</default>
</entry>
<entry name="labelWidth" type="Int">
<label>The width of the grid cells when using icon view. 0 = Narrow, 1 = Medium, 2 = Wide</label>
<default>1</default>
</entry>
<entry name="textLines" type="Int">
<label>The (maximum) number of lines of text to use below Folder View icons.</label>
<default>2</default>
</entry>
<entry name="textColor" type="String">
<label>The text color to use below Folder View icons. Only used when serving as containment.</label>
<default>white</default>
</entry>
<entry name="filterPattern" type="String">
<label>The pattern to filter files by. Supports wildcards.</label>
<default>*</default>
</entry>
<entry name="filterMode" type="Int">
<label>The file filter mode: 0 = Show All Files, 1 = Show Files Matching, 2 = Hide Files Matching</label>
<default>0</default>
</entry>
<entry name="filterMimeTypes" type="StringList">
<label>List of MIME types to filter by.</label>
<default>all/all</default>
</entry>
<entry name="showHiddenFiles" type="Bool">
<label>Show hidden files.</label>
<default>false</default>
</entry>
<entry name="textShadows" type="Bool">
<label>Use drop shadows for icon labels on the desktop.</label>
<default>true</default>
</entry>
<entry name="iconShadows" type="Bool">
<label>Use drop shadows for icons on the desktop.</label>
<default>false</default>
</entry>
</group>
</kcfg>

View file

@ -0,0 +1,45 @@
/*
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.components 3.0 as PC3
PC3.ToolButton {
id: button
property QtObject qAction
readonly property int iconSize: Kirigami.Settings.hasTransientTouchInput
? Kirigami.Units.iconSizes.medium
: Kirigami.Units.iconSizes.small
property alias toolTip: toolTip.text
onClicked: {
if (qAction) {
qAction.trigger()
}
if (!Plasmoid.containment.corona.editMode) {
appletContainer.editMode = false;
}
}
icon.width: iconSize
icon.height: iconSize
PC3.ToolTip {
id: toolTip
text: button.qAction ? button.qAction.text : ""
delay: 0
visible: button.hovered && text.length > 0
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
}
}

View file

@ -0,0 +1,126 @@
/*
SPDX-FileCopyrightText: 2011-2013 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.kirigami 2.20 as Kirigami
KSvg.FrameSvgItem {
id: upButton
width: gridView.cellWidth
height: visible ? gridView.cellHeight : 0
visible: history.length !== 0
property bool ignoreClick: false
property bool containsDrag: false
imagePath: "widgets/viewitem"
function handleDragMove() {
containsDrag = true;
hoverActivateTimer.restart();
}
function endDragMove() {
containsDrag = false;
hoverActivateTimer.stop();
}
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.BackButton
hoverEnabled: true
onContainsMouseChanged: {
gridView.hoveredItem = null;
}
onPressed: mouse => {
if (mouse.buttons & Qt.BackButton) {
if (root.isPopup && dir.resolvedUrl !== dir.resolve(Plasmoid.configuration.url)) {
doBack();
ignoreClick = true;
}
}
}
onClicked: mouse => {
if (ignoreClick) {
ignoreClick = false;
return;
}
doBack();
}
}
Kirigami.Icon {
id: icon
anchors {
left: parent.left
leftMargin: Kirigami.Units.smallSpacing
verticalCenter: parent.verticalCenter
}
width: gridView.iconSize
height: gridView.iconSize
source: "arrow-left"
}
PlasmaComponents3.Label {
id: label
anchors {
left: icon.right
leftMargin: Kirigami.Units.smallSpacing * 2
verticalCenter: parent.verticalCenter
}
width: parent.width - icon.width - (Kirigami.Units.smallSpacing * 4);
height: undefined // Unset PlasmaComponents.Label's default.
textFormat: Text.PlainText
maximumLineCount: root.isPopup ? 1 : Plasmoid.configuration.textLines
wrapMode: Text.Wrap
elide: Text.ElideRight
text: i18n("Back")
}
Timer {
id: hoverActivateTimer
interval: root.hoverActivateDelay
onTriggered: doBack()
}
states: [
State {
name: "hover"
when: mouseArea.containsMouse || containsDrag
PropertyChanges {
target: upButton
prefix: "hover"
}
}
]
}

View file

@ -0,0 +1,73 @@
/*
SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.draganddrop 2.0 as DragDrop
import org.kde.kirigami 2.20 as Kirigami
DragDrop.DropArea {
readonly property bool inPanel: [
PlasmaCore.Types.TopEdge,
PlasmaCore.Types.LeftEdge,
PlasmaCore.Types.RightEdge,
PlasmaCore.Types.BottomEdge,
].includes(Plasmoid.location)
Layout.minimumWidth: Plasmoid.formFactor === PlasmaCore.Types.Horizontal ? height : Kirigami.Units.iconSizes.small
Layout.minimumHeight: Plasmoid.formFactor === PlasmaCore.Types.Vertical ? width : (Kirigami.Units.iconSizes.small + 2 * Kirigami.Units.iconSizes.sizeForLabels)
property Item folderView: null
onContainsDragChanged: contained => {
if (containsDrag) {
hoverActivateTimer.restart();
} else {
hoverActivateTimer.stop();
}
}
onDrop: event => {
folderView.model.dropCwd(event);
}
preventStealing: true
function toggle() {
root.expanded = !root.expanded;
}
Kirigami.Icon {
id: icon
anchors.fill: parent
active: mouseArea.containsMouse
source: Plasmoid.configuration.useCustomIcon ? Plasmoid.configuration.icon : folderView.model.iconName
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: mouse => toggle()
}
Timer {
id: hoverActivateTimer
interval: root.hoverActivateDelay
onTriggered: toggle()
}
}

View file

@ -0,0 +1,230 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.core as PlasmaCore
import org.kde.private.desktopcontainment.folder 0.1 as Folder
import org.kde.kitemmodels 1.0 as KItemModels
ColumnLayout {
id: configIcons
property alias cfg_filterMode: filterMode.currentIndex
property alias cfg_filterPattern: filterPattern.text
property alias cfg_filterMimeTypes: mimeTypesModel.checkedTypes
property alias cfg_showHiddenFiles: showHiddenFiles.checked
KItemModels.KSortFilterProxyModel {
id: filteredMimeTypesModel
sourceModel: Folder.MimeTypesModel {
id: mimeTypesModel
}
filterRegularExpression: RegExp(mimeFilter.text, "i")
filterRoleName: "name"
sortRoleName: "name"
sortOrder: Qt.AscendingOrder
function checkFiltered() {
var types = [];
for (var i = 0; i < count; ++i) {
types.push(get(i).name);
}
mimeTypesModel.checkedTypes = types;
}
function uncheckFiltered() {
var types = [];
for (var i = 0; i < count; ++i) {
types.push(get(i).name);
}
mimeTypesModel.checkedTypes = mimeTypesModel.checkedTypes
.filter(x => types.indexOf(x) === -1);
}
}
Kirigami.FormLayout {
ComboBox {
id: filterMode
Kirigami.FormData.label: i18n("Files:")
model: [i18n("Show all"), i18n("Show matching"), i18n("Hide matching")]
}
TextField {
id: filterPattern
Kirigami.FormData.label: i18n("File name pattern:")
enabled: (filterMode.currentIndex > 0)
inputMethodHints: Qt.ImhNoPredictiveText
}
Kirigami.SearchField {
id: mimeFilter
Kirigami.FormData.label: i18n("File types:")
enabled: (filterMode.currentIndex > 0)
}
CheckBox {
id: showHiddenFiles
Kirigami.FormData.label: i18n("Show hidden files:")
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
CheckBox { // Purely for metrics.
id: metricsCheckBox
visible: false
}
ScrollView {
id: scrollView
enabled: (filterMode.currentIndex > 0)
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: 100 // Note: this arbitrary number is a workaround to the layout trying to resize the scrollview to an huge value, the behavior is still correctly stretching
Component.onCompleted: {
if (background) {
background.visible = true;
}
}
contentItem: ListView {
id: mimeTypesView
clip: true
// Signal the delegates listen to when user presses space to toggle current row.
signal toggleCurrent()
model: filteredMimeTypesModel
property real columnSize: Kirigami.Units.iconSizes.small * 15
headerPositioning: ListView.OverlayHeader
Keys.onSpacePressed: toggleCurrent()
header: HorizontalHeaderView {
id: headerView
z: 9
implicitWidth: mimeTypesView.width
rowHeightProvider: function () {
return Kirigami.Units.iconSizes.small * 2
}
clip: true // This removes event handling blocking by the header
model: ListModel {
Component.onCompleted: {
append({ display: i18n("File Type") });
append({ display: i18n("Description") });
}
}
interactive: false
columnWidthProvider: function(column) {
if (column === 0) {
return mimeTypesView.columnSize;
} else {
return mimeTypesView.width - mimeTypesView.columnSize;
}
}
}
delegate: ItemDelegate {
id: delegate
width: mimeTypesView.width
required property string name
required property string comment
required property var decoration
contentItem: RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: Kirigami.Units.iconSizes.small
RowLayout {
Layout.preferredWidth: mimeTypesView.columnSize
Layout.maximumWidth: mimeTypesView.columnSize
Layout.fillHeight: true
CheckBox {
Layout.fillHeight: true
checked: mimeTypesModel.checkedTypes.indexOf(name) >= 0
onToggled: {
let idx = mimeTypesModel.checkedTypes.indexOf(name);
if (idx >= 0) {
mimeTypesModel.checkedTypes.splice(idx, 1);
} else {
mimeTypesModel.checkedTypes.push(name)
}
}
}
Kirigami.Icon {
Layout.fillHeight: true
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small
animated: false // TableView re-uses delegates, avoid animation when sorting/filtering.
source: decoration
}
Label {
text: name
elide: Text.ElideRight
Layout.fillWidth: true
Layout.fillHeight: true
}
}
Label {
text: comment
elide: Text.ElideRight
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
}
}
RowLayout {
id: selectLayout
Button {
id: selectAllButton
enabled: (filterMode.currentIndex > 0)
icon.name: "edit-select-all"
ToolTip.delay: Kirigami.Units.toolTipDelay
ToolTip.visible: (Kirigami.Settings.isMobile ? pressed : hovered) && ToolTip.text.length > 0
ToolTip.text: i18n("Select All")
onClicked: filteredMimeTypesModel.checkFiltered()
}
Button {
id: deselectAllButton
enabled: (filterMode.currentIndex > 0)
icon.name: "edit-select-none"
ToolTip.delay: Kirigami.Units.toolTipDelay
ToolTip.visible: (Kirigami.Settings.isMobile ? pressed : hovered) && ToolTip.text.length > 0
ToolTip.text: i18n("Deselect All")
onClicked: filteredMimeTypesModel.uncheckFiltered()
}
Button {
enabled: (filterMode.currentIndex > 0)
icon.name: filteredMimeTypesModel.sortOrder === Qt.AscendingOrder ? "view-sort-ascending-symbolic" : "view-sort-descending-symbolic"
ToolTip.delay: Kirigami.Units.toolTipDelay
ToolTip.visible: (Kirigami.Settings.isMobile ? pressed : hovered) && ToolTip.text.length > 0
ToolTip.text: i18n("Switch Sort Order")
onClicked: {
filteredMimeTypesModel.sortOrder = filteredMimeTypesModel.sortOrder === Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder;
filteredMimeTypesModel.sort(0, filteredMimeTypesModel.sortOrder);
}
}
}
}
}

View file

@ -0,0 +1,370 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.iconthemes as KIconThemes
import org.kde.config // for KAuthorized
import org.kde.kirigami 2.20 as Kirigami
import org.kde.private.desktopcontainment.folder 0.1 as Folder
Item {
id: configIcons
property bool isPopup: (Plasmoid.location !== PlasmaCore.Types.Floating)
property string cfg_icon: Plasmoid.configuration.icon
property alias cfg_useCustomIcon: useCustomIcon.checked
property alias cfg_arrangement: arrangement.currentIndex
property alias cfg_alignment: alignment.currentIndex
property bool cfg_locked
property alias cfg_sortMode: sortMode.mode
property alias cfg_sortDesc: sortDesc.checked
property alias cfg_sortDirsFirst: sortDirsFirst.checked
property alias cfg_toolTips: toolTips.checked
property alias cfg_selectionMarkers: selectionMarkers.checked
property alias cfg_renameInline: renameInline.checked
property alias cfg_popups: popups.checked
property alias cfg_previews: previews.checked
property var cfg_previewPlugins
property alias cfg_viewMode: viewMode.currentIndex
property alias cfg_iconSize: iconSize.value
property alias cfg_labelWidth: labelWidth.currentIndex
property alias cfg_textLines: textLines.value
property alias cfg_textShadows: textShadows.checked
property alias cfg_iconShadows: iconShadows.checked
readonly property bool lockedByKiosk: !KAuthorized.authorize("editable_desktop_icons")
KIconThemes.IconDialog {
id: iconDialog
onIconNameChanged: cfg_icon = iconName || "folder-symbolic";
}
Kirigami.FormLayout {
anchors {
top: parent.top
left: parent.left
right: parent.right
}
// Panel button
RowLayout {
spacing: Kirigami.Units.smallSpacing
visible: isPopup
Kirigami.FormData.label: i18n("Panel button:")
CheckBox {
id: useCustomIcon
visible: isPopup
checked: cfg_useCustomIcon
text: i18n("Use a custom icon")
}
Button {
id: iconButton
Layout.minimumWidth: Kirigami.Units.iconSizes.large + Kirigami.Units.smallSpacing * 2
Layout.maximumWidth: Layout.minimumWidth
Layout.minimumHeight: Layout.minimumWidth
Layout.maximumHeight: Layout.minimumWidth
checkable: true
enabled: useCustomIcon.checked
onClicked: {
checked = Qt.binding(() =>
iconMenu.status === PlasmaExtras.Menu.Open);
iconMenu.open(0, height);
}
Kirigami.Icon {
anchors.centerIn: parent
width: Kirigami.Units.iconSizes.large
height: width
source: cfg_icon
}
}
PlasmaExtras.Menu {
id: iconMenu
visualParent: iconButton
PlasmaExtras.MenuItem {
text: i18nc("@item:inmenu Open icon chooser dialog", "Choose…")
icon: "document-open-folder"
onClicked: iconDialog.open()
}
PlasmaExtras.MenuItem {
text: i18nc("@item:inmenu Reset icon to default", "Clear Icon")
icon: "edit-clear"
onClicked: cfg_icon = "folder-symbolic";
}
}
}
Item {
visible: isPopup
Kirigami.FormData.isSection: true
}
// Arrangement section
ComboBox {
id: arrangement
Layout.fillWidth: true
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
Kirigami.FormData.label: i18n("Arrangement:")
model: [
Qt.application.layoutDirection === Qt.LeftToRight ?
i18nc("@item:inlistbox arrangement of icons", "Left to Right") :
i18nc("@item:inlistbox arrangement of icons", "Right to Left"),
i18nc("@item:inlistbox arrangement of icons", "Top to Bottom"),
]
}
ComboBox {
id: alignment
Layout.fillWidth: true
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
model: [i18nc("@item:inlistbox alignment of icons", "Align left"),
i18nc("@item:inlistbox alignment of icons", "Align right")]
}
CheckBox {
id: locked
visible: ("containmentType" in plasmoid)
checked: cfg_locked || lockedByKiosk
enabled: !lockedByKiosk
onCheckedChanged: {
if (!lockedByKiosk) {
cfg_locked = checked;
}
}
text: i18n("Lock in place")
}
Item {
Kirigami.FormData.isSection: true
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
}
// Sorting section
ComboBox {
id: sortMode
Layout.fillWidth: true
Kirigami.FormData.label: i18n("Sorting:")
property int mode
// FIXME TODO HACK: This maps the combo box list model to the KDirModel::ModelColumns
// enum, which should be done in C++.
property var indexToMode: [-1, 0, 1, 6, 2]
property var modeToIndex: {'-1': '0', '0': '1', '1': '2', '6': '3', '2': '4'}
model: [i18nc("@item:inlistbox sort icons manually", "Manual"),
i18nc("@item:inlistbox sort icons by name", "Name"),
i18nc("@item:inlistbox sort icons by size", "Size"),
i18nc("@item:inlistbox sort icons by file type", "Type"),
i18nc("@item:inlistbox sort icons by date", "Date")]
Component.onCompleted: currentIndex = modeToIndex[mode]
onActivated: mode = indexToMode[index]
}
CheckBox {
id: sortDesc
enabled: sortMode.currentIndex !== 0
text: i18nc("@option:check sort icons in descending order", "Descending")
}
CheckBox {
id: sortDirsFirst
enabled: sortMode.currentIndex !== 0
text: i18nc("@option:check sort icons with folders first", "Folders first")
}
Item {
Kirigami.FormData.isSection: true
}
// View Mode section (only if we're a pop-up)
ComboBox {
id: viewMode
visible: isPopup
Layout.fillWidth: true
Kirigami.FormData.label: i18nc("whether to use icon or list view", "View mode:")
model: [i18nc("@item:inlistbox show icons in a list", "List"),
i18nc("@item:inlistbox show icons in a grid", "Grid")]
}
// Size section
Slider {
id: iconSize
Layout.fillWidth: true
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
Kirigami.FormData.label: i18n("Icon size:")
from: 0
to: 6
stepSize: 1
snapMode: Slider.SnapAlways
}
RowLayout {
Layout.fillWidth: true
Label {
Layout.alignment: Qt.AlignLeft
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
text: i18nc("@label:slider smallest icon size", "Small")
}
Item {
Layout.fillWidth: true
}
Label {
Layout.alignment: Qt.AlignRight
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
text: i18nc("@label:slider largest icon size", "Large")
}
}
ComboBox {
id: labelWidth
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
Layout.fillWidth: true
Kirigami.FormData.label: i18n("Label width:")
model: [
i18nc("@item:inlistbox how long a text label should be", "Narrow"),
i18nc("@item:inlistbox how long a text label should be", "Medium"),
i18nc("@item:inlistbox how long a text label should be", "Wide"),
]
}
SpinBox {
id: textLines
visible: !isPopup || viewMode.currentIndex === 1 /* Icons mode */
Kirigami.FormData.label: i18n("Text lines:")
from: 1
to: 10
stepSize: 1
}
Item {
Kirigami.FormData.isSection: true
}
// Features section
CheckBox {
id: toolTips
Kirigami.FormData.label: i18n("When hovering over icons:")
text: i18n("Show tooltips")
}
CheckBox {
id: selectionMarkers
visible: Qt.styleHints.singleClickActivation
text: i18n("Show selection markers")
}
CheckBox {
id: popups
visible: !isPopup
text: i18n("Show folder preview popups")
}
Item {
Kirigami.FormData.isSection: true
}
CheckBox {
id: renameInline
Kirigami.FormData.label: i18n("Rename:")
visible: !selectionMarkers.visible
text: i18n("Rename inline by clicking selected item's text")
}
Item {
Kirigami.FormData.isSection: true
visible: renameInline.visible
}
CheckBox {
id: textShadows
text: i18n("Use drop shadows for icon labels on the desktop")
}
CheckBox {
id: iconShadows
text: i18n("Use drop shadows for icons on the desktop")
}
CheckBox {
id: previews
Kirigami.FormData.label: i18n("Previews:")
text: i18n("Show preview thumbnails")
}
Button {
id: previewSettings
Layout.fillWidth: true
icon.name: "configure"
text: i18n("Configure Preview Plugins…")
onClicked: {
const component = Qt.createComponent(Qt.resolvedUrl("FolderItemPreviewPluginsDialog.qml"));
component.incubateObject(configIcons.Window.window.contentItem, {
"previewPlugins": configIcons.cfg_previewPlugins,
}, Qt.Asynchronous);
component.destroy();
}
}
}
}

View file

@ -0,0 +1,201 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.private.desktopcontainment.folder 0.1 as Folder
Item {
id: configLocation
property string cfg_url
property alias cfg_labelMode: labelMode.currentIndex
property alias cfg_labelText: labelText.text
property bool titleVisible: !("containmentType" in plasmoid)
onCfg_urlChanged: applyConfig()
function applyConfig(force) {
if (!force && locationGroup.checkedButton !== null) {
return;
}
if (cfg_url === "desktop:/") {
locationDesktop.checked = true;
locationCustomValue.text = "";
} else if (cfg_url === "activities:/current/") {
locationCurrentActivity.checked = true;
locationCustomValue.text = "";
} else {
var placeForUrl = placesModel.indexForUrl(cfg_url);
if (placeForUrl !== -1) {
locationPlace.checked = true;
locationPlaceValue.currentIndex = placeForUrl;
locationCustomValue.text = "";
} else {
locationCustom.checked = true;
locationCustomValue.text = cfg_url;
}
}
locationPlaceValue.enabled = locationPlace.checked;
}
Folder.PlacesModel {
id: placesModel
showDesktopEntry: false
onPlacesChanged: applyConfig(true)
}
ButtonGroup {
id: locationGroup
buttons: [locationDesktop, locationCurrentActivity, locationPlace, locationCustom]
onCheckedButtonChanged: {
if (checkedButton === locationDesktop) {
cfg_url = "desktop:/";
} else if (checkedButton === locationCurrentActivity) {
cfg_url = "activities:/current/";
}
}
}
Kirigami.FormLayout {
anchors.horizontalCenter: parent.horizontalCenter
RadioButton {
id: locationDesktop
Kirigami.FormData.label: i18n("Show:")
text: i18n("Desktop folder")
}
RadioButton {
id: locationCurrentActivity
visible: placesModel.activityLinkingEnabled
text: i18n("Files linked to the current activity")
}
RowLayout {
RadioButton {
id: locationPlace
text: i18n("Places panel item:")
onCheckedChanged: {
locationPlaceValue.enabled = checked;
}
}
ComboBox {
id: locationPlaceValue
Layout.fillWidth: true
model: placesModel
textRole: "display"
enabled: true
onEnabledChanged: {
if (enabled && currentIndex !== -1) {
cfg_url = placesModel.urlForIndex(currentIndex);
}
}
onActivated: {
cfg_url = placesModel.urlForIndex(index);
}
}
}
RowLayout {
RadioButton {
id: locationCustom
text: i18n("Custom location:")
}
TextField {
id: locationCustomValue
enabled: locationCustom.checked
Layout.fillWidth: true
placeholderText: i18n("Type path or URL…")
inputMethodHints: Qt.ImhNoPredictiveText
onEnabledChanged: {
if (enabled && text !== "") {
cfg_url = text;
}
}
onTextChanged: {
if (enabled) {
cfg_url = text;
}
}
}
Button {
icon.name: "document-open"
enabled: locationCustom.checked
onClicked: {
directoryPicker.open();
}
}
Folder.DirectoryPicker {
id: directoryPicker
onUrlChanged: {
locationCustomValue.text = url;
}
}
}
Item {
visible: titleVisible
Kirigami.FormData.isSection: true
}
ComboBox {
id: labelMode
visible: titleVisible
Kirigami.FormData.label: i18n("Title:")
model: [i18n("None"), i18n("Default"), i18n("Full path"), i18n("Custom title")]
}
RowLayout {
visible: titleVisible
Item {
width: Kirigami.Units.iconSizes.small
}
TextField {
id: labelText
Layout.fillWidth: true
enabled: (labelMode.currentIndex === 3)
placeholderText: i18n("Enter custom title…")
}
}
}
}

View file

@ -0,0 +1,247 @@
/*
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
ContainmentLayoutManager.ConfigOverlayWithHandles {
id: overlay
SequentialAnimation {
id: removeAnim
NumberAnimation {
target: overlay.itemContainer
property: "scale"
from: 1
to: 0
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
ScriptAction {
script: {
appletContainer.applet.plasmoid.internalAction("remove").trigger();
appletContainer.editMode = false;
}
}
}
KSvg.FrameSvgItem {
id: frame
anchors.verticalCenter: parent.verticalCenter
x: overlay.rightAvailableSpace > width + Kirigami.Units.iconSizes.small
? parent.width + Kirigami.Units.iconSizes.small
: -width - Kirigami.Units.iconSizes.small
// This MouseArea is used to block input between the applet and the handle, to not make it steal by other applets
MouseArea {
anchors {
top: parent.top
bottom: parent.bottom
}
z: -1
x: overlay.rightAvailableSpace > parent.width + Kirigami.Units.iconSizes.small ? -Kirigami.Units.iconSizes.small : 0
width: Kirigami.Units.iconSizes.small + parent.width
hoverEnabled: true
}
transform: Translate {
x: open ? 0 : (overlay.rightAvailableSpace > frame.width + Kirigami.Units.iconSizes.small ? -frame.width : frame.width)
Behavior on x {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
width: layout.implicitWidth + margins.left + margins.right
height: Math.max(layout.implicitHeight + margins.top + margins.bottom, parent.height)
imagePath: "widgets/background"
ColumnLayout {
id: layout
anchors {
fill: parent
topMargin: parent.margins.top
leftMargin: parent.margins.left
bottomMargin: parent.margins.bottom
rightMargin: parent.margins.right
}
ActionButton {
id: rotateButton
icon.name: "object-rotate-left-symbolic"
toolTip: !rotateHandle.pressed ? i18n("Click and drag to rotate") : ""
action: applet ? applet.plasmoid.internalAction("rotate") : null
down: rotateHandle.pressed
Component.onCompleted: {
if (action !== null) {
action.enabled = true;
}
}
MouseArea {
id: rotateHandle
anchors.fill: parent
property int startRotation
property real startCenterRelativeAngle
function pointAngle(pos: point): real {
var r = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
var cosine = pos.x / r;
if (pos.y >= 0) {
return Math.acos(cosine) * (180/Math.PI);
} else {
return -Math.acos(cosine) * (180/Math.PI);
}
}
function centerRelativePos(x: real, y: real): point {
var mousePos = overlay.itemContainer.parent.mapFromItem(rotateButton, x, y);
var centerPos = overlay.itemContainer.parent.mapFromItem(overlay.itemContainer, overlay.itemContainer.width/2, overlay.itemContainer.height/2);
mousePos.x -= centerPos.x;
mousePos.y -= centerPos.y;
return mousePos;
}
onPressed: mouse => {
mouse.accepted = true;
startRotation = overlay.itemContainer.rotation;
startCenterRelativeAngle = pointAngle(centerRelativePos(mouse.x, mouse.y));
}
onPositionChanged: mouse => {
var rot = startRotation % 360;
var snap = 4;
var newRotation = Math.round(pointAngle(centerRelativePos(mouse.x, mouse.y)) - startCenterRelativeAngle + startRotation);
if (newRotation < 0) {
newRotation = newRotation + 360;
} else if (newRotation >= 360) {
newRotation = newRotation % 360;
}
snapIt(0);
snapIt(90);
snapIt(180);
snapIt(270);
function snapIt(snapTo) {
if (newRotation > (snapTo - snap) && newRotation < (snapTo + snap)) {
newRotation = snapTo;
}
}
overlay.itemContainer.rotation = newRotation;
}
onReleased: mouse => {
// save rotation
appletsLayout.save();
}
}
}
ActionButton {
icon.name: "configure"
visible: qAction && qAction.enabled && (applet && applet.plasmoid.hasConfigurationInterface)
qAction: applet ? applet.plasmoid.internalAction("configure") : null
Component.onCompleted: {
if (qAction) {
qAction.enabled = true;
}
}
}
ActionButton {
// FIXME: missing from Breeze icons! See
// https://bugs.kde.org/show_bug.cgi?id=472863.
icon.name: "showbackground"
toolTip: checked ? i18n("Hide Background") : i18n("Show Background")
visible: (applet.plasmoid.backgroundHints & PlasmaCore.Types.ConfigurableBackground)
checked: applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.StandardBackground || applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.TranslucentBackground
checkable: true
onClicked: {
if (checked) {
if (applet.plasmoid.backgroundHints & PlasmaCore.Types.StandardBackground || applet.plasmoid.backgroundHints & PlasmaCore.Types.TranslucentBackground) {
applet.plasmoid.userBackgroundHints = applet.plasmoid.backgroundHints;
} else {
applet.plasmoid.userBackgroundHints = PlasmaCore.Types.StandardBackground;
}
} else {
if (applet.plasmoid.backgroundHints & PlasmaCore.Types.ShadowBackground || applet.plasmoid.backgroundHints & PlasmaCore.Types.NoBackground) {
applet.plasmoid.userBackgroundHints = applet.plasmoid.backgroundHints;
} else {
applet.plasmoid.userBackgroundHints = PlasmaCore.Types.ShadowBackground;
}
}
}
}
MouseArea {
drag.target: overlay.itemContainer
Layout.minimumHeight: Kirigami.Units.iconSizes.small * 3
Layout.fillHeight: true
Layout.fillWidth: true
cursorShape: containsPress ? Qt.DragMoveCursor : Qt.OpenHandCursor
hoverEnabled: true
onPressed: mouse => {
appletsLayout.releaseSpace(overlay.itemContainer);
}
onPositionChanged: mouse => {
if (!pressed) {
return;
}
appletsLayout.showPlaceHolderForItem(overlay.itemContainer);
var dragPos = mapToItem(overlay.itemContainer, mouse.x, mouse.y);
overlay.itemContainer.userDrag(Qt.point(overlay.itemContainer.x, overlay.itemContainer.y), dragPos);
}
onReleased: mouse => {
appletsLayout.hidePlaceHolder();
appletsLayout.positionItem(overlay.itemContainer);
}
}
ActionButton {
id: closeButton
icon.name: "edit-delete-remove"
toolTip: i18n("Remove")
visible: {
if (!applet) {
return false;
}
var a = applet.plasmoid.internalAction("remove");
return a && a.enabled || false;
}
// we don't set action, since we want to catch the button click,
// animate, and then trigger the "remove" action
// Triggering the action is handled in the overlay.itemContainer, we just
// Q_EMIT a signal here to avoid the applet-gets-removed-before-we-
// can-animate it race condition.
onClicked: {
removeAnim.restart();
}
Component.onCompleted: {
var a = applet.plasmoid.internalAction("remove");
if (a) {
a.enabled = true;
}
}
}
}
}
}

View file

@ -0,0 +1,79 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
KSvg.SvgItem {
id: actionButton
width: {
if (!visible) {
return 0;
}
switch (Plasmoid.configuration.iconSize) {
case 0: return Kirigami.Units.iconSizes.small;
case 1: return Kirigami.Units.iconSizes.small;
case 2: return Kirigami.Units.iconSizes.smallMedium;
case 3: return Kirigami.Units.iconSizes.smallMedium;
case 4: return Kirigami.Units.iconSizes.smallMedium;
case 5: return Kirigami.Units.iconSizes.medium;
case 6: return Kirigami.Units.iconSizes.large;
default: return Kirigami.Units.iconSizes.small;
}
}
height: width
signal clicked()
property string element
svg: KSvg.Svg {
imagePath: "widgets/action-overlays"
multipleImages: true
size: "16x16"
}
elementId: element + "-normal"
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration }
}
MouseArea {
id: actionButtonMouseArea
anchors.fill: actionButton
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: mouse => actionButton.clicked()
states: [
State {
name: "hover"
when: actionButtonMouseArea.containsMouse && !actionButtonMouseArea.pressed
PropertyChanges {
target: actionButton
elementId: actionButton.element + "-hover"
}
},
State {
name: "pressed"
when: actionButtonMouseArea.pressed
PropertyChanges {
target: actionButton
elementId: actionButton.element + "-pressed"
}
}
]
}
}

View file

@ -0,0 +1,517 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Window 2.15
import Qt5Compat.GraphicalEffects
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras as PlasmaExtras
import org.kde.plasma.components as PlasmaComponents
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.kquickcontrolsaddons 2.0
Item {
id: main
property int index: model.index
property string name: model.blank ? "" : model.display
property string nameWrapped: model.blank ? "" : model.displayWrapped
property bool blank: model.blank
property bool isDir: loader.item ? loader.item.isDir : false
property QtObject popupDialog: loader.item ? loader.item.popupDialog : null
property Item iconArea: loader.item ? loader.item.iconArea : null
property Item label: loader.item ? loader.item.label : null
property Item labelArea: loader.item ? loader.item.labelArea : null
property Item actionsOverlay: loader.item ? loader.item.actionsOverlay : null
property Item hoverArea: loader.item ? loader.item.hoverArea : null
property Item frame: loader.item ? loader.item.frame : null
property Item toolTip: loader.item ? loader.item.toolTip : null
Accessible.name: name
Accessible.role: Accessible.Canvas
// This MouseArea exists to intercept press and hold; preventing edit mode
// from being triggered when pressing and holding on an icon (if there is one).
MouseArea {
anchors.fill: parent
visible: !main.blank
}
function openPopup() {
if (isDir) {
loader.item.openPopup();
}
}
function closePopup() {
if (popupDialog) {
popupDialog.requestDestroy();
loader.item.popupDialog = null;
}
}
Loader {
id: loader
// On the desktop we pad our cellSize to avoid a gap at the right/bottom of the screen.
// The padding per item is quite small and causes the delegate to be positioned on fractional pixels
// leading to blurry rendering. The Loader is offset to account for this.
x: -main.x % 1
y: -main.y % 1
width: parent.width
height: parent.height
visible: status === Loader.Ready
active: !model.blank
sourceComponent: delegateImplementation
asynchronous: true
}
Component {
id: delegateImplementation
Item {
id: impl
anchors.fill: parent
property bool blank: model.blank
property bool selected: model.blank ? false : model.selected
property bool isDir: model.blank ? false : model.isDir
property bool hovered: (main.GridView.view.hoveredItem === main)
property QtObject popupDialog: null
property Item iconArea: icon
property Item label: label
property Item labelArea: label
property Item actionsOverlay: actions
property Item hoverArea: toolTip
property Item frame: frameLoader
property Item toolTip: toolTip
property Item selectionButton: null
property Item popupButton: null
readonly property bool iconAndLabelsShouldlookSelected: impl.hovered
// When a drop happens, a new item is created, and is set to selected
// grabToImagebefore it gets the final width, making grabToImage fail because it's still 0x0
onSelectedChanged: Qt.callLater(updateDragImage)
function updateDragImage() {
if (selected && !blank) {
frameLoader.grabToImage(result => {
dir.addItemDragImage(positioner.map(index), main.x + frameLoader.x, main.y + frameLoader.y, frameLoader.width, frameLoader.height, result.image);
});
}
}
Connections {
target: model
function onSelectedChanged() {
if (dir.usedByContainment && model.selected) {
gridView.currentIndex = model.index;
}
}
}
onHoveredChanged: {
if (hovered) {
// In list view, it behaves more like a menu, and menus always activate their items on a single click
if (Plasmoid.configuration.selectionMarkers && (Qt.styleHints.singleClickActivation || root.useListViewMode)) {
selectionButton = selectionButtonComponent.createObject(actions);
}
if (model.isDir) {
if (!main.GridView.view.isRootView || root.containsDrag) {
hoverActivateTimer.restart();
}
if (Plasmoid.configuration.popups && !root.useListViewMode) {
popupButton = popupButtonComponent.createObject(actions);
}
}
} else if (!hovered) {
if (popupDialog != null) {
closePopup();
}
if (selectionButton) {
selectionButton.destroy();
selectionButton = null;
}
if (popupButton) {
popupButton.destroy();
popupButton = null;
}
}
}
function openPopup() {
if (folderViewDialogComponent.status === Component.Ready) {
impl.popupDialog = folderViewDialogComponent.createObject(impl);
impl.popupDialog.visualParent = icon;
impl.popupDialog.url = model.linkDestinationUrl;
impl.popupDialog.visible = true;
}
}
PlasmaCore.ToolTipArea {
id: toolTip
active: (Plasmoid.configuration.toolTips || label.truncated)
&& popupDialog === null
&& !model.blank
interactive: false
location: root.useListViewMode ? (Plasmoid.location === PlasmaCore.Types.LeftEdge ? PlasmaCore.Types.LeftEdge : PlasmaCore.Types.RightEdge) : Plasmoid.location
z: 999
//anchors.fill: parent
MouseArea {
id: ma
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onPositionChanged: (mouse) => {
if (containsMouse && !model.blank) {
if (toolTip.active) {
toolTip.textFormat = Text.RichText;
toolTip.mainText = model.display;
if (model.size !== undefined) {
toolTip.subText = model.type + "<br>" + "Size: " + model.size;
} else {
toolTip.subText = model.type;
}
}
main.GridView.view.hoveredItem = main;
}
mouse.accepted = false;
}
}
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: toolTip
anchors.horizontalCenter: parent.horizontalCenter
}
PropertyChanges {
target: toolTip
x: Kirigami.Units.smallSpacing
y: Kirigami.Units.smallSpacing
width: parent.width - Kirigami.Units.smallSpacing
height: parent.height - Kirigami.Units.smallSpacing
//width: Math.max(icon.paintedWidth, label.paintedWidth)
//height: (label.y + label.paintedHeight)
//y: frameLoader.y + icon.y
//width: Math.max(icon.paintedWidth, label.paintedWidth)
//height: (label.y + label.paintedHeight) - y
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: toolTip
anchors.horizontalCenter: undefined
}
PropertyChanges {
target: toolTip
x: frameLoader.x
y: frameLoader.y
width: frameLoader.width
height: frameLoader.height
}
}
]
}
Loader {
id: frameLoader
x: 0//root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
y: root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
property Item iconShadow: null
property string prefix: ""
sourceComponent: frameComponent
active: impl.iconAndLabelsShouldlookSelected || model.selected
asynchronous: true
width: {
if (root.useListViewMode) {
if (main.GridView.view.overflowing) {
return parent.width// - Kirigami.Units.smallSpacing;
} else {
return parent.width;
}
}
return parent.width// - (Kirigami.Units.smallSpacing * 2);
}
height: root.useListViewMode
? parent.height
// the smallSpacings are for padding
: icon.height + (Kirigami.Units.iconSizes.small * label.lineCount) + (Kirigami.Units.smallSpacing * 3)
Kirigami.Icon {
id: icon
z: 2
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: icon
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: icon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
}
]
anchors {
topMargin: Kirigami.Units.smallSpacing
leftMargin: Kirigami.Units.smallSpacing
}
width: root.useListViewMode ? main.GridView.view.iconSize : (parent.width - 2 * Kirigami.Units.smallSpacing)
height: main.GridView.view.iconSize
opacity: {
if (root.useListViewMode && selectionButton) {
return 0.3;
}
if (model.isHidden) {
return 0.6;
}
return 1.0;
}
animated: false
source: model.decoration
}
PlasmaComponents.Label {
id: label
z: 2 // So it's always above the highlight effect
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: label
anchors.top: icon.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
PropertyChanges {
target: label
anchors.topMargin: Kirigami.Units.smallSpacing
width: parent.width - Kirigami.Units.smallSpacing
maximumLineCount: Plasmoid.configuration.textLines
horizontalAlignment: Text.AlignHCenter
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: label
anchors.left: icon.right
anchors.verticalCenter: parent.verticalCenter
}
PropertyChanges {
target: label
anchors.leftMargin: Kirigami.Units.smallSpacing * 2
anchors.rightMargin: Kirigami.Units.smallSpacing * 2
width: parent.width - icon.width - (Kirigami.Units.smallSpacing * 4)
maximumLineCount: 1
horizontalAlignment: Text.AlignLeft
}
}
]
color: {
if (Plasmoid.isContainment) {
// In this situation there's a shadow or a background rect, both of which are always black
return "white";
}
if (model.selected) {
return Kirigami.Theme.highlightedTextColor;
}
return Kirigami.Theme.textColor;
}
//renderShadow: false //(Plasmoid.isContainment && (!editor || editor.targetItem !== main)) && Plasmoid.configuration.textShadows
opacity: model.isHidden ? 0.6 : 1
text: main.nameWrapped
elide: Text.ElideRight
//font.italic: model.isLink
wrapMode: (maximumLineCount === 1) ? Text.NoWrap : Text.Wrap
horizontalAlignment: Text.AlignHCenter
layer.enabled: true
layer.effect: DropShadow {
anchors.fill: label
z: 1
horizontalOffset: 1
verticalOffset: 1
radius: 3.0
samples: radius * 2
spread: 0.435
color: "#F9080808"
opacity: model.isHidden ? 0.6 : 1
source: label
visible: (Plasmoid.isContainment && (!editor || editor.targetItem !== main)) && Plasmoid.configuration.textShadows
}
}
Component {
id: frameComponent
PlasmaExtras.Highlight {
// Workaround for a bug where the frameComponent does not
// get unloaded when items are dragged to a different
// place on the desktop.
visible: this === frameLoader.item
hovered: impl.iconAndLabelsShouldlookSelected
pressed: model.selected
active: Window.active
}
}
Component {
id: selectionButtonComponent
FolderItemActionButton {
element: model.selected ? "remove" : "add"
onClicked: {
dir.toggleSelected(positioner.map(index));
main.GridView.view.currentIndex = index;
}
}
}
Component {
id: popupButtonComponent
FolderItemActionButton {
visible: main.GridView.view.isRootView && (popupDialog == null)
element: "open"
onClicked: {
dir.setSelected(positioner.map(index));
main.GridView.view.currentIndex = index;
openPopup();
}
}
}
Component {
id: iconShadowComponent
DropShadow {
anchors.fill: icon
z: 1
verticalOffset: 1
radius: 5.0
samples: radius * 2 + 1
spread: 0.05
color: "black"
opacity: model.isHidden ? 0.3 : 0.6
visible: Plasmoid.configuration.iconShadows
source: icon
}
}
}
Column {
id: actions
visible: {
if (main.GridView.view.isRootView && root.containsDrag) {
return false;
}
if (!main.GridView.view.isRootView && main.GridView.view.dialog && main.GridView.view.dialog.containsDrag) {
return false;
}
if (popupDialog) {
return false;
}
return true;
}
anchors {
left: frameLoader.left
top: frameLoader.top
leftMargin: root.useListViewMode ? (icon.x + (icon.width / 2)) - (width / 2) : 0
topMargin: root.useListViewMode ? (icon.y + (icon.height / 2)) - (height / 2) : 0
}
width: implicitWidth
height: implicitHeight
}
Component.onCompleted: {
if (Plasmoid.isContainment && main.GridView.view.isRootView && root.GraphicsInfo.api === GraphicsInfo.OpenGL) {
frameLoader.iconShadow = iconShadowComponent.createObject(frameLoader);
}
}
}
}
}

View file

@ -0,0 +1,52 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.private.desktopcontainment.folder 0.1 as Folder
import org.kde.kirigami 2.20 as Kirigami
Kirigami.OverlaySheet {
id: dialog
required property var previewPlugins
title: i18n("Preview Plugins")
onClosed: destroy()
footer: DialogButtonBox {
standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
onAccepted: {
configIcons.cfg_previewPlugins = previewPluginsModel.checkedPlugins;
dialog.close();
}
onRejected: dialog.close();
}
ListView {
implicitWidth: Kirigami.Units.iconSizes.small * 15
model: Folder.PreviewPluginsModel {
id: previewPluginsModel
}
delegate: CheckDelegate {
width: ListView.view.width
text: model.display
checked: model.checked
onToggled: model.checked = checked;
}
}
Component.onCompleted: {
previewPluginsModel.checkedPlugins = dialog.previewPlugins;
open();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,115 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import org.kde.private.desktopcontainment.folder 0.1 as Folder
Folder.SubDialog {
id: dialog
visible: false
property bool containsDrag: {
if (folderViewDropArea.containsDrag) {
return true;
}
if (folderView.hoveredItem && folderView.hoveredItem.popupDialog) {
return folderView.hoveredItem.popupDialog.containsDrag;
}
return false;
}
property QtObject closeTimer: closeTimer
property QtObject childDialog: (folderView.hoveredItem !== null) ? folderView.hoveredItem.popupDialog : null
property bool containsMouse: folderView.containsMouse || (childDialog !== null && childDialog.containsMouse)
property alias url: folderView.url
location: PlasmaCore.Types.Floating
hideOnWindowDeactivate: (childDialog === null)
onContainsMouseChanged: {
if (containsMouse) {
closeTimer.stop();
} else {
closeTimer.start();
}
}
mainItem: FolderViewDropArea {
id: folderViewDropArea
width: folderView.cellWidth * 3 + Kirigami.Units.iconSizes.small // FIXME HACK: Use actual scrollbar width.
height: folderView.cellHeight * 2
folderView: folderView
FolderView {
id: folderView
anchors.fill: parent
isRootView: false
dialog: dialog
locked: true
sortMode: ((Plasmoid.configuration.sortMode === 0) ? 1 : Plasmoid.configuration.sortMode)
filterMode: 0
// TODO: Bidi.
flow: GridView.FlowLeftToRight
layoutDirection: Qt.LeftToRight
onDragInProgressAnywhereChanged: {
if (!dragInProgressAnywhere && !dialog.visible) {
dialog.destroy();
}
}
}
}
data: [
Timer {
id: closeTimer
interval: Kirigami.Units.longDuration * 2
onTriggered: {
if (childDialog !== null) {
childDialog.closeTimer.stop();
childDialog.visible = false;
}
dialog.visible = false;
delayedDestroy();
}
}
]
function requestDestroy() {
if (folderView.dragInProgressAnywhere) {
visible = false;
} else {
destroy();
}
}
function delayedDestroy() {
Qt.callLater(() => itemDialog.destroy());
}
Component.onDestruction: {
closeTimer.stop();
}
}

View file

@ -0,0 +1,60 @@
/*
SPDX-FileCopyrightText: 2014-2017 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.4
import org.kde.draganddrop 2.0 as DragDrop
import org.kde.kirigami 2.20 as Kirigami
DragDrop.DropArea {
id: dropArea
property Item folderView: null
function handleDragMove(folderView, pos) {
// Trigger autoscroll.
folderView.scrollLeft = (pos.x < (Kirigami.Units.iconSizes.small * 3));
folderView.scrollRight = (pos.x > width - (Kirigami.Units.iconSizes.small * 3));
folderView.scrollUp = (pos.y < (Kirigami.Units.iconSizes.small * 3));
folderView.scrollDown = (pos.y > height - (Kirigami.Units.iconSizes.small * 3));
folderView.handleDragMove(pos.x, pos.y);
}
function handleDragEnd(folderView) {
// Cancel autoscroll.
folderView.scrollLeft = false;
folderView.scrollRight = false;
folderView.scrollUp = false;
folderView.scrollDown = false;
folderView.endDragMove();
}
onDragMove: event => {
// TODO: We should reject drag moves onto file items that don't accept drops
// (cf. QAbstractItemModel::flags() here, but DeclarativeDropArea currently
// is currently incapable of rejecting drag events.
if (folderView) {
handleDragMove(folderView, mapToItem(folderView, event.x, event.y));
}
}
onDragLeave: event => {
if (folderView) {
handleDragEnd(folderView);
}
}
onDrop: event => {
if (folderView) {
handleDragEnd(folderView);
folderView.drop(folderView, event, mapToItem(folderView, event.x, event.y));
}
}
}

View file

@ -0,0 +1,429 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQml 2.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.config // for KAuthorized
import org.kde.kirigami 2.20 as Kirigami
import org.kde.private.desktopcontainment.folder 0.1 as Folder
FocusScope {
id: folderViewLayerComponent
property var sharedActions: ["newMenu", "paste", "undo", "emptyTrash"]
property Component folderViewDialogComponent: Qt.createComponent("FolderViewDialog.qml", Qt.Asynchronous, root)
property Item view: folderView
property Item label: null
property int labelHeight: Kirigami.Units.iconSizes.sizeForLabels
+ (root.isPopup ? (Kirigami.Units.smallSpacing * 2) : 0)
property alias model: folderView.model
property alias overflowing: folderView.overflowing
property alias flow: folderView.flow
property string resolution: Math.round(root.screenGeometry.width) + "x" + Math.round(root.screenGeometry.height)
readonly property bool lockedByKiosk: !KAuthorized.authorize("editable_desktop_icons")
focus: true
function updateContextualActions() {
folderView.model.updateActions();
for (let i = 0, len = sharedActions.length; i < len; i++) {
const actionName = sharedActions[i];
const appletAction = Plasmoid.internalAction(actionName);
if (appletAction) {
modelAction = folderView.model.action(actionName);
appletAction.text = modelAction.text;
appletAction.enabled = modelAction.enabled;
appletAction.visible = modelAction.visible;
}
}
}
function cancelRename() {
folderView.cancelRename();
}
function goHome() {
if (folderView.url !== Plasmoid.configuration.url) {
folderView.url = Qt.binding(() => Plasmoid.configuration.url);
folderView.history = [];
folderView.updateHistory();
}
}
Binding {
target: Plasmoid
property: "title"
value: labelGenerator.displayLabel
restoreMode: Binding.RestoreBinding
}
Folder.LabelGenerator {
id: labelGenerator
folderModel: folderView.model
rtl: (Qt.application.layoutDirection === Qt.RightToLeft)
labelMode: Plasmoid.configuration.labelMode || (isContainment ? 0 : 1)
labelText: Plasmoid.configuration.labelText
}
Folder.ViewPropertiesMenu {
id: viewPropertiesMenu
showLayoutActions: !isPopup
showLockAction: isContainment
showIconSizeActions: !root.useListViewMode
lockedEnabled: !lockedByKiosk
onArrangementChanged: {
Plasmoid.configuration.arrangement = arrangement;
}
onAlignmentChanged: {
Plasmoid.configuration.alignment = alignment;
}
onPreviewsChanged: {
Plasmoid.configuration.previews = previews;
}
onLockedChanged: {
if (!lockedByKiosk) {
Plasmoid.configuration.locked = locked;
}
}
onSortModeChanged: {
Plasmoid.configuration.sortMode = sortMode;
}
onSortDescChanged: {
Plasmoid.configuration.sortDesc = sortDesc;
}
onSortDirsFirstChanged: {
Plasmoid.configuration.sortDirsFirst = sortDirsFirst;
}
onIconSizeChanged: {
Plasmoid.configuration.iconSize = iconSize;
}
Component.onCompleted: {
arrangement = Plasmoid.configuration.arrangement;
alignment = Plasmoid.configuration.alignment;
previews = Plasmoid.configuration.previews;
locked = Plasmoid.configuration.locked || lockedByKiosk;
sortMode = Plasmoid.configuration.sortMode;
sortDesc = Plasmoid.configuration.sortDesc;
sortDirsFirst = Plasmoid.configuration.sortDirsFirst;
iconSize = Plasmoid.configuration.iconSize;
}
}
PlasmaComponents.Label {
anchors.fill: parent
text: folderView.errorString
textFormat: Text.PlainText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
}
Connections {
target: root
function onExpandedChanged() {
if (root.isPopup) {
if (root.expanded) {
folderView.currentIndex = -1;
folderView.forceActiveFocus();
folderView.positionViewAtBeginning();
} else {
goHome();
folderView.currentIndex = -1;
folderView.model.clearSelection();
folderView.cancelRename();
}
}
}
}
function getPositions() {
let allPositions;
try {
allPositions = JSON.parse(Plasmoid.configuration.positions);
} catch (err) {
allPositions = {};
allPositions[resolution] = Plasmoid.configuration.positions;
}
return allPositions[resolution] || "";
}
function savePositions(positions) {
let allPositions;
try {
allPositions = JSON.parse(Plasmoid.configuration.positions);
} catch (err) {
allPositions = {};
}
allPositions[resolution] = positions;
Plasmoid.configuration.positions = JSON.stringify(allPositions, Object.keys(allPositions).sort());
}
Connections {
target: Plasmoid.configuration
function onArrangementChanged() {
viewPropertiesMenu.arrangement = Plasmoid.configuration.arrangement;
}
function onAlignmentChanged() {
viewPropertiesMenu.alignment = Plasmoid.configuration.alignment;
}
function onLockedChanged() {
viewPropertiesMenu.locked = Plasmoid.configuration.locked;
}
function onSortModeChanged() {
folderView.sortMode = Plasmoid.configuration.sortMode;
viewPropertiesMenu.sortMode = Plasmoid.configuration.sortMode;
}
function onSortDescChanged() {
viewPropertiesMenu.sortDesc = Plasmoid.configuration.sortDesc;
}
function onSortDirsFirstChanged() {
viewPropertiesMenu.sortDirsFirst = Plasmoid.configuration.sortDirsFirst;
}
function onIconSizeChanged() {
viewPropertiesMenu.iconSize = Plasmoid.configuration.iconSize;
}
function onPositionsChanged() {
folderView.positions = getPositions();
}
}
FolderView {
id: folderView
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: folderViewLayerComponent.label !== null ? folderViewLayerComponent.label.height : 0
anchors.right: parent.right
anchors.bottom: parent.bottom
focus: true
isRootView: true
url: Plasmoid.configuration.url
locked: (Plasmoid.configuration.locked || !isContainment || lockedByKiosk)
filterMode: Plasmoid.configuration.filterMode
filterPattern: Plasmoid.configuration.filterPattern
filterMimeTypes: Plasmoid.configuration.filterMimeTypes
showHiddenFiles: Plasmoid.configuration.showHiddenFiles
flow: (Plasmoid.configuration.arrangement === 0) ? GridView.FlowLeftToRight : GridView.FlowTopToBottom
layoutDirection: (Plasmoid.configuration.alignment === 0) ? Qt.LeftToRight : Qt.RightToLeft
onSortModeChanged: {
Plasmoid.configuration.sortMode = sortMode;
}
onPositionsChanged: {
saveTimer.restart()
}
onPerStripeChanged: {
folderView.positions = getPositions();
}
Timer {
id: saveTimer
interval: Kirigami.Units.humanMoment
onTriggered: savePositions(folderView.positions)
}
Component.onCompleted: {
folderView.sortMode = Plasmoid.configuration.sortMode;
folderView.positions = getPositions();
}
}
Component {
id: labelComponent
Item {
id: label
// If we bind height to visible, it will be invisible initially (since "visible"
// propagates recursively) and that confuses the Label, hence the temp property.
readonly property bool active: (Plasmoid.configuration.labelMode !== 0)
readonly property bool showPin: root.isPopup && root.compactRepresentationItem && root.compactRepresentationItem.visible
width: parent.width
height: active ? labelHeight : 0
visible: active
property Item windowPin: null
property Item homeButton: null
onVisibleChanged: {
if (root.isPopup && !visible) {
root.hideOnWindowDeactivate = true;
}
}
onShowPinChanged: {
if (!windowPin && showPin) {
windowPin = windowPinComponent.createObject(label);
} else if (windowPin) {
windowPin.destroy();
windowPin = null;
}
}
Connections {
target: folderView
function onUrlChanged() {
if (!label.homeButton && folderView.url !== Plasmoid.configuration.url) {
label.homeButton = homeButtonComponent.createObject(label);
} else if (label.homeButton && folderView.url === Plasmoid.configuration.url) {
label.homeButton.destroy();
}
}
}
PlasmaComponents.Label {
id: text
anchors {
left: label.homeButton ? label.homeButton.right : parent.left
right: label.windowPin ? label.windowPin.left : parent.right
margins: Kirigami.Units.smallSpacing
}
height: parent.height
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
elide: Text.ElideMiddle
text: labelGenerator.displayLabel
textFormat: Text.PlainText
font.underline: labelMouseArea.containsMouse
}
MouseArea {
id: labelMouseArea
anchors {
top: text.top
horizontalCenter: text.horizontalCenter
}
width: text.contentWidth
height: text.contentHeight
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Folder.AppLauncher.openUrl(folderView.url)
}
}
Component {
id: windowPinComponent
PlasmaComponents.ToolButton {
id: windowPin
anchors.right: parent.right
visible: label.showPin
width: root.isPopup ? Math.round(Kirigami.Units.iconSizes.small * 1.25) : 0
height: width
checkable: true
icon.name: "window-pin"
onCheckedChanged: root.hideOnWindowDeactivate = !checked
}
}
Component {
id: homeButtonComponent
PlasmaComponents.ToolButton {
id: homeButton
anchors.left: parent.left
visible: root.isPopup && folderView.url !== Plasmoid.configuration.url
width: root.isPopup ? Math.round(Kirigami.Units.iconSizes.small * 1.25) : 0
height: width
icon.name: "go-home"
onClicked: goHome()
}
}
Component.onCompleted: {
if (root.showPin) {
windowPin = windowPinComponent.createObject(label);
}
}
}
}
PlasmaCore.Action {
id: viewPropertiesAction
text: i18n("Icons")
icon.name: "view-list-icons"
menu: viewPropertiesMenu.menu
}
PlasmaCore.Action {
id: actionSeparator
isSeparator: true
}
Component.onCompleted: {
if (!isContainment) {
label = labelComponent.createObject(folderViewLayerComponent);
}
for (let i = 0, len = sharedActions.length; i < len; i++) {
const actionName = sharedActions[i];
const modelAction = folderView.model.action(actionName);
Plasmoid.contextualActions.push(modelAction)
if (actionName === "newMenu") {
Plasmoid.contextualActions.push(viewPropertiesAction)
}
}
Plasmoid.contextualActions.push(actionSeparator);
Plasmoid.contextualActionsAboutToShow.connect(updateContextualActions);
Plasmoid.contextualActionsAboutToShow.connect(folderView.model.clearSelection);
}
}

View file

@ -0,0 +1,201 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kirigami 2.20 as Kirigami
PlasmaComponents.ScrollView {
id: root
property alias text: editor.text
property alias targetItem: editor.targetItem
signal commit
onFocusChanged: {
if (focus) {
editor.forceActiveFocus();
}
}
PlasmaComponents.TextArea {
id: editor
wrapMode: root.useListViewMode ? TextEdit.NoWrap : TextEdit.Wrap
textMargin: 0
//leftPadding:
horizontalAlignment: root.useListViewMode ? TextEdit.AlignLeft : TextEdit.AlignHCenter
rightPadding: root.PlasmaComponents.ScrollBar.vertical.visible ? root.PlasmaComponents.ScrollBar.vertical.width : Kirigami.Units.smallSpacing
property Item targetItem: null
Binding {
target: editor.background
property: "width"
value: root.width
}
Binding {
target: editor.background
property: "height"
value: root.height
}
Component.onCompleted: root.contentItem.clip = false
onTargetItemChanged: {
if (targetItem !== null) {
var xy = getXY();
root.x = xy[0];
root.y = xy[1];
root.width = getWidth();
root.height = getInitHeight();
text = targetItem.name;
adjustSize();
editor.select(0, dir.fileExtensionBoundary(positioner.map(targetItem.index)));
if (isPopup) {
root.contentItem.contentX = Math.max(root.contentItem.contentWidth - contentItem.width, 0);
} else {
root.contentItem.contentY = Math.max(root.contentItem.contentHeight - contentItem.height, 0);
}
root.visible = true;
} else {
root.x = 0;
root.y = 0;
root.visible = false;
}
}
Keys.onPressed: event => {
switch(event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
root.commit();
break;
case Qt.Key_Escape:
if (targetItem) {
targetItem = null;
event.accepted = true;
}
break;
case Qt.Key_Home:
if (event.modifiers & Qt.ShiftModifier) {
editor.select(0, cursorPosition);
} else {
editor.select(0, 0);
}
event.accepted = true;
break;
case Qt.Key_End:
if (event.modifiers & Qt.ShiftModifier) {
editor.select(cursorPosition, text.length);
} else {
editor.select(text.length, text.length);
}
event.accepted = true;
break;
default:
adjustSize();
break;
}
}
Keys.onReleased: event => {
adjustSize();
}
function getXY() {
if (!targetItem) {
return [0,0];
}
var pos = main.mapFromItem(targetItem, targetItem.labelArea.x, targetItem.labelArea.y);
var _x, _y;
if (root.useListViewMode) {
_x = targetItem.labelArea.x - editor.leftPadding;
_y = pos.y - editor.topPadding;
} else {
_x = targetItem.x + Math.abs(Math.min(gridView.contentX, gridView.originX));
_x += editor.leftPadding;
_x += scrollArea.viewport.x;
_x -= Kirigami.Units.smallSpacing*2;
if (root.PlasmaComponents.ScrollBar.vertical.policy === Qt.ScrollBarAlwaysOn
&& gridView.effectiveLayoutDirection === Qt.RightToLeft) {
_x -= root.PlasmaComponents.ScrollBar.vertical.width;
}
_y = pos.y + Kirigami.Units.smallSpacing - editor.topPadding;
}
return [ _x, _y ];
}
function getWidth(addWidthVerticalScroller) {
if (!targetItem) {
return 0;
}
return(targetItem.label.parent.width + Kirigami.Units.smallSpacing +
(root.useListViewMode ? -(editor.leftPadding + editor.rightPadding + Kirigami.Units.smallSpacing) : 0) +
(addWidthVerticalScroller ? root.PlasmaComponents.ScrollBar.vertical.width : 0));
}
function getHeight(addWidthHoriozontalScroller, init) {
if (!targetItem) {
return 0;
}
var _height;
if (isPopup || init) {
_height = targetItem.labelArea.height + editor.topPadding + editor.bottomPadding;
} else {
var realHeight = contentHeight + editor.topPadding + editor.bottomPadding;
var maxHeight = Kirigami.Units.iconSizes.sizeForLabels * (Plasmoid.configuration.textLines + 1) + editor.topPadding + editor.bottomPadding;
_height = Math.min(realHeight, maxHeight);
}
return _height + (addWidthHoriozontalScroller ? root.PlasmaComponents.ScrollBar.horizontal.height : 0);
}
function getInitHeight() {
return getHeight(false, true);
}
function adjustSize() {
if (isPopup) {
if(contentWidth + editor.leftPadding + editor.rightPadding > root.width) {
root.visible = targetItem !== null;
root.PlasmaComponents.ScrollBar.horizontal.policy = Qt.ScrollBarAlwaysOn;
root.height = getHeight(true);
} else {
root.PlasmaComponents.ScrollBar.horizontal.policy = Qt.ScrollBarAlwaysOff;
root.height = getHeight();
}
} else {
root.height = getHeight();
if(contentHeight + editor.topPadding + editor.bottomPadding > root.height) {
root.visible = targetItem !== null;
root.PlasmaComponents.ScrollBar.vertical.policy = Qt.ScrollBarAlwaysOn;
root.width = getWidth(true);
} else {
root.PlasmaComponents.ScrollBar.vertical.policy = Qt.ScrollBarAlwaysOff;
root.width = getWidth();
}
}
var xy = getXY();
root.x = xy[0];
root.y = xy[1];
if(root.PlasmaComponents.ScrollBar.vertical.policy === Qt.ScrollBarAlwaysOn)
root.x -= root.PlasmaComponents.ScrollBar.vertical.width/2;
}
}
}

View file

@ -0,0 +1,69 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
var iconSizes = [Kirigami.Units.iconSizes.smallMedium,
Kirigami.Units.iconSizes.medium,
Kirigami.Units.iconSizes.large,
Kirigami.Units.iconSizes.huge,
Kirigami.Units.iconSizes.large*2,
Kirigami.Units.iconSizes.enormous,
Kirigami.Units.iconSizes.enormous*2];
function iconSizeFromTheme(size) {
return iconSizes[size];
}
function effectiveNavDirection(flow, layoutDirection, direction) {
if (direction == Qt.LeftArrow) {
if (flow == GridView.FlowLeftToRight) {
if (layoutDirection == Qt.LeftToRight) {
return Qt.LeftArrow;
} else {
return Qt.RightArrow;
}
} else {
if (layoutDirection == Qt.LeftToRight) {
return Qt.UpArrow;
} else {
return Qt.DownArrow;
}
}
} else if (direction == Qt.RightArrow) {
if (flow == GridView.FlowLeftToRight) {
if (layoutDirection == Qt.LeftToRight) {
return Qt.RightArrow;
} else {
return Qt.LeftArrow;
}
} else {
if (layoutDirection == Qt.LeftToRight) {
return Qt.DownArrow;
} else {
return Qt.UpArrow;
}
}
} else if (direction == Qt.UpArrow) {
if (flow == GridView.FlowLeftToRight) {
return Qt.UpArrow;
} else {
return Qt.LeftArrow;
}
} else if (direction == Qt.DownArrow) {
if (flow == GridView.FlowLeftToRight) {
return Qt.DownArrow;
} else {
return Qt.RightArrow
}
}
}
function isFileDrag(event) {
var taskUrl = event.mimeData.formats.indexOf("text/x-orgkdeplasmataskmanager_taskurl") != -1;
var arkService = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-service") != -1;
var arkPath = event.mimeData.formats.indexOf("application/x-kde-ark-dndextract-path") != -1;
return (event.mimeData.hasUrls || taskUrl || (arkService && arkPath));
}

View file

@ -0,0 +1,404 @@
/*
SPDX-FileCopyrightText: 2011-2013 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2011-2019 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.ksvg 1.0 as KSvg
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
import org.kde.kirigami 2.20 as Kirigami
import org.kde.private.desktopcontainment.folder 0.1 as Folder
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
import "code/FolderTools.js" as FolderTools
ContainmentItem {
id: root
switchWidth: { switchSize(); }
switchHeight: { switchSize(); }
// Only exists because the default CompactRepresentation doesn't:
// - open on drag
// - allow defining a custom drop handler
// TODO remove once it gains that feature (perhaps optionally?)
compactRepresentation: (isFolder && !isContainment) ? compactRepresentation : null
objectName: isFolder ? "folder" : "desktop"
width: isPopup ? undefined : preferredWidth(false) // Initial size when adding to e.g. desktop.
height: isPopup ? undefined : preferredHeight(false) // Initial size when adding to e.g. desktop.
function switchSize() {
// Support expanding into the full representation on very thick vertical panels.
if (isPopup && Plasmoid.formFactor === PlasmaCore.Types.Vertical) {
return Kirigami.Units.iconSizes.small * 8;
}
return 0;
}
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
property bool isFolder: (Plasmoid.pluginName === "org.kde.plasma.folder")
property bool isContainment: Plasmoid.isContainment
property bool isPopup: (Plasmoid.location !== PlasmaCore.Types.Floating)
property bool useListViewMode: isPopup && Plasmoid.configuration.viewMode === 0
property Component appletAppearanceComponent
property Item toolBox
property int handleDelay: 800
property real haloOpacity: 0.5
property int iconSize: Kirigami.Units.iconSizes.small
property int iconWidth: iconSize
property int iconHeight: iconWidth
readonly property int hoverActivateDelay: 750 // Magic number that matches Dolphin's auto-expand folders delay.
readonly property Loader folderViewLayer: fullRepresentationItem.folderViewLayer
readonly property ContainmentLayoutManager.AppletsLayout appletsLayout: fullRepresentationItem.appletsLayout
// Plasmoid.title is set by a Binding {} in FolderViewLayer
toolTipSubText: ""
Plasmoid.icon: (!Plasmoid.configuration.useCustomIcon && folderViewLayer.ready) ? symbolicizeIconName(folderViewLayer.view.model.iconName) : Plasmoid.configuration.icon
onIconHeightChanged: updateGridSize()
// We want to do this here rather than in the model because we don't always want
// symbolic icons everywhere, but we do know that we always want them in this
// specific representation right here
function symbolicizeIconName(iconName) {
const symbolicSuffix = "-symbolic";
if (iconName.endsWith(symbolicSuffix)) {
return iconName;
}
return iconName + symbolicSuffix;
}
function updateGridSize() {
// onIconHeightChanged can be triggered before this component is complete and all the children are created
if (!toolBoxSvg) {
return;
}
appletsLayout.cellWidth = root.iconWidth + toolBoxSvg.elementSize("left").width + toolBoxSvg.elementSize("right").width;
appletsLayout.cellHeight = root.iconHeight + toolBoxSvg.elementSize("top").height + toolBoxSvg.elementSize("bottom").height;
appletsLayout.defaultItemWidth = appletsLayout.cellWidth * 6;
appletsLayout.defaultItemHeight = appletsLayout.cellHeight * 6;
}
function addLauncher(desktopUrl) {
if (!isFolder) {
return;
}
folderViewLayer.view.linkHere(desktopUrl);
}
function preferredWidth(forMinimumSize: bool): real {
if (isContainment || !folderViewLayer.ready) {
return -1;
} else if (useListViewMode) {
return (forMinimumSize ? folderViewLayer.view.cellHeight * 4 : Kirigami.Units.iconSizes.small * 16);
}
return (folderViewLayer.view.cellWidth * (forMinimumSize ? 1 : 3)) + (Kirigami.Units.iconSizes.small * 2);
}
function preferredHeight(forMinimumSize: bool): real {
let height;
if (isContainment || !folderViewLayer.ready) {
return -1;
} else if (useListViewMode) {
height = (folderViewLayer.view.cellHeight * (forMinimumSize ? 1 : 15)) + Kirigami.Units.smallSpacing;
} else {
height = (folderViewLayer.view.cellHeight * (forMinimumSize ? 1 : 2)) + Kirigami.Units.iconSizes.small;
}
if (Plasmoid.configuration.labelMode !== 0) {
height += folderViewLayer.item.labelHeight;
}
return height;
}
function isDrag(fromX, fromY, toX, toY) {
const length = Math.abs(fromX - toX) + Math.abs(fromY - toY);
return length >= Qt.styleHints.startDragDistance;
}
onFocusChanged: {
if (focus && isFolder) {
folderViewLayer.item.forceActiveFocus();
}
}
onExternalData: (mimetype, data) => {
Plasmoid.configuration.url = data
}
component ShortDropBehavior : Behavior {
NumberAnimation {
duration: Kirigami.Units.shortDuration
easing.type: Easing.InOutQuad
}
}
component LongDropBehavior : Behavior {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
KSvg.FrameSvgItem {
id: highlightItemSvg
visible: false
imagePath: isPopup ? "widgets/viewitem" : ""
prefix: "hover"
}
KSvg.FrameSvgItem {
id: listItemSvg
visible: false
imagePath: isPopup ? "widgets/viewitem" : ""
prefix: "normal"
}
KSvg.Svg {
id: toolBoxSvg
imagePath: "widgets/toolbox"
property int rightBorder: elementSize("right").width
property int topBorder: elementSize("top").height
property int bottomBorder: elementSize("bottom").height
property int leftBorder: elementSize("left").width
}
// FIXME: the use and existence of this property is a workaround
preloadFullRepresentation: true
fullRepresentation: FolderViewDropArea {
id: dropArea
anchors {
fill: parent
leftMargin: (isContainment && root.availableScreenRect) ? root.availableScreenRect.x : 0
topMargin: (isContainment && root.availableScreenRect) ? root.availableScreenRect.y : 0
rightMargin: (isContainment && root.availableScreenRect && parent)
? (parent.width - root.availableScreenRect.x - root.availableScreenRect.width) : 0
bottomMargin: (isContainment && root.availableScreenRect && parent)
? (parent.height - root.availableScreenRect.y - root.availableScreenRect.height) : 0
}
LongDropBehavior on anchors.topMargin { }
LongDropBehavior on anchors.leftMargin { }
LongDropBehavior on anchors.rightMargin { }
LongDropBehavior on anchors.bottomMargin { }
property alias folderViewLayer: folderViewLayer
property alias appletsLayout: appletsLayout
Layout.minimumWidth: preferredWidth(!isPopup)
Layout.minimumHeight: preferredHeight(!isPopup)
Layout.preferredWidth: preferredWidth(false)
Layout.preferredHeight: preferredHeight(false)
// Maximum size is intentionally unbounded
preventStealing: true
onDragEnter: event => {
if (isContainment && Plasmoid.immutable && !(isFolder && FolderTools.isFileDrag(event))) {
event.ignore();
}
// Don't allow any drops while listing.
if (isFolder && folderViewLayer.view.status === Folder.FolderModel.Listing) {
event.ignore();
}
// Firefox tabs are regular drags. Since all of our drop handling is asynchronous
// we would accept this drop and have Firefox not spawn a new window. (Bug 337711)
if (event.mimeData.formats.indexOf("application/x-moz-tabbrowser-tab") !== -1) {
event.ignore();
}
}
onDragMove: event => {
// TODO: We should reject drag moves onto file items that don't accept drops
// (cf. QAbstractItemModel::flags() here, but DeclarativeDropArea currently
// is currently incapable of rejecting drag events.
// Trigger autoscroll.
if (isFolder && FolderTools.isFileDrag(event)) {
handleDragMove(folderViewLayer.view, mapToItem(folderViewLayer.view, event.x, event.y));
} else if (isContainment) {
appletsLayout.showPlaceHolderAt(
Qt.rect(event.x - appletsLayout.minimumItemWidth / 2,
event.y - appletsLayout.minimumItemHeight / 2,
appletsLayout.minimumItemWidth,
appletsLayout.minimumItemHeight)
);
}
}
onDragLeave: event => {
// Cancel autoscroll.
if (isFolder) {
handleDragEnd(folderViewLayer.view);
}
if (isContainment) {
appletsLayout.hidePlaceHolder();
}
}
onDrop: event => {
if (isFolder && FolderTools.isFileDrag(event)) {
handleDragEnd(folderViewLayer.view);
folderViewLayer.view.drop(root, event, mapToItem(folderViewLayer.view, event.x, event.y));
} else if (isContainment) {
root.processMimeData(event.mimeData,
event.x - appletsLayout.placeHolder.width / 2,
event.y - appletsLayout.placeHolder.height / 2);
event.accept(event.proposedAction);
appletsLayout.hidePlaceHolder();
}
}
Component {
id: compactRepresentation
CompactRepresentation { folderView: folderViewLayer.view }
}
Connections {
target: Plasmoid.containment.corona
ignoreUnknownSignals: true
function onEditModeChanged() {
appletsLayout.editMode = Plasmoid.containment.corona.editMode;
}
}
ContainmentLayoutManager.AppletsLayout {
id: appletsLayout
anchors.fill: parent
relayoutLock: width !== root.availableScreenRect.width || height !== root.availableScreenRect.height
// NOTE: use root.availableScreenRect and not own width and height as they are updated not atomically
configKey: "ItemGeometries-" + Math.round(root.screenGeometry.width) + "x" + Math.round(root.screenGeometry.height)
fallbackConfigKey: root.availableScreenRect.width > root.availableScreenRect.height ? "ItemGeometriesHorizontal" : "ItemGeometriesVertical"
containment: Plasmoid
containmentItem: root
editModeCondition: Plasmoid.immutable
? ContainmentLayoutManager.AppletsLayout.Locked
: ContainmentLayoutManager.AppletsLayout.AfterPressAndHold
// Sets the containment in edit mode when we go in edit mode as well
onEditModeChanged: Plasmoid.containment.corona.editMode = editMode;
minimumItemWidth: Kirigami.Units.iconSizes.small * 3
minimumItemHeight: minimumItemWidth
cellWidth: Kirigami.Units.iconSizes.small
cellHeight: cellWidth
eventManagerToFilter: folderViewLayer.item?.view.view ?? null
appletContainerComponent: ContainmentLayoutManager.BasicAppletContainer {
id: appletContainer
editModeCondition: Plasmoid.immutable
? ContainmentLayoutManager.ItemContainer.Locked
: ContainmentLayoutManager.ItemContainer.AfterPressAndHold
configOverlaySource: "ConfigOverlay.qml"
onUserDrag: (newPosition, dragCenter) => {
const pos = mapToItem(root.parent, dragCenter.x, dragCenter.y);
const newCont = root.containmentItemAt(pos.x, pos.y);
if (newCont && newCont.plasmoid !== Plasmoid) {
const newPos = newCont.mapFromApplet(Plasmoid, pos.x, pos.y);
// First go out of applet edit mode, get rid of the config overlay, release mouse grabs in preparation of applet reparenting
cancelEdit();
newCont.Plasmoid.addApplet(appletContainer.applet.plasmoid, Qt.rect(newPos.x, newPos.y, appletContainer.applet.width, appletContainer.applet.height));
appletsLayout.hidePlaceHolder();
}
}
ShortDropBehavior on x { }
ShortDropBehavior on y { }
}
placeHolder: ContainmentLayoutManager.PlaceHolder {}
Loader {
id: folderViewLayer
anchors.fill: parent
property bool ready: status === Loader.Ready
property Item view: item?.view ?? null
property QtObject model: item?.model ?? null
focus: true
active: isFolder
asynchronous: false
source: "FolderViewLayer.qml"
onFocusChanged: {
if (!focus && model) {
model.clearSelection();
}
}
Connections {
target: folderViewLayer.view
// `FolderViewDropArea` is not a FocusScope. We need to forward manually.
function onPressed() {
folderViewLayer.forceActiveFocus();
}
}
}
}
PlasmaCore.Action {
id: configAction
text: i18n("Desktop and Wallpaper")
icon.name: "preferences-desktop-wallpaper"
shortcut: "alt+d,alt+s"
onTriggered: Plasmoid.containment.configureRequested(Plasmoid)
}
Component.onCompleted: {
if (!Plasmoid.isContainment) {
return;
}
Plasmoid.setInternalAction("configure", configAction)
updateGridSize();
}
}
}

View file

@ -0,0 +1,257 @@
{
"KPackageStructure": "Plasma/Applet",
"KPlugin": {
"Authors": [
{
"Email": "sebas@kde.org",
"Name": "Sebastian Kügler",
"Name[ar]": "Sebastian Kügler",
"Name[az]": "Sebastian Kügler",
"Name[be]": "Sebastian Kügler",
"Name[bg]": "Sebastian Kügler",
"Name[ca@valencia]": "Sebastian Kügler",
"Name[ca]": "Sebastian Kügler",
"Name[cs]": "Sebastian Kügler",
"Name[da]": "Sebastian Kügler",
"Name[de]": "Sebastian Kügler",
"Name[en_GB]": "Sebastian Kügler",
"Name[eo]": "Sebastian Kügler",
"Name[es]": "Sebastian Kügler",
"Name[et]": "Sebastian Kügler",
"Name[eu]": "Sebastian Kügler",
"Name[fi]": "Sebastian Kügler",
"Name[fr]": "Sebastian Kügler",
"Name[gl]": "Sebastian Kügler",
"Name[he]": "סבסטיאן קיגלר",
"Name[hu]": "Sebastian Kügler",
"Name[ia]": "Sebastian Kügler",
"Name[id]": "Sebastian Kügler",
"Name[ie]": "Sebastian Kügler",
"Name[is]": "Sebastian Kügler",
"Name[it]": "Sebastian Kügler",
"Name[ja]": "Sebastian Kügler",
"Name[ka]": "სებასტიან კუგლერი",
"Name[ko]": "Sebastian Kügler",
"Name[lt]": "Sebastian Kügler",
"Name[lv]": "Sebastian Kügler",
"Name[nl]": "Sebastian Kügler",
"Name[nn]": "Sebastian Kügler",
"Name[pl]": "Sebastian Kügler",
"Name[pt]": "Sebastian Kügler",
"Name[pt_BR]": "Sebastian Kügler",
"Name[ro]": "Sebastian Kügler",
"Name[ru]": "Sebastian Kügler",
"Name[sk]": "Sebastian Kügler",
"Name[sl]": "Sebastian Kügler",
"Name[sv]": "Sebastian Kügler",
"Name[ta]": "ஸெபாஸ்டியன் கூக்லர்",
"Name[tr]": "Sebastian Kügler",
"Name[uk]": "Sebastian Kügler",
"Name[vi]": "Sebastian Kügler",
"Name[x-test]": "xxSebastian Küglerxx",
"Name[zh_CN]": "Sebastian Kügler",
"Name[zh_TW]": "Sebastian Kügler"
},
{
"Email": "hein@kde.org",
"Name": "Eike Hein",
"Name[ar]": "Eike Hein",
"Name[az]": "Eike Hein",
"Name[be]": "Eike Hein",
"Name[bg]": "Eike Hein",
"Name[ca@valencia]": "Eike Hein",
"Name[ca]": "Eike Hein",
"Name[cs]": "Eike Hein",
"Name[da]": "Eike Hein",
"Name[de]": "Eike Hein",
"Name[en_GB]": "Eike Hein",
"Name[eo]": "Eike Hein",
"Name[es]": "Eike Hein",
"Name[et]": "Eike Hein",
"Name[eu]": "Eike Hein",
"Name[fi]": "Eike Hein",
"Name[fr]": "Eike Hein",
"Name[gl]": "Eike Hein",
"Name[he]": "אייק היין",
"Name[hu]": "Eike Hein",
"Name[ia]": "Eike Hein",
"Name[id]": "Eike Hein",
"Name[ie]": "Eike Hein",
"Name[is]": "Eike Hein",
"Name[it]": "Eike Hein",
"Name[ja]": "Eike Hein",
"Name[ka]": "აიკე ჰაინი",
"Name[ko]": "Eike Hein",
"Name[lt]": "Eike Hein",
"Name[lv]": "Eike Hein",
"Name[nl]": "Eike Hein",
"Name[nn]": "Eike Hein",
"Name[pa]": "ਇਕੀ ਹੀਇਨ",
"Name[pl]": "Eike Hein",
"Name[pt]": "Eike Hein",
"Name[pt_BR]": "Eike Hein",
"Name[ro]": "Eike Hein",
"Name[ru]": "Eike Hein",
"Name[sk]": "Eike Hein",
"Name[sl]": "Eike Hein",
"Name[sv]": "Eike Hein",
"Name[ta]": "எய்கே ஹைன்",
"Name[tr]": "Eike Hein",
"Name[uk]": "Eike Hein",
"Name[vi]": "Eike Hein",
"Name[x-test]": "xxEike Heinxx",
"Name[zh_CN]": "Eike Hein",
"Name[zh_TW]": "Eike Hein"
}
],
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=plasmashell&component=Desktop%20Containment",
"Category": "Containments",
"Description": "A clean and simple layout",
"Description[ar]": "تصميم نظيف وبسيط",
"Description[az]": "Təmiz və Sadə şablon",
"Description[be]": "Просты макет",
"Description[bg]": "Едно изчистено и просто оформление",
"Description[ca@valencia]": "Una disposició neta i senzilla",
"Description[ca]": "Una disposició neta i senzilla",
"Description[cs]": "Čisté a jednoduché rozvržení",
"Description[da]": "Et rent og simpelt layout",
"Description[de]": "Ein klares und einfaches Layout",
"Description[en_GB]": "A clean and simple layout",
"Description[eo]": "Pura kaj simpla aranĝo",
"Description[es]": "Un esquema sencillo y claro",
"Description[et]": "Puhas ja lihtne paigutus",
"Description[eu]": "Antolaera garbi eta xumea",
"Description[fi]": "Selkeä ja yksinkertainen asettelu",
"Description[fr]": "Une disposition simple et épurée",
"Description[gl]": "Unha disposición sinxela e limpa.",
"Description[he]": "פריסה פשוטה ונקיה",
"Description[hu]": "Egy tiszta és egyszerű elrendezés",
"Description[ia]": "Un disposition simple e munde",
"Description[id]": "Sebuah tata letak yang bersih dan sederhana",
"Description[ie]": "Un simplic e nett arangement",
"Description[is]": "Skýr og einföld framsetning",
"Description[it]": "Una disposizione semplice e pulita",
"Description[ja]": "クリーンでシンプルなレイアウト",
"Description[ka]": "სუფთა და მარტივი განლაგება",
"Description[ko]": "깨끗하고 정돈된 레이아웃",
"Description[lt]": "Tvarkingas ir paprastas išdėstymas",
"Description[lv]": "Skaidrs un vienkāršs izkārtojums",
"Description[nl]": "Een schone en simpele opmaak",
"Description[nn]": "Ei enkel og stilrein utforming",
"Description[pa]": "ਸਾਫ਼ ਅਤੇ ਸਧਾਰਨ ਲੇਆਉਟ",
"Description[pl]": "Schludny i prosty układ",
"Description[pt]": "Uma disposição limpa e simples",
"Description[pt_BR]": "Um layout limpo e simples",
"Description[ro]": "Aranjament curat și simplu",
"Description[ru]": "Ясный и простой шаблон",
"Description[sk]": "Čisté a jednoduché rozloženie",
"Description[sl]": "Čist in preprost razpored",
"Description[sv]": "En ren och enkel layout",
"Description[ta]": "தெளிவான மற்றும் எளிய தளவமைப்பு",
"Description[tr]": "Temiz ve basit bir yerleşim",
"Description[uk]": "Просте компонування",
"Description[vi]": "Một bố cục thoáng đãng và đơn giản",
"Description[x-test]": "xxA clean and simple layoutxx",
"Description[zh_CN]": "一款简洁的布局",
"Description[zh_TW]": "乾淨、簡單的佈局",
"EnabledByDefault": true,
"Icon": "user-desktop",
"Id": "org.kde.desktopcontainment",
"License": "GPL-2.0+",
"Name": "Desktop",
"Name[af]": "Werkskerm",
"Name[ar]": "سطح المكتب",
"Name[ast]": "Escritoriu",
"Name[az]": "İş masası",
"Name[be@latin]": "Rabočy stoł",
"Name[be]": "Працоўны стол",
"Name[bg]": "Работен плот",
"Name[bn]": "ডেস্কটপ",
"Name[bn_IN]": "ডেস্কটপ",
"Name[br]": "Gorretaol",
"Name[bs]": "Radna površina",
"Name[ca@valencia]": "Escriptori",
"Name[ca]": "Escriptori",
"Name[cs]": "Pracovní plocha",
"Name[csb]": "Pùlt",
"Name[cy]": "Penbwrdd",
"Name[da]": "Skrivebord",
"Name[de]": "Arbeitsfläche",
"Name[el]": "Επιφάνεια εργασίας",
"Name[en_GB]": "Desktop",
"Name[eo]": "Labortablo",
"Name[es]": "Escritorio",
"Name[et]": "Töölaud",
"Name[eu]": "Mahaigaina",
"Name[fa]": "رومیزی",
"Name[fi]": "Työpöytä",
"Name[fr]": "Bureau",
"Name[fy]": "Buroblêd",
"Name[ga]": "Deasc",
"Name[gl]": "Escritorio",
"Name[gu]": "ડેસ્કટોપ",
"Name[he]": "שולחן עבודה",
"Name[hi]": "डेस्कटॉप",
"Name[hne]": "डेस्कटाप",
"Name[hr]": "Radna površina",
"Name[hsb]": "Dźěłowy powjerch",
"Name[hu]": "Munkaasztal",
"Name[ia]": "Scriptorio",
"Name[id]": "Desktop",
"Name[ie]": "Pupitre",
"Name[is]": "Skjáborð",
"Name[it]": "Desktop",
"Name[ja]": "デスクトップ",
"Name[ka]": "სამუშაო მაგიდა",
"Name[kk]": "Жұмыс үстелі",
"Name[kn]": "ಗಣಕತೆರೆ",
"Name[ko]": "바탕 화면",
"Name[ku]": "Sermasê",
"Name[lt]": "Darbalaukis",
"Name[lv]": "Darbvirsma",
"Name[mai]": "डेस्कटाप",
"Name[mk]": "Работна површина",
"Name[ml]": "പണിയിടം",
"Name[mr]": "डेस्कटॉप",
"Name[ms]": "Ruang Kerja",
"Name[nb]": "Skrivebord",
"Name[nds]": "Schriefdisch",
"Name[ne]": "डेस्कटप",
"Name[nl]": "Bureaublad",
"Name[nn]": "Skrivebord",
"Name[oc]": "Burèu",
"Name[or]": "ଡ଼େସ୍କଟପ",
"Name[pa]": "ਡੈਸਕਟਾਪ",
"Name[pl]": "Pulpit",
"Name[pt]": "Ambiente de Trabalho",
"Name[pt_BR]": "Área de trabalho",
"Name[ro]": "Birou",
"Name[ru]": "Рабочий стол",
"Name[se]": "Čállinbeavdi",
"Name[si]": "වැඩතලය",
"Name[sk]": "Plocha",
"Name[sl]": "Namizje",
"Name[sr@ijekavian]": "Површ",
"Name[sr@ijekavianlatin]": "Površ",
"Name[sr@latin]": "Površ",
"Name[sr]": "Површ",
"Name[sv]": "Skrivbord",
"Name[ta]": "பணிமேடை",
"Name[te]": "రంగస్ఠలం",
"Name[tg]": "Мизи корӣ",
"Name[th]": "พื้นที่ทำงาน",
"Name[tr]": "Masaüstü",
"Name[uk]": "Стільниця",
"Name[uz@cyrillic]": "Иш столи",
"Name[uz]": "Ish stoli",
"Name[vi]": "Bàn làm việc",
"Name[wa]": "Sicribanne",
"Name[x-test]": "xxDesktopxx",
"Name[xh]": "Desktop",
"Name[zh_CN]": "桌面",
"Name[zh_TW]": "桌面",
"Website": "https://www.kde.org/plasma-desktop"
},
"X-Plasma-API-Minimum-Version": "6.0",
"X-Plasma-ContainmentType": "Desktop"
}