Skip to content

Commit 3821137

Browse files
committed
Add hybrid shared-data source composition
1 parent 172127e commit 3821137

19 files changed

Lines changed: 485 additions & 31 deletions

CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ qt_add_executable(BrickSuite
101101
src/services/storage/SessionStorageSelectionService.cpp
102102
src/services/application/ApplicationServices.h
103103
src/services/application/ApplicationServices.cpp
104+
src/services/application/ApplicationServicesCore.cpp
105+
src/services/application/UnavailableApplicationServices.cpp
106+
src/services/application/SharedDataSource.h
104107
src/services/database/AutomaticBackupRetention.h
105108
src/services/database/AutomaticBackupRetention.cpp
106109
src/services/Logger.h
@@ -958,9 +961,30 @@ if(BUILD_TESTING)
958961
src/models/InventoryRecord.h src/models/InventoryRecord.cpp
959962
src/models/CollectionItem.h src/models/CollectionItem.cpp
960963
src/services/application/ApplicationServices.h
964+
src/services/application/ApplicationServicesCore.cpp
965+
src/services/application/UnavailableApplicationServices.cpp
966+
src/services/application/SharedDataSource.h
967+
src/services/parts/PartReferenceManifest.h src/services/parts/PartReferenceManifest.cpp
968+
src/app/WorkspaceContext.h src/app/WorkspaceContext.cpp
961969
)
962970
target_link_libraries(ApplicationServiceContractsTest PRIVATE Qt6::Core)
963971
add_test(NAME ApplicationServiceContracts COMMAND ApplicationServiceContractsTest)
972+
973+
qt_add_executable(SharedDataSourceSettingsTest EXCLUDE_FROM_ALL
974+
tests/SharedDataSourceSettingsTest.cpp
975+
src/settings/UserSettings.h src/settings/UserSettings.cpp
976+
src/services/application/SharedDataSource.h
977+
src/services/CredentialStore.h src/services/CredentialStore.cpp
978+
src/services/database/AutomaticBackupPolicy.h
979+
src/services/database/AutomaticBackupPolicy.cpp
980+
)
981+
target_link_libraries(SharedDataSourceSettingsTest PRIVATE Qt6::Core Qt6::Sql)
982+
if(WIN32)
983+
target_link_libraries(SharedDataSourceSettingsTest PRIVATE Advapi32)
984+
elseif(APPLE)
985+
target_link_libraries(SharedDataSourceSettingsTest PRIVATE "-framework Security")
986+
endif()
987+
add_test(NAME SharedDataSourceSettings COMMAND SharedDataSourceSettingsTest)
964988
endif()
965989

966990
if(WIN32)

resources/help/settings.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ <h2>General</h2>
3636
automatically when the application starts. When only one Workspace exists, BrickSuite can select
3737
it automatically.</p>
3838

39+
<p><b>Shared Data Source</b> controls where workshop data is owned. <b>This Computer</b> uses this
40+
device for both local reference catalogs and Workspaces, Storage, Inventory, Builds, and Collection.
41+
<b>BrickSuite Host</b> continues using this device's Rebrickable catalogs, compositions, images, and
42+
built-in Part Reference while shared workshop data comes from a Host. Changing this setting takes
43+
effect after restarting BrickSuite; it never copies, merges, or deletes either source's data.</p>
44+
45+
<div class="note"><b>Development status:</b> Host connectivity is not configured in this phase.
46+
Selecting BrickSuite Host therefore leaves shared workshop views visibly unavailable after restart,
47+
while local catalog browsing and Rebrickable file imports remain available.</div>
48+
3949
<div class="note"><b>Changing the Default Workspace does not move or combine inventory.</b>
4050
It changes the Workspace selected by default; each Workspace continues to maintain its own data.</div>
4151

