From 82d9410226fcc0dc0c4f3867734b2b25c3f96679 Mon Sep 17 00:00:00 2001 From: rhin123 Date: Sat, 13 Jul 2019 19:58:04 -0500 Subject: [PATCH] TextEditorWidget: Added improved save feature. Instead of saving to a temp file, the TextEditorWidget now saves to a path returned by the improved GFilePicker. --- Applications/TextEditor/TextEditorWidget.cpp | 37 +++++++++--- Applications/TextEditor/TextEditorWidget.h | 6 +- Libraries/LibGUI/GFilePicker.cpp | 62 +++++++++++++++++++- Libraries/LibGUI/GFilePicker.h | 27 ++++++++- 4 files changed, 115 insertions(+), 17 deletions(-) diff --git a/Applications/TextEditor/TextEditorWidget.cpp b/Applications/TextEditor/TextEditorWidget.cpp index 913fdd1806..40c6292bab 100644 --- a/Applications/TextEditor/TextEditorWidget.cpp +++ b/Applications/TextEditor/TextEditorWidget.cpp @@ -1,4 +1,5 @@ #include "TextEditorWidget.h" +#include #include #include #include @@ -33,17 +34,35 @@ TextEditorWidget::TextEditorWidget() }); auto open_action = GAction::create("Open document", { Mod_Ctrl, Key_O }, GraphicsBitmap::load_from_file("/res/icons/16x16/open.png"), [this](const GAction&) { - GFilePicker picker; + Optional open_name = GFilePicker::get_open_filepath(); - if (picker.exec() == GDialog::ExecOK) { - m_path = picker.selected_file().string(); - open_sesame(m_path); - } + if (!open_name.has_value()) + return; + + m_path = open_name.value(); + open_sesame(m_path); }); auto save_action = GAction::create("Save document", { Mod_Ctrl, Key_S }, GraphicsBitmap::load_from_file("/res/icons/16x16/save.png"), [this](const GAction&) { - dbgprintf("Writing document to '%s'\n", m_path.characters()); - m_editor->write_to_file(m_path); + if (!m_path.is_empty()) { + if (!m_editor->write_to_file(m_path)) + GMessageBox::show("Unable to save file.\n", "Error", GMessageBox::Type::Error, window()); + + return; + } + + Optional save_name = GFilePicker::get_save_filepath(); + if (!save_name.has_value()) + return; + + dbgprintf("Writing document to '%s'\n", save_name.value()); + if (!m_editor->write_to_file(save_name.value())) { + GMessageBox::show("Unable to save file.\n", "Error", GMessageBox::Type::Error, window()); + return; + } + + m_path = save_name.value(); + window()->set_title(String::format("Text Editor: %s", m_path.characters())); }); auto menubar = make(); @@ -121,5 +140,5 @@ void TextEditorWidget::open_sesame(const String& path) window()->set_title(String::format("Text Editor: %s", path.characters())); m_editor->set_text(String::copy(file.read_all())); -} - + m_path = path; +} \ No newline at end of file diff --git a/Applications/TextEditor/TextEditorWidget.h b/Applications/TextEditor/TextEditorWidget.h index 107ce2c461..08be955f28 100644 --- a/Applications/TextEditor/TextEditorWidget.h +++ b/Applications/TextEditor/TextEditorWidget.h @@ -15,6 +15,6 @@ public: void open_sesame(const String& path); private: - GTextEditor* m_editor{ nullptr }; - String m_path = "/tmp/TextEditor.save.txt"; -}; + GTextEditor* m_editor { nullptr }; + String m_path; +}; \ No newline at end of file diff --git a/Libraries/LibGUI/GFilePicker.cpp b/Libraries/LibGUI/GFilePicker.cpp index 0dfb4ebfd0..3ac50850d5 100644 --- a/Libraries/LibGUI/GFilePicker.cpp +++ b/Libraries/LibGUI/GFilePicker.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -12,9 +13,46 @@ #include #include -GFilePicker::GFilePicker(const StringView& path, CObject* parent) +Optional GFilePicker::get_open_filepath() +{ + GFilePicker picker(Mode::Open); + + if (picker.exec() == GDialog::ExecOK) { + String file_path = picker.selected_file().string(); + + if (file_path.is_null()) + return {}; + + return file_path; + } + return {}; +} + +Optional GFilePicker::get_save_filepath() +{ + GFilePicker picker(Mode::Save); + + if (picker.exec() == GDialog::ExecOK) { + String file_path = picker.selected_file().string(); + + if (file_path.is_null()) + return {}; + + if (GFilePicker::file_exists(file_path)) { + //TODO: Add Yes, No Messagebox to give the user a proper option + GMessageBox::show("File already exists: Overwrite?\n", "Error", GMessageBox::Type::Information, &picker); + return file_path; + } + + return file_path; + } + return {}; +} + +GFilePicker::GFilePicker(Mode mode, const StringView& path, CObject* parent) : GDialog(parent) , m_model(GDirectoryModel::create()) + , m_mode(mode) { set_title("GFilePicker"); set_rect(200, 200, 700, 400); @@ -95,12 +133,16 @@ GFilePicker::GFilePicker(const StringView& path, CObject* parent) filename_label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); filename_label->set_preferred_size({ 60, 0 }); auto* filename_textbox = new GTextBox(filename_container); + if (m_mode == Mode::Save) { + filename_textbox->set_text("Untitled.txt"); //TODO: replace .txt with a preferred extension + filename_textbox->set_focus(true); + filename_textbox->select_all(); + } m_view->on_activation = [this, filename_textbox](auto& index) { auto& filter_model = (GSortingProxyModel&)*m_view->model(); auto local_index = filter_model.map_to_target(index); const GDirectoryModel::Entry& entry = m_model->entry(local_index.row()); - FileSystemPath path(String::format("%s/%s", m_model->path().characters(), entry.name.characters())); clear_preview(); @@ -132,7 +174,7 @@ GFilePicker::GFilePicker(const StringView& path, CObject* parent) auto* ok_button = new GButton(button_container); ok_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); ok_button->set_preferred_size({ 80, 0 }); - ok_button->set_text("OK"); + ok_button->set_text(ok_button_name(m_mode)); ok_button->on_click = [this, filename_textbox](auto&) { FileSystemPath path(String::format("%s/%s", m_model->path().characters(), filename_textbox->text().characters())); m_selected_file = path; @@ -189,3 +231,17 @@ void GFilePicker::clear_preview() m_preview_name_label->set_text(String::empty()); m_preview_geometry_label->set_text(String::empty()); } + +bool GFilePicker::file_exists(const StringView& path) +{ + struct stat st; + int rc = stat(String(path).characters(), &st); + if (rc < 0) { + if (errno == ENOENT) + return false; + } + if (rc == 0) { + return true; + } + return false; +} \ No newline at end of file diff --git a/Libraries/LibGUI/GFilePicker.h b/Libraries/LibGUI/GFilePicker.h index b091edb2e7..ccb68134b0 100644 --- a/Libraries/LibGUI/GFilePicker.h +++ b/Libraries/LibGUI/GFilePicker.h @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,7 +8,16 @@ class GLabel; class GFilePicker final : public GDialog { public: - GFilePicker(const StringView& path = "/", CObject* parent = nullptr); + enum class Mode { + Open, + Save + }; + + static Optional get_open_filepath(); + static Optional get_save_filepath(); + static bool file_exists(const StringView& path); + + GFilePicker(Mode type = Mode::Open, const StringView& path = "/", CObject* parent = nullptr); virtual ~GFilePicker() override; FileSystemPath selected_file() const { return m_selected_file; } @@ -18,6 +28,18 @@ private: void set_preview(const FileSystemPath&); void clear_preview(); + static String ok_button_name(Mode mode) + { + switch (mode) { + case Mode::Open: + return "Open"; + case Mode::Save: + return "Save"; + default: + return "OK"; + } + } + GTableView* m_view { nullptr }; NonnullRefPtr m_model; FileSystemPath m_selected_file; @@ -25,4 +47,5 @@ private: GLabel* m_preview_image_label { nullptr }; GLabel* m_preview_name_label { nullptr }; GLabel* m_preview_geometry_label { nullptr }; -}; + Mode m_mode { Mode::Open }; +}; \ No newline at end of file