You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libcutefish/files/fileitem.h

180 lines
5.4 KiB
C++

// SPDX-FileCopyrightText: 2026 Reion Wong <reionwong@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "files/url.h"
namespace cutefish::files {
// A file or folder with what was read about it. Copies share their data until
// one of them changes, so lists of thousands of items copy cheaply; one item
// must not be changed and read on two threads at once.
//
// Times are milliseconds since the epoch: nothing here converts to local time,
// which stats the time zone file on every conversion.
class FileItem
{
public:
enum FileTime {
CreationTime,
ModificationTime,
AccessTime
};
FileItem() = default;
// Reads the file's metadata, and for an item at the top of a trash its info file.
explicit FileItem(const Url& url);
const Url& url() const;
Url mostLocalUrl() const { return Url::fromLocalFile(localPath()); }
const std::string& localPath() const;
// The URL's file name, as the listing decoded it.
const std::string& name() const;
std::string text() const;
void setDisplayName(const std::string& name);
void setIconName(const std::string& icon);
Url targetUrl() const;
void setTargetUrl(const Url& url);
bool isNull() const { return !d; }
bool isLocalFile() const { return d && d->url.isLocalFile(); }
// Links followed, so a broken link is neither file nor folder. Read on
// first use for an item a listing has not prepared.
bool exists() const;
bool isFile() const;
bool isDir() const;
bool isLink() const;
bool isHidden() const;
bool isWritable() const;
bool isDesktopFile() const;
uint64_t size() const;
// For an item at the top of a trash, where it was trashed from and when, as its
// info file says; empty otherwise.
std::string originalPath() const;
std::optional<int64_t> deletionTime() const;
// Empty when the file system keeps no such time.
std::optional<int64_t> time(FileTime type) const;
// Descriptions and icon names by MIME type, shared by the items of one listing.
using TypeDetails = std::unordered_map<std::string, std::pair<std::string, std::string>>;
// Reads the metadata the accessors use and detects the type.
void prepareMetadata();
// The same, but when previous is this file, unchanged, its type, icon and names
// are kept instead; returns whether they were.
bool prepareMetadata(const FileItem& previous, TypeDetails* details);
// The canonical MIME type; detected now for an item not prepared.
std::string mimetype() const;
std::string typeDescription() const;
std::string iconName() const;
// Whether both were prepared from a file or directory of the same kind, size and
// times, which answers for size(), isDir(), isLink() and the modification time.
bool sameStat(const FileItem& other) const;
bool operator==(const FileItem& other) const { return d == other.d; }
private:
friend class FileEnumerator;
// For a child the enumerator found in a directory it already resolved; name is
// the URL's file name.
FileItem(const Url& url, std::string localPath, std::string name);
// What prepareMetadata() saw, so a later listing can compare without reading
// the item, which other threads may share.
struct Stamp
{
int64_t size = -1;
int64_t modified = 0;
int64_t changed = 0;
// Set only for a directory or regular file; links are followed.
unsigned kind = 0;
bool operator==(const Stamp&) const = default;
};
struct Stat
{
bool read = false;
bool exists = false;
bool link = false;
bool file = false;
bool dir = false;
bool writable = false;
// The kind of special file, as st_mode has it; 0 for none.
unsigned special = 0;
uint64_t size = 0;
std::optional<int64_t> birth;
int64_t access = 0;
int64_t modified = 0;
int64_t changed = 0;
};
struct Data
{
Url url;
std::string name;
std::string localPath;
Stat stat;
Stamp stamp;
std::string mimeType;
std::string displayName;
std::string iconName;
std::string typeDescription;
Url targetUrl;
std::string originalPath;
std::optional<int64_t> deletionTime;
};
Data& detach();
const Stat& stat() const;
void readStat(Stat* stat) const;
void detectType(TypeDetails* details);
std::shared_ptr<Data> d;
};
using FileItemList = std::vector<FileItem>;
class FileItemListProperties
{
public:
explicit FileItemListProperties(const FileItemList& items)
: m_items(items)
{
}
bool supportsMoving() const;
bool supportsDeleting() const { return supportsMoving(); }
private:
FileItemList m_items;
};
// In powers of 1024 with two decimals in the session's locale, e.g. "1.50 KiB".
std::string convertSize(uint64_t size);
// Empty unless path is the home directory or an XDG user directory, as they were
// on the first call.
std::string standardFolderIconName(const std::string& path);
bool isStandardFolder(const Url& url);
bool canMoveStandardFolderTo(const Url& source, const Url& destination);
} // namespace cutefish::files