Port Plasmoid to Plasma 6
* Split QML part into distinct versions for Plasma 5 and 6 as there are too many differences and `#ifdef` is not possible * Change API usage according to https://develop.kde.org/docs/plasma/widget/porting_kf6 * Port "contextualActions" to API documented on https://invent.kde.org/frameworks/plasma-framework/-/blob/master/src/plasma/applet.h * Document testing * Add FIXMEs/notes for remaining problems; there are likely many more, though
This commit is contained in:
parent
7e651be694
commit
912dca1564
|
@ -1,12 +1,28 @@
|
|||
# Testing and debugging Dolphin/KIO plugin with Qt Creator
|
||||
|
||||
1. Build as usual, ensure `NO_FILE_ITEM_ACTION_PLUGIN` is turned off
|
||||
2. Copy `*.desktop` file to `~/.local/share/kservices5` and enable it in Dolphin
|
||||
if packaged version is not already installed
|
||||
3. Add new config for run in Qt Creator and set `dolphin` as executable
|
||||
1. Build as usual, ensure `NO_FILE_ITEM_ACTION_PLUGIN` is turned off.
|
||||
2. Copy `*.desktop` file to `~/.local/share/kservices5` and enable it in Dolphin if a packaged version
|
||||
with the same configuration name is not already installed. Replace `5` with the current major version
|
||||
of KDE.
|
||||
3. Add new config for run in Qt Creator and set `dolphin` as executable.
|
||||
4. In execution environment, set
|
||||
* `QT_PLUGIN_PATH` to directory containing plugin `\*.so`-file
|
||||
* `QT_DEBUG_PLUGINS` to 1 for verbose plugin detection
|
||||
* `QT_XCB_NO_GRAB_SERVER` to 1 to prevent grabbing so the debugger is usable
|
||||
5. Ignore warning that executable is no debug build, it is sufficiant when
|
||||
plugin is debug build
|
||||
* `QT_PLUGIN_PATH` to directory containing plugin `\*.so`-file.
|
||||
* `QT_DEBUG_PLUGINS` to 1 for verbose plugin detection.
|
||||
* `QT_XCB_NO_GRAB_SERVER` to 1 to prevent grabbing so the debugger is usable.
|
||||
5. Ignore warning that executable is no debug build, it is sufficiant when plugin is debug build.
|
||||
|
||||
## Testing against a development build of Dolphin
|
||||
NOTE: This does not actually work with a KF6 build. Maybe the `*.desktop` file needs to be changed.
|
||||
|
||||
1. Build the whole dependency chain up to `dolphin` installing it under some custom prefix.
|
||||
2. Then follow the usual steps but make sure you build Syncthing Tray against the custom KDE builds.
|
||||
This is achieved the easiest by using the `debug-kde` CMake preset. This preset uses the environment
|
||||
variable `KDE_INSTALL_DIR` which must point to the custom prefix used in step 1.
|
||||
3. Copy the `*.desktop` file into the custom prefix used in step 1 under `share/kservices6`. Replace `6`
|
||||
with the current major version of KDE. The directory likely needs to be created first.
|
||||
4. Source the `prefix.sh` script that should be present in the build directory of any KDE library
|
||||
you built in step 1, e.g. `source kde/plasma-sdk/prefix.sh`.
|
||||
5. When setting the environment one needs to be more careful to not override variables set in step 4.
|
||||
It is the easiest to just start e.g. `plasmawindowed` from the shell:
|
||||
```
|
||||
QT_PLUGIN_PATH=$BUILD_DIR/syncthingtray/debug-kde/syncthingtray/fileitemactionplugin:$QT_PLUGIN_PATH dolphin
|
||||
```
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# the generated desktop file is required by inittesting.sh
|
||||
# the generated desktop/JSON file is required by inittesting.sh
|
||||
metadata.desktop
|
||||
metadata.json
|
||||
|
|
|
@ -11,38 +11,37 @@ set(META_QT5_VERSION 5.8)
|
|||
# use testfiles directory from syncthingconnector
|
||||
set(META_SRCDIR_REFS "${CMAKE_CURRENT_SOURCE_DIR}\n${CMAKE_CURRENT_SOURCE_DIR}/../syncthingconnector")
|
||||
|
||||
# find Plasma
|
||||
find_package(${KF_PACKAGE_PREFIX}Plasma REQUIRED)
|
||||
|
||||
# source files
|
||||
set(PLASMOID_FILES_BASE "package${KF_MAJOR_VERSION}")
|
||||
set(PLASMOID_FILES_UI "${PLASMOID_FILES_BASE}/contents/ui")
|
||||
set(PLASMOID_FILES
|
||||
package/contents/ui/CompactRepresentation.qml
|
||||
package/contents/ui/FullRepresentation.qml
|
||||
package/contents/ui/DirectoriesPage.qml
|
||||
package/contents/ui/DevicesPage.qml
|
||||
package/contents/ui/DownloadsPage.qml
|
||||
package/contents/ui/RecentChangesPage.qml
|
||||
package/contents/ui/TopLevelView.qml
|
||||
package/contents/ui/TopLevelItem.qml
|
||||
package/contents/ui/DetailView.qml
|
||||
package/contents/ui/DetailItem.qml
|
||||
package/contents/ui/TabButton.qml
|
||||
package/contents/ui/ToolTipTrigger.qml
|
||||
package/contents/ui/ToolTipView.qml
|
||||
package/contents/ui/ToolBar.qml
|
||||
package/contents/ui/ToolButton.qml
|
||||
package/contents/ui/TinyButton.qml
|
||||
package/contents/ui/IconLabel.qml
|
||||
package/contents/ui/StatisticsView.qml
|
||||
package/contents/ui/main.qml)
|
||||
${PLASMOID_FILES_UI}/CompactRepresentation.qml
|
||||
${PLASMOID_FILES_UI}/FullRepresentation.qml
|
||||
${PLASMOID_FILES_UI}/DirectoriesPage.qml
|
||||
${PLASMOID_FILES_UI}/DevicesPage.qml
|
||||
${PLASMOID_FILES_UI}/DownloadsPage.qml
|
||||
${PLASMOID_FILES_UI}/RecentChangesPage.qml
|
||||
${PLASMOID_FILES_UI}/TopLevelView.qml
|
||||
${PLASMOID_FILES_UI}/TopLevelItem.qml
|
||||
${PLASMOID_FILES_UI}/DetailView.qml
|
||||
${PLASMOID_FILES_UI}/DetailItem.qml
|
||||
${PLASMOID_FILES_UI}/TabButton.qml
|
||||
${PLASMOID_FILES_UI}/ToolTipTrigger.qml
|
||||
${PLASMOID_FILES_UI}/ToolTipView.qml
|
||||
${PLASMOID_FILES_UI}/ToolBar.qml
|
||||
${PLASMOID_FILES_UI}/ToolButton.qml
|
||||
${PLASMOID_FILES_UI}/TinyButton.qml
|
||||
${PLASMOID_FILES_UI}/IconLabel.qml
|
||||
${PLASMOID_FILES_UI}/StatisticsView.qml
|
||||
${PLASMOID_FILES_UI}/main.qml)
|
||||
|
||||
# find ECM (required by Plasma)
|
||||
find_package(ECM REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_MODULE_PATH})
|
||||
|
||||
# find Plasma
|
||||
set(KF_PACKAGE_PREFIX
|
||||
"KF5"
|
||||
CACHE STRING "specifies the prefix for KDE Frameworks packages")
|
||||
find_package(${KF_PACKAGE_PREFIX}Plasma REQUIRED)
|
||||
|
||||
# find c++utilities
|
||||
find_package(${PACKAGE_NAMESPACE_PREFIX}c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.20.0 REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CPP_UTILITIES_MODULE_DIRS})
|
||||
|
@ -50,14 +49,22 @@ list(APPEND CMAKE_MODULE_PATH ${CPP_UTILITIES_MODULE_DIRS})
|
|||
# prepare plasmoid package/configuration
|
||||
set(PLASMOID_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/package")
|
||||
file(MAKE_DIRECTORY "${PLASMOID_PACKAGE_DIR}")
|
||||
set(PLASMOID_CONFIG_TARGET_FILE "${PLASMOID_PACKAGE_DIR}/metadata.desktop")
|
||||
if (KF_MAJOR_VERSION LESS 6)
|
||||
set(PLASMOID_CONFIG_TARGET_FILE "${PLASMOID_PACKAGE_DIR}/metadata.desktop")
|
||||
else ()
|
||||
set(PLASMOID_CONFIG_TARGET_FILE "${PLASMOID_PACKAGE_DIR}/metadata.json")
|
||||
endif ()
|
||||
|
||||
# make plugin library
|
||||
add_subdirectory(lib)
|
||||
|
||||
# make plasmoid configuration
|
||||
include(TemplateFinder)
|
||||
find_template_file("metadata.desktop" "${META_PROJECT_NAME}" PLASMOID_CONFIG_TEMPLATE_FILE)
|
||||
if (KF_MAJOR_VERSION LESS 6)
|
||||
find_template_file("metadata.desktop" "${META_PROJECT_NAME}" PLASMOID_CONFIG_TEMPLATE_FILE)
|
||||
else ()
|
||||
find_template_file("metadata.json" "${META_PROJECT_NAME}" PLASMOID_CONFIG_TEMPLATE_FILE)
|
||||
endif ()
|
||||
get_filename_component(PLASMOID_CONFIG_TARGET_FILE_ABSOLUTE_PATH "${PLASMOID_CONFIG_TARGET_FILE}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
configure_file("${PLASMOID_CONFIG_TEMPLATE_FILE}" "${PLASMOID_CONFIG_TARGET_FILE}")
|
||||
|
||||
|
@ -75,6 +82,6 @@ plasma_install_package("${PLASMOID_PACKAGE_DIR}" "${META_ID}")
|
|||
set(PLASMOID_TESTDIR "${CMAKE_BINARY_DIR}" CACHE STRING "specifies the Plasmoid test directory")
|
||||
file(MAKE_DIRECTORY "${PLASMOID_TESTDIR}")
|
||||
add_custom_target(init_plasmoid_testing
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/inittesting.sh" "${PLASMOID_CONFIG_TARGET_FILE_ABSOLUTE_PATH}"
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/inittesting.sh" "${PLASMOID_CONFIG_TARGET_FILE_ABSOLUTE_PATH}" "${PLASMOID_FILES_BASE}"
|
||||
WORKING_DIRECTORY "${PLASMOID_TESTDIR}"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"KPackageStructure": "Plasma/Applet",
|
||||
"KPlugin": {
|
||||
"Authors": [{"Name": "@META_APP_AUTHOR@"}],
|
||||
"BugReportUrl": "@META_APP_BUGTRACKER_URL@",
|
||||
"Category": "SystemServices",
|
||||
"Description": "@META_APP_DESCRIPTION@",
|
||||
"EnabledByDefault": false,
|
||||
"Icon": "syncthingtray",
|
||||
"Id": "@META_ID@",
|
||||
"License": "@META_PROJECT_LICENSE@",
|
||||
"Name": "Syncthing",
|
||||
"Version": "@META_APP_VERSION@",
|
||||
"Website": "@META_APP_URL@"
|
||||
},
|
||||
"Keywords": "syncthing;sync;",
|
||||
"X-Plasma-API": "declarativeappletscript",
|
||||
"X-Plasma-MainScript": "ui/main.qml"
|
||||
}
|
|
@ -34,6 +34,10 @@ use_syncthingwidgets()
|
|||
|
||||
# link also explicitly against the following Qt modules
|
||||
list(APPEND ADDITIONAL_QT_MODULES Network Qml)
|
||||
if (KF_MAJOR_VERSION GREATER_EQUAL 6)
|
||||
set(Config_MODULE_TARGETS ${KF_PACKAGE_PREFIX}::ConfigCore)
|
||||
list(APPEND ADDITIONAL_KF_MODULES Config)
|
||||
endif ()
|
||||
list(APPEND ADDITIONAL_KF_MODULES Plasma)
|
||||
|
||||
include(BasicConfig)
|
||||
|
@ -55,9 +59,16 @@ set(META_PROJECT_LICENSE
|
|||
"${META_PROJECT_LICENSE}"
|
||||
PARENT_SCOPE)
|
||||
|
||||
# what ever this does, it is done
|
||||
kcoreaddons_desktop_to_json("${META_TARGET_NAME}" "${PLASMOID_CONFIG_TARGET_FILE}" DESKTOP_TO_JSON_OUTPUT_DIR
|
||||
"${PLASMOID_PACKAGE_DIR}")
|
||||
# convert meta-data file to JSON
|
||||
if (KF_MAJOR_VERSION LESS 6)
|
||||
kcoreaddons_desktop_to_json("${META_TARGET_NAME}" "${PLASMOID_CONFIG_TARGET_FILE}" DESKTOP_TO_JSON_OUTPUT_DIR
|
||||
"${PLASMOID_PACKAGE_DIR}")
|
||||
endif ()
|
||||
|
||||
# set the library prefix so it doesn't start with "lib" and is rather prefixed with "martchus."
|
||||
if (KF_MAJOR_VERSION GREATER_EQUAL 6)
|
||||
set_target_properties(${META_TARGET_NAME} PROPERTIES PREFIX "martchus.")
|
||||
endif ()
|
||||
|
||||
# install appstream file
|
||||
add_appstream_file()
|
||||
|
|
|
@ -69,7 +69,11 @@ static inline QPalette paletteFromTheme(const Plasma::Theme &theme)
|
|||
}
|
||||
|
||||
SyncthingApplet::SyncthingApplet(QObject *parent, const QVariantList &data)
|
||||
#if PLASMA_VERSION >= QT_VERSION_CHECK(5, 240, 0)
|
||||
: Applet(parent, KPluginMetaData(), data)
|
||||
#else
|
||||
: Applet(parent, data)
|
||||
#endif
|
||||
, m_faUrl(QStringLiteral("image://fa/"))
|
||||
, m_iconManager(IconManager::instance(&m_palette))
|
||||
, m_aboutDlg(nullptr)
|
||||
|
@ -678,6 +682,12 @@ void SyncthingApplet::handleSystemdStatusChanged()
|
|||
|
||||
} // namespace Plasmoid
|
||||
|
||||
#if PLASMA_VERSION >= QT_VERSION_CHECK(5, 240, 0)
|
||||
namespace Plasmoid {
|
||||
K_PLUGIN_CLASS(SyncthingApplet)
|
||||
}
|
||||
#else
|
||||
K_EXPORT_PLASMA_APPLET_WITH_JSON(syncthing, Plasmoid::SyncthingApplet, "metadata.json")
|
||||
#endif
|
||||
|
||||
#include "syncthingapplet.moc"
|
||||
|
|
|
@ -95,7 +95,6 @@ PlasmaExtras.Representation {
|
|||
id: searchButton
|
||||
anchors.right: mainLayout.right
|
||||
anchors.rightMargin: PlasmaCore.Units.smallSpacing * 2
|
||||
anchors.verticalCenter: infoLayout.verticalCenter
|
||||
icon.source: plasmoid.nativeInterface.faUrl + "search"
|
||||
width: PlasmaCore.Units.iconSizes.smallMedium
|
||||
height: width
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
|
||||
MouseArea {
|
||||
Layout.fillWidth: false
|
||||
hoverEnabled: true
|
||||
onClicked: plasmoid.expanded = !plasmoid.expanded
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
id: icon
|
||||
anchors.fill: parent
|
||||
source: plasmoid.statusIcon
|
||||
active: parent.containsMouse
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
id: detailItem
|
||||
|
||||
property string detailName: name ? name : ""
|
||||
property string detailValue: detail ? detail : ""
|
||||
|
||||
width: detailRow.implicitWidth
|
||||
height: detailRow.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: detailRow
|
||||
width: parent.width
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
source: detailIcon
|
||||
Layout.leftMargin: Kirigami.Units.iconSizes.small * 1.1
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
opacity: 0.8
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.preferredWidth: 100
|
||||
text: detailName
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.leftMargin: theme.defaultFont.pointSize * 0.9
|
||||
Layout.fillWidth: true
|
||||
text: detailValue
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
acceptedButtons: Qt.RightButton
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
var view = detailItem.ListView.view
|
||||
var coordinates = mapToItem(view, mouseX, mouseY)
|
||||
view.showContextMenu(detailItem, coordinates.x, coordinates.y)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import QtQuick 2.7
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
ListView {
|
||||
id: detailView
|
||||
property DetailItem contextMenuItem: null
|
||||
currentIndex: -1
|
||||
interactive: false
|
||||
height: contentHeight
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr('Copy value')
|
||||
icon: "edit-copy"
|
||||
onClicked: {
|
||||
var item = detailView.contextMenuItem
|
||||
if (item) {
|
||||
plasmoid.copyToClipboard(item.detailValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showContextMenu(item, x, y) {
|
||||
contextMenuItem = item
|
||||
contextMenu.open(x, y)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml.Models 2.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
property alias view: deviceView
|
||||
objectName: "DevicesPage"
|
||||
|
||||
PlasmaComponents3.ScrollView {
|
||||
anchors.fill: parent
|
||||
|
||||
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
|
||||
contentItem: TopLevelView {
|
||||
id: deviceView
|
||||
model: plasmoid.sortFilterDevModel
|
||||
|
||||
delegate: TopLevelItem {
|
||||
id: item
|
||||
width: deviceView.effectiveWidth()
|
||||
readonly property string devName: name
|
||||
readonly property string devID: devId
|
||||
property alias resumePauseButton: resumePauseButton
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
source: statusIcon
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: name
|
||||
}
|
||||
RowLayout {
|
||||
id: toolButtonsLayout
|
||||
spacing: 0
|
||||
PlasmaComponents3.Label {
|
||||
height: implicitHeight
|
||||
text: statusString
|
||||
color: statusColor ? statusColor : PlasmaCore.ColorScope.textColor
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
}
|
||||
Item {
|
||||
width: 3
|
||||
}
|
||||
TinyButton {
|
||||
id: resumePauseButton
|
||||
icon.source: plasmoid.faUrl + (paused ? "play" : "pause")
|
||||
icon.cache: false
|
||||
tooltip: paused ? qsTr("Resume") : qsTr("Pause")
|
||||
enabled: !isOwnDevice
|
||||
onClicked: {
|
||||
paused ? plasmoid.connection.resumeDevice(
|
||||
[devId]) : plasmoid.connection.pauseDevice(
|
||||
[devId])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetailView {
|
||||
id: detailsView
|
||||
visible: item.expanded
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 3
|
||||
|
||||
model: DelegateModel {
|
||||
model: plasmoid.devModel
|
||||
rootIndex: deviceView.model.mapToSource(deviceView.model.index(index, 0))
|
||||
delegate: DetailItem {
|
||||
width: detailsView.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
|
||||
function init(item) {
|
||||
// use value for properties depending on paused state from buttons
|
||||
resumePauseItem.text = item.resumePauseButton.tooltip
|
||||
resumePauseItem.icon = item.resumePauseButton.icon
|
||||
}
|
||||
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy name")
|
||||
icon: "edit-copy"
|
||||
onClicked: deviceView.copyCurrentItemData("devName")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy ID")
|
||||
icon: "edit-copy"
|
||||
onClicked: deviceView.copyCurrentItemData("devID")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
separator: true
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
id: resumePauseItem
|
||||
text: qsTr("Pause")
|
||||
icon: "media-playback-pause"
|
||||
onClicked: deviceView.clickCurrentItemButton(
|
||||
"resumePauseButton")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml.Models 2.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
ColumnLayout {
|
||||
property alias view: directoryView
|
||||
property alias filter: filter
|
||||
objectName: "DirectoriesPage"
|
||||
|
||||
PlasmaComponents3.TextField {
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing * 2
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing * 2
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing * 2
|
||||
property bool explicitelyShown: false
|
||||
id: filter
|
||||
clearButtonShown: true
|
||||
Layout.fillWidth: true
|
||||
visible: explicitelyShown || text !== ""
|
||||
placeholderText: qsTr("Filter directories")
|
||||
onTextChanged: directoryView.model.filterRegularExpression = new RegExp(text)
|
||||
}
|
||||
|
||||
PlasmaComponents3.ScrollView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
|
||||
contentItem: TopLevelView {
|
||||
id: directoryView
|
||||
model: plasmoid.sortFilterDirModel
|
||||
|
||||
delegate: TopLevelItem {
|
||||
id: item
|
||||
width: directoryView.effectiveWidth()
|
||||
readonly property string dirName: name
|
||||
readonly property string dirPath: path
|
||||
property alias errorsButton: errorsButton
|
||||
property alias rescanButton: rescanButton
|
||||
property alias resumePauseButton: resumePauseButton
|
||||
property alias openButton: openButton
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: itemSummary
|
||||
Layout.fillWidth: true
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
Layout.preferredWidth: units.iconSizes.small
|
||||
Layout.preferredHeight: units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
source: statusIcon
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: name
|
||||
}
|
||||
RowLayout {
|
||||
id: toolButtonsLayout
|
||||
spacing: 0
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
height: implicitHeight
|
||||
text: statusString
|
||||
color: statusColor ? statusColor : PlasmaCore.ColorScope.textColor
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
}
|
||||
Item {
|
||||
width: units.smallSpacing
|
||||
}
|
||||
TinyButton {
|
||||
id: errorsButton
|
||||
icon.source: plasmoid.faUrl + "exclamation-triangle"
|
||||
tooltip: qsTr("Show errors")
|
||||
visible: pullErrorCount > 0
|
||||
onClicked: {
|
||||
plasmoid.showDirectoryErrors(
|
||||
dirId)
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
}
|
||||
TinyButton {
|
||||
id: rescanButton
|
||||
icon.source: plasmoid.faUrl + "refresh"
|
||||
tooltip: qsTr("Rescan")
|
||||
enabled: !paused
|
||||
onClicked: plasmoid.connection.rescan(
|
||||
dirId)
|
||||
}
|
||||
TinyButton {
|
||||
id: resumePauseButton
|
||||
icon.source: plasmoid.faUrl + (paused ? "play" : "pause")
|
||||
tooltip: paused ? qsTr("Resume") : qsTr("Pause")
|
||||
onClicked: {
|
||||
paused ? plasmoid.connection.resumeDirectories(
|
||||
[dirId]) : plasmoid.connection.pauseDirectories(
|
||||
[dirId])
|
||||
}
|
||||
}
|
||||
TinyButton {
|
||||
id: openButton
|
||||
icon.source: plasmoid.faUrl + "folder"
|
||||
tooltip: qsTr("Open in file browser")
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(plasmoid.substituteTilde(path))
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetailView {
|
||||
id: detailsView
|
||||
visible: item.expanded
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 3
|
||||
|
||||
model: DelegateModel {
|
||||
model: plasmoid.dirModel
|
||||
rootIndex: directoryView.model.mapToSource(directoryView.model.index(index, 0))
|
||||
delegate: DetailItem {
|
||||
width: detailsView.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
|
||||
function init(item) {
|
||||
// use value for properties depending on paused state from buttons
|
||||
rescanItem.enabled = item.rescanButton.enabled
|
||||
resumePauseItem.text = item.resumePauseButton.tooltip
|
||||
resumePauseItem.icon = item.resumePauseButton.icon
|
||||
}
|
||||
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy label/ID")
|
||||
icon: "edit-copy"
|
||||
onClicked: directoryView.copyCurrentItemData("dirName")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy path")
|
||||
icon: "edit-copy"
|
||||
onClicked: directoryView.copyCurrentItemData("dirPath")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
separator: true
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
id: rescanItem
|
||||
text: qsTr("Rescan")
|
||||
icon: "view-refresh"
|
||||
onClicked: directoryView.clickCurrentItemButton(
|
||||
"rescanButton")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
id: resumePauseItem
|
||||
text: qsTr("Pause")
|
||||
icon: "media-playback-pause"
|
||||
onClicked: directoryView.clickCurrentItemButton(
|
||||
"resumePauseButton")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
id: openItem
|
||||
text: qsTr("Open in file browser")
|
||||
icon: "folder"
|
||||
onClicked: directoryView.clickCurrentItemButton(
|
||||
"openButton")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml.Models 2.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
property alias view: downloadView
|
||||
objectName: "DownloadsPage"
|
||||
|
||||
PlasmaComponents3.ScrollView {
|
||||
anchors.fill: parent
|
||||
|
||||
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
|
||||
contentItem: TopLevelView {
|
||||
id: downloadView
|
||||
model: plasmoid.downloadModel
|
||||
|
||||
delegate: TopLevelItem {
|
||||
id: item
|
||||
width: downloadView.effectiveWidth()
|
||||
readonly property string downloadName: name
|
||||
property alias openButton: openButton
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: itemSummary
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
spacing: units.smallSpacing
|
||||
PlasmaComponents3.Label {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: name ? name : "?"
|
||||
}
|
||||
}
|
||||
PlasmaComponents3.ProgressBar {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
from: 0.0
|
||||
to: 100.0
|
||||
value: percentage ? percentage : 0.0
|
||||
}
|
||||
RowLayout {
|
||||
id: toolButtonsLayout
|
||||
spacing: 0
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
height: implicitHeight
|
||||
text: progressLabel ? progressLabel : ""
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
}
|
||||
Item {
|
||||
width: 3
|
||||
}
|
||||
TinyButton {
|
||||
id: openButton
|
||||
icon.source: plasmoid.faUrl + "folder"
|
||||
tooltip: qsTr("Open in file browser")
|
||||
enabled: path !== undefined
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(path)
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetailView {
|
||||
id: detailsView
|
||||
visible: item.expanded
|
||||
Layout.fillWidth: true
|
||||
|
||||
model: DelegateModel {
|
||||
model: plasmoid.downloadModel
|
||||
rootIndex: detailsView.model.modelIndex(index)
|
||||
delegate: RowLayout {
|
||||
width: detailsView.width
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
source: fileIcon
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Layout.fillWidth: true
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
text: name
|
||||
font.pointSize: theme.defaultFont.pointSize * 0.8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
text: progressLabel
|
||||
font.pointSize: theme.defaultFont.pointSize * 0.8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
PlasmaComponents3.ProgressBar {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 8
|
||||
Layout.topMargin: 0
|
||||
from: 0.0
|
||||
to: 100.0
|
||||
value: percentage
|
||||
}
|
||||
}
|
||||
TinyButton {
|
||||
icon.source: plasmoid.faUrl + "folder"
|
||||
tooltip: qsTr("Open in file browser")
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(path + "/..")
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy label/ID")
|
||||
icon: "edit-copy"
|
||||
onClicked: downloadView.copyCurrentItemData("downloadName")
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
separator: true
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
id: openItem
|
||||
text: qsTr("Open in file browser")
|
||||
icon: "folder"
|
||||
onClicked: downloadView.clickCurrentItemButton("openButton")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
import QtQml 2.2
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15 as QQ2
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
PlasmaExtras.Representation {
|
||||
// disable margins as they don't look good together with the scroll view
|
||||
// note: Would be collapsed automatically if the scroll view was the immediate content item.
|
||||
collapseMarginsHint: true
|
||||
|
||||
// header ("toolbar" with buttons and combo box) and footer ("tabbar")
|
||||
header: PlasmaExtras.PlasmoidHeading {
|
||||
ToolBar {
|
||||
id: toolbar
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
footer: PlasmaExtras.PlasmoidHeading {
|
||||
spacing: 0
|
||||
topPadding: 0
|
||||
height: Kirigami.Units.iconSizes.medium
|
||||
PlasmaComponents3.TabBar {
|
||||
id: tabBar
|
||||
readonly property double buttonWidth: parent.width / count
|
||||
position: PlasmaComponents3.TabBar.Footer
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
TabButton {
|
||||
id: dirsTabButton
|
||||
text: qsTr("Directories")
|
||||
icon.source: plasmoid.faUrl + "folder"
|
||||
width: tabBar.buttonWidth
|
||||
}
|
||||
TabButton {
|
||||
id: devsTabButton
|
||||
text: qsTr("Devices")
|
||||
icon.source: plasmoid.faUrl + "sitemap"
|
||||
width: tabBar.buttonWidth
|
||||
}
|
||||
TabButton {
|
||||
id: downloadsTabButton
|
||||
text: qsTr("Downloads")
|
||||
icon.source: plasmoid.faUrl + "download"
|
||||
width: tabBar.buttonWidth
|
||||
}
|
||||
TabButton {
|
||||
id: recentChangesTabButton
|
||||
text: qsTr("History")
|
||||
icon.source: plasmoid.faUrl + "history"
|
||||
width: tabBar.buttonWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// define functions to locate the current page and filter
|
||||
function findCurrentPage() {
|
||||
switch (tabBar.currentIndex) {
|
||||
case 0: return directoriesPage
|
||||
case 1: return devicesPage
|
||||
case 2: return downloadsPage
|
||||
case 3: return recentChangesPage
|
||||
default: return directoriesPage
|
||||
}
|
||||
}
|
||||
function findCurrentFilter() {
|
||||
return findCurrentPage().filter
|
||||
}
|
||||
|
||||
// define shortcuts to trigger actions for currently selected item
|
||||
function clickCurrentItemButton(buttonName) {
|
||||
findCurrentPage().view.clickCurrentItemButton(buttonName)
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+R"
|
||||
onActivated: clickCurrentItemButton("rescanButton")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+P"
|
||||
onActivated: clickCurrentItemButton("resumePauseButton")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+O"
|
||||
onActivated: clickCurrentItemButton("openButton")
|
||||
}
|
||||
|
||||
// main contents
|
||||
FocusScope {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: Kirigami.Units.smallSpacing * 2
|
||||
|
||||
TinyButton {
|
||||
id: searchButton
|
||||
anchors.right: mainLayout.right
|
||||
anchors.rightMargin: Kirigami.Units.smallSpacing * 2
|
||||
icon.source: plasmoid.faUrl + "search"
|
||||
width: Kirigami.Units.iconSizes.smallMedium
|
||||
height: width
|
||||
enabled: tabBar.currentIndex === 0
|
||||
opacity: enabled ? 1.0 : 0.25
|
||||
tooltip: qsTr("Toggle filter")
|
||||
onClicked: {
|
||||
var filter = findCurrentFilter()
|
||||
if (!filter) {
|
||||
return
|
||||
}
|
||||
if (!filter.explicitelyShown) {
|
||||
filter.explicitelyShown = true
|
||||
filter.forceActiveFocus()
|
||||
} else {
|
||||
filter.explicitelyShown = false
|
||||
filter.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// ensure keyboard events can be received after initialization
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
|
||||
// define custom key handling for switching tabs, selecting items and filtering
|
||||
function sendKeyEventToFilter(event) {
|
||||
var filter = findCurrentFilter()
|
||||
if (!filter || event.text === "" || filter.activeFocus) {
|
||||
return
|
||||
}
|
||||
if (event.key === Qt.Key_Backspace && filter.text === "") {
|
||||
filter.explicitelyShown = false
|
||||
return
|
||||
}
|
||||
if (event.matches(StandardKey.Paste)) {
|
||||
filter.paste()
|
||||
} else {
|
||||
filter.text = ""
|
||||
filter.text += event.text
|
||||
}
|
||||
filter.forceActiveFocus()
|
||||
}
|
||||
Keys.onPressed: function(event) {
|
||||
// note: event only received after clicking the tab buttons in plasmoidviewer
|
||||
// but works as expected in plasmashell
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
switch (event.modifiers) {
|
||||
case Qt.NoModifier:
|
||||
// select previous item in current tab
|
||||
findCurrentPage().view.decrementCurrentIndex()
|
||||
break
|
||||
case Qt.ShiftModifier:
|
||||
// select previous connection
|
||||
--plasmoid.currentConnectionConfigIndex
|
||||
break
|
||||
}
|
||||
break
|
||||
case Qt.Key_Down:
|
||||
switch (event.modifiers) {
|
||||
case Qt.NoModifier:
|
||||
// select next item in current tab
|
||||
findCurrentPage().view.incrementCurrentIndex()
|
||||
break
|
||||
case Qt.ShiftModifier:
|
||||
// select previous connection
|
||||
++plasmoid.currentConnectionConfigIndex
|
||||
break
|
||||
}
|
||||
break
|
||||
case Qt.Key_Left:
|
||||
// select previous tab
|
||||
tabBar.currentIndex = tabBar.currentIndex > 0 ? tabBar.currentIndex - 1 : 3
|
||||
break
|
||||
case Qt.Key_Right:
|
||||
// select next tab
|
||||
tabBar.currentIndex = tabBar.currentIndex < 3 ? tabBar.currentIndex + 1 : 0
|
||||
break
|
||||
case Qt.Key_Enter:
|
||||
|
||||
// fallthrough
|
||||
case Qt.Key_Return:
|
||||
// toggle expanded state of current item
|
||||
var currentItem = findCurrentPage().view.currentItem
|
||||
if (currentItem) {
|
||||
currentItem.expanded = !currentItem.expanded
|
||||
}
|
||||
break
|
||||
case Qt.Key_Escape:
|
||||
var filter = findCurrentFilter()
|
||||
if (filter && filter.text !== "") {
|
||||
// reset filter
|
||||
filter.explicitelyShown = false
|
||||
filter.text = ""
|
||||
event.accepted = true
|
||||
} else {
|
||||
// hide plasmoid
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
break
|
||||
case Qt.Key_1:
|
||||
tabBar.currentIndex = 0
|
||||
break
|
||||
case Qt.Key_2:
|
||||
tabBar.currentIndex = 1
|
||||
break
|
||||
case Qt.Key_3:
|
||||
tabBar.currentIndex = 2
|
||||
break
|
||||
case Qt.Key_4:
|
||||
tabBar.currentIndex = 3
|
||||
break
|
||||
default:
|
||||
sendKeyEventToFilter(event)
|
||||
return
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
// global statistics and traffic
|
||||
GridLayout {
|
||||
id: infoLayout
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing * 2
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing * 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: false
|
||||
Layout.maximumWidth: parent.width
|
||||
columns: 4
|
||||
rowSpacing: 1
|
||||
columnSpacing: 4
|
||||
|
||||
Image {
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
height: 16
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: plasmoid.faUrl + "globe"
|
||||
cache: false
|
||||
}
|
||||
StatisticsView {
|
||||
Layout.leftMargin: 4
|
||||
statistics: plasmoid.globalStatistics
|
||||
context: qsTr("Global")
|
||||
}
|
||||
IconLabel {
|
||||
Layout.leftMargin: 5
|
||||
iconSource: plasmoid.faUrl + "cloud-download"
|
||||
iconOpacity: plasmoid.hasIncomingTraffic ? 1.0 : 0.5
|
||||
text: plasmoid.incomingTraffic
|
||||
tooltip: qsTr("Global incoming traffic")
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.rowSpan: 2
|
||||
}
|
||||
Image {
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
height: 16
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: plasmoid.faUrl + "home"
|
||||
cache: false
|
||||
}
|
||||
StatisticsView {
|
||||
Layout.leftMargin: 4
|
||||
statistics: plasmoid.localStatistics
|
||||
context: qsTr("Local")
|
||||
}
|
||||
IconLabel {
|
||||
Layout.leftMargin: 5
|
||||
iconSource: plasmoid.faUrl + "cloud-upload"
|
||||
iconOpacity: plasmoid.hasOutgoingTraffic ? 1.0 : 0.5
|
||||
text: plasmoid.outgoingTraffic
|
||||
tooltip: qsTr("Global outgoing traffic")
|
||||
}
|
||||
}
|
||||
|
||||
// tab content
|
||||
StackLayout {
|
||||
id: tabLayout
|
||||
currentIndex: tabBar.currentIndex
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
DirectoriesPage {
|
||||
id: directoriesPage
|
||||
}
|
||||
DevicesPage {
|
||||
id: devicesPage
|
||||
}
|
||||
DownloadsPage {
|
||||
id: downloadsPage
|
||||
}
|
||||
RecentChangesPage {
|
||||
id: recentChangesPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
|
||||
Item {
|
||||
property alias iconSource: iconItem.source
|
||||
property alias iconOpacity: iconItem.opacity
|
||||
property alias text: label.text
|
||||
property alias tooltip: tooltipTrigger.tooltip
|
||||
|
||||
implicitWidth: layout.implicitWidth
|
||||
implicitHeight: layout.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
Image {
|
||||
id: iconItem
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
height: 16
|
||||
cache: false
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
id: label
|
||||
}
|
||||
}
|
||||
ToolTipTrigger {
|
||||
id: tooltipTrigger
|
||||
anchors.fill: layout
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml.Models 2.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
property alias view: recentChangesView
|
||||
objectName: "RecentChangesPage"
|
||||
|
||||
PlasmaComponents3.ScrollView {
|
||||
anchors.fill: parent
|
||||
|
||||
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
|
||||
contentItem: TopLevelView {
|
||||
id: recentChangesView
|
||||
model: plasmoid.recentChangesModel
|
||||
delegate: TopLevelItem {
|
||||
width: recentChangesView.effectiveWidth()
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
PlasmaCore.IconItem {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
source: actionIcon
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: extendedAction
|
||||
}
|
||||
Item {
|
||||
width: Kirigami.Units.smallSpacing
|
||||
}
|
||||
Image {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: plasmoid.faUrl + "calendar"
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: eventTime
|
||||
}
|
||||
Item {
|
||||
width: Kirigami.Units.smallSpacing
|
||||
}
|
||||
Image {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: plasmoid.faUrl + "qrcode"
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: modifiedBy
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Image {
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: plasmoid.faUrl + (itemType === "file" ? "file-o" : "folder-o")
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
text: directoryId + ": "
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
text: path
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copyPath() {
|
||||
plasmoid.copyToClipboard(path)
|
||||
}
|
||||
function copyDeviceId() {
|
||||
plasmoid.copyToClipboard(modifiedBy)
|
||||
}
|
||||
function copyFolderId() {
|
||||
plasmoid.copyToClipboard(folderId)
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy path")
|
||||
icon: "edit-copy"
|
||||
onClicked: recentChangesView.currentItem.copyPath()
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy device ID")
|
||||
icon: "network-server-symbolic"
|
||||
onClicked: recentChangesView.currentItem.copyDeviceId()
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: qsTr("Copy directory ID")
|
||||
icon: "folder"
|
||||
onClicked: recentChangesView.currentItem.copyFolderId()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
property var statistics
|
||||
property string context: "?"
|
||||
|
||||
IconLabel {
|
||||
iconSource: plasmoid.faUrl + "file-o"
|
||||
text: statistics.files !== undefined ? statistics.files : "?"
|
||||
tooltip: context + qsTr(" files")
|
||||
}
|
||||
IconLabel {
|
||||
iconSource: plasmoid.faUrl + "folder-o"
|
||||
text: statistics.dirs !== undefined ? statistics.dirs : "?"
|
||||
tooltip: context + qsTr(" directories")
|
||||
}
|
||||
IconLabel {
|
||||
iconSource: plasmoid.faUrl + "hdd-o"
|
||||
text: statistics.bytes !== undefined ? plasmoid.formatFileSize(
|
||||
statistics.bytes) : "?"
|
||||
tooltip: context + qsTr(" size")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import QtQuick 2.8
|
||||
import QtQuick.Templates 2.15 as T
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.5 as Kirigami
|
||||
|
||||
PlasmaComponents3.TabButton {
|
||||
id: root
|
||||
spacing: 0
|
||||
|
||||
property bool showTabText: plasmoid.showTabTexts
|
||||
property string tooltip: ""
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
id: tooltip
|
||||
text: root.tooltip !== "" ? root.tooltip : (root.showTabText ? "" : root.text)
|
||||
visible: text !== "" && parent instanceof T.AbstractButton && (Kirigami.Settings.tabletMode ? parent.pressed : parent.hovered)
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: label.visible ? Kirigami.Units.smallSpacing : 0
|
||||
PlasmaCore.ColorScope.inherit: true
|
||||
width: parent.width
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Image {
|
||||
id: image
|
||||
Layout.preferredHeight: height
|
||||
source: root.icon.source
|
||||
cache: false
|
||||
height: Kirigami.Units.iconSizes.small
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
id: label
|
||||
visible: text.length > 0
|
||||
text: root.showTabText ? root.text : ""
|
||||
color: PlasmaCore.ColorScope.textColor
|
||||
elide: Text.ElideRight
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import QtQuick 2.8
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: root
|
||||
|
||||
property alias tooltip: tooltip.text
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
id: tooltip
|
||||
}
|
||||
contentItem: Image {
|
||||
source: root.icon.source
|
||||
cache: false
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
import QtQml 2.3
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import martchus.syncthingplasmoid 0.6 as SyncthingPlasmoid
|
||||
|
||||
RowLayout {
|
||||
id: toolBar
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Layout.minimumHeight: Kirigami.Units.iconSizes.medium
|
||||
Layout.maximumHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
readonly property bool showExtraButtons: !(plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentDrawsPlasmoidHeading)
|
||||
|
||||
ToolButton {
|
||||
id: connectButton
|
||||
states: [
|
||||
State {
|
||||
name: "disconnected"
|
||||
PropertyChanges {
|
||||
target: connectButton
|
||||
text: qsTr("Connect")
|
||||
icon.source: plasmoid.faUrl + "refresh"
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "connecting"
|
||||
PropertyChanges {
|
||||
target: connectButton
|
||||
text: qsTr("Connecting …")
|
||||
icon.source: plasmoid.faUrl + "refresh"
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "paused"
|
||||
PropertyChanges {
|
||||
target: connectButton
|
||||
text: qsTr("Resume")
|
||||
icon.source: plasmoid.faUrl + "play"
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "idle"
|
||||
PropertyChanges {
|
||||
target: connectButton
|
||||
text: qsTr("Pause")
|
||||
icon.source: plasmoid.faUrl + "pause"
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
state: {
|
||||
switch (plasmoid.connection.status) {
|
||||
case SyncthingPlasmoid.Data.Disconnected:
|
||||
return plasmoid.connection.connecting ? "connecting" : "disconnected"
|
||||
case SyncthingPlasmoid.Data.Reconnecting:
|
||||
return "connecting";
|
||||
case SyncthingPlasmoid.Data.Paused:
|
||||
return "paused"
|
||||
default:
|
||||
return "idle"
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
switch (plasmoid.connection.status) {
|
||||
case SyncthingPlasmoid.Data.Disconnected:
|
||||
plasmoid.connection.connect()
|
||||
break
|
||||
case SyncthingPlasmoid.Data.Reconnecting:
|
||||
break
|
||||
case SyncthingPlasmoid.Data.Paused:
|
||||
plasmoid.connection.resumeAllDevs()
|
||||
break
|
||||
default:
|
||||
plasmoid.connection.pauseAllDevs()
|
||||
break
|
||||
}
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: connectButton.text
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+Shift+P"
|
||||
onActivated: connectButton.clicked()
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: startStopButton
|
||||
states: [
|
||||
State {
|
||||
name: "running"
|
||||
PropertyChanges {
|
||||
target: startStopButton
|
||||
visible: true
|
||||
text: qsTr("Stop")
|
||||
icon.source: plasmoid.faUrl + "stop"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: startStopToolTip
|
||||
text: (plasmoid.service.userScope ? "systemctl --user stop " : "systemctl stop ")
|
||||
+ plasmoid.service.unitName
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "stopped"
|
||||
PropertyChanges {
|
||||
target: startStopButton
|
||||
visible: true
|
||||
text: qsTr("Start")
|
||||
icon.source: plasmoid.faUrl + "play"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: startStopToolTip
|
||||
text: (plasmoid.service.userScope ? "systemctl --user start " : "systemctl start ")
|
||||
+ plasmoid.service.unitName
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "irrelevant"
|
||||
PropertyChanges {
|
||||
target: startStopButton
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
]
|
||||
state: {
|
||||
// the systemd unit status is only relevant when connected to the local instance
|
||||
if (!plasmoid.local || !plasmoid.startStopEnabled) {
|
||||
return "irrelevant"
|
||||
}
|
||||
// show start/stop button only when the configured unit is available
|
||||
var service = plasmoid.service
|
||||
if (!service || !service.systemdAvailable) {
|
||||
return "irrelevant"
|
||||
}
|
||||
return service.running ? "running" : "stopped"
|
||||
}
|
||||
onClicked: plasmoid.service.toggleRunning()
|
||||
PlasmaComponents3.ToolTip {
|
||||
id: startStopToolTip
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+Shift+S"
|
||||
onActivated: {
|
||||
if (startStopButton.visible) {
|
||||
startStopButton.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: showNewNotifications
|
||||
icon.name: "emblem-warning"
|
||||
visible: plasmoid.notificationsAvailable
|
||||
onClicked: {
|
||||
plasmoid.showNotificationsDialog()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Show new notifications")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+N"
|
||||
onActivated: {
|
||||
if (showNewNotifications.visible) {
|
||||
showNewNotifications.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
icon.source: plasmoid.faUrl + "info"
|
||||
visible: showExtraButtons
|
||||
onClicked: {
|
||||
plasmoid.showAboutDialog()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("About Syncthing Tray")
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: showOwnIdButton
|
||||
icon.source: plasmoid.faUrl + "qrcode"
|
||||
visible: showExtraButtons
|
||||
onClicked: {
|
||||
plasmoid.showOwnDeviceId()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Show own device ID")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+I"
|
||||
onActivated: showOwnIdButton.clicked()
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: showLogButton
|
||||
icon.source: plasmoid.faUrl + "file-text"
|
||||
visible: showExtraButtons
|
||||
onClicked: {
|
||||
plasmoid.showLog()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Show Syncthing log")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+L"
|
||||
onActivated: showLogButton.clicked()
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: rescanAllDirsButton
|
||||
icon.source: plasmoid.faUrl + "refresh"
|
||||
onClicked: plasmoid.connection.rescanAllDirs()
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Rescan all directories")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+Shift+R"
|
||||
onActivated: rescanAllDirsButton.clicked()
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: settingsButton
|
||||
icon.source: plasmoid.faUrl + "cog"
|
||||
visible: showExtraButtons
|
||||
onClicked: {
|
||||
plasmoid.showSettingsDlg()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Settings")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+S"
|
||||
onActivated: settingsButton.clicked()
|
||||
}
|
||||
}
|
||||
ToolButton {
|
||||
id: webUIButton
|
||||
icon.source: plasmoid.faUrl + "syncthing"
|
||||
onClicked: {
|
||||
plasmoid.showWebUI()
|
||||
plasmoid.expanded = false
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: qsTr("Open Syncthing")
|
||||
}
|
||||
Shortcut {
|
||||
sequence: "Ctrl+W"
|
||||
onActivated: webUIButton.clicked()
|
||||
}
|
||||
}
|
||||
PlasmaComponents3.ComboBox {
|
||||
id: connectionConfigsMenu
|
||||
model: plasmoid.connectionConfigNames
|
||||
visible: plasmoid.connectionConfigNames.length > 1
|
||||
currentIndex: plasmoid.currentConnectionConfigIndex
|
||||
onCurrentIndexChanged: plasmoid.currentConnectionConfigIndex = currentIndex
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: implicitWidth
|
||||
Shortcut {
|
||||
sequence: "Ctrl+Shift+C"
|
||||
onActivated: connectionConfigsMenu.popup()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import QtQuick 2.8
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: root
|
||||
Layout.fillHeight: true
|
||||
contentItem: Grid {
|
||||
columns: 2
|
||||
columnSpacing: label.visible ? Kirigami.Units.smallSpacing : 0
|
||||
verticalItemAlignment: Grid.AlignVCenter
|
||||
PlasmaCore.ColorScope.inherit: true
|
||||
Image {
|
||||
source: root.icon.source
|
||||
cache: false
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
id: label
|
||||
visible: text.length > 0
|
||||
text: root.text
|
||||
color: PlasmaCore.ColorScope.textColor
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick 2.0
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
|
||||
MouseArea {
|
||||
property alias interval: timer.interval
|
||||
property alias tooltip: tooltip.text
|
||||
hoverEnabled: true
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 1000
|
||||
running: parent.containsMouse && parent.tooltip.length !== 0
|
||||
onTriggered: tooltip.open()
|
||||
}
|
||||
PlasmaComponents3.ToolTip {
|
||||
id: tooltip
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
id: tooltipIcon
|
||||
source: plasmoid.statusIcon
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: true
|
||||
implicitWidth: Kirigami.Units.iconSizes.large
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||
Layout.preferredWidth: implicitWidth
|
||||
Layout.preferredHeight: implicitWidth
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Kirigami.Heading {
|
||||
id: tooltipMaintext
|
||||
level: 3
|
||||
elide: Text.ElideRight
|
||||
text: plasmoid.statusText
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
id: tooltipSubtext
|
||||
text: plasmoid.additionalStatusText
|
||||
opacity: 0.6
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// Based on PlasmaComponents.ListItem from Plasma 5.44.0
|
||||
// (Can't use PlasmaComponents.ListItem itself because creating a MouseArea filling
|
||||
// the entire entire item for detecting right-mouse-click is not possible due to binding
|
||||
// loop of width and height properties.)
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.ksvg 1.0 as KSvg
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
id: listItem
|
||||
property bool expanded: false
|
||||
default property alias content: paddingItem.data
|
||||
|
||||
/**
|
||||
* If true makes the list item look as checked or pressed. It has to be set
|
||||
* from the code, it won't change by itself.
|
||||
*/
|
||||
//plasma extension
|
||||
//always look pressed?
|
||||
property bool checked: false
|
||||
|
||||
/**
|
||||
* If true the item will be a delegate for a section, so will look like a
|
||||
* "title" for the otems under it.
|
||||
*/
|
||||
//is this to be used as section delegate?
|
||||
property bool sectionDelegate: false
|
||||
|
||||
/**
|
||||
* type: bool
|
||||
* True if the separator between items is visible
|
||||
* default: true
|
||||
*/
|
||||
property bool separatorVisible: true
|
||||
|
||||
width: parent ? parent.width : childrenRect.width
|
||||
height: paddingItem.childrenRect.height + background.margins.top + background.margins.bottom
|
||||
|
||||
implicitHeight: paddingItem.childrenRect.height + background.margins.top
|
||||
+ background.margins.bottom
|
||||
|
||||
function activate(containsMouse) {
|
||||
view.activate(containsMouse ? index : -1)
|
||||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: background
|
||||
imagePath: "widgets/listitem"
|
||||
prefix: (listItem.sectionDelegate ? "section" : (itemMouse.pressed
|
||||
|| listItem.checked) ? "pressed" : "normal")
|
||||
|
||||
anchors.fill: parent
|
||||
visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Kirigami.Units.longDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
KSvg.SvgItem {
|
||||
svg: KSvg.Svg {
|
||||
imagePath: "widgets/listitem"
|
||||
}
|
||||
elementId: "separator"
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
}
|
||||
height: naturalSize.height
|
||||
visible: separatorVisible && (listItem.sectionDelegate
|
||||
|| (typeof (index) != "undefined"
|
||||
&& index > 0 && !listItem.checked
|
||||
&& !itemMouse.pressed))
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouse
|
||||
property bool changeBackgroundOnPress: !listItem.checked
|
||||
&& !listItem.sectionDelegate
|
||||
anchors.fill: background
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onClicked: function(mouse) {
|
||||
switch (mouse.button) {
|
||||
case Qt.LeftButton:
|
||||
expanded = !expanded
|
||||
break
|
||||
case Qt.RightButton:
|
||||
var view = listItem.ListView.view
|
||||
var coordinates = mapToItem(view, mouseX, mouseY)
|
||||
view.showContextMenu(listItem, coordinates.x, coordinates.y)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
listItem.activate(containsMouse)
|
||||
}
|
||||
|
||||
Item {
|
||||
id: paddingItem
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: background.margins.left
|
||||
topMargin: background.margins.top
|
||||
rightMargin: background.margins.right
|
||||
bottomMargin: background.margins.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.ListItem
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import QtQuick 2.7
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
ListView {
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
interactive: contentHeight > height
|
||||
keyNavigationEnabled: true
|
||||
keyNavigationWraps: true
|
||||
currentIndex: -1
|
||||
|
||||
highlightMoveDuration: 0
|
||||
highlightResizeDuration: 0
|
||||
highlight: PlasmaExtras.Highlight {
|
||||
}
|
||||
|
||||
topMargin: Kirigami.Units.smallSpacing * 2
|
||||
bottomMargin: Kirigami.Units.smallSpacing * 2
|
||||
leftMargin: Kirigami.Units.smallSpacing * 2
|
||||
rightMargin: Kirigami.Units.smallSpacing * 2
|
||||
|
||||
function effectiveWidth() {
|
||||
return width - leftMargin - rightMargin
|
||||
}
|
||||
|
||||
function activate(index) {
|
||||
if (typeof contextMenu !== "undefined"
|
||||
&& contextMenu.status !== PlasmaExtras.DialogStatus.Closed) {
|
||||
return
|
||||
}
|
||||
currentIndex = index
|
||||
}
|
||||
|
||||
function clickCurrentItemButton(buttonName) {
|
||||
if (!currentItem) {
|
||||
return
|
||||
}
|
||||
var button = currentItem[buttonName]
|
||||
if (button && button.enabled) {
|
||||
button.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
function copyCurrentItemData(fieldName) {
|
||||
if (!currentItem) {
|
||||
return
|
||||
}
|
||||
var data = currentItem[fieldName]
|
||||
if (data) {
|
||||
plasmoid.copyToClipboard(data)
|
||||
}
|
||||
}
|
||||
|
||||
function showContextMenu(item, x, y) {
|
||||
if (typeof contextMenu === "undefined") {
|
||||
return
|
||||
}
|
||||
if (typeof contextMenu.init !== "undefined") {
|
||||
contextMenu.init(item)
|
||||
}
|
||||
contextMenu.open(x, y)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
PlasmoidItem {
|
||||
id: syncthingApplet
|
||||
|
||||
// FIXME: adding title causes plasmawindowed to segfault
|
||||
//Plasmoid.title: "Syncthing"
|
||||
Plasmoid.icon: "syncthing"
|
||||
// FIXME: not sure whether assigning switchWidth/switchHeight like this works
|
||||
switchWidth: fullRepresentationItem ? fullRepresentationItem.Layout.minimumWidth : -1
|
||||
switchHeight: fullRepresentationItem ? fullRepresentationItem.Layout.minimumHeight : -1
|
||||
preferredRepresentation: fullRepresentation
|
||||
compactRepresentation: CompactRepresentation {}
|
||||
fullRepresentation: FullRepresentation {
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * Plasmoid.size.width
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * Plasmoid.size.height
|
||||
}
|
||||
toolTipMainText: Plasmoid.statusText
|
||||
toolTipSubText: Plasmoid.additionalStatusText
|
||||
toolTipItem: ToolTipView {}
|
||||
|
||||
Plasmoid.contextualActions: [
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Open Syncthing")
|
||||
icon.name: "syncthing"
|
||||
onTriggered: Plasmoid.showWebUI()
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Rescan all directories")
|
||||
icon.name: "folder-sync"
|
||||
onTriggered: Plasmoid.connection.rescanAllDirs()
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Show own device ID")
|
||||
icon.name: "view-barcode-qr"
|
||||
onTriggered: Plasmoid.showOwnDeviceId()
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Restart Syncthing")
|
||||
icon.name: "system-reboot"
|
||||
onTriggered: Plasmoid.connection.restart()
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Log")
|
||||
icon.name: "text-x-generic"
|
||||
onTriggered: Plasmoid.showLog()
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("Internal errors")
|
||||
icon.name: "data-error"
|
||||
onTriggered: Plasmoid.showInternalErrorsDialog()
|
||||
visible: Plasmoid.hasInternalErrors
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: qsTr("About")
|
||||
icon.name: "help-about"
|
||||
onTriggered: Plasmoid.showAboutDialog()
|
||||
}
|
||||
]
|
||||
|
||||
PlasmaCore.Action {
|
||||
id: configureAction
|
||||
text: qsTr("Settings")
|
||||
icon.name: "configure"
|
||||
onTriggered: Plasmoid.showSettingsDlg()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Plasmoid.initEngine(this)
|
||||
Plasmoid.setInternalAction("configure", configureAction)
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ source "$script_dir/settestenv.sh"
|
|||
|
||||
# use the package dir within the source-tree so one does not need to run CMake again for updating
|
||||
# build-tree copy all the time
|
||||
package_dir=$script_dir/../package
|
||||
package_dir=$script_dir/../$2
|
||||
|
||||
# copy the generated desktop file back into the source-tree package dir so it can actually be used
|
||||
meta_data_file=$1
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
# Testing and debugging Plasma 5 plasmoid with Qt Creator
|
||||
|
||||
# Testing and debugging Plasmoid for Plasma with Qt Creator
|
||||
The following instructions allow to test the Plasmoid by installing it in a test directory
|
||||
rather than the regular home to separate testing from production.
|
||||
|
||||
1. Build as usual, ensure `NO_PLASMOID` is turned off
|
||||
1. Build as usual, ensure `NO_PLASMOID` is turned off.
|
||||
2. Add build step to execute the custom target `init_plasmoid_testing` which
|
||||
will install the Plasmoid in a test directory which is `$CMAKE_BUILD_DIR/plasmoid-testing`
|
||||
by default (configurable via cache variable `PLASMOID_TESTDIR`, the sub directory
|
||||
`plasmoid-testing` is not part of the variable)
|
||||
3. Add new config for run in Qt Creator and set `bash` as executable
|
||||
`plasmoid-testing` is not part of the variable).
|
||||
3. Add new config for run in Qt Creator and set `bash` as executable.
|
||||
4. Set `%{sourceDir}/../../syncthingtray/plasmoid/scripts/starttesting.sh plasmoidviewer --applet martchus.syncthingplasmoid`
|
||||
as CLI argument
|
||||
as CLI argument.
|
||||
* It is also possible to use `plasmawindowed` or `plasmashell`, see sections below.
|
||||
* It is also possible to specify `org.kde.plasma.systemtray` as applet to test how the Plasmoid
|
||||
looks like within the system tray plasmoid.
|
||||
|
@ -21,12 +20,12 @@ rather than the regular home to separate testing from production.
|
|||
already take care of setting the environment.
|
||||
* The home directory is set in accordance with the directory used in step 2. but can be overridden
|
||||
by setting `TEST_HOME`; make sure that `TEST_HOME` and the CMake variable `PLASMOID_TESTDIR` are
|
||||
set in accordance
|
||||
set in accordance.
|
||||
* If not already set, `QT_PLUGIN_PATH` is set to `$CMAKE_CURRENT_BINARY_DIR/plasmoid/lib` which
|
||||
should contain the plugin for the Plasmoid under `plasma/applets/libsyncthingplasmoid.so`
|
||||
* Set `QT_DEBUG_PLUGINS` to 1 for verbose plugin detection
|
||||
7. Ignore warning that executable is no debug build, it is sufficiant when
|
||||
the plugin is a debug build (see next section for QML debugging)
|
||||
should contain the plugin for the Plasmoid under `plasma/applets/libsyncthingplasmoid.so`.
|
||||
* Set `QT_DEBUG_PLUGINS` to 1 for verbose plugin detection.
|
||||
7. Ignore warning that executable is no debug build, it is sufficient when
|
||||
the plugin is a debug build (see next section for QML debugging).
|
||||
|
||||
## Saving/restoring settings
|
||||
|
||||
|
@ -64,3 +63,18 @@ To create a debug build of `plasmoidviewer` manually:
|
|||
3. Prepend the build directory containing the `plasmoidviewer` binary to the path variable
|
||||
in the build environment of Syncthing Tray.
|
||||
4. Enable QML debugging in the *Run* section.
|
||||
|
||||
# Testing against a development build of Plasma
|
||||
1. Build the whole dependency chain up to `plasma-desktop` installing it under some custom prefix.
|
||||
Note that `plasma-sdk` alone is not sufficient.
|
||||
2. Then follow the usual steps but make sure you build Syncthing Tray against the custom KDE builds.
|
||||
This is achieved the easiest by using the `debug-kde` CMake preset. This preset uses the environment
|
||||
variable `KDE_INSTALL_DIR` which must point to the custom prefix used in step 1.
|
||||
3. Source the `prefix.sh` script that should be present in the build directory of any KDE library
|
||||
you built in step 1, e.g. `source kde/plasma-sdk/prefix.sh`.
|
||||
4. When setting the environment one needs to be more careful to not override variables set in step 3.
|
||||
It is the easiest to just start e.g. `plasmawindowed` from the shell:
|
||||
```
|
||||
QT_PLUGIN_PATH=$BUILD_DIR/syncthingtray/debug-kde/syncthingtray/plasmoid/lib:$QT_PLUGIN_PATH HOME=$BUILD_DIR/syncthingtray/debug-kde/plasmoid-testing kdeinstall/bin/plasmawindowed martchus.syncthingplasmoid-devel
|
||||
```
|
||||
* It would make sense to tweak `starttesting.sh` to be able to do the sourcing automatically.
|
||||
|
|
Loading…
Reference in New Issue