FileManager: Add file properties tab for PDF documents

This commit is contained in:
Sam Atkins 2023-07-26 12:04:13 +01:00 committed by Sam Atkins
parent a333d9959c
commit 7c8772ad86
4 changed files with 247 additions and 1 deletions

View file

@ -12,6 +12,7 @@ compile_gml(PropertiesWindowAudioTab.gml PropertiesWindowAudioTabGML.h propertie
compile_gml(PropertiesWindowFontTab.gml PropertiesWindowFontTabGML.h properties_window_font_tab_gml)
compile_gml(PropertiesWindowGeneralTab.gml PropertiesWindowGeneralTabGML.h properties_window_general_tab_gml)
compile_gml(PropertiesWindowImageTab.gml PropertiesWindowImageTabGML.h properties_window_image_tab_gml)
compile_gml(PropertiesWindowPDFTab.gml PropertiesWindowPDFTabGML.h properties_window_pdf_tab_gml)
set(SOURCES
DesktopWidget.cpp
@ -30,7 +31,8 @@ set(GENERATED_SOURCES
PropertiesWindowFontTabGML.h
PropertiesWindowGeneralTabGML.h
PropertiesWindowImageTabGML.h
PropertiesWindowPDFTabGML.h
)
serenity_app(FileManager ICON app-file-manager)
target_link_libraries(FileManager PRIVATE LibArchive LibAudio LibCore LibFileSystem LibGfx LibGUI LibDesktop LibConfig LibMain LibThreading)
target_link_libraries(FileManager PRIVATE LibArchive LibAudio LibConfig LibCore LibDesktop LibFileSystem LibGfx LibGUI LibMain LibPDF LibThreading)

View file

@ -16,6 +16,7 @@
#include <Applications/FileManager/PropertiesWindowFontTabGML.h>
#include <Applications/FileManager/PropertiesWindowGeneralTabGML.h>
#include <Applications/FileManager/PropertiesWindowImageTabGML.h>
#include <Applications/FileManager/PropertiesWindowPDFTabGML.h>
#include <LibArchive/Zip.h>
#include <LibAudio/Loader.h>
#include <LibCore/Directory.h>
@ -39,6 +40,7 @@
#include <LibGfx/Font/WOFF/Font.h>
#include <LibGfx/ICC/Profile.h>
#include <LibGfx/ICC/Tags.h>
#include <LibPDF/Document.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
@ -238,6 +240,9 @@ ErrorOr<void> PropertiesWindow::create_file_type_specific_tabs(GUI::TabWidget& t
if (mime_type.starts_with("image/"sv))
return create_image_tab(tab_widget, move(mapped_file), mime_type);
if (mime_type == "application/pdf"sv)
return create_pdf_tab(tab_widget, move(mapped_file));
return {};
}
@ -451,6 +456,59 @@ ErrorOr<void> PropertiesWindow::create_image_tab(GUI::TabWidget& tab_widget, Non
return {};
}
ErrorOr<void> PropertiesWindow::create_pdf_tab(GUI::TabWidget& tab_widget, NonnullRefPtr<Core::MappedFile> mapped_file)
{
auto maybe_document = PDF::Document::create(mapped_file->bytes());
if (maybe_document.is_error()) {
warnln("Failed to open '{}': {}", m_path, maybe_document.error().message());
return {};
}
auto document = maybe_document.release_value();
if (auto handler = document->security_handler(); handler && !handler->has_user_password()) {
// FIXME: Show a password dialog, once we've switched to lazy-loading
auto tab = TRY(tab_widget.try_add_tab<GUI::Label>("PDF"_short_string));
tab->set_text(TRY("PDF is password-protected."_string));
return {};
}
if (auto maybe_error = document->initialize(); maybe_error.is_error()) {
warnln("PDF '{}' seems to be invalid: {}", m_path, maybe_error.error().message());
return {};
}
auto tab = TRY(tab_widget.try_add_tab<GUI::Widget>("PDF"_short_string));
TRY(tab->load_from_gml(properties_window_pdf_tab_gml));
tab->find_descendant_of_type_named<GUI::Label>("pdf_version")->set_text(TRY(String::formatted("{}.{}", document->version().major, document->version().minor)));
tab->find_descendant_of_type_named<GUI::Label>("pdf_page_count")->set_text(TRY(String::number(document->get_page_count())));
auto maybe_info_dict = document->info_dict();
if (maybe_info_dict.is_error()) {
warnln("Failed to read InfoDict from '{}': {}", m_path, maybe_info_dict.error().message());
} else if (maybe_info_dict.value().has_value()) {
auto get_info_string = [](PDF::PDFErrorOr<Optional<DeprecatedString>> input) -> ErrorOr<String> {
if (input.is_error())
return String {};
if (!input.value().has_value())
return String {};
return String::from_deprecated_string(input.value().value());
};
auto info_dict = maybe_info_dict.release_value().release_value();
tab->find_descendant_of_type_named<GUI::Label>("pdf_title")->set_text(TRY(get_info_string(info_dict.title())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_author")->set_text(TRY(get_info_string(info_dict.author())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_subject")->set_text(TRY(get_info_string(info_dict.subject())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_keywords")->set_text(TRY(get_info_string(info_dict.keywords())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_creator")->set_text(TRY(get_info_string(info_dict.creator())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_producer")->set_text(TRY(get_info_string(info_dict.producer())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_creation_date")->set_text(TRY(get_info_string(info_dict.creation_date())));
tab->find_descendant_of_type_named<GUI::Label>("pdf_modification_date")->set_text(TRY(get_info_string(info_dict.modification_date())));
}
return {};
}
void PropertiesWindow::update()
{
m_icon->set_bitmap(GUI::FileIconProvider::icon_for_path(make_full_path(m_name), m_mode).bitmap_for_size(32));

View file

@ -34,6 +34,7 @@ private:
ErrorOr<void> create_audio_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>);
ErrorOr<void> create_font_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>, StringView mime_type);
ErrorOr<void> create_image_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>, StringView mime_type);
ErrorOr<void> create_pdf_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>);
struct PermissionMasks {
mode_t read;

View file

@ -0,0 +1,185 @@
@GUI::Widget {
layout: @GUI::VerticalBoxLayout {
margins: [8]
spacing: 12
}
@GUI::GroupBox {
title: "PDF"
preferred_height: "shrink"
layout: @GUI::VerticalBoxLayout {
margins: [12, 8, 0]
spacing: 2
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Version:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_version"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Page count:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_page_count"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Title:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_title"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Author:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_author"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Subject:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_subject"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Keywords:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_keywords"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Creator:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_creator"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Producer:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_producer"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Created:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_creation_date"
text_alignment: "TopLeft"
}
}
@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 12
}
@GUI::Label {
text: "Modified:"
text_alignment: "TopLeft"
fixed_width: 80
}
@GUI::Label {
name: "pdf_modification_date"
text_alignment: "TopLeft"
}
}
}
}