Repository: keepassxreboot/keepassxc (C++)

Issue:
Sort advanced attribute list using locale aware sort
## Overview
Additional Attributes are sorted by string ascii values, resulting in 10 coming before 2.

This results in strange behavior like the KP2A URL fields in the Browser integration tab being ordered oddly. When adding a 10th Additional URL, the new line will appear after the 1st entry and before the 2nd, not at the end of the list as you'd expect.

![Example of the new KP2A_URL_# fields sorted badly](https://user-images.githubusercontent.com/868821/108930229-66afc080-75fa-11eb-99e0-9c4d8c7f3703.png)

## Steps to Reproduce
1. Create 10 "Additional URLs" on an entry.
2. Note that the 10th is added before the 2nd entry in the list.
3. Flip to the Advanced tab and see why.

## Expected Behavior
10 should appear at the end of the list.

## Actual Behavior
10 appears after 1 and before 2.

## Context
Note that this also happens in Windows and should happen on every platform.

KeePassXC - Version 2.6.4
Revision: 34a78f0
Distribution: Flatpak

Qt 5.15.2
Debugging mode is disabled.

Operating system: KDE Flatpak runtime (System: Ubuntu 20.04.2 LTS)
CPU architecture: x86_64
Kernel: linux 5.8.0-43-generic

Enabled extensions:
- Auto-Type
- Browser Integration
- SSH Agent
- KeeShare (signed and unsigned sharing)
- YubiKey

Cryptographic libraries:
- libgcrypt 1.8.7

Desktop Env: Gnome
Windowing System: X11



Fix (patch):
diff --git a/src/gui/entry/EntryAttributesModel.cpp b/src/gui/entry/EntryAttributesModel.cpp
index 9ce9ed251a..604f9af643 100644
--- a/src/gui/entry/EntryAttributesModel.cpp
+++ b/src/gui/entry/EntryAttributesModel.cpp
@@ -24,6 +24,7 @@ EntryAttributesModel::EntryAttributesModel(QObject* parent)
     , m_entryAttributes(nullptr)
     , m_nextRenameDataChange(false)
 {
+    m_collator.setNumericMode(true);
 }
 
 void EntryAttributesModel::setEntryAttributes(EntryAttributes* entryAttributes)
@@ -150,7 +151,7 @@ void EntryAttributesModel::attributeAboutToAdd(const QString& key)
 {
     QList<QString> rows = m_attributes;
     rows.append(key);
-    std::sort(rows.begin(), rows.end());
+    std::sort(rows.begin(), rows.end(), m_collator);
     int row = rows.indexOf(key);
     beginInsertRows(QModelIndex(), row, row);
 }
@@ -180,7 +181,7 @@ void EntryAttributesModel::attributeAboutToRename(const QString& oldKey, const Q
     QList<QString> rows = m_attributes;
     rows.removeOne(oldKey);
     rows.append(newKey);
-    std::sort(rows.begin(), rows.end());
+    std::sort(rows.begin(), rows.end(), m_collator);
     int newRow = rows.indexOf(newKey);
     if (newRow > oldRow) {
         newRow++;
@@ -232,4 +233,5 @@ void EntryAttributesModel::updateAttributes()
             m_attributes.append(key);
         }
     }
+    std::sort(m_attributes.begin(), m_attributes.end(), m_collator);
 }
diff --git a/src/gui/entry/EntryAttributesModel.h b/src/gui/entry/EntryAttributesModel.h
index 7d613c1f0d..650426c32b 100644
--- a/src/gui/entry/EntryAttributesModel.h
+++ b/src/gui/entry/EntryAttributesModel.h
@@ -19,6 +19,7 @@
 #define KEEPASSX_ENTRYATTRIBUTESMODEL_H
 
 #include <QAbstractListModel>
+#include <QCollator>
 
 class EntryAttributes;
 
@@ -55,6 +56,7 @@ private slots:
     EntryAttributes* m_entryAttributes;
     QList<QString> m_attributes;
     bool m_nextRenameDataChange;
+    QCollator m_collator;
 };
 
 #endif // KEEPASSX_ENTRYATTRIBUTESMODEL_H