1#!/usr/bin/python
2
3
4#############################################################################
5##
6## Copyright (C) 2018 Riverbank Computing Limited
7## Copyright (C) 2017 Ford Motor Company
8##
9## This file is part of the PyQt examples.
10##
11## $QT_BEGIN_LICENSE:BSD$
12## Commercial License Usage
13## Licensees holding valid commercial Qt licenses may use this file in
14## accordance with the commercial license agreement provided with the
15## Software or, alternatively, in accordance with the terms contained in
16## a written agreement between you and The Qt Company. For licensing terms
17## and conditions see https://www.qt.io/terms-conditions. For further
18## information use the contact form at https://www.qt.io/contact-us.
19##
20## BSD License Usage
21## Alternatively, you may use this file under the terms of the BSD license
22## as follows:
23##
24## "Redistribution and use in source and binary forms, with or without
25## modification, are permitted provided that the following conditions are
26## met:
27##   * Redistributions of source code must retain the above copyright
28##     notice, this list of conditions and the following disclaimer.
29##   * Redistributions in binary form must reproduce the above copyright
30##     notice, this list of conditions and the following disclaimer in
31##     the documentation and/or other materials provided with the
32##     distribution.
33##   * Neither the name of The Qt Company Ltd nor the names of its
34##     contributors may be used to endorse or promote products derived
35##     from this software without specific prior written permission.
36##
37##
38## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
49## $QT_END_LICENSE$
50##
51#############################################################################
52
53
54import sys
55
56from PyQt5.QtCore import (pyqtSlot, QLoggingCategory, QModelIndex, QObject, Qt,
57        QTimer, QUrl)
58from PyQt5.QtGui import QColor, QStandardItem, QStandardItemModel
59from PyQt5.QtRemoteObjects import QRemoteObjectHost, QRemoteObjectRegistryHost
60from PyQt5.QtWidgets import QApplication, QTreeView
61
62
63class TimerHandler(QObject):
64
65    def __init__(self, model, parent=None):
66        super().__init__(parent)
67
68        self._model = model
69
70    @pyqtSlot()
71    def changeData(self):
72        for i in range(10, 50):
73            self._model.setData(self._model.index(i, 1), QColor(Qt.blue),
74                    Qt.BackgroundRole)
75
76    @pyqtSlot()
77    def insertData(self):
78        self._model.insertRows(2, 9)
79
80        for i in range(2, 11):
81            self._model.setData(self._model.index(i, 1), QColor(Qt.green),
82                    Qt.BackgroundRole)
83            self._model.setData(self._model.index(i, 1), "InsertedRow",
84                    Qt.DisplayRole)
85
86    @pyqtSlot()
87    def removeData(self):
88        self._model.removeRows(2, 4)
89
90    @pyqtSlot()
91    def changeFlags(self):
92        item = self._model.item(0, 0)
93        item.setEnabled(False)
94
95        item = item.child(0, 0)
96        item.setFlags(item.flags() & Qt.ItemIsSelectable)
97
98    @pyqtSlot()
99    def moveData(self):
100        self._model.moveRows(QModelIndex(), 2, 4, QModelIndex(), 10)
101
102
103def addChild(numChildren, nestingLevel):
104    result = []
105
106    if nestingLevel == 0:
107        return result
108
109    for i in range(numChildren):
110        child = QStandardItem(
111                "Child num {}, nesting level {}".format(i + 1, nestingLevel))
112
113        if i == 0:
114            child.appendRow(addChild(numChildren, nestingLevel - 1))
115
116        result.append(child)
117
118    return result
119
120
121if __name__ == '__main__':
122
123    QLoggingCategory.setFilterRules('qt.remoteobjects.debug=false\n'
124                                    'qt.remoteobjects.warning=false')
125
126    app = QApplication(sys.argv)
127
128    sourceModel = QStandardItemModel()
129    sourceModel.setHorizontalHeaderLabels(
130            ["First Column with spacing", "Second Column with spacing"])
131
132    for i in range(10000):
133        firstItem = QStandardItem("FancyTextNumber {}".format(i))
134        if i == 0:
135            firstItem.appendRow(addChild(2, 2))
136
137        secondItem = QStandardItem("FancyRow2TextNumber {}".format(i))
138        if i % 2 == 0:
139            firstItem.setBackground(Qt.red)
140
141        sourceModel.invisibleRootItem().appendRow([firstItem, secondItem])
142
143    # Needed by QMLModelViewClient.
144    roleNames = {
145        Qt.DisplayRole: b'_text',
146        Qt.BackgroundRole: b'_color'
147    }
148    sourceModel.setItemRoleNames(roleNames)
149
150    roles = [Qt.DisplayRole, Qt.BackgroundRole]
151
152    node = QRemoteObjectRegistryHost(QUrl('local:registry'))
153
154    node2 = QRemoteObjectHost(QUrl('local:replica'), QUrl('local:registry'))
155    node2.enableRemoting(sourceModel, 'RemoteModel', roles)
156
157    view = QTreeView()
158    view.setWindowTitle("SourceView")
159    view.setModel(sourceModel)
160    view.show()
161
162    handler = TimerHandler(sourceModel)
163    QTimer.singleShot(5000, handler.changeData)
164    QTimer.singleShot(10000, handler.insertData)
165    QTimer.singleShot(11000, handler.changeFlags)
166    QTimer.singleShot(12000, handler.removeData)
167    QTimer.singleShot(13000, handler.moveData)
168
169    sys.exit(app.exec_())
170