From 545147c1d79aa8442264913efe32c0711b00528b Mon Sep 17 00:00:00 2001
From: michaelrossherron <michaelrossherron@gmail.com>
Date: Thu, 16 Jan 2025 12:35:01 -0700
Subject: [PATCH 1/4] Added support for updating to different branches with
 autoupdater

---
 FEBioStudio/UpdateChecker.cpp  | 12 +++++++++++-
 FEBioStudio/UpdateChecker.h    |  3 ++-
 Updater/FEBioStudioUpdater.cpp |  8 +++++++-
 Updater/MainWindow.cpp         | 18 ++++++++++++++++--
 Updater/MainWindow.h           |  3 ++-
 Updater/mvUtil.cpp             | 17 ++++++++++++++++-
 6 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/FEBioStudio/UpdateChecker.cpp b/FEBioStudio/UpdateChecker.cpp
index 4694ea369..0dd2b94ad 100644
--- a/FEBioStudio/UpdateChecker.cpp
+++ b/FEBioStudio/UpdateChecker.cpp
@@ -38,6 +38,7 @@ SOFTWARE.*/
 #include <QDialogButtonBox>
 #include <QPushButton>
 #include <QCheckBox>
+#include <QUrlQuery>
 #include "UpdateChecker.h"
 #include "ServerSettings.h"
 #include "version.h"
@@ -84,11 +85,12 @@ void CUpdateWidget::connFinished(QNetworkReply *r)
 	}
 }
 
-void CUpdateWidget::checkForUpdate(bool dev, bool checkSDK, bool upCheck)
+void CUpdateWidget::checkForUpdate(bool dev, bool checkSDK, bool upCheck, QString branch)
 {
 	updaterUpdateCheck = upCheck;
 	devChannel = dev;
     m_askSDK = checkSDK;
+    m_branch = branch;
 
 	if(updaterUpdateCheck)
 	{
@@ -119,6 +121,14 @@ void CUpdateWidget::checkForAppUpdate()
 	myurl.setPort(ServerSettings::Port());
 	myurl.setPath(urlBase + ".xml");
 
+    if(!m_branch.isEmpty())
+    {
+        QUrlQuery query;
+        query.addQueryItem("branch", m_branch);
+
+        myurl.setQuery(query);
+    }
+
 	QNetworkRequest request;
 	request.setUrl(myurl);
 	request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::SameOriginRedirectPolicy);
diff --git a/FEBioStudio/UpdateChecker.h b/FEBioStudio/UpdateChecker.h
index 8713d2662..1a2c00822 100644
--- a/FEBioStudio/UpdateChecker.h
+++ b/FEBioStudio/UpdateChecker.h
@@ -93,7 +93,7 @@ class CUpdateWidget : public QWidget
 public:
     CUpdateWidget(QWidget* parent = nullptr);
 
-    void checkForUpdate(bool dev = false, bool checkSDK = false, bool updaterUpdateCheck = false);
+    void checkForUpdate(bool dev = false, bool checkSDK = false, bool updaterUpdateCheck = false, QString branch = "");
 
     QString getServerMessage();
 
@@ -144,6 +144,7 @@ private slots:
 
 	bool devChannel;
     bool devAlreadyParsed;
+    QString m_branch;
 	bool updaterUpdateCheck;
 	bool doingUpdaterUpdate;
 
diff --git a/Updater/FEBioStudioUpdater.cpp b/Updater/FEBioStudioUpdater.cpp
index 710b84e9a..2e49e41c1 100644
--- a/Updater/FEBioStudioUpdater.cpp
+++ b/Updater/FEBioStudioUpdater.cpp
@@ -61,6 +61,7 @@ int main(int argc, char* argv[])
 		// Check if --devChannel flag is present
 		bool devChannel = false;
 		bool updaterUpdateCheck = true;
+        QString branch = "";
 		for(int index = 1; index < argc; index++)
 		{
 			if(QString(argv[index]) == QString("--devChannel") || QString(argv[index]) == QString("-d"))
@@ -71,10 +72,15 @@ int main(int argc, char* argv[])
 			{
 				updaterUpdateCheck = false;
 			}
+            else if((QString(argv[index]) == QString("--branch") || QString(argv[index]) == QString("-b")) && index + 1 < argc)
+            {
+                devChannel = true;
+                branch = QString(argv[index + 1]);
+            }
 		}
 
 		// create the main window
-		CMainWindow wnd(devChannel, updaterUpdateCheck);
+		CMainWindow wnd(devChannel, updaterUpdateCheck, branch);
 		wnd.show();
 
 		return app.exec();
diff --git a/Updater/MainWindow.cpp b/Updater/MainWindow.cpp
index 5a90d77c9..46c61c7a5 100644
--- a/Updater/MainWindow.cpp
+++ b/Updater/MainWindow.cpp
@@ -16,6 +16,7 @@
 #include <QNetworkRequest>
 #include <QNetworkReply>
 #include <QSslError>
+#include <QUrlQuery>
 #include <QJsonDocument>
 #include <QJsonObject>
 #include <QJsonArray>
@@ -178,9 +179,9 @@ class Ui::CMainWindow
 };
 
 
