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 "serverlistrowhandler.h"
24 #include "serverlistcolumn.h"
25 #include "serverlistmodel.h"
26 #include "configuration/doomseekerconfig.h"
27 #include "gui/helpers/playersdiagram.h"
28 #include "gui/widgets/serverlistview.h"
29 #include "gui/dockBuddiesList.h"
30 #include "gui/mainwindow.h"
31 #include "gui/serverlist.h"
32 #include "ip2c/ip2c.h"
33 #include "serverapi/playerslist.h"
34 #include "serverapi/server.h"
36 #include "application.h"
37 #include "log.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  {
73  emptyItem(item(i));
74  }
75  }
76 }
77 
78 void ServerListRowHandler::emptyItem(QStandardItem* item)
79 {
80  item->setData("", Qt::DisplayRole);
81  item->setData(QVariant(), Qt::DecorationRole);
82  item->setData(QVariant(), DTSort);
83 }
84 
85 QStringList ServerListRowHandler::extractValidGameCVarNames(const QList<GameCVar> &cvars)
86 {
87  QStringList result;
88  foreach (const GameCVar &cvar, cvars)
89  {
90  if (!cvar.isValid())
91  {
92  result << cvar.name();
93  }
94  }
95  return result;
96 }
97 
98 void ServerListRowHandler::fillAddressColumn()
99 {
100  QStandardItem* pItem = item(IDAddress);
101  fillItem(pItem, d->server->address(), d->server->hostName() );
102 }
103 
104 void ServerListRowHandler::fillItem(QStandardItem* item, const QString& str)
105 {
106  QString strLowcase = str.toLower();
107  item->setData(str, Qt::DisplayRole);
108  item->setData(strLowcase, DTSort);
109 }
110 
111 void ServerListRowHandler::fillItem(QStandardItem* item, int sort, const QString& str)
112 {
113  QVariant var = sort;
114 
115  fillItem(item, str);
116  item->setData(sort, DTSort);
117 }
118 
119 void ServerListRowHandler::fillItem(QStandardItem* item, int num)
120 {
121  QVariant var = num;
122 
123  item->setData(var, Qt::DisplayRole);
124  item->setData(var, DTSort);
125 }
126 
127 void ServerListRowHandler::fillItem(QStandardItem* item, const QHostAddress& addr, const QString& actualDisplay)
128 {
129  QVariant var = addr.toIPv4Address();
130 
131  if (actualDisplay.isEmpty())
132  {
133  item->setData(addr.toString(), Qt::DisplayRole);
134  }
135  else
136  {
137  item->setData(actualDisplay, Qt::DisplayRole);
138  }
139  item->setData(var, DTSort);
140 }
141 
142 void ServerListRowHandler::fillItem(QStandardItem* item, const QString& sort, const QPixmap& icon)
143 {
144  item->setIcon(QIcon(icon));
145  item->setData(sort, DTSort);
146 }
147 
148 void ServerListRowHandler::fillItem(QStandardItem* item, int sort, const QPixmap& image)
149 {
150  item->setData(image, Qt::DecorationRole);
151  item->setData(sort, DTSort);
152 }
153 
154 void ServerListRowHandler::fillPlayerColumn()
155 {
156  QStandardItem* pItem = item(IDPlayers);
157 
158  QString style = gConfig.doomseeker.slotStyle;
159  bool botsAreNotPlayers = gConfig.doomseeker.bBotsAreNotPlayers;
160 
161  const PlayersList &players = d->server->players();
162  int sortValue = 0;
163 
164  if (botsAreNotPlayers)
165  {
166  sortValue = players.numClientsWithoutBots();
167  }
168  else
169  {
170  sortValue = players.numClients();
171  }
172 
173  if(!PlayersDiagram::isNumericStyle(style))
174  {
175  fillItem(pItem, sortValue, PlayersDiagram(d->server).pixmap());
176  }
177  else
178  {
179  fillItem(pItem, sortValue, QString("%1/%2").arg(players.numClients())
180  .arg(d->server->numTotalSlots()));
181  }
182 
183  // Unset some data if it has been set before.
184  pItem->setData(QVariant(QVariant::Invalid), PlayersDiagram::isNumericStyle(style) ? Qt::DecorationRole : Qt::DisplayRole);
185  pItem->setData(PlayersDiagram::isNumericStyle(style) ? 0 : USERROLE_RIGHTALIGNDECORATION, Qt::UserRole);
186 }
187 
188 void ServerListRowHandler::fillPortIconColumn()
189 {
190  QStandardItem* pItem = item(IDPort);
191  QPixmap icon = d->server->icon();
192  if(d->server->isKnown())
193  {
194  if(d->server->isLockedAnywhere()) // Draw a key if it is locked.
195  {
196  QPainter iconPainter(&icon);
197  iconPainter.drawPixmap(0, 0, QPixmap(":/locked.png"));
198  iconPainter.end();
199  }
200  else if(d->server->isSecure())
201  {
202  QPainter iconPainter(&icon);
203  iconPainter.drawPixmap(0, 0, QPixmap(":/shield.png"));
204  iconPainter.end();
205  }
206  // 't' is drawn on a different part of the logo therefore it can be
207  // drawn together with other icons
208  if (d->server->isTestingServer())
209  {
210  QPainter iconPainter(&icon);
211  iconPainter.drawPixmap(0, 0, QPixmap(":/t.png"));
212  iconPainter.end();
213  }
214  }
215  fillItem(pItem, d->server->metaObject()->className(), icon);
216 }
217 
218 void ServerListRowHandler::fillServerPointerColumn()
219 {
220  QStandardItem* pItem = item(IDHiddenServerPointer);
221  QVariant savePointer = qVariantFromValue(d->server);
222  pItem->setData(savePointer, DTPointerToServerStructure);
223 }
224 
225 QStandardItem* ServerListRowHandler::item(int columnIndex)
226 {
227  return model->item(row, columnIndex);
228 }
229 
230 void ServerListRowHandler::redraw()
231 {
232  updateServer();
233 
234  // Since updateServer doesn't do anything with the flags we need to
235  // explicitly redraw it here.
236  setCountryFlag();
237 }
238 
239 ServerPtr ServerListRowHandler::server()
240 {
241  return d->server;
242 }
243 
244 void ServerListRowHandler::setBackgroundColor()
245 {
246  QString color;
247  if (d->server->isCustom())
248  {
249  color = gConfig.doomseeker.customServersColor;
250  }
251  else if (d->server->isLan())
252  {
253  color = gConfig.doomseeker.lanServersColor;
254  }
255  else if (gApp->mainWindow()->buddiesList()->hasBuddy(d->server))
256  {
257  if (gConfig.doomseeker.bMarkServersWithBuddies)
258  {
259  color = gConfig.doomseeker.buddyServersColor;
260  }
261  }
262 
263  for (int column = 0; column < NUM_SERVERLIST_COLUMNS; ++column)
264  {
265  QBrush brush = !color.isEmpty()
266  ? QBrush(QColor(color))
267  : Qt::NoBrush;
268  QStandardItem* pItem = item(column);
269  pItem->setBackground(brush);
270  }
271 }
272 
273 void ServerListRowHandler::setBad()
274 {
275  QStandardItem* qstdItem;
276 
278 
279  qstdItem = item(IDServerName);
280  fillItem(qstdItem, tr("<ERROR>"));
281 
282  qstdItem = item(IDHiddenGroup);
283  fillItem(qstdItem, SGBad);
284 }
285 
286 void ServerListRowHandler::setBanned()
287 {
288  QStandardItem* qstdItem;
289 
291 
292  qstdItem = item(IDServerName);
293  fillItem(qstdItem, tr("You are banned from this server!"));
294 
295  qstdItem = item(IDHiddenGroup);
296  fillItem(qstdItem, SGBanned);
297 }
298 
299 void ServerListRowHandler::setCountryFlag()
300 {
301  QStandardItem* pItem = item(IDServerName);
302 
303  if (!IP2C::instance()->isDataAccessLocked())
304  {
305  IP2CCountryInfo countryInfo = IP2C::instance()->obtainCountryInfo(d->server->address());
306  if (countryInfo.isValid())
307  {
308  QPixmap flag = *countryInfo.flag;
309  pItem->setIcon(flag);
310  }
311  }
312 }
313 
314 void ServerListRowHandler::setFirstQuery()
315 {
316  QStandardItem* qstdItem = item(IDHiddenGroup);
317  fillItem(qstdItem, SGFirstQuery);
318 }
319 
320 void ServerListRowHandler::setGood()
321 {
322  QStandardItem* qstdItem;
323  QString strTmp;
324 
325  fillPlayerColumn();
326 
327  qstdItem = item(IDPing);
328  fillItem(qstdItem, d->server->ping());
329 
330  qstdItem = item(IDServerName);
331  fillItem(qstdItem, d->server->name());
332 
333  qstdItem = item(IDIwad);
334  fillItem(qstdItem, d->server->iwad());
335 
336  qstdItem = item(IDMap);
337  fillItem(qstdItem, d->server->map());
338 
339  strTmp.clear();
340  foreach(const PWad &wad, d->server->wads())
341  {
342  if(wad.isOptional())
343  {
344  strTmp += QString("[%1] ").arg(wad.name());
345  }
346  else
347  {
348  strTmp += wad.name() + " ";
349  }
350  }
351  strTmp.chop(1);
352  qstdItem = item(IDWads);
353  fillItem(qstdItem, strTmp);
354 
355  qstdItem = item(IDGametype);
356  QString fullGameModeName = d->server->gameMode().name();
357  QStringList modifierNames = extractValidGameCVarNames(d->server->modifiers());
358  if (!modifierNames.isEmpty())
359  {
360  fullGameModeName += QString(" (%1)").arg(modifierNames.join(", "));
361  }
362  fillItem(qstdItem, fullGameModeName);
363 
364  qstdItem = item(IDHiddenGroup);
365  fillItem(qstdItem, SGNormal);
366 }
367 
368 void ServerListRowHandler::setRefreshing()
369 {
370  QStandardItem* qstdItem = item(IDServerName);
371  qstdItem->setText(tr("<REFRESHING>"));
372 }
373 
374 void ServerListRowHandler::setTimeout()
375 {
376  QStandardItem* qstdItem;
377 
379 
380  qstdItem = item(IDServerName);
381  fillItem(qstdItem, tr("<NO RESPONSE>"));
382 
383  qstdItem = item(IDHiddenGroup);
384  fillItem(qstdItem, SGTimeout);
385 }
386 
387 void ServerListRowHandler::setWait()
388 {
389  QStandardItem* qstdItem;
390 
392 
393  qstdItem = item(IDServerName);
394  fillItem(qstdItem, tr("<Refreshed too soon, wait a while and try again>") );
395 
396  qstdItem = item(IDHiddenGroup);
397  fillItem(qstdItem, SGWait);
398 }
399 
400 ServerPtr ServerListRowHandler::serverFromList(const ServerListModel* parentModel, int rowIndex)
401 {
402  QStandardItem* pItem = parentModel->item(rowIndex, IDHiddenServerPointer);
403  QVariant pointer = pItem->data(DTPointerToServerStructure);
404  if (!pointer.isValid())
405  {
406  return ServerPtr();
407  }
408  return pointer.value<ServerPtr>();
409 }
410 
411 int ServerListRowHandler::updateServer()
412 {
413  fillServerPointerColumn();
414  fillPortIconColumn();
415  fillAddressColumn();
416 
417  switch(d->server->lastResponse())
418  {
420  setBad();
421  break;
422 
424  setBanned();
425  break;
426 
428  setGood();
429  break;
430 
432  if (d->server->isKnown())
433  {
434  setGood();
435  }
436  else
437  {
438  setWait();
439  }
440  break;
441 
443  setTimeout();
444  break;
445 
447  setFirstQuery();
448  if (d->server->isRefreshing())
449  {
450  setRefreshing();
451  }
452  break;
453 
454  default:
455  gLog << tr("Unknown server response (%1): %2:%3").arg(d->server->lastResponse())
456  .arg(d->server->address().toString()).arg(d->server->port());
457  break;
458  }
459 
460  setBackgroundColor();
461 
462  return row;
463 }
const QString & name() const
Nice name to display to user in Create Game dialog and in other widgets.
IP2CCountryInfo obtainCountryInfo(unsigned int ipaddress)
Definition: ip2c.cpp:157
PWAD hosted on a server.
bool isValid() const
&#39;Null&#39; objects are invalid.
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 erroreneous.
Definition: server.h:128
Response was parsed properly and Server information is available.
Definition: server.h:113
Flag and name of the country.
bool isOptional() const
Is this WAD required to join the server?
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
const QString & name() const
File name of the WAD.