KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_clipboard.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 KiCad Developers, see AUTHORS.TXT for contributors.
5 * Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Kristoffer Ödmark
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <wx/clipbrd.h>
27#include <wx/log.h>
28
29#include <board.h>
30#include <core/ignore.h>
31#include <pad.h>
32#include <pcb_group.h>
33#include <pcb_shape.h>
34#include <pcb_text.h>
35#include <pcb_textbox.h>
36#include <zone.h>
37#include <locale_io.h>
38#include <netinfo.h>
40
42#include <kicad_clipboard.h>
43#include "confirm.h"
44
47 m_formatter()
48{
50}
51
52
54{
55}
56
57
59{
60 m_board = aBoard;
61}
62
63
64void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootprintEditor )
65{
66 VECTOR2I refPoint( 0, 0 );
67
68 // dont even start if the selection is empty
69 if( aSelected.Empty() )
70 return;
71
72 if( aSelected.HasReferencePoint() )
73 refPoint = aSelected.GetReferencePoint();
74
75 // Prepare net mapping that assures that net codes saved in a file are consecutive integers
77
78 if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_FOOTPRINT_T )
79 {
80 // make the footprint safe to transfer to other pcbs
81 const FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aSelected.Front() );
82 // Do not modify existing board
83 FOOTPRINT newFootprint( *footprint );
84
85 for( PAD* pad : newFootprint.Pads() )
86 pad->SetNetCode( 0 );
87
88 // locked means "locked in place"; copied items therefore can't be locked
89 newFootprint.SetLocked( false );
90
91 // locate the reference point at (0, 0) in the copied items
92 newFootprint.Move( VECTOR2I( -refPoint.x, -refPoint.y ) );
93
94 Format( static_cast<BOARD_ITEM*>( &newFootprint ) );
95
96 newFootprint.SetParent( nullptr );
97 newFootprint.SetParentGroup( nullptr );
98 }
99 else if( isFootprintEditor )
100 {
101 FOOTPRINT partialFootprint( m_board );
102
103 // Useful to copy the selection to the board editor (if any), and provides
104 // a dummy lib id.
105 // Perhaps not a good Id, but better than a empty id
106 KIID dummy;
107 LIB_ID id( "clipboard", dummy.AsString() );
108 partialFootprint.SetFPID( id );
109
110 for( const EDA_ITEM* item : aSelected )
111 {
112 const BOARD_ITEM* boardItem = dynamic_cast<const BOARD_ITEM*>( item );
113 const PCB_GROUP* group = dynamic_cast<const PCB_GROUP*>( item );
114 BOARD_ITEM* clone = nullptr;
115
116 wxCHECK2( boardItem, continue );
117
118 if( const PCB_FIELD* field = dynamic_cast<const PCB_FIELD*>( item ) )
119 {
120 if( field->IsMandatoryField() )
121 continue;
122 }
123
124 if( group )
125 clone = static_cast<BOARD_ITEM*>( group->DeepClone() );
126 else
127 clone = static_cast<BOARD_ITEM*>( boardItem->Clone() );
128
129 // If it is only a footprint, clear the nets from the pads
130 if( PAD* pad = dynamic_cast<PAD*>( clone ) )
131 pad->SetNetCode( 0 );
132
133 // Don't copy group membership information for the 1st level objects being copied
134 // since the group they belong to isn't being copied.
135 clone->SetParentGroup( nullptr );
136
137 // Add the pad to the new footprint before moving to ensure the local coords are
138 // correct
139 partialFootprint.Add( clone );
140
141 // A list of not added items, when adding items to the footprint
142 // some PCB_TEXT (reference and value) cannot be added to the footprint
143 std::vector<BOARD_ITEM*> skipped_items;
144
145 if( group )
146 {
147 static_cast<PCB_GROUP*>( clone )->RunOnDescendants(
148 [&]( BOARD_ITEM* descendant )
149 {
150 // One cannot add an additional mandatory field to a given footprint:
151 // only one is allowed. So add only non-mandatory fields.
152 bool can_add = true;
153
154 if( const PCB_FIELD* field = dynamic_cast<const PCB_FIELD*>( item ) )
155 {
156 if( field->IsMandatoryField() )
157 can_add = false;
158 }
159
160 if( can_add )
161 partialFootprint.Add( descendant );
162 else
163 skipped_items.push_back( descendant );
164 } );
165 }
166
167 // locate the reference point at (0, 0) in the copied items
168 clone->Move( -refPoint );
169
170 // Now delete items, duplicated but not added:
171 for( BOARD_ITEM* skp_item : skipped_items )
172 {
173 skp_item->SetParentGroup( nullptr );
174 delete skp_item;
175 }
176 }
177
178 // Set the new relative internal local coordinates of copied items
179 FOOTPRINT* editedFootprint = m_board->Footprints().front();
180 VECTOR2I moveVector = partialFootprint.GetPosition() + editedFootprint->GetPosition();
181
182 partialFootprint.MoveAnchorPosition( moveVector );
183
184 Format( &partialFootprint, 0 );
185
186 partialFootprint.SetParent( nullptr );
187 }
188 else
189 {
190 // we will fake being a .kicad_pcb to get the full parser kicking
191 // This means we also need layers and nets
192 LOCALE_IO io;
193
194 m_formatter.Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n",
196
197 m_formatter.Print( 0, "\n" );
198
201
202 m_formatter.Print( 0, "\n" );
203
204 for( EDA_ITEM* item : aSelected )
205 {
206 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
207 BOARD_ITEM* copy = nullptr;
208
209 wxCHECK2( boardItem, continue );
210
211 if( boardItem->Type() == PCB_FIELD_T || boardItem->Type() == PCB_TEXT_T )
212 {
213 copy = static_cast<BOARD_ITEM*>( boardItem->Clone() );
214
215 PCB_TEXT* textItem = static_cast<PCB_TEXT*>( copy );
216
217 if( textItem->GetText() == wxT( "${VALUE}" ) )
218 textItem->SetText( boardItem->GetParentFootprint()->GetValue() );
219 else if( textItem->GetText() == wxT( "${REFERENCE}" ) )
220 textItem->SetText( boardItem->GetParentFootprint()->GetReference() );
221 }
222 else if( boardItem->Type() == PCB_PAD_T )
223 {
224 // Create a parent to own the copied pad
225 FOOTPRINT* footprint = new FOOTPRINT( m_board );
226 PAD* pad = (PAD*) boardItem->Clone();
227
228 footprint->SetPosition( pad->GetPosition() );
229 footprint->Add( pad );
230 copy = footprint;
231 }
232 else if( boardItem->Type() == PCB_GROUP_T )
233 {
234 copy = static_cast<PCB_GROUP*>( boardItem )->DeepClone();
235 }
236 else
237 {
238 copy = static_cast<BOARD_ITEM*>( boardItem->Clone() );
239 }
240
241 auto prepItem = [&]( BOARD_ITEM* aItem )
242 {
243 aItem->SetLocked( false );
244 };
245
246 if( copy )
247 {
248 prepItem( copy );
249
250 // locate the reference point at (0, 0) in the copied items
251 copy->Move( -refPoint );
252
253 Format( copy, 1 );
254
255 if( copy->Type() == PCB_GROUP_T )
256 {
257 static_cast<PCB_GROUP*>( copy )->RunOnDescendants( prepItem );
258 static_cast<PCB_GROUP*>( copy )->RunOnDescendants( [&]( BOARD_ITEM* titem )
259 {
260 Format( titem, 1 );
261 } );
262 }
263
264 copy->SetParentGroup( nullptr );
265 delete copy;
266 }
267 }
268 m_formatter.Print( 0, "\n)" );
269 }
270
271 // These are placed at the end to minimize the open time of the clipboard
272 wxLogNull doNotLog; // disable logging of failed clipboard actions
273 auto clipboard = wxTheClipboard;
274 wxClipboardLocker clipboardLock( clipboard );
275
276 if( !clipboardLock || !clipboard->IsOpened() )
277 return;
278
279 clipboard->SetData( new wxTextDataObject( wxString( m_formatter.GetString().c_str(),
280 wxConvUTF8 ) ) );
281
282 clipboard->Flush();
283
284 #ifndef __WXOSX__
285 // This section exists to return the clipboard data, ensuring it has fully
286 // been processed by the system clipboard. This appears to be needed for
287 // extremely large clipboard copies on asynchronous linux clipboard managers
288 // such as KDE's Klipper. However, a read back of the data on OSX before the
289 // clipboard is closed seems to cause an ASAN error (heap-buffer-overflow)
290 // since it uses the cached version of the clipboard data and not the system
291 // clipboard data.
292 if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) )
293 {
294 wxTextDataObject data;
295 clipboard->GetData( data );
296 ignore_unused( data.GetText() );
297 }
298 #endif
299}
300
301
303{
304 BOARD_ITEM* item;
305 wxString result;
306
307 wxLogNull doNotLog; // disable logging of failed clipboard actions
308
309 auto clipboard = wxTheClipboard;
310 wxClipboardLocker clipboardLock( clipboard );
311
312 if( !clipboardLock )
313 return nullptr;
314
315 if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) )
316 {
317 wxTextDataObject data;
318 clipboard->GetData( data );
319 result = data.GetText();
320 }
321
322 try
323 {
324 item = PCB_PLUGIN::Parse( result );
325 }
326 catch (...)
327 {
328 item = nullptr;
329 }
330
331 return item;
332}
333
334
335void CLIPBOARD_IO::SaveBoard( const wxString& aFileName, BOARD* aBoard,
336 const STRING_UTF8_MAP* aProperties )
337{
338 init( aProperties );
339
340 m_board = aBoard; // after init()
341
342 // Prepare net mapping that assures that net codes saved in a file are consecutive integers
343 m_mapping->SetBoard( aBoard );
344
345 STRING_FORMATTER formatter;
346
347 m_out = &formatter;
348
349 m_out->Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n", SEXPR_BOARD_FILE_VERSION );
350
351 Format( aBoard, 1 );
352
353 m_out->Print( 0, ")\n" );
354
355 wxLogNull doNotLog; // disable logging of failed clipboard actions
356
357 auto clipboard = wxTheClipboard;
358 wxClipboardLocker clipboardLock( clipboard );
359
360 if( !clipboardLock )
361 return;
362
363 clipboard->SetData( new wxTextDataObject(
364 wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
365 clipboard->Flush();
366
367 // This section exists to return the clipboard data, ensuring it has fully
368 // been processed by the system clipboard. This appears to be needed for
369 // extremely large clipboard copies on asynchronous linux clipboard managers
370 // such as KDE's Klipper
371 if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) )
372 {
373 wxTextDataObject data;
374 clipboard->GetData( data );
375 ignore_unused( data.GetText() );
376 }
377}
378
379
380BOARD* CLIPBOARD_IO::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
381 const STRING_UTF8_MAP* aProperties, PROJECT* aProject,
382 PROGRESS_REPORTER* aProgressReporter )
383{
384 std::string result;
385
386 wxLogNull doNotLog; // disable logging of failed clipboard actions
387
388 auto clipboard = wxTheClipboard;
389 wxClipboardLocker clipboardLock( clipboard );
390
391 if( !clipboardLock )
392 return nullptr;
393
394 if( clipboard->IsSupported( wxDF_TEXT ) || clipboard->IsSupported( wxDF_UNICODETEXT ) )
395 {
396 wxTextDataObject data;
397 clipboard->GetData( data );
398
399 result = data.GetText().mb_str();
400 }
401
402 std::function<bool( wxString, int, wxString, wxString )> queryUser =
403 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
404 {
405 KIDIALOG dlg( nullptr, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
406
407 if( !aAction.IsEmpty() )
408 dlg.SetOKLabel( aAction );
409
410 dlg.DoNotShowCheckbox( aMessage, 0 );
411
412 return dlg.ShowModal() == wxID_OK;
413 };
414
415 STRING_LINE_READER reader( result, wxT( "clipboard" ) );
416 PCB_PARSER parser( &reader, aAppendToMe, queryUser );
417
418 init( aProperties );
419
420 BOARD_ITEM* item;
421 BOARD* board;
422
423 try
424 {
425 item = parser.Parse();
426 }
427 catch( const FUTURE_FORMAT_ERROR& )
428 {
429 // Don't wrap a FUTURE_FORMAT_ERROR in another
430 throw;
431 }
432 catch( const PARSE_ERROR& parse_error )
433 {
434 if( parser.IsTooRecent() )
435 throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
436 else
437 throw;
438 }
439
440 if( item->Type() != PCB_T )
441 {
442 // The parser loaded something that was valid, but wasn't a board.
443 THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ), parser.CurSource(),
444 parser.CurLine(), parser.CurLineNumber(), parser.CurOffset() );
445 }
446 else
447 {
448 board = dynamic_cast<BOARD*>( item );
449 }
450
451 // Give the filename to the board if it's new
452 if( board && !aAppendToMe )
453 board->SetFileName( aFileName );
454
455 return board;
456}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
void SetParentGroup(PCB_GROUP *aGroup)
Definition: board_item.h:90
virtual void SetLocked(bool aLocked)
Definition: board_item.h:278
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:292
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:247
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:271
void SetFileName(const wxString &aFileName)
Definition: board.h:306
FOOTPRINTS & Footprints()
Definition: board.h:313
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
STRING_FORMATTER m_formatter
BOARD_ITEM * Parse()
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties=nullptr, PROJECT *aProject=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Load information from some input file format that this PLUGIN implementation knows about into either ...
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const STRING_UTF8_MAP *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PLUGIN implementation knows about or it can be u...
void SetBoard(BOARD *aBoard)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:82
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:95
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:180
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:1944
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:231
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: footprint.h:372
void MoveAnchorPosition(const VECTOR2I &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1971
PADS & Pads()
Definition: footprint.h:188
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition: footprint.cpp:1842
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:705
const wxString & GetValue() const
Definition: footprint.h:575
const wxString & GetReference() const
Definition: footprint.h:553
VECTOR2I GetPosition() const override
Definition: footprint.h:206
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:47
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
int ShowModal() override
Definition: confirm.cpp:100
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
void SetBoard(const BOARD *aBoard)
Set a BOARD object that is used to prepare the net code map.
Definition: netinfo.h:215
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:475
Definition: pad.h:58
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
Read a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD_ITEM object...
Definition: pcb_parser.h:74
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:105
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:765
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
Definition: pcb_parser.cpp:229
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
Definition: pcb_plugin.h:271
BOARD * m_board
which BOARD, no ownership here
Definition: pcb_plugin.h:440
void init(const STRING_UTF8_MAP *aProperties)
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
Definition: pcb_plugin.cpp:333
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
Definition: pcb_plugin.h:449
NETINFO_MAPPING * m_mapping
mapping for net codes, so only not empty net codes are stored with consecutive integers as net codes
Definition: pcb_plugin.h:451
void formatNetInformation(const BOARD *aBoard, int aNestLevel=0) const
formats the Nets and Netclasses
Definition: pcb_plugin.cpp:691
void formatBoardLayers(const BOARD *aBoard, int aNestLevel=0) const
formats the board layer information
Definition: pcb_plugin.cpp:621
void Format(const BOARD_ITEM *aItem, int aNestLevel=0) const
Output aItem to aFormatter in s-expression format.
Definition: pcb_plugin.cpp:354
A progress reporter interface for use in multi-threaded environments.
Container for project specific data.
Definition: project.h:62
VECTOR2I GetReferencePoint() const
Definition: selection.h:252
EDA_ITEM * Front() const
Definition: selection.h:208
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:109
bool HasReferencePoint() const
Definition: selection.h:247
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:427
const std::string & GetString()
Definition: richio.h:450
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:253
A name/value tuple with unique names and optional values.
This file is part of the common library.
#define _(s)
void ignore_unused(const T &)
Definition: ignore.h:24
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
Class to handle a set of BOARD_ITEMs.
Pcbnew s-expression file format parser definition.
#define CTL_FOR_CLIPBOARD
Format output for the clipboard instead of footprint library or BOARD.
Definition: pcb_plugin.h:165
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
Definition: pcb_plugin.h:143
std::vector< FAB_LAYER_COLOR > dummy
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:175
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119
@ PCB_T
Definition: typeinfo.h:82
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588