-CMainWindow::CMainWindow(bool devChannel, bool updaterUpdateCheck) 
+CMainWindow::CMainWindow(bool devChannel, bool updaterUpdateCheck, QString& branch) 
 	: ui(new Ui::CMainWindow), restclient(new QNetworkAccessManager), m_devChannel(devChannel), 
-    m_updaterUpdateCheck(updaterUpdateCheck), m_downloadingSDK(false)
+    m_updaterUpdateCheck(updaterUpdateCheck), m_downloadingSDK(false), m_branch(branch)
 {
 	QString dir = QApplication::applicationDirPath();
 	bool correctDir = false;
@@ -284,6 +285,14 @@ void CMainWindow::getFile()
 
 	myurl.setPath(currentFile.baseURL + "/" + currentFile.name);
 
+    if(!m_branch.isEmpty())
+    {
+        QUrlQuery query;
+        query.addQueryItem("branch", m_branch);
+
+        myurl.setQuery(query);
+    }
+
 	QNetworkRequest request;
 	request.setUrl(myurl);
 	request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::SameOriginRedirectPolicy);
@@ -610,6 +619,11 @@ void CMainWindow::onFinish()
 		QStringList args;
 		args.push_back(QApplication::applicationDirPath() + FBSUPDATERBINARY);
 		if(m_devChannel) args.push_back("-d");
+        if(!m_branch.isEmpty())
+        {
+            args.push_back("-b");
+            args.push_back(m_branch);
+        }
 
 		for(auto file : ui->updateWidget->updateFiles)
 		{
diff --git a/Updater/MainWindow.h b/Updater/MainWindow.h
index 5ed326e4b..89ec7a8a7 100644
--- a/Updater/MainWindow.h
+++ b/Updater/MainWindow.h
@@ -31,7 +31,7 @@ class CMainWindow : public QWizard
 	Q_OBJECT
 
 public:
-	CMainWindow(bool devChannel, bool updaterUpdateCheck);
+	CMainWindow(bool devChannel, bool updaterUpdateCheck, QString& branch);
 
     void makePath(QString path);
     void addNewFile(const QString filename);
@@ -68,4 +68,5 @@ private slots:
 	bool m_devChannel;
 	bool m_updaterUpdateCheck;
     bool m_downloadingSDK;
+    QString m_branch;
 };
diff --git a/Updater/mvUtil.cpp b/Updater/mvUtil.cpp
index 20855d0e2..b26abd2df 100644
--- a/Updater/mvUtil.cpp
+++ b/Updater/mvUtil.cpp
@@ -1,6 +1,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <string.h>
+#include <string>
 #include <sys/stat.h>
 
 #ifdef WIN32
@@ -38,6 +39,7 @@ int main(int argc, char* argv[])
 
     int start = 2;
     bool dev = false;
+    std::string branch;
 
     if(strcmp(argv[2], "-d") == 0)
     {
@@ -45,6 +47,12 @@ int main(int argc, char* argv[])
         dev = true;
     }
 
+    if(argc > 4 && strcmp(argv[3], "-b") == 0)
+    {
+        start += 2;
+        branch = argv[4];
+    }
+
     if((argc - start) % 2 != 0) return -1;
 
 	for (int index = start; index < argc; index += 2)
