Skip to content

Commit 6c89081

Browse files
authored
Merge pull request #3557 from softins/version-sort-new
Add version sorting in Connect Dialog using CMappedTreeWidgetItem
2 parents 79185f9 + 9773ee1 commit 6c89081

File tree

2 files changed

+109
-24
lines changed

2 files changed

+109
-24
lines changed

src/connectdlg.cpp

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,75 @@
2525
#include "connectdlg.h"
2626

2727
/* Implementation *************************************************************/
28+
29+
// mapVersionStr - converts a version number to a sortable string
30+
static QString mapVersionStr ( const QString& versionStr )
31+
{
32+
QString key;
33+
QString x = ">"; // default suffix is later (git, dev, nightly, etc)
34+
35+
// Regex for SemVer: major.minor.patch-suffix
36+
QRegularExpression semVerRegex ( R"(^(\d+)\.(\d+)\.(\d+)-?(.*)$)" );
37+
QRegularExpressionMatch match = semVerRegex.match ( versionStr );
38+
39+
if ( !match.hasMatch() )
40+
{
41+
return versionStr; // fallback: plain text
42+
}
43+
44+
int major = match.captured ( 1 ).toInt();
45+
int minor = match.captured ( 2 ).toInt();
46+
int patch = match.captured ( 3 ).toInt();
47+
QString suffix = match.captured ( 4 ); // may be empty
48+
49+
if ( suffix.isEmpty() )
50+
{
51+
x = "="; // bare version number
52+
}
53+
else if ( suffix.startsWith ( "rc" ) || suffix.startsWith ( "beta" ) || suffix.startsWith ( "alpha" ) )
54+
{
55+
x = "<"; // pre-release version
56+
}
57+
58+
// construct a sortable key mmmnnnpppksuffix, where:
59+
// mmm = major
60+
// nnn = minor
61+
// ppp = patch
62+
// k = sort key to sort alpha, beta, rc before bare version number, and other suffixes after (<, =, >)
63+
// suffix = supplied suffix
64+
key = QString ( "%1%2%3%4%5" )
65+
.arg ( major, 3, 10, QLatin1Char ( '0' ) )
66+
.arg ( minor, 3, 10, QLatin1Char ( '0' ) )
67+
.arg ( patch, 3, 10, QLatin1Char ( '0' ) )
68+
.arg ( x )
69+
.arg ( suffix );
70+
71+
return key;
72+
}
73+
74+
// Subclass of QTreeWidgetItem that allows LVC_VERSION to sort by the UserRole data value
75+
CMappedTreeWidgetItem::CMappedTreeWidgetItem ( QTreeWidget* owner ) : QTreeWidgetItem ( owner ), owner ( owner ) {}
76+
77+
bool CMappedTreeWidgetItem::operator<( const QTreeWidgetItem& other ) const
78+
{
79+
if ( !owner )
80+
return QTreeWidgetItem::operator<( other );
81+
82+
int column = owner->sortColumn();
83+
84+
// we only need this override for comparing server versions
85+
if ( column != CConnectDlg::LVC_VERSION )
86+
return QTreeWidgetItem::operator<( other );
87+
88+
QVariant lhs = data ( column, Qt::UserRole );
89+
QVariant rhs = other.data ( column, Qt::UserRole );
90+
91+
if ( !lhs.isValid() || !rhs.isValid() )
92+
return QTreeWidgetItem::operator<( other );
93+
94+
return lhs.toString() < rhs.toString();
95+
}
96+
2897
CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteRegList, const bool bNEnableIPv6, QWidget* parent ) :
2998
CBaseDlg ( parent, Qt::Dialog ),
3099
pSettings ( pNSetP ),
@@ -121,7 +190,7 @@ CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteR
121190
lvwServers->setColumnWidth ( LVC_PING, 75 );
122191
lvwServers->setColumnWidth ( LVC_CLIENTS, 70 );
123192
lvwServers->setColumnWidth ( LVC_LOCATION, 220 );
124-
lvwServers->setColumnWidth ( LVC_VERSION, 65 );
193+
lvwServers->setColumnWidth ( LVC_VERSION, 95 );
125194
#endif
126195
lvwServers->clear();
127196

