From 9499eda7efa229982480236ee58bfb99e9d66562 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Sun, 1 Dec 2024 21:37:13 -0500 Subject: [PATCH] API: Implement saving selection and board as string --- pcbnew/api/api_handler_pcb.cpp | 77 ++++++++++++++++- pcbnew/api/api_handler_pcb.h | 9 ++ pcbnew/kicad_clipboard.cpp | 154 ++++++++++++++------------------- pcbnew/kicad_clipboard.h | 8 ++ 4 files changed, 155 insertions(+), 93 deletions(-) diff --git a/pcbnew/api/api_handler_pcb.cpp b/pcbnew/api/api_handler_pcb.cpp index 34f3f6f6bf..dc29515988 100644 --- a/pcbnew/api/api_handler_pcb.cpp +++ b/pcbnew/api/api_handler_pcb.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -45,9 +46,9 @@ #include using namespace kiapi::common::commands; -using kiapi::common::types::CommandStatus; -using kiapi::common::types::DocumentType; -using kiapi::common::types::ItemRequestStatus; +using types::CommandStatus; +using types::DocumentType; +using types::ItemRequestStatus; API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) : @@ -75,6 +76,13 @@ API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) : registerHandler( &API_HANDLER_PCB::handleInteractiveMoveItems ); registerHandler( &API_HANDLER_PCB::handleGetNets ); registerHandler( &API_HANDLER_PCB::handleRefillZones ); + + registerHandler( + &API_HANDLER_PCB::handleSaveDocumentToString ); + registerHandler( + &API_HANDLER_PCB::handleSaveSelectionToString ); + registerHandler( + &API_HANDLER_PCB::handleParseAndCreateItemsFromString ); } @@ -846,3 +854,66 @@ HANDLER_RESULT API_HANDLER_PCB::handleRefillZones( RefillZones& aMsg, return Empty(); } + + +HANDLER_RESULT API_HANDLER_PCB::handleSaveDocumentToString( + SaveDocumentToString& aMsg, const HANDLER_CONTEXT& aCtx ) +{ + HANDLER_RESULT documentValidation = validateDocument( aMsg.document() ); + + if( !documentValidation ) + return tl::unexpected( documentValidation.error() ); + + SavedDocumentResponse response; + response.mutable_document()->CopyFrom( aMsg.document() ); + + CLIPBOARD_IO io; + io.SetWriter( + [&]( const wxString& aData ) + { + response.set_contents( aData.ToUTF8() ); + } ); + + io.SaveBoard( wxEmptyString, frame()->GetBoard(), nullptr ); + + return response; +} + + +HANDLER_RESULT API_HANDLER_PCB::handleSaveSelectionToString( + SaveSelectionToString& aMsg, const HANDLER_CONTEXT& aCtx ) +{ + SavedSelectionResponse response; + + TOOL_MANAGER* mgr = frame()->GetToolManager(); + PCB_SELECTION_TOOL* selectionTool = mgr->GetTool(); + PCB_SELECTION& selection = selectionTool->GetSelection(); + + CLIPBOARD_IO io; + io.SetWriter( + [&]( const wxString& aData ) + { + response.set_contents( aData.ToUTF8() ); + } ); + + io.SetBoard( frame()->GetBoard() ); + io.SaveSelection( selection, false ); + + return response; +} + + +HANDLER_RESULT API_HANDLER_PCB::handleParseAndCreateItemsFromString( + ParseAndCreateItemsFromString& aMsg, const HANDLER_CONTEXT& aCtx ) +{ + if( std::optional busy = checkForBusy() ) + return tl::unexpected( *busy ); + + HANDLER_RESULT documentValidation = validateDocument( aMsg.document() ); + + if( !documentValidation ) + return tl::unexpected( documentValidation.error() ); + + CreateItemsResponse response; + return response; +} diff --git a/pcbnew/api/api_handler_pcb.h b/pcbnew/api/api_handler_pcb.h index 8ad862e576..0e6246c057 100644 --- a/pcbnew/api/api_handler_pcb.h +++ b/pcbnew/api/api_handler_pcb.h @@ -93,6 +93,15 @@ private: HANDLER_RESULT handleRefillZones( RefillZones& aMsg, const HANDLER_CONTEXT& aCtx ); + HANDLER_RESULT handleSaveDocumentToString( + commands::SaveDocumentToString& aMsg, const HANDLER_CONTEXT& aCtx ); + + HANDLER_RESULT handleSaveSelectionToString( + commands::SaveSelectionToString& aMsg, const HANDLER_CONTEXT& aCtx ); + + HANDLER_RESULT handleParseAndCreateItemsFromString( + commands::ParseAndCreateItemsFromString& aMsg, const HANDLER_CONTEXT& aCtx ); + protected: std::unique_ptr createCommit() override; diff --git a/pcbnew/kicad_clipboard.cpp b/pcbnew/kicad_clipboard.cpp index cabca4a079..b1368ec433 100644 --- a/pcbnew/kicad_clipboard.cpp +++ b/pcbnew/kicad_clipboard.cpp @@ -45,7 +45,9 @@ CLIPBOARD_IO::CLIPBOARD_IO(): PCB_IO_KICAD_SEXPR(CTL_FOR_CLIPBOARD ), - m_formatter() + m_formatter(), + m_writer( &CLIPBOARD_IO::clipboardWriter ), + m_reader( &CLIPBOARD_IO::clipboardReader ) { m_out = &m_formatter; } @@ -62,6 +64,58 @@ void CLIPBOARD_IO::SetBoard( BOARD* aBoard ) } +void CLIPBOARD_IO::clipboardWriter( const wxString& aData ) +{ + wxLogNull doNotLog; // disable logging of failed clipboard actions + auto clipboard = wxTheClipboard; + wxClipboardLocker clipboardLock( clipboard ); + + if( !clipboardLock || !clipboard->IsOpened() ) + return; + + clipboard->SetData( new wxTextDataObject( aData ) ); + + clipboard->Flush(); + +#ifndef __WXOSX__ + // This section exists to return the clipboard data, ensuring it has fully + // been processed by the system clipboard. This appears to be needed for + // extremely large clipboard copies on asynchronous linux clipboard managers + // such as KDE's Klipper. However, a read back of the data on OSX before the + // clipboard is closed seems to cause an ASAN error (heap-buffer-overflow) + // since it uses the cached version of the clipboard data and not the system + // clipboard data. + if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) + { + wxTextDataObject data; + clipboard->GetData( data ); + ignore_unused( data.GetText() ); + } +#endif +} + + +wxString CLIPBOARD_IO::clipboardReader() +{ + wxLogNull doNotLog; // disable logging of failed clipboard actions + + auto clipboard = wxTheClipboard; + wxClipboardLocker clipboardLock( clipboard ); + + if( !clipboardLock ) + return wxEmptyString; + + if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) + { + wxTextDataObject data; + clipboard->GetData( data ); + return data.GetText(); + } + + return wxEmptyString; +} + + void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootprintEditor ) { VECTOR2I refPoint( 0, 0 ); @@ -399,54 +453,14 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri KICAD_FORMAT::Prettify( prettyData, true ); // These are placed at the end to minimize the open time of the clipboard - wxLogNull doNotLog; // disable logging of failed clipboard actions - auto clipboard = wxTheClipboard; - wxClipboardLocker clipboardLock( clipboard ); - - if( !clipboardLock || !clipboard->IsOpened() ) - return; - - clipboard->SetData( new wxTextDataObject( wxString( prettyData.c_str(), wxConvUTF8 ) ) ); - - clipboard->Flush(); - -#ifndef __WXOSX__ - // This section exists to return the clipboard data, ensuring it has fully - // been processed by the system clipboard. This appears to be needed for - // extremely large clipboard copies on asynchronous linux clipboard managers - // such as KDE's Klipper. However, a read back of the data on OSX before the - // clipboard is closed seems to cause an ASAN error (heap-buffer-overflow) - // since it uses the cached version of the clipboard data and not the system - // clipboard data. - if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) - { - wxTextDataObject data; - clipboard->GetData( data ); - ignore_unused( data.GetText() ); - } -#endif + m_writer( wxString( prettyData.c_str(), wxConvUTF8 ) ); } BOARD_ITEM* CLIPBOARD_IO::Parse() { BOARD_ITEM* item; - wxString result; - - wxLogNull doNotLog; // disable logging of failed clipboard actions - - auto clipboard = wxTheClipboard; - wxClipboardLocker clipboardLock( clipboard ); - - if( !clipboardLock ) - return nullptr; - - if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) - { - wxTextDataObject data; - clipboard->GetData( data ); - result = data.GetText(); - } + wxString result = m_reader(); try { @@ -471,65 +485,25 @@ void CLIPBOARD_IO::SaveBoard( const wxString& aFileName, BOARD* aBoard, // Prepare net mapping that assures that net codes saved in a file are consecutive integers m_mapping->SetBoard( aBoard ); - STRING_FORMATTER formatter; - - m_out = &formatter; - - m_out->Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)", + m_formatter.Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)", SEXPR_BOARD_FILE_VERSION, - m_out->Quotew( GetMajorMinorVersion() ).c_str() ); + m_formatter.Quotew( GetMajorMinorVersion() ).c_str() ); Format( aBoard ); - m_out->Print( ")" ); + m_formatter.Print( ")" ); - wxLogNull doNotLog; // disable logging of failed clipboard actions + std::string prettyData = m_formatter.GetString(); + KICAD_FORMAT::Prettify( prettyData, true ); - auto clipboard = wxTheClipboard; - wxClipboardLocker clipboardLock( clipboard ); - - if( !clipboardLock ) - return; - - clipboard->SetData( new wxTextDataObject( - wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) ); - clipboard->Flush(); - - // This section exists to return the clipboard data, ensuring it has fully - // been processed by the system clipboard. This appears to be needed for - // extremely large clipboard copies on asynchronous linux clipboard managers - // such as KDE's Klipper - if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) - { - wxTextDataObject data; - clipboard->GetData( data ); - ignore_unused( data.GetText() ); - } + m_writer( wxString( prettyData.c_str(), wxConvUTF8 ) ); } BOARD* CLIPBOARD_IO::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe, const std::map* aProperties, PROJECT* aProject ) { - std::string result; - - wxLogNull doNotLog; // disable logging of failed clipboard actions - - fontconfig::FONTCONFIG::SetReporter( nullptr ); - - auto clipboard = wxTheClipboard; - wxClipboardLocker clipboardLock( clipboard ); - - if( !clipboardLock ) - return nullptr; - - if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) ) - { - wxTextDataObject data; - clipboard->GetData( data ); - - result = data.GetText().mb_str(); - } + std::string result( m_reader().mb_str() ); std::function queryUser = [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool diff --git a/pcbnew/kicad_clipboard.h b/pcbnew/kicad_clipboard.h index 7672904d77..49e7e40e18 100644 --- a/pcbnew/kicad_clipboard.h +++ b/pcbnew/kicad_clipboard.h @@ -44,6 +44,9 @@ public: CLIPBOARD_IO(); ~CLIPBOARD_IO(); + void SetWriter( std::function aWriter ) { m_writer = aWriter; } + void SetReader( std::function aReader ) { m_reader = aReader; } + /* * Saves the entire board to the clipboard formatted using the PCB_IO_KICAD_SEXPR formatting */ @@ -64,7 +67,12 @@ public: void SetBoard( BOARD* aBoard ); private: + static void clipboardWriter( const wxString& aData ); + static wxString clipboardReader(); + STRING_FORMATTER m_formatter; + std::function m_writer; + std::function m_reader; };