KCM.qml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * Copyright (C) 2015 Malte Veerman <malte.veerman@gmail.com>
  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: Fancontrol.base
  38. onNeedsApplyChanged: kcm.needsSave = Fancontrol.base.needsApply
  39. }
  40. Connections {
  41. target: kcm
  42. onAboutToSave: {
  43. Fancontrol.base.apply();
  44. }
  45. onAboutToLoad: {
  46. Fancontrol.base.load();
  47. enabledBox.checked = systemdCom.serviceActive;
  48. }
  49. onAboutToDefault: enabledBox.checked = false
  50. }
  51. ColumnLayout {
  52. id: noFansInfo
  53. width: parent.width
  54. anchors.verticalCenter: parent.verticalCenter
  55. spacing: 20
  56. visible: pwmFans.length === 0
  57. Label {
  58. Layout.alignment: Qt.AlignCenter
  59. text: i18n("There are no pwm capable fans in your system.")
  60. font.pointSize: 14
  61. font.bold: true
  62. }
  63. Button {
  64. Layout.alignment: Qt.AlignCenter
  65. text: loader.sensorsDetected ? i18n("Detect fans again") : i18n("Detect fans")
  66. iconName: kcm.needsAuthorization ? "dialog-password" : ""
  67. onClicked: loader.detectSensors()
  68. }
  69. }
  70. CheckBox {
  71. id: enabledBox
  72. anchors.top: parent.top
  73. visible: pwmFans.length > 0
  74. text: i18n("Control fans manually")
  75. checked: systemdCom.serviceEnabled && systemdCom.serviceActive;
  76. onCheckedChanged: {
  77. systemdCom.serviceActive = enabledBox.checked;
  78. loader.restartServiceAfterTesting = checked;
  79. autostartBox.checked = true;
  80. }
  81. Connections {
  82. target: systemdCom
  83. onServiceActiveChanged: if (systemdCom.serviceActive != enabledBox.checked) enabledBox.checked = systemdCom.serviceActive
  84. }
  85. }
  86. ColumnLayout {
  87. id: bodyLayout
  88. width: parent.width
  89. anchors.bottom: advancedButton.top
  90. anchors.top: enabledBox.bottom
  91. anchors.bottomMargin: advancedButton.height / 4
  92. visible: enabledBox.checked
  93. CheckBox {
  94. id: autostartBox
  95. text: i18n("Enable service at boot")
  96. checked: systemdCom.serviceEnabled
  97. onCheckedChanged: systemdCom.serviceEnabled = checked
  98. Connections {
  99. target: systemdCom
  100. onServiceEnabledChanged: if (systemdCom.serviceEnabled != autostartBox.checked) autostartBox.checked = systemdCom.serviceEnabled
  101. }
  102. }
  103. RowLayout {
  104. visible: enabledBox.checked && pwmFans.length > 0
  105. Label {
  106. text: i18n("Fan:")
  107. Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
  108. renderType: Text.NativeRendering
  109. }
  110. ComboBox {
  111. id: fanComboBox
  112. model: pwmFanModel
  113. textRole: "display"
  114. Layout.fillWidth: true
  115. Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
  116. }
  117. Button {
  118. Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
  119. text: i18n("Detect fans")
  120. iconName: kcm.needsAuthorization ? "dialog-password" : ""
  121. onClicked: loader.detectSensors()
  122. }
  123. }
  124. Loader {
  125. Layout.fillWidth: true
  126. Layout.fillHeight: true
  127. active: pwmFans.length > fanComboBox.currentIndex && fanComboBox.currentIndex >= 0
  128. sourceComponent: Fancontrol.FanItem {
  129. unit: Fancontrol.base.unit
  130. fan: pwmFans[fanComboBox.currentIndex]
  131. systemdCom: root.systemdCom
  132. tempModel: root.tempModel
  133. minTemp: Fancontrol.base.minTemp
  134. maxTemp: Fancontrol.base.maxTemp
  135. }
  136. }
  137. }
  138. Item {
  139. id: advancedButton
  140. property bool expanded: false
  141. anchors.bottom: settingsArea.top
  142. width: parent.width
  143. height: advancedArrow.height
  144. visible: enabledBox.checked
  145. Image {
  146. id: advancedArrow
  147. source: parent.expanded ? "image://icon/go-down" : "image://icon/go-next"
  148. fillMode: Image.PreserveAspectFit
  149. height: advancedLabel.implicitHeight
  150. }
  151. Label {
  152. id: advancedLabel
  153. anchors.left: advancedArrow.right
  154. text: i18n("Advanced settings")
  155. font.bold: true
  156. }
  157. MouseArea {
  158. anchors.fill: parent
  159. onClicked: parent.expanded = !parent.expanded
  160. }
  161. }
  162. ColumnLayout {
  163. id: settingsArea
  164. visible: enabledBox.checked && parent.height - enabledBox.height - bodyLayout.height - advancedButton.height > height
  165. width: parent.width
  166. anchors.bottom: parent.bottom
  167. clip: true
  168. state: advancedButton.expanded ? "VISIBLE" : "HIDDEN"
  169. states: [
  170. State {
  171. name: "VISIBLE"
  172. PropertyChanges {
  173. target: settingsArea
  174. height: settingsArea.implicitHeight
  175. }
  176. },
  177. State {
  178. name: "HIDDEN"
  179. PropertyChanges {
  180. target: settingsArea
  181. height: 0
  182. }
  183. }
  184. ]
  185. transitions: Transition {
  186. NumberAnimation {
  187. properties: "height"
  188. easing.type: Easing.InOutQuad
  189. }
  190. }
  191. RowLayout {
  192. width: parent.width
  193. Label {
  194. Layout.preferredWidth: root.textWidth
  195. clip: true
  196. text: i18n("Interval:")
  197. horizontalAlignment: Text.AlignRight
  198. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  199. }
  200. SpinBox {
  201. Layout.minimumWidth: implicitWidth
  202. Layout.fillWidth: true
  203. value: loader.interval
  204. suffix: " " + i18np("second", "seconds", loader.interval)
  205. minimumValue: 1.0
  206. onValueChanged: loader.interval = value
  207. }
  208. }
  209. RowLayout {
  210. width: parent.width
  211. Label {
  212. Layout.preferredWidth: root.textWidth
  213. clip: true
  214. text: i18n("Minimum temperature for fan graphs:")
  215. horizontalAlignment: Text.AlignRight
  216. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  217. }
  218. SpinBox {
  219. id: minTempBox
  220. Layout.minimumWidth: implicitWidth
  221. Layout.fillWidth: true
  222. decimals: 2
  223. maximumValue: maxTempBox.value
  224. minimumValue: Units.fromKelvin(0, Fancontrol.base.unit)
  225. value: Units.fromCelsius(Fancontrol.base.minTemp, Fancontrol.base.unit)
  226. suffix: Fancontrol.base.unit
  227. onValueChanged: Fancontrol.base.minTemp = Units.toCelsius(value, Fancontrol.base.unit)
  228. }
  229. }
  230. RowLayout {
  231. width: parent.width
  232. Label {
  233. Layout.preferredWidth: root.textWidth
  234. clip: true
  235. text: i18n("Maximum temperature for fan graphs:")
  236. horizontalAlignment: Text.AlignRight
  237. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  238. }
  239. SpinBox {
  240. id: maxTempBox
  241. Layout.minimumWidth: implicitWidth
  242. Layout.fillWidth: true
  243. decimals: 2
  244. maximumValue: Number.POSITIVE_INFINITY
  245. minimumValue: minTempBox.value
  246. value: Units.fromCelsius(Fancontrol.base.maxTemp, Fancontrol.base.unit)
  247. suffix: Fancontrol.base.unit
  248. onValueChanged: Fancontrol.base.maxTemp = Units.toCelsius(value, Fancontrol.base.unit)
  249. }
  250. }
  251. RowLayout {
  252. width: parent.width
  253. Label {
  254. Layout.preferredWidth: root.textWidth
  255. clip: true
  256. text: i18n("Name of the fancontrol systemd service:")
  257. horizontalAlignment: Text.AlignRight
  258. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  259. }
  260. Fancontrol.OptionInput {
  261. Layout.minimumWidth: implicitWidth
  262. Layout.fillWidth: true
  263. color: systemdCom.serviceExists ? "green" : "red"
  264. value: Fancontrol.base.serviceName
  265. onTextChanged: Fancontrol.base.serviceName = text
  266. }
  267. }
  268. RowLayout {
  269. width: parent.width
  270. Label {
  271. Layout.preferredWidth: root.textWidth
  272. clip: true
  273. text: i18n("Path to the fancontrol config file:")
  274. horizontalAlignment: Text.AlignRight
  275. Component.onCompleted: root.textWidth = Math.max(root.textWidth, contentWidth)
  276. }
  277. Fancontrol.OptionInput {
  278. Layout.minimumWidth: implicitWidth
  279. Layout.fillWidth: true
  280. value: Fancontrol.base.configUrl.toString().replace("file://", "")
  281. color: Fancontrol.base.configValid ? "green" : "red"
  282. onTextChanged: Fancontrol.base.configUrl = text
  283. }
  284. Button {
  285. action: loadAction
  286. }
  287. }
  288. }
  289. Action {
  290. id: loadAction
  291. iconName: "document-open"
  292. onTriggered: openFileDialog.open()
  293. tooltip: i18n("Load configuration file")
  294. shortcut: StandardKey.Open
  295. }
  296. FileDialog {
  297. id: openFileDialog
  298. title: i18n("Please choose a configuration file")
  299. folder: "file:///etc"
  300. selectExisting: true
  301. selectMultiple: false
  302. onAccepted: Fancontrol.base.configUrl = fileUrl;
  303. }
  304. Fancontrol.ErrorDialog {
  305. id: errorDialog
  306. modality: Qt.ApplicationModal
  307. }
  308. }