Skip to content

Commit

Permalink
multiple files storage, added configurable option to use for the embe…
Browse files Browse the repository at this point in the history
…dded files a constant name (#2354)
  • Loading branch information
giuspen committed Jan 16, 2025
1 parent 85fce26 commit c33fb4b
Show file tree
Hide file tree
Showing 25 changed files with 276 additions and 75 deletions.
41 changes: 29 additions & 12 deletions src/ct/ct_actions_edit.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_actions_find.cc
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -212,28 +212,45 @@ void CtActions::embfile_insert_path(const std::string& filepath)
if (not _node_sel_and_rich_text()) return;
if (not _is_curr_node_not_read_only_or_error()) return;

if (fs::file_size(filepath) > static_cast<uintmax_t>(_pCtConfig->embfileMaxSize * 1024 * 1024)) {
bool is_sqlite = fs::get_doc_type_from_file_ext(_pCtMainWin->get_ct_storage()->get_file_path()) == CtDocType::SQLite;
auto message = str::format(_("The Maximum Size for Embedded Files is %s MB."), _pCtConfig->embfileMaxSize);
if (is_sqlite) {
if (not CtDialogs::question_dialog(message + "\n" + _("Do you want to Continue?"), *_pCtMainWin))
return;
std::string blob;
const bool embfileMFNameOnDisk = _pCtConfig->embfileMFNameOnDisk and fs::is_directory(_pCtMainWin->get_ct_storage()->get_file_path());

const std::string name = Glib::path_get_basename(filepath);
fs::path embfilePath;
if (embfileMFNameOnDisk) {
embfilePath = _pCtMainWin->get_ct_storage()->get_embedded_filepath(_pCtMainWin->curr_tree_iter(), name);
if (not fs::exists(embfilePath)) {
const bool copyRes = fs::copy_file(filepath, embfilePath);
spdlog::debug("{} {} {} -> {}", __FUNCTION__, copyRes ? "OK":"!!", filepath.c_str(), embfilePath.c_str());
}
else {
CtDialogs::error_dialog(message, *_pCtMainWin);
return;
spdlog::debug("{} ?? {} exists", __FUNCTION__, embfilePath.c_str());
}
}
else {
if (fs::file_size(filepath) > static_cast<uintmax_t>(_pCtConfig->embfileMaxSize * 1024 * 1024)) {
bool is_sqlite = fs::get_doc_type_from_file_ext(_pCtMainWin->get_ct_storage()->get_file_path()) == CtDocType::SQLite;
auto message = str::format(_("The Maximum Size for Embedded Files is %s MB."), _pCtConfig->embfileMaxSize);
if (is_sqlite) {
if (not CtDialogs::question_dialog(message + "\n" + _("Do you want to Continue?"), *_pCtMainWin))
return;
}
else {
CtDialogs::error_dialog(message, *_pCtMainWin);
return;
}
}
blob = Glib::file_get_contents(filepath);
}

std::string blob = Glib::file_get_contents(filepath);
std::string name = Glib::path_get_basename(filepath);
CtAnchoredWidget* pAnchoredWidget = new CtImageEmbFile{_pCtMainWin,
name,
blob,
std::time(nullptr),
_curr_buffer()->get_insert()->get_iter().get_offset(),
"",
CtImageEmbFile::get_next_unique_id()};
CtImageEmbFile::get_next_unique_id(),
embfilePath.empty() ? embfilePath : embfilePath.parent_path()};
pAnchoredWidget->insertInTextBuffer(_curr_buffer());

_pCtMainWin->get_tree_store().addAnchoredWidgets(_pCtMainWin->curr_tree_iter(),
Expand Down
4 changes: 2 additions & 2 deletions src/ct/ct_actions_export.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_actions_export.cc
*
* Copyright 2009-2023
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -82,7 +82,7 @@ void CtActions::export_to_ct()
start_offset = iter_sel_start.get_offset();
end_offset = iter_sel_end.get_offset();
}
const fs::path currDocFilepath = _pCtMainWin->get_ct_storage()->get_file_path();
const fs::path& currDocFilepath = _pCtMainWin->get_ct_storage()->get_file_path();
CtDialogs::CtStorageSelectArgs storageSelArgs{};
if (not currDocFilepath.empty()) {
storageSelArgs.ctDocType = fs::get_doc_type_from_file_ext(currDocFilepath);
Expand Down
5 changes: 3 additions & 2 deletions src/ct/ct_actions_file.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_actions_file.cc
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -60,7 +60,7 @@ void CtActions::file_save_as()
}
CtDialogs::CtStorageSelectArgs storageSelArgs{};
storageSelArgs.showAutosaveOptions = true;
const fs::path currDocFilepath = _pCtMainWin->get_ct_storage()->get_file_path();
const fs::path& currDocFilepath = _pCtMainWin->get_ct_storage()->get_file_path();
if (not currDocFilepath.empty()) {
storageSelArgs.ctDocType = fs::get_doc_type_from_file_ext(currDocFilepath);
storageSelArgs.ctDocEncrypt = fs::get_doc_encrypt_from_file_ext(currDocFilepath);
Expand Down Expand Up @@ -228,6 +228,7 @@ void CtActions::preferences_import()
_pCtConfig->latexSizeDpi = ctConfigImported.latexSizeDpi;
_pCtConfig->embfileIconSize = ctConfigImported.embfileIconSize;
_pCtConfig->embfileShowFileName = ctConfigImported.embfileShowFileName;
_pCtConfig->embfileMFNameOnDisk = ctConfigImported.embfileMFNameOnDisk;
_pCtConfig->embfileMaxSize = ctConfigImported.embfileMaxSize;
_pCtConfig->lineWrapping = ctConfigImported.lineWrapping;
_pCtConfig->autoSmartQuotes = ctConfigImported.autoSmartQuotes;
Expand Down
16 changes: 16 additions & 0 deletions src/ct/ct_actions_others.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,27 @@ void CtActions::embfile_save()
if (filepath.empty()) return;

_pCtConfig->pickDirFile = Glib::path_get_dirname(filepath);

if (curr_file_anchor->get_raw_blob().empty() and not curr_file_anchor->get_dirLastMultiFile().empty()) {
const fs::path embfilePathLast = curr_file_anchor->get_dirLastMultiFile() / curr_file_anchor->get_file_name();
if (fs::exists(embfilePathLast) and fs::copy_file(embfilePathLast, filepath.c_str())) {
return;
}
}

g_file_set_contents(filepath.c_str(), curr_file_anchor->get_raw_blob().c_str(), (gssize)curr_file_anchor->get_raw_blob().size(), nullptr);
}

void CtActions::embfile_open()
{
if (curr_file_anchor->get_raw_blob().empty() and not curr_file_anchor->get_dirLastMultiFile().empty()) {
const fs::path embfilePathLast = curr_file_anchor->get_dirLastMultiFile() / curr_file_anchor->get_file_name();
if (fs::exists(embfilePathLast)) {
fs::open_filepath(embfilePathLast, false/*open_folder_if_file_not_exists*/, _pCtConfig);
return;
}
}

const size_t open_id = curr_file_anchor->get_unique_id();
auto mapIter = _embfiles_opened.find(open_id);
fs::path tmp_filepath;
Expand Down
4 changes: 3 additions & 1 deletion src/ct/ct_config.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_config.cc
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -293,6 +293,7 @@ void CtConfig::_populate_keyfile_from_data()
_uKeyFile->set_integer(_currentGroup, "latex_size_dpi", latexSizeDpi);
_uKeyFile->set_integer(_currentGroup, "embfile_icon_size", embfileIconSize);
_uKeyFile->set_boolean(_currentGroup, "embfile_show_filename", embfileShowFileName);
_uKeyFile->set_boolean(_currentGroup, "embfile_mfname_ondisk", embfileMFNameOnDisk);
_uKeyFile->set_integer(_currentGroup, "embfile_max_size", embfileMaxSize);
_uKeyFile->set_boolean(_currentGroup, "line_wrapping", lineWrapping);
_uKeyFile->set_boolean(_currentGroup, "auto_smart_quotes", autoSmartQuotes);
Expand Down Expand Up @@ -606,6 +607,7 @@ void CtConfig::_populate_data_from_keyfile()
_populate_int_from_keyfile("latex_size_dpi", &latexSizeDpi);
_populate_int_from_keyfile("embfile_icon_size", &embfileIconSize);
_populate_bool_from_keyfile("embfile_show_filename", &embfileShowFileName);
_populate_bool_from_keyfile("embfile_mfname_ondisk", &embfileMFNameOnDisk);
_populate_int_from_keyfile("embfile_max_size", &embfileMaxSize);
_populate_bool_from_keyfile("line_wrapping", &lineWrapping);
_populate_bool_from_keyfile("auto_smart_quotes", &autoSmartQuotes);
Expand Down
3 changes: 2 additions & 1 deletion src/ct/ct_config.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_config.h
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -123,6 +123,7 @@ class CtConfig
int latexSizeDpi{140};
int embfileIconSize{48};
bool embfileShowFileName{true};
bool embfileMFNameOnDisk{false};
int embfileMaxSize{10};
bool lineWrapping{true};
bool autoSmartQuotes{true};
Expand Down
104 changes: 86 additions & 18 deletions src/ct/ct_image.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_image.cc
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -592,18 +592,56 @@ CtImageEmbFile::CtImageEmbFile(CtMainWin* pCtMainWin,
const time_t timeSeconds,
const int charOffset,
const std::string& justification,
const size_t uniqueId)
const size_t uniqueId,
const fs::path& dirLastMultiFile)
: CtImage{pCtMainWin, _get_file_icon(pCtMainWin, fileName), charOffset, justification}
, _fileName{fileName}
, _rawBlob{rawBlob}
, _timeSeconds{timeSeconds}
, _uniqueId{uniqueId}
, _dirLastMultiFile{dirLastMultiFile}
{
signal_button_press_event().connect(sigc::mem_fun(*this, &CtImageEmbFile::_on_button_press_event), false);
update_tooltip();
update_label_widget();
}

void CtImageEmbFile::_checkNonEmptyRawBlob(const char* multifile_dir)
{
if (not _rawBlob.empty()) {
return;
}
// an embedded file can potentially be empty, but if that is the case, we will check if a constant file name exists
if (multifile_dir and multifile_dir[0]) {
// the current data format is multifile, let's check in the current multifile directory
const fs::path embfilePath = fs::path{multifile_dir} / _fileName;
if (fs::exists(embfilePath)) {
_rawBlob = Glib::file_get_contents(embfilePath.string());
spdlog::debug("{} FROM multifile constant {}", __FUNCTION__, embfilePath.c_str());
}
else {
spdlog::warn("?? {} missing {}", __FUNCTION__, embfilePath.c_str());
}
}
if (not _rawBlob.empty()) {
return;
}
// let's check also if the embedded file was copied/moved and the original file is still in the old directory
if (not _dirLastMultiFile.empty()) {
const fs::path embfilePathLast = _dirLastMultiFile / _fileName;
if (fs::exists(embfilePathLast)) {
_rawBlob = Glib::file_get_contents(embfilePathLast.string());
spdlog::debug("{} FROM multifile constant foreign {}", __FUNCTION__, embfilePathLast.string());
}
else {
spdlog::warn("?? missing foreign {}", __FUNCTION__, embfilePathLast.c_str());
}
}
else {
spdlog::warn("?? {} {} empty _dirLastMultiFile", __FUNCTION__, _fileName.c_str());
}
}

void CtImageEmbFile::to_xml(xmlpp::Element* p_node_parent,
const int offset_adjustment,
CtStorageCache*,
Expand All @@ -615,12 +653,35 @@ void CtImageEmbFile::to_xml(xmlpp::Element* p_node_parent,
p_image_node->set_attribute("filename", _fileName.string());
p_image_node->set_attribute("time", std::to_string(_timeSeconds));
if (multifile_dir.empty()) {
// target is not multifile
_checkNonEmptyRawBlob(nullptr/*multifile_dir*/);
const std::string encodedBlob = Glib::Base64::encode(_rawBlob);
p_image_node->add_child_text(encodedBlob);
}
else {
const std::string sha256sum = CtStorageMultiFile::save_blob(_rawBlob, multifile_dir, _fileName.extension());
p_image_node->set_attribute("sha256sum", sha256sum);
// target is multifile
if (_pCtMainWin->get_ct_config()->embfileMFNameOnDisk) {
// save as multifile constant name on disk - we are not touching the file if it already exists!
const fs::path embfilePath = fs::path{multifile_dir} / _fileName;
if (not fs::exists(embfilePath)) {
_checkNonEmptyRawBlob(multifile_dir.c_str());
Glib::file_set_contents(embfilePath.string(), _rawBlob);
if (fs::exists(embfilePath)) {
spdlog::debug("{} written multifile constant name {}, cleared _rawBlob", __FUNCTION__, embfilePath.c_str());
_dirLastMultiFile = multifile_dir;
_rawBlob.clear();
}
else {
spdlog::warn("!! {} multifile constant name {} could not write", __FUNCTION__, embfilePath.c_str());
}
}
}
else {
// save as multifile with sha256 as name
_checkNonEmptyRawBlob(multifile_dir.c_str());
const std::string sha256sum = CtStorageMultiFile::save_blob(_rawBlob, multifile_dir, _fileName.extension());
p_image_node->set_attribute("sha256sum", sha256sum);
}
}
}

Expand All @@ -638,6 +699,7 @@ bool CtImageEmbFile::to_sqlite(sqlite3* pDb, const gint64 node_id, const int off
sqlite3_bind_int64(p_stmt, 2, _charOffset+offset_adjustment);
sqlite3_bind_text(p_stmt, 3, _justification.c_str(), _justification.size(), SQLITE_STATIC);
sqlite3_bind_text(p_stmt, 4, "", -1, SQLITE_STATIC); // anchor
_checkNonEmptyRawBlob(nullptr/*multifile_dir*/);
sqlite3_bind_blob(p_stmt, 5, _rawBlob.c_str(), _rawBlob.size(), SQLITE_STATIC);
sqlite3_bind_text(p_stmt, 6, file_name.c_str(), file_name.size(), SQLITE_STATIC);
sqlite3_bind_text(p_stmt, 7, "", -1, SQLITE_STATIC); // link
Expand Down Expand Up @@ -670,21 +732,26 @@ void CtImageEmbFile::update_label_widget()

void CtImageEmbFile::update_tooltip()
{
char humanReadableSize[16];
const size_t embfileBytes{_rawBlob.size()};
const double embfileKbytes{static_cast<double>(embfileBytes)/1024};
const double embfileMbytes{embfileKbytes/1024};
if (embfileMbytes > 1) {
snprintf(humanReadableSize, 16, "%.1f MB", embfileMbytes);
if (embfileBytes > 0u) {
const double embfileKbytes{static_cast<double>(embfileBytes)/1024};
const double embfileMbytes{embfileKbytes/1024};
char humanReadableSize[16];
if (embfileMbytes > 1) {
snprintf(humanReadableSize, 16, "%.1f MB", embfileMbytes);
}
else {
snprintf(humanReadableSize, 16, "%.1f KB", embfileKbytes);
}
const Glib::DateTime dateTime{Glib::DateTime::create_now_local(static_cast<gint64>(_timeSeconds))};
const Glib::ustring strDateTime = dateTime.format(_pCtMainWin->get_ct_config()->timestampFormat);
char buffTooltip[128];
snprintf(buffTooltip, 128, "%s\n%s (%zu Bytes)\n%s", _fileName.c_str(), humanReadableSize, embfileBytes, strDateTime.c_str());
set_tooltip_text(buffTooltip);
}
else {
snprintf(humanReadableSize, 16, "%.1f KB", embfileKbytes);
set_tooltip_text(_fileName.string());
}
const Glib::DateTime dateTime{Glib::DateTime::create_now_local(static_cast<gint64>(_timeSeconds))};
const Glib::ustring strDateTime = dateTime.format(_pCtMainWin->get_ct_config()->timestampFormat);
char buffTooltip[128];
snprintf(buffTooltip, 128, "%s\n%s (%zu Bytes)\n%s", _fileName.c_str(), humanReadableSize, embfileBytes, strDateTime.c_str());
set_tooltip_text(buffTooltip);
}

/*static*/Glib::RefPtr<Gdk::Pixbuf> CtImageEmbFile::_get_file_icon(CtMainWin* pCtMainWin, const fs::path& fileName)
Expand All @@ -711,10 +778,11 @@ bool CtImageEmbFile::_on_button_press_event(GdkEventButton* event)
{
_pCtMainWin->get_ct_actions()->curr_file_anchor = this;
_pCtMainWin->get_ct_actions()->object_set_selection(this);
if (event->button == 3)
if (event->button == 3) {
_pCtMainWin->get_ct_menu().get_popup_menu(CtMenu::POPUP_MENU_TYPE::EmbFile)->popup(event->button, event->time);
else if (event->type == GDK_2BUTTON_PRESS)
}
else if (event->type == GDK_2BUTTON_PRESS) {
_pCtMainWin->get_ct_actions()->embfile_open();

}
return true; // do not propagate the event
}
8 changes: 6 additions & 2 deletions src/ct/ct_image.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ct_image.h
*
* Copyright 2009-2024
* Copyright 2009-2025
* Giuseppe Penone <giuspen@gmail.com>
* Evgenii Gurianov <https://github.com/txe>
*
Expand Down Expand Up @@ -175,7 +175,8 @@ class CtImageEmbFile : public CtImage
const time_t timeSeconds,
const int charOffset,
const std::string& justification,
const size_t uniqueId);
const size_t uniqueId,
const fs::path& dirLastMultiFile);
~CtImageEmbFile() override {}

void to_xml(xmlpp::Element* p_node_parent, const int offset_adjustment, CtStorageCache* cache, const std::string& multifile_dir) override;
Expand All @@ -190,6 +191,7 @@ class CtImageEmbFile : public CtImage
time_t get_time() { return _timeSeconds; }
void set_time(const time_t time) { _timeSeconds = time; }
size_t get_unique_id() { return _uniqueId; }
const fs::path& get_dirLastMultiFile() { return _dirLastMultiFile; }

static size_t get_next_unique_id();

Expand All @@ -201,10 +203,12 @@ class CtImageEmbFile : public CtImage

private:
bool _on_button_press_event(GdkEventButton* event);
void _checkNonEmptyRawBlob(const char* multifile_dir);

protected:
fs::path _fileName;
std::string _rawBlob; // raw data, not a string
time_t _timeSeconds;
const size_t _uniqueId;
fs::path _dirLastMultiFile;
};
Loading

0 comments on commit c33fb4b

Please sign in to comment.