Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 87 additions & 15 deletions src/connectdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,75 @@
#include "connectdlg.h"

/* Implementation *************************************************************/

// mapVersionStr - converts a version number to a sortable string
static QString mapVersionStr ( const QString& versionStr )
{
QString key;
QString x = ">"; // default suffix is later (git, dev, nightly, etc)

// Regex for SemVer: major.minor.patch-suffix
QRegularExpression semVerRegex ( R"(^(\d+)\.(\d+)\.(\d+)-?(.*)$)" );
QRegularExpressionMatch match = semVerRegex.match ( versionStr );

if ( !match.hasMatch() )
{
return versionStr; // fallback: plain text
}

int major = match.captured ( 1 ).toInt();
int minor = match.captured ( 2 ).toInt();
int patch = match.captured ( 3 ).toInt();
QString suffix = match.captured ( 4 ); // may be empty

if ( suffix.isEmpty() )
{
x = "="; // bare version number
}
else if ( suffix.startsWith ( "rc" ) || suffix.startsWith ( "beta" ) || suffix.startsWith ( "alpha" ) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Document somewhere on the release docs that the application actually filters based on these suffixes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not so much a filter. All suffixes are shown. It's just that alpha, beta and rc sort before the base version, and all other suffixes sort after. I agree it's worth documenting somewhere suitable.

Copy link
Collaborator

@pljones pljones Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a reminder in one of COMPILING.md or CONTRIBUTING.md -- or a comment at the top of Jamulus.pro perhaps.

{
x = "<"; // pre-release version
}

// construct a sortable key mmmnnnpppksuffix, where:
// mmm = major
// nnn = minor
// ppp = patch
// k = sort key to sort alpha, beta, rc before bare version number, and other suffixes after (<, =, >)
// suffix = supplied suffix
key = QString ( "%1%2%3%4%5" )
.arg ( major, 3, 10, QLatin1Char ( '0' ) )
.arg ( minor, 3, 10, QLatin1Char ( '0' ) )
.arg ( patch, 3, 10, QLatin1Char ( '0' ) )
.arg ( x )
.arg ( suffix );

return key;
}

// Subclass of QTreeWidgetItem that allows LVC_VERSION to sort by the UserRole data value
CMappedTreeWidgetItem::CMappedTreeWidgetItem ( QTreeWidget* owner ) : QTreeWidgetItem ( owner ), owner ( owner ) {}

bool CMappedTreeWidgetItem::operator<( const QTreeWidgetItem& other ) const
{
if ( !owner )
return QTreeWidgetItem::operator<( other );

int column = owner->sortColumn();

// we only need this override for comparing server versions
if ( column != CConnectDlg::LVC_VERSION )
return QTreeWidgetItem::operator<( other );

QVariant lhs = data ( column, Qt::UserRole );
QVariant rhs = other.data ( column, Qt::UserRole );

if ( !lhs.isValid() || !rhs.isValid() )
return QTreeWidgetItem::operator<( other );

return lhs.toString() < rhs.toString();
}

CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteRegList, const bool bNEnableIPv6, QWidget* parent ) :
CBaseDlg ( parent, Qt::Dialog ),
pSettings ( pNSetP ),
Expand Down Expand Up @@ -121,7 +190,7 @@ CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteR
lvwServers->setColumnWidth ( LVC_PING, 75 );
lvwServers->setColumnWidth ( LVC_CLIENTS, 70 );
lvwServers->setColumnWidth ( LVC_LOCATION, 220 );
lvwServers->setColumnWidth ( LVC_VERSION, 65 );
lvwServers->setColumnWidth ( LVC_VERSION, 95 );
#endif
lvwServers->clear();

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

// create new list view item
QTreeWidgetItem* pNewListViewItem = new QTreeWidgetItem ( lvwServers );
CMappedTreeWidgetItem* pNewListViewItem = new CMappedTreeWidgetItem ( 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
Expand Down Expand Up @@ -471,7 +540,7 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector<CS
void CConnectDlg::SetConnClientsList ( const CHostAddress& InetAddr, const CVector<CChannelInfo>& vecChanInfo )
{
// find the server with the correct address
QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );

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

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

for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
{
QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
bool bFilterFound = false;
CMappedTreeWidgetItem* pCurListViewItem = static_cast<CMappedTreeWidgetItem*> ( lvwServers->topLevelItem ( iIdx ) );
bool bFilterFound = false;

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

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

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

// get host address from selected list view item as a string
strSelectedAddress = pCurSelTopListItem->data ( LVC_NAME, Qt::UserRole ).toString();
Expand Down Expand Up @@ -820,7 +889,7 @@ void CConnectDlg::EmitCLServerListPingMes ( const CHostAddress& haServerAddress,
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 );
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );

if ( pCurListViewItem )
{
Expand Down Expand Up @@ -951,15 +1020,18 @@ void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr,
void CConnectDlg::SetServerVersionResult ( const CHostAddress& InetAddr, const QString& strVersion )
{
// apply the received server version to the correct server list entry
QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
CMappedTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );

if ( pCurListViewItem )
{
pCurListViewItem->setText ( LVC_VERSION, strVersion );

// and store sortable mapped version number
pCurListViewItem->setData ( LVC_VERSION, Qt::UserRole, mapVersionStr ( strVersion ) );
}
}

QTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
CMappedTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
{
const int iServerListLen = lvwServers->topLevelItemCount();

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

return nullptr;
}

QTreeWidgetItem* CConnectDlg::GetParentListViewItem ( QTreeWidgetItem* pItem )
CMappedTreeWidgetItem* 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();
return static_cast<CMappedTreeWidgetItem*> ( pItem->parent() );
}
else
{
// this item is already the top item
return pItem;
return static_cast<CMappedTreeWidgetItem*> ( pItem );
}
}

Expand Down
31 changes: 22 additions & 9 deletions src/connectdlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@
#define SERV_LIST_REQ_UPDATE_TIME_MS 2000 // ms

/* Classes ********************************************************************/

// Subclass of QTreeWidgetItem that allows LVC_VERSION to sort by the UserRole data value
class CMappedTreeWidgetItem : public QTreeWidgetItem
{
public:
explicit CMappedTreeWidgetItem ( QTreeWidget* owner = nullptr );

bool operator<( const QTreeWidgetItem& other ) const override;

private:
QTreeWidget* owner = nullptr;
};

class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
{
Q_OBJECT
Expand All @@ -65,7 +78,6 @@ class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
QString GetSelectedAddress() const { return strSelectedAddress; }
QString GetSelectedServerName() const { return strSelectedServerName; }

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

protected:
virtual void showEvent ( QShowEvent* );
virtual void hideEvent ( QHideEvent* );

QTreeWidgetItem* FindListViewItem ( const CHostAddress& InetAddr );
QTreeWidgetItem* GetParentListViewItem ( QTreeWidgetItem* pItem );
void DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem );
void UpdateListFilter();
void ShowAllMusicians ( const bool bState );
void RequestServerList();
void EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion );
void UpdateDirectoryComboBox();
CMappedTreeWidgetItem* FindListViewItem ( const CHostAddress& InetAddr );
CMappedTreeWidgetItem* GetParentListViewItem ( QTreeWidgetItem* pItem );
void DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem );
void UpdateListFilter();
void ShowAllMusicians ( const bool bState );
void RequestServerList();
void EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion );
void UpdateDirectoryComboBox();

CClientSettings* pSettings;

Expand Down
Loading