@@ -78,7 +86,14 @@ int main(int argc, char* argv[])
 
     if(dev)
     {
-        sprintf(command, "\"%s\" --noUpdaterCheck --devChannel", argv[1]);
+        if(branch.empty())
+        {
+            sprintf(command, "\"%s\" --noUpdaterCheck --devChannel", argv[1]);
+        }
+        else
+        {
+            sprintf(command, "\"%s\" --noUpdaterCheck --devChannel --branch %s", argv[1], branch.c_str());
+        }
     }
     else
     {

From 60dab74d1a96b0a063751c170361232cc123e8d1 Mon Sep 17 00:00:00 2001
From: michaelrossherron <michaelrossherron@gmail.com>
Date: Thu, 16 Jan 2025 13:16:23 -0700
Subject: [PATCH 2/4] Fixed bug in updater code

---
 Updater/MainWindow.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Updater/MainWindow.cpp b/Updater/MainWindow.cpp
index 46c61c7a5..1129b5404 100644
--- a/Updater/MainWindow.cpp
+++ b/Updater/MainWindow.cpp
@@ -442,7 +442,7 @@ void CMainWindow::initializePage(int id)
 	switch(id)
 	{
 	case 1:
-		ui->updateWidget->checkForUpdate(m_devChannel, true, m_updaterUpdateCheck);
+		ui->updateWidget->checkForUpdate(m_devChannel, true, m_updaterUpdateCheck, m_branch);
 		break;
 	case 2:
 		deleteFiles();

From cb1652d2910bd52f791369d557ee6b487bde3456 Mon Sep 17 00:00:00 2001
From: SteveMaas1978 <steve.maas@utah.edu>
Date: Fri, 17 Jan 2025 13:11:18 -0700
Subject: [PATCH 3/4] Fixed issue with puring selections.

---
 GeomLib/GModel.cpp | 12 ++++++++++--
 GeomLib/GModel.h   |  1 +
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/GeomLib/GModel.cpp b/GeomLib/GModel.cpp
index a38675c04..0ab2bc50c 100644
--- a/GeomLib/GModel.cpp
+++ b/GeomLib/GModel.cpp
@@ -313,6 +313,14 @@ void GModel::ClearGroups()
 	imp->m_GNode.Clear();
 }
 
+void GModel::ClearUnusedGroups()
+{
+	clearVector<GPartList>(imp->m_GPart, [](GPartList* pg) { return (pg->GetReferenceCount() == 0); });
+	clearVector<GFaceList>(imp->m_GFace, [](GFaceList* pg) { return (pg->GetReferenceCount() == 0); });
+	clearVector<GEdgeList>(imp->m_GEdge, [](GEdgeList* pg) { return (pg->GetReferenceCount() == 0); });
+	clearVector<GNodeList>(imp->m_GNode, [](GNodeList* pg) { return (pg->GetReferenceCount() == 0); });
+}
+
 //-----------------------------------------------------------------------------
 void GModel::ClearDiscrete()
 {
@@ -1608,11 +1616,11 @@ void GModel::RemoveNamedSelections()
 	for (int i=0; i<(int)imp->m_Obj.Size(); ++i)
 	{
 		GObject& obj = *imp->m_Obj[i];
-		obj.ClearFEGroups();
+		obj.RemoveUnusedFEGroups();
 	}
 
 	// remove all geometry selections
-	ClearGroups();
+	ClearUnusedGroups();
 }
 
 void GModel::RemoveMeshData()
diff --git a/GeomLib/GModel.h b/GeomLib/GModel.h
index b79a31979..f4aec49b5 100644
--- a/GeomLib/GModel.h
+++ b/GeomLib/GModel.h
@@ -72,6 +72,7 @@ class GModel : public FSObject
 
 	//! clear groups
 	void ClearGroups();
+	void ClearUnusedGroups();
 
 	//! clear all discrete objects
 	void ClearDiscrete();

From d69ededf5237e9a3e55f55e8efae7b50cf1a5510 Mon Sep 17 00:00:00 2001
From: SteveMaas1978 <steve.maas@utah.edu>
Date: Sat, 18 Jan 2025 08:26:22 -0700
Subject: [PATCH 4/4] Default plot variables are reset when changing the
 physics module.

---
 FEMLib/FSProject.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/FEMLib/FSProject.cpp b/FEMLib/FSProject.cpp
index ad93d97c7..502a7c6ce 100644
--- a/FEMLib/FSProject.cpp
+++ b/FEMLib/FSProject.cpp
@@ -231,8 +231,9 @@ void FSProject::SetModule(int mod, bool setDefaultPlotVariables)
 		FSModel& fem = GetFSModel();
 		FEBio::InitFSModel(fem);
 
-		if (setDefaultPlotVariables && (m_plt.PlotVariables() == 0))
+		if (setDefaultPlotVariables)
 		{
+			m_plt.Clear();
 			// add some default variables
 			// TODO: Maybe I can pull this info from FEBio somehow
 			SetDefaultPlotVariables();