2020-08-23 00:55:16 -03:00
/*
2022-02-10 16:28:48 -03:00
* Copyright ( c ) 2020 - 2022 , the SerenityOS developers .
2020-08-23 00:55:16 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-08-23 00:55:16 -03:00
*/
# include "SpreadsheetModel.h"
2020-09-25 16:01:39 -03:00
# include "ConditionalFormatting.h"
2020-11-02 13:51:07 -03:00
# include <AK/URL.h>
2020-11-07 16:48:41 -03:00
# include <LibGUI/AbstractView.h>
2020-08-26 00:22:54 -03:00
# include <LibJS/Runtime/Error.h>
# include <LibJS/Runtime/Object.h>
2020-08-23 00:55:16 -03:00
namespace Spreadsheet {
GUI : : Variant SheetModel : : data ( const GUI : : ModelIndex & index , GUI : : ModelRole role ) const
{
if ( ! index . is_valid ( ) )
return { } ;
if ( role = = GUI : : ModelRole : : Display ) {
2022-04-01 14:58:27 -03:00
auto const * cell = m_sheet - > at ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
2020-08-28 10:25:06 -03:00
if ( ! cell )
2020-08-23 00:55:16 -03:00
return String : : empty ( ) ;
2021-11-20 22:38:00 -03:00
Function < String ( JS : : Value ) > to_string_as_exception = [ & ] ( JS : : Value value ) {
2022-08-21 10:00:56 -03:00
auto & vm = cell - > sheet ( ) . global_object ( ) . vm ( ) ;
2021-11-20 22:38:00 -03:00
StringBuilder builder ;
builder . append ( " Error: " sv ) ;
if ( value . is_object ( ) ) {
auto & object = value . as_object ( ) ;
if ( is < JS : : Error > ( object ) ) {
auto message = object . get_without_side_effects ( " message " ) ;
2022-08-21 10:00:56 -03:00
auto error = message . to_string ( vm ) ;
2021-11-20 22:38:00 -03:00
if ( error . is_throw_completion ( ) )
builder . append ( message . to_string_without_side_effects ( ) ) ;
else
builder . append ( error . release_value ( ) ) ;
return builder . to_string ( ) ;
2020-12-22 07:48:33 -03:00
}
2020-08-26 00:22:54 -03:00
}
2022-08-21 10:00:56 -03:00
auto error_message = value . to_string ( vm ) ;
2021-11-20 22:38:00 -03:00
if ( error_message . is_throw_completion ( ) )
2021-12-28 13:42:14 -03:00
return to_string_as_exception ( * error_message . release_error ( ) . value ( ) ) ;
2021-11-20 22:38:00 -03:00
builder . append ( error_message . release_value ( ) ) ;
return builder . to_string ( ) ;
} ;
if ( cell - > kind ( ) = = Spreadsheet : : Cell : : Formula ) {
2022-02-07 11:00:40 -03:00
if ( auto opt_throw_value = cell - > thrown_value ( ) ; opt_throw_value . has_value ( ) )
return to_string_as_exception ( * opt_throw_value ) ;
2020-08-26 00:22:54 -03:00
}
2020-08-23 00:55:16 -03:00
2021-11-20 22:38:00 -03:00
auto display = cell - > typed_display ( ) ;
if ( display . is_error ( ) )
2021-12-28 13:42:14 -03:00
return to_string_as_exception ( * display . release_error ( ) . value ( ) ) ;
2021-11-20 22:38:00 -03:00
return display . release_value ( ) ;
2020-08-23 00:55:16 -03:00
}
2020-11-07 16:48:41 -03:00
if ( role = = GUI : : ModelRole : : MimeData )
2021-02-23 10:36:07 -03:00
return Position { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } . to_url ( m_sheet ) . to_string ( ) ;
2020-11-02 13:51:07 -03:00
2020-08-29 03:51:18 -03:00
if ( role = = GUI : : ModelRole : : TextAlignment ) {
2022-04-01 14:58:27 -03:00
auto const * cell = m_sheet - > at ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
2020-08-29 03:51:18 -03:00
if ( ! cell )
return { } ;
return cell - > type_metadata ( ) . alignment ;
}
2020-08-23 00:55:16 -03:00
2020-08-26 00:22:54 -03:00
if ( role = = GUI : : ModelRole : : ForegroundColor ) {
2022-04-01 14:58:27 -03:00
auto const * cell = m_sheet - > at ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
2020-08-28 10:25:06 -03:00
if ( ! cell )
2020-08-26 00:22:54 -03:00
return { } ;
2020-12-20 06:28:14 -03:00
if ( cell - > kind ( ) = = Spreadsheet : : Cell : : Formula ) {
2022-02-07 11:00:40 -03:00
if ( cell - > thrown_value ( ) . has_value ( ) )
2020-08-26 00:22:54 -03:00
return Color ( Color : : Red ) ;
}
2020-09-25 16:01:39 -03:00
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 ( ) )
2020-09-12 07:59:58 -03:00
return color . value ( ) ;
return { } ;
}
if ( role = = GUI : : ModelRole : : BackgroundColor ) {
2022-04-01 14:58:27 -03:00
auto const * cell = m_sheet - > at ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
2020-09-12 07:59:58 -03:00
if ( ! cell )
return { } ;
2020-09-25 16:01:39 -03:00
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 ( ) )
2020-09-12 07:59:58 -03:00
return color . value ( ) ;
2020-08-26 00:22:54 -03:00
return { } ;
}
2022-06-25 16:42:23 -03:00
if ( to_underlying ( role ) = = to_underlying ( Role : : Tooltip ) ) {
auto const * cell = m_sheet - > at ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
if ( ! cell | | ! cell - > thrown_value ( ) . has_value ( ) )
return { } ;
auto value = cell - > thrown_value ( ) . value ( ) ;
if ( ! value . is_object ( ) )
return { } ;
auto & object = value . as_object ( ) ;
if ( ! is < JS : : Error > ( object ) )
return { } ;
auto & error = static_cast < JS : : Error & > ( object ) ;
auto const & trace = error . traceback ( ) ;
StringBuilder builder ;
builder . appendff ( " {} \n " , error . get_without_side_effects ( object . vm ( ) . names . message ) . to_string_without_side_effects ( ) ) ;
for ( auto const & frame : trace . in_reverse ( ) ) {
2022-07-11 14:32:29 -03:00
if ( frame . source_range . filename . contains ( " runtime.js " sv ) ) {
2022-06-25 16:42:23 -03:00
if ( frame . function_name = = " <unknown> " )
builder . appendff ( " in a builtin function at line {}, column {} \n " , frame . source_range . start . line , frame . source_range . start . column ) ;
else
builder . appendff ( " while evaluating builtin '{}' \n " , frame . function_name ) ;
2022-07-11 14:32:29 -03:00
} else if ( frame . source_range . filename . starts_with ( " cell " sv ) ) {
2022-06-25 16:42:23 -03:00
builder . appendff ( " in cell '{}', at line {}, column {} \n " , frame . source_range . filename . substring_view ( 5 ) , frame . source_range . start . line , frame . source_range . start . column ) ;
}
}
return builder . to_string ( ) ;
}
2020-08-23 00:55:16 -03:00
return { } ;
}
2020-11-07 16:48:41 -03:00
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 ;
} ) ;
2021-02-23 16:42:32 -03:00
VERIFY ( cursor ) ;
2020-11-07 16:48:41 -03:00
2021-02-23 10:36:07 -03:00
Position cursor_position { ( size_t ) cursor - > column ( ) , ( size_t ) cursor - > row ( ) } ;
2021-09-10 18:42:39 -03:00
auto mime_data_buffer = mime_data - > data ( " text/x-spreadsheet-data " ) ;
2020-11-07 16:48:41 -03:00
auto new_data = String : : formatted ( " {} \n {} " ,
2021-02-23 10:36:07 -03:00
cursor_position . to_url ( m_sheet ) . to_string ( ) ,
2021-09-10 18:42:39 -03:00
StringView ( mime_data_buffer ) ) ;
2020-11-07 16:48:41 -03:00
mime_data - > set_data ( " text/x-spreadsheet-data " , new_data . to_byte_buffer ( ) ) ;
return mime_data ;
}
2020-08-23 00:55:16 -03:00
String SheetModel : : column_name ( int index ) const
{
if ( index < 0 )
return { } ;
2020-08-26 11:03:45 -03:00
return m_sheet - > column ( index ) ;
2020-08-23 00:55:16 -03:00
}
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 ;
2021-02-23 10:36:07 -03:00
auto & cell = m_sheet - > ensure ( { ( size_t ) index . column ( ) , ( size_t ) index . row ( ) } ) ;
2022-02-19 17:03:50 -03:00
auto previous_data = cell . data ( ) ;
2020-08-23 00:55:16 -03:00
cell . set_data ( value . to_string ( ) ) ;
2022-02-19 17:03:50 -03:00
if ( on_cell_data_change )
on_cell_data_change ( cell , previous_data ) ;
2021-08-30 12:58:52 -03:00
did_update ( UpdateFlag : : DontInvalidateIndices ) ;
2020-08-23 00:55:16 -03:00
}
void SheetModel : : update ( )
{
m_sheet - > update ( ) ;
2021-04-29 17:23:52 -03:00
did_update ( UpdateFlag : : DontInvalidateIndices ) ;
2020-08-23 00:55:16 -03:00
}
2022-04-07 18:04:36 -03:00
CellsUndoCommand : : CellsUndoCommand ( Vector < CellChange > cell_changes )
{
m_cell_changes = cell_changes ;
}
CellsUndoCommand : : CellsUndoCommand ( Cell & cell , String const & previous_data )
{
m_cell_changes . append ( CellChange ( cell , previous_data ) ) ;
}
void CellsUndoCommand : : undo ( )
{
for ( size_t i = 0 ; i < m_cell_changes . size ( ) ; + + i ) {
m_cell_changes [ i ] . cell ( ) . set_data ( m_cell_changes [ i ] . previous_data ( ) ) ;
}
}
void CellsUndoCommand : : redo ( )
{
for ( size_t i = 0 ; i < m_cell_changes . size ( ) ; + + i ) {
m_cell_changes [ i ] . cell ( ) . set_data ( m_cell_changes [ i ] . new_data ( ) ) ;
}
}
2020-08-23 00:55:16 -03:00
}