src/app/Application.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "../services/database/AutomaticBackupService.h"
2929
#include "../services/storage/SessionStorageSelectionService.h"
3030
#include "../services/application/ApplicationServices.h"
31+
#include "../settings/UserSettings.h"
3132
#include "../ui/MainWindow.h"
3233

3334
#include <QDebug>
@@ -80,7 +81,15 @@ bool Application::initialize(const StartupProgress& progress)
8081
phaseTimer.restart();
8182
m_workspaceContext = std::make_unique<WorkspaceContext>();
8283
m_sessionStorageSelectionService = std::make_unique<SessionStorageSelectionService>();
83-
m_applicationServices = std::make_unique<ApplicationServices>();
84+
const SharedDataSource sharedDataSource = UserSettings::instance().sharedDataSource();
85+
m_applicationServices = sharedDataSource == SharedDataSource::ThisComputer
86+
? std::make_unique<ApplicationServices>()
87+
: createUnavailableHostApplicationServices();
88+
qInfo().noquote() << "Shared data source:"
89+
<< (sharedDataSource == SharedDataSource::ThisComputer
90+
? "This Computer" : "BrickSuite Host");
91+
if (!m_applicationServices->sharedStatus().isAvailable())
92+
qWarning().noquote() << "BrickSuite Host shared services are unavailable until remote connectivity is configured.";
8493
qInfo() << "Startup phase application service creation completed in"
8594
<< phaseTimer.elapsed() << "ms.";
8695

src/services/application/ApplicationServices.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class LocalPartReferenceService final : public SharedPartReferenceCustomizationS
7777
int id) const override
7878
{ return PartReferenceCustomizationService(manifest).remove(id); }
7979
};
80+
8081
}
8182

8283
ApplicationServices::ApplicationServices()
@@ -85,17 +86,3 @@ ApplicationServices::ApplicationServices()
8586
std::make_unique<LocalBuildService>(),
8687
std::make_unique<LocalCollectionService>(),
8788
std::make_unique<LocalPartReferenceService>()) {}
88-
89-
ApplicationServices::ApplicationServices(std::unique_ptr<WorkspaceApplicationService> w,
90-
std::unique_ptr<InventoryApplicationService> i, std::unique_ptr<BuildApplicationService> b,
91-
std::unique_ptr<CollectionApplicationService> c,
92-
std::unique_ptr<SharedPartReferenceCustomizationService> p)
93-
: m_workspaces(std::move(w)), m_inventory(std::move(i)), m_builds(std::move(b)),
94-
m_collection(std::move(c)), m_partReference(std::move(p)) {}
95-
96-
WorkspaceApplicationService& ApplicationServices::workspaces() const { return *m_workspaces; }
97-
InventoryApplicationService& ApplicationServices::inventory() const { return *m_inventory; }
98-
BuildApplicationService& ApplicationServices::builds() const { return *m_builds; }
99-
CollectionApplicationService& ApplicationServices::collection() const { return *m_collection; }
100-
SharedPartReferenceCustomizationService& ApplicationServices::partReferenceCustomizations() const
101-
{ return *m_partReference; }

src/services/application/ApplicationServices.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "SharedDataSource.h"
4+
35
// M26 ownership boundary: catalog/reference services remain local to each
46
// device. These contracts cover shared, Host-authoritative application data.
57
// The composition root supplies local implementations today and may supply
@@ -25,10 +27,30 @@
2527

2628
class PartReferenceManifest;
2729

