QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsnewsfeedmodel.cpp
Go to the documentation of this file.
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"
17 #include <QPainter>
18 
19 //
20 // QgsNewsFeedModel
21 //
22 
24  : QAbstractItemModel( parent )
25  , mParser( parser )
26 {
27  Q_ASSERT( mParser );
28  const QList< QgsNewsFeedParser::Entry > initialEntries = mParser->entries();
29  for ( const QgsNewsFeedParser::Entry &e : initialEntries )
30  onEntryAdded( e );
31 
32  connect( mParser, &QgsNewsFeedParser::entryAdded, this, &QgsNewsFeedModel::onEntryAdded );
33  connect( mParser, &QgsNewsFeedParser::entryDismissed, this, &QgsNewsFeedModel::onEntryRemoved );
34  connect( mParser, &QgsNewsFeedParser::imageFetched, this, &QgsNewsFeedModel::onImageFetched );
35 }
36 
37 QVariant QgsNewsFeedModel::data( const QModelIndex &index, int role ) const
38 {
39  if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
40  return QVariant();
41 
42  const QgsNewsFeedParser::Entry &entry = mEntries.at( index.row() );
43 
44  switch ( role )
45  {
46  case Qt::DisplayRole:
47  case Content:
48  return entry.content;
49 
50  case Qt::ToolTipRole:
51  case Title:
52  return entry.title;
53 
54  case Key:
55  return entry.key;
56 
57  case ImageUrl:
58  return entry.imageUrl;
59 
60  case Image:
61  return entry.image;
62 
63  case Link:
64  return entry.link;
65 
66  case Sticky:
67  return entry.sticky;
68 
69  case Qt::DecorationRole:
70  if ( entry.image.isNull() )
71  return QVariant();
72  return entry.image;
73  }
74  return QVariant();
75 }
76 
77 Qt::ItemFlags QgsNewsFeedModel::flags( const QModelIndex &index ) const
78 {
79  Qt::ItemFlags flags = QAbstractItemModel::flags( index );
80  return flags;
81 }
82 
83 QModelIndex QgsNewsFeedModel::index( int row, int column, const QModelIndex &parent ) const
84 {
85  if ( !hasIndex( row, column, parent ) )
86  return QModelIndex();
87 
88  if ( !parent.isValid() )
89  {
90  return createIndex( row, column );
91  }
92 
93  return QModelIndex();
94 }
95 
96 QModelIndex QgsNewsFeedModel::parent( const QModelIndex & ) const
97 {
98  //all items are top level for now
99  return QModelIndex();
100 }
101 
102 int QgsNewsFeedModel::rowCount( const QModelIndex &parent ) const
103 {
104  if ( !parent.isValid() )
105  {
106  return mEntries.count();
107  }
108  return 0;
109 }
110 
111 int QgsNewsFeedModel::columnCount( const QModelIndex & ) const
112 {
113  return 1;
114 }
115 
116 void QgsNewsFeedModel::onEntryAdded( const QgsNewsFeedParser::Entry &entry )
117 {
118  beginInsertRows( QModelIndex(), mEntries.count(), mEntries.count() );
119  mEntries.append( entry );
120  endInsertRows();
121 }
122 
123 void QgsNewsFeedModel::onEntryRemoved( const QgsNewsFeedParser::Entry &entry )
124 {
125  // find index of entry
126  auto findIter = std::find_if( mEntries.begin(), mEntries.end(), [entry]( const QgsNewsFeedParser::Entry & candidate )
127  {
128  return candidate.key == entry.key;
129  } );
130  if ( findIter == mEntries.end() )
131  return;
132 
133  const int entryIndex = static_cast< int >( std::distance( mEntries.begin(), findIter ) );
134  beginRemoveRows( QModelIndex(), entryIndex, entryIndex );
135  mEntries.removeAt( entryIndex );
136  endRemoveRows();
137 }
138 
139 void QgsNewsFeedModel::onImageFetched( const int key, const QPixmap &pixmap )
140 {
141  // find index of entry
142  auto findIter = std::find_if( mEntries.begin(), mEntries.end(), [key]( const QgsNewsFeedParser::Entry & candidate )
143  {
144  return candidate.key == key;
145  } );
146  if ( findIter == mEntries.end() )
147  return;
148 
149  const int entryIndex = static_cast< int >( std::distance( mEntries.begin(), findIter ) );
150  mEntries[ entryIndex ].image = pixmap;
151  emit dataChanged( index( entryIndex, 0, QModelIndex() ), index( entryIndex, 0, QModelIndex() ) );
152 }
153 
154 
155 //
156 // QgsNewsFeedProxyModel
157 //
158 
160  : QSortFilterProxyModel( parent )
161 {
162  mModel = new QgsNewsFeedModel( parser, this );
163  setSortCaseSensitivity( Qt::CaseInsensitive );
164  setSourceModel( mModel );
165  setDynamicSortFilter( true );
166  sort( 0 );
167 }
168 
169 bool QgsNewsFeedProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
170 {
171  const bool leftSticky = sourceModel()->data( left, QgsNewsFeedModel::Sticky ).toBool();
172  const bool rightSticky = sourceModel()->data( right, QgsNewsFeedModel::Sticky ).toBool();
173 
174  // sticky items come first
175  if ( leftSticky && !rightSticky )
176  return true;
177  if ( rightSticky && !leftSticky )
178  return false;
179 
180  // else sort by descending key
181  const int leftKey = sourceModel()->data( left, QgsNewsFeedModel::Key ).toInt();
182  const int rightKey = sourceModel()->data( right, QgsNewsFeedModel::Key ).toInt();
183  return rightKey < leftKey;
184 }
QgsNewsFeedParser
Parser for published QGIS news feeds.
Definition: qgsnewsfeedparser.h:37
QgsNewsFeedModel::Content
@ Content
Entry content.
Definition: qgsnewsfeedmodel.h:45
QgsNewsFeedModel::data
QVariant data(const QModelIndex &index, int role) const override
Definition: qgsnewsfeedmodel.cpp:37
QgsNewsFeedParser::entryDismissed
void entryDismissed(const QgsNewsFeedParser::Entry &entry)
Emitted whenever an entry is dismissed (as a result of a call to dismissEntry()).
QgsNewsFeedProxyModel::QgsNewsFeedProxyModel
QgsNewsFeedProxyModel(QgsNewsFeedParser *parser, QObject *parent=nullptr)
Constructor for QgsNewsFeedProxyModel, with the specified parent object.
Definition: qgsnewsfeedmodel.cpp:159
QgsNewsFeedParser::entryAdded
void entryAdded(const QgsNewsFeedParser::Entry &entry)
Emitted whenever a new entry is available from the feed (as a result of a call to fetch()).
QgsNewsFeedModel::Key
@ Key
Entry unique key.
Definition: qgsnewsfeedmodel.h:43
QgsNewsFeedModel::Image
@ Image
Optional entry image.
Definition: qgsnewsfeedmodel.h:47
QgsNewsFeedParser::Entry::sticky
bool sticky
true if entry is "sticky" and should always be shown at the top
Definition: qgsnewsfeedparser.h:69
QgsNewsFeedModel::Sticky
@ Sticky
Whether entry is sticky.
Definition: qgsnewsfeedmodel.h:49
QgsNewsFeedModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsnewsfeedmodel.cpp:102
QgsNewsFeedProxyModel::lessThan
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
Definition: qgsnewsfeedmodel.cpp:169
QgsNewsFeedModel::ImageUrl
@ ImageUrl
Optional entry image URL.
Definition: qgsnewsfeedmodel.h:46
QgsNewsFeedModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgsnewsfeedmodel.cpp:83
QgsNewsFeedModel
A model for published QGIS news feeds.
Definition: qgsnewsfeedmodel.h:34
QgsNewsFeedModel::parent
QModelIndex parent(const QModelIndex &index) const override
Definition: qgsnewsfeedmodel.cpp:96
QgsNewsFeedParser::Entry::link
QUrl link
Optional URL link for entry.
Definition: qgsnewsfeedparser.h:66
QgsNewsFeedParser::Entry::title
QString title
Entry title.
Definition: qgsnewsfeedparser.h:54
QgsNewsFeedModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: qgsnewsfeedmodel.cpp:77
QgsNewsFeedModel::QgsNewsFeedModel
QgsNewsFeedModel(QgsNewsFeedParser *parser, QObject *parent=nullptr)
Constructor for QgsNewsFeedModel, with the specified parent object.
Definition: qgsnewsfeedmodel.cpp:23
QgsNewsFeedParser::imageFetched
void imageFetched(int key, const QPixmap &pixmap)
Emitted when the image attached to the entry with the specified key has been fetched and is now avail...
QgsNewsFeedParser::Entry::content
QString content
HTML content of news entry.
Definition: qgsnewsfeedparser.h:63
QgsNewsFeedParser::Entry
Represents a single entry from a news feed.
Definition: qgsnewsfeedparser.h:47
QgsNewsFeedParser::Entry::imageUrl
QString imageUrl
Optional URL for image associated with entry.
Definition: qgsnewsfeedparser.h:57
qgsnewsfeedmodel.h
QgsNewsFeedParser::Entry::image
QPixmap image
Optional image data.
Definition: qgsnewsfeedparser.h:60
qgsnetworkcontentfetcher.h
QgsNewsFeedModel::Link
@ Link
Optional entry URL link.
Definition: qgsnewsfeedmodel.h:48
QgsNewsFeedParser::entries
QList< QgsNewsFeedParser::Entry > entries() const
Returns a list of existing entries in the feed.
Definition: qgsnewsfeedparser.cpp:83
QgsNewsFeedModel::Title
@ Title
Entry title.
Definition: qgsnewsfeedmodel.h:44
QgsNewsFeedParser::Entry::key
int key
Unique entry identifier.
Definition: qgsnewsfeedparser.h:51
QgsNewsFeedModel::columnCount
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsnewsfeedmodel.cpp:111