Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsnewsfeedmodel.cpp
3 : : -------------------
4 : : begin : July 2019
5 : : copyright : (C) 2019 by Nyall Dawson
6 : : email : nyall dot dawson at gmail dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : : #include "qgsnewsfeedmodel.h"
16 : : #include "qgsnetworkcontentfetcher.h"
17 : : #include <QPainter>
18 : :
19 : : //
20 : : // QgsNewsFeedModel
21 : : //
22 : :
23 : 0 : QgsNewsFeedModel::QgsNewsFeedModel( QgsNewsFeedParser *parser, QObject *parent )
24 : 0 : : QAbstractItemModel( parent )
25 : 0 : , mParser( parser )
26 : 0 : {
27 : : Q_ASSERT( mParser );
28 : 0 : const QList< QgsNewsFeedParser::Entry > initialEntries = mParser->entries();
29 : 0 : for ( const QgsNewsFeedParser::Entry &e : initialEntries )
30 : 0 : onEntryAdded( e );
31 : :
32 : 0 : connect( mParser, &QgsNewsFeedParser::entryAdded, this, &QgsNewsFeedModel::onEntryAdded );
33 : 0 : connect( mParser, &QgsNewsFeedParser::entryDismissed, this, &QgsNewsFeedModel::onEntryRemoved );
34 : 0 : connect( mParser, &QgsNewsFeedParser::imageFetched, this, &QgsNewsFeedModel::onImageFetched );
35 : 0 : }
36 : :
37 : 0 : QVariant QgsNewsFeedModel::data( const QModelIndex &index, int role ) const
38 : : {
39 : 0 : if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
40 : 0 : return QVariant();
41 : :
42 : 0 : const QgsNewsFeedParser::Entry &entry = mEntries.at( index.row() );
43 : :
44 : 0 : switch ( role )
45 : : {
46 : : case Qt::DisplayRole:
47 : : case Content:
48 : 0 : return entry.content;
49 : :
50 : : case Qt::ToolTipRole:
51 : : case Title:
52 : 0 : return entry.title;
53 : :
54 : : case Key:
55 : 0 : return entry.key;
56 : :
57 : : case ImageUrl:
58 : 0 : return entry.imageUrl;
59 : :
60 : : case Image:
61 : 0 : return entry.image;
62 : :
63 : : case Link:
64 : 0 : return entry.link;
65 : :
66 : : case Sticky:
67 : 0 : return entry.sticky;
68 : :
69 : : case Qt::DecorationRole:
70 : 0 : if ( entry.image.isNull() )
71 : 0 : return QVariant();
72 : 0 : return entry.image;
73 : : }
74 : 0 : return QVariant();
75 : 0 : }
76 : :
77 : 0 : Qt::ItemFlags QgsNewsFeedModel::flags( const QModelIndex &index ) const
78 : : {
79 : 0 : Qt::ItemFlags flags = QAbstractItemModel::flags( index );
80 : 0 : return flags;
81 : : }
82 : :
83 : 0 : QModelIndex QgsNewsFeedModel::index( int row, int column, const QModelIndex &parent ) const
84 : : {
85 : 0 : if ( !hasIndex( row, column, parent ) )
86 : 0 : return QModelIndex();
87 : :
88 : 0 : if ( !parent.isValid() )
89 : : {
90 : 0 : return createIndex( row, column );
91 : : }
92 : :
93 : 0 : return QModelIndex();
94 : 0 : }
95 : :
96 : 0 : QModelIndex QgsNewsFeedModel::parent( const QModelIndex & ) const
97 : : {
98 : : //all items are top level for now
99 : 0 : return QModelIndex();
100 : : }
101 : :
102 : 0 : int QgsNewsFeedModel::rowCount( const QModelIndex &parent ) const
103 : : {
104 : 0 : if ( !parent.isValid() )
105 : 0 : {
106 : 0 : return mEntries.count();
107 : : }
108 : 0 : return 0;
109 : 0 : }
110 : :
111 : 0 : int QgsNewsFeedModel::columnCount( const QModelIndex & ) const
112 : : {
113 : 0 : return 1;
114 : : }
115 : :
116 : 0 : void QgsNewsFeedModel::onEntryAdded( const QgsNewsFeedParser::Entry &entry )
117 : : {
118 : 0 : beginInsertRows( QModelIndex(), mEntries.count(), mEntries.count() );
119 : 0 : mEntries.append( entry );
120 : 0 : endInsertRows();
121 : 0 : }
122 : :
123 : 0 : void QgsNewsFeedModel::onEntryRemoved( const QgsNewsFeedParser::Entry &entry )
124 : : {
125 : : // find index of entry
126 : 0 : auto findIter = std::find_if( mEntries.begin(), mEntries.end(), [entry]( const QgsNewsFeedParser::Entry & candidate )
127 : : {
128 : 0 : return candidate.key == entry.key;
129 : : } );
130 : 0 : if ( findIter == mEntries.end() )
131 : 0 : return;
132 : :
133 : 0 : const int entryIndex = static_cast< int >( std::distance( mEntries.begin(), findIter ) );
134 : 0 : beginRemoveRows( QModelIndex(), entryIndex, entryIndex );
135 : 0 : mEntries.removeAt( entryIndex );
136 : 0 : endRemoveRows();
137 : 0 : }
138 : :
139 : 0 : void QgsNewsFeedModel::onImageFetched( const int key, const QPixmap &pixmap )
140 : : {
141 : : // find index of entry
142 : 0 : auto findIter = std::find_if( mEntries.begin(), mEntries.end(), [key]( const QgsNewsFeedParser::Entry & candidate )
143 : : {
144 : 0 : return candidate.key == key;
145 : : } );
146 : 0 : if ( findIter == mEntries.end() )
147 : 0 : return;
148 : :
149 : 0 : const int entryIndex = static_cast< int >( std::distance( mEntries.begin(), findIter ) );
150 : 0 : mEntries[ entryIndex ].image = pixmap;
151 : 0 : emit dataChanged( index( entryIndex, 0, QModelIndex() ), index( entryIndex, 0, QModelIndex() ) );
152 : 0 : }
153 : :
154 : :
155 : : //
156 : : // QgsNewsFeedProxyModel
157 : : //
158 : :
159 : 0 : QgsNewsFeedProxyModel::QgsNewsFeedProxyModel( QgsNewsFeedParser *parser, QObject *parent )
160 : 0 : : QSortFilterProxyModel( parent )
161 : 0 : {
162 : 0 : mModel = new QgsNewsFeedModel( parser, this );
163 : 0 : setSortCaseSensitivity( Qt::CaseInsensitive );
164 : 0 : setSourceModel( mModel );
165 : 0 : setDynamicSortFilter( true );
166 : 0 : sort( 0 );
167 : 0 : }
168 : :
169 : 0 : bool QgsNewsFeedProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
170 : : {
171 : 0 : const bool leftSticky = sourceModel()->data( left, QgsNewsFeedModel::Sticky ).toBool();
172 : 0 : const bool rightSticky = sourceModel()->data( right, QgsNewsFeedModel::Sticky ).toBool();
173 : :
174 : : // sticky items come first
175 : 0 : if ( leftSticky && !rightSticky )
176 : 0 : return true;
177 : 0 : if ( rightSticky && !leftSticky )
178 : 0 : return false;
179 : :
180 : : // else sort by descending key
181 : 0 : const int leftKey = sourceModel()->data( left, QgsNewsFeedModel::Key ).toInt();
182 : 0 : const int rightKey = sourceModel()->data( right, QgsNewsFeedModel::Key ).toInt();
183 : 0 : return rightKey < leftKey;
184 : 0 : }
|