Skip to content

Commit d811ae8

Browse files
authored
add mutex for updating asset list (#1300)
1 parent 60d7406 commit d811ae8

2 files changed

Lines changed: 120 additions & 66 deletions

File tree

src/ui/viewmodels/AssetListViewModel.cpp

Lines changed: 119 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ void AssetListViewModel::OnDataModelStringValueChanged(gsl::index nIndex, const
168168
const auto* pItem = pGameContext.Assets().GetItemAt(nIndex);
169169
if (pItem != nullptr)
170170
{
171+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
172+
171173
const auto nFilteredIndex = GetFilteredAssetIndex(*pItem);
172174
if (nFilteredIndex != -1)
173175
m_vFilteredAssets.SetItemValue(nFilteredIndex, AssetSummaryViewModel::LabelProperty, args.tNewValue);
@@ -179,6 +181,8 @@ void AssetListViewModel::OnDataModelStringValueChanged(gsl::index nIndex, const
179181
const auto* pAsset = pGameContext.Assets().GetItemAt(nIndex);
180182
if (pAsset != nullptr)
181183
{
184+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
185+
182186
const auto nFilteredIndex = GetFilteredAssetIndex(*pAsset);
183187
if (nFilteredIndex != -1)
184188
m_vFilteredAssets.SetItemValue(nFilteredIndex, args.Property, args.tNewValue);
@@ -194,11 +198,16 @@ void AssetListViewModel::OnDataModelIntValueChanged(gsl::index nIndex, const Int
194198
const auto* pAsset = pGameContext.Assets().GetItemAt(nIndex);
195199
Expects(pAsset != nullptr);
196200
const auto* pAchievement = dynamic_cast<const ra::data::models::AchievementModel*>(pAsset);
197-
if (pAchievement != nullptr && GetFilteredAssetIndex(*pAsset) >= 0)
201+
if (pAchievement != nullptr)
198202
{
199-
auto nPoints = GetTotalPoints();
200-
nPoints += args.tNewValue - args.tOldValue;
201-
SetValue(TotalPointsProperty, nPoints);
203+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
204+
205+
if (GetFilteredAssetIndex(*pAsset) >= 0)
206+
{
207+
auto nPoints = GetTotalPoints();
208+
nPoints += args.tNewValue - args.tOldValue;
209+
SetValue(TotalPointsProperty, nPoints);
210+
}
202211
}
203212
}
204213
else if (args.Property == ra::data::models::AssetModelBase::StateProperty)
@@ -280,6 +289,8 @@ void AssetListViewModel::OnDataModelIntValueChanged(gsl::index nIndex, const Int
280289
const auto* pAsset = pGameContext.Assets().GetItemAt(nIndex);
281290
if (pAsset != nullptr)
282291
{
292+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
293+
283294
const auto nFilteredIndex = GetFilteredAssetIndex(*pAsset);
284295
if (nFilteredIndex != -1)
285296
{
@@ -301,21 +312,25 @@ void AssetListViewModel::OnDataModelIntValueChanged(gsl::index nIndex, const Int
301312

302313
RA_LOG_INFO("%s %u ID changed from %d to %d", ra::data::models::AssetModelBase::GetAssetTypeString(pAsset->GetType()), pAsset->GetID(), args.tOldValue, args.tNewValue);
303314

304-
// have to find the filtered item using the old ID
305-
for (gsl::index nScanIndex = 0; nScanIndex < gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()); ++nScanIndex)
306315
{
307-
auto* pItem = m_vFilteredAssets.GetItemAt(nScanIndex);
308-
if (pItem != nullptr && pItem->GetId() == args.tOldValue && pItem->GetType() == nType)
316+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
317+
318+
// have to find the filtered item using the old ID
319+
for (gsl::index nScanIndex = 0; nScanIndex < gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()); ++nScanIndex)
309320
{
310-
nFilteredIndex = nScanIndex;
311-
break;
321+
auto* pItem = m_vFilteredAssets.GetItemAt(nScanIndex);
322+
if (pItem != nullptr && pItem->GetId() == args.tOldValue && pItem->GetType() == nType)
323+
{
324+
nFilteredIndex = nScanIndex;
325+
break;
326+
}
312327
}
313-
}
314328

315-
if (nFilteredIndex != -1)
316-
m_vFilteredAssets.SetItemValue(nFilteredIndex, AssetSummaryViewModel::IdProperty, args.tNewValue);
329+
if (nFilteredIndex != -1)
330+
m_vFilteredAssets.SetItemValue(nFilteredIndex, AssetSummaryViewModel::IdProperty, args.tNewValue);
317331

318-
AddOrRemoveFilteredItem(*pAsset);
332+
AddOrRemoveFilteredItem(*pAsset);
333+
}
319334
}
320335
}
321336
}
@@ -332,19 +347,23 @@ void AssetListViewModel::OnDataModelRemoved(_UNUSED gsl::index nIndex)
332347
const auto& pGameContext = ra::services::ServiceLocator::Get<ra::data::context::GameContext>();
333348
if (!pGameContext.Assets().IsUpdating())
334349
{
335-
// the item has already been removed from the vAssets collection, and all we know about it
336-
// is the index where it was located. scan through the vFilteredAssets collection and remove
337-
// any that no longer exist in the vAssets collection.
338-
for (gsl::index nFilteredIndex = 0; nFilteredIndex < gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()); ++nFilteredIndex)
339350
{
340-
auto* pItem = m_vFilteredAssets.GetItemAt(nFilteredIndex);
341-
if (pItem != nullptr)
351+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
352+
353+
// the item has already been removed from the vAssets collection, and all we know about it
354+
// is the index where it was located. scan through the vFilteredAssets collection and remove
355+
// any that no longer exist in the vAssets collection.
356+
for (gsl::index nFilteredIndex = 0; nFilteredIndex < gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()); ++nFilteredIndex)
342357
{
343-
if (!pGameContext.Assets().FindAsset(pItem->GetType(), pItem->GetId()))
358+
auto* pItem = m_vFilteredAssets.GetItemAt(nFilteredIndex);
359+
if (pItem != nullptr)
344360
{
345-
m_vFilteredAssets.RemoveAt(nFilteredIndex);
346-
UpdateButtons();
347-
break;
361+
if (!pGameContext.Assets().FindAsset(pItem->GetType(), pItem->GetId()))
362+
{
363+
m_vFilteredAssets.RemoveAt(nFilteredIndex);
364+
UpdateButtons();
365+
break;
366+
}
348367
}
349368
}
350369
}
@@ -376,12 +395,16 @@ void AssetListViewModel::UpdateTotals()
376395
int nAchievementCount = 0;
377396
int nTotalPoints = 0;
378397

379-
for (const auto& pAsset : m_vFilteredAssets)
380398
{
381-
if (pAsset.GetType() == ra::data::models::AssetType::Achievement)
399+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
400+
401+
for (const auto& pAsset : m_vFilteredAssets)
382402
{
383-
++nAchievementCount;
384-
nTotalPoints += pAsset.GetPoints();
403+
if (pAsset.GetType() == ra::data::models::AssetType::Achievement)
404+
{
405+
++nAchievementCount;
406+
nTotalPoints += pAsset.GetPoints();
407+
}
385408
}
386409
}
387410

@@ -425,23 +448,27 @@ void AssetListViewModel::ApplyFilter()
425448
if (m_bInitializingFilter)
426449
return;
427450

428-
const auto& pGameContext = ra::services::ServiceLocator::Get<ra::data::context::GameContext>();
429-
m_vFilteredAssets.BeginUpdate();
430-
431-
// first pass: remove any filtered items no longer in the source collection
432-
for (gsl::index nIndex = gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()) -1; nIndex >= 0; --nIndex)
433451
{
434-
auto* pItem = m_vFilteredAssets.GetItemAt(nIndex);
435-
if (pItem != nullptr)
452+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
453+
454+
const auto& pGameContext = ra::services::ServiceLocator::Get<ra::data::context::GameContext>();
455+
m_vFilteredAssets.BeginUpdate();
456+
457+
// first pass: remove any filtered items no longer in the source collection
458+
for (gsl::index nIndex = gsl::narrow_cast<gsl::index>(m_vFilteredAssets.Count()) - 1; nIndex >= 0; --nIndex)
436459
{
437-
if (!pGameContext.Assets().FindAsset(pItem->GetType(), pItem->GetId()))
438-
m_vFilteredAssets.RemoveAt(nIndex);
460+
auto* pItem = m_vFilteredAssets.GetItemAt(nIndex);
461+
if (pItem != nullptr)
462+
{
463+
if (!pGameContext.Assets().FindAsset(pItem->GetType(), pItem->GetId()))
464+
m_vFilteredAssets.RemoveAt(nIndex);
465+
}
439466
}
440-
}
441467

442-
// second pass: update visibility of each item in the source collection
443-
for (const auto& pAsset : pGameContext.Assets())
444-
AddOrRemoveFilteredItem(pAsset);
468+
// second pass: update visibility of each item in the source collection
469+
for (const auto& pAsset : pGameContext.Assets())
470+
AddOrRemoveFilteredItem(pAsset);
471+
}
445472

