Working open & open & edit
parent
e4a4fde97d
commit
569dc10d47
139
src/draw.cc
139
src/draw.cc
|
@ -163,6 +163,11 @@ void Draw::populate_popup(Gtk::Menu *menu)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Show a message on screen
|
||||
* \param message Headliner
|
||||
* \param detailed_info Additional text info
|
||||
*/
|
||||
void Draw::showMessage(const std::string &message, const std::string &detailed_info)
|
||||
{
|
||||
if (get_editable())
|
||||
|
@ -176,6 +181,9 @@ void Draw::showMessage(const std::string &message, const std::string &detailed_i
|
|||
this->insertText(detailed_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draw homepage
|
||||
*/
|
||||
void Draw::showStartPage()
|
||||
{
|
||||
if (get_editable())
|
||||
|
@ -194,7 +202,8 @@ This browser has even a built-in editor. Check it out in the menu: File->New Doc
|
|||
}
|
||||
|
||||
/**
|
||||
* Process AST document (markdown format) and draw the text in the GTK TextView
|
||||
* \brief Process AST document (markdown format) and draw the text in the GTK TextView
|
||||
* \param root_node Markdown AST tree that will be displayed on screen
|
||||
*/
|
||||
void Draw::processDocument(cmark_node *root_node)
|
||||
{
|
||||
|
@ -225,6 +234,9 @@ void Draw::setViewSourceMenuItem(bool isEnabled)
|
|||
this->addViewSourceMenuItem = isEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Prepare for new document
|
||||
*/
|
||||
void Draw::newDocument()
|
||||
{
|
||||
this->undoPool.clear();
|
||||
|
@ -235,57 +247,35 @@ void Draw::newDocument()
|
|||
grab_focus(); // Claim focus on text view
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieve the current text buffer (not thread-safe)
|
||||
*/
|
||||
std::string Draw::getText()
|
||||
{
|
||||
return get_buffer().get()->get_text();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set text in text buffer (for example plain text) - thead-safe
|
||||
* \param content Content string that needs to be set as buffer text
|
||||
*/
|
||||
void Draw::setText(const std::string &content)
|
||||
{
|
||||
DispatchData *data = g_new0(struct DispatchData, 1);
|
||||
data->buffer = buffer;
|
||||
data->text = content;
|
||||
gdk_threads_add_idle((GSourceFunc)insertPlainTextIdle, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clear all text on the screen
|
||||
*/
|
||||
void Draw::clearText()
|
||||
{
|
||||
auto buffer = get_buffer();
|
||||
buffer->erase(buffer->begin(), buffer->end());
|
||||
}
|
||||
|
||||
void Draw::enableEdit()
|
||||
{
|
||||
set_editable(true);
|
||||
set_cursor_visible(true);
|
||||
auto buffer = get_buffer();
|
||||
this->beginUserActionSignalHandler = buffer->signal_begin_user_action().connect(sigc::mem_fun(this, &Draw::begin_user_action), false);
|
||||
this->endUserActionSignalHandler = buffer->signal_end_user_action().connect(sigc::mem_fun(this, &Draw::end_user_action), false);
|
||||
this->insertTextSignalHandler = buffer->signal_insert().connect(sigc::mem_fun(this, &Draw::on_insert), false);
|
||||
this->deleteTextSignalHandler = buffer->signal_erase().connect(sigc::mem_fun(this, &Draw::on_delete), false);
|
||||
}
|
||||
|
||||
void Draw::disableEdit()
|
||||
{
|
||||
set_editable(false);
|
||||
set_cursor_visible(false);
|
||||
// Disconnect signal handles
|
||||
this->beginUserActionSignalHandler.disconnect();
|
||||
this->endUserActionSignalHandler.disconnect();
|
||||
this->insertTextSignalHandler.disconnect();
|
||||
this->deleteTextSignalHandler.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for links
|
||||
*/
|
||||
void Draw::followLink(Gtk::TextBuffer::iterator &iter)
|
||||
{
|
||||
auto tags = iter.get_tags();
|
||||
for (auto const &tag : tags)
|
||||
{
|
||||
char *url = static_cast<char *>(tag->get_data("url"));
|
||||
if (url != 0 && (strlen(url) > 0))
|
||||
{
|
||||
// Get the URL
|
||||
mainWindow.doRequest(url, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo action (Ctrl + Z)
|
||||
*/
|
||||
|
@ -753,6 +743,47 @@ void Draw::on_delete(const Gtk::TextBuffer::iterator &range_start, const Gtk::Te
|
|||
* Private methods
|
||||
************************************************/
|
||||
|
||||
void Draw::enableEdit()
|
||||
{
|
||||
set_editable(true);
|
||||
set_cursor_visible(true);
|
||||
auto buffer = get_buffer();
|
||||
this->beginUserActionSignalHandler = buffer->signal_begin_user_action().connect(sigc::mem_fun(this, &Draw::begin_user_action), false);
|
||||
this->endUserActionSignalHandler = buffer->signal_end_user_action().connect(sigc::mem_fun(this, &Draw::end_user_action), false);
|
||||
this->insertTextSignalHandler = buffer->signal_insert().connect(sigc::mem_fun(this, &Draw::on_insert), false);
|
||||
this->deleteTextSignalHandler = buffer->signal_erase().connect(sigc::mem_fun(this, &Draw::on_delete), false);
|
||||
}
|
||||
|
||||
void Draw::disableEdit()
|
||||
{
|
||||
set_editable(false);
|
||||
set_cursor_visible(false);
|
||||
// Disconnect signal handles
|
||||
this->beginUserActionSignalHandler.disconnect();
|
||||
this->endUserActionSignalHandler.disconnect();
|
||||
this->insertTextSignalHandler.disconnect();
|
||||
this->deleteTextSignalHandler.disconnect();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for links
|
||||
*/
|
||||
void Draw::followLink(Gtk::TextBuffer::iterator &iter)
|
||||
{
|
||||
auto tags = iter.get_tags();
|
||||
for (auto const &tag : tags)
|
||||
{
|
||||
char *url = static_cast<char *>(tag->get_data("url"));
|
||||
if (url != 0 && (strlen(url) > 0))
|
||||
{
|
||||
// Get the URL
|
||||
mainWindow.doRequest(url, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process and parse each node in the AST
|
||||
*/
|
||||
|
@ -1156,6 +1187,14 @@ void Draw::insertText(std::string text, const std::string &url, CodeTypeEnum cod
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert plain text - thread safe
|
||||
*/
|
||||
void Draw::insertPlainText(const std::string &content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert url link - thread safe
|
||||
*/
|
||||
|
@ -1226,7 +1265,8 @@ void Draw::clearOnThread()
|
|||
gdk_threads_add_idle((GSourceFunc)clearBufferIdle, buffer);
|
||||
}
|
||||
|
||||
/* Looks at all tags covering the position (x, y) in the text view,
|
||||
/**
|
||||
* Looks at all tags covering the position (x, y) in the text view,
|
||||
* and if one of them is a link, change the cursor to the "hands" cursor
|
||||
* typically used by web browsers.
|
||||
*/
|
||||
|
@ -1260,7 +1300,7 @@ void Draw::changeCursor(int x, int y)
|
|||
}
|
||||
|
||||
/**
|
||||
* Insert text on Idle Call function
|
||||
* Insert markup text on Idle call function
|
||||
*/
|
||||
gboolean Draw::insertTextIdle(struct DispatchData *data)
|
||||
{
|
||||
|
@ -1272,7 +1312,18 @@ gboolean Draw::insertTextIdle(struct DispatchData *data)
|
|||
}
|
||||
|
||||
/**
|
||||
* Insert link url on Idle Call function
|
||||
* Insert plain text on Idle call function
|
||||
*/
|
||||
gboolean Draw::insertPlainTextIdle(struct DispatchData *data)
|
||||
{
|
||||
GtkTextIter end_iter;
|
||||
gtk_text_buffer_set_text(data->buffer, data->text.c_str(), -1);
|
||||
g_free(data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert link url on Idle call function
|
||||
*/
|
||||
gboolean Draw::insertLinkIdle(struct DispatchData *data)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
void setViewSourceMenuItem(bool isEnabled);
|
||||
void newDocument();
|
||||
std::string getText();
|
||||
void setText(const std::string &content);
|
||||
void clearText();
|
||||
void undo();
|
||||
void redo();
|
||||
|
@ -122,8 +123,9 @@ private:
|
|||
void disableEdit();
|
||||
void followLink(Gtk::TextBuffer::iterator &iter);
|
||||
void processNode(cmark_node *node, cmark_event_type ev_type);
|
||||
// Helper functions for inserting text
|
||||
// Helper functions for inserting text (thread-safe)
|
||||
void insertText(std::string text, const std::string &url = "", CodeTypeEnum codeType = CodeTypeEnum::NONE);
|
||||
void insertPlainText(const std::string &content);
|
||||
void insertLink(const std::string &text, const std::string &url, const std::string &urlFont = "");
|
||||
void truncateText(int charsTruncated);
|
||||
void encodeText(std::string &string);
|
||||
|
@ -132,6 +134,7 @@ private:
|
|||
void clearOnThread();
|
||||
void changeCursor(int x, int y);
|
||||
static gboolean insertTextIdle(struct DispatchData *data);
|
||||
static gboolean insertPlainTextIdle(struct DispatchData *data);
|
||||
static gboolean insertLinkIdle(struct DispatchData *data);
|
||||
static gboolean truncateTextIdle(struct DispatchData *data);
|
||||
static gboolean clearBufferIdle(GtkTextBuffer *textBuffer);
|
||||
|
|
|
@ -78,6 +78,7 @@ MainWindow::MainWindow()
|
|||
// Menu & toolbar signals
|
||||
m_menu.new_doc.connect(sigc::mem_fun(this, &MainWindow::new_doc)); /*!< Menu item for new document */
|
||||
m_menu.open.connect(sigc::mem_fun(this, &MainWindow::open)); /*!< Menu item for opening existing document */
|
||||
m_menu.open_edit.connect(sigc::mem_fun(this, &MainWindow::open_and_edit)); /*!< Menu item for opening & editing existing document */
|
||||
m_menu.save.connect(sigc::mem_fun(this, &MainWindow::save)); /*!< Menu item for save document */
|
||||
m_menu.save_as.connect(sigc::mem_fun(this, &MainWindow::save_as)); /*!< Menu item for save document as */
|
||||
m_menu.publish.connect(sigc::mem_fun(this, &MainWindow::publish)); /*!< Menu item for publishing */
|
||||
|
@ -112,7 +113,7 @@ MainWindow::MainWindow()
|
|||
m_vbox.pack_start(m_menu, false, false, 0);
|
||||
|
||||
// Editor buttons
|
||||
m_openButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::open));
|
||||
m_openButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::open_and_edit));
|
||||
m_saveButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::save));
|
||||
m_publishButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::publish));
|
||||
m_cutButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::cut));
|
||||
|
@ -400,14 +401,19 @@ MainWindow::MainWindow()
|
|||
#else
|
||||
std::cout << "INFO: Running as Debug mode, opening test.md." << std::endl;
|
||||
// Load test file when developing
|
||||
doRequest("file://../../test.md", true);
|
||||
doRequest("file://../../test.md");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch document from disk or IPFS, using threading
|
||||
* \param path File path that needs to be opened (either from disk or IPFS network)
|
||||
* \param isSetAddressBar If true change update the address bar with the file path (default: true)
|
||||
* \param isHistoryRequest Set to true if this is an history request call: back/forward (default: false)
|
||||
* \param isDisableEditor If true the editor will be disabled if needed (default: true)
|
||||
* \param isParseContext If true the content received will be parsed and displayed as markdown syntax (default: true), set to false if you want to editor the content
|
||||
*/
|
||||
void MainWindow::doRequest(const std::string &path, bool setAddressBar, bool isHistoryRequest)
|
||||
void MainWindow::doRequest(const std::string &path, bool isSetAddressBar, bool isHistoryRequest, bool isDisableEditor, bool isParseContent)
|
||||
{
|
||||
if (m_requestThread)
|
||||
{
|
||||
|
@ -422,8 +428,8 @@ void MainWindow::doRequest(const std::string &path, bool setAddressBar, bool isH
|
|||
|
||||
if (m_requestThread == nullptr)
|
||||
{
|
||||
m_requestThread = new std::thread(&MainWindow::processRequest, this, path);
|
||||
this->postDoRequest(path, setAddressBar, isHistoryRequest);
|
||||
m_requestThread = new std::thread(&MainWindow::processRequest, this, path, isParseContent);
|
||||
this->postDoRequest(path, isSetAddressBar, isHistoryRequest, isDisableEditor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,8 +645,16 @@ void MainWindow::selectAll()
|
|||
*/
|
||||
void MainWindow::new_doc()
|
||||
{
|
||||
// Clear content & requestPath
|
||||
currentContent = "";
|
||||
requestPath = "";
|
||||
|
||||
// Enable editing mode
|
||||
this->enableEdit();
|
||||
// Change address bar
|
||||
this->m_addressBar.set_text("file://unsaved");
|
||||
// Set new title
|
||||
this->set_title("Untitled * - " + m_appName);
|
||||
}
|
||||
|
||||
void MainWindow::open()
|
||||
|
@ -666,14 +680,41 @@ void MainWindow::open()
|
|||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::open_and_edit()
|
||||
{
|
||||
auto dialog = new Gtk::FileChooserDialog("Open & Edit", Gtk::FILE_CHOOSER_ACTION_OPEN);
|
||||
dialog->set_transient_for(*this);
|
||||
dialog->set_modal(true);
|
||||
dialog->signal_response().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::on_open_edit_dialog_response), dialog));
|
||||
dialog->add_button("_Cancel", Gtk::ResponseType::RESPONSE_CANCEL);
|
||||
dialog->add_button("_Open", Gtk::ResponseType::RESPONSE_OK);
|
||||
|
||||
// Add filters, so that only certain file types can be selected:
|
||||
auto filter_markdown = Gtk::FileFilter::create();
|
||||
filter_markdown->set_name("Markdown files (.md)");
|
||||
filter_markdown->add_mime_type("text/markdown");
|
||||
dialog->add_filter(filter_markdown);
|
||||
|
||||
auto filter_any = Gtk::FileFilter::create();
|
||||
filter_any->set_name("Any files");
|
||||
filter_any->add_pattern("*");
|
||||
dialog->add_filter(filter_any);
|
||||
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_open_dialog_response(int response_id, Gtk::FileChooserDialog *dialog)
|
||||
{
|
||||
switch (response_id)
|
||||
{
|
||||
case Gtk::ResponseType::RESPONSE_OK:
|
||||
{
|
||||
auto filename = dialog->get_file()->get_path();
|
||||
std::cout << "TODO. File selected: " << filename << std::endl;
|
||||
auto filePath = dialog->get_file()->get_path();
|
||||
// Open file, set address bar & disable editor if needed
|
||||
doRequest("file://" + filePath);
|
||||
|
||||
// Set new title
|
||||
this->set_title("openings.md - " + m_appName);
|
||||
break;
|
||||
}
|
||||
case Gtk::ResponseType::RESPONSE_CANCEL:
|
||||
|
@ -682,7 +723,43 @@ void MainWindow::on_open_dialog_response(int response_id, Gtk::FileChooserDialog
|
|||
}
|
||||
default:
|
||||
{
|
||||
std::cerr << "ERROR: Unexpected button clicked." << std::endl;
|
||||
std::cerr << "WARN: Unexpected button clicked." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete dialog;
|
||||
}
|
||||
|
||||
void MainWindow::on_open_edit_dialog_response(int response_id, Gtk::FileChooserDialog *dialog)
|
||||
{
|
||||
switch (response_id)
|
||||
{
|
||||
case Gtk::ResponseType::RESPONSE_OK:
|
||||
{
|
||||
auto filePath = dialog->get_file()->get_path();
|
||||
std::string path = "file://" + filePath;
|
||||
// Open file and set address bar, but do not parse the content or the disable editor
|
||||
doRequest(path, true, false, false, false);
|
||||
|
||||
// Enable editor if needed
|
||||
if (!this->isEditorEnabled())
|
||||
this->enableEdit();
|
||||
|
||||
// Change address bar
|
||||
this->m_addressBar.set_text(path);
|
||||
// Set new title
|
||||
this->set_title("open_edit.md - " + m_appName);
|
||||
// Set current file path for saving feature
|
||||
this->currentFileSavedPath = filePath;
|
||||
break;
|
||||
}
|
||||
case Gtk::ResponseType::RESPONSE_CANCEL:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::cerr << "WARN: Unexpected button clicked." << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -739,7 +816,14 @@ void MainWindow::save_as()
|
|||
// If user is saving as an existing file, set the current uri path
|
||||
if (!this->currentFileSavedPath.empty())
|
||||
{
|
||||
dialog->set_uri(Glib::filename_to_uri(currentFileSavedPath));
|
||||
try
|
||||
{
|
||||
dialog->set_uri(Glib::filename_to_uri(currentFileSavedPath));
|
||||
}
|
||||
catch (Glib::Error &e)
|
||||
{
|
||||
std::cerr << "ERROR: Incorrect filename most likely. Error: " << e.what() << ". Error Code: " << e.code() << std::endl;
|
||||
}
|
||||
}
|
||||
dialog->show();
|
||||
}
|
||||
|
@ -758,10 +842,14 @@ void MainWindow::on_save_as_dialog_response(int response_id, Gtk::FileChooserDia
|
|||
try
|
||||
{
|
||||
File::write(filePath, this->currentContent);
|
||||
|
||||
// Set/update the current file saved path variable (used for the 'save' feature)
|
||||
// Only if editor mode is enabled
|
||||
if (this->isEditorEnabled())
|
||||
{
|
||||
// Set/update the current file saved path variable (used for the 'save' feature)
|
||||
this->currentFileSavedPath = filePath;
|
||||
// And also update the address bar with the current file path
|
||||
this->m_addressBar.set_text("file://" + filePath);
|
||||
}
|
||||
}
|
||||
catch (std::ios_base::failure &e)
|
||||
{
|
||||
|
@ -788,14 +876,19 @@ void MainWindow::publish()
|
|||
}
|
||||
|
||||
/**
|
||||
* Post processing request actions
|
||||
* \brief Post-processing request actions
|
||||
* \param path File path (on disk or IPFS) that needs to be processed
|
||||
* \param isSetAddressBar If true change update the address bar with the file path
|
||||
* \param isHistoryRequest Set to true if this is an history request call: back/forward
|
||||
* \param isDisableEditor If true the editor will be disabled if needed
|
||||
*/
|
||||
void MainWindow::postDoRequest(const std::string &path, bool setAddressBar, bool isHistoryRequest)
|
||||
void MainWindow::postDoRequest(const std::string &path, bool isSetAddressBar, bool isHistoryRequest, bool isDisableEditor)
|
||||
{
|
||||
if (setAddressBar)
|
||||
if (isSetAddressBar)
|
||||
m_addressBar.set_text(path);
|
||||
|
||||
this->disableEdit();
|
||||
if (isDisableEditor && isEditorEnabled())
|
||||
this->disableEdit();
|
||||
|
||||
// Do not insert history back/forward calls into the history (again)
|
||||
if (!isHistoryRequest)
|
||||
|
@ -819,16 +912,17 @@ void MainWindow::postDoRequest(const std::string &path, bool setAddressBar, bool
|
|||
m_menu.setForwardMenuSensitive(currentHistoryIndex < history.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Show homepage
|
||||
*/
|
||||
void MainWindow::go_home()
|
||||
{
|
||||
this->requestPath = "";
|
||||
this->finalRequestPath = "";
|
||||
this->currentContent = "";
|
||||
this->m_addressBar.set_text("");
|
||||
this->disableEdit();
|
||||
m_draw_main.showStartPage();
|
||||
doRequest("about:home", true, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Show IFFS status popup
|
||||
*/
|
||||
void MainWindow::show_status()
|
||||
{
|
||||
this->m_statusPopover.popup();
|
||||
|
@ -896,7 +990,7 @@ void MainWindow::on_replace()
|
|||
*/
|
||||
void MainWindow::address_bar_activate()
|
||||
{
|
||||
doRequest(m_addressBar.get_text());
|
||||
doRequest(m_addressBar.get_text(), false);
|
||||
// When user actually entered the address bar, focus on the main draw
|
||||
m_draw_main.grab_focus();
|
||||
}
|
||||
|
@ -967,7 +1061,9 @@ void MainWindow::forward()
|
|||
|
||||
void MainWindow::refresh()
|
||||
{
|
||||
doRequest();
|
||||
// Only allow refresh if editor is disabled (doesn't make sense otherwise to refresh)
|
||||
if (!this->isEditorEnabled())
|
||||
doRequest("", false, false, false); /*!< Reload existing file, don't need to update the address bar, don't disable the editor */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -991,6 +1087,8 @@ bool MainWindow::isInstalled()
|
|||
|
||||
void MainWindow::enableEdit()
|
||||
{
|
||||
// Reset the current content
|
||||
|
||||
// Inform the Draw class that we are creating a new document
|
||||
this->m_draw_main.newDocument();
|
||||
// Show editor toolbars
|
||||
|
@ -1003,9 +1101,7 @@ void MainWindow::enableEdit()
|
|||
// Connect changed signal
|
||||
this->textChangedSignalHandler = m_draw_main.get_buffer().get()->signal_changed().connect(sigc::mem_fun(this, &MainWindow::editor_changed_text));
|
||||
// Enable publish button in menu
|
||||
m_menu.setPublishMenuSensitive(true);
|
||||
// Set new title
|
||||
set_title("Untitled * - " + m_appName);
|
||||
this->m_menu.setPublishMenuSensitive(true);
|
||||
}
|
||||
|
||||
void MainWindow::disableEdit()
|
||||
|
@ -1035,24 +1131,37 @@ void MainWindow::disableEdit()
|
|||
*/
|
||||
bool MainWindow::isEditorEnabled()
|
||||
{
|
||||
// TODO: maybe use: return this->m_draw_main.get_editable();
|
||||
return m_hboxStandardEditorToolbar.is_visible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file from disk or IPFS network, from the provided path,
|
||||
* \brief Get the file from disk or IPFS network, from the provided path,
|
||||
* parse the content, and display the document
|
||||
* \param path File path that needs to be fetched (from disk or IPFS network)
|
||||
* \param isParseContent Set to true if you want to parse and display the content as markdown syntax (from disk or IPFS network),
|
||||
* set to false if you want to edit the content
|
||||
*/
|
||||
void MainWindow::processRequest(const std::string &path)
|
||||
void MainWindow::processRequest(const std::string &path, bool isParseContent)
|
||||
{
|
||||
currentContent = "";
|
||||
// Do not update the requestPath when path is empty,
|
||||
// this is used for refreshing the page
|
||||
if (!path.empty())
|
||||
{
|
||||
requestPath = path;
|
||||
}
|
||||
|
||||
if (requestPath.empty())
|
||||
{
|
||||
std::cerr << "Info: Empty request path." << std::endl;
|
||||
}
|
||||
// Handle homepage
|
||||
else if (requestPath.compare("about:home") == 0)
|
||||
{
|
||||
m_draw_main.showStartPage();
|
||||
}
|
||||
// Handle disk or IPFS file paths
|
||||
else
|
||||
{
|
||||
// Check if CID
|
||||
|
@ -1060,43 +1169,48 @@ void MainWindow::processRequest(const std::string &path)
|
|||
{
|
||||
finalRequestPath = requestPath;
|
||||
finalRequestPath.erase(0, 7);
|
||||
fetchFromIPFS();
|
||||
fetchFromIPFS(isParseContent);
|
||||
}
|
||||
else if ((requestPath.length() == 46) && (requestPath.rfind("Qm", 0) == 0))
|
||||
{
|
||||
// CIDv0
|
||||
finalRequestPath = requestPath;
|
||||
fetchFromIPFS();
|
||||
fetchFromIPFS(isParseContent);
|
||||
}
|
||||
else if (requestPath.rfind("file://", 0) == 0)
|
||||
{
|
||||
finalRequestPath = requestPath;
|
||||
finalRequestPath.erase(0, 7);
|
||||
openFromDisk();
|
||||
openFromDisk(isParseContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// IPFS as fallback / CIDv1
|
||||
finalRequestPath = requestPath;
|
||||
fetchFromIPFS();
|
||||
fetchFromIPFS(isParseContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for processRequest(),
|
||||
* Display markdown file from IPFS network.
|
||||
* \brief Helper method for processRequest(), display markdown file from IPFS network.
|
||||
* Runs in a seperate thread.
|
||||
* \param isParseContent Set to true if you want to parse and display the content as markdown syntax (from disk or IPFS network),
|
||||
* set to false if you want to edit the content
|
||||
*/
|
||||
void MainWindow::fetchFromIPFS()
|
||||
void MainWindow::fetchFromIPFS(bool isParseContent)
|
||||
{
|
||||
// TODO: Execute the code in a seperate thread/process?
|
||||
// Since otherwise this may block the UI if it takes too long!
|
||||
try
|
||||
{
|
||||
currentContent = File::fetch(finalRequestPath);
|
||||
cmark_node *doc = Parser::parseContent(currentContent);
|
||||
m_draw_main.processDocument(doc);
|
||||
cmark_node_free(doc);
|
||||
if (isParseContent) {
|
||||
cmark_node *doc = Parser::parseContent(currentContent);
|
||||
m_draw_main.processDocument(doc);
|
||||
cmark_node_free(doc);
|
||||
} else {
|
||||
// directly set the plain content
|
||||
m_draw_main.setText(currentContent);
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error &error)
|
||||
{
|
||||
|
@ -1122,17 +1236,24 @@ void MainWindow::fetchFromIPFS()
|
|||
}
|
||||
|
||||
/**
|
||||
* Helper method for processRequest(),
|
||||
* Display markdown file from disk.
|
||||
* \brief Helper method for processRequest(), display markdown file from disk.
|
||||
* Runs in a seperate thread.
|
||||
* \param isParseContent Set to true if you want to parse and display the content as markdown syntax (from disk or IPFS network),
|
||||
* set to false if you want to edit the content
|
||||
*/
|
||||
void MainWindow::openFromDisk()
|
||||
void MainWindow::openFromDisk(bool isParseContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
currentContent = File::read(finalRequestPath);
|
||||
cmark_node *doc = Parser::parseContent(currentContent);
|
||||
m_draw_main.processDocument(doc);
|
||||
cmark_node_free(doc);
|
||||
if (isParseContent) {
|
||||
cmark_node *doc = Parser::parseContent(currentContent);
|
||||
m_draw_main.processDocument(doc);
|
||||
cmark_node_free(doc);
|
||||
} else {
|
||||
// directly set the plain content
|
||||
m_draw_main.setText(currentContent);
|
||||
}
|
||||
}
|
||||
catch (const std::ios_base::failure &e)
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@ class MainWindow : public Gtk::Window
|
|||
{
|
||||
public:
|
||||
MainWindow();
|
||||
void doRequest(const std::string &path = std::string(), bool setAddressBar = false, bool isHistoryRequest = false);
|
||||
void doRequest(const std::string &path = std::string(), bool isSetAddressBar = true, bool isHistoryRequest = false, bool isDisableEditor = true, bool isParseContent = true);
|
||||
|
||||
protected:
|
||||
// Signal handlers
|
||||
|
@ -44,7 +44,9 @@ protected:
|
|||
void selectAll();
|
||||
void new_doc();
|
||||
void open();
|
||||
void open_and_edit();
|
||||
void on_open_dialog_response(int response_id, Gtk::FileChooserDialog* dialog);
|
||||
void on_open_edit_dialog_response(int response_id, Gtk::FileChooserDialog* dialog);
|
||||
void save();
|
||||
void save_as();
|
||||
void on_save_as_dialog_response(int response_id, Gtk::FileChooserDialog* dialog);
|
||||
|
@ -169,10 +171,10 @@ private:
|
|||
void enableEdit();
|
||||
void disableEdit();
|
||||
bool isEditorEnabled();
|
||||
void postDoRequest(const std::string &path, bool setAddressBar, bool isHistoryRequest);
|
||||
void processRequest(const std::string &path);
|
||||
void fetchFromIPFS();
|
||||
void openFromDisk();
|
||||
void postDoRequest(const std::string &path, bool isSetAddressBar, bool isHistoryRequest, bool isDisableEditor);
|
||||
void processRequest(const std::string &path, bool isParseContent);
|
||||
void fetchFromIPFS(bool isParseContent);
|
||||
void openFromDisk(bool isParseContent);
|
||||
std::string getIconImageFromTheme(const std::string &iconName, const std::string &typeofIcon);
|
||||
};
|
||||
|
||||
|
|
17
src/menu.cc
17
src/menu.cc
|
@ -13,6 +13,9 @@ Menu::Menu(const Glib::RefPtr<Gtk::AccelGroup> &accelgroup)
|
|||
auto openMenuItem = createMenuItem("_Open...");
|
||||
openMenuItem->add_accelerator("activate", accelgroup, GDK_KEY_O, Gdk::ModifierType::CONTROL_MASK, Gtk::AccelFlags::ACCEL_VISIBLE);
|
||||
openMenuItem->signal_activate().connect(open);
|
||||
auto openEditMenuItem = createMenuItem("Open and _Edit...");
|
||||
openEditMenuItem->add_accelerator("activate", accelgroup, GDK_KEY_E, Gdk::ModifierType::CONTROL_MASK, Gtk::AccelFlags::ACCEL_VISIBLE);
|
||||
openEditMenuItem->signal_activate().connect(open_edit);
|
||||
auto saveMenuitem = createMenuItem("_Save");
|
||||
saveMenuitem->add_accelerator("activate", accelgroup, GDK_KEY_S, Gdk::ModifierType::CONTROL_MASK, Gtk::AccelFlags::ACCEL_VISIBLE);
|
||||
saveMenuitem->signal_activate().connect(save);
|
||||
|
@ -81,29 +84,31 @@ Menu::Menu(const Glib::RefPtr<Gtk::AccelGroup> &accelgroup)
|
|||
// Add items to sub-menus
|
||||
m_fileSubmenu.append(*newDocumentMenuItem);
|
||||
m_fileSubmenu.append(*openMenuItem);
|
||||
m_fileSubmenu.append(*openEditMenuItem);
|
||||
m_fileSubmenu.append(m_separator1);
|
||||
m_fileSubmenu.append(*saveMenuitem);
|
||||
m_fileSubmenu.append(*saveAsMenuItem);
|
||||
m_fileSubmenu.append(m_separator1);
|
||||
m_fileSubmenu.append(*publishMenuItem);
|
||||
m_fileSubmenu.append(m_separator2);
|
||||
m_fileSubmenu.append(*publishMenuItem);
|
||||
m_fileSubmenu.append(m_separator3);
|
||||
m_fileSubmenu.append(*quitMenuItem);
|
||||
m_editSubmenu.append(*undoMenuItem);
|
||||
m_editSubmenu.append(*redoMenuItem);
|
||||
m_editSubmenu.append(m_separator3);
|
||||
m_editSubmenu.append(m_separator4);
|
||||
m_editSubmenu.append(*cutMenuItem);
|
||||
m_editSubmenu.append(*copyMenuItem);
|
||||
m_editSubmenu.append(*pasteMenuItem);
|
||||
m_editSubmenu.append(*deleteMenuItem);
|
||||
m_editSubmenu.append(m_separator4);
|
||||
m_editSubmenu.append(*selectAllMenuItem);
|
||||
m_editSubmenu.append(m_separator5);
|
||||
m_editSubmenu.append(*selectAllMenuItem);
|
||||
m_editSubmenu.append(m_separator6);
|
||||
m_editSubmenu.append(*findMenuItem);
|
||||
m_editSubmenu.append(*replaceMenuItem);
|
||||
m_viewSubmenu.append(*backMenuItem);
|
||||
m_viewSubmenu.append(*forwardMenuItem);
|
||||
m_viewSubmenu.append(*reloadMenuItem);
|
||||
m_viewSubmenu.append(*homePageMenuItem);
|
||||
m_viewSubmenu.append(m_separator6);
|
||||
m_viewSubmenu.append(m_separator7);
|
||||
m_viewSubmenu.append(*sourceCodeMenuItem);
|
||||
m_helpSubmenu.append(*aboutMenuItem);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ class Menu : public Gtk::MenuBar
|
|||
public:
|
||||
sigc::signal<void> new_doc;
|
||||
sigc::signal<void> open;
|
||||
sigc::signal<void> open_edit;
|
||||
sigc::signal<void> save;
|
||||
sigc::signal<void> save_as;
|
||||
sigc::signal<void> publish;
|
||||
|
@ -58,6 +59,7 @@ protected:
|
|||
Gtk::SeparatorMenuItem m_separator4;
|
||||
Gtk::SeparatorMenuItem m_separator5;
|
||||
Gtk::SeparatorMenuItem m_separator6;
|
||||
Gtk::SeparatorMenuItem m_separator7;
|
||||
|
||||
private:
|
||||
Gtk::MenuItem *createMenuItem(const Glib::ustring &label_text);
|
||||
|
|
Loading…
Reference in New Issue