KCM.qml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright (C) 2015 Malte Veerman <maldela@halloarsch.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. */
  19. import QtQuick 2.4
  20. import QtQuick.Controls 1.3
  21. import QtQuick.Layouts 1.2
  22. import QtQuick.Dialogs 1.2
  23. import org.kde.kcm 1.0
  24. import Fancontrol.Qml 1.0 as Fancontrol
  25. Item {
  26. property QtObject loader: Fancontrol.base.loader
  27. property QtObject systemdCom: Fancontrol.base.systemdCom
  28. property QtObject pwmFanModel: Fancontrol.base.pwmFanModel
  29. property QtObject tempModel: Fancontrol.base.tempModel
  30. property var locale: Qt.locale()
  31. property real textWidth: 0
  32. property var pwmFans: pwmFanModel.fans
  33. id: root
  34. implicitWidth: 1024
  35. implicitHeight: 768
  36. Connections {
  37. target: loader
  38. onConfigFileChanged: kcm.needsSave = true
  39. }
  40. Connections {
  41. target: Fancontrol.base
  42. onMinTempChanged: kcm.needsSave = true
  43. onMaxTempChanged: kcm.needsSave = true
  44. onServiceNameChanged: kcm.needsSave = true
  45. onConfigUrlChanged: kcm.needsSave = true
  46. }
  47. Connections {
  48. target: kcm
  49. onAboutToSave: {
  50. Fancontrol.base.save(true);
  51. if (systemdCom.serviceActive && enabledBox.checked) {
  52. systemdCom.restartService();
  53. } else {
  54. systemdCom.serviceActive = enabledBox.checked;
  55. }
  56. systemdCom.serviceEnabled = enabledBox.checked;
  57. }
  58. onAboutToLoad: {
  59. Fancontrol.base.load();
  60. enabledBox.checked = systemdCom.serviceEnabled && systemdCom.serviceActive;
  61. }
  62. onAboutToDefault: enabledBox.checked = false
  63. }
  64. ColumnLayout {
  65. id: noFansInfo
  66. width: parent.width
  67. anchors.verticalCenter: parent.verticalCenter
  68. spacing: 20
  69. visible: pwmFans.length === 0
  70. Label {
  71. Layout.alignment: Qt.AlignCenter
  72. text: i18n("There are no pwm capable fans in your system.")
  73. font.pointSize: 14
  74. font.bold: true
  75. }
  76. Button {
  77. Layout.alignment: Qt.AlignCenter
  78. text: loader.sensorsDetected ? i18n("Detect fans again") : i18n("Detect fans")
  79. iconName: kcm.needsAuthorization ? "dialog-password" : ""
  80. onClicked: loader.detectSensors()
  81. }
  82. }
  83. CheckBox {
  84. id: enabledBox
  85. anchors.top: parent.top
  86. visible: pwmFans.length > 0
  87. text: i18n("Control fans manually")
  88. checked: systemdCom.serviceEnabled && systemdCom.serviceActive;
  89. onCheckedChanged: if (checked !== systemdCom.serviceActive || checked !== systemdCom.serviceEnabled) {
  90. kcm.needsSave = true;
  91. loader.restartServiceAfterTesting = checked;
  92. }
  93. }
  94. ColumnLayout {
  95. id: bodyLayout
  96. width: parent.width
  97. anchors.bottom: advancedButton.top
  98. anchors.top: enabledBox.bottom
  99. anchors.bottomMargin: advancedButton.height / 4
  100. visible: enabledBox.checked
  101. RowLayout {
  102. visible: enabledBox.checked && pwmFans.length > 0
  103. Label {
  104. text: i18n("Fan:")
  105. Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
  106. renderType: Text.NativeRendering
  107. }
  108. ComboBox {
  109. id: fanComboBox
  110. model: pwmFanModel
  111. textRole: "display"
  112. Layout.fillWidth: true
  113. Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
  114. }
  115. Button {
  116. Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
  117. text: i18n("Detect fans")
  118. iconName: kcm.needsAuthorization ? "dialog-password" : ""
  119. onClicked: loader.detectSensors()
  120. }
  121. }
  122. Loader {
  123. Layout.fillWidth: true
  124. Layout.fillHeight: true
  125. active: pwmFans.length > fanComboBox.currentIndex && fanComboBox.currentIndex >= 0
  126. sourceComponent: Fancontrol.FanItem {
  127. unit: Fancontrol.base.unit
  128. fan: pwmFans[fanComboBox.currentIndex]
  129. systemdCom: root.systemdCom
  130. tempModel: root.tempModel
  131. minTemp: Fancontrol.base.minTemp
  132. maxTemp: Fancontrol.base.maxTemp
  133. }
  134. }
  135. }
  136. Item {
  137. id: advancedButton
  138. property bool expanded: false
  139. anchors.bottom: settingsArea.top
  140. width: parent.width
  141. height: advancedArrow.height
  142. visible: enabledBox.checked
  143. Image {
  144. id: advancedArrow
  145. source: parent.expanded ? "image://icon/go-down" : "image://icon/go-next"
  146. fillMode: Image.PreserveAspectFit
  147. height: advancedLabel.implicitHeight
  148. }
  149. Label {
  150. id: advancedLabel
  151. anchors.left: advancedArrow.right
  152. text: i18n("Advanced settings")
  153. font.bold: true
  154. }
  155. MouseArea {
  156. anchors.fill: parent
  157. onClicked: parent.expanded = !parent.expanded
  158. }
  159. }
  160. ColumnLayout {
  161. id: settingsArea
  162. visible: enabledBox.checked && parent.height - enabledBox.height - bodyLayout.height - advancedButton.height > height
  163. width: parent.width
  164. anchors.bottom: parent.bottom
  165. clip: true
  166. state: advancedButton.expanded ? "VISIBLE" : "HIDDEN"
  167. states: [
  168. State {
  169. name: "VISIBLE"
  170. PropertyChanges {
  171. target: settingsArea
  172. height: settingsArea.implicitHeight
  173. }
  174. },
  175. State {
  176. name: "HIDDEN"
  177. PropertyChanges {
  178. target: settingsArea
  179. height: 0
  180. }
  181. }
  182. ]
  183. transitions: Transition {
  184. NumberAnimation {
  185. properties: "height"
  186. easing.type: Easing.InOutQuad
  187. }
  188. }
  189. RowLayout {
  190. width: parent.width
  191. Label {
  192. Layout.preferredWidth: root.textWidth
  193. clip: true
  194. text: i18n("Interval:")
  195. horizontalAlignment: Text.AlignRight
  196. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  197. }
  198. SpinBox {
  199. Layout.minimumWidth: implicitWidth
  200. Layout.fillWidth: true
  201. value: loader.interval
  202. suffix: " " + i18np("second", "seconds", loader.interval)
  203. minimumValue: 1.0
  204. onValueChanged: loader.interval = value
  205. }
  206. }
  207. RowLayout {
  208. width: parent.width
  209. Label {
  210. Layout.preferredWidth: root.textWidth
  211. clip: true
  212. text: i18n("Minimum temperature for fan graphs:")
  213. horizontalAlignment: Text.AlignRight
  214. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  215. }
  216. SpinBox {
  217. id: minTempBox
  218. Layout.minimumWidth: implicitWidth
  219. Layout.fillWidth: true
  220. decimals: 2
  221. maximumValue: maxTempBox.value
  222. minimumValue: Units.fromKelvin(0, Fancontrol.base.unit)
  223. value: Units.fromCelsius(Fancontrol.base.minTemp, Fancontrol.base.unit)
  224. suffix: Fancontrol.base.unit
  225. onValueChanged: Fancontrol.base.minTemp = Units.toCelsius(value, Fancontrol.base.unit)
  226. }
  227. }
  228. RowLayout {
  229. width: parent.width
  230. Label {
  231. Layout.preferredWidth: root.textWidth
  232. clip: true
  233. text: i18n("Maximum temperature for fan graphs:")
  234. horizontalAlignment: Text.AlignRight
  235. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  236. }
  237. SpinBox {
  238. id: maxTempBox
  239. Layout.minimumWidth: implicitWidth
  240. Layout.fillWidth: true
  241. decimals: 2
  242. maximumValue: Number.POSITIVE_INFINITY
  243. minimumValue: minTempBox.value
  244. value: Units.fromCelsius(Fancontrol.base.maxTemp, Fancontrol.base.unit)
  245. suffix: Fancontrol.base.unit
  246. onValueChanged: Fancontrol.base.maxTemp = Units.toCelsius(value, Fancontrol.base.unit)
  247. }
  248. }
  249. RowLayout {
  250. width: parent.width
  251. Label {
  252. Layout.preferredWidth: root.textWidth
  253. clip: true
  254. text: i18n("Name of the fancontrol systemd service:")
  255. horizontalAlignment: Text.AlignRight
  256. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  257. }
  258. Fancontrol.OptionInput {
  259. Layout.minimumWidth: implicitWidth
  260. Layout.fillWidth: true
  261. color: systemdCom.serviceExists ? "green" : "red"
  262. value: Fancontrol.base.serviceName
  263. onTextChanged: Fancontrol.base.serviceName = text
  264. }
  265. }
  266. RowLayout {
  267. width: parent.width
  268. Label {
  269. Layout.preferredWidth: root.textWidth
  270. clip: true
  271. text: i18n("Path to the fancontrol config file:")
  272. horizontalAlignment: Text.AlignRight
  273. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  274. }
  275. Fancontrol.OptionInput {
  276. Layout.minimumWidth: implicitWidth
  277. Layout.fillWidth: true
  278. text: Fancontrol.base.configUrl.toString().replace("file://", "")
  279. color: Fancontrol.base.configValid ? "green" : "red"
  280. onTextChanged: Fancontrol.base.configUrl = text
  281. }
  282. Button {
  283. action: loadAction
  284. }
  285. }
  286. }
  287. Action {
  288. id: loadAction
  289. iconName: "document-open"
  290. onTriggered: openFileDialog.open()
  291. tooltip: i18n("Load configuration file")
  292. shortcut: StandardKey.Open
  293. }
  294. FileDialog {
  295. id: openFileDialog
  296. title: i18n("Please choose a configuration file")
  297. folder: "file:///etc"
  298. selectExisting: true
  299. selectMultiple: false
  300. onAccepted: Fancontrol.base.configUrl = fileUrl;
  301. }
  302. Fancontrol.ErrorDialog {
  303. id: errorDialog
  304. modality: Qt.ApplicationModal
  305. }
  306. }