1"""
2Preview item model.
3"""
4import os
5import logging
6
7from AnyQt.QtGui import (
8    QStandardItemModel, QStandardItem, QIcon
9)
10from AnyQt.QtCore import Qt, QTimer
11from AnyQt.QtCore import pyqtSlot as Slot
12
13from ..gui.svgiconengine import SvgIconEngine
14from . import scanner
15
16
17log = logging.getLogger(__name__)
18
19# Preview Data Roles
20####################
21
22# Name of the item, (same as `Qt.DisplayRole`)
23NameRole = Qt.DisplayRole
24
25# Items description (items long description)
26DescriptionRole = Qt.UserRole + 1
27
28# Items url/path (where previewed resource is located).
29PathRole = Qt.UserRole + 2
30
31# Items preview SVG contents string
32ThumbnailSVGRole = Qt.UserRole + 3
33
34
35UNKNOWN_SVG = \
36"""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
37<svg width="161.8mm" height="100.0mm"
38 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
39 version="1.2" baseProfile="tiny">
40</svg>
41"""
42
43
44class PreviewModel(QStandardItemModel):
45    """A model for preview items.
46    """
47
48    def __init__(self, parent=None, items=None):
49        super().__init__(parent)
50        self.__preview_index = -1
51        if items is not None:
52            self.insertColumn(0, items)
53
54        self.__timer = QTimer(self)
55        self.__timer.timeout.connect(self.__process_next)
56
57    def delayedScanUpdate(self, delay=10):
58        """Run a delayed preview item scan update.
59        """
60        self.__preview_index = -1
61        self.__timer.start(delay)
62        log.debug("delayedScanUpdate: Start")
63
64    @Slot()
65    def __process_next(self):
66        index = self.__preview_index
67        log.debug("delayedScanUpdate: Next %i", index + 1)
68        if not 0 <= index + 1 < self.rowCount():
69            self.__timer.stop()
70            log.debug("delayedScanUpdate: Stop")
71            return
72
73        self.__preview_index = index = index + 1
74
75        assert 0 <= index < self.rowCount()
76        item = self.item(index)
77        if os.path.isfile(item.path()):
78            try:
79                scanner.scan_update(item)
80            except Exception:
81                log.error("An unexpected error occurred while "
82                          "scanning '%s'.", item.text(), exc_info=True)
83                item.setEnabled(False)
84
85
86class PreviewItem(QStandardItem):
87    """A preview item.
88    """
89    def __init__(self, name=None, description=None, thumbnail=None,
90                 icon=None, path=None):
91        super().__init__()
92
93        self.__name = ""
94
95        if name is None:
96            name = "Untitled"
97
98        self.setName(name)
99
100        if description is None:
101            description = "No description."
102        self.setDescription(description)
103
104        if thumbnail is None:
105            thumbnail = UNKNOWN_SVG
106        self.setThumbnail(thumbnail)
107
108        if icon is not None:
109            self.setIcon(icon)
110
111        if path is not None:
112            self.setPath(path)
113
114    def name(self):
115        """Return the name (title) of the item (same as `text()`.
116        """
117        return self.__name
118
119    def setName(self, value):
120        """Set the item name. `value` if not empty will be used as
121        the items DisplayRole otherwise an 'untitled' placeholder will
122        be used.
123
124        """
125        self.__name = value
126
127        if not value:
128            self.setText("untitled")
129        else:
130            self.setText(value)
131
132    def description(self):
133        """Return the detailed description for the item.
134
135        This is stored as `DescriptionRole`, if no data is set then
136        return the string for `WhatsThisRole`.
137
138        """
139        desc = self.data(DescriptionRole)
140
141        if desc is not None:
142            return str(desc)
143
144        whatsthis = self.data(Qt.WhatsThisRole)
145        if whatsthis is not None:
146            return str(whatsthis)
147        else:
148            return ""
149
150    def setDescription(self, description):
151        self.setData(description, DescriptionRole)
152        self.setWhatsThis(description)
153
154    def thumbnail(self):
155        """Return the thumbnail SVG string for the preview item.
156
157        This is stored as `ThumbnailSVGRole`
158        """
159        thumb = self.data(ThumbnailSVGRole)
160        if thumb is not None:
161            return str(thumb)
162        else:
163            return ""
164
165    def setThumbnail(self, thumbnail):
166        """Set the thumbnail SVG contents as a string.
167
168        When set it also overrides the icon role.
169
170        """
171        self.setData(thumbnail, ThumbnailSVGRole)
172        engine = SvgIconEngine(thumbnail.encode("utf-8"))
173        self.setIcon(QIcon(engine))
174
175    def path(self):
176        """Return the path item data.
177        """
178        return str(self.data(PathRole))
179
180    def setPath(self, path):
181        """Set the path data of the item.
182
183        .. note:: This also sets the Qt.StatusTipRole
184
185        """
186        self.setData(path, PathRole)
187        self.setStatusTip(path)
188        self.setToolTip(path)
189