diff --git a/src/gui/filedetails/sharemodel.cpp b/src/gui/filedetails/sharemodel.cpp index 078e3ccb4a39..2a314c3faec6 100644 --- a/src/gui/filedetails/sharemodel.cpp +++ b/src/gui/filedetails/sharemodel.cpp @@ -90,7 +90,8 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const { Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); - const auto share = _shares.at(index.row()); + const auto shareIdx = index.row(); + const auto share = _shares.at(shareIdx); if (!share) { return {}; @@ -138,7 +139,7 @@ QVariant ShareModel::data(const QModelIndex &index, const int role) const switch (role) { case Qt::DisplayRole: - return displayStringForShare(share); + return displayStringForShare(share, _duplicateDisplayNameShareIndices.contains(shareIdx)); case ShareRole: return QVariant::fromValue(share); case ShareTypeRole: @@ -486,6 +487,41 @@ void ShareModel::slotSharesFetched(const QList &shares) slotAddShare(share); } + // Perform forward pass on shares and check for duplicate display names; store these indeces so + // we can check for these and display the specific user identifier in the display string later + _duplicateDisplayNameShareIndices.clear(); + const auto shareCount = _shares.count(); + for (auto i = 0; i < shareCount; ++i) { + if (_duplicateDisplayNameShareIndices.contains(i)) { + continue; + } + + const auto sharee = _shares.at(i)->getShareWith(); + if (sharee == nullptr) { + continue; + } + + const auto duplicateIndices = QSharedPointer>::create(); + const auto handleDuplicateIndex = [this, duplicateIndices](const unsigned int idx) { + duplicateIndices->insert(idx); + _duplicateDisplayNameShareIndices[idx] = duplicateIndices; + const auto targetIdx = index(idx); + dataChanged(targetIdx, targetIdx, {Qt::DisplayRole}); + }; + + for (auto j = i + 1; j < shareCount; ++j) { + const auto otherSharee = _shares.at(j)->getShareWith(); + if (otherSharee == nullptr || sharee->format() != otherSharee->format()) { + continue; + } + handleDuplicateIndex(j); + } + + if (!duplicateIndices->isEmpty()) { + handleDuplicateIndex(i); + } + } + handleLinkShare(); } @@ -611,10 +647,26 @@ void ShareModel::slotRemoveShareWithId(const QString &shareId) const auto sharee = share->getShareWith(); slotRemoveSharee(sharee); - beginRemoveRows({}, shareIndex.row(), shareIndex.row()); - _shares.removeAt(shareIndex.row()); + const auto shareRow = shareIndex.row(); + beginRemoveRows({}, shareRow, shareRow); + _shares.removeAt(shareRow); endRemoveRows(); + // Handle display name duplicates now. First remove the index from the bucket it was in; then, + // check if this removal means the remaining index in the bucket is no longer a duplicate. + // If this is the case then handle the update for this item too. + const auto duplicateShares = _duplicateDisplayNameShareIndices.value(shareRow); + if (duplicateShares) { + duplicateShares->remove(shareRow); + if (duplicateShares->count() == 1) { + const auto noLongerDuplicateIndex = *(duplicateShares->begin()); + _duplicateDisplayNameShareIndices.remove(noLongerDuplicateIndex); + const auto noLongerDuplicateModelIndex = index(noLongerDuplicateIndex); + Q_EMIT dataChanged(noLongerDuplicateModelIndex, noLongerDuplicateModelIndex, {Qt::DisplayRole}); + } + _duplicateDisplayNameShareIndices.remove(shareRow); + } + handleLinkShare(); Q_EMIT sharesChanged(); @@ -642,7 +694,7 @@ void ShareModel::slotRemoveSharee(const ShareePtr &sharee) Q_EMIT shareesChanged(); } -QString ShareModel::displayStringForShare(const SharePtr &share) const +QString ShareModel::displayStringForShare(const SharePtr &share, const bool verbose) const { if (const auto linkShare = share.objectCast()) { @@ -662,7 +714,8 @@ QString ShareModel::displayStringForShare(const SharePtr &share) const } else if (share->getShareType() == Share::TypeSecureFileDropPlaceholderLink) { return tr("Secure file drop"); } else if (share->getShareWith()) { - return share->getShareWith()->format(); + const auto sharee = share->getShareWith(); + return verbose ? QString{"%1 (%2)"}.arg(sharee->format(), sharee->shareWith()) : sharee->format(); } qCWarning(lcShareModel) << "Unable to provide good display string for share"; diff --git a/src/gui/filedetails/sharemodel.h b/src/gui/filedetails/sharemodel.h index 694f0d37eeb3..09d136f1ea0f 100644 --- a/src/gui/filedetails/sharemodel.h +++ b/src/gui/filedetails/sharemodel.h @@ -217,7 +217,7 @@ private slots: void slotDeleteE2EeShare(const SharePtr &share) const; private: - [[nodiscard]] QString displayStringForShare(const SharePtr &share) const; + [[nodiscard]] QString displayStringForShare(const SharePtr &share, bool verbose = false) const; [[nodiscard]] QString iconUrlForShare(const SharePtr &share) const; [[nodiscard]] QString avatarUrlForShare(const SharePtr &share) const; [[nodiscard]] long long enforcedMaxExpireDateForShare(const SharePtr &share) const; @@ -253,6 +253,8 @@ private slots: QHash _shareIdIndexHash; QHash _shareIdRecentlySetPasswords; QVector _sharees; + // Buckets of sharees with the same display name + QHash>> _duplicateDisplayNameShareIndices; }; } // namespace OCC