23 #include "serverlist.h" 25 #include "configuration/doomseekerconfig.h" 26 #include "gui/mainwindow.h" 27 #include "gui/remoteconsole.h" 28 #include "gui/models/serverlistcolumn.h" 29 #include "gui/models/serverlistmodel.h" 30 #include "gui/models/serverlistproxymodel.h" 31 #include "gui/widgets/serverlistcontextmenu.h" 32 #include "gui/widgets/serverlistview.h" 33 #include "refresher/refresher.h" 34 #include "serverapi/tooltips/servertooltip.h" 35 #include "serverapi/server.h" 36 #include "urlopener.h" 37 #include <QHeaderView> 38 #include <QMessageBox> 44 : mainWindow(pMainWindow), model(NULL), needsCleaning(false),
45 proxyModel(NULL), sortOrder(Qt::AscendingOrder),
46 sortIndex(-1), table(serverTable)
52 ServerList::~ServerList()
54 saveColumnsWidthsSettings();
59 gConfig.serverFilter.info = filterInfo;
60 proxyModel->setFilterInfo(filterInfo);
64 bool ServerList::areColumnsWidthsSettingsChanged()
66 for(
int i = 0; i < NUM_SERVERLIST_COLUMNS; ++i)
68 if(ServerListColumns::columns[i].width != table->columnWidth(i))
77 void ServerList::cleanUp()
85 void ServerList::cleanUpRightNow()
87 if (mainWindow->isEffectivelyActiveWindow())
93 void ServerList::cleanUpForce()
95 if (table == NULL || table->model() == NULL)
101 pModel->invalidate();
102 pModel->sortServers(sortIndex, sortOrder);
105 setCountryFlagsIfNotPresent();
106 needsCleaning =
false;
109 void ServerList::clearAdditionalSorting()
111 proxyModel->clearAdditionalSorting();
114 void ServerList::columnHeaderClicked(
int index)
116 if (isSortingByColumn(index))
118 sortOrder = swappedCurrentSortOrder();
122 sortOrder = getColumnDefaultSortOrder(index);
128 QHeaderView* header = table->horizontalHeader();
129 header->setSortIndicator(sortIndex, sortOrder);
132 void ServerList::connectTableModelProxySlots()
134 QHeaderView* header = table->horizontalHeader();
135 this->connect(header, SIGNAL(sectionClicked(
int)), SLOT(columnHeaderClicked(
int)));
137 this->connect(table->selectionModel(),
138 SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
139 SLOT(itemSelected(QItemSelection)));
140 this->connect(table, SIGNAL(middleMouseClicked(QModelIndex, QPoint)),
141 SLOT(tableMiddleClicked(QModelIndex, QPoint)));
142 this->connect(table, SIGNAL(rightMouseClicked(QModelIndex, QPoint)),
143 SLOT(tableRightClicked(QModelIndex, QPoint)));
144 this->connect(table, SIGNAL(entered(QModelIndex)), SLOT(mouseEntered(QModelIndex)));
145 this->connect(table, SIGNAL(leftMouseDoubleClicked(QModelIndex, QPoint)),
146 SLOT(doubleClicked(QModelIndex)));
149 void ServerList::contextMenuAboutToHide()
151 sender()->deleteLater();
154 void ServerList::contextMenuTriggered(QAction* action)
157 ServerPtr server = contextMenu->server();
162 emit serverFilterModified(contextMenu->serverFilter());
165 switch (contextMenuResult)
171 case ServerListContextMenu::FindMissingWADs:
172 emit findMissingWADs(server);
175 case ServerListContextMenu::Join:
176 emit serverDoubleClicked(server);
179 case ServerListContextMenu::OpenRemoteConsole:
183 case ServerListContextMenu::OpenURL:
187 UrlOpener::instance()->open(server->webSite());
194 case ServerListContextMenu::Refresh:
198 case ServerListContextMenu::ShowJoinCommandLine:
199 emit displayServerJoinCommandLine(server);
202 case ServerListContextMenu::SortAdditionallyAscending:
203 sortAdditionally(contextMenu->modelIndex(), Qt::AscendingOrder);
206 case ServerListContextMenu::SortAdditionallyDescending:
207 sortAdditionally(contextMenu->modelIndex(), Qt::DescendingOrder);
210 case ServerListContextMenu::RemoveAdditionalSortingForColumn:
211 removeAdditionalSortingForColumn(contextMenu->modelIndex());
214 case ServerListContextMenu::ClearAdditionalSorting:
215 clearAdditionalSorting();
218 case ServerListContextMenu::TogglePinServers:
219 foreach (
const ServerPtr &server, contextMenu->servers())
221 model->redraw(server.data());
226 QMessageBox::warning(mainWindow, tr(
"Doomseeker - context menu warning"),
227 tr(
"Unhandled behavior in ServerList::contextMenuTriggered()"));
235 serverListModel->prepareHeaders();
236 return serverListModel;
242 this->connect(proxy, SIGNAL(additionalSortColumnsChanged()),
243 SLOT(updateHeaderTitles()));
244 this->connect(proxy, SIGNAL(additionalSortColumnsChanged()),
245 SLOT(saveAdditionalSortingConfig()));
246 proxy->setSourceModel(serverListModel);
247 proxy->setSortRole(ServerListModel::SLDT_SORT);
248 proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
249 proxy->setFilterKeyColumn(IDServerName);
254 void ServerList::doubleClicked(
const QModelIndex& index)
256 emit serverDoubleClicked(serverFromIndex(index));
259 Qt::SortOrder ServerList::getColumnDefaultSortOrder(
int columnId)
262 return ServerListColumns::columns[columnId].defaultSortOrder;
265 bool ServerList::hasAtLeastOneServer()
const 267 return model->rowCount() > 0;
270 void ServerList::initCleanerTimer()
272 cleanerTimer.setInterval(200);
273 cleanerTimer.start();
274 connect(&cleanerTimer, SIGNAL( timeout() ),
this, SLOT ( cleanUp() ) );
277 bool ServerList::isAnyColumnSortedAdditionally()
const 279 return proxyModel->isAnyColumnSortedAdditionally();
282 bool ServerList::isSortingAdditionallyByColumn(
int column)
const 284 return proxyModel->isSortingAdditionallyByColumn(column);
287 bool ServerList::isSortingByColumn(
int columnIndex)
289 return sortIndex == columnIndex;
292 void ServerList::itemSelected(
const QItemSelection& selection)
294 QSortFilterProxyModel* pModel =
static_cast<QSortFilterProxyModel*
>(table->model());
295 QModelIndexList indexList = selection.indexes();
297 QList<ServerPtr> servers;
298 for(
int i = 0; i < indexList.count(); ++i)
300 QModelIndex realIndex = pModel->mapToSource(indexList[i]);
301 ServerPtr server = model->serverFromList(realIndex);
302 servers.append(server);
304 emit serversSelected(servers);
309 for (
int i = 0; i < model->rowCount(); ++i)
311 ServerPtr server = model->serverFromList(i);
312 server->lookupHost();
316 void ServerList::mouseEntered(
const QModelIndex& index)
318 QSortFilterProxyModel* pModel =
static_cast<QSortFilterProxyModel*
>(table->model());
319 QModelIndex realIndex = pModel->mapToSource(index);
320 ServerPtr server = model->serverFromList(realIndex);
326 switch(index.column())
329 tooltip = ServerTooltip::createPortToolTip(server);
333 tooltip = server->hostName(
true);
337 tooltip = ServerTooltip::createPlayersToolTip(server);
341 tooltip = ServerTooltip::createServerNameToolTip(server);
345 tooltip = ServerTooltip::createIwadToolTip(server);
349 tooltip = ServerTooltip::createPwadsToolTip(server);
357 QToolTip::showText(QCursor::pos(), tooltip, NULL);
360 void ServerList::prepareServerTable()
362 model = createModel();
363 proxyModel = createSortingProxy(model);
365 columnHeaderClicked(IDPlayers);
366 table->setModel(proxyModel);
367 table->setupTableProperties();
369 if(gConfig.doomseeker.serverListSortIndex >= 0)
371 sortIndex = gConfig.doomseeker.serverListSortIndex;
372 sortOrder =
static_cast<Qt::SortOrder
> (gConfig.doomseeker.serverListSortDirection);
375 connectTableModelProxySlots();
376 proxyModel->setAdditionalSortColumns(gConfig.doomseeker.additionalSortColumns());
379 void ServerList::redraw()
384 void ServerList::refreshSelected()
386 foreach (
const ServerPtr &server, selectedServers())
388 gRefresher->registerServer(server.data());
392 void ServerList::registerServer(ServerPtr server)
394 ServerPtr serverOnList = model->findSameServer(server.data());
395 if (serverOnList != NULL)
397 serverOnList->setCustom(server->isCustom() || serverOnList->isCustom());
398 model->redraw(serverOnList.data());
401 this->connect(server.data(), SIGNAL(updated(ServerPtr,
int)),
402 SLOT(onServerUpdated(ServerPtr)));
403 this->connect(server.data(), SIGNAL(begunRefreshing(ServerPtr)),
404 SLOT(onServerBegunRefreshing(ServerPtr)));
405 model->addServer(server);
406 emit serverRegistered(server);
409 void ServerList::removeServer(
const ServerPtr &server)
411 server->disconnect(
this);
412 model->removeServer(server);
413 emit serverDeregistered(server);
416 void ServerList::removeCustomServers()
418 foreach (ServerPtr server, model->customServers())
420 removeServer(server);
424 void ServerList::removeNonSpecialServers()
426 foreach (ServerPtr server, model->nonSpecialServers())
428 removeServer(server);
432 void ServerList::removeAdditionalSortingForColumn(
const QModelIndex &modelIndex)
434 proxyModel->removeAdditionalColumnSorting(modelIndex.column());
437 void ServerList::saveAdditionalSortingConfig()
439 gConfig.doomseeker.setAdditionalSortColumns(proxyModel->additionalSortColumns());
442 void ServerList::saveColumnsWidthsSettings()
444 gConfig.doomseeker.serverListColumnState = table->horizontalHeader()->saveState().toBase64();
445 gConfig.doomseeker.serverListSortIndex = sortIndex;
446 gConfig.doomseeker.serverListSortDirection = sortOrder;
449 QList<ServerPtr> ServerList::selectedServers()
const 451 QModelIndexList indexList = table->selectionModel()->selectedRows();
453 QList<ServerPtr> servers;
454 for(
int i = 0; i < indexList.count(); ++i)
456 QModelIndex realIndex = proxyModel->mapToSource(indexList[i]);
457 ServerPtr server = model->serverFromList(realIndex);
458 servers.append(server);
463 void ServerList::onServerBegunRefreshing(
const ServerPtr &server)
465 model->setRefreshing(server);
468 QList<ServerPtr> ServerList::servers()
const 470 return model->servers();
473 ServerPtr ServerList::serverFromIndex(
const QModelIndex &index)
475 QSortFilterProxyModel* pModel =
static_cast<QSortFilterProxyModel*
>(table->model());
476 QModelIndex indexReal = pModel->mapToSource(index);
477 return model->serverFromList(indexReal);
480 QList<ServerPtr> ServerList::serversForPlugin(
const EnginePlugin *plugin)
const 482 return model->serversForPlugin(plugin);
485 void ServerList::onServerUpdated(
const ServerPtr &server)
487 int rowIndex = model->findServerOnTheList(server.data());
490 rowIndex = model->updateServer(rowIndex, server);
494 rowIndex = model->addServer(server);
497 needsCleaning =
true;
498 emit serverInfoUpdated(server);
503 const bool FORCE =
true;
504 updateCountryFlags(!FORCE);
507 void ServerList::setGroupServersWithPlayersAtTop(
bool b)
509 proxyModel->setGroupServersWithPlayersAtTop(b);
512 void ServerList::sortAdditionally(
const QModelIndex &modelIndex, Qt::SortOrder order)
515 model->addAdditionalColumnSorting(modelIndex.column(), order);
518 Qt::SortOrder ServerList::swappedCurrentSortOrder()
520 return sortOrder == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
523 void ServerList::tableMiddleClicked(
const QModelIndex& index,
const QPoint& cursorPosition)
528 void ServerList::tableRightClicked(
const QModelIndex& index,
const QPoint& cursorPosition)
530 ServerPtr server = serverFromIndex(index);
533 proxyModel->filterInfo(), index, selectedServers(),
this);
534 this->connect(contextMenu, SIGNAL(aboutToHide()), SLOT(contextMenuAboutToHide()));
535 this->connect(contextMenu, SIGNAL(triggered(QAction*)), SLOT(contextMenuTriggered(QAction*)));
537 QPoint displayPoint = table->viewport()->mapToGlobal(cursorPosition);
538 contextMenu->popup(displayPoint);
541 void ServerList::updateCountryFlags()
543 const bool FORCE =
true;
544 updateCountryFlags(FORCE);
547 void ServerList::updateCountryFlags(
bool force)
549 for (
int i = 0; i < model->rowCount(); ++i)
551 model->updateFlag(i, force);
555 void ServerList::updateHeaderTitles()
557 const QList<ColumnSort> &sortings = proxyModel->additionalSortColumns();
558 for (
int i = 0; i < ServerListColumnId::NUM_SERVERLIST_COLUMNS; ++i)
561 model->setHeaderData(i, Qt::Horizontal, QIcon(), Qt::DecorationRole);
563 QStringList labels = ServerListColumns::generateColumnHeaderLabels();
564 for (
int i = 0; i < sortings.size(); ++i)
567 labels[sort.columnId()] = QString(
"[%1] %2").arg(i + 1).arg(labels[sort.columnId()]);
568 QIcon icon = sort.order() == Qt::AscendingOrder ?
569 QIcon(
":/icons/ascending.png") :
570 QIcon(
":/icons/descending.png");
571 model->setHeaderData(sort.columnId(), Qt::Horizontal, icon, Qt::DecorationRole);
573 model->setHorizontalHeaderLabels(labels);
576 void ServerList::updateSearch(
const QString& search)
578 QRegExp pattern(QString(
"*") + search +
"*", Qt::CaseInsensitive, QRegExp::Wildcard);
579 proxyModel->setFilterRegExp(pattern);
Structure describing server filter.
void lookupHosts()
Looks up hosts for all available servers.
void setCountryFlagsIfNotPresent()
Sets country flags for servers that don't have flags present yet.