Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ find_package(chmlib CONFIG REQUIRED)
find_package(lexbor CONFIG REQUIRED)
find_package(maddy CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(pdfium CONFIG REQUIRED)
find_package(pdfium CONFIG REQUIRED )
find_package(wxWidgets CONFIG REQUIRED COMPONENTS webview)
find_package(Poco REQUIRED COMPONENTS Foundation XML)
find_package(wxWidgets CONFIG REQUIRED)
find_package(Gettext)

if(GETTEXT_FOUND)
Expand Down Expand Up @@ -95,8 +95,11 @@ target_link_libraries(paperback PRIVATE
wx::base
wx::core
wx::net
wx::webview
)

if(WIN32)
target_link_libraries(paperback PRIVATE "${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/lib/WebView2LoaderStatic.lib")
endif()
if(WIN32)
file(GLOB DLLS "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/*.dll")
set(LOCAL_DLLS "")
Expand Down Expand Up @@ -157,4 +160,4 @@ if(WIN32)
endif()
else()
add_custom_target(release DEPENDS package)
endif()
endif()
2 changes: 2 additions & 0 deletions src/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ enum {
ID_NEXT_LINK,
ID_PREVIOUS_LINK,
ID_ACTIVATE_LINK,
ID_PREVIOUS_TABLE,
ID_NEXT_TABLE,
ID_PREVIOUS_LIST,
ID_NEXT_LIST,
ID_PREVIOUS_LIST_ITEM,
Expand Down
7 changes: 7 additions & 0 deletions src/document.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ struct heading_info {
std::string text;
};

struct table_info {
size_t offset;
std::string text;
std::string ref;
};

struct document_stats {
size_t word_count{0};
size_t line_count{0};
Expand All @@ -48,6 +54,7 @@ struct document {
document_buffer buffer;
std::vector<std::unique_ptr<toc_item>> toc_items;
std::map<std::string, size_t> id_positions;
std::map<size_t, wxString> html_tables;
std::vector<std::string> spine_items;
std::map<std::string, std::string> manifest_items;
mutable document_stats stats;
Expand Down
6 changes: 6 additions & 0 deletions src/document_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,16 @@ void document_buffer::add_link(int pos, const wxString& text, const wxString& re
markers.emplace_back(pos, marker_type::link, text, ref, 0);
}


void document_buffer::finalize_markers() {
sort_markers();
}

void document_buffer::add_table(int pos, const wxString& text, const wxString& ref) {
markers.emplace_back(pos, marker_type::table, text, ref, 0);
sort_markers();
}

void document_buffer::add_marker(int pos, marker_type type, const wxString& text, const wxString& ref, int level) {
if (is_heading_marker(type) && level == 0) {
level = heading_level_from_type(type);
Expand Down
2 changes: 2 additions & 0 deletions src/document_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum class marker_type {
section_break,
toc_item,
link,
table,
list,
list_item
};
Expand Down Expand Up @@ -67,6 +68,7 @@ class document_buffer {
void add_section_break(const wxString& label = wxString());
void add_toc_marker(const wxString& text, const wxString& ref = wxString());
void add_link(int pos, const wxString& text, const wxString& ref);
void add_table(int pos, const wxString& text, const wxString& ref);
void add_marker(int pos, marker_type type, const wxString& text = wxString(), const wxString& ref = wxString(), int level = 0);
void finalize_markers();
void clear();
Expand Down
73 changes: 72 additions & 1 deletion src/document_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "dialogs.hpp"
#include "document.hpp"
#include "document_buffer.hpp"
#include "table_dialog.hpp"
#include "main_window.hpp"
#include "parser.hpp"
#include "utils.hpp"
Expand Down Expand Up @@ -441,6 +442,54 @@ void document_manager::go_to_next_link() const {
navigate_to_link(true);
}



void document_manager::go_to_previous_table() {
document* doc = get_active_document();
wxTextCtrl* text_ctrl = get_active_text_ctrl();
if (!doc || !text_ctrl) {
return;
}
if (doc->buffer.count_markers_by_type(marker_type::table) == 0) {
speak(_("No tables."));
return;
}
int current_pos = text_ctrl->GetInsertionPoint();
int prev_index = doc->buffer.previous_marker_index(current_pos, marker_type::table);
if (prev_index == -1) {
speak(_("No previous table."));
return;
}
const marker* table_marker = doc->buffer.get_marker(prev_index);
if (table_marker) {
go_to_position(table_marker->pos);
speak(table_marker->text);
}
}

void document_manager::go_to_next_table() {
document* doc = get_active_document();
wxTextCtrl* text_ctrl = get_active_text_ctrl();
if (!doc || !text_ctrl) {
return;
}
if (doc->buffer.count_markers_by_type(marker_type::table) == 0) {
speak(_("No tables."));
return;
}
int current_pos = text_ctrl->GetInsertionPoint();
int next_index = doc->buffer.next_marker_index(current_pos, marker_type::table);
if (next_index == -1) {
speak(_("No next table."));
return;
}
const marker* table_marker = doc->buffer.get_marker(next_index);
if (table_marker) {
go_to_position(table_marker->pos);
speak(table_marker->text);
}
}

void document_manager::activate_current_link() const {
document* doc = get_active_document();
const wxTextCtrl* text_ctrl = get_active_text_ctrl();
Expand Down Expand Up @@ -522,6 +571,28 @@ void document_manager::activate_current_link() const {
}
}

void document_manager::activate_current_table() {
document* doc = get_active_document();
wxTextCtrl* text_ctrl = get_active_text_ctrl();
if (!doc || !text_ctrl) {
return;
}
int current_pos = text_ctrl->GetInsertionPoint();
int table_index = doc->buffer.current_marker_index(current_pos, marker_type::table);
if (table_index == -1) {
return;
}
const marker* table_marker = doc->buffer.get_marker(table_index);
if (!table_marker) {
return;
}
if (current_pos < table_marker->pos || current_pos > (table_marker->pos + table_marker->text.length())) {
return;
}
table_dialog dlg(&main_win, _("Table"), table_marker->ref);
dlg.ShowModal();
}

void document_manager::navigate_to_list(bool next) const {
const document* doc = get_active_document();
wxTextCtrl* text_ctrl = get_active_text_ctrl();
Expand Down Expand Up @@ -665,7 +736,7 @@ void document_manager::toggle_bookmark() const {
std::vector<bookmark> bookmarks = config.get_bookmarks(tab->file_path);
bookmark to_toggle(bookmark_start, bookmark_end);
bool was_bookmarked = false;
for (const auto& bm : bookmarks) {
for (const auto& bm : bookmarks) {
if (bm == to_toggle) {
was_bookmarked = true;
break;
Expand Down
3 changes: 3 additions & 0 deletions src/document_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class document_manager {
void go_to_next_bookmark() const;
void go_to_previous_link() const;
void go_to_next_link() const;
void go_to_previous_table();
void go_to_next_table();
void activate_current_table();
void go_to_previous_list() const;
void go_to_next_list() const;
void go_to_previous_list_item() const;
Expand Down
70 changes: 68 additions & 2 deletions src/docx_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,13 @@ void docx_parser::traverse(Node* node, wxString& text, std::vector<heading_info>
}
if (local_name == "p") {
process_paragraph(element, text, headings, doc, rels);
return; // process_paragraph handles its children
}
return;
} else if (local_name == "tbl") {
auto table_data = process_table(element);
doc->buffer.add_table(text.length(), table_data.first, table_data.second);
text += table_data.first + "\n";
return;
}
}
Node* child = node->firstChild();
while (child != nullptr) {
Expand All @@ -139,6 +144,67 @@ void docx_parser::traverse(Node* node, wxString& text, std::vector<heading_info>
}
}

std::pair<wxString, wxString> docx_parser::process_table(Element* table_element) {
wxString html = "<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">";
wxString placeholder = "table: ";

NodeList* rows = table_element->getElementsByTagNameNS(WORDML_NS, "tr");
for (unsigned long i = 0; i < rows->length(); ++i) {
html += "<tr>";
auto* row = dynamic_cast<Element*>(rows->item(i));
NodeList* cells = row->getElementsByTagNameNS(WORDML_NS, "tc");
for (unsigned long j = 0; j < cells->length(); ++j) {
auto* cell = dynamic_cast<Element*>(cells->item(j));
wxString cell_text = get_cell_text(cell);

if (i == 0) {
placeholder += cell_text + " ";
}

wxString style;
Element* tcPr = cell->getChildElementNS(WORDML_NS, "tcPr");
if (tcPr) {
Element* tcW = tcPr->getChildElementNS(WORDML_NS, "tcW");
if (tcW) {
std::string width_str = tcW->getAttributeNS(WORDML_NS, "w");
if (!width_str.empty()) {
try {
double width = std::stod(width_str);
style += wxString::Format("width: %.2fpt;", width / 20.0);
} catch (...) {
// Ignore invalid width values
}
}
}
}

html += wxString::Format("<td style=\"%s\">%s</td>", style, cell_text);
}
html += "</tr>";
}
html += "</table>";

placeholder.Trim();
return {placeholder, html};
}

wxString docx_parser::get_cell_text(Element* cell_element) {
wxString cell_text;
NodeList* paragraphs = cell_element->getElementsByTagNameNS(WORDML_NS, "p");
for (unsigned long i = 0; i < paragraphs->length(); ++i) {
auto* p_element = dynamic_cast<Element*>(paragraphs->item(i));
NodeList* runs = p_element->getElementsByTagNameNS(WORDML_NS, "r");
for (unsigned long j = 0; j < runs->length(); ++j) {
auto* run_element = dynamic_cast<Element*>(runs->item(j));
cell_text += wxString::FromUTF8(get_run_text(run_element));
}
if (i < paragraphs->length() - 1) {
cell_text += "\n";
}
}
return cell_text;
}

void docx_parser::process_paragraph(Element* element, wxString& text, std::vector<heading_info>& headings, document* doc, const std::map<std::string, std::string>& rels) {
wxString paragraph_text;
int heading_level = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/docx_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class docx_parser : public parser {
static void process_hyperlink(Poco::XML::Element* element, wxString& text, document* doc, const std::map<std::string, std::string>& rels, size_t paragraph_start_offset);
static int get_heading_level(Poco::XML::Element* pr_element);
static std::string get_run_text(Poco::XML::Element* prun_element);
static std::pair<wxString, wxString> process_table(Poco::XML::Element* table_element);
static wxString get_cell_text(Poco::XML::Element* cell_element);
static std::string parse_hyperlink_instruction(const std::string& instruction);
};

Expand Down
4 changes: 4 additions & 0 deletions src/epub_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ void epub_parser::process_section_content(conv& converter, const std::string& co
const auto& text = converter.get_text();
const auto& headings = converter.get_headings();
const auto& links = converter.get_links();
const auto& tables = converter.get_tables();
const auto& lists = converter.get_lists();
const auto& list_items = converter.get_list_items();
const auto& id_positions = converter.get_id_positions();
Expand Down Expand Up @@ -221,6 +222,9 @@ void epub_parser::process_section_content(conv& converter, const std::string& co
}
buffer.add_link(section_start + link.offset, wxString::FromUTF8(link.text), resolved_href);
}
for (const auto& table : tables) {
buffer.add_table(section_start + table.offset, wxString::FromUTF8(table.text), wxString::FromUTF8(table.ref));
}
for (const auto& list : lists) {
buffer.add_marker(section_start + list.offset, marker_type::list, wxString(), wxString(), list.item_count);
}
Expand Down
4 changes: 4 additions & 0 deletions src/html_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ std::unique_ptr<document> html_parser::load(const wxString& path) const {
for (const auto& link : links) {
doc->buffer.add_link(link.offset, wxString::FromUTF8(link.text), wxString::FromUTF8(link.ref));
}
const auto& tables = converter.get_tables();
for (const auto& table : tables) {
doc->buffer.add_table(table.offset, wxString::FromUTF8(table.text), wxString::FromUTF8(table.ref));
}
for (const auto& list : lists) {
doc->buffer.add_marker(list.offset, marker_type::list, wxString(), wxString(), list.item_count);
}
Expand Down
Loading