446473
m_vFilteredAssets.EndUpdate();
447474

@@ -528,7 +555,13 @@ void AssetListViewModel::AddOrRemoveFilteredItem(gsl::index nAssetIndex)
528555
const auto* pAsset = pGameContext.Assets().GetItemAt(nAssetIndex);
529556
if (pAsset != nullptr)
530557
{
531-
if (AddOrRemoveFilteredItem(*pAsset))
558+
bool bUpdated = false;
559+
{
560+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
561+
bUpdated = AddOrRemoveFilteredItem(*pAsset);
562+
}
563+
564+
if (bUpdated)
532565
{
533566
UpdateTotals();
534567
UpdateButtons();
@@ -633,6 +666,8 @@ void AssetListViewModel::OpenEditor(const AssetSummaryViewModel* pAsset)
633666

634667
bool AssetListViewModel::HasSelection(ra::data::models::AssetType nAssetType) const
635668
{
669+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
670+
636671
for (const auto& pItem : m_vFilteredAssets)
637672
{
638673
if (pItem.IsSelected())
@@ -722,6 +757,8 @@ void AssetListViewModel::DoUpdateButtons()
722757
{
723758
SetValue(CanCreateProperty, true);
724759

760+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
761+
725762
for (const auto& pItem : m_vFilteredAssets)
726763
{
727764
switch (pItem.GetChanges())
@@ -937,6 +974,8 @@ void AssetListViewModel::GetSelectedAssets(std::vector<ra::data::models::AssetMo
937974
{
938975
auto& pGameContext = ra::services::ServiceLocator::GetMutable<ra::data::context::GameContext>();
939976

977+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
978+
940979
for (const auto& pItem : m_vFilteredAssets)
941980
{
942981
if (pItem.IsSelected())
@@ -1094,13 +1133,17 @@ void AssetListViewModel::SaveSelected()
10941133
if (sSaveButtonText.at(0) == '&') // "&Save" / "&Save All"
10951134
{
10961135
// save - find the selected items (allow empty to mean all)
1097-
for (const auto& pItem : m_vFilteredAssets)
10981136
{
1099-
if (pItem.IsSelected())
1137+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
1138+
1139+
for (const auto& pItem : m_vFilteredAssets)
11001140
{
1101-
auto* pAsset = pGameContext.Assets().FindAsset(pItem.GetType(), pItem.GetId());
1102-
if (pAsset != nullptr)
1103-
vSelectedAssets.push_back(pAsset);
1141+
if (pItem.IsSelected())
1142+
{
1143+
auto* pAsset = pGameContext.Assets().FindAsset(pItem.GetType(), pItem.GetId());
1144+
if (pAsset != nullptr)
1145+
vSelectedAssets.push_back(pAsset);
1146+
}
11041147
}
11051148
}
11061149

@@ -1431,13 +1474,17 @@ void AssetListViewModel::ResetSelected()
14311474

14321475
bool bCoreAssetSelected = false;
14331476
std::vector<const AssetSummaryViewModel*> vSelectedAssets;
1434-
for (const auto& pItem : m_vFilteredAssets)
14351477
{
1436-
if (pItem.IsSelected())
1478+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
1479+
1480+
for (const auto& pItem : m_vFilteredAssets)
14371481
{
1438-
vSelectedAssets.push_back(&pItem);
1482+
if (pItem.IsSelected())
1483+
{
1484+
vSelectedAssets.push_back(&pItem);
14391485

1440-
bCoreAssetSelected |= (pItem.GetCategory() == ra::data::models::AssetCategory::Core);
1486+
bCoreAssetSelected |= (pItem.GetCategory() == ra::data::models::AssetCategory::Core);
1487+
}
14411488
}
14421489
}
14431490

@@ -1757,8 +1804,8 @@ void AssetListViewModel::CreateNew()
17571804
nType = vmNewAsset.GetSelectedType();
17581805
}
17591806

1760-
FilteredAssets().BeginUpdate();
17611807
bool bUpdateAsset = true;
1808+
gsl::index nIndex = -1;
17621809

17631810
auto& pGameContext = ra::services::ServiceLocator::GetMutable<ra::data::context::GameContext>();
17641811
ra::data::models::AssetModelBase* pNewAsset = nullptr;
@@ -1795,6 +1842,7 @@ void AssetListViewModel::CreateNew()
17951842
}
17961843

17971844
Expects(pNewAsset != nullptr);
1845+
17981846
pNewAsset->SetSubsetID(GetSubsetFilter());
17991847

18001848
if (bUpdateAsset)
@@ -1808,23 +1856,28 @@ void AssetListViewModel::CreateNew()
18081856

18091857
EnsureAppearsInFilteredList(*pNewAsset);
18101858

1811-
const auto nId = ra::to_signed(pNewAsset->GetID());
1812-
1813-
// select the new viewmodel, and deselect everything else
1814-
gsl::index nIndex = -1;
1815-
for (gsl::index i = 0; i < ra::to_signed(m_vFilteredAssets.Count()); ++i)
18161859
{
1817-
auto* pItem = m_vFilteredAssets.GetItemAt(i);
1818-
if (pItem != nullptr)
1860+
std::lock_guard<std::mutex> lock(m_mtxFilteredItems);
1861+
1862+
FilteredAssets().BeginUpdate();
1863+
1864+
const auto nId = ra::to_signed(pNewAsset->GetID());
1865+
1866+
// select the new viewmodel, and deselect everything else
1867+
for (gsl::index i = 0; i < ra::to_signed(m_vFilteredAssets.Count()); ++i)
18191868
{
1820-
if (pItem->GetId() == nId && pItem->GetType() == nType)
1821-
{
1822-
pItem->SetSelected(true);
1823-
nIndex = i;
1824-
}
1825-
else
1869+
auto* pItem = m_vFilteredAssets.GetItemAt(i);
1870+
if (pItem != nullptr)
18261871
{
1827-
pItem->SetSelected(false);
1872+
if (pItem->GetId() == nId && pItem->GetType() == nType)
1873+
{
1874+
pItem->SetSelected(true);
1875+
nIndex = i;
1876+
}
1877+
else
1878+
{
1879+
pItem->SetSelected(false);
1880+
}
18281881
}
18291882
}
18301883
}

src/ui/viewmodels/AssetListViewModel.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ private:
341341
gsl::index GetFilteredAssetIndex(const ra::data::models::AssetModelBase& pAsset) const;
342342
void ApplyFilter();
343343
bool m_bInitializingFilter = false;
344+
mutable std::mutex m_mtxFilteredItems;
344345

345346
void RevalidateNoteAssetValidationWarnings();
346347

0 commit comments

Comments
 (0)