1 /*
2   remotemodelserver.h
3 
4   This file is part of GammaRay, the Qt application inspection and
5   manipulation tool.
6 
7   Copyright (C) 2013-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8   Author: Volker Krause <volker.krause@kdab.com>
9 
10   Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11   accordance with GammaRay Commercial License Agreement provided with the Software.
12 
13   Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 
15   This program is free software; you can redistribute it and/or modify
16   it under the terms of the GNU General Public License as published by
17   the Free Software Foundation, either version 2 of the License, or
18   (at your option) any later version.
19 
20   This program is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23   GNU General Public License for more details.
24 
25   You should have received a copy of the GNU General Public License
26   along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 */
28 
29 #ifndef GAMMARAY_REMOTEMODELSERVER_H
30 #define GAMMARAY_REMOTEMODELSERVER_H
31 
32 #include <common/protocol.h>
33 
34 #include <QObject>
35 #include <QPointer>
36 #include <QRegExp>
37 
38 QT_BEGIN_NAMESPACE
39 class QBuffer;
40 class QAbstractItemModel;
41 QT_END_NAMESPACE
42 
43 namespace GammaRay {
44 class Message;
45 
46 /** Provides the server-side interface for a QAbstractItemModel to be used from a separate process.
47  *  If the source model is a QSortFilterProxyModel, this also forwards properties for configuring
48  *  the proxy behavior, enabling server-side searching and sorting.
49  */
50 class RemoteModelServer : public QObject
51 {
52     Q_OBJECT
53     Q_PROPERTY(bool dynamicSortFilter READ proxyDynamicSortFilter WRITE setProxyDynamicSortFilter)
54     Q_PROPERTY(
55         Qt::CaseSensitivity filterCaseSensitivity READ proxyFilterCaseSensitivity WRITE setProxyFilterCaseSensitivity)
56     Q_PROPERTY(int filterKeyColumn READ proxyFilterKeyColumn WRITE setProxyFilterKeyColumn)
57     Q_PROPERTY(QRegExp filterRegExp READ proxyFilterRegExp WRITE setProxyFilterRegExp)
58 
59 public:
60     /** Registers a new model server object with name @p objectName (must be unique). */
61     explicit RemoteModelServer(const QString &objectName, QObject *parent = nullptr);
62     ~RemoteModelServer() override;
63 
64     /** Returns the source model. */
65     QAbstractItemModel *model() const;
66     /** Set the source model for this model server instance. */
67     void setModel(QAbstractItemModel *model);
68 
69 public slots:
70     void newRequest(const GammaRay::Message &msg);
71     /** Notifications about an object on the client side (un)monitoring this object.
72      *  If no one is watching, we don't send out any change notification to reduce network traffice.
73      */
74     void modelMonitored(bool monitored = false);
75 
76 private:
77     void connectModel();
78     void disconnectModel();
79     void sendAddRemoveMessage(Protocol::MessageType type, const QModelIndex &parent, int start,
80                               int end);
81     void sendMoveMessage(Protocol::MessageType type, const Protocol::ModelIndex &sourceParent,
82                          int sourceStart, int sourceEnd,
83                          const Protocol::ModelIndex &destinationParent, int destinationIndex);
84     QMap< int, QVariant > filterItemData(QMap<int, QVariant> &&itemData) const;
85     void sendLayoutChanged(
86         const QVector<Protocol::ModelIndex> &parents = QVector<Protocol::ModelIndex>(),
87         quint32 hint = 0);
88     bool canSerialize(const QVariant &value) const;
89 
90     // proxy model settings
91     bool proxyDynamicSortFilter() const;
92     void setProxyDynamicSortFilter(bool dynamicSortFilter);
93     Qt::CaseSensitivity proxyFilterCaseSensitivity() const;
94     void setProxyFilterCaseSensitivity(Qt::CaseSensitivity caseSensitivity);
95     int proxyFilterKeyColumn() const;
96     void setProxyFilterKeyColumn(int column);
97     QRegExp proxyFilterRegExp() const;
98     void setProxyFilterRegExp(const QRegExp &regExp);
99 
100     // unit test hooks
101     static void (*s_registerServerCallback)();
102     void registerServer();
103     virtual bool isConnected() const;
104     virtual void sendMessage(const Message &msg) const;
105     friend class FakeRemoteModelServer;
106 
107 private slots:
108     void dataChanged(const QModelIndex &begin, const QModelIndex &end,
109                      const QVector<int> &roles = QVector<int>());
110     void headerDataChanged(Qt::Orientation orientation, int first, int last);
111     void rowsInserted(const QModelIndex &parent, int start, int end);
112     void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
113                             const QModelIndex &destinationParent, int destinationRow);
114     void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
115                    const QModelIndex &destinationParent, int destinationRow);
116     void rowsRemoved(const QModelIndex &parent, int start, int end);
117     void columnsInserted(const QModelIndex &parent, int start, int end);
118     void columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
119                       const QModelIndex &destinationParent, int destinationColumn);
120     void columnsRemoved(const QModelIndex &parent, int start, int end);
121     void layoutChanged(const QList<QPersistentModelIndex> &parents,
122                        QAbstractItemModel::LayoutChangeHint hint);
123 
124     void modelReset();
125 
126     void modelDeleted();
127 
128 private:
129     QPointer<QAbstractItemModel> m_model;
130     // those two are used for canSerialize, since recreating the QBuffer is somewhat expensive,
131     // especially since being a QObject triggers all kind of GammaRay internals
132     QByteArray m_dummyData;
133     QBuffer *m_dummyBuffer;
134     // converted model indexes from aboutToBeX signals, needed in cases where the operation changes
135     // the serialized index (move to sub-tree of source parent for example)
136     // as operations can occur nested, we need to have a stack for this
137     QList<Protocol::ModelIndex> m_preOpIndexes;
138     Protocol::ObjectAddress m_myAddress;
139     bool m_monitored;
140 };
141 }
142 
143 #endif
144