diff --git a/src/Mod/Start/App/CMakeLists.txt b/src/Mod/Start/App/CMakeLists.txt
index 992fad97de..ad27072f24 100644
--- a/src/Mod/Start/App/CMakeLists.txt
+++ b/src/Mod/Start/App/CMakeLists.txt
@@ -37,6 +37,8 @@ SET(Start_SRCS
DisplayedFilesModel.h
ExamplesModel.cpp
ExamplesModel.h
+ CustomFolderModel.cpp
+ CustomFolderModel.h
PreCompiled.cpp
PreCompiled.h
RecentFilesModel.cpp
diff --git a/src/Mod/Start/App/CustomFolderModel.cpp b/src/Mod/Start/App/CustomFolderModel.cpp
new file mode 100644
index 0000000000..bd7036e2e1
--- /dev/null
+++ b/src/Mod/Start/App/CustomFolderModel.cpp
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 The FreeCAD Project Association AISBL *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#endif
+
+#include "CustomFolderModel.h"
+#include
+
+using namespace Start;
+
+
+CustomFolderModel::CustomFolderModel(QObject* parent)
+ : DisplayedFilesModel(parent)
+{
+
+ Base::Reference parameterGroup = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Start");
+
+ _customFolderDirectory =
+ QDir(QString::fromStdString(parameterGroup->GetASCII("CustomFolder", "")));
+}
+
+void CustomFolderModel::loadCustomFolder()
+{
+ beginResetModel();
+ clear();
+ if (!_customFolderDirectory.isReadable()) {
+ Base::Console().Warning(
+ "BaseApp/Preferences/Mod/Start/CustomFolder: cannot read custom folder %s\n",
+ _customFolderDirectory.absolutePath().toStdString().c_str());
+ }
+ auto entries = _customFolderDirectory.entryList(QDir::Filter::Files | QDir::Filter::Readable,
+ QDir::SortFlag::Name);
+ for (const auto& entry : entries) {
+ addFile(_customFolderDirectory.filePath(entry));
+ }
+ endResetModel();
+}
diff --git a/src/Mod/Start/App/CustomFolderModel.h b/src/Mod/Start/App/CustomFolderModel.h
new file mode 100644
index 0000000000..d4c132708d
--- /dev/null
+++ b/src/Mod/Start/App/CustomFolderModel.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2024 The FreeCAD Project Association AISBL *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#ifndef FREECAD_START_CUSTOMFOLDERMODEL_H
+#define FREECAD_START_CUSTOMFOLDERMODEL_H
+
+#include
+#include
+#include
+
+#include "DisplayedFilesModel.h"
+#include "../StartGlobal.h"
+
+namespace Start
+{
+
+/// A model for displaying a list of files including a thumbnail or icon, plus various file
+/// statistics.
+class StartExport CustomFolderModel: public DisplayedFilesModel
+{
+ Q_OBJECT
+public:
+ explicit CustomFolderModel(QObject* parent = nullptr);
+
+ void loadCustomFolder();
+
+private:
+ QDir _customFolderDirectory;
+};
+
+} // namespace Start
+
+#endif // FREECAD_START_CUSTOMFOLDERMODEL_H
diff --git a/src/Mod/Start/Gui/StartView.cpp b/src/Mod/Start/Gui/StartView.cpp
index 0942ea80a2..e398c142ae 100644
--- a/src/Mod/Start/Gui/StartView.cpp
+++ b/src/Mod/Start/Gui/StartView.cpp
@@ -185,6 +185,7 @@ StartView::StartView(QWidget* parent)
, _newFileLabel {nullptr}
, _examplesLabel {nullptr}
, _recentFilesLabel {nullptr}
+ , _customFolderLabel {nullptr}
, _showOnStartupCheckBox {nullptr}
{
setObjectName(QLatin1String("StartView"));
@@ -193,6 +194,30 @@ StartView::StartView(QWidget* parent)
auto cardSpacing = hGrp->GetInt("FileCardSpacing", 15); // NOLINT
auto showExamples = hGrp->GetBool("ShowExamples", true); // NOLINT
+ // Migrate legacy property, can be removed in later releases
+ std::string legacyCustomFolder(hGrp->GetASCII("ShowCustomFolder", ""));
+ if (!legacyCustomFolder.empty()) {
+ hGrp->SetASCII("CustomFolder", legacyCustomFolder);
+ hGrp->RemoveASCII("ShowCustomFolder");
+ Base::Console().Message("v1.1: renamed ShowCustomFolder parameter to CustomFolder\n");
+ }
+ // End of migration code
+
+ // Verify that the folder specified in preferences is available before showing it
+ std::string customFolder(hGrp->GetASCII("CustomFolder", ""));
+ bool showCustomFolder = false;
+ if (!customFolder.empty()) {
+ auto customFolderDirectory = QDir(QString::fromStdString(customFolder));
+ if (customFolderDirectory.exists()) {
+ showCustomFolder = true;
+ }
+ else {
+ Base::Console().Warning(
+ "BaseApp/Preferences/Mod/Start/CustomFolder: '%s' does not exist\n",
+ customFolderDirectory.absolutePath().toStdString().c_str());
+ }
+ }
+
// First start page
auto firstStartScrollArea = gsl::owner(new QScrollArea());
auto firstStartScrollWidget = gsl::owner(new QWidget(firstStartScrollArea));
@@ -245,6 +270,15 @@ StartView::StartView(QWidget* parent)
connect(recentFilesListWidget, &QListView::clicked, this, &StartView::fileCardSelected);
documentsContentLayout->addWidget(recentFilesListWidget);
+ auto customFolderListWidget = gsl::owner(new FileCardView(_contents));
+ customFolderListWidget->setVisible(showCustomFolder);
+ _customFolderLabel = gsl::owner(new QLabel());
+ _customFolderLabel->setVisible(showCustomFolder);
+ documentsContentLayout->addWidget(_customFolderLabel);
+
+ connect(customFolderListWidget, &QListView::clicked, this, &StartView::fileCardSelected);
+ documentsContentLayout->addWidget(customFolderListWidget);
+
auto examplesListWidget = gsl::owner(new FileCardView(_contents));
examplesListWidget->setVisible(showExamples);
_examplesLabel = gsl::owner(new QLabel());
@@ -281,6 +315,7 @@ StartView::StartView(QWidget* parent)
// Set startup widget according to the first start parameter
auto firstStart = hGrp->GetBool("FirstStart2024", true); // NOLINT
_contents->setCurrentWidget(firstStart ? firstStartScrollArea : documentsWidget);
+ configureCustomFolderListWidget(customFolderListWidget);
configureExamplesListWidget(examplesListWidget);
configureRecentFilesListWidget(recentFilesListWidget, _recentFilesLabel);
@@ -370,6 +405,14 @@ void StartView::configureExamplesListWidget(QListView* examplesListWidget)
}
+void StartView::configureCustomFolderListWidget(QListView* customFolderListWidget)
+{
+ _customFolderModel.loadCustomFolder();
+ customFolderListWidget->setModel(&_customFolderModel);
+ configureFileCardWidget(customFolderListWidget);
+}
+
+
void StartView::newEmptyFile() const
{
Gui::Application::Instance->commandManager().runCommandByName("Std_New");
@@ -529,6 +572,7 @@ void StartView::retranslateUi()
_newFileLabel->setText(h1Start + tr("New File") + h1End);
_examplesLabel->setText(h1Start + tr("Examples") + h1End);
_recentFilesLabel->setText(h1Start + tr("Recent Files") + h1End);
+ _customFolderLabel->setText(h1Start + tr("Custom Folder") + h1End);
QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
_openFirstStart->setText(tr("Open first start setup"));
diff --git a/src/Mod/Start/Gui/StartView.h b/src/Mod/Start/Gui/StartView.h
index 04f89c23c7..3530a5435b 100644
--- a/src/Mod/Start/Gui/StartView.h
+++ b/src/Mod/Start/Gui/StartView.h
@@ -31,6 +31,7 @@
#include "../App/DisplayedFilesModel.h"
#include "../App/RecentFilesModel.h"
#include "../App/ExamplesModel.h"
+#include "../App/CustomFolderModel.h"
class QCheckBox;
class QEvent;
@@ -86,6 +87,7 @@ protected:
static void configureFileCardWidget(QListView* fileCardWidget);
void configureRecentFilesListWidget(QListView* recentFilesListWidget, QLabel* recentFilesLabel);
void configureExamplesListWidget(QListView* examplesListWidget);
+ void configureCustomFolderListWidget(QListView* customFolderListWidget);
void postStart(PostStartBehavior behavior) const;
@@ -101,9 +103,11 @@ private:
QStackedWidget* _contents = nullptr;
Start::RecentFilesModel _recentFilesModel;
Start::ExamplesModel _examplesModel;
+ Start::CustomFolderModel _customFolderModel;
QLabel* _newFileLabel;
QLabel* _examplesLabel;
QLabel* _recentFilesLabel;
+ QLabel* _customFolderLabel;
QPushButton* _openFirstStart;
QCheckBox* _showOnStartupCheckBox;