1# Copyright (c) 2020 Ultimaker B.V.
2# Uranium is released under the terms of the LGPLv3 or higher.
3
4from PyQt5.QtCore import Qt, pyqtSlot, pyqtProperty, pyqtSignal
5
6from UM.Application import Application
7from UM.Qt.ListModel import ListModel
8
9from PyQt5.QtQml import QQmlEngine
10
11
12class OutputDevicesModel(ListModel):
13    """A list model providing a list of all registered OutputDevice instances.
14
15    This list model wraps OutputDeviceManager's list of OutputDevice instances.
16    Additionally it provides a function to set OutputDeviceManager's active device.
17
18    Exposes the following roles:
19    * id - The device ID
20    * name - The human-readable name of the device
21    * short_description - The short description of the device
22    * description - The full description of the device
23    * icon_name - The name of the icon used to identify the device
24    * priority - The device priority
25
26    """
27
28    IdRole = Qt.UserRole + 1
29    NameRole = Qt.UserRole + 2
30    ShortDescriptionRole = Qt.UserRole + 3
31    DescriptionRole = Qt.UserRole + 4
32    IconNameRole = Qt.UserRole + 5
33    PriorityRole = Qt.UserRole + 6
34
35    def __init__(self, parent = None):
36        super().__init__(parent)
37        # Ensure that this model doesn't get garbage collected (Now the bound object is destroyed when the wrapper is)
38        QQmlEngine.setObjectOwnership(self, QQmlEngine.CppOwnership)
39        self._device_manager = Application.getInstance().getOutputDeviceManager()
40
41        self.addRoleName(self.IdRole, "id")
42        self.addRoleName(self.NameRole, "name")
43        self.addRoleName(self.ShortDescriptionRole, "short_description")
44        self.addRoleName(self.DescriptionRole, "description")
45        self.addRoleName(self.IconNameRole, "icon_name")
46        self.addRoleName(self.PriorityRole, "priority")
47
48        self._device_manager.outputDevicesChanged.connect(self._update)
49        self._update()
50
51    @pyqtSlot(str, result = "QVariantMap")
52    def getDevice(self, device_id):
53        index = self.find("id", device_id)
54        if index != -1:
55            return self.getItem(index)
56
57        return { "id": "", "name": "", "short_description": "", "description": "", "icon_name": "save", "priority": -1 }
58
59    outputDevicesChanged = pyqtSignal()
60
61    @pyqtProperty(int, notify = outputDevicesChanged)
62    def deviceCount(self):
63        return self.count
64
65    def _update(self):
66        try:
67            self.beginResetModel()
68        except RuntimeError:
69            # Don't break if the object was garbage collected.
70            return
71
72        self._items.clear()
73        devices = list(self._device_manager.getOutputDevices())[:]  # Make a copy here, because we could discover devices during iteration.
74        for device in devices:
75            self._items.append({
76                "id": device.getId(),
77                "name": device.getName(),
78                "short_description": device.getShortDescription(),
79                "description": device.getDescription(),
80                "icon_name": device.getIconName(),
81                "priority": device.getPriority()
82            })
83
84        self.sort(lambda i: -i["priority"])
85        self.endResetModel()
86
87        self.outputDevicesChanged.emit()
88