@@ -365,7 +434,7 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector<CS
365434
}
366435

367436
// create new list view item
368-
QTreeWidgetItem* pNewListViewItem = new QTreeWidgetItem ( lvwServers );
437+
CMappedTreeWidgetItem* pNewListViewItem = new CMappedTreeWidgetItem ( lvwServers );
369438

370439
// make the entry invisible (will be set to visible on successful ping
371440
// result) if the complete list of registered servers shall not be shown
@@ -471,7 +540,7 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector<CS
471540
void CConnectDlg::SetConnClientsList ( const CHostAddress& InetAddr, const CVector<CChannelInfo>& vecChanInfo )
472541
{
473542
// find the server with the correct address
474-
QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
543+
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
475544

476545
if ( pCurListViewItem )
477546
{
@@ -484,7 +553,7 @@ void CConnectDlg::SetConnClientsList ( const CHostAddress& InetAddr, const CVect
484553
for ( int i = 0; i < iNumConnectedClients; i++ )
485554
{
486555
// create new list view item
487-
QTreeWidgetItem* pNewChildListViewItem = new QTreeWidgetItem ( pCurListViewItem );
556+
QTreeWidgetItem* pNewChildListViewItem = new QTreeWidgetItem ( static_cast<QTreeWidgetItem*> ( pCurListViewItem ) );
488557

489558
// child items shall use only one column
490559
pNewChildListViewItem->setFirstColumnSpanned ( true );
@@ -632,8 +701,8 @@ void CConnectDlg::UpdateListFilter()
632701

633702
for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
634703
{
635-
QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
636-
bool bFilterFound = false;
704+
CMappedTreeWidgetItem* pCurListViewItem = static_cast<CMappedTreeWidgetItem*> ( lvwServers->topLevelItem ( iIdx ) );
705+
bool bFilterFound = false;
637706

638707
// DEFINITION: if "#" is set at the beginning of the filter text, we show
639708
// occupied servers (#397)
@@ -692,7 +761,7 @@ void CConnectDlg::UpdateListFilter()
692761

693762
for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
694763
{
695-
QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
764+
CMappedTreeWidgetItem* pCurListViewItem = static_cast<CMappedTreeWidgetItem*> ( lvwServers->topLevelItem ( iIdx ) );
696765

697766
// if ping time is empty, hide item (if not already hidden)
698767
if ( pCurListViewItem->text ( LVC_PING ).isEmpty() && !bShowCompleteRegList )
@@ -725,7 +794,7 @@ void CConnectDlg::OnConnectClicked()
725794
if ( CurSelListItemList.count() > 0 )
726795
{
727796
// get the parent list view item
728-
QTreeWidgetItem* pCurSelTopListItem = GetParentListViewItem ( CurSelListItemList[0] );
797+
CMappedTreeWidgetItem* pCurSelTopListItem = GetParentListViewItem ( CurSelListItemList[0] );
729798

730799
// get host address from selected list view item as a string
731800
strSelectedAddress = pCurSelTopListItem->data ( LVC_NAME, Qt::UserRole ).toString();
@@ -820,7 +889,7 @@ void CConnectDlg::EmitCLServerListPingMes ( const CHostAddress& haServerAddress,
820889
void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, const int iPingTime, const int iNumClients )
821890
{
822891
// apply the received ping time to the correct server list entry
823-
QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
892+
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
824893

825894
if ( pCurListViewItem )
826895
{
@@ -951,15 +1020,18 @@ void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr,
9511020
void CConnectDlg::SetServerVersionResult ( const CHostAddress& InetAddr, const QString& strVersion )
9521021
{
9531022
// apply the received server version to the correct server list entry
954-
QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
1023+
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
9551024

9561025
if ( pCurListViewItem )
9571026
{
9581027
pCurListViewItem->setText ( LVC_VERSION, strVersion );
1028+
1029+
// and store sortable mapped version number
1030+
pCurListViewItem->setData ( LVC_VERSION, Qt::UserRole, mapVersionStr ( strVersion ) );
9591031
}
9601032
}
9611033

962-
QTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
1034+
CMappedTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
9631035
{
9641036
const int iServerListLen = lvwServers->topLevelItemCount();
9651037

@@ -969,27 +1041,27 @@ QTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
9691041
// host address by a string compare
9701042
if ( !lvwServers->topLevelItem ( iIdx )->data ( LVC_NAME, Qt::UserRole ).toString().compare ( InetAddr.toString() ) )
9711043
{
972-
return lvwServers->topLevelItem ( iIdx );
1044+
return static_cast<CMappedTreeWidgetItem*> ( lvwServers->topLevelItem ( iIdx ) );
9731045
}
9741046
}
9751047

9761048
return nullptr;
9771049
}
9781050

979-
QTreeWidgetItem* CConnectDlg::GetParentListViewItem ( QTreeWidgetItem* pItem )
1051+
CMappedTreeWidgetItem* CConnectDlg::GetParentListViewItem ( QTreeWidgetItem* pItem )
9801052
{
9811053
// check if the current item is already the top item, i.e. the parent
9821054
// query fails and returns null
9831055
if ( pItem->parent() )
9841056
{
9851057
// we only have maximum one level, i.e. if we call the parent function
9861058
// we are at the top item
987-
return pItem->parent();
1059+
return static_cast<CMappedTreeWidgetItem*> ( pItem->parent() );
9881060
}
9891061
else
9901062
{
9911063
// this item is already the top item
992-
return pItem;
1064+
return static_cast<CMappedTreeWidgetItem*> ( pItem );
9931065
}
9941066
}
9951067

src/connectdlg.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@
4444
#define SERV_LIST_REQ_UPDATE_TIME_MS 2000 // ms
4545

4646
/* Classes ********************************************************************/
47+
48+
// Subclass of QTreeWidgetItem that allows LVC_VERSION to sort by the UserRole data value
49+
class CMappedTreeWidgetItem : public QTreeWidgetItem
50+
{
51+
public:
52+
explicit CMappedTreeWidgetItem ( QTreeWidget* owner = nullptr );
53+
54+
bool operator<( const QTreeWidgetItem& other ) const override;
55+
56+
private:
57+
QTreeWidget* owner = nullptr;
58+
};
59+
4760
class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
4861
{
4962
Q_OBJECT
@@ -65,7 +78,6 @@ class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
6578
QString GetSelectedAddress() const { return strSelectedAddress; }
6679
QString GetSelectedServerName() const { return strSelectedServerName; }
6780

68-
protected:
6981
// NOTE: This enum must list the columns in the same order
7082
// as their column headings in connectdlgbase.ui
7183
enum EConnectListViewColumns
@@ -80,17 +92,18 @@ class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
8092
LVC_COLUMNS // total number of columns
8193
};
8294

95+
protected:
8396
virtual void showEvent ( QShowEvent* );
8497
virtual void hideEvent ( QHideEvent* );
8598

86-
QTreeWidgetItem* FindListViewItem ( const CHostAddress& InetAddr );
87-
QTreeWidgetItem* GetParentListViewItem ( QTreeWidgetItem* pItem );
88-
void DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem );
89-
void UpdateListFilter();
90-
void ShowAllMusicians ( const bool bState );
91-
void RequestServerList();
92-
void EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion );
93-
void UpdateDirectoryComboBox();
99+
CMappedTreeWidgetItem* FindListViewItem ( const CHostAddress& InetAddr );
100+
CMappedTreeWidgetItem* GetParentListViewItem ( QTreeWidgetItem* pItem );
101+
void DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem );
102+
void UpdateListFilter();
103+
void ShowAllMusicians ( const bool bState );
104+
void RequestServerList();
105+
void EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion );
106+
void UpdateDirectoryComboBox();
94107

95108
CClientSettings* pSettings;
96109

0 commit comments

Comments
 (0)