From: Christian Kamm Date: Tue, 16 Apr 2019 08:17:21 +0000 (+0200) Subject: Vfs: "free space" only shows when it has an effect #7143 X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~243 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=7f3f13fd976ea5c83e5418b8dbba94c8f930ec86;p=nextcloud-desktop.git Vfs: "free space" only shows when it has an effect #7143 To do this, introduce AllDehydrated availability and rename SomeDehydrated to Mixed - it now guarantees there are also hydrated items. --- diff --git a/src/common/pinstate.h b/src/common/pinstate.h index 44ee12417..c86d11ae5 100644 --- a/src/common/pinstate.h +++ b/src/common/pinstate.h @@ -83,13 +83,15 @@ enum class PinState { * * Note that this is only about *intent*. The file could still be out of date, * or not have been synced for other reasons, like errors. + * + * NOTE: The numerical values and ordering of this enum are relevant. */ enum class VfsItemAvailability { /** The item and all its subitems are hydrated and pinned AlwaysLocal. * * This guarantees that all contents will be kept in sync. */ - AlwaysLocal, + AlwaysLocal = 0, /** The item and all its subitems are hydrated. * @@ -98,20 +100,24 @@ enum class VfsItemAvailability { * * A folder with no file contents will have this availability. */ - AllHydrated, + AllHydrated = 1, - /** There are dehydrated items but the pin state isn't all OnlineOnly. + /** There are dehydrated and hydrated items. * * This would happen if a dehydration happens to a Unspecified item that * used to be hydrated. */ - SomeDehydrated, + Mixed = 2, + + /** There are only dehydrated items but the pin state isn't all OnlineOnly. + */ + AllDehydrated = 3, /** The item and all its subitems are dehydrated and OnlineOnly. * * This guarantees that contents will not take up space. */ - OnlineOnly, + OnlineOnly = 4, }; } diff --git a/src/common/syncjournaldb.cpp b/src/common/syncjournaldb.cpp index c5c6a459a..1d46332ee 100644 --- a/src/common/syncjournaldb.cpp +++ b/src/common/syncjournaldb.cpp @@ -1328,18 +1328,16 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename, return _setFileRecordLocalMetadataQuery.exec(); } -Optional SyncJournalDb::hasDehydratedFiles(const QByteArray &filename) +Optional SyncJournalDb::hasHydratedOrDehydratedFiles(const QByteArray &filename) { QMutexLocker locker(&_mutex); if (!checkConnect()) return {}; auto &query = _countDehydratedFilesQuery; - static_assert(ItemTypeVirtualFile == 4 && ItemTypeVirtualFileDownload == 5, ""); if (!query.initOrReset(QByteArrayLiteral( - "SELECT count(*) FROM metadata" - " WHERE (" IS_PREFIX_PATH_OR_EQUAL("?1", "path") " OR ?1 == '')" - " AND (type == 4 OR type == 5);"), _db)) { + "SELECT DISTINCT type FROM metadata" + " WHERE (" IS_PREFIX_PATH_OR_EQUAL("?1", "path") " OR ?1 == '');"), _db)) { return {}; } @@ -1347,10 +1345,21 @@ Optional SyncJournalDb::hasDehydratedFiles(const QByteArray &filename) if (!query.exec()) return {}; - if (!query.next().hasData) - return {}; + HasHydratedDehydrated result; + forever { + auto next = query.next(); + if (!next.ok) + return {}; + if (!next.hasData) + break; + auto type = static_cast(query.intValue(0)); + if (type == ItemTypeFile || type == ItemTypeVirtualFileDehydration) + result.hasHydrated = true; + if (type == ItemTypeVirtualFile || type == ItemTypeVirtualFileDownload) + result.hasDehydrated = true; + } - return query.intValue(0) > 0; + return result; } static void toDownloadInfo(SqlQuery &query, SyncJournalDb::DownloadInfo *res) diff --git a/src/common/syncjournaldb.h b/src/common/syncjournaldb.h index a68960555..695d9e040 100644 --- a/src/common/syncjournaldb.h +++ b/src/common/syncjournaldb.h @@ -73,8 +73,15 @@ public: bool updateLocalMetadata(const QString &filename, qint64 modtime, qint64 size, quint64 inode); + /// Return value for hasHydratedOrDehydratedFiles() + struct HasHydratedDehydrated + { + bool hasHydrated = false; + bool hasDehydrated = false; + }; + /** Returns whether the item or any subitems are dehydrated */ - Optional hasDehydratedFiles(const QByteArray &filename); + Optional hasHydratedOrDehydratedFiles(const QByteArray &filename); bool exists(); void walCheckpoint(); diff --git a/src/common/vfs.cpp b/src/common/vfs.cpp index 54f6cb6bd..c24c11cd6 100644 --- a/src/common/vfs.cpp +++ b/src/common/vfs.cpp @@ -83,15 +83,17 @@ Optional Vfs::availabilityInDb(const QString &folderPath, c { auto pin = _setupParams.journal->internalPinStates().effectiveForPathRecursive(pinPath.toUtf8()); // not being able to retrieve the pin state isn't too bad - Optional hasDehydrated = _setupParams.journal->hasDehydratedFiles(folderPath.toUtf8()); - if (!hasDehydrated) + auto hydrationStatus = _setupParams.journal->hasHydratedOrDehydratedFiles(folderPath.toUtf8()); + if (!hydrationStatus) return {}; - if (*hasDehydrated) { + if (hydrationStatus->hasDehydrated) { + if (hydrationStatus->hasHydrated) + return VfsItemAvailability::Mixed; if (pin && *pin == PinState::OnlineOnly) return VfsItemAvailability::OnlineOnly; else - return VfsItemAvailability::SomeDehydrated; + return VfsItemAvailability::AllDehydrated; } else { if (pin && *pin == PinState::AlwaysLocal) return VfsItemAvailability::AlwaysLocal; diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index d4d139fe3..7aa4c8041 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -449,7 +449,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos) auto availabilityMenu = menu->addMenu(tr("Availability")); auto availability = folder->vfs().availability(QString()); if (availability) { - ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability, true)); + ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability)); ac->setEnabled(false); } @@ -458,7 +458,9 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos) connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::AlwaysLocal); }); ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText()); - ac->setEnabled(!availability || *availability != VfsItemAvailability::OnlineOnly); + ac->setEnabled(!availability + || !(*availability == VfsItemAvailability::OnlineOnly + || *availability == VfsItemAvailability::AllDehydrated)); connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::OnlineOnly); }); ac = menu->addAction(tr("Disable virtual file support...")); diff --git a/src/gui/guiutility.cpp b/src/gui/guiutility.cpp index 751e171cc..aa991b12a 100644 --- a/src/gui/guiutility.cpp +++ b/src/gui/guiutility.cpp @@ -69,19 +69,17 @@ bool Utility::openEmailComposer(const QString &subject, const QString &body, QWi return true; } -QString Utility::vfsCurrentAvailabilityText(VfsItemAvailability availability, bool forFolder) +QString Utility::vfsCurrentAvailabilityText(VfsItemAvailability availability) { switch(availability) { case VfsItemAvailability::AlwaysLocal: return QCoreApplication::translate("utility", "Currently always available locally"); case VfsItemAvailability::AllHydrated: return QCoreApplication::translate("utility", "Currently available locally"); - case VfsItemAvailability::SomeDehydrated: - if (forFolder) { - return QCoreApplication::translate("utility", "Currently some available online only"); - } else { - return QCoreApplication::translate("utility", "Currently available online only"); - } + case VfsItemAvailability::Mixed: + return QCoreApplication::translate("utility", "Currently some available online only"); + case VfsItemAvailability::AllDehydrated: + return QCoreApplication::translate("utility", "Currently available online only"); case VfsItemAvailability::OnlineOnly: return QCoreApplication::translate("utility", "Currently available online only"); } diff --git a/src/gui/guiutility.h b/src/gui/guiutility.h index b25ecc937..6e2c5f163 100644 --- a/src/gui/guiutility.h +++ b/src/gui/guiutility.h @@ -41,7 +41,7 @@ namespace Utility { * * This will be used in context menus to describe the current state. */ - QString vfsCurrentAvailabilityText(VfsItemAvailability availability, bool forFolder); + QString vfsCurrentAvailabilityText(VfsItemAvailability availability); /** Translated text for "making items always available locally" */ QString vfsPinActionText(); diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index f893bd4b2..be8f0beac 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -1049,19 +1049,19 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe auto merge = [](VfsItemAvailability lhs, VfsItemAvailability rhs) { if (lhs == rhs) return lhs; - if (lhs == VfsItemAvailability::SomeDehydrated || rhs == VfsItemAvailability::SomeDehydrated - || lhs == VfsItemAvailability::OnlineOnly || rhs == VfsItemAvailability::OnlineOnly) { - return VfsItemAvailability::SomeDehydrated; - } - return VfsItemAvailability::AllHydrated; + auto l = int(lhs) < int(rhs) ? lhs : rhs; // reduce cases by sorting + auto r = int(lhs) < int(rhs) ? rhs : lhs; + if (l == VfsItemAvailability::AlwaysLocal && r == VfsItemAvailability::AllHydrated) + return VfsItemAvailability::AllHydrated; + if (l == VfsItemAvailability::AllDehydrated && r == VfsItemAvailability::OnlineOnly) + return VfsItemAvailability::AllDehydrated; + return VfsItemAvailability::Mixed; }; - bool isFolderOrMultiple = false; for (const auto &file : files) { auto fileData = FileData::get(file); - isFolderOrMultiple = QFileInfo(fileData.localPath).isDir(); auto availability = syncFolder->vfs().availability(fileData.folderRelativePath); if (!availability) - availability = VfsItemAvailability::SomeDehydrated; // db error + availability = VfsItemAvailability::Mixed; // db error if (!combined) { combined = availability; } else { @@ -1069,13 +1069,11 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe } } ENFORCE(combined); - if (files.size() > 1) - isFolderOrMultiple = true; // TODO: Should be a submenu, should use icons auto makePinContextMenu = [&](bool makeAvailableLocally, bool freeSpace) { listener->sendMessage(QLatin1String("MENU_ITEM:CURRENT_PIN:d:") - + Utility::vfsCurrentAvailabilityText(*combined, isFolderOrMultiple)); + + Utility::vfsCurrentAvailabilityText(*combined)); listener->sendMessage(QLatin1String("MENU_ITEM:MAKE_AVAILABLE_LOCALLY:") + (makeAvailableLocally ? QLatin1String(":") : QLatin1String("d:")) + Utility::vfsPinActionText()); @@ -1089,11 +1087,10 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe makePinContextMenu(false, true); break; case VfsItemAvailability::AllHydrated: + case VfsItemAvailability::Mixed: makePinContextMenu(true, true); break; - case VfsItemAvailability::SomeDehydrated: - makePinContextMenu(true, true); - break; + case VfsItemAvailability::AllDehydrated: case VfsItemAvailability::OnlineOnly: makePinContextMenu(true, false); break; diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index 86845bc8e..b059dc824 100644 --- a/test/testsyncvirtualfiles.cpp +++ b/test/testsyncvirtualfiles.cpp @@ -1061,21 +1061,23 @@ private slots: QCOMPARE(*vfs->availability("local/file1"), VfsItemAvailability::AlwaysLocal); QCOMPARE(*vfs->availability("online"), VfsItemAvailability::OnlineOnly); QCOMPARE(*vfs->availability("online/file1.nextcloud"), VfsItemAvailability::OnlineOnly); - QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::SomeDehydrated); - QCOMPARE(*vfs->availability("unspec/file1.nextcloud"), VfsItemAvailability::SomeDehydrated); + QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::AllDehydrated); + QCOMPARE(*vfs->availability("unspec/file1.nextcloud"), VfsItemAvailability::AllDehydrated); // Subitem pin states can ruin "pure" availabilities setPin("local/sub", PinState::OnlineOnly); QCOMPARE(*vfs->availability("local"), VfsItemAvailability::AllHydrated); setPin("online/sub", PinState::Unspecified); - QCOMPARE(*vfs->availability("online"), VfsItemAvailability::SomeDehydrated); + QCOMPARE(*vfs->availability("online"), VfsItemAvailability::AllDehydrated); triggerDownload(fakeFolder, "unspec/file1"); setPin("local/file2", PinState::OnlineOnly); + setPin("online/file2", PinState::AlwaysLocal); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(*vfs->availability("unspec"), VfsItemAvailability::AllHydrated); - QCOMPARE(*vfs->availability("local"), VfsItemAvailability::SomeDehydrated); + QCOMPARE(*vfs->availability("local"), VfsItemAvailability::Mixed); + QCOMPARE(*vfs->availability("online"), VfsItemAvailability::Mixed); vfs->setPinState("local", PinState::AlwaysLocal); vfs->setPinState("online", PinState::OnlineOnly);