serverlistrowhandler.cpp
1 //------------------------------------------------------------------------------
2 // serverlistrowhandler.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2010 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "application.h"
24 #include "configuration/doomseekerconfig.h"
25 #include "gui/dockBuddiesList.h"
26 #include "gui/helpers/playersdiagram.h"
27 #include "gui/mainwindow.h"
28 #include "gui/serverlist.h"
29 #include "gui/widgets/serverlistview.h"
30 #include "ip2c/ip2c.h"
31 #include "log.h"
32 #include "serverapi/playerslist.h"
33 #include "serverapi/server.h"
35 #include "serverlistcolumn.h"
36 #include "serverlistmodel.h"
37 #include "serverlistrowhandler.h"
38 #include <QPainter>
39 
40 using namespace ServerListColumnId;
41 
42 DClass<ServerListRowHandler>
43 {
44 public:
45  ServerPtr server;
46 };
47 
48 DPointered(ServerListRowHandler)
49 
51  int rowIndex, const ServerPtr &server)
52  : model(parentModel), row(rowIndex)
53 {
54  d->server = server;
55 }
56 
57 ServerListRowHandler::ServerListRowHandler(ServerListModel *parentModel, int rowIndex)
58  : model(parentModel), row(rowIndex)
59 {
60  d->server = serverFromList(parentModel, rowIndex);
61 }
62 
63 ServerListRowHandler::~ServerListRowHandler()
64 {
65 }
66 
68 {
69  for (int i = 0; i < NUM_SERVERLIST_COLUMNS; ++i)
70  {
71  if (!ServerListColumns::isColumnVital(i))
72  emptyItem(item(i));
73  }
74 }
75 
76 void ServerListRowHandler::emptyItem(QStandardItem *item)
77 {
78  item->setData("", Qt::DisplayRole);
79  item->setData(QVariant(), Qt::DecorationRole);
80  item->setData(QVariant(), DTSort);
81 }
82 
83 QStringList ServerListRowHandler::extractValidGameCVarNames(const QList<GameCVar> &cvars)
84 {
85  QStringList result;
86  for (const GameCVar &cvar : cvars)
87  {
88  if (!cvar.isValid())
89  result << cvar.name();
90  }
91  return result;
92 }
93 
94 void ServerListRowHandler::fillAddressColumn()
95 {
96  QStandardItem *pItem = item(IDAddress);
97  fillItem(pItem, d->server->address(), d->server->hostName());
98 }
99 
100 void ServerListRowHandler::fillItem(QStandardItem *item, const QString &str)
101 {
102  QString strLowcase = str.toLower();
103  item->setData(str, Qt::DisplayRole);
104  item->setData(strLowcase, DTSort);
105 }
106 
107 void ServerListRowHandler::fillItem(QStandardItem *item, int sort, const QString &str)
108 {
109  QVariant var = sort;
110 
111  fillItem(item, str);
112  item->setData(sort, DTSort);
113 }
114 
115 void ServerListRowHandler::fillItem(QStandardItem *item, int num)
116 {
117  QVariant var = num;
118 
119  item->setData(var, Qt::DisplayRole);
120  item->setData(var, DTSort);
121 }
122 
123 void ServerListRowHandler::fillItem(QStandardItem *item, const QHostAddress &addr, const QString &actualDisplay)
124 {
125  QVariant var = addr.toIPv4Address();
126 
127  if (actualDisplay.isEmpty())
128  item->setData(addr.toString(), Qt::DisplayRole);
129  else
130  item->setData(actualDisplay, Qt::DisplayRole);
131  item->setData(var, DTSort);
132 }
133 
134 void ServerListRowHandler::fillItem(QStandardItem *item, const QString &sort, const QPixmap &icon)
135 {
136  item->setIcon(QIcon(icon));
137  item->setData(sort, DTSort);
138 }
139 
140 void ServerListRowHandler::fillItem(QStandardItem *item, int sort, const QPixmap &image)
141 {
142  item->setData(image, Qt::DecorationRole);
143  item->setData(sort, DTSort);
144 }
145 
146 void ServerListRowHandler::fillPlayerColumn()
147 {
148  QStandardItem *pItem = item(IDPlayers);
149 
150  QString style = gConfig.doomseeker.slotStyle;
151  bool botsAreNotPlayers = gConfig.doomseeker.bBotsAreNotPlayers;
152 
153  const PlayersList &players = d->server->players();
154  int sortValue = 0;
155 
156  if (botsAreNotPlayers)
157  sortValue = players.numClientsWithoutBots();
158  else
159  sortValue = players.numClients();
160 
161  if (!PlayersDiagram::isNumericStyle(style))
162  fillItem(pItem, sortValue, PlayersDiagram(d->server).pixmap());
163  else
164  {
165  fillItem(pItem, sortValue, QString("%1/%2").arg(players.numClients())
166  .arg(d->server->numTotalSlots()));
167  }
168 
169  // Unset some data if it has been set before.
170  pItem->setData(QVariant(QVariant::Invalid), PlayersDiagram::isNumericStyle(style) ? Qt::DecorationRole : Qt::DisplayRole);
171  pItem->setData(PlayersDiagram::isNumericStyle(style) ? 0 : USERROLE_RIGHTALIGNDECORATION, Qt::UserRole);
172 }
173 
174 void ServerListRowHandler::fillPortIconColumn()
175 {
176  QStandardItem *pItem = item(IDPort);
177  QPixmap icon = d->server->icon();
178  if (d->server->isKnown())
179  {
180  if (d->server->isLockedAnywhere()) // Draw a key if it is locked.
181  {
182  QPainter iconPainter(&icon);
183  iconPainter.drawPixmap(0, 0, QPixmap(":/locked.png"));
184  iconPainter.end();
185  }
186  else if (d->server->isSecure())
187  {
188  QPainter iconPainter(&icon);
189  iconPainter.drawPixmap(0, 0, QPixmap(":/shield.png"));
190  iconPainter.end();
191  }
192  // 't' is drawn on a different part of the logo therefore it can be
193  // drawn together with other icons
194  if (d->server->isTestingServer())
195  {
196  QPainter iconPainter(&icon);
197  iconPainter.drawPixmap(0, 0, QPixmap(":/t.png"));
198  iconPainter.end();
199  }
200  }
201  fillItem(pItem, d->server->metaObject()->className(), icon);
202 }
203 
204 void ServerListRowHandler::fillServerPointerColumn()
205 {
206  QStandardItem *pItem = item(IDHiddenServerPointer);
207  QVariant savePointer = qVariantFromValue(d->server);
208  pItem->setData(savePointer, DTPointerToServerStructure);
209 }
210 
211 QStandardItem *ServerListRowHandler::item(int columnIndex)
212 {
213  return model->item(row, columnIndex);
214 }
215 
216 void ServerListRowHandler::redraw()
217 {
218  updateServer();
219 
220  // Since updateServer doesn't do anything with the flags we need to
221  // explicitly redraw it here.
222  setCountryFlag();
223 }
224 
225 ServerPtr ServerListRowHandler::server()
226 {
227  return d->server;
228 }
229 
230 void ServerListRowHandler::setBackgroundColor()
231 {
232  QString color;
233  if (d->server->isCustom())
234  color = gConfig.doomseeker.customServersColor;
235  else if (d->server->isLan())
236  color = gConfig.doomseeker.lanServersColor;
237  else if (gApp->mainWindow()->buddiesList()->hasBuddy(d->server))
238  {
239  if (gConfig.doomseeker.bMarkServersWithBuddies)
240  color = gConfig.doomseeker.buddyServersColor;
241  }
242 
243  for (int column = 0; column < NUM_SERVERLIST_COLUMNS; ++column)
244  {
245  QBrush brush = !color.isEmpty()
246  ? QBrush(QColor(color))
247  : Qt::NoBrush;
248  QStandardItem *pItem = item(column);
249  pItem->setBackground(brush);
250  }
251 }
252 
253 void ServerListRowHandler::setBad()
254 {
255  QStandardItem *qstdItem;
256 
258 
259  qstdItem = item(IDServerName);
260  fillItem(qstdItem, tr("<ERROR>"));
261 
262  qstdItem = item(IDHiddenGroup);
263  fillItem(qstdItem, SGBad);
264 }
265 
266 void ServerListRowHandler::setBanned()
267 {
268  QStandardItem *qstdItem;
269 
271 
272  qstdItem = item(IDServerName);
273  fillItem(qstdItem, tr("You are banned from this server!"));
274 
275  qstdItem = item(IDHiddenGroup);
276  fillItem(qstdItem, SGBanned);
277 }
278 
279 void ServerListRowHandler::setCountryFlag()
280 {
281  QStandardItem *pItem = item(IDServerName);
282 
283  if (!IP2C::instance()->isDataAccessLocked())
284  {
285  IP2CCountryInfo countryInfo = IP2C::instance()->obtainCountryInfo(d->server->address());
286  if (countryInfo.isValid())
287  {
288  QPixmap flag = *countryInfo.flag;
289  pItem->setIcon(flag);
290  }
291  }
292 }
293 
294 void ServerListRowHandler::setFirstQuery()
295 {
296  QStandardItem *qstdItem = item(IDHiddenGroup);
297  fillItem(qstdItem, SGFirstQuery);
298 }
299 
300 void ServerListRowHandler::setGood()
301 {
302  QStandardItem *qstdItem;
303  QString strTmp;
304 
305  fillPlayerColumn();
306 
307  qstdItem = item(IDPing);
308  fillItem(qstdItem, d->server->ping());
309 
310  qstdItem = item(IDServerName);
311  fillItem(qstdItem, d->server->name());
312 
313  qstdItem = item(IDIwad);
314  fillItem(qstdItem, d->server->iwad());
315 
316  qstdItem = item(IDMap);
317  fillItem(qstdItem, d->server->map());
318 
319  strTmp.clear();
320  for (const PWad &wad : d->server->wads())
321  {
322  if (wad.isOptional())
323  strTmp += QString("[%1] ").arg(wad.name());
324  else
325  strTmp += wad.name() + " ";
326  }
327  strTmp.chop(1);
328  qstdItem = item(IDWads);
329  fillItem(qstdItem, strTmp);
330 
331  qstdItem = item(IDGametype);
332  QString fullGameModeName = d->server->gameMode().name();
333  QStringList modifierNames = extractValidGameCVarNames(d->server->modifiers());
334  if (!modifierNames.isEmpty())
335  fullGameModeName += QString(" (%1)").arg(modifierNames.join(", "));
336  fillItem(qstdItem, fullGameModeName);
337 
338  qstdItem = item(IDHiddenGroup);
339  fillItem(qstdItem, SGNormal);
340 }
341 
342 void ServerListRowHandler::setRefreshing()
343 {
344  QStandardItem *qstdItem = item(IDServerName);
345  qstdItem->setText(tr("<REFRESHING>"));
346 }
347 
348 void ServerListRowHandler::setTimeout()
349 {
350  QStandardItem *qstdItem;
351 
353 
354  qstdItem = item(IDServerName);
355  fillItem(qstdItem, tr("<NO RESPONSE>"));
356 
357  qstdItem = item(IDHiddenGroup);
358  fillItem(qstdItem, SGTimeout);
359 }
360 
361 void ServerListRowHandler::setWait()
362 {
363  QStandardItem *qstdItem;
364 
366 
367  qstdItem = item(IDServerName);
368  fillItem(qstdItem, tr("<Refreshed too soon, wait a while and try again>"));
369 
370  qstdItem = item(IDHiddenGroup);
371  fillItem(qstdItem, SGWait);
372 }
373 
374 ServerPtr ServerListRowHandler::serverFromList(const ServerListModel *parentModel, int rowIndex)
375 {
376  QStandardItem *pItem = parentModel->item(rowIndex, IDHiddenServerPointer);
377  QVariant pointer = pItem->data(DTPointerToServerStructure);
378  if (!pointer.isValid())
379  return ServerPtr();
380  return pointer.value<ServerPtr>();
381 }
382 
383 int ServerListRowHandler::updateServer()
384 {
385  fillServerPointerColumn();
386  fillPortIconColumn();
387  fillAddressColumn();
388 
389  switch (d->server->lastResponse())
390  {
392  setBad();
393  break;
394 
396  setBanned();
397  break;
398 
400  setGood();
401  break;
402 
404  if (d->server->isKnown())
405  setGood();
406  else
407  setWait();
408  break;
409 
411  setTimeout();
412  break;
413 
415  setFirstQuery();
416  if (d->server->isRefreshing())
417  setRefreshing();
418  break;
419 
420  default:
421  gLog << tr("Unknown server response (%1): %2:%3").arg(d->server->lastResponse())
422  .arg(d->server->address().toString()).arg(d->server->port());
423  break;
424  }
425 
426  setBackgroundColor();
427 
428  return row;
429 }
IP2CCountryInfo obtainCountryInfo(unsigned int ipaddress)
Definition: ip2c.cpp:147
PWAD hosted on a server.
Player is banned from that server.
Definition: server.h:132
"Dummy" response for servers that weren&#39;t refreshed yet.
Definition: server.h:136
Response from the server was erroneous.
Definition: server.h:128
Response was parsed properly and Server information is available.
Definition: server.h:113
Flag and name of the country.
Server didn&#39;t respond at all.
Definition: server.h:117
int numClients() const
Overall number of people and bots on the server.
A general game setting or variable (like fraglimit).
Server responded with "wait", may happen when we refresh too quickly.
Definition: server.h:122