diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt	2026-04-22 13:27:36.664415561 +0200
+++ b/CMakeLists.txt	2026-04-22 13:27:36.664467103 +0200
@@ -25,7 +25,7 @@
 set(CMAKE_AUTORCC ON)
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
-find_package(Qt5 REQUIRED COMPONENTS Qml Widgets Concurrent)
+find_package(Qt6 REQUIRED COMPONENTS Qml Widgets Concurrent Core5Compat)
 
 include_directories(src ${CMAKE_CURRENT_BINARY_DIR}/src thirdparty/qtcolorpicker-2.6)
 
@@ -205,7 +205,7 @@
     src/word.cpp
     resources.qrc
     ${SOURCES})
-target_link_libraries(DwarfTherapist Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Network Qt5::Concurrent ${LIBS})
+target_link_libraries(DwarfTherapist Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Qml Qt6::Network Qt6::Concurrent Qt6::Core5Compat ${LIBS})
 if(UNIX)
     if(APPLE)
         set_target_properties(DwarfTherapist PROPERTIES
diff --git a/src/activity.cpp b/src/activity.cpp
--- a/src/activity.cpp	2026-04-22 13:27:36.664227811 +0200
+++ b/src/activity.cpp	2026-04-22 13:47:57.140088332 +0200
@@ -69,5 +69,5 @@
 }
 
 QPair<int, QString> Activity::find_activity(int histfig_id){
-    return m_histfig_actions.value(histfig_id,qMakePair<int,QString>(DwarfJob::JOB_UNKNOWN,"unknown"));
+    return m_histfig_actions.value(histfig_id,qMakePair(DwarfJob::JOB_UNKNOWN,"unknown"));
 }
diff --git a/src/activityevent.cpp b/src/activityevent.cpp
--- a/src/activityevent.cpp	2026-04-22 13:27:36.664152052 +0200
+++ b/src/activityevent.cpp	2026-04-22 13:27:36.666798907 +0200
@@ -70,7 +70,8 @@
             GameDataReader *gdr = GameDataReader::ptr();
             USIZE participant_offset = mem->activity_offset("participants");
             VIRTADDR participant_addr = m_address + participant_offset;