30+
enum class ApplicationServiceAvailability
31+
{
32+
AvailableLocal,
33+
AvailableRemote,
34+
UnavailableNotConnected,
35+
UnavailableMaintenance
36+
};
37+
38+
struct ApplicationServiceStatus
39+
{
40+
ApplicationServiceAvailability availability = ApplicationServiceAvailability::AvailableLocal;
41+
QString message;
42+
bool isAvailable() const
43+
{
44+
return availability == ApplicationServiceAvailability::AvailableLocal
45+
|| availability == ApplicationServiceAvailability::AvailableRemote;
46+
}
47+
};
48+
2849
class WorkspaceApplicationService
2950
{
3051
public:
3152
virtual ~WorkspaceApplicationService() = default;
53+
virtual ApplicationServiceStatus status() const { return {}; }
3254
virtual QList<Workspace> list() const = 0;
3355
virtual std::optional<Workspace> get(int workspaceId) const = 0;
3456
virtual bool exists(int workspaceId) const = 0;
@@ -41,6 +63,7 @@ class InventoryApplicationService
4163
public:
4264
struct Page { QList<InventorySearchResult> rows; int total = 0; };
4365
virtual ~InventoryApplicationService() = default;
66+
virtual ApplicationServiceStatus status() const { return {}; }
4467
virtual int count(const InventorySearchCriteria& criteria) const = 0;
4568
virtual QList<InventorySearchResult> searchRows(
4669
const InventorySearchCriteria& criteria) const = 0;
@@ -55,6 +78,7 @@ class BuildApplicationService
5578
{
5679
public:
5780
virtual ~BuildApplicationService() = default;
81+
virtual ApplicationServiceStatus status() const { return {}; }
5882
virtual QList<Build> list(int workspaceId, bool includeArchived) const = 0;
5983
virtual std::optional<Build> get(int buildId) const = 0;
6084
virtual QList<BuildRequirement> requirements(int buildId) const = 0;
@@ -68,6 +92,7 @@ class CollectionApplicationService
6892
public:
6993
struct Page { QList<CollectionSearchResult> rows; int total = 0; };
7094
virtual ~CollectionApplicationService() = default;
95+
virtual ApplicationServiceStatus status() const { return {}; }
7196
virtual int count(const CollectionSearchCriteria& criteria) const = 0;
7297
virtual QList<CollectionSearchResult> searchRows(
7398
const CollectionSearchCriteria& criteria) const = 0;
@@ -80,6 +105,7 @@ class SharedPartReferenceCustomizationService
80105
{
81106
public:
82107
virtual ~SharedPartReferenceCustomizationService() = default;
108+
virtual ApplicationServiceStatus status() const { return {}; }
83109
virtual QList<PartReferenceEntry> effectiveEntries(
84110
const PartReferenceManifest& manifest, QString* errorMessage) const = 0;
85111
virtual PartReferenceCustomizationResult add(
@@ -98,18 +124,24 @@ class ApplicationServices
98124
std::unique_ptr<InventoryApplicationService> inventory,
99125
std::unique_ptr<BuildApplicationService> builds,
100126
std::unique_ptr<CollectionApplicationService> collection,
101-
std::unique_ptr<SharedPartReferenceCustomizationService> partReference);
127+
std::unique_ptr<SharedPartReferenceCustomizationService> partReference,
128+
SharedDataSource source = SharedDataSource::ThisComputer);
102129

103130
WorkspaceApplicationService& workspaces() const;
104131
InventoryApplicationService& inventory() const;
105132
BuildApplicationService& builds() const;
106133
CollectionApplicationService& collection() const;
107134
SharedPartReferenceCustomizationService& partReferenceCustomizations() const;
135+
SharedDataSource sharedDataSource() const;
136+
ApplicationServiceStatus sharedStatus() const;
108137

109138
private:
110139
std::unique_ptr<WorkspaceApplicationService> m_workspaces;
111140
std::unique_ptr<InventoryApplicationService> m_inventory;
112141
std::unique_ptr<BuildApplicationService> m_builds;
113142
std::unique_ptr<CollectionApplicationService> m_collection;
114143
std::unique_ptr<SharedPartReferenceCustomizationService> m_partReference;
144+
SharedDataSource m_source = SharedDataSource::ThisComputer;
115145
};
146+
147+
std::unique_ptr<ApplicationServices> createUnavailableHostApplicationServices();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "ApplicationServices.h"
2+
3+
ApplicationServices::ApplicationServices(std::unique_ptr<WorkspaceApplicationService> w,
4+
std::unique_ptr<InventoryApplicationService> i, std::unique_ptr<BuildApplicationService> b,
5+
std::unique_ptr<CollectionApplicationService> c,
6+
std::unique_ptr<SharedPartReferenceCustomizationService> p, SharedDataSource source)
7+
: m_workspaces(std::move(w)), m_inventory(std::move(i)), m_builds(std::move(b)),
8+
m_collection(std::move(c)), m_partReference(std::move(p)), m_source(source) {}
9+
10+
WorkspaceApplicationService& ApplicationServices::workspaces() const { return *m_workspaces; }
11+
InventoryApplicationService& ApplicationServices::inventory() const { return *m_inventory; }
12+
BuildApplicationService& ApplicationServices::builds() const { return *m_builds; }
13+
CollectionApplicationService& ApplicationServices::collection() const { return *m_collection; }
14+
SharedPartReferenceCustomizationService& ApplicationServices::partReferenceCustomizations() const
15+
{ return *m_partReference; }
16+
SharedDataSource ApplicationServices::sharedDataSource() const { return m_source; }
17+
ApplicationServiceStatus ApplicationServices::sharedStatus() const { return m_workspaces->status(); }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
// Stable device-local composition choice. Keep serialized spellings in
4+
// UserSettings; this enum is shared by startup composition and presentation.
5+
enum class SharedDataSource
6+
{
7+
ThisComputer,
8+
BrickSuiteHost
9+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include "ApplicationServices.h"
2+
3+
#include "../parts/PartReferenceManifest.h"
4+
5+
namespace {
6+
const QString kHostUnavailable = QStringLiteral("BrickSuite Host shared data is not connected.");
7+
ApplicationServiceStatus unavailable()
8+
{ return {ApplicationServiceAvailability::UnavailableNotConnected, kHostUnavailable}; }
9+
10+
class Workspaces final : public WorkspaceApplicationService {
11+
public:
12+
ApplicationServiceStatus status() const override{return unavailable();}
13+
QList<Workspace> list() const override{return {};} std::optional<Workspace> get(int) const override{return {};}
14+
bool exists(int) const override{return false;} bool create(Workspace&) const override{return false;} bool update(Workspace&) const override{return false;}
15+
};
16+
class Inventory final : public InventoryApplicationService {
17+
public:
18+
ApplicationServiceStatus status() const override{return unavailable();}
19+
int count(const InventorySearchCriteria&) const override{return 0;} QList<InventorySearchResult> searchRows(const InventorySearchCriteria&) const override{return {};}
20+
std::optional<InventoryRecord> get(int) const override{return {};} QList<InventoryHistoryResult> history(int,int,int) const override{return {};}
21+
};
22+
class Builds final : public BuildApplicationService {
23+
public:
24+
ApplicationServiceStatus status() const override{return unavailable();}
25+
QList<Build> list(int,bool) const override{return {};} std::optional<Build> get(int) const override{return {};}
26+
QList<BuildRequirement> requirements(int) const override{return {};} QList<MissingPartsService::MissingPart> missingParts(int,int) const override{return {};}
27+
BuildPullingService::PullingView pullingView(int) const override{BuildPullingService::PullingView r;r.message=kHostUnavailable;return r;}
28+
};
29+
class Collection final : public CollectionApplicationService {
30+
public:
31+
ApplicationServiceStatus status() const override{return unavailable();}
32+
int count(const CollectionSearchCriteria&) const override{return 0;} QList<CollectionSearchResult> searchRows(const CollectionSearchCriteria&) const override{return {};}
33+
std::optional<CollectionSearchResult> getDisplay(int) const override{return {};}
34+
};
35+
class PartReference final : public SharedPartReferenceCustomizationService {
36+
public:
37+
ApplicationServiceStatus status() const override{return unavailable();}
38+
QList<PartReferenceEntry> effectiveEntries(const PartReferenceManifest& manifest,QString* error) const override
39+
{if(error)*error=kHostUnavailable+QStringLiteral(" Built-in Part Reference entries remain available; shared customizations are unavailable.");return manifest.entries();}
40+
PartReferenceCustomizationResult add(const PartReferenceManifest&,const QString&,const QString&,const QString&,PartReferencePlacement,const QString&) const override{return {false,kHostUnavailable,0};}
41+
PartReferenceCustomizationResult remove(const PartReferenceManifest&,int) const override{return {false,kHostUnavailable,0};}
42+
};
43+
}
44+
45+
std::unique_ptr<ApplicationServices> createUnavailableHostApplicationServices()
46+
{
47+
return std::make_unique<ApplicationServices>(std::make_unique<Workspaces>(),
48+
std::make_unique<Inventory>(),std::make_unique<Builds>(),
49+
std::make_unique<Collection>(),std::make_unique<PartReference>(),
50+
SharedDataSource::BrickSuiteHost);
51+
}

src/settings/UserSettings.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ constexpr auto kThemeKey = "Theme";
4040
constexpr auto kResultsPerPageKey = "ResultsPerPage";
4141

4242
constexpr auto kDefaultWorkspaceIdKey = "DefaultWorkspaceId";
43+
constexpr auto kSharedDataSourceKey = "SharedDataSource";
4344

4445
constexpr auto kRebrickableApiKey = "ApiKey";
4546
constexpr auto kRebrickableConnectionPreviouslyVerifiedKey = "ConnectionPreviouslyVerified";
@@ -124,6 +125,34 @@ void UserSettings::setTheme(Theme theme)
124125
settings.endGroup();
125126
}
126127

128+
SharedDataSource UserSettings::sharedDataSource() const
129+
{
130+
QSettings settings;
131+
settings.beginGroup(kGroupGeneral);
132+
const QString value = settings.value(kSharedDataSourceKey, "this-computer").toString();
133+
settings.endGroup();
134+
if (value.compare("this-computer", Qt::CaseInsensitive) == 0)
135+
return SharedDataSource::ThisComputer;
136+
if (value.compare("bricksuite-host", Qt::CaseInsensitive) == 0)
137+
return SharedDataSource::BrickSuiteHost;
138+
qWarning() << "Unknown Shared Data Source setting; using This Computer:" << value;
139+
return SharedDataSource::ThisComputer;
140+
}
141+
142+
void UserSettings::setSharedDataSource(SharedDataSource source)
143+
{
144+
QSettings settings;
145+
settings.beginGroup(kGroupGeneral);
146+
settings.setValue(kSharedDataSourceKey, sharedDataSourceToString(source));
147+
settings.endGroup();
148+
}
149+
150+
QString UserSettings::sharedDataSourceToString(SharedDataSource source)
151+
{
152+
return source == SharedDataSource::BrickSuiteHost
153+
? QStringLiteral("bricksuite-host") : QStringLiteral("this-computer");
154+
}
155+
127156
int UserSettings::resultsPerPage() const
128157
{
129158
QSettings settings;

src/settings/UserSettings.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <QDateTime>
2525
#include <QString>
2626

27+
#include "../services/application/SharedDataSource.h"
28+
2729
class UserSettings
2830
{
2931
public:
@@ -34,6 +36,10 @@ class UserSettings
3436
Theme theme() const;
3537
void setTheme(Theme theme);
3638

39+
SharedDataSource sharedDataSource() const;
40+
void setSharedDataSource(SharedDataSource source);
41+
static QString sharedDataSourceToString(SharedDataSource source);
42+
3743
int resultsPerPage() const;
3844
void setResultsPerPage(int resultsPerPage);
3945

0 commit comments

Comments
 (0)