diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cc657130..183b603c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -675,6 +675,8 @@ list(APPEND TRANSLATION_SOURCES ${VENUS_QML_MODULE_SOURCES}) list(APPEND VenusQMLModule_CPP_SOURCES src/aggregatedevicemodel.h src/aggregatedevicemodel.cpp + src/visibleitemmodel.h + src/visibleitemmodel.cpp src/basedevicemodel.h src/basedevicemodel.cpp src/theme.h diff --git a/components/PageGensetModel.qml b/components/PageGensetModel.qml index 5cfe56ed1..1cb4ff599 100644 --- a/components/PageGensetModel.qml +++ b/components/PageGensetModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix @@ -226,7 +226,7 @@ ObjectModel { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Speed" text: qsTrId("ac-in-genset_speed") @@ -345,7 +345,7 @@ ObjectModel { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSpinBox { //% "Charge voltage" text: qsTrId("genset_charge_voltage") diff --git a/components/listitems/ListChargeSchedule.qml b/components/listitems/ListChargeSchedule.qml index 25f669da9..c27137fb9 100644 --- a/components/listitems/ListChargeSchedule.qml +++ b/components/listitems/ListChargeSchedule.qml @@ -108,7 +108,7 @@ ListNavigation { id: scheduledOptionsPage GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: itemEnabled diff --git a/pages/ControlCardsPage.qml b/pages/ControlCardsPage.qml index d588e9509..b6bafcd2f 100644 --- a/pages/ControlCardsPage.qml +++ b/pages/ControlCardsPage.qml @@ -36,7 +36,7 @@ Page { maximumFlickVelocity: Theme.geometry_flickable_maximumFlickVelocity flickDeceleration: Theme.geometry_flickable_flickDeceleration - model: ObjectModel { + model: VisibleItemModel { Loader { active: systemType.value === "ESS" || systemType.value === "Hub-4" width: active ? root.cardWidth : -cardsView.spacing diff --git a/pages/SettingsPage.qml b/pages/SettingsPage.qml index 65be38cd7..447da9634 100644 --- a/pages/SettingsPage.qml +++ b/pages/SettingsPage.qml @@ -24,7 +24,7 @@ SwipeViewPage { id: settingsListView clip: true - model: ObjectModel { + model: VisibleItemModel { SettingsListNavigation { text: CommonWords.devices //% "All connected devices" diff --git a/pages/evcs/EvChargerPage.qml b/pages/evcs/EvChargerPage.qml index fbdaeafd8..171b11e95 100644 --- a/pages/evcs/EvChargerPage.qml +++ b/pages/evcs/EvChargerPage.qml @@ -16,7 +16,7 @@ Page { title: evCharger.name GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItemBackground { height: phaseTable.y + phaseTable.height diff --git a/pages/evcs/EvChargerSetupPage.qml b/pages/evcs/EvChargerSetupPage.qml index 0a5a4f777..a26d249e7 100644 --- a/pages/evcs/EvChargerSetupPage.qml +++ b/pages/evcs/EvChargerSetupPage.qml @@ -13,7 +13,7 @@ Page { required property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListEvChargerPositionRadioButtonGroup { dataItem.uid: root.bindPrefix + "/Position" } diff --git a/pages/invertercharger/OverviewInverterChargerPage.qml b/pages/invertercharger/OverviewInverterChargerPage.qml index 81b558053..84cc1df63 100644 --- a/pages/invertercharger/OverviewInverterChargerPage.qml +++ b/pages/invertercharger/OverviewInverterChargerPage.qml @@ -50,7 +50,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { id: modeListButton diff --git a/pages/settings/GeneratorCondition.qml b/pages/settings/GeneratorCondition.qml index 7f88cc731..3afa2ebeb 100644 --- a/pages/settings/GeneratorCondition.qml +++ b/pages/settings/GeneratorCondition.qml @@ -56,7 +56,7 @@ ListNavigation { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { text: root.enableDescription diff --git a/pages/settings/PageCanbusStatus.qml b/pages/settings/PageCanbusStatus.qml index b3b9351db..6dc0eb28a 100644 --- a/pages/settings/PageCanbusStatus.qml +++ b/pages/settings/PageCanbusStatus.qml @@ -93,7 +93,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListTextGroup { id: stateGroup diff --git a/pages/settings/PageDeviceInfo.qml b/pages/settings/PageDeviceInfo.qml index 98d4267f0..799bbc2be 100644 --- a/pages/settings/PageDeviceInfo.qml +++ b/pages/settings/PageDeviceInfo.qml @@ -16,7 +16,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Connection" text: qsTrId("settings_deviceinfo_connection") diff --git a/pages/settings/PageGenerator.qml b/pages/settings/PageGenerator.qml index 147c7070e..210b61a3b 100644 --- a/pages/settings/PageGenerator.qml +++ b/pages/settings/PageGenerator.qml @@ -45,7 +45,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: startStopModel ListSwitch { diff --git a/pages/settings/PageGeneratorAcLoad.qml b/pages/settings/PageGeneratorAcLoad.qml index b113e227e..091b75759 100644 --- a/pages/settings/PageGeneratorAcLoad.qml +++ b/pages/settings/PageGeneratorAcLoad.qml @@ -30,7 +30,7 @@ Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: enableSwitch diff --git a/pages/settings/PageGeneratorConditions.qml b/pages/settings/PageGeneratorConditions.qml index ad42f3069..462401bd7 100644 --- a/pages/settings/PageGeneratorConditions.qml +++ b/pages/settings/PageGeneratorConditions.qml @@ -33,7 +33,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: monitorService diff --git a/pages/settings/PageGeneratorRuntimeService.qml b/pages/settings/PageGeneratorRuntimeService.qml index fe230f6a8..d40bc596b 100644 --- a/pages/settings/PageGeneratorRuntimeService.qml +++ b/pages/settings/PageGeneratorRuntimeService.qml @@ -41,7 +41,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Total run time" diff --git a/pages/settings/PageGeneratorTestRun.qml b/pages/settings/PageGeneratorTestRun.qml index 7ca1f4e94..a6fd0f7ea 100644 --- a/pages/settings/PageGeneratorTestRun.qml +++ b/pages/settings/PageGeneratorTestRun.qml @@ -11,7 +11,7 @@ Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: enableSwitch diff --git a/pages/settings/PageGps.qml b/pages/settings/PageGps.qml index e3f35700c..edd348116 100644 --- a/pages/settings/PageGps.qml +++ b/pages/settings/PageGps.qml @@ -35,7 +35,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.status secondaryText: { diff --git a/pages/settings/PageHub4Debug.qml b/pages/settings/PageHub4Debug.qml index ecef95e1b..7cfccfc36 100644 --- a/pages/settings/PageHub4Debug.qml +++ b/pages/settings/PageHub4Debug.qml @@ -20,7 +20,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSpinBox { id: gridSetpoint diff --git a/pages/settings/PageRelayGenerator.qml b/pages/settings/PageRelayGenerator.qml index ad4b351c6..0f082f2c7 100644 --- a/pages/settings/PageRelayGenerator.qml +++ b/pages/settings/PageRelayGenerator.qml @@ -16,7 +16,7 @@ PageGenerator { model: !relayFunction.isValid || relayFunction.value === 1 ? startStopModel : disabledModel - ObjectModel { + VisibleItemModel { id: disabledModel ListItem { diff --git a/pages/settings/PageSettingsAcSystem.qml b/pages/settings/PageSettingsAcSystem.qml index cb2f87ce5..03d6f2b3c 100644 --- a/pages/settings/PageSettingsAcSystem.qml +++ b/pages/settings/PageSettingsAcSystem.qml @@ -34,7 +34,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: acInput1 diff --git a/pages/settings/PageSettingsAccessAndSecurity.qml b/pages/settings/PageSettingsAccessAndSecurity.qml index 3bb12a3d5..2056305ab 100644 --- a/pages/settings/PageSettingsAccessAndSecurity.qml +++ b/pages/settings/PageSettingsAccessAndSecurity.qml @@ -67,7 +67,7 @@ Page { id: settingsListView boundsBehavior: Flickable.DragOverBounds - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "Access level" text: qsTrId("settings_access_level") diff --git a/pages/settings/PageSettingsAlarmsAndFeedback.qml b/pages/settings/PageSettingsAlarmsAndFeedback.qml index 5488d2107..372f8e920 100644 --- a/pages/settings/PageSettingsAlarmsAndFeedback.qml +++ b/pages/settings/PageSettingsAlarmsAndFeedback.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListSwitch { //% "Audible alarm" text: qsTrId("settings_audible_alarm") diff --git a/pages/settings/PageSettingsBatteries.qml b/pages/settings/PageSettingsBatteries.qml index d39ab4443..10fead837 100644 --- a/pages/settings/PageSettingsBatteries.qml +++ b/pages/settings/PageSettingsBatteries.qml @@ -14,7 +14,7 @@ Page { title: CommonWords.batteries GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: batteryMonitorRadioButtons diff --git a/pages/settings/PageSettingsBatteryMeasurements.qml b/pages/settings/PageSettingsBatteryMeasurements.qml index 481d8279f..6db33c4d5 100644 --- a/pages/settings/PageSettingsBatteryMeasurements.qml +++ b/pages/settings/PageSettingsBatteryMeasurements.qml @@ -81,7 +81,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: root._visibleText //% "Active battery monitor" diff --git a/pages/settings/PageSettingsBleSensors.qml b/pages/settings/PageSettingsBleSensors.qml index 6d1df8282..85107b1f9 100644 --- a/pages/settings/PageSettingsBleSensors.qml +++ b/pages/settings/PageSettingsBleSensors.qml @@ -33,7 +33,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: enable text: CommonWords.enable diff --git a/pages/settings/PageSettingsBluetooth.qml b/pages/settings/PageSettingsBluetooth.qml index 069f2fbac..38e07cefb 100644 --- a/pages/settings/PageSettingsBluetooth.qml +++ b/pages/settings/PageSettingsBluetooth.qml @@ -11,7 +11,7 @@ Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: bluetoothEnabled diff --git a/pages/settings/PageSettingsCGwacs.qml b/pages/settings/PageSettingsCGwacs.qml index 25bf2521d..c92d596e0 100644 --- a/pages/settings/PageSettingsCGwacs.qml +++ b/pages/settings/PageSettingsCGwacs.qml @@ -29,7 +29,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { text: CommonWords.ac_input_role optionModel: Global.acInputs.roles.map(function(role) { diff --git a/pages/settings/PageSettingsCanbus.qml b/pages/settings/PageSettingsCanbus.qml index d6353c6ee..bbad89ea0 100644 --- a/pages/settings/PageSettingsCanbus.qml +++ b/pages/settings/PageSettingsCanbus.qml @@ -35,7 +35,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "CAN-bus profile" text: qsTrId("settings_canbus_profile") diff --git a/pages/settings/PageSettingsConnectivity.qml b/pages/settings/PageSettingsConnectivity.qml index bd1e062a3..e7eb90df7 100644 --- a/pages/settings/PageSettingsConnectivity.qml +++ b/pages/settings/PageSettingsConnectivity.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "Ethernet" text: qsTrId("pagesettingsconnectivity_ethernet") diff --git a/pages/settings/PageSettingsDisplayAndAppearance.qml b/pages/settings/PageSettingsDisplayAndAppearance.qml index e1f4b3591..b92c05f9f 100644 --- a/pages/settings/PageSettingsDisplayAndAppearance.qml +++ b/pages/settings/PageSettingsDisplayAndAppearance.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: autoBrightness diff --git a/pages/settings/PageSettingsDisplayMinMax.qml b/pages/settings/PageSettingsDisplayMinMax.qml index 4653d9719..753b15d30 100644 --- a/pages/settings/PageSettingsDisplayMinMax.qml +++ b/pages/settings/PageSettingsDisplayMinMax.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { //: Whether to adjust the min/max values in the range dynamically, based on the lowest and highest values observed on the system. //% "Auto-ranging" diff --git a/pages/settings/PageSettingsDisplayStartPage.qml b/pages/settings/PageSettingsDisplayStartPage.qml index a54365442..4aedb9bb6 100644 --- a/pages/settings/PageSettingsDisplayStartPage.qml +++ b/pages/settings/PageSettingsDisplayStartPage.qml @@ -30,7 +30,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { id: startPageNavigation //% "Start page" @@ -99,7 +99,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: startPageMode text: CommonWords.auto diff --git a/pages/settings/PageSettingsDisplayUnits.qml b/pages/settings/PageSettingsDisplayUnits.qml index d5e7fa17f..806ce4a9e 100644 --- a/pages/settings/PageSettingsDisplayUnits.qml +++ b/pages/settings/PageSettingsDisplayUnits.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { text: CommonWords.temperature optionModel: [ diff --git a/pages/settings/PageSettingsDvcc.qml b/pages/settings/PageSettingsDvcc.qml index f0e2dc64e..e1d739685 100644 --- a/pages/settings/PageSettingsDvcc.qml +++ b/pages/settings/PageSettingsDvcc.qml @@ -13,7 +13,7 @@ Page { GradientListView { id: dvccSettings - model: ObjectModel { + model: VisibleItemModel { PrimaryListLabel { //% "CAUTION: Read the manual before adjusting." text: qsTrId("settings_dvcc_instructions") diff --git a/pages/settings/PageSettingsDynamicEss.qml b/pages/settings/PageSettingsDynamicEss.qml index 49e58e0ee..d64b0468e 100644 --- a/pages/settings/PageSettingsDynamicEss.qml +++ b/pages/settings/PageSettingsDynamicEss.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: dEssMode text: CommonWords.mode diff --git a/pages/settings/PageSettingsEthernet.qml b/pages/settings/PageSettingsEthernet.qml index 97d31f100..03f382f81 100644 --- a/pages/settings/PageSettingsEthernet.qml +++ b/pages/settings/PageSettingsEthernet.qml @@ -14,7 +14,7 @@ Page { model: networkServices.ready ? connectedModel : disconnectedModel } - ObjectModel { + VisibleItemModel { id: disconnectedModel ListText { @@ -27,7 +27,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: connectedModel ListText { diff --git a/pages/settings/PageSettingsFirmware.qml b/pages/settings/PageSettingsFirmware.qml index aa1c57068..867566f3c 100644 --- a/pages/settings/PageSettingsFirmware.qml +++ b/pages/settings/PageSettingsFirmware.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListText { id: remotePort diff --git a/pages/settings/PageSettingsFirmwareOffline.qml b/pages/settings/PageSettingsFirmwareOffline.qml index c45c61430..75f8276d0 100644 --- a/pages/settings/PageSettingsFirmwareOffline.qml +++ b/pages/settings/PageSettingsFirmwareOffline.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListFirmwareCheckButton { //% "Check for updates on SD/USB" diff --git a/pages/settings/PageSettingsFirmwareOnline.qml b/pages/settings/PageSettingsFirmwareOnline.qml index 91585a64e..527020fda 100644 --- a/pages/settings/PageSettingsFirmwareOnline.qml +++ b/pages/settings/PageSettingsFirmwareOnline.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "Auto update" diff --git a/pages/settings/PageSettingsFronius.qml b/pages/settings/PageSettingsFronius.qml index d5968e6fc..909c62e64 100644 --- a/pages/settings/PageSettingsFronius.qml +++ b/pages/settings/PageSettingsFronius.qml @@ -24,7 +24,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "Inverters" text: qsTrId("page_settings_fronius_inverters") diff --git a/pages/settings/PageSettingsFroniusInverter.qml b/pages/settings/PageSettingsFroniusInverter.qml index 5d41ddd1d..7174056ac 100644 --- a/pages/settings/PageSettingsFroniusInverter.qml +++ b/pages/settings/PageSettingsFroniusInverter.qml @@ -25,7 +25,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListPvInverterPositionRadioButtonGroup { dataItem.uid: bindPrefix + "/Position" } diff --git a/pages/settings/PageSettingsGeneral.qml b/pages/settings/PageSettingsGeneral.qml index af18b73cb..8fafc52af 100644 --- a/pages/settings/PageSettingsGeneral.qml +++ b/pages/settings/PageSettingsGeneral.qml @@ -13,7 +13,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { SettingsListHeader { //% "System" text: qsTrId("pagesettingsgeneral_system") diff --git a/pages/settings/PageSettingsGenerator.qml b/pages/settings/PageSettingsGenerator.qml index 4bcdc7119..7dbd3b8c4 100644 --- a/pages/settings/PageSettingsGenerator.qml +++ b/pages/settings/PageSettingsGenerator.qml @@ -22,7 +22,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "Conditions" @@ -50,7 +50,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListSpinBox { //% "Warm-up time" text: qsTrId("page_settings_generator_warm_up_time") diff --git a/pages/settings/PageSettingsGpsList.qml b/pages/settings/PageSettingsGpsList.qml index 1b89a95de..2b3e5a6ad 100644 --- a/pages/settings/PageSettingsGpsList.qml +++ b/pages/settings/PageSettingsGpsList.qml @@ -74,7 +74,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //: Format of reported GPS data //% "Format" diff --git a/pages/settings/PageSettingsGsm.qml b/pages/settings/PageSettingsGsm.qml index 594f42dff..d1c2b2aa0 100644 --- a/pages/settings/PageSettingsGsm.qml +++ b/pages/settings/PageSettingsGsm.qml @@ -32,7 +32,7 @@ Page { model: simStatus.isValid ? modemConnected : notConnected - ObjectModel { + VisibleItemModel { id: notConnected ListItem { @@ -41,7 +41,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: modemConnected ListText { @@ -160,7 +160,7 @@ Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: useDefaultApn diff --git a/pages/settings/PageSettingsHub4.qml b/pages/settings/PageSettingsHub4.qml index da61be4a0..45d14c358 100644 --- a/pages/settings/PageSettingsHub4.qml +++ b/pages/settings/PageSettingsHub4.qml @@ -32,7 +32,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: essSettings ListRadioButtonGroup { diff --git a/pages/settings/PageSettingsHub4Feedin.qml b/pages/settings/PageSettingsHub4Feedin.qml index 1a3696006..ccb45cd60 100644 --- a/pages/settings/PageSettingsHub4Feedin.qml +++ b/pages/settings/PageSettingsHub4Feedin.qml @@ -12,7 +12,7 @@ Page { property int hub4Mode GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: acFeedin diff --git a/pages/settings/PageSettingsHub4Peakshaving.qml b/pages/settings/PageSettingsHub4Peakshaving.qml index bd08b2844..7bb04df59 100644 --- a/pages/settings/PageSettingsHub4Peakshaving.qml +++ b/pages/settings/PageSettingsHub4Peakshaving.qml @@ -42,7 +42,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "Peak shaving" text: qsTrId("settings_ess_peak_shaving") diff --git a/pages/settings/PageSettingsIntegrations.qml b/pages/settings/PageSettingsIntegrations.qml index cf057c9e2..1a5af2c6b 100644 --- a/pages/settings/PageSettingsIntegrations.qml +++ b/pages/settings/PageSettingsIntegrations.qml @@ -12,7 +12,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListNavigation { text: CommonWords.add_device icon.source: "qrc:/images/icon_plus_32.svg" diff --git a/pages/settings/PageSettingsIo.qml b/pages/settings/PageSettingsIo.qml index 9f1d7b666..1d413ad2a 100644 --- a/pages/settings/PageSettingsIo.qml +++ b/pages/settings/PageSettingsIo.qml @@ -25,7 +25,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "Analog inputs" diff --git a/pages/settings/PageSettingsLarge.qml b/pages/settings/PageSettingsLarge.qml index 8a9d839ac..f4a8db8ff 100644 --- a/pages/settings/PageSettingsLarge.qml +++ b/pages/settings/PageSettingsLarge.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { } } diff --git a/pages/settings/PageSettingsLogger.qml b/pages/settings/PageSettingsLogger.qml index 853372365..83c4b5c25 100644 --- a/pages/settings/PageSettingsLogger.qml +++ b/pages/settings/PageSettingsLogger.qml @@ -31,7 +31,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: vrmPortalMode diff --git a/pages/settings/PageSettingsModbus.qml b/pages/settings/PageSettingsModbus.qml index 975608aaa..320a97e78 100644 --- a/pages/settings/PageSettingsModbus.qml +++ b/pages/settings/PageSettingsModbus.qml @@ -26,7 +26,7 @@ Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { text: CommonWords.automatic_scanning dataItem.uid: root.settings + "/AutoScan" diff --git a/pages/settings/PageSettingsModbusAddDevice.qml b/pages/settings/PageSettingsModbusAddDevice.qml index ac9b0fba3..4cb4df066 100644 --- a/pages/settings/PageSettingsModbusAddDevice.qml +++ b/pages/settings/PageSettingsModbusAddDevice.qml @@ -21,7 +21,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: protocol diff --git a/pages/settings/PageSettingsModbusDevices.qml b/pages/settings/PageSettingsModbusDevices.qml index c4080d93e..97b89be92 100644 --- a/pages/settings/PageSettingsModbusDevices.qml +++ b/pages/settings/PageSettingsModbusDevices.qml @@ -39,7 +39,7 @@ Page { //% "No Modbus devices saved" text: qsTrId("settings_modbus_no_devices_saved") } - model: ObjectModel { + model: VisibleItemModel { Column { width: parent ? parent.width : 0 diff --git a/pages/settings/PageSettingsModbusTcp.qml b/pages/settings/PageSettingsModbusTcp.qml index 7ff5dc913..f60304049 100644 --- a/pages/settings/PageSettingsModbusTcp.qml +++ b/pages/settings/PageSettingsModbusTcp.qml @@ -22,7 +22,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: enableModbusTcp diff --git a/pages/settings/PageSettingsNodeRed.qml b/pages/settings/PageSettingsNodeRed.qml index 804668342..1f4415d08 100644 --- a/pages/settings/PageSettingsNodeRed.qml +++ b/pages/settings/PageSettingsNodeRed.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: nodered diff --git a/pages/settings/PageSettingsRelay.qml b/pages/settings/PageSettingsRelay.qml index d0d463d85..0b6cbca9a 100644 --- a/pages/settings/PageSettingsRelay.qml +++ b/pages/settings/PageSettingsRelay.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: relayFunction diff --git a/pages/settings/PageSettingsRelayTempSensors.qml b/pages/settings/PageSettingsRelayTempSensors.qml index 65ca1127b..1faf0e06a 100644 --- a/pages/settings/PageSettingsRelayTempSensors.qml +++ b/pages/settings/PageSettingsRelayTempSensors.qml @@ -87,7 +87,7 @@ Page { ? tempRelayModel : disabledModel - ObjectModel { + VisibleItemModel { id: tempRelayModel ListSwitch { @@ -113,7 +113,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: disabledModel PrimaryListLabel { diff --git a/pages/settings/PageSettingsRootfsSelect.qml b/pages/settings/PageSettingsRootfsSelect.qml index 51d8fe8f3..9bef6725e 100644 --- a/pages/settings/PageSettingsRootfsSelect.qml +++ b/pages/settings/PageSettingsRootfsSelect.qml @@ -45,7 +45,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { PrimaryListLabel { //% "This option allows you to switch between the current and the previous firmware version. No internet or sdcard needed." text: qsTrId("settings_firmware_version_switch_option") diff --git a/pages/settings/PageSettingsRvcDevice.qml b/pages/settings/PageSettingsRvcDevice.qml index 26fa8fe39..efb21ccb8 100644 --- a/pages/settings/PageSettingsRvcDevice.qml +++ b/pages/settings/PageSettingsRvcDevice.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.model_name diff --git a/pages/settings/PageSettingsRvcDeviceConfiguration.qml b/pages/settings/PageSettingsRvcDeviceConfiguration.qml index c22ac670f..4f83ea314 100644 --- a/pages/settings/PageSettingsRvcDeviceConfiguration.qml +++ b/pages/settings/PageSettingsRvcDeviceConfiguration.qml @@ -27,7 +27,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSpinBox { //% "Charger instance" text: qsTrId("settings_rvc_charger_instance") diff --git a/pages/settings/PageSettingsSystem.qml b/pages/settings/PageSettingsSystem.qml index cfe8e4b00..537cbe206 100644 --- a/pages/settings/PageSettingsSystem.qml +++ b/pages/settings/PageSettingsSystem.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: systemNameRadioButtons diff --git a/pages/settings/PageSettingsSystemStatus.qml b/pages/settings/PageSettingsSystemStatus.qml index 82ab5eca1..bc9d8f4c6 100644 --- a/pages/settings/PageSettingsSystemStatus.qml +++ b/pages/settings/PageSettingsSystemStatus.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Synchronize VE.Bus SOC with battery" text: qsTrId("settings_system_status_sync_vebus_soc_with_battery") diff --git a/pages/settings/PageSettingsTailscale.qml b/pages/settings/PageSettingsTailscale.qml index 2e69fc326..a02867eb8 100644 --- a/pages/settings/PageSettingsTailscale.qml +++ b/pages/settings/PageSettingsTailscale.qml @@ -161,7 +161,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: switchTailscaleEnabled @@ -250,7 +250,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { //% "Access local ethernet network" text: qsTrId("settings_tailscale_local_network_access_ethernet") @@ -307,7 +307,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListTextField { //% "Custom \"tailscale up\" arguments" text: qsTrId("settings_tailscale_advanced_custom_tailscale_up_arguments") diff --git a/pages/settings/PageSettingsTankPump.qml b/pages/settings/PageSettingsTankPump.qml index 802b81d67..3f390c559 100644 --- a/pages/settings/PageSettingsTankPump.qml +++ b/pages/settings/PageSettingsTankPump.qml @@ -30,7 +30,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: disabledModel PrimaryListLabel { @@ -39,7 +39,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: startStopModel ListText { diff --git a/pages/settings/PageSettingsTcpIp.qml b/pages/settings/PageSettingsTcpIp.qml index 2f6941b00..ae7e56f71 100644 --- a/pages/settings/PageSettingsTcpIp.qml +++ b/pages/settings/PageSettingsTcpIp.qml @@ -115,7 +115,7 @@ Page { model: root.ready ? connectedModel : disconnectedModel } - ObjectModel { + VisibleItemModel { id: disconnectedModel ListText { @@ -128,7 +128,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: connectedModel ListText { diff --git a/pages/settings/PageSettingsVecanDevice.qml b/pages/settings/PageSettingsVecanDevice.qml index 0c83b7b0f..13485ba96 100644 --- a/pages/settings/PageSettingsVecanDevice.qml +++ b/pages/settings/PageSettingsVecanDevice.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.model_name diff --git a/pages/settings/PageSettingsVrm.qml b/pages/settings/PageSettingsVrm.qml index 62e44915d..d6986030e 100644 --- a/pages/settings/PageSettingsVrm.qml +++ b/pages/settings/PageSettingsVrm.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "VRM Portal mode" text: qsTrId("settings_vrm_portal_mode") diff --git a/pages/settings/PageTzInfo.qml b/pages/settings/PageTzInfo.qml index 5d3e0ff8a..1db8b8ffb 100644 --- a/pages/settings/PageTzInfo.qml +++ b/pages/settings/PageTzInfo.qml @@ -80,7 +80,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Date/Time UTC" diff --git a/pages/settings/debug/PageDebug.qml b/pages/settings/debug/PageDebug.qml index 9a3497159..308d23a63 100644 --- a/pages/settings/debug/PageDebug.qml +++ b/pages/settings/debug/PageDebug.qml @@ -10,7 +10,7 @@ Page { id: root GradientListView { - model: ObjectModel { + model: VisibleItemModel { component SwitchItem : ListItem { id: switchItem diff --git a/pages/settings/debug/PagePowerDebug.qml b/pages/settings/debug/PagePowerDebug.qml index 387b27957..33fc9ee1f 100644 --- a/pages/settings/debug/PagePowerDebug.qml +++ b/pages/settings/debug/PagePowerDebug.qml @@ -73,7 +73,7 @@ Page { // in a D-Bus format. model: BackendConnection.type === BackendConnection.MqttSource ? invalidModel : validModel - ObjectModel { + VisibleItemModel { id: invalidModel PrimaryListLabel { @@ -81,7 +81,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: validModel ListTextGroup { diff --git a/pages/settings/debug/PageSettingsDemo.qml b/pages/settings/debug/PageSettingsDemo.qml index 1f6446800..c54f115c8 100644 --- a/pages/settings/debug/PageSettingsDemo.qml +++ b/pages/settings/debug/PageSettingsDemo.qml @@ -13,7 +13,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { PrimaryListLabel { text: "This page demonstrates the components that can be used to build settings pages." } @@ -24,6 +24,11 @@ Page { onClicked: Global.pageManager.pushPage(newPageComponent, { title: "Page name" }) } + ListNavigation { + text: "VisibleItemModel demo" + onClicked: Global.pageManager.pushPage(visibleItemDemoComponent, { title: text }) + } + ListSwitch { text: "Switch" property bool value @@ -340,7 +345,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { text: "New page item" } @@ -348,4 +353,59 @@ Page { } } } + + Component { + id: visibleItemDemoComponent + + Page { + component VisibleModelSwitch : ListSwitch { + preferredVisible: true + checked: preferredVisible + onClicked: preferredVisible = !preferredVisible + } + + GradientListView { + header: PrimaryListLabel { + text: "VisibleItemModel filters out any non-visible items from the model.\nFor example, click a switch below to set preferredVisible=false and remove it from the model." + } + footer: Column { + width: parent.width + PrimaryListLabel { + horizontalAlignment: Text.AlignHCenter + text: "%1 items in source model, %2 items in visible model" + .arg(visibleItemModel.sourceModel.length) + .arg(visibleItemModel.count) + } + ListItemButton { + anchors.horizontalCenter: parent.horizontalCenter + text: "Reset 'preferredVisible' values" + onClicked: { + toggle1.preferredVisible = true + toggle2.preferredVisible = true + toggle3.preferredVisible = true + } + } + } + + model: VisibleItemModel { + id: visibleItemModel + + VisibleModelSwitch { + id: toggle1 + text: "Toggle A" + } + + VisibleModelSwitch { + id: toggle2 + text: "Toggle B" + } + + VisibleModelSwitch { + id: toggle3 + text: "Toggle C" + } + } + } + } + } } diff --git a/pages/settings/debug/PageSystemData.qml b/pages/settings/debug/PageSystemData.qml index c5768be69..4ebdd3507 100644 --- a/pages/settings/debug/PageSystemData.qml +++ b/pages/settings/debug/PageSystemData.qml @@ -22,7 +22,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListTextGroup { text: "PV On ACIn1" textModel: [ diff --git a/pages/settings/devicelist/PageAcCharger.qml b/pages/settings/devicelist/PageAcCharger.qml index 239d8839a..80c5ea100 100644 --- a/pages/settings/devicelist/PageAcCharger.qml +++ b/pages/settings/devicelist/PageAcCharger.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { text: CommonWords.switch_mode dataItem.uid: root.bindPrefix + "/Mode" diff --git a/pages/settings/devicelist/PageDigitalInput.qml b/pages/settings/devicelist/PageDigitalInput.qml index 069f14804..07b8195c4 100644 --- a/pages/settings/devicelist/PageDigitalInput.qml +++ b/pages/settings/devicelist/PageDigitalInput.qml @@ -20,7 +20,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.state dataItem.uid: root.bindPrefix + "/State" @@ -40,7 +40,7 @@ Page { readonly property string settingsBindPrefix: Global.systemSettings.serviceUid + "/Settings/DigitalInput/" + (deviceInstance.value || 0) GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { id: alarmSwitch //% "Enable alarm" diff --git a/pages/settings/devicelist/PageMeteo.qml b/pages/settings/devicelist/PageMeteo.qml index 8dd7a5c8b..987effcdd 100644 --- a/pages/settings/devicelist/PageMeteo.qml +++ b/pages/settings/devicelist/PageMeteo.qml @@ -30,7 +30,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { property var displayText: Units.getDisplayText(VenusOS.Units_WattsPerSquareMeter, dataItem.value, 1) diff --git a/pages/settings/devicelist/PageMeteoSettings.qml b/pages/settings/devicelist/PageMeteoSettings.qml index d98a16111..51adc8db4 100644 --- a/pages/settings/devicelist/PageMeteoSettings.qml +++ b/pages/settings/devicelist/PageMeteoSettings.qml @@ -18,7 +18,7 @@ Page { ] GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "Wind speed sensor" text: qsTrId("page_meteo_settings_wind_speed_sensor") diff --git a/pages/settings/devicelist/PageMotorDrive.qml b/pages/settings/devicelist/PageMotorDrive.qml index d62a6e65c..58b508d17 100644 --- a/pages/settings/devicelist/PageMotorDrive.qml +++ b/pages/settings/devicelist/PageMotorDrive.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Motor RPM" text: qsTrId("devicelist_motordrive_motorrpm") diff --git a/pages/settings/devicelist/PageUnsupportedDevice.qml b/pages/settings/devicelist/PageUnsupportedDevice.qml index 19160a900..3d94953a1 100644 --- a/pages/settings/devicelist/PageUnsupportedDevice.qml +++ b/pages/settings/devicelist/PageUnsupportedDevice.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Unsupported device found" text: qsTrId("devicelist_unsupporteddevices_found") diff --git a/pages/settings/devicelist/ac-in/PageAcInModel.qml b/pages/settings/devicelist/ac-in/PageAcInModel.qml index 04cb1be65..d879c7955 100644 --- a/pages/settings/devicelist/ac-in/PageAcInModel.qml +++ b/pages/settings/devicelist/ac-in/PageAcInModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix diff --git a/pages/settings/devicelist/ac-in/PageAcInSetup.qml b/pages/settings/devicelist/ac-in/PageAcInSetup.qml index 86f1d6bda..9e910f9ad 100644 --- a/pages/settings/devicelist/ac-in/PageAcInSetup.qml +++ b/pages/settings/devicelist/ac-in/PageAcInSetup.qml @@ -73,7 +73,7 @@ Page { GradientListView { id: settingsListView - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: role diff --git a/pages/settings/devicelist/ac-in/PageSmappeeCTSetup.qml b/pages/settings/devicelist/ac-in/PageSmappeeCTSetup.qml index 2afdf20fe..122a60341 100644 --- a/pages/settings/devicelist/ac-in/PageSmappeeCTSetup.qml +++ b/pages/settings/devicelist/ac-in/PageSmappeeCTSetup.qml @@ -29,7 +29,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: type diff --git a/pages/settings/devicelist/battery/BatterySettingsAlarmModel.qml b/pages/settings/devicelist/battery/BatterySettingsAlarmModel.qml index feb56c49b..21562a415 100644 --- a/pages/settings/devicelist/battery/BatterySettingsAlarmModel.qml +++ b/pages/settings/devicelist/battery/BatterySettingsAlarmModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix diff --git a/pages/settings/devicelist/battery/BatterySettingsRelayModel.qml b/pages/settings/devicelist/battery/BatterySettingsRelayModel.qml index 380adc9fb..70d490dfb 100644 --- a/pages/settings/devicelist/battery/BatterySettingsRelayModel.qml +++ b/pages/settings/devicelist/battery/BatterySettingsRelayModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix diff --git a/pages/settings/devicelist/battery/Page48TlDiagnostics.qml b/pages/settings/devicelist/battery/Page48TlDiagnostics.qml index ac2ebbe05..148eecf73 100644 --- a/pages/settings/devicelist/battery/Page48TlDiagnostics.qml +++ b/pages/settings/devicelist/battery/Page48TlDiagnostics.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { //% "Status LEDs" text: qsTrId("batterydiagnostics_status_leds") diff --git a/pages/settings/devicelist/battery/PageBattery.qml b/pages/settings/devicelist/battery/PageBattery.qml index fbd860e1f..eac1cd38b 100644 --- a/pages/settings/devicelist/battery/PageBattery.qml +++ b/pages/settings/devicelist/battery/PageBattery.qml @@ -21,7 +21,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { text: CommonWords.switch_mode dataItem.uid: root.bindPrefix + "/Mode" diff --git a/pages/settings/devicelist/battery/PageBatteryAlarms.qml b/pages/settings/devicelist/battery/PageBatteryAlarms.qml index 23ec476fe..9d3759d8d 100644 --- a/pages/settings/devicelist/battery/PageBatteryAlarms.qml +++ b/pages/settings/devicelist/battery/PageBatteryAlarms.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListAlarm { text: CommonWords.low_battery_voltage dataItem.uid: root.bindPrefix + "/Alarms/LowVoltage" diff --git a/pages/settings/devicelist/battery/PageBatteryDetails.qml b/pages/settings/devicelist/battery/PageBatteryDetails.qml index c5480ba97..9c7593263 100644 --- a/pages/settings/devicelist/battery/PageBatteryDetails.qml +++ b/pages/settings/devicelist/battery/PageBatteryDetails.qml @@ -13,7 +13,7 @@ Page { property BatteryDetails details GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantityGroup { //% "Lowest cell voltage" text: qsTrId("batterydetails_lowest_cell_voltage") diff --git a/pages/settings/devicelist/battery/PageBatteryHistory.qml b/pages/settings/devicelist/battery/PageBatteryHistory.qml index 1ecf94dde..b46d7dde2 100644 --- a/pages/settings/devicelist/battery/PageBatteryHistory.qml +++ b/pages/settings/devicelist/battery/PageBatteryHistory.qml @@ -13,7 +13,7 @@ Page { required property BatteryHistory history GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Deepest discharge" text: qsTrId("batteryalarms_deepest_discharge") diff --git a/pages/settings/devicelist/battery/PageBatteryParameters.qml b/pages/settings/devicelist/battery/PageBatteryParameters.qml index 355c442de..0ca08fded 100644 --- a/pages/settings/devicelist/battery/PageBatteryParameters.qml +++ b/pages/settings/devicelist/battery/PageBatteryParameters.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Charge Voltage Limit (CVL)" text: qsTrId("batteryparameters_charge_voltage_limit_cvl") diff --git a/pages/settings/devicelist/battery/PageBatterySettings.qml b/pages/settings/devicelist/battery/PageBatterySettings.qml index 169139783..99b2c14cf 100644 --- a/pages/settings/devicelist/battery/PageBatterySettings.qml +++ b/pages/settings/devicelist/battery/PageBatterySettings.qml @@ -32,7 +32,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { //% "Battery bank" text: qsTrId("batterysettings_battery_bank") diff --git a/pages/settings/devicelist/battery/PageBatterySettingsBattery.qml b/pages/settings/devicelist/battery/PageBatterySettingsBattery.qml index 6afdba2ef..e83becc1c 100644 --- a/pages/settings/devicelist/battery/PageBatterySettingsBattery.qml +++ b/pages/settings/devicelist/battery/PageBatterySettingsBattery.qml @@ -18,7 +18,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { //% "Nominal Voltage" text: qsTrId("batterysettingsbattery_nominal_voltage") diff --git a/pages/settings/devicelist/battery/PageLynxIonDiagnostics.qml b/pages/settings/devicelist/battery/PageLynxIonDiagnostics.qml index fa02a57cb..b83e52f2f 100644 --- a/pages/settings/devicelist/battery/PageLynxIonDiagnostics.qml +++ b/pages/settings/devicelist/battery/PageLynxIonDiagnostics.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Shutdowns due error" text: qsTrId("lynxiondiagnostics_shutdowns_due_error") diff --git a/pages/settings/devicelist/battery/PageLynxIonIo.qml b/pages/settings/devicelist/battery/PageLynxIonIo.qml index 5b2d89d45..443958b03 100644 --- a/pages/settings/devicelist/battery/PageLynxIonIo.qml +++ b/pages/settings/devicelist/battery/PageLynxIonIo.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "System Switch" text: qsTrId("lynxionio_system_switch") diff --git a/pages/settings/devicelist/battery/PageLynxIonSystem.qml b/pages/settings/devicelist/battery/PageLynxIonSystem.qml index a9469c356..466c1ab0e 100644 --- a/pages/settings/devicelist/battery/PageLynxIonSystem.qml +++ b/pages/settings/devicelist/battery/PageLynxIonSystem.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Capacity" text: qsTrId("lynxionsystem_capacity") diff --git a/pages/settings/devicelist/dc-in/PageAlternatorModel.qml b/pages/settings/devicelist/dc-in/PageAlternatorModel.qml index 4c1fb1984..fd16bdb5c 100644 --- a/pages/settings/devicelist/dc-in/PageAlternatorModel.qml +++ b/pages/settings/devicelist/dc-in/PageAlternatorModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix @@ -113,7 +113,7 @@ ObjectModel { model: overallHistoryModel } - ObjectModel { + VisibleItemModel { id: overallHistoryModel ListText { diff --git a/pages/settings/devicelist/dc-in/PageDcDcConverter.qml b/pages/settings/devicelist/dc-in/PageDcDcConverter.qml index e0b3d95c1..777317c64 100644 --- a/pages/settings/devicelist/dc-in/PageDcDcConverter.qml +++ b/pages/settings/devicelist/dc-in/PageDcDcConverter.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { text: CommonWords.switch_mode dataItem.uid: root.bindPrefix + "/Mode" diff --git a/pages/settings/devicelist/dc-in/PageDcMeterAlarms.qml b/pages/settings/devicelist/dc-in/PageDcMeterAlarms.qml index 03ff39a42..d4b90f892 100644 --- a/pages/settings/devicelist/dc-in/PageDcMeterAlarms.qml +++ b/pages/settings/devicelist/dc-in/PageDcMeterAlarms.qml @@ -23,7 +23,7 @@ Page { && !highTemp.visible } - model: ObjectModel { + model: VisibleItemModel { ListAlarm { id: lowVoltage diff --git a/pages/settings/devicelist/dc-in/PageDcMeterHistory.qml b/pages/settings/devicelist/dc-in/PageDcMeterHistory.qml index 57b4a3ab6..0d3520366 100644 --- a/pages/settings/devicelist/dc-in/PageDcMeterHistory.qml +++ b/pages/settings/devicelist/dc-in/PageDcMeterHistory.qml @@ -25,7 +25,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { text: CommonWords.minimum_voltage dataItem.uid: root.bindPrefix + "/History/MinimumVoltage" diff --git a/pages/settings/devicelist/dc-in/PageDcMeterModel.qml b/pages/settings/devicelist/dc-in/PageDcMeterModel.qml index 0576dc734..11766b270 100644 --- a/pages/settings/devicelist/dc-in/PageDcMeterModel.qml +++ b/pages/settings/devicelist/dc-in/PageDcMeterModel.qml @@ -6,7 +6,7 @@ import QtQuick import Victron.VenusOS -ObjectModel { +VisibleItemModel { id: root property string bindPrefix diff --git a/pages/settings/devicelist/inverter/PageInverter.qml b/pages/settings/devicelist/inverter/PageInverter.qml index 2b1a71246..25489dc10 100644 --- a/pages/settings/devicelist/inverter/PageInverter.qml +++ b/pages/settings/devicelist/inverter/PageInverter.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { id: modeListButton diff --git a/pages/settings/devicelist/inverter/PageSolarStats.qml b/pages/settings/devicelist/inverter/PageSolarStats.qml index 67f6b8225..1729337e6 100644 --- a/pages/settings/devicelist/inverter/PageSolarStats.qml +++ b/pages/settings/devicelist/inverter/PageSolarStats.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Maximum PV voltage" text: qsTrId("inverter_maximum_pv_voltage") diff --git a/pages/settings/devicelist/pulsemeter/PagePulseCounter.qml b/pages/settings/devicelist/pulsemeter/PagePulseCounter.qml index 1d0c86aa1..41bf7ecca 100644 --- a/pages/settings/devicelist/pulsemeter/PagePulseCounter.qml +++ b/pages/settings/devicelist/pulsemeter/PagePulseCounter.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListQuantity { //% "Aggregate" text: qsTrId("pulsecounter_aggregate") diff --git a/pages/settings/devicelist/pulsemeter/PagePulseCounterSetup.qml b/pages/settings/devicelist/pulsemeter/PagePulseCounterSetup.qml index 5d02a7d24..17b07b6fc 100644 --- a/pages/settings/devicelist/pulsemeter/PagePulseCounterSetup.qml +++ b/pages/settings/devicelist/pulsemeter/PagePulseCounterSetup.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListVolumeUnitRadioButtonGroup {} ListSwitch { diff --git a/pages/settings/devicelist/rs/PageMultiRs.qml b/pages/settings/devicelist/rs/PageMultiRs.qml index 3a602fde3..d9b3c1559 100644 --- a/pages/settings/devicelist/rs/PageMultiRs.qml +++ b/pages/settings/devicelist/rs/PageMultiRs.qml @@ -46,7 +46,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.state secondaryText: Global.system.systemStateToText(dataItem.value) diff --git a/pages/settings/devicelist/rs/PageRsSystem.qml b/pages/settings/devicelist/rs/PageRsSystem.qml index e1a3a21ec..f8b10020c 100644 --- a/pages/settings/devicelist/rs/PageRsSystem.qml +++ b/pages/settings/devicelist/rs/PageRsSystem.qml @@ -25,7 +25,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { id: modeListButton diff --git a/pages/settings/devicelist/rs/PageRsSystemAlarms.qml b/pages/settings/devicelist/rs/PageRsSystemAlarms.qml index e279d72a0..6359e16c6 100644 --- a/pages/settings/devicelist/rs/PageRsSystemAlarms.qml +++ b/pages/settings/devicelist/rs/PageRsSystemAlarms.qml @@ -17,7 +17,7 @@ Page { uid: root.bindPrefix + "/Ac/NumberOfPhases" } - ObjectModel { + VisibleItemModel { id: validAlarmsModel VeBusAlarm { @@ -52,7 +52,7 @@ Page { } } - ObjectModel { + VisibleItemModel { id: noAlarmsModel PrimaryListLabel { diff --git a/pages/settings/devicelist/rs/PageRsSystemEss.qml b/pages/settings/devicelist/rs/PageRsSystemEss.qml index 3c14b2abc..965159628 100644 --- a/pages/settings/devicelist/rs/PageRsSystemEss.qml +++ b/pages/settings/devicelist/rs/PageRsSystemEss.qml @@ -27,7 +27,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { id: essMode text: CommonWords.mode diff --git a/pages/settings/devicelist/tank/PageTankAlarm.qml b/pages/settings/devicelist/tank/PageTankAlarm.qml index 3e8477491..a9d0ab48e 100644 --- a/pages/settings/devicelist/tank/PageTankAlarm.qml +++ b/pages/settings/devicelist/tank/PageTankAlarm.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSwitch { //% "Enable alarm" text: qsTrId("devicelist_tankalarm_enable_alarm") diff --git a/pages/settings/devicelist/tank/PageTankSensor.qml b/pages/settings/devicelist/tank/PageTankSensor.qml index e2ebe1e28..1664510e2 100644 --- a/pages/settings/devicelist/tank/PageTankSensor.qml +++ b/pages/settings/devicelist/tank/PageTankSensor.qml @@ -19,7 +19,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.status dataItem.uid: root.bindPrefix + "/Status" diff --git a/pages/settings/devicelist/tank/PageTankSetup.qml b/pages/settings/devicelist/tank/PageTankSetup.qml index a025cab70..c55bf347c 100644 --- a/pages/settings/devicelist/tank/PageTankSetup.qml +++ b/pages/settings/devicelist/tank/PageTankSetup.qml @@ -13,7 +13,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListSpinBox { //% "Capacity" text: qsTrId("devicelist_tanksetup_capacity") diff --git a/pages/settings/devicelist/temperature/PageTemperatureSensor.qml b/pages/settings/devicelist/temperature/PageTemperatureSensor.qml index a8c6e48f3..01b273917 100644 --- a/pages/settings/devicelist/temperature/PageTemperatureSensor.qml +++ b/pages/settings/devicelist/temperature/PageTemperatureSensor.qml @@ -29,7 +29,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.status dataItem.uid: root.bindPrefix + "/Status" diff --git a/pages/settings/devicelist/temperature/PageTemperatureSensorSetup.qml b/pages/settings/devicelist/temperature/PageTemperatureSensorSetup.qml index 2cd04647d..388f5fc2b 100644 --- a/pages/settings/devicelist/temperature/PageTemperatureSensorSetup.qml +++ b/pages/settings/devicelist/temperature/PageTemperatureSensorSetup.qml @@ -22,7 +22,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListRadioButtonGroup { text: CommonWords.type dataItem.uid: bindPrefix + "/TemperatureType" diff --git a/pages/solar/PvInverterPage.qml b/pages/solar/PvInverterPage.qml index 42bbab0f5..ba6527337 100644 --- a/pages/solar/PvInverterPage.qml +++ b/pages/solar/PvInverterPage.qml @@ -14,7 +14,7 @@ Page { title: pvInverter.name GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItemBackground { height: phaseTable.y + phaseTable.height diff --git a/pages/solar/SolarChargerAlarmsAndErrorsPage.qml b/pages/solar/SolarChargerAlarmsAndErrorsPage.qml index a2c267dc2..e8fbe9840 100644 --- a/pages/solar/SolarChargerAlarmsAndErrorsPage.qml +++ b/pages/solar/SolarChargerAlarmsAndErrorsPage.qml @@ -15,7 +15,7 @@ Page { GradientListView { id: chargerListView - model: ObjectModel { + model: VisibleItemModel { PrimaryListLabel { preferredVisible: lowBatteryAlarm.visible || highBatteryAlarm.visible || highTemperatureAlarm.visible || shortCircuitAlarm.visible leftPadding: 0 diff --git a/pages/solar/SolarChargerNetworkedOperationPage.qml b/pages/solar/SolarChargerNetworkedOperationPage.qml index 1a6277a80..b964bb1f0 100644 --- a/pages/solar/SolarChargerNetworkedOperationPage.qml +++ b/pages/solar/SolarChargerNetworkedOperationPage.qml @@ -15,7 +15,7 @@ Page { GradientListView { id: chargerListView - model: ObjectModel { + model: VisibleItemModel { ListText { id: networkModeEnabled //% "Networked" diff --git a/pages/solar/SolarChargerPage.qml b/pages/solar/SolarChargerPage.qml index 2054d8901..89b9c3700 100644 --- a/pages/solar/SolarChargerPage.qml +++ b/pages/solar/SolarChargerPage.qml @@ -16,7 +16,7 @@ Page { title: solarCharger.name GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItemBackground { height: trackerTable.y + trackerTable.height diff --git a/pages/vebusdevice/PageAcSensor.qml b/pages/vebusdevice/PageAcSensor.qml index 70b0f8263..e4c07216e 100644 --- a/pages/vebusdevice/PageAcSensor.qml +++ b/pages/vebusdevice/PageAcSensor.qml @@ -13,7 +13,7 @@ Page { property int index GradientListView { - model: ObjectModel { + model: VisibleItemModel { Column { width: parent ? parent.width : 0 diff --git a/pages/vebusdevice/PageAcSensors.qml b/pages/vebusdevice/PageAcSensors.qml index 6e5b0eebb..3c9e4c101 100644 --- a/pages/vebusdevice/PageAcSensors.qml +++ b/pages/vebusdevice/PageAcSensors.qml @@ -12,7 +12,7 @@ Page { property string bindPrefix GradientListView { - model: ObjectModel { + model: VisibleItemModel { Column { width: parent ? parent.width : 0 diff --git a/pages/vebusdevice/PageVeBus.qml b/pages/vebusdevice/PageVeBus.qml index b28badeb0..000fd9afd 100644 --- a/pages/vebusdevice/PageVeBus.qml +++ b/pages/vebusdevice/PageVeBus.qml @@ -67,7 +67,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListItem { id: modeListButton @@ -174,7 +174,7 @@ Page { onTriggered: Global.pageManager.popPage() } - model: ObjectModel { + model: VisibleItemModel { ListItem { text: { var message = "" diff --git a/pages/vebusdevice/PageVeBusAdvanced.qml b/pages/vebusdevice/PageVeBusAdvanced.qml index 83e853995..9e677a21f 100644 --- a/pages/vebusdevice/PageVeBusAdvanced.qml +++ b/pages/vebusdevice/PageVeBusAdvanced.qml @@ -78,7 +78,7 @@ Page { GradientListView { id: gradientListView - model: ObjectModel { + model: VisibleItemModel { ListButton { property bool interrupt: vebusSubState.value === VenusOS.VeBusDevice_ChargeState_Equalize @@ -260,7 +260,7 @@ Page { Page { GradientListView { - model: ObjectModel { + model: VisibleItemModel { Column { width: parent ? parent.width : 0 diff --git a/pages/vebusdevice/PageVeBusAlarms.qml b/pages/vebusdevice/PageVeBusAlarms.qml index 8b5970a21..05a9bbcf4 100644 --- a/pages/vebusdevice/PageVeBusAlarms.qml +++ b/pages/vebusdevice/PageVeBusAlarms.qml @@ -23,7 +23,7 @@ Page { title: CommonWords.alarm_status GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.vebus_error diff --git a/pages/vebusdevice/PageVeBusBms.qml b/pages/vebusdevice/PageVeBusBms.qml index ba2cd757c..d38125259 100644 --- a/pages/vebusdevice/PageVeBusBms.qml +++ b/pages/vebusdevice/PageVeBusBms.qml @@ -13,7 +13,7 @@ Page { property int bmsType GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { text: CommonWords.allow_to_charge secondaryText: CommonWords.yesOrNo(dataItem.value) diff --git a/pages/vebusdevice/PageVeBusDebug.qml b/pages/vebusdevice/PageVeBusDebug.qml index 5933a7196..234f78fea 100644 --- a/pages/vebusdevice/PageVeBusDebug.qml +++ b/pages/vebusdevice/PageVeBusDebug.qml @@ -36,7 +36,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListNavigation { text: CommonWords.ac_sensors diff --git a/pages/vebusdevice/PageVeBusError11Device.qml b/pages/vebusdevice/PageVeBusError11Device.qml index cb9b7aa7c..4b19ed800 100644 --- a/pages/vebusdevice/PageVeBusError11Device.qml +++ b/pages/vebusdevice/PageVeBusError11Device.qml @@ -26,7 +26,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "Last VE.Bus Error 11 report #%1" diff --git a/pages/vebusdevice/PageVeBusError11View.qml b/pages/vebusdevice/PageVeBusError11View.qml index 0996f057b..c67bc50d0 100644 --- a/pages/vebusdevice/PageVeBusError11View.qml +++ b/pages/vebusdevice/PageVeBusError11View.qml @@ -18,7 +18,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { PrimaryListLabel { //% "VE.Bus Error 11 reporting requires minimum VE.Bus firmware version 454." diff --git a/pages/vebusdevice/PageVeBusKwhCounters.qml b/pages/vebusdevice/PageVeBusKwhCounters.qml index c1ad50915..972b66cd0 100644 --- a/pages/vebusdevice/PageVeBusKwhCounters.qml +++ b/pages/vebusdevice/PageVeBusKwhCounters.qml @@ -13,7 +13,7 @@ Page { property var service GradientListView { - model: ObjectModel { + model: VisibleItemModel { ListText { //% "VE.Bus Quirks" diff --git a/pages/vebusdevice/PageVeBusSerialNumbers.qml b/pages/vebusdevice/PageVeBusSerialNumbers.qml index 66a5f2253..d9946fef0 100644 --- a/pages/vebusdevice/PageVeBusSerialNumbers.qml +++ b/pages/vebusdevice/PageVeBusSerialNumbers.qml @@ -30,7 +30,7 @@ Page { } GradientListView { - model: ObjectModel { + model: VisibleItemModel { Column { width: parent ? parent.width : 0 diff --git a/src/visibleitemmodel.cpp b/src/visibleitemmodel.cpp new file mode 100644 index 000000000..7f96b3fc9 --- /dev/null +++ b/src/visibleitemmodel.cpp @@ -0,0 +1,242 @@ +/* +** Copyright (C) 2025 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +#include "visibleitemmodel.h" + +#include +#include +#include + +using namespace Victron::VenusOS; + + +class VisibleItemModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(VisibleItemModel) +public: + VisibleItemModelPrivate() + : QObjectPrivate() {} + + static void sourceModel_append(QQmlListProperty *prop, QObject *object) { + static_cast(prop->data)->append(object); + } + + static qsizetype sourceModel_count(QQmlListProperty *prop) { + auto d = static_cast(prop->data); + return d->allObjects.count(); + } + + static QObject *sourceModel_at(QQmlListProperty *prop, qsizetype index) { + auto d = static_cast(prop->data); + return d->allObjects.value(index); + } + + static void sourceModel_clear(QQmlListProperty *prop) { + static_cast(prop->data)->clear(); + } + + static void sourceModel_removeLast(QQmlListProperty *prop) { + static_cast(prop->data)->removeLast(); + } + + void append(QObject *object) { + Q_Q(VisibleItemModel); + allObjects.append(object); + + if (QQuickItem *item = qobject_cast(object)) { + const QVariant preferredVisible = item->property("preferredVisible"); + if (preferredVisible.isValid()) { + QObject::connect(item, SIGNAL(preferredVisibleChanged()), q, SLOT(preferredVisibleChanged())); + } + // Add the item to the visible item list, if preferredVisible=true, or if it has no + // preferredVisible property and thus should not be filtered out. + preferredVisibleChanged(item, !preferredVisible.isValid() || preferredVisible.toBool()); + } + + emit q->sourceModelChanged(); + } + + void removeLast() { + Q_Q(VisibleItemModel); + if (allObjects.count() > 0) { + QObject *last = allObjects.takeLast(); + last->disconnect(q); + const int visibleItemIndex = visibleItems.indexOf(last); + if (visibleItemIndex >= 0) { + QQmlChangeSet changeSet; + changeSet.remove(visibleItemIndex, 1); + visibleItems.removeAt(visibleItemIndex); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); + } + emit q->sourceModelChanged(); + } + } + + void clear() { + Q_Q(VisibleItemModel); + if (!allObjects.isEmpty()) { + for (const QObject *object : allObjects) { + object->disconnect(q); + } + allObjects.clear(); + if (!visibleItems.isEmpty()) { + QQmlChangeSet changeSet; + changeSet.remove(0, visibleItems.count()); + visibleItems.clear(); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); + } + emit q->sourceModelChanged(); + } + } + + void preferredVisibleChanged(QQuickItem *item, bool preferredVisible) { + Q_Q(VisibleItemModel); + + if (preferredVisible) { + const int insertionIndex = visibleInsertionIndex(item); + if (insertionIndex >= 0) { + QQmlChangeSet changeSet; + changeSet.insert(insertionIndex, 1); + visibleItems.insert(insertionIndex, item); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); + } + } else { + const int removalIndex = visibleItems.indexOf(item); + if (removalIndex >= 0) { + QQmlChangeSet changeSet; + changeSet.remove(removalIndex, 1); + visibleItems.removeAt(removalIndex); + emit q->modelUpdated(changeSet, false); + emit q->countChanged(); + } + } + } + + /* + Returns the index at which an item should be inserted into visibleItems. + Returns -1 if the index should not be inserted. + */ + int visibleInsertionIndex(QQuickItem *item) { + if (!item || visibleItems.indexOf(item) >= 0) { + return -1; + } + + // In the overall list: find the last item that is visible before this one. + const int overallIndex = allObjects.indexOf(item); + if (overallIndex < 0) { + return -1; + } + QObject *prevVisibleItem = nullptr; + for (int i = overallIndex - 1; i >= 0 && i < allObjects.count(); --i) { + if (QQuickItem *previousItem = qobject_cast(allObjects.at(i))) { + const QVariant preferredVisible = previousItem->property("preferredVisible"); + if (!preferredVisible.isValid() || preferredVisible.toBool()) { + prevVisibleItem = previousItem; + break; + } + } + } + + // In the visible items list: find the index of that previous visible item. + if (prevVisibleItem) { + const int prevVisibleIndex = visibleItems.indexOf(prevVisibleItem); + if (prevVisibleIndex >= 0) { + // Insert the new item after that previous visible item. + return prevVisibleIndex + 1; + } + } + // There is no previous visible item, so this must be the first visible item. + return 0; + } + + QVector allObjects; + QVector visibleItems; +}; + +VisibleItemModel::VisibleItemModel(QObject *parent) + : QQmlInstanceModel(*(new VisibleItemModelPrivate), parent) +{ +} + +QQmlListProperty VisibleItemModel::sourceModel() +{ + Q_D(VisibleItemModel); + return QQmlListProperty(this, d, + VisibleItemModelPrivate::sourceModel_append, + VisibleItemModelPrivate::sourceModel_count, + VisibleItemModelPrivate::sourceModel_at, + VisibleItemModelPrivate::sourceModel_clear, + nullptr, + VisibleItemModelPrivate::sourceModel_removeLast); +} + +QObject* VisibleItemModel::get(int index) +{ + return object(index, QQmlIncubator::Synchronous); +} + +int VisibleItemModel::count() const +{ + Q_D(const VisibleItemModel); + return d->visibleItems.count(); +} + +bool VisibleItemModel::isValid() const +{ + return true; +} + +QObject *VisibleItemModel::object(int index, QQmlIncubator::IncubationMode) +{ + Q_D(VisibleItemModel); + if (index < 0 || index >= d->visibleItems.count()) { + return nullptr; + } + return d->visibleItems.at(index); +} + +QQmlInstanceModel::ReleaseFlags VisibleItemModel::release(QObject *, ReusableFlag) +{ + // Always return Referenced flag. Otherwise, when a view sees the item is no longer referenced, + // it will unparent the item. + return QQmlInstanceModel::Referenced; +} + +QVariant VisibleItemModel::variantValue(int index, const QString &role) +{ + Q_D(VisibleItemModel); + if (index < 0 || index >= d->visibleItems.count()) { + return QVariant(); + } + return d->visibleItems.at(index)->property(role.toUtf8().constData()); +} + +QQmlIncubator::Status VisibleItemModel::incubationStatus(int) +{ + // The model does not internally create objects, so any referenced objects are always available. + return QQmlIncubator::Ready; +} + +int VisibleItemModel::indexOf(QObject *item, QObject *context) const +{ + Q_D(const VisibleItemModel); + for (int i = 0; i < d->visibleItems.count(); ++i) { + if (d->visibleItems.at(i) == item) { + return i; + } + } + return -1; +} + +void VisibleItemModel::preferredVisibleChanged() +{ + Q_D(VisibleItemModel); + if (QQuickItem *item = qobject_cast(sender())) { + d->preferredVisibleChanged(item, item->property("preferredVisible").toBool()); + } +} diff --git a/src/visibleitemmodel.h b/src/visibleitemmodel.h new file mode 100644 index 000000000..8226a8287 --- /dev/null +++ b/src/visibleitemmodel.h @@ -0,0 +1,73 @@ +/* +** Copyright (C) 2025 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +#ifndef VISIBLEITEMMODEL_H +#define VISIBLEITEMMODEL_H + +#include +#include + +class VisibleItemModelPrivate; + +namespace Victron { +namespace VenusOS { + +/* + Provides an instance model that filters out non-visible items from the specified source model. + + If any item in the source model has preferredVisible=false, then it is filtered out of the + instance model, and thus will not be loaded in any view that uses the model. Non-items are also + filtered out of the model. + + The sourceModel is the default property, so items can be declared directly as children, + similarly to how ObjectModel is used: + + ListView { + // Make a VisibleItemModel with two source items + model: VisibleItemModel { + ListItem { preferredVisible: false } // this item will not be loaded by the view + ListItem {} // this item will be loaded by the view + } + } +*/ +class VisibleItemModel : public QQmlInstanceModel +{ + Q_OBJECT + Q_DECLARE_PRIVATE(VisibleItemModel) + + Q_PROPERTY(QQmlListProperty sourceModel READ sourceModel NOTIFY sourceModelChanged DESIGNABLE false FINAL) + Q_CLASSINFO("DefaultProperty", "sourceModel") + QML_ELEMENT + +public: + explicit VisibleItemModel(QObject *parent = nullptr); + + Q_INVOKABLE QObject* get(int index); + + int count() const override; + bool isValid() const override; + QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override; + ReleaseFlags release(QObject *object, ReusableFlag reusable = NotReusable) override; + QVariant variantValue(int index, const QString &role) override; + void setWatchedRoles(const QList &) override {} + QQmlIncubator::Status incubationStatus(int index) override; + + int indexOf(QObject *object, QObject *context) const override; + + QQmlListProperty sourceModel(); + +Q_SIGNALS: + void sourceModelChanged(); + +private: + Q_DISABLE_COPY(VisibleItemModel) + + Q_INVOKABLE void preferredVisibleChanged(); +}; + +} /* VenusOS */ +} /* Victron */ + +#endif // VISIBLEITEMMODEL_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0fd803a30..c00ebb768 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,3 +20,4 @@ add_subdirectory(firmwareversion) add_subdirectory(units) add_subdirectory(screenblanker) add_subdirectory(backendconnection) +add_subdirectory(visibleitemmodel) diff --git a/tests/visibleitemmodel/CMakeLists.txt b/tests/visibleitemmodel/CMakeLists.txt new file mode 100644 index 000000000..daa7414a9 --- /dev/null +++ b/tests/visibleitemmodel/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# Copyright (C) 2024 Victron Energy B.V. +# See LICENSE.txt for license information. +# + +cmake_minimum_required(VERSION 3.16) +project(tst_visibleitemmodel LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml QuickTest Quick) + +qt_add_executable(tst_visibleitemmodel + tst_visibleitemmodel.cpp + ../../src/visibleitemmodel.h + ../../src/visibleitemmodel.cpp +) + +include_directories(../../src) + +qt_add_qml_module( ${PROJECT_NAME} + URI ${PROJECT_NAME} + VERSION 1.0 + RESOURCE_PREFIX / + QML_FILES + tst_visibleitemmodel.qml + OUTPUT_DIRECTORY Victron/VenusOS +) + +set_target_properties(tst_visibleitemmodel PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +option(VENUS_INSTALL_TESTS "enable test installation via cmake -DVENUS_INSTALL_TESTS=ON" OFF) # Disabled by default +if (VENUS_INSTALL_TESTS) + install(FILES tst_visibleitemmodel.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/../../install/tests/visibleitemmodel) + install(TARGETS tst_visibleitemmodel DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/../../install/tests/visibleitemmodel) +endif() + +target_link_libraries(tst_visibleitemmodel PRIVATE + Qt6::Core + Qt6::Gui + Qt6::QuickPrivate + Qt6::QuickTest + Qt6::Quick +) + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) diff --git a/tests/visibleitemmodel/tst_visibleitemmodel.cpp b/tests/visibleitemmodel/tst_visibleitemmodel.cpp new file mode 100644 index 000000000..6bcdd3a24 --- /dev/null +++ b/tests/visibleitemmodel/tst_visibleitemmodel.cpp @@ -0,0 +1,16 @@ +/* +** Copyright (C) 2024 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +#include +#include +#include "visibleitemmodel.h" + +int main(int argc, char **argv) \ +{ + qmlRegisterType("Victron.VenusOS", 2, 0, "VisibleItemModel"); + + QTEST_SET_MAIN_SOURCE_PATH + return quick_test_main(argc, argv, "tst_visibleitemmodel", nullptr); +} diff --git a/tests/visibleitemmodel/tst_visibleitemmodel.qml b/tests/visibleitemmodel/tst_visibleitemmodel.qml new file mode 100644 index 000000000..254b04a64 --- /dev/null +++ b/tests/visibleitemmodel/tst_visibleitemmodel.qml @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 Victron Energy B.V. + * See LICENSE.txt for license information. +*/ + +import QtTest +import QtQuick +import Victron.VenusOS +import QtQuick.Window + +TestCase { + id: root + name: "visibleItemModelTest" + when: windowShown + + component ListDelegate : Rectangle { + property bool preferredVisible: true + + width: 800 + height: 20 + border.width: 1 + + Text { text: parent.objectName } + } + + Window { + width: 800 + height: 600 + visible: true + + Rectangle { + anchors.fill: parent + color: "yellow" + + ListView { + id: viewA + anchors.fill: parent + model: VisibleItemModel { + ListDelegate { + id: itemA1 + objectName: "itemA1" + } + ListDelegate { + id: itemA2 + objectName: "itemA2" + } + ListDelegate { + id: itemA3 + objectName: "itemA3" + } + } + } + + ListView { + id: viewB + anchors.fill: parent + model: VisibleItemModel { + ListDelegate { + id: itemB1 + property bool shouldBeVisible + objectName: "itemB1" + preferredVisible: shouldBeVisible + } + ListDelegate { + id: itemB2 + objectName: "itemB2" + } + ListDelegate { + id: itemB3 + objectName: "itemB3" + } + ListDelegate { + id: itemB4 + objectName: "itemB4" + preferredVisible: false + } + ListDelegate { + id: itemB5 + objectName: "itemB5" + } + } + } + + ListView { + id: viewWithQObjects + anchors.fill: parent + model: VisibleItemModel { + QtObject { id: viewWithQObjects_object1 } + ListDelegate { id: viewWithQObjects_object2 } + } + } + + ListView { + id: viewWithNestedItems + anchors.fill: parent + model: VisibleItemModel { + Column { + id: viewWithNestedItems_item1 + width: parent ? parent.width : 0 + ListDelegate {} + ListDelegate {} + } + ListDelegate { id: viewWithNestedItems_item2 } + } + } + } + } + + function test_allItemsVisible() { + const visibleItemModel = viewA.model + const allItemsList = viewA.model.sourceModel + + compare(allItemsList.length, 3) + compare(allItemsList[0], itemA1) + compare(allItemsList[1], itemA2) + compare(allItemsList[2], itemA3) + + compare(visibleItemModel.count, 3) + compare(viewA.count, 3) + compare(visibleItemModel.get(0), itemA1) + compare(visibleItemModel.get(1), itemA2) + compare(visibleItemModel.get(2), itemA3) + } + + function test_someItemsVisible() { + const visibleItemModel = viewB.model + const allItemsList = viewB.model.sourceModel + + compare(allItemsList.length, 5) + compare(allItemsList[0], itemB1) + compare(allItemsList[1], itemB2) + compare(allItemsList[2], itemB3) + compare(allItemsList[3], itemB4) + compare(allItemsList[4], itemB5) + + // The two non-visible items should be filtered out + compare(visibleItemModel.count, 3) + compare(viewB.count, 3) + compare(visibleItemModel.get(0), itemB2) + compare(visibleItemModel.get(1), itemB3) + compare(visibleItemModel.get(2), itemB5) + verify(!visibleItemModel.get(3)) + verify(!visibleItemModel.get(4)) + + // Test that the model is updated if an item becomes visible by forcing preferredVisible=true. + itemB4.preferredVisible = true + compare(visibleItemModel.count, 4) + compare(viewB.count, 4) + compare(visibleItemModel.get(0), itemB2) + compare(visibleItemModel.get(1), itemB3) + compare(visibleItemModel.get(2), itemB4) + compare(visibleItemModel.get(3), itemB5) + + // Test that the model is updated if an item becomes visible by updating a binding. + itemB1.shouldBeVisible = true + compare(visibleItemModel.count, 5) + compare(viewB.count, 5) + compare(visibleItemModel.get(0), itemB1) + compare(visibleItemModel.get(1), itemB2) + compare(visibleItemModel.get(2), itemB3) + compare(visibleItemModel.get(3), itemB4) + compare(visibleItemModel.get(4), itemB5) + } + + function test_itemsVisibilityChanges() { + const visibleItemModel = viewA.model + const allItemsList = viewA.model.sourceModel + + // Hide all items + compare(allItemsList.length, 3) + compare(visibleItemModel.count, 3) + for (let i = 0; i < 3; ++i) { + allItemsList[i].preferredVisible = false + } + compare(allItemsList.length, 3) + compare(visibleItemModel.count, 0) + compare(viewA.count, 0) + + // Make the 2nd source item visible, so it becomes the 1st item in the visibleItemModel. + allItemsList[1].preferredVisible = true + compare(visibleItemModel.count, 1) + compare(viewA.count, 1) + compare(visibleItemModel.get(0), itemA2) + + // Make the 1st source item visible, so it becomes the 1st item in the visibleItemModel. + allItemsList[0].preferredVisible = true + compare(visibleItemModel.count, 2) + compare(viewA.count, 2) + compare(visibleItemModel.get(0), itemA1) + compare(visibleItemModel.get(1), itemA2) + + // Make the 1st source item visible again + allItemsList[0].preferredVisible = false + compare(visibleItemModel.count, 1) + compare(viewA.count, 1) + compare(visibleItemModel.get(0), itemA2) + + // Make the 3rd item visible, so it becomes the 2nd item in the visibleItemModel. + allItemsList[2].preferredVisible = true + compare(visibleItemModel.count, 2) + compare(viewA.count, 2) + compare(visibleItemModel.get(0), itemA2) + compare(visibleItemModel.get(1), itemA3) + + // Make the 1st item visible again + allItemsList[0].preferredVisible = true + compare(visibleItemModel.count, 3) + compare(viewA.count, 3) + compare(visibleItemModel.get(0), itemA1) + compare(visibleItemModel.get(1), itemA2) + compare(visibleItemModel.get(2), itemA3) + } + + function test_viewWithQObjects() { + // The sourceModel has both a QtObject and an Item + compare(viewWithQObjects.model.sourceModel.length, 2) + compare(viewWithQObjects.model.sourceModel[0], viewWithQObjects_object1) + compare(viewWithQObjects.model.sourceModel[1], viewWithQObjects_object2) + + // The QtObject is filtered out of the view and the model. + compare(viewWithQObjects.model.count, 1) + compare(viewWithQObjects.model.get(0), viewWithQObjects_object2) + compare(viewWithQObjects.count, 1) + } + + function test_viewWithNestedItems() { + compare(viewWithNestedItems.model.sourceModel.length, 2) + compare(viewWithNestedItems.model.sourceModel[0], viewWithNestedItems_item1) + compare(viewWithNestedItems.model.sourceModel[1], viewWithNestedItems_item2) + + // The Column should not be filtered out, as it does not have a preferredVisible property. + compare(viewWithNestedItems.model.count, 2) + compare(viewWithNestedItems.model.get(0), viewWithNestedItems_item1) + compare(viewWithNestedItems.model.get(1), viewWithNestedItems_item2) + compare(viewWithNestedItems.count, 2) + } +}