summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Applications/Spreadsheet/CMakeLists.txt1
-rw-r--r--Applications/Spreadsheet/SpreadsheetWidget.cpp127
-rw-r--r--Applications/Spreadsheet/SpreadsheetWidget.h8
-rw-r--r--Applications/Spreadsheet/Workbook.cpp136
-rw-r--r--Applications/Spreadsheet/Workbook.h66
5 files changed, 228 insertions, 110 deletions
diff --git a/Applications/Spreadsheet/CMakeLists.txt b/Applications/Spreadsheet/CMakeLists.txt
index 61db474cf4..614fbc4ae0 100644
--- a/Applications/Spreadsheet/CMakeLists.txt
+++ b/Applications/Spreadsheet/CMakeLists.txt
@@ -5,6 +5,7 @@ set(SOURCES
SpreadsheetModel.cpp
SpreadsheetView.cpp
SpreadsheetWidget.cpp
+ Workbook.cpp
main.cpp
)
diff --git a/Applications/Spreadsheet/SpreadsheetWidget.cpp b/Applications/Spreadsheet/SpreadsheetWidget.cpp
index 88fd89e7fd..b56c93857a 100644
--- a/Applications/Spreadsheet/SpreadsheetWidget.cpp
+++ b/Applications/Spreadsheet/SpreadsheetWidget.cpp
@@ -27,10 +27,6 @@
#include "SpreadsheetWidget.h"
#include "CellSyntaxHighlighter.h"
#include "HelpWindow.h"
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonObjectSerializer.h>
-#include <AK/JsonParser.h>
#include <LibCore/File.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h>
@@ -44,7 +40,7 @@
namespace Spreadsheet {
SpreadsheetWidget::SpreadsheetWidget(NonnullRefPtrVector<Sheet>&& sheets, bool should_add_sheet_if_empty)
- : m_sheets(move(sheets))
+ : m_workbook(make<Workbook>(move(sheets)))
{
set_fill_with_background_color(true);
set_layout<GUI::VerticalBoxLayout>().set_margins({ 2, 2, 2, 2 });
@@ -82,8 +78,8 @@ SpreadsheetWidget::SpreadsheetWidget(NonnullRefPtrVector<Sheet>&& sheets, bool s
m_cell_value_editor = cell_value_editor;
m_current_cell_label = current_cell_label;
- if (m_sheets.is_empty() && should_add_sheet_if_empty)
- m_sheets.append(Sheet::construct("Sheet 1"));
+ if (!m_workbook->has_sheets() && should_add_sheet_if_empty)
+ m_workbook->add_sheet("Sheet 1");
setup_tabs();
}
@@ -91,7 +87,7 @@ SpreadsheetWidget::SpreadsheetWidget(NonnullRefPtrVector<Sheet>&& sheets, bool s
void SpreadsheetWidget::setup_tabs()
{
RefPtr<GUI::Widget> first_tab_widget;
- for (auto& sheet : m_sheets) {
+ for (auto& sheet : m_workbook->sheets()) {
auto& tab = m_tab_widget->add_tab<SpreadsheetView>(sheet.name(), sheet);
if (!first_tab_widget)
first_tab_widget = &tab;
@@ -134,121 +130,40 @@ void SpreadsheetWidget::setup_tabs()
};
}
-SpreadsheetWidget::~SpreadsheetWidget()
-{
-}
-
-void SpreadsheetWidget::set_filename(const String& filename)
+void SpreadsheetWidget::save(const StringView& filename)
{
- if (m_current_filename == filename)
- return;
-
- m_current_filename = filename;
- StringBuilder builder;
- builder.append("Spreadsheet - ");
- builder.append(m_current_filename);
-
- window()->set_title(builder.string_view());
- window()->update();
+ auto result = m_workbook->save(filename);
+ if (result.is_error())
+ GUI::MessageBox::show_error(window(), result.error());
}
void SpreadsheetWidget::load(const StringView& filename)
{
- auto file_or_error = Core::File::open(filename, Core::IODevice::OpenMode::ReadOnly);
- if (file_or_error.is_error()) {
- StringBuilder sb;
- sb.append("Failed to open ");
- sb.append(filename);
- sb.append(" for reading. Error: ");
- sb.append(file_or_error.error());
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
+ auto result = m_workbook->load(filename);
+ if (result.is_error()) {
+ GUI::MessageBox::show_error(window(), result.error());
return;
}
-
- auto json_value_option = JsonParser(file_or_error.value()->read_all()).parse();
- if (!json_value_option.has_value()) {
- StringBuilder sb;
- sb.append("Failed to parse ");
- sb.append(filename);
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- auto& json_value = json_value_option.value();
- if (!json_value.is_array()) {
- StringBuilder sb;
- sb.append("Did not find a spreadsheet in ");
- sb.append(filename);
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- NonnullRefPtrVector<Sheet> sheets;
-
- auto& json_array = json_value.as_array();
- json_array.for_each([&](auto& sheet_json) {
- if (!sheet_json.is_object())
- return IterationDecision::Continue;
-
- auto sheet = Sheet::from_json(sheet_json.as_object());
- if (!sheet)
- return IterationDecision::Continue;
-
- sheets.append(sheet.release_nonnull());
-
- return IterationDecision::Continue;
- });
-
- m_sheets.clear();
- m_sheets = move(sheets);
-
while (auto* widget = m_tab_widget->active_widget()) {
m_tab_widget->remove_tab(*widget);
}
setup_tabs();
-
- set_filename(filename);
}
-void SpreadsheetWidget::save(const StringView& filename)
+void SpreadsheetWidget::set_filename(const String& filename)
{
- JsonArray array;
- m_tab_widget->for_each_child_of_type<SpreadsheetView>([&](auto& view) {
- array.append(view.sheet().to_json());
- return IterationDecision::Continue;
- });
-
- auto file_content = array.to_string();
-
- auto file = Core::File::construct(filename);
- file->open(Core::IODevice::WriteOnly);
- if (!file->is_open()) {
- StringBuilder sb;
- sb.append("Failed to open ");
- sb.append(filename);
- sb.append(" for write. Error: ");
- sb.append(file->error_string());
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
- }
+ if (m_workbook->set_filename(filename)) {
+ StringBuilder builder;
+ builder.append("Spreadsheet - ");
+ builder.append(current_filename());
- bool result = file->write(file_content);
- if (!result) {
- int error_number = errno;
- StringBuilder sb;
- sb.append("Unable to save file. Error: ");
- sb.append(strerror(error_number));
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
+ window()->set_title(builder.string_view());
+ window()->update();
}
-
- set_filename(filename);
}
+SpreadsheetWidget::~SpreadsheetWidget()
+{
+}
}
diff --git a/Applications/Spreadsheet/SpreadsheetWidget.h b/Applications/Spreadsheet/SpreadsheetWidget.h
index 6ade762440..c32483f455 100644
--- a/Applications/Spreadsheet/SpreadsheetWidget.h
+++ b/Applications/Spreadsheet/SpreadsheetWidget.h
@@ -27,6 +27,7 @@
#pragma once
#include "SpreadsheetView.h"
+#include "Workbook.h"
#include <AK/NonnullRefPtrVector.h>
#include <LibGUI/Widget.h>
@@ -41,7 +42,7 @@ public:
void save(const StringView& filename);
void load(const StringView& filename);
- const String& current_filename() const { return m_current_filename; }
+ const String& current_filename() const { return m_workbook->current_filename(); }
void set_filename(const String& filename);
private:
@@ -49,13 +50,12 @@ private:
void setup_tabs();
- NonnullRefPtrVector<Sheet> m_sheets;
SpreadsheetView* m_selected_view { nullptr };
- RefPtr<GUI::TabWidget> m_tab_widget;
RefPtr<GUI::Label> m_current_cell_label;
RefPtr<GUI::TextEditor> m_cell_value_editor;
+ RefPtr<GUI::TabWidget> m_tab_widget;
- String m_current_filename;
+ OwnPtr<Workbook> m_workbook;
};
}
diff --git a/Applications/Spreadsheet/Workbook.cpp b/Applications/Spreadsheet/Workbook.cpp
new file mode 100644
index 0000000000..8f20eb9897
--- /dev/null
+++ b/Applications/Spreadsheet/Workbook.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Workbook.h"
+#include <AK/JsonArray.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonObjectSerializer.h>
+#include <AK/JsonParser.h>
+#include <LibCore/File.h>
+#include <string.h>
+
+namespace Spreadsheet {
+
+bool Workbook::set_filename(const String& filename)
+{
+ if (m_current_filename == filename)
+ return false;
+
+ m_current_filename = filename;
+ return true;
+}
+
+Result<bool, String> Workbook::load(const StringView& filename)
+{
+ auto file_or_error = Core::File::open(filename, Core::IODevice::OpenMode::ReadOnly);
+ if (file_or_error.is_error()) {
+ StringBuilder sb;
+ sb.append("Failed to open ");
+ sb.append(filename);
+ sb.append(" for reading. Error: ");
+ sb.append(file_or_error.error());
+
+ return sb.to_string();
+ }
+
+ auto json_value_option = JsonParser(file_or_error.value()->read_all()).parse();
+ if (!json_value_option.has_value()) {
+ StringBuilder sb;
+ sb.append("Failed to parse ");
+ sb.append(filename);
+
+ return sb.to_string();
+ }
+
+ auto& json_value = json_value_option.value();
+ if (!json_value.is_array()) {
+ StringBuilder sb;
+ sb.append("Did not find a spreadsheet in ");
+ sb.append(filename);
+
+ return sb.to_string();
+ }
+
+ NonnullRefPtrVector<Sheet> sheets;
+
+ auto& json_array = json_value.as_array();
+ json_array.for_each([&](auto& sheet_json) {
+ if (!sheet_json.is_object())
+ return IterationDecision::Continue;
+
+ auto sheet = Sheet::from_json(sheet_json.as_object());
+ if (!sheet)
+ return IterationDecision::Continue;
+
+ sheets.append(sheet.release_nonnull());
+
+ return IterationDecision::Continue;
+ });
+
+ m_sheets.clear();
+ m_sheets = move(sheets);
+
+ set_filename(filename);
+
+ return true;
+}
+
+Result<bool, String> Workbook::save(const StringView& filename)
+{
+ JsonArray array;
+
+ for (auto& sheet : m_sheets)
+ array.append(sheet.to_json());
+
+ auto file_content = array.to_string();
+
+ auto file = Core::File::construct(filename);
+ file->open(Core::IODevice::WriteOnly);
+ if (!file->is_open()) {
+ StringBuilder sb;
+ sb.append("Failed to open ");
+ sb.append(filename);
+ sb.append(" for write. Error: ");
+ sb.append(file->error_string());
+
+ return sb.to_string();
+ }
+
+ bool result = file->write(file_content);
+ if (!result) {
+ int error_number = errno;
+ StringBuilder sb;
+ sb.append("Unable to save file. Error: ");
+ sb.append(strerror(error_number));
+
+ return sb.to_string();
+ }
+
+ set_filename(filename);
+ return true;
+}
+
+}
diff --git a/Applications/Spreadsheet/Workbook.h b/Applications/Spreadsheet/Workbook.h
new file mode 100644
index 0000000000..e3ec253ad3
--- /dev/null
+++ b/Applications/Spreadsheet/Workbook.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Spreadsheet.h"
+#include <AK/NonnullOwnPtrVector.h>
+#include <AK/Result.h>
+
+namespace Spreadsheet {
+
+class Workbook {
+public:
+ Workbook(NonnullRefPtrVector<Sheet>&& sheets)
+ : m_sheets(move(sheets))
+ {
+ }
+
+ Result<bool, String> save(const StringView& filename);
+ Result<bool, String> load(const StringView& filename);
+
+ const String& current_filename() const { return m_current_filename; }
+ bool set_filename(const String& filename);
+
+ bool has_sheets() const { return !m_sheets.is_empty(); }
+
+ const NonnullRefPtrVector<Sheet>& sheets() const { return m_sheets; }
+ NonnullRefPtrVector<Sheet> sheets() { return m_sheets; }
+
+ Sheet& add_sheet(const StringView& name)
+ {
+ auto sheet = Sheet::construct(name);
+ m_sheets.append(sheet);
+ return *sheet;
+ }
+
+private:
+ NonnullRefPtrVector<Sheet> m_sheets;
+
+ String m_current_filename;
+};
+
+}