/******************************************************************************\ * Copyright (c) 2004-2020 * * Author(s): * Volker Fischer * ****************************************************************************** * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * \******************************************************************************/ #include "connectdlg.h" /* Implementation *************************************************************/ CConnectDlg::CConnectDlg ( CClient* pNCliP, const bool bNewShowCompleteRegList, QWidget* parent, Qt::WindowFlags f ) : QDialog ( parent, f ), pClient ( pNCliP ), strCentralServerAddress ( "" ), strSelectedAddress ( "" ), strSelectedServerName ( "" ), bShowCompleteRegList ( bNewShowCompleteRegList ), bServerListReceived ( false ), bServerListItemWasChosen ( false ), bListFilterWasActive ( false ), bShowAllMusicians ( true ) { setupUi ( this ); // Add help text to controls ----------------------------------------------- // server list lvwServers->setWhatsThis ( "" + tr ( "Server List" ) + ": " + tr ( "The Connection Setup window shows a list of available servers. " "Server operators can optionally list their servers by music genre. " "Use the List dropdown to select a genre, click on the server you want " "to join and press the Connect button to connect to it. Alternatively, " "double click on on the server name. Permanent servers (those that have " "been listed for longer than 48 hours) are shown in bold." ) ); lvwServers->setAccessibleName ( tr ( "Server list view" ) ); // server address QString strServAddrH = "" + tr ( "Server Address" ) + ": " + tr ( "If you know the IP address or URL of a server, you can connect to it " "using the Server name/Address field. An optional port number can be added after the IP " "address or URL using a colon as a separator, e.g, " "example.org:" ) + QString().setNum ( DEFAULT_PORT_NUMBER ) + tr ( ". The field will " "also show a list of the most recently used server addresses."); lblServerAddr->setWhatsThis ( strServAddrH ); cbxServerAddr->setWhatsThis ( strServAddrH ); cbxServerAddr->setAccessibleName ( tr ( "Server address edit box" ) ); cbxServerAddr->setAccessibleDescription ( tr ( "Holds the current server " "IP address or URL. It also stores old URLs in the combo box list." ) ); // central server address type combo box cbxCentServAddrType->clear(); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_DEFAULT ) ); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_ALL_GENRES ) ); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_ROCK ) ); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_JAZZ ) ); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_CLASSICAL_FOLK ) ); cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_CUSTOM ) ); cbxCentServAddrType->setWhatsThis ( "" + tr ( "Server List Selection" ) + ": " + tr ( "Selects the server list to be shown." ) ); cbxCentServAddrType->setAccessibleName ( tr ( "Server list selection combo box" ) ); // filter edtFilter->setWhatsThis ( "" + tr ( "Filter" ) + ": " + tr ( "The server " "list is filtered by the given text. Note that the filter is case insensitive." ) ); edtFilter->setAccessibleName ( tr ( "Filter edit box" ) ); // show all mucisians chbExpandAll->setWhatsThis ( "" + tr ( "Show All Musicians" ) + ": " + tr ( "If you check this check box, the musicians of all servers are shown. If you " "uncheck the check box, all list view items are collapsed.") ); chbExpandAll->setAccessibleName ( tr ( "Show all musicians check box" ) ); // init server address combo box (max MAX_NUM_SERVER_ADDR_ITEMS entries) cbxServerAddr->setMaxCount ( MAX_NUM_SERVER_ADDR_ITEMS ); cbxServerAddr->setInsertPolicy ( QComboBox::NoInsert ); // set up list view for connected clients (note that the last column size // must not be specified since this column takes all the remaining space) #ifdef ANDROID // for Android we need larger numbers because of the default font size lvwServers->setColumnWidth ( 0, 200 ); lvwServers->setColumnWidth ( 1, 130 ); lvwServers->setColumnWidth ( 2, 100 ); #else lvwServers->setColumnWidth ( 0, 180 ); lvwServers->setColumnWidth ( 1, 75 ); lvwServers->setColumnWidth ( 2, 70 ); lvwServers->setColumnWidth ( 3, 220 ); #endif lvwServers->clear(); // make sure we do not get a too long horizontal scroll bar lvwServers->header()->setStretchLastSection ( false ); // add invisible columns which are used for sorting the list and storing // the current/maximum number of clients // 0: server name // 1: ping time // 2: number of musicians (including additional strings like " (full)") // 3: location // 4: minimum ping time (invisible) // 5: maximum number of clients (invisible) lvwServers->setColumnCount ( 6 ); lvwServers->hideColumn ( 4 ); lvwServers->hideColumn ( 5 ); // per default the root shall not be decorated (to save space) lvwServers->setRootIsDecorated ( false ); // make sure the connect button has the focus butConnect->setFocus(); // for "show all servers" mode make sort by click on header possible if ( bShowCompleteRegList ) { lvwServers->setSortingEnabled ( true ); lvwServers->sortItems ( 0, Qt::AscendingOrder ); } #ifdef ANDROID // for the android version maximize the window setWindowState ( Qt::WindowMaximized ); #endif // Connections ------------------------------------------------------------- // list view QObject::connect ( lvwServers, &QTreeWidget::itemSelectionChanged, this, &CConnectDlg::OnServerListItemSelectionChanged ); QObject::connect ( lvwServers, &QTreeWidget::itemDoubleClicked, this, &CConnectDlg::OnServerListItemDoubleClicked ); // to get default return key behaviour working QObject::connect ( lvwServers, &QTreeWidget::activated, this, &CConnectDlg::OnConnectClicked ); // line edit QObject::connect ( edtFilter, &QLineEdit::textEdited, this, &CConnectDlg::OnFilterTextEdited ); // combo boxes QObject::connect ( cbxServerAddr, &QComboBox::editTextChanged, this, &CConnectDlg::OnServerAddrEditTextChanged ); QObject::connect ( cbxCentServAddrType, static_cast ( &QComboBox::activated ), this, &CConnectDlg::OnCentServAddrTypeChanged ); // check boxes QObject::connect ( chbExpandAll, &QCheckBox::stateChanged, this, &CConnectDlg::OnExpandAllStateChanged ); // buttons QObject::connect ( butCancel, &QPushButton::clicked, this, &CConnectDlg::close ); QObject::connect ( butConnect, &QPushButton::clicked, this, &CConnectDlg::OnConnectClicked ); // timers QObject::connect ( &TimerPing, &QTimer::timeout, this, &CConnectDlg::OnTimerPing ); QObject::connect ( &TimerReRequestServList, &QTimer::timeout, this, &CConnectDlg::OnTimerReRequestServList ); } void CConnectDlg::Init ( const CVector& vstrIPAddresses ) { // load stored IP addresses in combo box cbxServerAddr->clear(); cbxServerAddr->clearEditText(); for ( int iLEIdx = 0; iLEIdx < MAX_NUM_SERVER_ADDR_ITEMS; iLEIdx++ ) { if ( !vstrIPAddresses[iLEIdx].isEmpty() ) { cbxServerAddr->addItem ( vstrIPAddresses[iLEIdx] ); } } } void CConnectDlg::showEvent ( QShowEvent* ) { // on opening the connect dialg, we always want to request a // new updated server list per definition RequestServerList(); } void CConnectDlg::RequestServerList() { // reset flags bServerListReceived = false; bServerListItemWasChosen = false; bListFilterWasActive = false; // clear current address and name strSelectedAddress = ""; strSelectedServerName = ""; // clear server list view lvwServers->clear(); // clear filter edit box edtFilter->setText ( "" ); // update list combo box (disable events to avoid a signal) cbxCentServAddrType->blockSignals ( true ); cbxCentServAddrType->setCurrentIndex ( static_cast ( pClient->GetCentralServerAddressType() ) ); cbxCentServAddrType->blockSignals ( false ); // get the IP address of the central server (using the ParseNetworAddress // function) when the connect dialog is opened, this seems to be the correct // time to do it if ( NetworkUtil().ParseNetworkAddress ( strCentralServerAddress, CentralServerAddress ) ) { // send the request for the server list emit ReqServerListQuery ( CentralServerAddress ); // start timer, if this message did not get any respond to retransmit // the server list request message TimerReRequestServList.start ( SERV_LIST_REQ_UPDATE_TIME_MS ); } } void CConnectDlg::hideEvent ( QHideEvent* ) { // if window is closed, stop timers TimerPing.stop(); TimerReRequestServList.stop(); } void CConnectDlg::OnTimerReRequestServList() { // if the server list is not yet received, retransmit the request for the // server list if ( !bServerListReceived ) { // note that this is a connection less message which may get lost // and therefore it makes sense to re-transmit it emit ReqServerListQuery ( CentralServerAddress ); } } void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector& vecServerInfo ) { // set flag and disable timer for resend server list request bServerListReceived = true; TimerReRequestServList.stop(); // first clear list lvwServers->clear(); // add list item for each server in the server list const int iServerInfoLen = vecServerInfo.Size(); for ( int iIdx = 0; iIdx < iServerInfoLen; iIdx++ ) { // get the host address, note that for the very first entry which is // the central server, we have to use the receive host address // instead CHostAddress CurHostAddress; if ( iIdx > 0 ) { CurHostAddress = vecServerInfo[iIdx].HostAddr; } else { // substitute the receive host address for central server CurHostAddress = InetAddr; } // create new list view item QTreeWidgetItem* pNewListViewItem = new QTreeWidgetItem ( lvwServers ); // make the entry invisible (will be set to visible on successful ping // result) if the complete list of registered servers shall not be shown if ( !bShowCompleteRegList ) { pNewListViewItem->setHidden ( true ); } // server name (if empty, show host address instead) if ( !vecServerInfo[iIdx].strName.isEmpty() ) { pNewListViewItem->setText ( 0, vecServerInfo[iIdx].strName ); } else { // IP address and port (use IP number without last byte) // Definition: If the port number is the default port number, we do // not show it. if ( vecServerInfo[iIdx].HostAddr.iPort == DEFAULT_PORT_NUMBER ) { // only show IP number, no port number pNewListViewItem->setText ( 0, CurHostAddress.toString ( CHostAddress::SM_IP_NO_LAST_BYTE ) ); } else { // show IP number and port pNewListViewItem->setText ( 0, CurHostAddress.toString ( CHostAddress::SM_IP_NO_LAST_BYTE_PORT ) ); } } // in case of all servers shown, add the registration number at the beginning if ( bShowCompleteRegList ) { pNewListViewItem->setText ( 0, QString ( "%1: " ).arg ( 1 + iIdx, 3 ) + pNewListViewItem->text ( 0 ) ); } // show server name in bold font if it is a permanent server QFont CurServerNameFont = pNewListViewItem->font ( 0 ); CurServerNameFont.setBold ( vecServerInfo[iIdx].bPermanentOnline ); pNewListViewItem->setFont ( 0, CurServerNameFont ); // the ping time shall be shown in bold font QFont CurPingTimeFont = pNewListViewItem->font ( 1 ); CurPingTimeFont.setBold ( true ); pNewListViewItem->setFont ( 1, CurPingTimeFont ); // server location (city and country) QString strLocation = vecServerInfo[iIdx].strCity; if ( ( !strLocation.isEmpty() ) && ( vecServerInfo[iIdx].eCountry != QLocale::AnyCountry ) ) { strLocation += ", "; } if ( vecServerInfo[iIdx].eCountry != QLocale::AnyCountry ) { QString strCountryToString = QLocale::countryToString ( vecServerInfo[iIdx].eCountry ); // Qt countryToString does not use spaces in between country name // parts but they use upper case letters which we can detect and // insert spaces as a post processing #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) if ( !strCountryToString.contains ( " " ) ) { QRegularExpressionMatchIterator reMatchIt = QRegularExpression ( "[A-Z][^A-Z]*" ).globalMatch ( strCountryToString ); QStringList slNames; while ( reMatchIt.hasNext() ) { slNames << reMatchIt.next().capturedTexts(); } strCountryToString = slNames.join ( " " ); } #endif strLocation += strCountryToString; } pNewListViewItem->setText ( 3, strLocation ); // init the minimum ping time with a large number (note that this number // must fit in an integer type) pNewListViewItem->setText ( 4, "99999999" ); // store the maximum number of clients pNewListViewItem->setText ( 5, QString().setNum ( vecServerInfo[iIdx].iMaxNumClients ) ); // store host address pNewListViewItem->setData ( 0, Qt::UserRole, CurHostAddress.toString() ); // per default expand the list item (if not "show all servers") if ( bShowAllMusicians ) { lvwServers->expandItem ( pNewListViewItem ); } } // immediately issue the ping measurements and start the ping timer since // the server list is filled now OnTimerPing(); TimerPing.start ( PING_UPDATE_TIME_SERVER_LIST_MS ); } void CConnectDlg::SetConnClientsList ( const CHostAddress& InetAddr, const CVector& vecChanInfo ) { // find the server with the correct address QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr ); if ( pCurListViewItem ) { // first remove any existing children DeleteAllListViewItemChilds ( pCurListViewItem ); // get number of connected clients const int iNumConnectedClients = vecChanInfo.Size(); for ( int i = 0; i < iNumConnectedClients; i++ ) { // create new list view item QTreeWidgetItem* pNewChildListViewItem = new QTreeWidgetItem ( pCurListViewItem ); // child items shall use only one column pNewChildListViewItem->setFirstColumnSpanned ( true ); // set the clients name QString sClientText = vecChanInfo[i].strName; // set the icon: country flag has priority over instrument bool bCountryFlagIsUsed = false; if ( vecChanInfo[i].eCountry != QLocale::AnyCountry ) { // try to load the country flag icon QPixmap CountryFlagPixmap ( CLocale::GetCountryFlagIconsResourceReference ( vecChanInfo[i].eCountry ) ); // first check if resource reference was valid if ( !CountryFlagPixmap.isNull() ) { // set correct picture pNewChildListViewItem->setIcon ( 0, QIcon ( CountryFlagPixmap ) ); // add the instrument information as text if ( !CInstPictures::IsNotUsedInstrument ( vecChanInfo[i].iInstrument ) ) { sClientText.append ( " (" + CInstPictures::GetName ( vecChanInfo[i].iInstrument ) + ")" ); } bCountryFlagIsUsed = true; } } if ( !bCountryFlagIsUsed ) { // get the resource reference string for this instrument const QString strCurResourceRef = CInstPictures::GetResourceReference ( vecChanInfo[i].iInstrument ); // first check if instrument picture is used or not and if it is valid if ( !( CInstPictures::IsNotUsedInstrument ( vecChanInfo[i].iInstrument ) || strCurResourceRef.isEmpty() ) ) { // set correct picture pNewChildListViewItem->setIcon ( 0, QIcon ( QPixmap ( strCurResourceRef ) ) ); } } // apply the client text to the list view item pNewChildListViewItem->setText ( 0, sClientText ); // add the new child to the corresponding server item pCurListViewItem->addChild ( pNewChildListViewItem ); // at least one server has children now, show decoration to be able // to show the children lvwServers->setRootIsDecorated ( true ); } } } void CConnectDlg::OnServerListItemSelectionChanged() { // get current selected item (we are only interested in the first selected // item) QList CurSelListItemList = lvwServers->selectedItems(); // if an item is clicked/selected, copy the server name to the combo box if ( CurSelListItemList.count() > 0 ) { // make sure no signals are send when we change the text cbxServerAddr->blockSignals ( true ); { cbxServerAddr->setEditText ( GetParentListViewItem ( CurSelListItemList[0] )->text ( 0 ) ); } cbxServerAddr->blockSignals ( false ); } } void CConnectDlg::OnServerListItemDoubleClicked ( QTreeWidgetItem* Item, int ) { // if a server list item was double clicked, it is the same as if the // connect button was clicked if ( Item != nullptr ) { OnConnectClicked(); } } void CConnectDlg::OnServerAddrEditTextChanged ( const QString& ) { // in the server address combo box, a text was changed, remove selection // in the server list (if any) lvwServers->clearSelection(); } void CConnectDlg::ShowAllMusicians ( const bool bState ) { bShowAllMusicians = bState; // update list if ( bState ) { lvwServers->expandAll(); } else { lvwServers->collapseAll(); } // update check box if necessary if ( ( chbExpandAll->checkState() == Qt::Checked && !bShowAllMusicians ) || ( chbExpandAll->checkState() == Qt::Unchecked && bShowAllMusicians ) ) { chbExpandAll->setCheckState ( bState ? Qt::Checked : Qt::Unchecked ); } } void CConnectDlg::UpdateListFilter() { const QString sFilterText = edtFilter->text(); if ( !sFilterText.isEmpty() ) { bListFilterWasActive = true; const int iServerListLen = lvwServers->topLevelItemCount(); for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ ) { QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx ); bool bFilterFound = false; // search server name if ( pCurListViewItem->text ( 0 ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 ) { bFilterFound = true; } // search location if ( pCurListViewItem->text ( 3 ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 ) { bFilterFound = true; } // search children for ( int iCCnt = 0; iCCnt < pCurListViewItem->childCount(); iCCnt++ ) { if ( pCurListViewItem->child ( iCCnt )->text ( 0 ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 ) { bFilterFound = true; } } // only update Hide state if ping time was received if ( !pCurListViewItem->text ( 1 ).isEmpty() || bShowCompleteRegList ) { // only update hide and expand status if the hide state has to be changed to // preserve if user clicked on expand icon manually if ( ( pCurListViewItem->isHidden() && bFilterFound ) || ( !pCurListViewItem->isHidden() && !bFilterFound ) ) { pCurListViewItem->setHidden ( !bFilterFound ); pCurListViewItem->setExpanded ( bShowAllMusicians ); } } } } else { // if the filter was active but is now disabled, we have to update all list // view items for the "ping received" hide state if ( bListFilterWasActive ) { const int iServerListLen = lvwServers->topLevelItemCount(); for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ ) { QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx ); // if ping time is empty, hide item (if not already hidden) if ( pCurListViewItem->text ( 1 ).isEmpty() && !bShowCompleteRegList ) { pCurListViewItem->setHidden ( true ); } else { // in case it was hidden, show it and take care of expand if ( pCurListViewItem->isHidden() ) { pCurListViewItem->setHidden ( false ); pCurListViewItem->setExpanded ( bShowAllMusicians ); } } } bListFilterWasActive = false; } } } void CConnectDlg::OnConnectClicked() { // get the IP address to be used according to the following definitions: // - if the list has focus and a line is selected, use this line // - if the list has no focus, use the current combo box text QList CurSelListItemList = lvwServers->selectedItems(); if ( CurSelListItemList.count() > 0 ) { // get the parent list view item QTreeWidgetItem* pCurSelTopListItem = GetParentListViewItem ( CurSelListItemList[0] ); // get host address from selected list view item as a string strSelectedAddress = pCurSelTopListItem->data ( 0, Qt::UserRole ).toString(); // store selected server name strSelectedServerName = pCurSelTopListItem->text ( 0 ); // set flag that a server list item was chosen to connect bServerListItemWasChosen = true; } else { strSelectedAddress = cbxServerAddr->currentText(); } // tell the parent window that the connection shall be initiated done ( QDialog::Accepted ); } void CConnectDlg::OnTimerPing() { // send ping messages to the servers in the list const int iServerListLen = lvwServers->topLevelItemCount(); for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ ) { CHostAddress CurServerAddress; // try to parse host address string which is stored as user data // in the server list item GUI control element if ( NetworkUtil().ParseNetworkAddress ( lvwServers->topLevelItem ( iIdx )-> data ( 0, Qt::UserRole ).toString(), CurServerAddress ) ) { // if address is valid, send ping or the version and OS request #ifdef ENABLE_CLIENT_VERSION_AND_OS_DEBUGGING emit CreateCLServerListReqVerAndOSMes ( CurServerAddress ); #else emit CreateCLServerListPingMes ( CurServerAddress ); #endif } } } void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, const int iPingTime, const int iNumClients ) { // apply the received ping time to the correct server list entry QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr ); if ( pCurListViewItem ) { // check if this is the first time a ping time is set const bool bIsFirstPing = pCurListViewItem->text ( 1 ).isEmpty(); bool bDoSorting = false; // update minimum ping time column (invisible, used for sorting) if // the new value is smaller than the old value int iMinPingTime = pCurListViewItem->text ( 4 ).toInt(); if ( iMinPingTime > iPingTime ) { // update the minimum ping time with the new lowest value iMinPingTime = iPingTime; // we pad to a total of 8 characters with zeros to make sure the // sorting is done correctly pCurListViewItem->setText ( 4, QString ( "%1" ).arg ( iPingTime, 8, 10, QLatin1Char ( '0' ) ) ); // update the sorting (lowest number on top) bDoSorting = true; } // for debugging it is good to see the current ping time in the list // and not the minimum ping time -> overwrite the value for debugging if ( bShowCompleteRegList ) { iMinPingTime = iPingTime; } // Only show minimum ping time in the list since this is the important // value. Temporary bad ping measurements are of no interest. // Color definition: <= 25 ms green, <= 50 ms yellow, otherwise red if ( iMinPingTime <= 25 ) { pCurListViewItem->setForeground ( 1, Qt::darkGreen ); } else { if ( iMinPingTime <= 50 ) { pCurListViewItem->setForeground ( 1, Qt::darkYellow ); } else { pCurListViewItem->setForeground ( 1, Qt::red ); } } // update ping text, take special care if ping time exceeds a // certain value if ( iMinPingTime > 500 ) { pCurListViewItem->setText ( 1, ">500 ms" ); } else { pCurListViewItem-> setText ( 1, QString().setNum ( iMinPingTime ) + " ms" ); } // update number of clients text if ( iNumClients >= pCurListViewItem->text ( 5 ).toInt() ) { pCurListViewItem-> setText ( 2, QString().setNum ( iNumClients ) + " (full)" ); } else { pCurListViewItem-> setText ( 2, QString().setNum ( iNumClients ) ); } // check if the number of child list items matches the number of // connected clients, if not then request the client names if ( iNumClients != pCurListViewItem->childCount() ) { emit CreateCLServerListReqConnClientsListMes ( InetAddr ); } // this is the first time a ping time was received, set item to visible if ( bIsFirstPing ) { pCurListViewItem->setHidden ( false ); } // Update sorting. Note that the sorting must be the last action for the // current item since the topLevelItem ( iIdx ) is then no longer valid. if ( bDoSorting && !bShowCompleteRegList ) // do not sort if "show all servers" { lvwServers->sortByColumn ( 4, Qt::AscendingOrder ); } } // if no server item has children, do not show decoration bool bAnyListItemHasChilds = false; const int iServerListLen = lvwServers->topLevelItemCount(); for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ ) { // check if the current list item has children if ( lvwServers->topLevelItem ( iIdx )->childCount() > 0 ) { bAnyListItemHasChilds = true; } } if ( !bAnyListItemHasChilds ) { lvwServers->setRootIsDecorated ( false ); } // we may have changed the Hidden state for some items, if a filter was active, we now // have to update it to void lines appear which do not satisfy the filter criteria UpdateListFilter(); } QTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr ) { const int iServerListLen = lvwServers->topLevelItemCount(); for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ ) { // compare the received address with the user data string of the // host address by a string compare if ( !lvwServers->topLevelItem ( iIdx )-> data ( 0, Qt::UserRole ).toString(). compare ( InetAddr.toString() ) ) { return lvwServers->topLevelItem ( iIdx ); } } return nullptr; } QTreeWidgetItem* CConnectDlg::GetParentListViewItem ( QTreeWidgetItem* pItem ) { // check if the current item is already the top item, i.e. the parent // query fails and returns null if ( pItem->parent() ) { // we only have maximum one level, i.e. if we call the parent function // we are at the top item return pItem->parent(); } else { // this item is already the top item return pItem; } } void CConnectDlg::DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem ) { // loop over all children while ( pItem->childCount() > 0 ) { // get the first child in the list QTreeWidgetItem* pCurChildItem = pItem->child ( 0 ); // remove it from the item (note that the object is not deleted) pItem->removeChild ( pCurChildItem ); // delete the object to avoid a memory leak delete pCurChildItem; } } #ifdef ENABLE_CLIENT_VERSION_AND_OS_DEBUGGING void CConnectDlg::SetVersionAndOSType ( CHostAddress InetAddr, COSUtil::EOpSystemType eOSType, QString strVersion ) { // apply the received version and OS type to the correct server list entry QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr ); if ( pCurListViewItem ) { // TEST since this is just a debug info, we just reuse the ping column (note // the we have to replace the ping message emit with the version and OS request // so that this works, see above code) pCurListViewItem-> setText ( 1, strVersion + "/" + COSUtil::GetOperatingSystemString ( eOSType ) ); // a version and OS type was received, set item to visible if ( pCurListViewItem->isHidden() ) { pCurListViewItem->setHidden ( false ); } } } #endif