import QtQuick 2.15; import QtQuick.Window 2.0;
import Qt.labs.platform 1.1
import istamon.internal 1.0
import org.kde.kirigami 2.10 as Kirigami
import QtQuick.Layouts 1.3
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import QtQuick.Controls 2.15 as QQC2
import org.kde.kitemmodels 1.0
import QtQuick.Dialogs 1.0
Kirigami.ApplicationWindow {
id: window;
title: "Istamon"
width: Kirigami.Units.gridUnit * 28
// intial position at the center, 1/3 from the top
Component.onCompleted: {
x = Screen.width / 2 - width / 2
y = height / 4
}
WindowIcon {
window: window
icon_name: istamon.status_icon_name
}
globalDrawer: Kirigami.GlobalDrawer {
isMenu: true
actions: [
Kirigami.Action {
iconName: 'configure'
text: 'Configuration'
onTriggered: {
applicationWindow().pageStack.replace(startPage)
}
},
Kirigami.Action {
icon.name: "application-exit"
text: 'Quit'
shortcut: StandardKey.Quit
onTriggered: Qt.quit()
}
]
}
// Minimize on Escape and Close
Shortcut {
sequences: ["Escape"]
onActivated: window.showMinimized()
}
flags: Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowMinimizeButtonHint
pageStack.initialPage: startPage
Component {
id: startPage
Kirigami.ScrollablePage {
title: 'Configuration'
id: configPage
Kirigami.Action {
id: showServicesAction
onTriggered: {
if (cfg.isConfigured) {
applicationWindow().pageStack.replace(istamonPage)
}
}
}
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: shortcuts.home
onAccepted: {
caCertText.text = IstamonUtil.urlFileName(fileDialog.fileUrl)
}
}
Kirigami.Action {
id: updateCfgAction
onTriggered: {
if (cfg.isConfigured) {
let c = cfg.getCfg();
urlText.text = c.url
if (c.hasCredentials) {
wantCredentials.checked = true
userText.text = c.user
passwordText.text = c.password
if (c.savePasswordChoice == 'dontsave') {
passwordDontSave.checked = true
} else if (c.savePasswordChoice == 'encrypted') {
passwordEncrypted.checked = true
} else if (c.savePasswordChoice == 'unencrypted') {
passwordUnencrypted.checked = true
}
}
if (c.hasCaCert) {
wantCaCert.checked = true
caCertText.text = c.caCert
}
}
}
}
Kirigami.Action {
id: putCfgAction
onTriggered: {
let c = cfg.getCfg()
c.url = urlText.text
c.hasCredentials = wantCredentials.checked
c.user = userText.text
c.password = passwordText.text
if (passwordDontSave.checked) {
c.savePasswordChoice = "dontsave"
} else if (passwordEncrypted.checked) {
c.savePasswordChoice = "encrypted"
} else if (passwordUnencrypted.checked) {
c.savePasswordChoice = "unencrypted"
}
c.hasCaCert = wantCaCert.checked
c.caCert = caCertText.text
cfg.setCfg(c);
}
}
Connections {
target: cfg
function onCfgUpdated() {
updateCfgAction.trigger()
showServicesAction.trigger()
}
}
Component.onCompleted: {
updateCfgAction.trigger()
}
Kirigami.FormLayout {
Layout.fillHeight: true
// this item defines the preferred width of the entire form
Item {
Layout.preferredWidth: configPage.width * 0.7
}
QQC2.TextField {
id: urlText
placeholderText: "https://example.com:5665"
Kirigami.FormData.label: "Server URL:"
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
}
QQC2.CheckBox {
id: wantCredentials
Kirigami.FormData.label: 'Credentials'
}
QQC2.TextField {
id: userText
enabled: wantCredentials.checked
Kirigami.FormData.label: "User:"
}
Kirigami.ActionTextField {
id: passwordText
enabled: wantCredentials.checked
echoMode: TextInput.Password
rightActions: [
Kirigami.Action {
id: passwordTextShowAction
icon.name: "password-show-on"
onTriggered: {
if (passwordText.echoMode == TextInput.Password) {
passwordText.echoMode = TextInput.Normal
passwordTextShowAction.icon.name = 'password-show-off'
} else {
passwordText.echoMode = TextInput.Password
passwordTextShowAction.icon.name = 'password-show-on'
}
}
}
]
Kirigami.FormData.label: "Password: "
}
ColumnLayout {
Layout.rowSpan: 3
Kirigami.FormData.buddyFor: passwordUnencrypted
QQC2.RadioButton {
id: passwordDontSave
enabled: wantCredentials.checked
checked: true
text: "Don't save"
}
QQC2.RadioButton {
id: passwordEncrypted
enabled: cfg.hasPasswordManager() && wantCredentials.checked
text: "Save encrypted"
}
QQC2.RadioButton {
id: passwordUnencrypted
enabled: wantCredentials.checked
text: "Save unencrypted"
}
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
}
QQC2.CheckBox {
id: wantCaCert
Kirigami.FormData.label: "CA-Cert"
}
Kirigami.ActionTextField {
id: caCertText
// The label is not shown, but the layout breaks when it is missing.
// this is probably a bug in Kirigami
Kirigami.FormData.label: "CA-Cert Path: "
enabled: wantCaCert.checked
placeholderText: "/path/to/ca-cert.pem"
rightActions: [
Kirigami.Action {
icon.name: "document-open-folder"
onTriggered: {
fileDialog.visible = true;
}
}
]
}
}
footer: ColumnLayout {
RowLayout {
Layout.alignment: Qt.AlignRight
Layout.margins: Kirigami.Units.largeSpacing
QQC2.Button {
text: 'Apply'
onClicked: {
putCfgAction.trigger()
}
}
QQC2.Button {
icon.name: 'document-save'
text: 'Apply and Save'
onClicked: {
putCfgAction.trigger()
cfg.saveCfg()
}
}
}
}
}
}
IstamonCfg {
id: cfg
istamon: istamon
Component.onCompleted: {
if (isConfigured) {
applicationWindow().pageStack.initialPage = istamonPage
} else {
showConfigErrors()
applicationWindow().pageStack.initialPage = startPage
}
}
onNotification: msg => {
showPassiveNotification(msg)
}
}
Component {
id: istamonPage
Kirigami.ScrollablePage {
id: page
title: cfg.title
contextualActions : [
showHandledToggleAction
]
header: RowLayout {
// FIXME: does this have any effect?
spacing: Kirigami.Units.largeSpacing
QQC2.Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
horizontalAlignment: Qt.AlignRight
// FIXME: somehow this text determines the width of the whole ColumnLayout... why?
text: `DOWN: ${istamon.host_down_count - istamon.host_down_handled_count} (${istamon.host_down_handled_count})`
}
QQC2.Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
// FIXME: just a cludge
Layout.leftMargin: Kirigami.Units.gridUnit
text: `PROBLEMS: ${istamon.critical_count + istamon.warning_count + istamon.unknown_count - istamon.critical_handled_count - istamon.warning_handled_count - istamon.unknown_handled_count} (${istamon.critical_handled_count + istamon.warning_handled_count + istamon.unknown_handled_count })`
}
QQC2.Label {
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
// FIXME: just a cludge
Layout.leftMargin: Kirigami.Units.gridUnit * 2
horizontalAlignment: Qt.AlignRight
// FIXME: somehow this text determines the width of the whole ColumnLayout... why?
text: `${istamon.last_run}`
}
}
ListView {
id: listServices
Layout.fillWidth: true
model: servicesSearchSortFilterModel
delegate: Kirigami.AbstractListItem {
backgroundColor: Kirigami.Theme.backgroundColor
RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
width: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: width
Layout.alignment: Qt.AlignVCenter|Qt.AlignLeft
border.width:1
radius: Kirigami.Units.smallSpacing / 2
opacity: 0.7
color: {
if (isService) {
if (itemState === 2) {
return '#f56';
} else if (itemState === 1){
return '#fa4';
} else if (itemState === 0){
return '#4b7';
} else {
return "#a4f";
}
} else {
// host
if (itemState === 1) {
return '#f56';
} else if (itemState === 0) {
return '#4b7';
} else {
return "#a4f";
}
}
}
}
ColumnLayout {
Kirigami.Heading {
Layout.fillWidth: true
text: {
if (isService) {
return `${handled?'*':''}${hostName}: ${displayName}`
} else {
return `${handled?'*':''}Host ${hostName}`
}
}
level: 3
elide: Text.ElideRight
}
QQC2.Label {
text: lastCheckOutput
visible: isService
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.8
}
}
}
}
}
}
}
// Note: Just for reference... if we want to re-enable the systray icon at
// some point.
//
// SystemTrayIcon {
// visible: true
// icon.source: `qrc:///icons/${istamon.status_icon_name}`
// tooltip: "istamon"
//
// onActivated: {
// window.show()
// window.raise()
// window.requestActivate()
// }
//
// }
//
Kirigami.Action {
id: showHandledToggleAction
checkable: true
onCheckedChanged: servicesSearchSortFilterModel.invalidateFilter()
text: 'Show Handled'
}
IstamonListModel {
id: _istamonListModel
}
IstamonContainer {
id: istamon
list: _istamonListModel
}
KSortFilterProxyModel {
id: servicesSearchSortFilterModel
sourceModel: istamon.list
filterRowCallback: function(source_row, source_parent) {
let state = sourceModel.data(sourceModel.index(source_row, 0), istamon.get_role("itemState"));
let handled = sourceModel.data(sourceModel.index(source_row, 0), istamon.get_role("handled"))
let show = showHandledToggleAction.checked || !handled
return state != 0 && show;
}
}
}