-            QSet<qint32> participants = m_df->enum_vec<qint32>(participant_addr).toList().toSet();
+            auto participants_list = m_df->enum_vec<qint32>(participant_addr).toList();
+            QSet<qint32> participants(participants_list.constBegin(), participants_list.constEnd());
 
             foreach(qint32 histfig_id,participants){
                 event_type = m_type;
diff --git a/src/attributecolumn.cpp b/src/attributecolumn.cpp
--- a/src/attributecolumn.cpp	2026-04-22 13:27:36.663946338 +0200
+++ b/src/attributecolumn.cpp	2026-04-22 13:27:36.667410881 +0200
@@ -121,7 +121,7 @@
 }
 
 void AttributeColumn::refresh_sort(COLUMN_SORT_TYPE sType){
-    foreach(Dwarf *d, m_cells.uniqueKeys()){
+    foreach(Dwarf *d, m_cells.keys()){
         refresh_sort(d,sType);
     }
     m_current_sort = sType;
diff --git a/src/basedock.cpp b/src/basedock.cpp
--- a/src/basedock.cpp	2026-04-22 13:27:36.663882734 +0200
+++ b/src/basedock.cpp	2026-04-22 13:27:36.666883263 +0200
@@ -7,7 +7,7 @@
 #else
     bool vis = this->isVisible();
     if(floating){
-        this->setWindowFlags(Qt::Window);
+        this->setWindowFlags(Qt::WindowFlags(Qt::Window));
         QPoint pos = this->pos();
         if(pos.x() < 0)
             pos.setX(0);
diff --git a/src/basedock.h b/src/basedock.h
--- a/src/basedock.h	2026-04-22 13:27:36.663857788 +0200
+++ b/src/basedock.h	2026-04-22 13:27:36.666268841 +0200
@@ -28,7 +28,7 @@
 class BaseDock : public QDockWidget {
     Q_OBJECT
 public:
-    BaseDock(QWidget *parent = 0, Qt::WindowFlags flags = 0)
+    BaseDock(QWidget *parent = 0, Qt::WindowFlags flags = Qt::WindowFlags())
         : QDockWidget(parent,flags)
     {
         connect(this,SIGNAL(topLevelChanged(bool)),this,SLOT(floating_changed(bool)));
diff --git a/src/customprofession.cpp b/src/customprofession.cpp
--- a/src/customprofession.cpp	2026-04-22 13:27:36.663048556 +0200
+++ b/src/customprofession.cpp	2026-04-22 13:27:36.666970956 +0200
@@ -384,7 +384,7 @@
 void CustomProfession::set_name(QString name){
     if(name.contains("::")){
         //an icon override will be stored as name::id
-        QStringList names = name.split("::",QString::SkipEmptyParts);
+        QStringList names = name.split("::",Qt::SkipEmptyParts);
         m_name = names.at(0);
     }else{
         m_name = name;
diff --git a/src/dfinstance.cpp b/src/dfinstance.cpp
--- a/src/dfinstance.cpp	2026-04-22 13:27:36.662495828 +0200
+++ b/src/dfinstance.cpp	2026-04-22 13:47:57.140164334 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "dfinstance.h"
+#include <QElapsedTimer>
 #include "cp437codec.h"
 #include "dwarf.h"
 #include "squad.h"
@@ -103,9 +104,9 @@
 }
 
 bool DFInstance::check_vector(const VIRTADDR start, const VIRTADDR end, const VIRTADDR addr){
-    TRACE << "beginning vector enumeration at" << hex << addr;
-    TRACE << "start of vector" << hex << start;
-    TRACE << "end of vector" << hex << end;
+    TRACE << "beginning vector enumeration at" << Qt::hex << addr;
+    TRACE << "start of vector" << Qt::hex << start;
+    TRACE << "end of vector" << Qt::hex << end;
 
     int entries = (end - start) / m_pointer_size;
     TRACE << "there appears to be" << entries << "entries in this vector";
@@ -341,7 +342,7 @@
 
     emit progress_range(0, creatures_addrs.size()-1);
     TRACE << "FOUND" << creatures_addrs.size() << "creatures";
-    QTime t;
+    QElapsedTimer t;
     t.start();
     if (!creatures_addrs.empty()) {
         QPointer<Dwarf> d;
@@ -408,7 +409,7 @@
 
     foreach(Dwarf *d, m_actual_dwarves){
         //load labor counts
-        foreach(int key, d->get_labors().uniqueKeys()){
+        foreach(int key, d->get_labors().keys()){
             if(d->labor_enabled(key)){
                 if(m_enabled_labor_count.contains(key))
                     labor_count = m_enabled_labor_count.value(key)+1;
@@ -429,7 +430,7 @@
 
         //load preference/thoughts/item wear totals, excluding babies/children according to settings
         if(d->is_adult() || (!d->is_adult() && !DT->hide_non_adults())){
-            foreach(QString category_name, d->get_grouped_preferences().uniqueKeys()){
+            foreach(QString category_name, d->get_grouped_preferences().keys()){
                 for(int i = 0; i < d->get_grouped_preferences().value(category_name)->count(); i++){
 
                     QString pref = d->get_grouped_preferences().value(category_name)->at(i);
@@ -543,7 +544,7 @@
         }
     }
 
-    QTime tr;
+    QElapsedTimer tr;
     tr.start();
     LOGV << "Role Facets Info:";
     DwarfStats::facets.init(facet_values);
@@ -1186,7 +1187,7 @@
             return ret;
         }
     }
-    return qMakePair<int,QString>(DwarfJob::JOB_UNKNOWN,"");
+    return qMakePair(DwarfJob::JOB_UNKNOWN,"");
 }
 
 void DFInstance::load_activities(){
diff --git a/src/dwarf.cpp b/src/dwarf.cpp
--- a/src/dwarf.cpp	2026-04-22 13:27:36.661589339 +0200
+++ b/src/dwarf.cpp	2026-04-22 13:27:36.665048368 +0200
@@ -21,6 +21,7 @@
 THE SOFTWARE.
 */
 #include "dwarf.h"
+#include <QRegularExpression>
 #include "dfinstance.h"
 #include "trait.h"
 #include "belief.h"
@@ -186,7 +187,7 @@
 }
 
 bool Dwarf::has_invalid_flags(QHash<uint, QString> invalid_flags, quint32 dwarf_flags){
-    foreach(uint invalid_flag, invalid_flags.uniqueKeys()) {
+    foreach(uint invalid_flag, invalid_flags.keys()) {
         QString reason = invalid_flags[invalid_flag];
         if(dwarf_flags & invalid_flag) {
             set_validation(QString("%1 flags:%2").arg(reason).arg(dwarf_flags));
@@ -1046,7 +1047,7 @@
 }
 
 bool Dwarf::has_syndrome(QString name){
-    QRegExp rx = QRegExp(".*" + name + ".*",Qt::CaseInsensitive);
+    QRegularExpression rx(".*" + name + ".*", QRegularExpression::CaseInsensitiveOption);
     foreach(Syndrome s, m_syndromes){
         if(s.name().contains(rx) || s.class_names().join(" ").contains(rx))
             return true;
@@ -1146,7 +1147,7 @@
     VIRTADDR current_job_addr = m_df->read_addr(addr);
     m_current_sub_job_id.clear();
 
-    TRACE << "Current job addr: " << hex << current_job_addr;
+    TRACE << "Current job addr: " << Qt::hex << current_job_addr;
     if(current_job_addr != 0){
         m_current_job_id = m_df->read_short(m_mem->job_field(current_job_addr, "id"));
 
@@ -1689,7 +1690,7 @@
     //missing uniform items
     if(m_uniform && m_uniform->get_missing_items().count() > 0){
         QString cat_name = Item::missing_group_name();
-        foreach(ITEM_TYPE itype, m_uniform->get_missing_items().uniqueKeys()){
+        foreach(ITEM_TYPE itype, m_uniform->get_missing_items().keys()){
             foreach(ItemDefUniform *u, m_uniform->get_missing_items().value(itype)){
                 Item *i = new ItemUniform(m_df,u,this);
                 if(itype == WEAPON){
@@ -1860,9 +1861,9 @@
 
         m_total_xp += s.actual_exp();
         m_skills.insert(s.id(),s);
-        m_sorted_skills.insertMulti(s.capped_level_precise(), s.id());
+        m_sorted_skills.insert(s.capped_level_precise(), s.id());
         if(!m_had_mood && GameDataReader::ptr()->moodable_skills().contains(skill_id)){
-            skills_by_level.insertMulti(s.raw_level(),s);
+            skills_by_level.insert(s.raw_level(),s);
         }
 
         if(s.rust_level() > m_worst_rust_level)
@@ -1931,7 +1932,7 @@
 
         foreach(UnitEmotion *ue, m_emotions){
             int stress_effect = ue->set_effect(stress_vuln);
-            QChar sign;
+            QString sign;
             if(stress_effect < 0){
                 sign = QLocale().positiveSign(); //stress down, happiness up
             }else if(stress_effect > 0){
@@ -2028,7 +2029,7 @@
                 UnitBelief ub = get_unit_belief(belief_id);
                 if((ub.belief_value() > 10 && val < 40)  || (ub.belief_value() < -10 && val > 60)){
                     m_beliefs[belief_id].add_trait_conflict(trait_id);
-                    m_conflicting_beliefs.insertMulti(trait_id, ub);
+                    m_conflicting_beliefs.insert(trait_id, ub);
                 }
             }
         }
@@ -2211,7 +2212,7 @@
         Skill s = Skill(skill_id, 0, -1, 0, skill_rate);
         s.get_balanced_level();
         m_skills.insert(skill_id,s);
-        m_sorted_skills.insertMulti(s.capped_level_precise(), skill_id);
+        m_sorted_skills.insert(s.capped_level_precise(), skill_id);
     }
     return m_skills.value(skill_id);
 }
@@ -2292,7 +2293,7 @@
 QVector<int> Dwarf::get_dirty_labors() {
     QVector<int> labors;
     Q_ASSERT(m_labors.size() == m_pending_labors.size());
-    foreach(int labor_id, m_pending_labors.uniqueKeys()) {
+    foreach(int labor_id, m_pending_labors.keys()) {
         if (is_labor_state_dirty(labor_id))
             labors << labor_id;
     }
@@ -2305,21 +2306,21 @@
 }
 
 void Dwarf::clear_labors(){
-    foreach(int key, m_pending_labors.uniqueKeys()){
+    foreach(int key, m_pending_labors.keys()){
         if(labor_enabled(key))
             set_labor(key,false,false);
     }
 }
 
 void Dwarf::assign_all_labors(){
-    foreach(int key, m_pending_labors.uniqueKeys()){
+    foreach(int key, m_pending_labors.keys()){
         if(!labor_enabled(key))
             set_labor(key,true,false);
     }
 }
 
 void Dwarf::toggle_skilled_labors(){
-    foreach(int key, m_pending_labors.uniqueKeys()){
+    foreach(int key, m_pending_labors.keys()){
         toggle_skilled_labor(key);
     }
 }
@@ -2395,7 +2396,7 @@
     if(pending_changes() <= 0)
         return;
     //update our header numbers before we refresh
-    foreach(int labor_id, m_pending_labors.uniqueKeys()) {
+    foreach(int labor_id, m_pending_labors.keys()) {
         if (labor_id >= 0 && is_labor_state_dirty(labor_id))
             m_df->update_labor_count(labor_id, labor_enabled(labor_id) ? -1 : 1);
     }
@@ -2419,7 +2420,7 @@
 }
 
 void Dwarf::clear_pending_labors() {
-    foreach(int labor_id, m_pending_labors.uniqueKeys()) {
+    foreach(int labor_id, m_pending_labors.keys()) {
         if (labor_id >= 0 && is_labor_state_dirty(labor_id))
             set_labor(labor_id, m_labors[labor_id], false);
     }
@@ -2431,7 +2432,7 @@
     QByteArray buf(94, 0);
     m_df->read_raw(addr, 94, buf); // set the buffer as it is in-game
     bool needs_equip_recheck = false;
-    foreach(int labor_id, m_pending_labors.uniqueKeys()) {
+    foreach(int labor_id, m_pending_labors.keys()) {
         if (labor_id < 0)
             continue;
         // change values to what's pending
@@ -2537,7 +2538,7 @@
 void Dwarf::apply_custom_profession(CustomProfession *cp) {
     //clear all labors if the custom profession is not being applied as a mask
     if(!cp->is_mask()){
-        foreach(int labor_id, m_pending_labors.uniqueKeys()) {
+        foreach(int labor_id, m_pending_labors.keys()) {
             set_labor(labor_id, false,false);
         }
     }
@@ -2656,7 +2657,7 @@
         bool use_color = s->value("tooltip_show_skills_use_color",true).toBool();
         bool top_skills_only = s->value("tooltip_only_top_skills",true).toBool();
         int top_skill_count = s->value("tooltip_top_skill_count",12).toInt();
-        QMapIterator<float,int> i(m_sorted_skills);
+        QMultiMapIterator<float,int> i(m_sorted_skills);
         i.toBack();
         while(i.hasPrevious()){
             i.previous();
@@ -2702,7 +2703,7 @@
 
             //beliefs
             QStringList beliefs_list;
-            foreach(int belief_id, m_beliefs.uniqueKeys()) {
+            foreach(int belief_id, m_beliefs.keys()) {
                 if(!belief_is_active(belief_id))
                     continue;
                 Belief *b = gdr->get_belief(belief_id);
@@ -2844,7 +2845,7 @@
         QStringList status_wound_summary = m_unit_health.get_status_summary(colors, symbols);
         QMap<QString,QStringList> wound_summary = m_unit_health.get_wound_summary(colors, symbols);
         if(wound_summary.size() > 0){
-            foreach(QString key, wound_summary.uniqueKeys()){
+            foreach(QString key, wound_summary.keys()){
                 QStringList info = wound_summary.value(key);
                 foreach(QString i, info){
                     if(!status_wound_summary.contains(i))
@@ -3171,7 +3172,7 @@
 void Dwarf::refresh_role_display_ratings(){
     GameDataReader *gdr = GameDataReader::ptr();
     //keep a sorted list of the display ratings for tooltips, detail pane, etc.
-    foreach(QString name, m_raw_role_ratings.uniqueKeys()){
+    foreach(QString name, m_raw_role_ratings.keys()){
         Role::simple_rating sr;
         sr.is_custom = gdr->get_role(name)->is_custom();
         float display_rating = DwarfStats::roles.rating(m_raw_role_ratings.value(name)) * 100.0f;
diff --git a/src/dwarfdetailswidget.cpp b/src/dwarfdetailswidget.cpp
--- a/src/dwarfdetailswidget.cpp	2026-04-22 13:27:36.661314130 +0200
+++ b/src/dwarfdetailswidget.cpp	2026-04-22 13:27:36.667268799 +0200
@@ -503,7 +503,7 @@
     ui->tw_traits->setSortingEnabled(false);
     QColor trait_color;
     QList<int> conflicted_beliefs;
-    foreach(int trait_id, traits.uniqueKeys()) {
+    foreach(int trait_id, traits.keys()) {
         if (d->trait_is_active(trait_id))
         {
             trait_color = QColor(); // invalid color will leave default color
@@ -533,7 +533,7 @@
         }
     }
     //also append goals
-    foreach(int id, d->goals().uniqueKeys()){
+    foreach(int id, d->goals().keys()){
         QString name = "~" + gdr->get_goal_name(id);
         QString desc = gdr->get_goal_desc(id,d->goals().value(id));
         add_personality_row(name,d->goals().value(id)*100,desc,desc,adaptive.color(Trait::goal_color));
@@ -586,7 +586,7 @@
     ui->tw_prefs->setSortingEnabled(false);
 
     QString prefs;
-    foreach(QString name, d->get_grouped_preferences().uniqueKeys()){
+    foreach(QString name, d->get_grouped_preferences().keys()){
 
         prefs = capitalize(d->get_grouped_preferences().value(name)->join(", "));
 
@@ -622,12 +622,12 @@
 
         //add the treatments
         QHash<eHealth::H_INFO, QList<HealthInfo*> > t_info = dHealth.get_treatment_info();
-        foreach(eHealth::H_INFO h, t_info.uniqueKeys()){
+        foreach(eHealth::H_INFO h, t_info.keys()){
             QList<HealthInfo*> infos = t_info.value(h);
             foreach(HealthInfo* hi, infos){
                 QTreeWidgetItem *node = new QTreeWidgetItem(treatments);
                 node->setData(0, Qt::UserRole, hi->symbol(false));
-                node->setData(0,Qt::TextColorRole, hi->color());
+                node->setData(0,Qt::ForegroundRole, hi->color());
                 node->setText(0, hi->symbol(false));
 
                 node->setData(1, Qt::UserRole, hi->description(false));
@@ -637,13 +637,13 @@
 
         //add the statuses
         QHash<eHealth::H_INFO, QList<HealthInfo*> > s_info = dHealth.get_status_info();
-        foreach(eHealth::H_INFO h, s_info.uniqueKeys()){
+        foreach(eHealth::H_INFO h, s_info.keys()){
             QList<HealthInfo*> infos = s_info.value(h);
             foreach(HealthInfo* hi, infos){
             //HealthInfo *hi = dHealth.get_most_severe(h);
                 QTreeWidgetItem *node = new QTreeWidgetItem(statuses);
                 node->setData(0, Qt::UserRole, hi->symbol(false));
-                node->setData(0,Qt::TextColorRole, hi->color());
+                node->setData(0,Qt::ForegroundRole, hi->color());
                 node->setText(0, hi->symbol(false));
 
                 node->setData(1, Qt::UserRole, hi->description(false));
@@ -654,7 +654,7 @@
         //add each wounded body part as a node, and then each wound as a node of the body part
         QHash<QString, QList<HealthInfo*> > wounds_info  = dHealth.get_wound_details();
         QList<QTreeWidgetItem*> wound_nodes;
-        foreach(QString bp, wounds_info.uniqueKeys()){
+        foreach(QString bp, wounds_info.keys()){
             QList<HealthInfo*> infos = wounds_info.value(bp);
             //add the body part as the parent node
             QString name = capitalizeEach(bp);
@@ -666,7 +666,7 @@
             foreach(HealthInfo* hi, infos){
                 QTreeWidgetItem *node = new QTreeWidgetItem(body_part_node);
                 node->setData(0, Qt::UserRole, hi->symbol(false));
-                node->setData(0,Qt::TextColorRole, hi->color());
+                node->setData(0,Qt::ForegroundRole, hi->color());
                 node->setText(0, hi->symbol(false));
 
                 node->setData(1, Qt::UserRole, hi->description(false));
diff --git a/src/dwarfdetailswidget.h b/src/dwarfdetailswidget.h
--- a/src/dwarfdetailswidget.h	2026-04-22 13:27:36.661276704 +0200
+++ b/src/dwarfdetailswidget.h	2026-04-22 13:27:36.666238353 +0200
@@ -42,7 +42,7 @@
 class DwarfDetailsWidget: public QWidget {
     Q_OBJECT
 public:
-    DwarfDetailsWidget(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+    DwarfDetailsWidget(QWidget *parent = 0, Qt::WindowFlags flags = Qt::WindowFlags());
     ~DwarfDetailsWidget();
 
     int saved_id() const { return m_saved_id; }
diff --git a/src/dwarfjob.h b/src/dwarfjob.h
--- a/src/dwarfjob.h	2026-04-22 13:27:36.660981898 +0200
+++ b/src/dwarfjob.h	2026-04-22 13:27:36.668768710 +0200
@@ -24,6 +24,7 @@
 #define DWARF_JOB_H
 
 #include "truncatingfilelogger.h"
+#include <QRegularExpression>
 #include "gamedatareader.h"
 
 #include <QString>
@@ -120,10 +121,10 @@
             return m_name;
         }else{
             QString name = m_name;
-            QRegExp re(".*(\\[.*\\]).*");
-            int idx = re.indexIn(m_name);
-            if(idx > -1){
-                name.replace(re.cap(1),replacement);
+            QRegularExpression re(".*(\\[.*\\]).*");
+            QRegularExpressionMatch m = re.match(m_name);
+            if(m.hasMatch()){
+                name.replace(m.captured(1),replacement);
             }
             return name;
         }
diff --git a/src/dwarfmodel.cpp b/src/dwarfmodel.cpp
--- a/src/dwarfmodel.cpp	2026-04-22 13:27:36.660822048 +0200
+++ b/src/dwarfmodel.cpp	2026-04-22 13:27:36.665733445 +0200
@@ -21,6 +21,7 @@
 THE SOFTWARE.
 */
 #include "dfinstance.h"
+#include <QElapsedTimer>
 #include "dwarfmodel.h"
 #include "dwarf.h"
 #include "skill.h"
@@ -127,7 +128,7 @@
                     if(l->labor_id()==id){
                         l->update_count(); //tell this column to update it's count
                         QStandardItem* header = this->horizontalHeaderItem(index);
-                        header->setData(col->bg_color(), Qt::BackgroundColorRole);
+                        header->setData(col->bg_color(), Qt::BackgroundRole);
                         header->setData(set->name(), Qt::UserRole);
                         if(m_show_labor_counts){
                             header->setText(QString("%1 %2")
@@ -153,7 +154,7 @@
     QString max_title = "";
     foreach(ViewColumnSet *set, m_gridview->sets()) {
         /*QStandardItem *set_header = new QStandardItem(set->name());
-        set_header->setData(set->bg_color(), Qt::BackgroundColorRole);
+        set_header->setData(set->bg_color(), Qt::BackgroundRole);
         set_header->setData(true);
         setHorizontalHeaderItem(start_col++, set_header);
         emit set_index_as_spacer(start_col - 1);
@@ -172,7 +173,7 @@
 
             QStandardItem *header = new QStandardItem(h_name);
             header->setToolTip(build_col_tooltip(col));
-            header->setData(col->bg_color(), Qt::BackgroundColorRole);
+            header->setData(col->bg_color(), Qt::BackgroundRole);
             header->setData(set->name(), Qt::UserRole);
             setHorizontalHeaderItem(start_col++, header);
             switch (col->type()) {
@@ -407,7 +408,7 @@
         }
     }
 
-    foreach(QString key, m_grouped_dwarves.uniqueKeys()) {
+    foreach(QString key, m_grouped_dwarves.keys()) {
         build_row(key);
     }
 
@@ -795,7 +796,7 @@
     LOGI << "group_by now set to" << group_by << " for view " << current_grid_view()->name();
     m_group_by = static_cast<GROUP_BY>(group_by);
     if(!m_df.isNull()){
-        QTime t;
+        QElapsedTimer t;
         t.start();
         build_rows();
         LOGI << "loaded rows for" << m_gridview->name() << t.elapsed() << "ms";
diff --git a/src/dwarfmodelproxy.cpp b/src/dwarfmodelproxy.cpp
--- a/src/dwarfmodelproxy.cpp	2026-04-22 13:27:36.660707144 +0200
+++ b/src/dwarfmodelproxy.cpp	2026-04-22 13:27:36.677435048 +0200
@@ -113,14 +113,17 @@
     if(sType == SCR_ALL){
         m_scripts.clear();
     }else{
+        QStringList keys_to_remove;
         QHashIterator<QString,script_info> i(m_scripts);
-        i.toBack();
-        while (i.hasPrevious()) {
-            i.previous();
+        while (i.hasNext()) {
+            i.next();
             if(static_cast<script_info>(i.value()).script_type == sType){
-                m_scripts.remove(i.key());
+                keys_to_remove.append(i.key());
             }
         }
+        for (const QString &key : keys_to_remove) {
+            m_scripts.remove(key);
+        }
     }
     if(refresh){
         invalidateFilter();
diff --git a/src/dwarftherapist.cpp b/src/dwarftherapist.cpp
--- a/src/dwarftherapist.cpp	2026-04-22 13:27:36.660478786 +0200
+++ b/src/dwarftherapist.cpp	2026-04-22 13:27:36.666081591 +0200
@@ -629,7 +629,7 @@
 
     df->attach();
     if (generic_lang_table != 0xFFFFFFFF && generic_lang_table != 0) {
-        LOGI << "Loading generic strings from" << hex << generic_lang_table;
+        LOGI << "Loading generic strings from" << Qt::hex << generic_lang_table;
         QVector<VIRTADDR> generic_words = df->enumerate_vector(generic_lang_table);
         LOGI << "generic words" << generic_words.size();
         foreach(VIRTADDR word_ptr, generic_words) {
@@ -643,12 +643,12 @@
         uint dwarf_entry = 0;
         foreach(uint lang, languages) {
             QString race_name = df->read_string(lang);
-            LOGI << "FOUND LANG ENTRY" << hex << lang << race_name;
+            LOGI << "FOUND LANG ENTRY" << Qt::hex << lang << race_name;
             if (race_name == "DWARF")
                 dwarf_entry = lang;
         }
         uint dwarf_lang_table = dwarf_entry + word_table_offset;
-        LOGI << "Loading dwarf strings from" << hex << dwarf_lang_table;
+        LOGI << "Loading dwarf strings from" << Qt::hex << dwarf_lang_table;
         QVector<VIRTADDR> dwarf_words = df->enumerate_vector(dwarf_lang_table);
         LOGI << "dwarf words" << dwarf_words.size();
 
diff --git a/src/equipmentcolumn.cpp b/src/equipmentcolumn.cpp
--- a/src/equipmentcolumn.cpp	2026-04-22 13:27:36.660268958 +0200
+++ b/src/equipmentcolumn.cpp	2026-04-22 13:27:36.666305880 +0200
@@ -72,7 +72,7 @@
 
     float sort_val = rating - d->get_max_wear_level();
     item->setData(d->get_max_wear_level(),DwarfModel::DR_SPECIAL_FLAG);
-    //item->setData(rating_color,Qt::BackgroundColorRole);
+    //item->setData(rating_color,Qt::BackgroundRole);
     item->setData(CT_EQUIPMENT, DwarfModel::DR_COL_TYPE);
     item->setData(rating, DwarfModel::DR_RATING); //other drawing 0-100
     item->setData(sort_val, DwarfModel::DR_SORT_VALUE);
diff --git a/src/equipmentoverviewwidget.cpp b/src/equipmentoverviewwidget.cpp
--- a/src/equipmentoverviewwidget.cpp	2026-04-22 13:27:36.660172737 +0200
+++ b/src/equipmentoverviewwidget.cpp	2026-04-22 13:27:36.664934370 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "dfinstance.h"
+#include <QRegularExpression>
 #include "dwarftherapist.h"
 #include "equipmentoverviewwidget.h"
 #include "equipwarn.h"
@@ -74,12 +75,12 @@
         m_option_state = DT->user_settings()->value(m_option_name,false).toBool();
         QHash<ITEM_TYPE,EquipWarn*> eq_warnings = DT->get_DFInstance()->get_equip_warnings();
 
-        foreach(ITEM_TYPE i_type, eq_warnings.uniqueKeys()){
+        foreach(ITEM_TYPE i_type, eq_warnings.keys()){
             EquipWarn *ew = eq_warnings.value(i_type);
             QString item_name = Item::get_item_generic_name(i_type);
             QStringList warn_desc;
             QVariantMap warn_counts;
-            foreach(Item::ITEM_STATE i_status, ew->get_wear_counts().uniqueKeys()){
+            foreach(Item::ITEM_STATE i_status, ew->get_wear_counts().keys()){
                 int count = ew->get_wear_counts().value(i_status);
                 warn_desc.append(tr("<font color=%1>%2 %3</font>")
                                  .arg(Item::get_color(i_status).name())
@@ -104,7 +105,7 @@
 
             AdaptiveColorFactory adaptive;
             QPair<QString,Item::ITEM_STATE> warn_key;
-            foreach(warn_key, ew->get_details().uniqueKeys()){
+            foreach(warn_key, ew->get_details().keys()){
                 EquipWarn::warn_count wc = ew->get_details().value(warn_key);
 
                 QString detail_name = warn_key.first;
@@ -131,7 +132,7 @@
                 item_node->setText(0, detail_name);
 
                 item_node->setToolTip(1, tooltip);
-                item_node->setData(1,Qt::TextColorRole, adaptive.color(col));
+                item_node->setData(1,Qt::ForegroundRole, adaptive.color(col));
                 item_node->setText(1,wear_desc);
 
                 item_node->setData(2, Qt::UserRole, wc.unit_ids.values());
@@ -154,7 +155,7 @@
 
 void EquipmentOverviewWidget::search_tree(QString val){
     val = "(" + val.replace(" ", "|") + ")";
-    QRegExp filter = QRegExp(val,Qt::CaseInsensitive, QRegExp::RegExp);
+    QRegularExpression filter(val, QRegularExpression::CaseInsensitiveOption);
     int hidden;
     bool parent_matches;
     for(int i = 0; i < m_tree_view->topLevelItemCount(); i++){
@@ -213,7 +214,7 @@
         QString curr_text = "";
 
         AdaptiveColorFactory adaptive;
-        foreach(QString wear_level, counts.uniqueKeys()){
+        foreach(QString wear_level, counts.keys()){
             int count = counts.value(wear_level).toInt();
             QColor col = adaptive.color(Item::get_color(static_cast<Item::ITEM_STATE>(wear_level.toInt())));
             if(curr_text != ""){
@@ -226,7 +227,7 @@
 }
 
 QString EquipWarnItemDelegate::appendText(QPainter *painter, const QStyleOptionViewItem &option, QColor text_color, QString curr_text, QString text) const {
-    int text_width = painter->fontMetrics().width(curr_text);
+    int text_width = painter->fontMetrics().horizontalAdvance(curr_text);
     QRect r_display = option.rect.adjusted(text_width,0,0,0);
     painter->setPen(text_color);
     painter->drawText(r_display,Qt::AlignLeft | Qt::AlignVCenter,text);
@@ -234,7 +235,7 @@
 }
 
 QString EquipWarnItemDelegate::prependText(QPainter *painter, const QStyleOptionViewItem &option, QColor text_color, QString curr_text, QString text) const {
-    int text_width = -painter->fontMetrics().width(curr_text);
+    int text_width = -painter->fontMetrics().horizontalAdvance(curr_text);
     QRect r_display = option.rect.adjusted(0,0,text_width,0);
     painter->setPen(text_color);
     painter->drawText(r_display,Qt::AlignRight | Qt::AlignVCenter,text);
diff --git a/src/flagarray.cpp b/src/flagarray.cpp
--- a/src/flagarray.cpp	2026-04-22 13:27:36.659985279 +0200
+++ b/src/flagarray.cpp	2026-04-22 13:27:36.667455566 +0200
@@ -69,7 +69,7 @@
     for(int i=0; i < m_flags.size(); i++){
         ret.append(output_flag(i,m_flags.at(i),active));
     }
-    foreach(int f, m_flags_custom.uniqueKeys()){
+    foreach(int f, m_flags_custom.keys()){
         ret.append(output_flag(f,m_flags_custom.value(f),active));
     }
     ret.removeAll("");
@@ -93,7 +93,7 @@
         if(m_flags.at(idx))
             active << idx;
     }
-    foreach(int f, m_flags_custom.uniqueKeys()){
+    foreach(int f, m_flags_custom.keys()){
         if(m_flags_custom.value(f))
             active << f;
     }
diff --git a/src/flagcolumn.cpp b/src/flagcolumn.cpp
--- a/src/flagcolumn.cpp	2026-04-22 13:27:36.659906779 +0200
+++ b/src/flagcolumn.cpp	2026-04-22 13:27:36.666361146 +0200
@@ -109,7 +109,7 @@
     }
 
     item->setData(state,DwarfModel::DR_STATE);
-    info_col_name = get_state_color(state).name();//item->data(Qt::BackgroundColorRole).value<QColor>().name();
+    info_col_name = get_state_color(state).name();//item->data(Qt::BackgroundRole).value<QColor>().name();
 
     item->setData(rating, DwarfModel::DR_SORT_VALUE);
     item->setData(m_bit_pos, DwarfModel::DR_OTHER_ID);
diff --git a/src/gamedatareader.cpp b/src/gamedatareader.cpp
--- a/src/gamedatareader.cpp	2026-04-22 13:27:36.659465209 +0200
+++ b/src/gamedatareader.cpp	2026-04-22 13:27:36.667495012 +0200
@@ -47,11 +47,9 @@
     if (!game_data_file.isEmpty()) {
         LOGI << "Found custom game_data.ini:" << game_data_file;
         m_data_settings = QPointer<QSettings>(new QSettings(game_data_file, QSettings::IniFormat));
-        m_data_settings->setIniCodec("UTF-8");
     } else {
         //load default game_data
         m_data_settings = QPointer<QSettings>(new QSettings(":config/game_data", QSettings::IniFormat));
-        m_data_settings->setIniCodec("UTF-8");
         if(m_data_settings->childGroups().count() <= 0){
             QString err = tr("Dwarf Therapist cannot run because game_data.ini could not be found!");
             QMessageBox::critical(0,tr("Missing File"),err);
@@ -123,7 +121,7 @@
 
     std::sort(attribute_names.begin(), attribute_names.end());
     foreach(QString sorted_name, attribute_names) {
-        foreach(ATTRIBUTES_TYPE id, m_attribute_names.uniqueKeys()) {
+        foreach(ATTRIBUTES_TYPE id, m_attribute_names.keys()) {
             if (m_attribute_names.value(id) == sorted_name) {
                 m_ordered_attribute_names << QPair<ATTRIBUTES_TYPE, QString>(id, m_attribute_names.value(id));
                 break;
@@ -188,7 +186,7 @@
 
     std::sort(goal_names.begin(), goal_names.end());
     foreach(QString name, goal_names) {
-        foreach(int goal_id, m_goals.uniqueKeys()) {
+        foreach(int goal_id, m_goals.keys()) {
             if (m_goals.value(goal_id).first == name) {
                 m_ordered_goals << qMakePair(goal_id,name);
                 break;
diff --git a/src/gridviewdialog.cpp b/src/gridviewdialog.cpp
--- a/src/gridviewdialog.cpp	2026-04-22 13:27:36.659076662 +0200
+++ b/src/gridviewdialog.cpp	2026-04-22 13:27:36.666443299 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "gridviewdialog.h"
+#include <QRegularExpression>
 #include "ui_gridviewdialog.h"
 #include "viewmanager.h"
 #include "gridview.h"
@@ -104,9 +105,7 @@
     , m_pref_model(pref_model)
 {
     qRegisterMetaType<ViewColumnSet *>();
-    qRegisterMetaTypeStreamOperators<ViewColumnSet *>();
     qRegisterMetaType<ViewColumn *>();
-    qRegisterMetaTypeStreamOperators<ViewColumn *>();
 
     ui->setupUi(this);
     ui->list_sets->setModel(m_set_model);
@@ -215,11 +214,11 @@
 
         QColor new_bg = vc->override_color() ? vc->bg_color() : set->bg_color();
         item->setBackground(new_bg);
-        item->setData(new_bg,Qt::BackgroundColorRole);
+        item->setData(new_bg,Qt::BackgroundRole);
         vc->set_bg_color(new_bg);
 
         item->setForeground(complement(new_bg));
-        item->setData(complement(new_bg),Qt::TextColorRole);
+        item->setData(complement(new_bg),Qt::ForegroundRole);
 
         if(set_changed){
             vc->get_colors()->inherit_colors(*set->get_colors());
@@ -236,12 +235,13 @@
 }
 
 void GridViewDialog::add_set() {
-    QRegExp rx = QRegExp("^New Set (\\d+)$");
+    QRegularExpression rx("^New Set (\\d+)$");
     int highest_new_set_number = 0;
     foreach(ViewColumnSet *set, m_pending_view->sets()) {
-        if (rx.indexIn(set->name()) != -1) {
-            if (rx.cap(1).toInt() > highest_new_set_number)
-                highest_new_set_number = rx.cap(1).toInt();
+        QRegularExpressionMatch m = rx.match(set->name());
+        if (m.hasMatch()) {
+            if (m.captured(1).toInt() > highest_new_set_number)
+                highest_new_set_number = m.captured(1).toInt();
         }
     }
 
@@ -268,7 +268,7 @@
 
         set->set_bg_color(d->background_color());
         item->setBackground(set->bg_color());
-        item->setData(set->bg_color(),Qt::BackgroundColorRole);
+        item->setData(set->bg_color(),Qt::BackgroundRole);
 
         set->get_colors()->set_overrides_cell_colors(d->ui->cb_override_cell_colors->isChecked());
         if(d->ui->cb_override_cell_colors->isChecked()){
diff --git a/src/happinesscolumn.cpp b/src/happinesscolumn.cpp
--- a/src/happinesscolumn.cpp	2026-04-22 13:27:36.658763584 +0200
+++ b/src/happinesscolumn.cpp	2026-04-22 13:27:36.667625737 +0200
@@ -104,7 +104,7 @@
 }
 
 void HappinessColumn::redraw_cells() {
-    foreach(Dwarf *d, m_cells.uniqueKeys()) {
+    foreach(Dwarf *d, m_cells.keys()) {
         if (d && m_cells[d] && m_cells[d]->model())
             m_cells[d]->setBackground(DT->get_happiness_color(d->get_happiness()));
     }
diff --git a/src/healthcategory.h b/src/healthcategory.h
--- a/src/healthcategory.h	2026-04-22 13:27:36.658688371 +0200
+++ b/src/healthcategory.h	2026-04-22 13:27:36.668816876 +0200
@@ -2,6 +2,7 @@
 #define HEALTHCATEGORY_H
 
 #include "truncatingfilelogger.h"
+#include <QRegularExpression>
 #include "healthinfo.h"
 #include <QSettings>
 
@@ -40,7 +41,7 @@
             HealthInfo *hi = new HealthInfo();
             hi->set_description(s.value("desc","???").toString());
             QString sym = s.value("symbol","?").toString();
-            if(sym.contains(QRegExp("0x[0-9A-F]{4}"))){
+            if(sym.contains(QRegularExpression("0x[0-9A-F]{4}"))){
                 hi->set_symbol(QChar(sym.toUInt(&hex_ok,16)));
             }else{
                 hi->set_symbol(sym);
diff --git a/src/healthcolumn.cpp b/src/healthcolumn.cpp
--- a/src/healthcolumn.cpp	2026-04-22 13:27:36.658636443 +0200
+++ b/src/healthcolumn.cpp	2026-04-22 13:27:36.667220660 +0200
@@ -72,7 +72,7 @@
     QMap<QString,QStringList> wound_details = dHealth.get_wound_summary(apply_color,use_symbols);
     if(wound_details.size() > 0){
         QString wnd_sum = "";
-        foreach(QString key, wound_details.uniqueKeys()){
+        foreach(QString key, wound_details.keys()){
             wnd_sum.append("<li>").append("<b>").append(capitalizeEach(key)).append("</b>");
             if(wound_details.value(key).length() > 0){
                  wnd_sum.append("<ul><li>");
@@ -105,7 +105,7 @@
                     health_summary.replace(re, QString("<b>%2</b>").arg(h_info->description(true)));
             }
         }
-        item->setData(hi->color(),Qt::TextColorRole);
+        item->setData(hi->color(),Qt::ForegroundRole);
     }
 
     item->setData(rating, DwarfModel::DR_SORT_VALUE);
diff --git a/src/healthlegendwidget.cpp b/src/healthlegendwidget.cpp
--- a/src/healthlegendwidget.cpp	2026-04-22 13:27:36.658527465 +0200
+++ b/src/healthlegendwidget.cpp	2026-04-22 13:27:36.667178859 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "healthlegendwidget.h"
+#include <QRegularExpression>
 #include "healthcategory.h"
 #include "unithealth.h"
 
@@ -48,7 +49,7 @@
             QTreeWidgetItem *node = new QTreeWidgetItem(parent_node);
 
             node->setData(0, Qt::UserRole, hi->severity());
-            node->setData(0,Qt::TextColorRole, hi->color());
+            node->setData(0,Qt::ForegroundRole, hi->color());
             node->setText(0, hi->symbol(false));
 
             node->setData(1, Qt::UserRole, hi->description(false));
@@ -63,7 +64,7 @@
 
 void HealthLegendWidget::search_tree(QString val){
     val = "(" + val.replace(" ", "|") + ")";
-    QRegExp filter = QRegExp(val,Qt::CaseInsensitive, QRegExp::RegExp);
+    QRegularExpression filter(val, QRegularExpression::CaseInsensitiveOption);
     int hidden;
     for(int i = 0; i < m_tree_view->topLevelItemCount(); i++){
         hidden = 0;
diff --git a/src/itemtypecolumn.cpp b/src/itemtypecolumn.cpp
--- a/src/itemtypecolumn.cpp	2026-04-22 13:27:36.657260873 +0200
+++ b/src/itemtypecolumn.cpp	2026-04-22 13:27:36.664593858 +0200
@@ -99,7 +99,7 @@
     QList<Item*> missing = grouped_equipment.take(Item::missing_group_name());
     QList<Item*> uncovered = grouped_equipment.take(Item::uncovered_group_name());
     if(grouped_equipment.size() > 0){
-        foreach(QString bp_name, grouped_equipment.uniqueKeys()){
+        foreach(QString bp_name, grouped_equipment.keys()){
             QString bp_group = "";
             if(grouped_equipment.value(bp_name).length() > 0){
                 QString items;
@@ -145,7 +145,7 @@
                 if(bp_name.contains(tr("left"),Qt::CaseInsensitive))
                     ord_idx += 13;
 
-                ordered_desc.insertMulti(ord_idx,group_desc);
+                ordered_desc.insert(ord_idx,group_desc);
             }
         }
     }
diff --git a/src/laboroptimizer.cpp b/src/laboroptimizer.cpp
--- a/src/laboroptimizer.cpp	2026-04-22 13:27:36.656844598 +0200
+++ b/src/laboroptimizer.cpp	2026-04-22 13:27:36.667693650 +0200
@@ -219,7 +219,7 @@
     }
 
     if(m_plan->auto_haulers){
-        foreach(int id, haulers.uniqueKeys()){
+        foreach(int id, haulers.keys()){
             Dwarf *d = haulers.value(id);
             foreach(l, skill_less_jobs){
                 d->set_labor(l->labor_id, true, false);
diff --git a/src/languages.cpp b/src/languages.cpp
--- a/src/languages.cpp	2026-04-22 13:27:36.656662146 +0200
+++ b/src/languages.cpp	2026-04-22 13:29:28.302258095 +0200
@@ -83,9 +83,9 @@
         int id = 0;
         foreach(VIRTADDR lang, languages) {
             QString race_name = m_df->read_string(lang);
-            TRACE << "FOUND LANG ENTRY" << hex << lang << race_name;
+            TRACE << "FOUND LANG ENTRY" << Qt::hex << lang << race_name;
             VIRTADDR lang_table = lang + word_table_offset;
-            TRACE << "Loading " << race_name << " strings from" << hex << lang_table;
+            TRACE << "Loading " << race_name << " strings from" << Qt::hex << lang_table;
             QVector<VIRTADDR> lang_words = m_df->enumerate_vector(lang_table);
             TRACE << race_name << " words" << lang_words.size();
             QStringList words_list;
@@ -201,8 +201,11 @@
 
     auto it = m_words.find(language_id);
     //if the language doesn't exist, use the last language (DF behaviour)
-    if (it == m_words.end())
-        --it;
+    if (it == m_words.end()) {
+        it = m_words.begin();
+        for (auto i = m_words.begin(); i != m_words.end(); ++i)
+            it = i;
+    }
 
     if (word < 0 || word >= it->count()) {
         LOGE << "Invalid word index:" << word;
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp	2026-04-22 13:27:36.656323689 +0200
+++ b/src/mainwindow.cpp	2026-04-22 13:29:28.311562151 +0200
@@ -21,6 +21,7 @@
 THE SOFTWARE.
 */
 #include "mainwindow.h"
+#include <QElapsedTimer>
 #include "ui_mainwindow.h"
 #include "aboutdialog.h"
 #include "dwarf.h"
@@ -99,6 +100,10 @@
 {
     ui->setupUi(this);
 
+    connect(ui->act_open_data_dir, &QAction::triggered, this, &MainWindow::open_data_dir);
+    connect(ui->act_open_log_dir, &QAction::triggered, this, &MainWindow::open_log_dir);
+    connect(ui->act_memory_layouts, &QAction::triggered, this, &MainWindow::show_memory_layouts);
+
     m_updater = std::make_unique<Updater>();
     m_notifier = std::make_unique<NotifierWidget>(this);
     connect(m_updater.get(), &Updater::notify,
@@ -466,7 +471,7 @@
         return;
     }
 
-    QTime t;
+    QElapsedTimer t;
     t.start();
 
     save_ui_selections();
@@ -510,7 +515,7 @@
 
     QHash<QPair<QString,QString>,DFInstance::pref_stat* > prefs = DT->get_DFInstance()->get_preference_stats();
     QPair<QString,QString> key_pair;
-    foreach(key_pair, prefs.uniqueKeys()){
+    foreach(key_pair, prefs.keys()){
         QStandardItem *i = new QStandardItem(key_pair.second);
         i->setData(key_pair.second,DwarfModel::DR_SPECIAL_FLAG);
         QVariantList data;
@@ -742,7 +747,7 @@
     QTreeWidgetItem *icons = new QTreeWidgetItem();
     icons->setText(0,"Custom Icons");
     icons->setToolTip(0,tr("Right click on a profession icon in the grid to customize the default icon."));
-    foreach(int key, DT->get_custom_prof_icons().uniqueKeys()){
+    foreach(int key, DT->get_custom_prof_icons().keys()){
         i = new QTreeWidgetItem(icons);
         cp = DT->get_custom_prof_icon(key);
         i->setText(0,cp->get_name());
@@ -931,7 +936,7 @@
                     row.append(col->title());
             }
         }
-        out << row.join(",") << endl;
+        out << row.join(",") << Qt::endl;
         row.clear();
 
         QList<Dwarf*> dwarves = m_proxy->get_filtered_dwarves();
@@ -946,7 +951,7 @@
                         row.append(col->get_cell_value(d));
                 }
             }
-            out << row.join(",") << endl;
+            out << row.join(",") << Qt::endl;
             row.clear();
         }
         f.close();
@@ -1033,7 +1038,7 @@
     }
     s->endGroup();
 
-    foreach(QString name, scripts.uniqueKeys()){
+    foreach(QString name, scripts.keys()){
         QStringList data;
         data.append(name);
         data.append(scripts.value(name));
@@ -1465,7 +1470,7 @@
     s->beginWriteArray("labor_optimizations");
     int count = 0;
     QHash<QString, laborOptimizerPlan*> plans = GameDataReader::ptr()->get_opt_plans();
-    foreach(QString key, plans.uniqueKeys()){
+    foreach(QString key, plans.keys()){
         s->setArrayIndex(count);
         plans.value(key)->write_to_ini(*s);
         count++;
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
--- a/src/mainwindow.ui	2026-04-22 13:27:36.648480419 +0200
+++ b/src/mainwindow.ui	2026-04-22 13:27:36.664643179 +0200
@@ -1857,54 +1857,6 @@
     </hint>
    </hints>
   </connection>
-  <connection>
-   <sender>act_open_data_dir</sender>
-   <signal>triggered()</signal>
-   <receiver>MainWindow</receiver>
-   <slot>open_data_dir()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>629</x>
-     <y>257</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>act_open_log_dir</sender>
-   <signal>triggered()</signal>
-   <receiver>MainWindow</receiver>
-   <slot>open_log_dir()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>629</x>
-     <y>257</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>act_memory_layouts</sender>
-   <signal>triggered()</signal>
-   <receiver>MainWindow</receiver>
-   <slot>show_memory_layouts()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>629</x>
-     <y>257</y>
-    </hint>
-   </hints>
-  </connection>
  </connections>
  <slots>
   <slot>connect_to_df()</slot>
@@ -1937,5 +1889,8 @@
   <slot>open_help()</slot>
   <slot>go_to_latest_release()</slot>
   <slot>check_latest_version()</slot>
+  <slot>open_data_dir()</slot>
+  <slot>open_log_dir()</slot>
+  <slot>show_memory_layouts()</slot>
  </slots>
 </ui>
diff --git a/src/multilabor.cpp b/src/multilabor.cpp
--- a/src/multilabor.cpp	2026-04-22 13:27:36.655788661 +0200
+++ b/src/multilabor.cpp	2026-04-22 13:27:36.667783225 +0200
@@ -38,7 +38,7 @@
 */
 QVector<int> MultiLabor::get_enabled_labors() {
     QVector<int> labors;
-    foreach(int labor, m_active_labors.uniqueKeys()) {
+    foreach(int labor, m_active_labors.keys()) {
         if (m_active_labors.value(labor)) {
             labors << labor;
         }
@@ -48,7 +48,7 @@
 
 QVector<int> MultiLabor::get_enabled_skilled_labors(){
     QVector<int> labors;
-    foreach(int labor, m_active_labors.uniqueKeys()) {
+    foreach(int labor, m_active_labors.keys()) {
         if (m_active_labors.value(labor) && gdr->get_labor(labor)->skill_id >= 0) {
             labors << labor;
         }
diff --git a/src/needswidget.cpp b/src/needswidget.cpp
--- a/src/needswidget.cpp	2026-04-22 13:27:36.655583588 +0200
+++ b/src/needswidget.cpp	2026-04-22 13:27:36.667109710 +0200
@@ -141,13 +141,13 @@
         auto focus_degree_name = new QStandardItem;
         focus_degree_name->setText(Dwarf::get_focus_adjective(i));
         focus_degree_name->setToolTip(Dwarf::get_focus_adjective(i));
-        focus_degree_name->setData(color, Qt::TextColorRole);
+        focus_degree_name->setData(color, Qt::ForegroundRole);
         focus_degree_name->setData(i, DegreeRole);
         focus_degree_name->setFlags(flags);
 
         auto focus_degree_count = new QStandardItem;
         focus_degree_count->setText(QString::number(size));
-        focus_degree_count->setData(color, Qt::TextColorRole);
+        focus_degree_count->setData(color, Qt::ForegroundRole);
         focus_degree_count->setFlags(flags);
 
         overall_focus_name->appendRow({focus_degree_name, focus_degree_count});
@@ -209,7 +209,7 @@
             need_degree_name->setText(UnitNeed::degree_adjective(i));
             need_degree_name->setToolTip(desc);
             need_degree_name->setData(i, SortRole);
-            need_degree_name->setData(color, Qt::TextColorRole);
+            need_degree_name->setData(color, Qt::ForegroundRole);
             need_degree_name->setData(need_id, NeedRole);
             need_degree_name->setData(deity_id, DeityRole);
             need_degree_name->setData(i, DegreeRole);
@@ -219,7 +219,7 @@
             need_degree_count->setText(QString::number(dwarves.size()));
             need_degree_count->setToolTip(desc);
             need_degree_count->setData((int)dwarves.size(), SortRole);
-            need_degree_count->setData(color, Qt::TextColorRole);
+            need_degree_count->setData(color, Qt::ForegroundRole);
             need_degree_count->setFlags(flags);
 
             need_name->appendRow({need_degree_name, need_degree_count});
diff --git a/src/notificationwidget.cpp b/src/notificationwidget.cpp
--- a/src/notificationwidget.cpp	2026-04-22 13:27:36.655437879 +0200
+++ b/src/notificationwidget.cpp	2026-04-22 13:33:59.610236366 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "notificationwidget.h"
+#include <QEnterEvent>
 #include "ui_notification.h"
 
 #include <QDesktopServices>
@@ -113,7 +114,7 @@
     }
 }
 
-void NotificationWidget::enterEvent(QEvent *evt){
+void NotificationWidget::enterEvent(QEnterEvent *evt){
     QFrame::enterEvent(evt);
     m_mouse_hover = true;
     if(m_fader){
diff --git a/src/notificationwidget.h b/src/notificationwidget.h
--- a/src/notificationwidget.h	2026-04-22 13:27:36.655402937 +0200
+++ b/src/notificationwidget.h	2026-04-22 13:33:59.605908918 +0200
@@ -45,7 +45,7 @@
     QPropertyAnimation *m_fader;
     bool m_mouse_hover;
 
-    void enterEvent(QEvent *);
+    void enterEvent(QEnterEvent *);
     void leaveEvent(QEvent *);
 
 private slots:
diff --git a/src/notifierwidget.cpp b/src/notifierwidget.cpp
--- a/src/notifierwidget.cpp	2026-04-22 13:27:36.655346090 +0200
+++ b/src/notifierwidget.cpp	2026-04-22 13:27:36.666854548 +0200
@@ -37,7 +37,7 @@
 
     setAttribute(Qt::WA_ShowWithoutActivating);
     setAttribute(Qt::WA_TranslucentBackground);
-    setWindowFlags(Qt::Window | //necessary to show window?
+    setWindowFlags(Qt::WindowFlags(Qt::Window) | //necessary to show window?
                    Qt::WindowDoesNotAcceptFocus | //no focus
                    Qt::FramelessWindowHint); //no border
     this->setVisible(false);
diff --git a/src/optimizereditor.cpp b/src/optimizereditor.cpp
--- a/src/optimizereditor.cpp	2026-04-22 13:27:36.655192447 +0200
+++ b/src/optimizereditor.cpp	2026-04-22 13:29:28.320194375 +0200
@@ -78,7 +78,7 @@
     QSplitterHandle *h = ui->splitter->handle(1);
     QVBoxLayout *layout = new QVBoxLayout(h);
     layout->setSpacing(0);
-    layout->setMargin(0);
+    layout->setContentsMargins(0,0,0,0);
     QFrame *line = new QFrame(h);
     line->setFrameShape(QFrame::HLine);
     line->setFrameShadow(QFrame::Sunken);
diff --git a/src/preferenceswidget.cpp b/src/preferenceswidget.cpp
--- a/src/preferenceswidget.cpp	2026-04-22 13:27:36.654022869 +0200
+++ b/src/preferenceswidget.cpp	2026-04-22 13:27:36.668712373 +0200
@@ -21,6 +21,7 @@
 THE SOFTWARE.
 */
 #include "preferenceswidget.h"
+#include <QRegularExpression>
 #include "dwarftherapist.h"
 #include "dfinstance.h"
 #include "standardpaths.h"
@@ -108,7 +109,7 @@
 
         tw_prefs->setSortingEnabled(false);
         QPair<QString,QString> key_pair;
-        foreach(key_pair, prefs.uniqueKeys()){
+        foreach(key_pair, prefs.keys()){
                 DFInstance::pref_stat *pref = prefs.value(key_pair);
                 tw_prefs->insertRow(0);
                 tw_prefs->setRowHeight(0, 18);
@@ -165,13 +166,13 @@
 
 void PreferencesWidget::search_changed(QString val){
     val = "(" + val.replace(" ", "|") + ")";
-    m_filter = QRegExp(val,Qt::CaseInsensitive, QRegExp::RegExp);
+    m_filter = QRegularExpression(val, QRegularExpression::CaseInsensitiveOption);
     filter();
 }
 
 void PreferencesWidget::filter(){
     for(int i = 0; i < tw_prefs->rowCount(); i++){
-        if(m_filter.isEmpty() || tw_prefs->item(i,0)->text().contains(m_filter) || tw_prefs->item(i,3)->text().contains(m_filter)){
+        if(m_filter.pattern().isEmpty() || tw_prefs->item(i,0)->text().contains(m_filter) || tw_prefs->item(i,3)->text().contains(m_filter)){
             tw_prefs->setRowHidden(i,false);
         }else{
             tw_prefs->setRowHidden(i,true);
diff --git a/src/preferenceswidget.h b/src/preferenceswidget.h
--- a/src/preferenceswidget.h	2026-04-22 13:27:36.653989451 +0200
+++ b/src/preferenceswidget.h	2026-04-22 13:27:36.668986339 +0200
@@ -25,7 +25,7 @@
 
 #include <QWidget>
 
-#include <QRegExp>
+#include <QRegularExpression>
 
 class QTableWidget;
 class QSettings;
@@ -40,7 +40,7 @@
 
 protected:
     QTableWidget *tw_prefs;
-    QRegExp m_filter;
+    QRegularExpression m_filter;
 
 public slots:
     //void cell_clicked(int r,int c);
diff --git a/src/role.cpp b/src/role.cpp
--- a/src/role.cpp	2026-04-22 13:27:36.653678807 +0200
+++ b/src/role.cpp	2026-04-22 13:27:36.664517821 +0200
@@ -305,7 +305,7 @@
                 details.insert(key,vals);
             }else{
                 detail.append(w_str);
-                details.insertMulti(key,QStringList(detail));
+                details.insert(key,QStringList(detail));
             }
         }
 
@@ -313,7 +313,7 @@
 
         QString aspect_list;
         if(group_lines){
-            foreach(float key, details.uniqueKeys()){
+            foreach(float key, details.keys()){
                 QStringList d = details.value(key);
                 d.sort();
                 //first value is the weight string, place it at the end
diff --git a/src/rotatedheader.cpp b/src/rotatedheader.cpp
--- a/src/rotatedheader.cpp	2026-04-22 13:27:36.652702999 +0200
+++ b/src/rotatedheader.cpp	2026-04-22 13:27:36.664992147 +0200
@@ -70,7 +70,7 @@
 
 
 void RotatedHeader::paintSection(QPainter *p, const QRect &rect, int idx) const {
-    QColor bg = model()->headerData(idx, Qt::Horizontal,Qt::BackgroundColorRole).value<QColor>();
+    QColor bg = model()->headerData(idx, Qt::Horizontal,Qt::BackgroundRole).value<QColor>();
 
     QBrush grad_brush = QBrush(bg);
     if (m_shade_column_headers) {
@@ -164,7 +164,7 @@
 
 void RotatedHeader::set_header_height(QString max_title){
     QFontMetrics fm(m_font);
-    m_preferred_height = fm.width(max_title)+15;
+    m_preferred_height = fm.horizontalAdvance(max_title)+15;
     if(m_preferred_height <= 0)
         m_preferred_height = 150;
 }
diff --git a/src/scriptdialog.cpp b/src/scriptdialog.cpp
--- a/src/scriptdialog.cpp	2026-04-22 13:27:36.652313263 +0200
+++ b/src/scriptdialog.cpp	2026-04-22 13:27:36.667839975 +0200
@@ -402,7 +402,7 @@
     for(int i=0; i < NUM_OF_ITEM_TYPES; i++){
         item_types.insert(Item::get_item_name_plural(static_cast<ITEM_TYPE>(i)),i);
     }
-    foreach(QString name, item_types.uniqueKeys()){
+    foreach(QString name, item_types.keys()){
         item_list.append(row_html.arg(QString::number(item_types.value(name))).arg(name));
     }
     item_list.append("</table>");
diff --git a/src/searchfiltertreeview.cpp b/src/searchfiltertreeview.cpp
--- a/src/searchfiltertreeview.cpp	2026-04-22 13:27:36.652112454 +0200
+++ b/src/searchfiltertreeview.cpp	2026-04-22 13:27:36.668852163 +0200
@@ -21,6 +21,7 @@
 THE SOFTWARE.
 */
 #include "searchfiltertreeview.h"
+#include <QRegularExpression>
 #include "ui_searchfiltertreeview.h"
 
 SearchFilterTreeView::SearchFilterTreeView(QWidget *parent)
@@ -125,14 +126,14 @@
 void SearchFilterTreeView::search_text(const QString &text)
 {
     QString val = text;
-    QRegExp filter("(" + val.replace(" ", "|") + ")", Qt::CaseInsensitive);
-    m_filter_proxy.setFilterRegExp(filter);
+    QRegularExpression filter("(" + val.replace(" ", "|") + ")", QRegularExpression::CaseInsensitiveOption);
+    m_filter_proxy.setFilterRegularExpression(filter);
     m_filter_proxy.setFilterKeyColumn(0);
 }
 
 void SearchFilterTreeView::clear_search()
 {
     ui->search_edit->setText("");
-    m_filter_proxy.setFilterRegExp(QRegExp());
+    m_filter_proxy.setFilterRegularExpression(QRegularExpression());
     ui->tree_view->collapseAll();
 }
diff --git a/src/skillcolumn.cpp b/src/skillcolumn.cpp
--- a/src/skillcolumn.cpp	2026-04-22 13:27:36.651894246 +0200
+++ b/src/skillcolumn.cpp	2026-04-22 13:27:36.667949360 +0200
@@ -82,7 +82,7 @@
 }
 
 void SkillColumn::refresh_sort(COLUMN_SORT_TYPE sType){
-    foreach(Dwarf *d, m_cells.uniqueKeys()){
+    foreach(Dwarf *d, m_cells.keys()){
         refresh_sort(d, sType);
     }
 }
diff --git a/src/spacercolumn.cpp b/src/spacercolumn.cpp
--- a/src/spacercolumn.cpp	2026-04-22 13:27:36.651660738 +0200
+++ b/src/spacercolumn.cpp	2026-04-22 13:27:36.666404833 +0200
@@ -54,7 +54,7 @@
     item->setData(d->nice_name(),DwarfModel::DR_GLOBAL); //default
     if(m_width <= 0){
         item->setData(QColor(Qt::transparent), DwarfModel::DR_DEFAULT_BG_COLOR);
-        item->setData(QColor(Qt::transparent),Qt::BackgroundColorRole);
+        item->setData(QColor(Qt::transparent),Qt::BackgroundRole);
     }
     return item;
 }
diff --git a/src/squad.cpp b/src/squad.cpp
--- a/src/squad.cpp	2026-04-22 13:27:36.651572551 +0200
+++ b/src/squad.cpp	2026-04-22 13:47:03.586248953 +0200
@@ -294,7 +294,7 @@
 int Squad::find_position(int hist_id){
     int position = -1;
     //find an open position
-    foreach(int idx, m_members.uniqueKeys()){
+    foreach(int idx, m_members.keys()){
         if(m_members.value(idx) == hist_id){
             position = idx;
             break;
@@ -347,7 +347,7 @@
     if(job_id != DwarfJob::JOB_UNKNOWN){
         desc = GameDataReader::ptr()->get_job(short(job_id))->name();
     }
-    return qMakePair<int,QString>(job_id,desc);
+    return qMakePair(job_id,desc);
 }
 
 bool Squad::on_duty(int histfig_id){
diff --git a/src/statetableview.cpp b/src/statetableview.cpp
--- a/src/statetableview.cpp	2026-04-22 13:27:36.651272508 +0200
+++ b/src/statetableview.cpp	2026-04-22 13:39:09.700533435 +0200
@@ -978,7 +978,7 @@
     if(col){
         int rank = 0;
         QModelIndex idx;
-        foreach(Dwarf *d, col->cells().uniqueKeys()){
+        foreach(Dwarf *d, col->cells().keys()){
             idx = col->cells().value(d)->index(); //get the index in the model
             idx = m_proxy->mapFromSource(idx); //get the index in the proxy
             rank = idx.row(); //row in the sorted view
@@ -1104,8 +1104,8 @@
 void StateTableView::wheelEvent(QWheelEvent *event){
     if(event->modifiers() & Qt::ControlModifier || event->modifiers() & Qt::AltModifier){
         QWheelEvent *evt_h = new QWheelEvent(
-                event->posF(), event->globalPosF(), event->pixelDelta(), event->angleDelta(),
-                event->delta(), Qt::Horizontal, event->buttons(), event->modifiers());
+                event->position(), event->globalPosition(), event->pixelDelta(), event->angleDelta(),
+                event->buttons(), event->modifiers(), event->phase(), event->inverted());
         QTreeView::wheelEvent(evt_h);
     }else{
         QTreeView::wheelEvent(event);
diff --git a/src/superlaborcolumn.cpp b/src/superlaborcolumn.cpp
--- a/src/superlaborcolumn.cpp	2026-04-22 13:27:36.650972390 +0200
+++ b/src/superlaborcolumn.cpp	2026-04-22 13:27:36.668241255 +0200
@@ -99,7 +99,7 @@
 
     QStringList modified_desc;
     QHash<int,QString> labors = ml->get_labor_desc();
-    foreach(int id, labors.uniqueKeys()){
+    foreach(int id, labors.keys()){
         if(d->labor_enabled(id))
             modified_desc.append(QString("<font color=%1>%2</font>").arg(ml->active_labor_color().name()).arg(labors.value(id)));
         else
diff --git a/src/syndrome.cpp b/src/syndrome.cpp
--- a/src/syndrome.cpp	2026-04-22 13:27:36.650888387 +0200
+++ b/src/syndrome.cpp	2026-04-22 13:27:36.668891519 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "syndrome.h"
+#include <QRegularExpression>
 #include "dfinstance.h"
 #include "memorylayout.h"
 #include "gamedatareader.h"
@@ -53,7 +54,7 @@
     if(syn_addr){
         m_name = capitalizeEach(m_df->read_string(syn_addr));
         //SYN_CLASS tokens
-        QRegExp rx = QRegExp("[-_\\*~@#\\^]");
+        QRegularExpression rx("[-_\\*~@#\\^]");
         QVector<VIRTADDR> classes_addr = m_df->enumerate_vector(m_mem->syndrome_field(syn_addr, "syn_classes_vector"));
         foreach(VIRTADDR class_addr, classes_addr){
             QString class_name = m_df->read_string(class_addr);
diff --git a/src/thoughtswidget.cpp b/src/thoughtswidget.cpp
--- a/src/thoughtswidget.cpp	2026-04-22 13:27:36.650731213 +0200
+++ b/src/thoughtswidget.cpp	2026-04-22 13:27:36.664881006 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "thoughtswidget.h"
+#include <QRegularExpression>
 #include "dwarftherapist.h"
 #include "gamedatareader.h"
 #include "dfinstance.h"
@@ -43,7 +44,7 @@
 void ThoughtsWidget::build_tree(){
     QHash<int, EmotionGroup*> emotions = DT->get_DFInstance()->get_emotion_stats();
     QString tooltip;
-    foreach(int id, emotions.uniqueKeys()){
+    foreach(int id, emotions.keys()){
         Thought *t = GameDataReader::ptr()->get_thought(id);
         EmotionGroup *eg = emotions.value(id);
 
@@ -79,7 +80,7 @@
 
         //add parent node
         AdaptiveColorFactory adaptive;
-        foreach(EMOTION_TYPE e_type, eg->get_details().uniqueKeys()){
+        foreach(EMOTION_TYPE e_type, eg->get_details().keys()){
             Emotion *e = GameDataReader::ptr()->get_emotion(e_type);
             if(e){
                 EmotionGroup::emotion_count ec = eg->get_details().value(e_type);
@@ -97,7 +98,7 @@
                         .arg(unit_names.join(unit_names.size() < 20 ? "<br/>" : ", "));
 
                 emotion_node->setData(0, Qt::UserRole, e_type);
-                emotion_node->setData(0,Qt::TextColorRole, adaptive.color(e->get_color()));
+                emotion_node->setData(0,Qt::ForegroundRole, adaptive.color(e->get_color()));
                 emotion_node->setToolTip(0, tooltip);
                 emotion_node->setText(0, emotion_desc);
 
@@ -130,7 +131,7 @@
 
 void ThoughtsWidget::search_tree(QString val){
     val = "(" + val.replace(" ", "|") + ")";
-    QRegExp filter = QRegExp(val,Qt::CaseInsensitive, QRegExp::RegExp);
+    QRegularExpression filter(val, QRegularExpression::CaseInsensitiveOption);
     int hidden;
     bool parent_matches;
     for(int i = 0; i < m_tree_view->topLevelItemCount(); i++){
@@ -198,7 +199,7 @@
 }
 
 QString ThoughtsItemDelegate::appendText(QPainter *painter, const QStyleOptionViewItem &option, QColor text_color, QString curr_text, QString text) const {
-    int text_width = painter->fontMetrics().width(curr_text);
+    int text_width = painter->fontMetrics().horizontalAdvance(curr_text);
     QRect r_display = option.rect.adjusted(text_width,0,0,0);
     painter->setPen(text_color);
     painter->drawText(r_display,Qt::AlignLeft | Qt::AlignVCenter,text);
@@ -206,7 +207,7 @@
 }
 
 QString ThoughtsItemDelegate::prependText(QPainter *painter, const QStyleOptionViewItem &option, QColor text_color, QString curr_text, QString text) const {
-    int text_width = -painter->fontMetrics().width(curr_text);
+    int text_width = -painter->fontMetrics().horizontalAdvance(curr_text);
     QRect r_display = option.rect.adjusted(0,0,text_width,0);
     painter->setPen(text_color);
     painter->drawText(r_display,Qt::AlignRight | Qt::AlignVCenter,text);
diff --git a/src/trait.cpp b/src/trait.cpp
--- a/src/trait.cpp	2026-04-22 13:27:36.650559867 +0200
+++ b/src/trait.cpp	2026-04-22 13:27:36.668285544 +0200
@@ -116,7 +116,7 @@
         return "";
     QStringList items;
     QString msg;
-    foreach(int skill_id, m_skill_conflicts.uniqueKeys()){
+    foreach(int skill_id, m_skill_conflicts.keys()){
         msg = skill_conflict_msg(skill_id,val);
         if(!msg.isEmpty())
             items.append(msg);
diff --git a/src/uberdelegate.cpp b/src/uberdelegate.cpp
--- a/src/uberdelegate.cpp	2026-04-22 13:27:36.650176234 +0200
+++ b/src/uberdelegate.cpp	2026-04-22 13:27:36.666630635 +0200
@@ -211,7 +211,7 @@
         break;
     case CT_ITEMTYPE:
     {
-        QColor bg = paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        QColor bg = paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundRole).value<QColor>());
         //if we're drawing numbers, we only want to draw counts for squads
         //this is a special case because we're drawing different information if it's text mode
         if(m_skill_drawing_method == SDM_NUMERIC && rating == 100)
@@ -326,19 +326,19 @@
         break;
     case CT_IDLE:
     {
-        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundRole).value<QColor>());
         paint_icon(adjusted,p,opt,idx);
     }
         break;
     case CT_PROFESSION:
     {
-        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundRole).value<QColor>());
         paint_icon(adjusted,p,opt,idx);
     }
         break;
     case CT_HIGHEST_MOOD:
     {
-        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        paint_bg(adjusted, p, opt, idx, true, model_idx.data(Qt::BackgroundRole).value<QColor>());
         paint_icon(adjusted,p,opt,idx);
 
         bool had_mood = idx.data(DwarfModel::DR_SPECIAL_FLAG).toBool();
@@ -401,7 +401,7 @@
         break;
     case CT_TRAINED:
     {
-        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundRole).value<QColor>());
         //arbitrary ignore range is used just to hide tame animals
         paint_values(adjusted, rating, text_rating, bg, p, opt, idx, 50.0f, 1.0f, 95.0f, 49.9f, 50.1f, true);
         paint_grid(adjusted, false, p, opt, idx);
@@ -409,14 +409,14 @@
         break;
     case CT_KILLS:
     {
-        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundRole).value<QColor>());
         paint_values(adjusted, rating, text_rating, bg, p, opt, idx, 50.0f, 1.0f, 95.0f, 49.9f, 50.1f, true);
         paint_grid(adjusted, false, p, opt, idx);
     }
         break;
     case CT_PREFERENCE:
     {
-        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundRole).value<QColor>());
         if (rating > 0)
             paint_values(adjusted, rating, text_rating, bg, p, opt, idx, 0.0f, 0.0f, 100.0f, 0.0f, 0.0f, true);
         paint_grid(adjusted, false, p, opt, idx);
@@ -424,13 +424,13 @@
         break;
     case CT_HEALTH:
     {
-        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundColorRole).value<QColor>());
+        QColor bg = paint_bg(adjusted, p, opt, idx, false, model_idx.data(Qt::BackgroundRole).value<QColor>());
 
         //draw the symbol text in bold
         p->save();
         if (rating != 0) {
             if(color_health_cells){
-                p->setPen(model_idx.data(Qt::TextColorRole).value<QColor>());
+                p->setPen(model_idx.data(Qt::ForegroundRole).value<QColor>());
             }else{
                 if(auto_contrast){
                     p->setPen(complement(bg));
diff --git a/src/uniform.cpp b/src/uniform.cpp
--- a/src/uniform.cpp	2026-04-22 13:27:36.650086600 +0200
+++ b/src/uniform.cpp	2026-04-22 13:27:36.668331192 +0200
@@ -104,7 +104,7 @@
 
 int Uniform::get_remaining_required(ITEM_TYPE itype){
     int count = 0;
-    foreach(ITEM_TYPE key, m_uniform_items.uniqueKeys()){
+    foreach(ITEM_TYPE key, m_uniform_items.keys()){
         QList<ItemDefUniform*> items = m_uniform_items.value(key);
         foreach(ItemDefUniform *u, items){
             if(u->get_stack_size() > 0 && (u->item_type() == itype || Item::type_in_group(itype,u->item_type())))
@@ -131,7 +131,7 @@
     m_missing_counts.insert(RANGED_EQUIPMENT,0);
     m_missing_counts.insert(SUPPLIES,0);
 
-    foreach(ITEM_TYPE itype, m_missing_items.uniqueKeys()){
+    foreach(ITEM_TYPE itype, m_missing_items.keys()){
         foreach(ItemDefUniform *item_miss, m_missing_items.value(itype)){
             int missing_count = m_missing_counts.value(itype,0);
             int item_qty = item_miss->get_stack_size();
@@ -162,7 +162,7 @@
     if(itype != NONE){
         required = (float)m_equip_counts.value(itype);
     }else{
-        foreach(ITEM_TYPE i,m_equip_counts.uniqueKeys()){
+        foreach(ITEM_TYPE i,m_equip_counts.keys()){
             if(i < NUM_OF_ITEM_TYPES)
                 required += m_equip_counts.value(i,0);
         }
diff --git a/src/unitemotion.cpp b/src/unitemotion.cpp
--- a/src/unitemotion.cpp	2026-04-22 13:27:36.649962481 +0200
+++ b/src/unitemotion.cpp	2026-04-22 13:39:09.676675950 +0200
@@ -29,7 +29,7 @@
 #include "subthoughttypes.h"
 #include "emotion.h"
 
-#include <QRegExp>
+#include <QRegularExpression>
 
 UnitEmotion::UnitEmotion(QObject *parent)
     : QObject(parent)
@@ -88,16 +88,16 @@
                 QString s_thought = s_types->get_subthought(id);
                 if(s_types->has_placeholder()){
                     m_desc.replace(s_types->get_placeholder(),s_thought);
-                    m_compare_id = id;
+                    m_compare_id = QString::number(id);
                 }else{
                     m_desc.append(s_thought);
                 }
             }else{
-                QRegExp re(".*(\\[.*\\]).*");
-                int idx = re.indexIn(m_desc);
-                if(idx > -1){
-                    m_compare_id = m_sub_id; //don't consider thoughts with skills, syndromes, poems, etc. the same
-                    QString key = re.cap(1);
+                QRegularExpression re(".*(\\[.*\\]).*");
+                QRegularExpressionMatch m = re.match(m_desc);
+                if(m.hasMatch()){
+                    m_compare_id = QString::number(m_sub_id); //don't consider thoughts with skills, syndromes, poems, etc. the same
+                    QString key = m.captured(1);
                     QString replace = "";
                     if(key=="[skill]"){
                         replace = gdr->get_skill_name(m_sub_id,(m_thought_id == 11));
diff --git a/src/unithealth.cpp b/src/unithealth.cpp
--- a/src/unithealth.cpp	2026-04-22 13:27:36.649832190 +0200
+++ b/src/unithealth.cpp	2026-04-22 13:47:03.585979559 +0200
@@ -479,7 +479,7 @@
     foreach(UnitWound w, m_wounds){
         //wound details by body part
         QHash<QString,QList<HealthInfo*> > wounds_info = w.get_wound_details();
-        foreach(QString bp_name, wounds_info.uniqueKeys()){
+        foreach(QString bp_name, wounds_info.keys()){
             QList<HealthInfo*> wnd_details = wounds_info.take(bp_name);
 
             //keep a list of body parts and their related health info stuff
@@ -554,7 +554,7 @@
     int key = ((int)colored << 1) | (int)symbols;
     if(m_wound_summary.value(key).isEmpty()){
         QMap<QString, QStringList> summary = m_wound_summary.value(key);
-        foreach(QString bp, m_wound_details.uniqueKeys()){
+        foreach(QString bp, m_wound_details.keys()){
             QList<HealthInfo*> infos = m_wound_details.value(bp);
             QStringList bp_summary = summary.value(bp);
             foreach(HealthInfo* hi, infos){
@@ -577,7 +577,7 @@
     int key = ((int)colored << 1) | (int)symbols;
     if(m_treatment_summary.value(key).isEmpty()){
         QStringList summary = m_treatment_summary.value(key);
-        foreach(eHealth::H_INFO h, m_treatment_info.uniqueKeys()){
+        foreach(eHealth::H_INFO h, m_treatment_info.keys()){
             foreach(HealthInfo* hi, m_treatment_info.value(h)){
                 summary.append(hi->formatted_value(colored,symbols));
             }
@@ -592,7 +592,7 @@
     int key = ((int)colored << 1) | (int)symbols;
     if(m_status_summary.value(key).isEmpty()){
         QStringList summary = m_status_summary.value(key);
-        foreach(eHealth::H_INFO h, m_status_info.uniqueKeys()){
+        foreach(eHealth::H_INFO h, m_status_info.keys()){
             if(m_status_info.value(h).count() > 0){
                 if(get_health_description(h)->allows_multiple()){ //m_display_descriptions.value(h).at(0)->can_have_multiple()){
                     foreach(HealthInfo *hi,m_status_info.value(h)){
@@ -630,9 +630,9 @@
 
         std::sort(cat_names.begin(), cat_names.end());
         foreach(QString name, cat_names) {
-            foreach(eHealth::H_INFO id, m_health_descriptions.uniqueKeys()) {
+            foreach(eHealth::H_INFO id, m_health_descriptions.keys()) {
                 if (m_health_descriptions.value(id)->name() == name) {
-                    m_ordered_category_names << qMakePair<eHealth::H_INFO, QString>(id, name);
+                    m_ordered_category_names << qMakePair(id, name);
                     break;
                 }
             }
diff --git a/src/unitwound.cpp b/src/unitwound.cpp
--- a/src/unitwound.cpp	2026-04-22 13:27:36.649598668 +0200
+++ b/src/unitwound.cpp	2026-04-22 13:27:36.668495644 +0200
@@ -369,7 +369,7 @@
     if(m_bp_info.size() <= 0 && m_wounded_parts.size() > 0){
         foreach(wounded_part_details wpd, m_wounded_parts){
             QList<HealthInfo*> body_infos = m_bp_info.take(wpd.body_part_name);
-            foreach(eHealth::H_INFO hs, wpd.wnd_info.uniqueKeys()){
+            foreach(eHealth::H_INFO hs, wpd.wnd_info.keys()){
                 QList<short> desc_indexes = wpd.wnd_info.value(hs);
                 bool visible = wpd.visible;
                 m_unitHealth->add_info(hs, desc_indexes,visible); //add to the top level statuses, treatments and wounds
diff --git a/src/updater.cpp b/src/updater.cpp
--- a/src/updater.cpp	2026-04-22 13:27:36.649522623 +0200
+++ b/src/updater.cpp	2026-04-22 13:43:43.215646080 +0200
@@ -46,18 +46,12 @@
 
 void Updater::check_for_updates()
 {
-    if (!m_network.networkAccessible()) {
-        notify({tr("Network Inaccessible"),
-                tr("Could not check for updates due to network inaccessibility"),
-                {}, {}, true});
-        return;
-    }
     auto settings = StandardPaths::settings();
     auto reply = m_network.get(QNetworkRequest(QString("https://api.github.com/repos/%1/%2/releases/latest")
                     .arg(settings->value("update_repo_owner", REPO_OWNER).toString())
                     .arg(settings->value("update_repo_name", REPO_NAME).toString())));
     LOGD << "Query latest release version from" << reply->request().url();
-    connect(reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error),
+    connect(reply, &QNetworkReply::errorOccurred,
             this, &Updater::network_error);
     connect(reply, &QNetworkReply::sslErrors,
             this, &Updater::ssl_errors);
@@ -131,7 +125,7 @@
                     .arg(settings->value("update_repo_name", REPO_NAME).toString())
                     .arg(LAYOUT_SUBDIR)));
     LOGD << "Querying memory layouts from repository" << reply->request().url();
-    connect(reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error),
+    connect(reply, &QNetworkReply::errorOccurred,
             this, &Updater::network_error);
     connect(reply, &QNetworkReply::sslErrors,
             this, &Updater::ssl_errors);
@@ -157,7 +151,7 @@
         QString git_sha = file.value("sha").toString();
         auto reply = m_network.get(QNetworkRequest(url));
         LOGD << "Downloading memory layout from repository" << reply->request().url();
-        connect(reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error),
+        connect(reply, &QNetworkReply::errorOccurred,
                 this, &Updater::network_error);
         connect(reply, &QNetworkReply::sslErrors,
                 this, &Updater::ssl_errors);
diff --git a/src/viewcolumn.cpp b/src/viewcolumn.cpp
--- a/src/viewcolumn.cpp	2026-04-22 13:27:36.649414361 +0200
+++ b/src/viewcolumn.cpp	2026-04-22 13:27:36.666579526 +0200
@@ -112,8 +112,8 @@
     } else {
         bg = set()->bg_color();
     }
-    item->setData(complement(bg),Qt::TextColorRole);
-    item->setData(bg, Qt::BackgroundColorRole);
+    item->setData(complement(bg),Qt::ForegroundRole);
+    item->setData(bg, Qt::BackgroundRole);
 
     item->setData(bg, DwarfModel::DR_DEFAULT_BG_COLOR);
     item->setData(false, DwarfModel::DR_IS_AGGREGATE);
@@ -134,7 +134,7 @@
         bg = m_bg_color;
     else
         bg = m_set->bg_color();
-    item->setData(bg, Qt::BackgroundColorRole);
+    item->setData(bg, Qt::BackgroundRole);
     item->setData(bg, DwarfModel::DR_DEFAULT_BG_COLOR);
 
     item->setData(group_name, DwarfModel::DR_GROUP_NAME);
diff --git a/src/viewcolumnset.cpp b/src/viewcolumnset.cpp
--- a/src/viewcolumnset.cpp	2026-04-22 13:27:36.649271660 +0200
+++ b/src/viewcolumnset.cpp	2026-04-22 13:27:36.668938133 +0200
@@ -22,6 +22,7 @@
 */
 
 #include "viewcolumnset.h"
+#include <QRegularExpression>
 #include "columntypes.h"
 #include "laborcolumn.h"
 #include "happinesscolumn.h"
@@ -201,13 +202,13 @@
             QString title = col->title();
             if (title == vc->title()) {
                 // col is a dupe, see if it ends with a number
-                QRegExp regex("([a-zA-Z0-9\\[\\]. ]*)\\s*(\\d+)$");
+                QRegularExpression regex("([a-zA-Z0-9\\[\\]. ]*)\\s*(\\d+)$");
                 QString stripped_title = title; // title without an ending number
                 int num = 0;
-                int pos = regex.indexIn(title);
-                if (pos != -1) {
-                    stripped_title = regex.cap(1).trimmed();
-                    num = regex.cap(2).toInt();
+                QRegularExpressionMatch match = regex.match(title);
+                if (match.hasMatch()) {
+                    stripped_title = match.captured(1).trimmed();
+                    num = match.captured(2).toInt();
                 }
                 col->set_title(QString("%1 %2").arg(stripped_title).arg(num + 1));
                 name_ok = false;
diff --git a/src/viewmanager.cpp b/src/viewmanager.cpp
--- a/src/viewmanager.cpp	2026-04-22 13:27:36.648965186 +0200
+++ b/src/viewmanager.cpp	2026-04-22 13:27:36.668567442 +0200
@@ -212,7 +212,7 @@
         //            grouped_weapons.value(weapon_pair.second.skill)->append(weapon_pair.second);
         //    }
         //    GridView *gv = new GridView("Weapons",this);
-        //    foreach(QString key, grouped_weapons.uniqueKeys()){
+        //    foreach(QString key, grouped_weapons.keys()){
         //        ViewColumnSet *vcs = new ViewColumnSet(key, this);
 
         //        QVector<GameDataReader::weapon> *glist = grouped_weapons.value(key);
@@ -358,7 +358,7 @@
     write_tab_settings();
 
     //write the default sorting
-    foreach(COLUMN_TYPE cType, m_default_column_sort.uniqueKeys()){
+    foreach(COLUMN_TYPE cType, m_default_column_sort.keys()){
         s->setValue("options/grid/" + get_column_type(cType), ViewColumn::get_sort_type(m_default_column_sort.value(cType)));
     }
 }
@@ -731,7 +731,7 @@
     //on a read of the data, find all the columns that were sorted on, and rebuild the sort keys for each dwarf, for each sort group
     if(m_model->get_global_sort_info().count() > 0){
         QPair<QString,int> key_pair;
-        foreach(int group_id, m_model->get_global_sort_info().uniqueKeys()){
+        foreach(int group_id, m_model->get_global_sort_info().keys()){
             key_pair = m_model->get_global_sort_info().value(group_id);
             //sorting on the name column is handled by the model proxy and persists through reads
             if(key_pair.second <= 0)
diff --git a/src/viewmanager.h b/src/viewmanager.h
--- a/src/viewmanager.h	2026-04-22 13:27:36.648926776 +0200
+++ b/src/viewmanager.h	2026-04-22 13:27:36.666923079 +0200
@@ -39,11 +39,11 @@
 class QErrorMessage;
 class QItemSelection;
 class QSettings;
-class QStringList;
+#include <QStringList>
 class QToolButton;
 class QTreeWidgetItem;
 class QWidget;
-template <class T> class QVector;
+#include <QList>
 
 
 /*!
diff --git a/src/weaponcolumn.cpp b/src/weaponcolumn.cpp
--- a/src/weaponcolumn.cpp	2026-04-22 13:27:36.648879780 +0200
+++ b/src/weaponcolumn.cpp	2026-04-22 13:27:36.667056152 +0200
@@ -127,7 +127,7 @@
     QString tt_title = m_title;
     if(tt_title.indexOf(",")>0){
         //add a weapon list to the description
-        QStringList l = m_title.split(",",QString::SkipEmptyParts);
+        QStringList l = m_title.split(",",Qt::SkipEmptyParts);
         desc += "<br><br><b>Weapons:</b><ul>";
         for(int i = 0; i<l.length(); i++){
             desc.append(QString("<li>%1</li>").arg(l.at(i)));
