mirror of
https://github.com/transmission/transmission
synced 2024-12-23 08:13:27 +00:00
feat: render file tree in legacy html-based QuickLook preview extension (#6091)
Signed-off-by: Dzmitry Neviadomski <nevack.d@gmail.com>
This commit is contained in:
parent
1500417704
commit
8ef7eba3bd
1 changed files with 79 additions and 12 deletions
|
@ -3,8 +3,11 @@
|
||||||
@import QuickLook;
|
@import QuickLook;
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <libtransmission/torrent-metainfo.h>
|
#include <libtransmission/torrent-metainfo.h>
|
||||||
|
#include <libtransmission/utils.h>
|
||||||
|
|
||||||
#import "NSStringAdditions.h"
|
#import "NSStringAdditions.h"
|
||||||
|
|
||||||
|
@ -13,6 +16,31 @@ OSStatus GeneratePreviewForURL(void* thisInterface, QLPreviewRequestRef preview,
|
||||||
void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview);
|
void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview);
|
||||||
QL_EXTERN_C_END
|
QL_EXTERN_C_END
|
||||||
|
|
||||||
|
static NSUInteger const kIconWidth = 16;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class FileTreeNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileTreeNode() = default;
|
||||||
|
~FileTreeNode() = default;
|
||||||
|
|
||||||
|
auto MaybeCreateChild(std::string_view child_name)
|
||||||
|
{
|
||||||
|
return children_.try_emplace(std::string{ child_name });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileTreeNode(FileTreeNode const&) = delete;
|
||||||
|
FileTreeNode& operator=(FileTreeNode&) = delete;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, FileTreeNode> children_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
NSString* generateIconData(NSString* fileExtension, NSUInteger width, NSMutableDictionary* allImgProps)
|
NSString* generateIconData(NSString* fileExtension, NSUInteger width, NSMutableDictionary* allImgProps)
|
||||||
{
|
{
|
||||||
NSString* rawFilename = ![fileExtension isEqualToString:@""] ? fileExtension : @"blank_file_name_transmission";
|
NSString* rawFilename = ![fileExtension isEqualToString:@""] ? fileExtension : @"blank_file_name_transmission";
|
||||||
|
@ -189,24 +217,63 @@ OSStatus GeneratePreviewForURL(void* /*thisInterface*/, QLPreviewRequestRef prev
|
||||||
localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu Files", nil, bundle, "quicklook file header"), n_files];
|
localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu Files", nil, bundle, "quicklook file header"), n_files];
|
||||||
[listSection appendFormat:@"<tr><th>%@</th></tr>", fileTitleString];
|
[listSection appendFormat:@"<tr><th>%@</th></tr>", fileTitleString];
|
||||||
|
|
||||||
#warning display folders?
|
FileTreeNode root{};
|
||||||
|
|
||||||
for (auto const& [path, size] : metainfo.files().sortedByPath())
|
for (auto const& [path, size] : metainfo.files().sortedByPath())
|
||||||
{
|
{
|
||||||
NSString* fullFilePath = @(path.c_str());
|
FileTreeNode* curNode = &root;
|
||||||
NSCAssert([fullFilePath hasPrefix:[name stringByAppendingString:@"/"]], @"Expected file path %@ to begin with %@/", fullFilePath, name);
|
size_t level = 0;
|
||||||
|
|
||||||
NSString* shortenedFilePath = [fullFilePath substringFromIndex:name.length + 1];
|
auto subpath = std::string_view{ path };
|
||||||
NSString* fileSize = [NSString stringForFileSize:size];
|
auto path_vec = std::vector<std::string_view>{};
|
||||||
|
auto token = std::string_view{};
|
||||||
|
while (tr_strv_sep(&subpath, &token, '/'))
|
||||||
|
{
|
||||||
|
path_vec.emplace_back(token);
|
||||||
|
}
|
||||||
|
size_t const last = path_vec.size() - 1;
|
||||||
|
|
||||||
NSUInteger const icon_width = 16;
|
for (auto const& part : path_vec)
|
||||||
[listSection appendFormat:@"<tr><td><img class=\"icon\" src=\"%@\" width=\"%ld\" height=\"%ld\" />%@</td><td class=\"grey\">%@</td></tr>",
|
{
|
||||||
generateIconData(shortenedFilePath.pathExtension, icon_width, allImgProps),
|
auto [it, inserted] = curNode->MaybeCreateChild(part);
|
||||||
icon_width,
|
if (inserted)
|
||||||
icon_width,
|
{
|
||||||
shortenedFilePath,
|
NSString* prefix = @"";
|
||||||
|
for (size_t i = 0; i < level; ++i)
|
||||||
|
{
|
||||||
|
prefix = [prefix stringByAppendingString:@" "];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* pathPart = @(it->first.c_str());
|
||||||
|
NSString* pathExt = nil;
|
||||||
|
NSString* fileSize = nil;
|
||||||
|
if (level < last)
|
||||||
|
{
|
||||||
|
// This node is a directory.
|
||||||
|
pathExt = NSFileTypeForHFSTypeCode(kGenericFolderIcon);
|
||||||
|
fileSize = @"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This node is a leaf file.
|
||||||
|
pathExt = pathPart.pathExtension;
|
||||||
|
fileSize = [NSString stringForFileSize:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
[listSection appendFormat:@"<tr><td>%@<img class=\"icon\" src=\"%@\" width=\"%ld\" height=\"%ld\" />%@</td><td class=\"grey\">%@</td></tr>",
|
||||||
|
prefix,
|
||||||
|
generateIconData(pathExt, kIconWidth, allImgProps),
|
||||||
|
kIconWidth,
|
||||||
|
kIconWidth,
|
||||||
|
pathPart,
|
||||||
fileSize];
|
fileSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curNode = &it->second;
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[listSection appendString:@"</table>"];
|
[listSection appendString:@"</table>"];
|
||||||
|
|
||||||
[lists addObject:listSection];
|
[lists addObject:listSection];
|
||||||
|
|
Loading…
Reference in a new issue