1 #include "gamesmodel.h"
2 
3 #include "pb/serverinfo_game.pb.h"
4 #include "pixmapgenerator.h"
5 #include "settingscache.h"
6 #include "tab_account.h"
7 #include "userlist.h"
8 
9 #include <QDateTime>
10 #include <QDebug>
11 #include <QIcon>
12 #include <QStringList>
13 #include <QTime>
14 
15 enum GameListColumn
16 {
17     ROOM,
18     CREATED,
19     DESCRIPTION,
20     CREATOR,
21     GAME_TYPE,
22     RESTRICTIONS,
23     PLAYERS,
24     SPECTATORS
25 };
26 
27 const bool DEFAULT_SHOW_FULL_GAMES = false;
28 const bool DEFAULT_SHOW_GAMES_THAT_STARTED = false;
29 const bool DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES = true;
30 const bool DEFAULT_SHOW_BUDDIES_ONLY_GAMES = true;
31 const bool DEFAULT_HIDE_IGNORED_USER_GAMES = false;
32 const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH = false;
33 const bool DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED = true;
34 const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT = false;
35 const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS = false;
36 const int DEFAULT_MAX_PLAYERS_MIN = 1;
37 const int DEFAULT_MAX_PLAYERS_MAX = 99;
38 constexpr QTime DEFAULT_MAX_GAME_AGE = QTime();
39 
getGameCreatedString(const int secs)40 const QString GamesModel::getGameCreatedString(const int secs)
41 {
42     static const QTime zeroTime{0, 0};
43     static const int halfHourSecs = zeroTime.secsTo(QTime(1, 0)) / 2;
44     static const int halfMinSecs = zeroTime.secsTo(QTime(0, 1)) / 2;
45     static const int wrapSeconds = zeroTime.secsTo(zeroTime.addSecs(-halfHourSecs)); // round up
46 
47     if (secs >= wrapSeconds) { // QTime wraps after a day
48         return tr(">1 day");
49     }
50 
51     QTime total = zeroTime.addSecs(secs);
52     QTime totalRounded = total.addSecs(halfMinSecs); // round up
53     QString form;
54     int amount;
55     if (totalRounded.hour()) {
56         amount = total.addSecs(halfHourSecs).hour(); // round up separately
57         form = tr("%1%2 hr", "short age in hours", amount);
58     } else if (total.minute() < 2) { // games are new during their first minute
59         return tr("new");
60     } else {
61         amount = totalRounded.minute();
62         form = tr("%1%2 min", "short age in minutes", amount);
63     }
64 
65     for (int aggregate : {40, 20, 10, 5}) { // floor to values in this list
66         if (amount >= aggregate) {
67             return form.arg(">").arg(aggregate);
68         }
69     }
70     return form.arg("").arg(amount);
71 }
72 
GamesModel(const QMap<int,QString> & _rooms,const QMap<int,GameTypeMap> & _gameTypes,QObject * parent)73 GamesModel::GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent)
74     : QAbstractTableModel(parent), rooms(_rooms), gameTypes(_gameTypes)
75 {
76 }
77 
data(const QModelIndex & index,int role) const78 QVariant GamesModel::data(const QModelIndex &index, int role) const
79 {
80     if (!index.isValid())
81         return QVariant();
82     if (role == Qt::UserRole)
83         return index.row();
84     if (role != Qt::DisplayRole && role != SORT_ROLE && role != Qt::DecorationRole && role != Qt::TextAlignmentRole)
85         return QVariant();
86     if ((index.row() >= gameList.size()) || (index.column() >= columnCount()))
87         return QVariant();
88 
89     const ServerInfo_Game &gameentry = gameList[index.row()];
90     switch (index.column()) {
91         case ROOM:
92             return rooms.value(gameentry.room_id());
93         case CREATED: {
94             switch (role) {
95                 case Qt::DisplayRole: {
96 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
97                     QDateTime then = QDateTime::fromSecsSinceEpoch(gameentry.start_time(), Qt::UTC);
98 #else
99                     QDateTime then = QDateTime::fromTime_t(gameentry.start_time(), Qt::UTC);
100 #endif
101                     int secs = then.secsTo(QDateTime::currentDateTimeUtc());
102                     return getGameCreatedString(secs);
103                 }
104                 case SORT_ROLE:
105                     return QVariant(-static_cast<qint64>(gameentry.start_time()));
106                 case Qt::TextAlignmentRole:
107                     return Qt::AlignCenter;
108                 default:
109                     return QVariant();
110             }
111         }
112         case DESCRIPTION:
113             switch (role) {
114                 case SORT_ROLE:
115                 case Qt::DisplayRole:
116                     return QString::fromStdString(gameentry.description());
117                 case Qt::TextAlignmentRole:
118                     return Qt::AlignLeft;
119                 default:
120                     return QVariant();
121             }
122         case CREATOR: {
123             switch (role) {
124                 case SORT_ROLE:
125                 case Qt::DisplayRole:
126                     return QString::fromStdString(gameentry.creator_info().name());
127                 case Qt::DecorationRole: {
128                     QPixmap avatarPixmap = UserLevelPixmapGenerator::generatePixmap(
129                         13, (UserLevelFlags)gameentry.creator_info().user_level(), false,
130                         QString::fromStdString(gameentry.creator_info().privlevel()));
131                     return QIcon(avatarPixmap);
132                 }
133                 default:
134                     return QVariant();
135             }
136         }
137         case GAME_TYPE:
138             switch (role) {
139                 case SORT_ROLE:
140                 case Qt::DisplayRole: {
141                     QStringList result;
142                     GameTypeMap gameTypeMap = gameTypes.value(gameentry.room_id());
143                     for (int i = gameentry.game_types_size() - 1; i >= 0; --i)
144                         result.append(gameTypeMap.value(gameentry.game_types(i)));
145                     return result.join(", ");
146                 }
147                 case Qt::TextAlignmentRole:
148                     return Qt::AlignLeft;
149                 default:
150                     return QVariant();
151             }
152         case RESTRICTIONS:
153             switch (role) {
154                 case SORT_ROLE:
155                 case Qt::DisplayRole: {
156                     QStringList result;
157                     if (gameentry.with_password())
158                         result.append(tr("password"));
159                     if (gameentry.only_buddies())
160                         result.append(tr("buddies only"));
161                     if (gameentry.only_registered())
162                         result.append(tr("reg. users only"));
163                     return result.join(", ");
164                 }
165                 case Qt::DecorationRole: {
166                     return gameentry.with_password() ? QIcon(LockPixmapGenerator::generatePixmap(13)) : QVariant();
167                     case Qt::TextAlignmentRole:
168                         return Qt::AlignLeft;
169                     default:
170                         return QVariant();
171                 }
172             }
173         case PLAYERS:
174             switch (role) {
175                 case SORT_ROLE:
176                 case Qt::DisplayRole:
177                     return QString("%1/%2").arg(gameentry.player_count()).arg(gameentry.max_players());
178                 case Qt::TextAlignmentRole:
179                     return Qt::AlignCenter;
180                 default:
181                     return QVariant();
182             }
183 
184         case SPECTATORS:
185             switch (role) {
186                 case SORT_ROLE:
187                 case Qt::DisplayRole: {
188                     if (gameentry.spectators_allowed()) {
189                         QString result;
190                         result.append(QString::number(gameentry.spectators_count()));
191 
192                         if (gameentry.spectators_can_chat() && gameentry.spectators_omniscient()) {
193                             result.append(" (")
194                                 .append(tr("can chat"))
195                                 .append(" & ")
196                                 .append(tr("see hands"))
197                                 .append(")");
198                         } else if (gameentry.spectators_can_chat()) {
199                             result.append(" (").append(tr("can chat")).append(")");
200                         } else if (gameentry.spectators_omniscient()) {
201                             result.append(" (").append(tr("can see hands")).append(")");
202                         }
203 
204                         return result;
205                     }
206                     return QVariant(tr("not allowed"));
207                 }
208                 case Qt::TextAlignmentRole:
209                     return Qt::AlignLeft;
210                 default:
211                     return QVariant();
212             }
213         default:
214             return QVariant();
215     }
216 }
217 
headerData(int section,Qt::Orientation,int role) const218 QVariant GamesModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
219 {
220     if ((role != Qt::DisplayRole) && (role != Qt::TextAlignmentRole))
221         return QVariant();
222     switch (section) {
223         case ROOM:
224             return tr("Room");
225         case CREATED: {
226             switch (role) {
227                 case Qt::DisplayRole:
228                     return tr("Age");
229                 case Qt::TextAlignmentRole:
230                     return Qt::AlignCenter;
231                 default:
232                     return QVariant();
233             }
234         }
235         case DESCRIPTION:
236             return tr("Description");
237         case CREATOR:
238             return tr("Creator");
239         case GAME_TYPE:
240             return tr("Type");
241         case RESTRICTIONS:
242             return tr("Restrictions");
243         case PLAYERS: {
244             switch (role) {
245                 case Qt::DisplayRole:
246                     return tr("Players");
247                 case Qt::TextAlignmentRole:
248                     return Qt::AlignCenter;
249                 default:
250                     return QVariant();
251             }
252         }
253         case SPECTATORS:
254             return tr("Spectators");
255         default:
256             return QVariant();
257     }
258 }
259 
getGame(int row)260 const ServerInfo_Game &GamesModel::getGame(int row)
261 {
262     Q_ASSERT(row < gameList.size());
263     return gameList[row];
264 }
265 
updateGameList(const ServerInfo_Game & game)266 void GamesModel::updateGameList(const ServerInfo_Game &game)
267 {
268     for (int i = 0; i < gameList.size(); i++) {
269         if (gameList[i].game_id() == game.game_id()) {
270             if (game.closed()) {
271                 beginRemoveRows(QModelIndex(), i, i);
272                 gameList.removeAt(i);
273                 endRemoveRows();
274             } else {
275                 gameList[i].MergeFrom(game);
276                 emit dataChanged(index(i, 0), index(i, NUM_COLS - 1));
277             }
278             return;
279         }
280     }
281     if (game.player_count() <= 0)
282         return;
283     beginInsertRows(QModelIndex(), gameList.size(), gameList.size());
284     gameList.append(game);
285     endInsertRows();
286 }
287 
GamesProxyModel(QObject * parent,const TabSupervisor * _tabSupervisor)288 GamesProxyModel::GamesProxyModel(QObject *parent, const TabSupervisor *_tabSupervisor)
289     : QSortFilterProxyModel(parent), ownUserIsRegistered(_tabSupervisor->isOwnUserRegistered()),
290       tabSupervisor(_tabSupervisor)
291 {
292     resetFilterParameters();
293     setSortRole(GamesModel::SORT_ROLE);
294     setDynamicSortFilter(true);
295 }
296 
setShowBuddiesOnlyGames(bool _showBuddiesOnlyGames)297 void GamesProxyModel::setShowBuddiesOnlyGames(bool _showBuddiesOnlyGames)
298 {
299     showBuddiesOnlyGames = _showBuddiesOnlyGames;
300     invalidateFilter();
301 }
302 
setHideIgnoredUserGames(bool _hideIgnoredUserGames)303 void GamesProxyModel::setHideIgnoredUserGames(bool _hideIgnoredUserGames)
304 {
305     hideIgnoredUserGames = _hideIgnoredUserGames;
306     invalidateFilter();
307 }
308 
setShowFullGames(bool _showFullGames)309 void GamesProxyModel::setShowFullGames(bool _showFullGames)
310 {
311     showFullGames = _showFullGames;
312     invalidateFilter();
313 }
314 
setShowGamesThatStarted(bool _showGamesThatStarted)315 void GamesProxyModel::setShowGamesThatStarted(bool _showGamesThatStarted)
316 {
317     showGamesThatStarted = _showGamesThatStarted;
318     invalidateFilter();
319 }
320 
setShowPasswordProtectedGames(bool _showPasswordProtectedGames)321 void GamesProxyModel::setShowPasswordProtectedGames(bool _showPasswordProtectedGames)
322 {
323     showPasswordProtectedGames = _showPasswordProtectedGames;
324     invalidateFilter();
325 }
326 
setGameNameFilter(const QString & _gameNameFilter)327 void GamesProxyModel::setGameNameFilter(const QString &_gameNameFilter)
328 {
329     gameNameFilter = _gameNameFilter;
330     invalidateFilter();
331 }
332 
setCreatorNameFilter(const QString & _creatorNameFilter)333 void GamesProxyModel::setCreatorNameFilter(const QString &_creatorNameFilter)
334 {
335     creatorNameFilter = _creatorNameFilter;
336     invalidateFilter();
337 }
338 
setGameTypeFilter(const QSet<int> & _gameTypeFilter)339 void GamesProxyModel::setGameTypeFilter(const QSet<int> &_gameTypeFilter)
340 {
341     gameTypeFilter = _gameTypeFilter;
342     invalidateFilter();
343 }
344 
setMaxPlayersFilter(int _maxPlayersFilterMin,int _maxPlayersFilterMax)345 void GamesProxyModel::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax)
346 {
347     maxPlayersFilterMin = _maxPlayersFilterMin;
348     maxPlayersFilterMax = _maxPlayersFilterMax;
349     invalidateFilter();
350 }
351 
setMaxGameAge(const QTime & _maxGameAge)352 void GamesProxyModel::setMaxGameAge(const QTime &_maxGameAge)
353 {
354     maxGameAge = _maxGameAge;
355     invalidateFilter();
356 }
357 
setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch)358 void GamesProxyModel::setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch)
359 {
360     showOnlyIfSpectatorsCanWatch = _showOnlyIfSpectatorsCanWatch;
361     invalidateFilter();
362 }
363 
setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected)364 void GamesProxyModel::setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected)
365 {
366     showSpectatorPasswordProtected = _showSpectatorPasswordProtected;
367     invalidateFilter();
368 }
369 
setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat)370 void GamesProxyModel::setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat)
371 {
372     showOnlyIfSpectatorsCanChat = _showOnlyIfSpectatorsCanChat;
373     invalidateFilter();
374 }
375 
setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands)376 void GamesProxyModel::setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands)
377 {
378     showOnlyIfSpectatorsCanSeeHands = _showOnlyIfSpectatorsCanSeeHands;
379     invalidateFilter();
380 }
381 
getNumFilteredGames() const382 int GamesProxyModel::getNumFilteredGames() const
383 {
384     GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
385     if (!model)
386         return 0;
387 
388     int numFilteredGames = 0;
389     for (int row = 0; row < model->rowCount(); ++row) {
390         if (!filterAcceptsRow(row)) {
391             ++numFilteredGames;
392         }
393     }
394     return numFilteredGames;
395 }
396 
resetFilterParameters()397 void GamesProxyModel::resetFilterParameters()
398 {
399     showFullGames = DEFAULT_SHOW_FULL_GAMES;
400     showGamesThatStarted = DEFAULT_SHOW_GAMES_THAT_STARTED;
401     showPasswordProtectedGames = DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES;
402     showBuddiesOnlyGames = DEFAULT_SHOW_BUDDIES_ONLY_GAMES;
403     hideIgnoredUserGames = DEFAULT_HIDE_IGNORED_USER_GAMES;
404     gameNameFilter = QString();
405     creatorNameFilter = QString();
406     gameTypeFilter.clear();
407     maxPlayersFilterMin = DEFAULT_MAX_PLAYERS_MIN;
408     maxPlayersFilterMax = DEFAULT_MAX_PLAYERS_MAX;
409     maxGameAge = DEFAULT_MAX_GAME_AGE;
410     showOnlyIfSpectatorsCanWatch = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH;
411     showSpectatorPasswordProtected = DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED;
412     showOnlyIfSpectatorsCanChat = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT;
413     showOnlyIfSpectatorsCanSeeHands = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS;
414 
415     invalidateFilter();
416 }
417 
areFilterParametersSetToDefaults() const418 bool GamesProxyModel::areFilterParametersSetToDefaults() const
419 {
420     return showFullGames == DEFAULT_SHOW_FULL_GAMES && showGamesThatStarted == DEFAULT_SHOW_GAMES_THAT_STARTED &&
421            showPasswordProtectedGames == DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES &&
422            showBuddiesOnlyGames == DEFAULT_SHOW_BUDDIES_ONLY_GAMES &&
423            hideIgnoredUserGames == DEFAULT_HIDE_IGNORED_USER_GAMES && gameNameFilter.isEmpty() &&
424            creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
425            maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE &&
426            showOnlyIfSpectatorsCanWatch == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH &&
427            showSpectatorPasswordProtected == DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED &&
428            showOnlyIfSpectatorsCanChat == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT &&
429            showOnlyIfSpectatorsCanSeeHands == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS;
430 }
431 
loadFilterParameters(const QMap<int,QString> & allGameTypes)432 void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameTypes)
433 {
434     GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
435     showFullGames = gameFilters.isShowFullGames();
436     showGamesThatStarted = gameFilters.isShowGamesThatStarted();
437     showPasswordProtectedGames = gameFilters.isShowPasswordProtectedGames();
438     hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames();
439     showBuddiesOnlyGames = gameFilters.isShowBuddiesOnlyGames();
440     gameNameFilter = gameFilters.getGameNameFilter();
441     creatorNameFilter = gameFilters.getCreatorNameFilter();
442     maxPlayersFilterMin = gameFilters.getMinPlayers();
443     maxPlayersFilterMax = gameFilters.getMaxPlayers();
444     maxGameAge = gameFilters.getMaxGameAge();
445     showOnlyIfSpectatorsCanWatch = gameFilters.isShowOnlyIfSpectatorsCanWatch();
446     showSpectatorPasswordProtected = gameFilters.isShowSpectatorPasswordProtected();
447     showOnlyIfSpectatorsCanChat = gameFilters.isShowOnlyIfSpectatorsCanChat();
448     showOnlyIfSpectatorsCanSeeHands = gameFilters.isShowOnlyIfSpectatorsCanSeeHands();
449 
450     QMapIterator<int, QString> gameTypesIterator(allGameTypes);
451     while (gameTypesIterator.hasNext()) {
452         gameTypesIterator.next();
453         if (gameFilters.isGameTypeEnabled(gameTypesIterator.value())) {
454             gameTypeFilter.insert(gameTypesIterator.key());
455         }
456     }
457 
458     invalidateFilter();
459 }
460 
saveFilterParameters(const QMap<int,QString> & allGameTypes)461 void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameTypes)
462 {
463     GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
464     gameFilters.setShowBuddiesOnlyGames(showBuddiesOnlyGames);
465     gameFilters.setShowFullGames(showFullGames);
466     gameFilters.setShowGamesThatStarted(showGamesThatStarted);
467     gameFilters.setShowPasswordProtectedGames(showPasswordProtectedGames);
468     gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames);
469     gameFilters.setGameNameFilter(gameNameFilter);
470     gameFilters.setCreatorNameFilter(creatorNameFilter);
471 
472     QMapIterator<int, QString> gameTypeIterator(allGameTypes);
473     while (gameTypeIterator.hasNext()) {
474         gameTypeIterator.next();
475         bool enabled = gameTypeFilter.contains(gameTypeIterator.key());
476         gameFilters.setGameTypeEnabled(gameTypeIterator.value(), enabled);
477     }
478 
479     gameFilters.setMinPlayers(maxPlayersFilterMin);
480     gameFilters.setMaxPlayers(maxPlayersFilterMax);
481     gameFilters.setMaxGameAge(maxGameAge);
482 
483     gameFilters.setShowOnlyIfSpectatorsCanWatch(showOnlyIfSpectatorsCanWatch);
484     gameFilters.setShowSpectatorPasswordProtected(showSpectatorPasswordProtected);
485     gameFilters.setShowOnlyIfSpectatorsCanChat(showOnlyIfSpectatorsCanChat);
486     gameFilters.setShowOnlyIfSpectatorsCanSeeHands(showOnlyIfSpectatorsCanSeeHands);
487 }
488 
filterAcceptsRow(int sourceRow,const QModelIndex &) const489 bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
490 {
491     return filterAcceptsRow(sourceRow);
492 }
493 
filterAcceptsRow(int sourceRow) const494 bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
495 {
496 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
497     static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, Qt::UTC).date();
498 #else
499     static const QDate epochDate = QDateTime::fromTime_t(0, Qt::UTC).date();
500 #endif
501     auto *model = qobject_cast<GamesModel *>(sourceModel());
502     if (!model)
503         return false;
504 
505     const ServerInfo_Game &game = model->getGame(sourceRow);
506 
507     if (!showBuddiesOnlyGames && game.only_buddies()) {
508         return false;
509     }
510     if (hideIgnoredUserGames && tabSupervisor->getUserListsTab()->getIgnoreList()->getUsers().contains(
511                                     QString::fromStdString(game.creator_info().name()))) {
512         return false;
513     }
514     if (!showFullGames && game.player_count() == game.max_players())
515         return false;
516     if (!showGamesThatStarted && game.started())
517         return false;
518     if (!ownUserIsRegistered)
519         if (game.only_registered())
520             return false;
521     if (!showPasswordProtectedGames && game.with_password())
522         return false;
523     if (!gameNameFilter.isEmpty())
524         if (!QString::fromStdString(game.description()).contains(gameNameFilter, Qt::CaseInsensitive))
525             return false;
526     if (!creatorNameFilter.isEmpty())
527         if (!QString::fromStdString(game.creator_info().name()).contains(creatorNameFilter, Qt::CaseInsensitive))
528             return false;
529 
530     QSet<int> gameTypes;
531     for (int i = 0; i < game.game_types_size(); ++i)
532         gameTypes.insert(game.game_types(i));
533     if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty())
534         return false;
535 
536     if (game.max_players() < maxPlayersFilterMin)
537         return false;
538     if (game.max_players() > maxPlayersFilterMax)
539         return false;
540 
541     if (maxGameAge.isValid()) {
542         QDateTime now = QDateTime::currentDateTimeUtc();
543         qint64 signed_start_time = game.start_time();      // cast to 64 bit value to allow signed value
544         QDateTime total = now.addSecs(-signed_start_time); // a 32 bit value would wrap at 2038-1-19
545         // games shouldn't have negative ages but we'll not filter them
546         // because qtime wraps after a day we consider all games older than a day to be too old
547         if (total.isValid() && total.date() >= epochDate && (total.date() > epochDate || total.time() > maxGameAge)) {
548             return false;
549         }
550     }
551 
552     if (showOnlyIfSpectatorsCanWatch) {
553         if (!game.spectators_allowed())
554             return false;
555         if (!showSpectatorPasswordProtected && game.spectators_need_password())
556             return false;
557         if (showOnlyIfSpectatorsCanChat && !game.spectators_can_chat())
558             return false;
559         if (showOnlyIfSpectatorsCanSeeHands && !game.spectators_omniscient())
560             return false;
561     }
562     return true;
563 }
564 
refresh()565 void GamesProxyModel::refresh()
566 {
567     invalidateFilter();
568 }
569