mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 20:32:44 +00:00 
			
		
		
		
	 3d4afe7614
			
		
	
	
		3d4afe7614
		
	
	
	
	
		
			
			I've wasted a silly amount of time in the past fretting over which of these words to use. Let's just choose one and use it everywhere. :^)
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2020, the SerenityOS developers.
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include "SpreadsheetModel.h"
 | |
| #include "ConditionalFormatting.h"
 | |
| #include <AK/URL.h>
 | |
| #include <LibGUI/AbstractView.h>
 | |
| #include <LibJS/Runtime/Error.h>
 | |
| #include <LibJS/Runtime/Object.h>
 | |
| 
 | |
| namespace Spreadsheet {
 | |
| 
 | |
| SheetModel::~SheetModel()
 | |
| {
 | |
| }
 | |
| 
 | |
| GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
 | |
| {
 | |
|     if (!index.is_valid())
 | |
|         return {};
 | |
| 
 | |
|     if (role == GUI::ModelRole::Display) {
 | |
|         const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
 | |
|         if (!cell)
 | |
|             return String::empty();
 | |
| 
 | |
|         if (cell->kind() == Spreadsheet::Cell::Formula) {
 | |
|             if (auto exception = cell->exception()) {
 | |
|                 StringBuilder builder;
 | |
|                 builder.append("Error: ");
 | |
|                 auto value = exception->value();
 | |
|                 if (value.is_object()) {
 | |
|                     auto& object = value.as_object();
 | |
|                     if (is<JS::Error>(object)) {
 | |
|                         auto error = object.get("message").to_string_without_side_effects();
 | |
|                         builder.append(error);
 | |
|                         return builder.to_string();
 | |
|                     }
 | |
|                 }
 | |
|                 auto error = value.to_string(cell->sheet().global_object());
 | |
|                 // This is annoying, but whatever.
 | |
|                 cell->sheet().interpreter().vm().clear_exception();
 | |
| 
 | |
|                 builder.append(error);
 | |
|                 return builder.to_string();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return cell->typed_display();
 | |
|     }
 | |
| 
 | |
|     if (role == GUI::ModelRole::MimeData)
 | |
|         return Position { (size_t)index.column(), (size_t)index.row() }.to_url(m_sheet).to_string();
 | |
| 
 | |
|     if (role == GUI::ModelRole::TextAlignment) {
 | |
|         const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
 | |
|         if (!cell)
 | |
|             return {};
 | |
| 
 | |
|         return cell->type_metadata().alignment;
 | |
|     }
 | |
| 
 | |
|     if (role == GUI::ModelRole::ForegroundColor) {
 | |
|         const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
 | |
|         if (!cell)
 | |
|             return {};
 | |
| 
 | |
|         if (cell->kind() == Spreadsheet::Cell::Formula) {
 | |
|             if (cell->exception())
 | |
|                 return Color(Color::Red);
 | |
|         }
 | |
| 
 | |
|         if (cell->evaluated_formats().foreground_color.has_value())
 | |
|             return cell->evaluated_formats().foreground_color.value();
 | |
| 
 | |
|         if (auto color = cell->type_metadata().static_format.foreground_color; color.has_value())
 | |
|             return color.value();
 | |
| 
 | |
|         return {};
 | |
|     }
 | |
| 
 | |
|     if (role == GUI::ModelRole::BackgroundColor) {
 | |
|         const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
 | |
|         if (!cell)
 | |
|             return {};
 | |
| 
 | |
|         if (cell->evaluated_formats().background_color.has_value())
 | |
|             return cell->evaluated_formats().background_color.value();
 | |
| 
 | |
|         if (auto color = cell->type_metadata().static_format.background_color; color.has_value())
 | |
|             return color.value();
 | |
| 
 | |
|         return {};
 | |
|     }
 | |
| 
 | |
|     return {};
 | |
| }
 | |
| 
 | |
| RefPtr<Core::MimeData> SheetModel::mime_data(const GUI::ModelSelection& selection) const
 | |
| {
 | |
|     auto mime_data = GUI::Model::mime_data(selection);
 | |
| 
 | |
|     bool first = true;
 | |
|     const GUI::ModelIndex* cursor = nullptr;
 | |
|     const_cast<SheetModel*>(this)->for_each_view([&](const GUI::AbstractView& view) {
 | |
|         if (!first)
 | |
|             return;
 | |
|         cursor = &view.cursor_index();
 | |
|         first = false;
 | |
|     });
 | |
| 
 | |
|     VERIFY(cursor);
 | |
| 
 | |
|     Position cursor_position { (size_t)cursor->column(), (size_t)cursor->row() };
 | |
|     auto new_data = String::formatted("{}\n{}",
 | |
|         cursor_position.to_url(m_sheet).to_string(),
 | |
|         StringView(mime_data->data("text/x-spreadsheet-data")));
 | |
|     mime_data->set_data("text/x-spreadsheet-data", new_data.to_byte_buffer());
 | |
| 
 | |
|     return mime_data;
 | |
| }
 | |
| 
 | |
| String SheetModel::column_name(int index) const
 | |
| {
 | |
|     if (index < 0)
 | |
|         return {};
 | |
| 
 | |
|     return m_sheet->column(index);
 | |
| }
 | |
| 
 | |
| bool SheetModel::is_editable(const GUI::ModelIndex& index) const
 | |
| {
 | |
|     if (!index.is_valid())
 | |
|         return false;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void SheetModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& value)
 | |
| {
 | |
|     if (!index.is_valid())
 | |
|         return;
 | |
| 
 | |
|     auto& cell = m_sheet->ensure({ (size_t)index.column(), (size_t)index.row() });
 | |
|     cell.set_data(value.to_string());
 | |
|     update();
 | |
| }
 | |
| 
 | |
| void SheetModel::update()
 | |
| {
 | |
|     m_sheet->update();
 | |
|     did_update(UpdateFlag::DontInvalidateIndices);
 | |
| }
 | |
| 
 | |
| }
 |