KiCad PCB EDA Suite
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 CHANGELOG.TXT for contributors.
5  * @author Kristoffer Ödmark
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <wx/clipbrd.h>
26 
27 #include <build_version.h>
28 #include <board.h>
29 #include <track.h>
30 #include <pcb_shape.h>
31 #include <pcb_text.h>
32 #include <fp_text.h>
33 #include <locale_io.h>
34 #include <netinfo.h>
36 
38 #include <kicad_clipboard.h>
39 
42  m_formatter(),
43  m_parser( new PCB_PARSER() )
44 {
45  m_out = &m_formatter;
46 }
47 
48 
50 {
51  delete m_parser;
52 }
53 
54 
56 {
57  m_board = aBoard;
58 }
59 
60 
61 void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootprintEditor )
62 {
63  VECTOR2I refPoint( 0, 0 );
64 
65  // dont even start if the selection is empty
66  if( aSelected.Empty() )
67  return;
68 
69  if( aSelected.HasReferencePoint() )
70  refPoint = aSelected.GetReferencePoint();
71 
72  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
74 
75  if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_FOOTPRINT_T )
76  {
77  // make the footprint safe to transfer to other pcbs
78  const FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aSelected.Front() );
79  // Do not modify existing board
80  FOOTPRINT newFootprint( *footprint );
81 
82  for( PAD* pad : newFootprint.Pads() )
83  pad->SetNetCode( 0 );
84 
85  // locked means "locked in place"; copied items therefore can't be locked
86  newFootprint.SetLocked( false );
87 
88  // locate the reference point at (0, 0) in the copied items
89  newFootprint.Move( wxPoint( -refPoint.x, -refPoint.y ) );
90 
91  Format( static_cast<BOARD_ITEM*>( &newFootprint ) );
92  }
93  else if( isFootprintEditor )
94  {
95  FOOTPRINT partialFootprint( m_board );
96 
97  // Usefull to copy the selection to the board editor (if any), and provides
98  // a dummy lib id.
99  // Perhaps not a good Id, but better than a empty id
100  KIID dummy;
101  LIB_ID id( "clipboard", dummy.AsString() );
102  partialFootprint.SetFPID( id );
103 
104  for( const EDA_ITEM* item : aSelected )
105  {
106  const PCB_GROUP* group = dynamic_cast<const PCB_GROUP*>( item );
107  BOARD_ITEM* clone;
108 
109  if( group )
110  clone = static_cast<BOARD_ITEM*>( group->DeepClone() );
111  else
112  clone = static_cast<BOARD_ITEM*>( item->Clone() );
113 
114  // If it is only a footprint, clear the nets from the pads
115  if( PAD* pad = dyn_cast<PAD*>( clone ) )
116  pad->SetNetCode( 0 );
117 
118  // Add the pad to the new footprint before moving to ensure the local coords are
119  // correct
120  partialFootprint.Add( clone );
121 
122  if( group )
123  {
124  static_cast<PCB_GROUP*>( clone )->RunOnDescendants(
125  [&]( BOARD_ITEM* descendant )
126  {
127  partialFootprint.Add( descendant );
128  } );
129  }
130 
131  // locate the reference point at (0, 0) in the copied items
132  clone->Move( (wxPoint) -refPoint );
133  }
134 
135  // Set the new relative internal local coordinates of copied items
136  FOOTPRINT* editedFootprint = m_board->Footprints().front();
137  wxPoint moveVector = partialFootprint.GetPosition() + editedFootprint->GetPosition();
138 
139  partialFootprint.MoveAnchorPosition( moveVector );
140 
141  Format( &partialFootprint, 0 );
142  }
143  else
144  {
145  // we will fake being a .kicad_pcb to get the full parser kicking
146  // This means we also need layers and nets
147  LOCALE_IO io;
148 
149  m_formatter.Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n",
151 
152  m_formatter.Print( 0, "\n" );
153 
156 
157  m_formatter.Print( 0, "\n" );
158 
159  for( EDA_ITEM* i : aSelected )
160  {
161  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
162  BOARD_ITEM* copy = nullptr;
163 
164  if( item->Type() == PCB_FP_SHAPE_T )
165  {
166  // Convert to PCB_SHAPE_T
167  copy = (BOARD_ITEM*) reinterpret_cast<PCB_SHAPE*>( item )->Clone();
168  copy->SetLayer( item->GetLayer() );
169  }
170  else if( item->Type() == PCB_FP_TEXT_T )
171  {
172  // Convert to PCB_TEXT_T
173  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item->GetParent() );
174  FP_TEXT* fp_text = static_cast<FP_TEXT*>( item );
175  PCB_TEXT* pcb_text = new PCB_TEXT( m_board );
176 
177  if( fp_text->GetText() == "${VALUE}" )
178  pcb_text->SetText( footprint->GetValue() );
179  else if( fp_text->GetText() == "${REFERENCE}" )
180  pcb_text->SetText( footprint->GetReference() );
181  else
182  pcb_text->CopyText( *fp_text );
183 
184  pcb_text->SetEffects( *fp_text );
185  pcb_text->SetLayer( fp_text->GetLayer() );
186  copy = pcb_text;
187  }
188  else if( item->Type() == PCB_PAD_T )
189  {
190  // Create a parent to own the copied pad
191  FOOTPRINT* footprint = new FOOTPRINT( m_board );
192  PAD* pad = (PAD*) item->Clone();
193 
194  footprint->SetPosition( pad->GetPosition() );
195  pad->SetPos0( wxPoint() );
196  footprint->Add( pad );
197  copy = footprint;
198  }
199  else if( item->Type() == PCB_FP_ZONE_T )
200  {
201  // Convert to PCB_ZONE_T
202  ZONE* zone = new ZONE( m_board );
203  zone->InitDataFromSrcInCopyCtor( *static_cast<ZONE*>( item ) );
204  copy = zone;
205  }
206  else if( item->Type() == PCB_GROUP_T )
207  {
208  copy = static_cast<PCB_GROUP*>( item )->DeepClone();
209  }
210  else
211  {
212  copy = static_cast<BOARD_ITEM*>( item->Clone() );
213  }
214 
215  auto prepItem = [&]( BOARD_ITEM* aItem )
216  {
217  aItem->SetLocked( false );
218  };
219 
220  if( copy )
221  {
222  prepItem( copy );
223 
224  // locate the reference point at (0, 0) in the copied items
225  copy->Move( (wxPoint) -refPoint );
226 
227  Format( copy, 1 );
228 
229  if( copy->Type() == PCB_GROUP_T )
230  {
231  static_cast<PCB_GROUP*>( copy )->RunOnDescendants( prepItem );
232  static_cast<PCB_GROUP*>( copy )->RunOnDescendants( [&]( BOARD_ITEM* titem )
233  {
234  Format( titem, 1 );
235  } );
236  }
237 
238  delete copy;
239  }
240  }
241  m_formatter.Print( 0, "\n)" );
242  }
243 
244  // These are placed at the end to minimize the open time of the clipboard
245  auto clipboard = wxTheClipboard;
246  wxClipboardLocker clipboardLock( clipboard );
247 
248  if( !clipboardLock || !clipboard->IsOpened() )
249  return;
250 
251  clipboard->SetData( new wxTextDataObject( wxString( m_formatter.GetString().c_str(),
252  wxConvUTF8 ) ) );
253 
254  clipboard->Flush();
255 
256  #ifndef __WXOSX__
257  // This section exists to return the clipboard data, ensuring it has fully
258  // been processed by the system clipboard. This appears to be needed for
259  // extremely large clipboard copies on asynchronous linux clipboard managers
260  // such as KDE's Klipper. However, a read back of the data on OSX before the
261  // clipboard is closed seems to cause an ASAN error (heap-buffer-overflow)
262  // since it uses the cached version of the clipboard data and not the system
263  // clipboard data.
264  {
265  wxTextDataObject data;
266  clipboard->GetData( data );
267  ( void )data.GetText(); // Keep unused variable
268  }
269  #endif
270 }
271 
272 
274 {
275  BOARD_ITEM* item;
276  wxString result;
277 
278  auto clipboard = wxTheClipboard;
279  wxClipboardLocker clipboardLock( clipboard );
280 
281  if( !clipboardLock )
282  return nullptr;
283 
284 
285  if( clipboard->IsSupported( wxDF_TEXT ) )
286  {
287  wxTextDataObject data;
288  clipboard->GetData( data );
289  result = data.GetText();
290  }
291 
292  try
293  {
294  item = PCB_IO::Parse( result );
295  }
296  catch (...)
297  {
298  item = nullptr;
299  }
300 
301  return item;
302 }
303 
304 
305 void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
306  const PROPERTIES* aProperties )
307 {
308  init( aProperties );
309 
310  m_board = aBoard; // after init()
311 
312  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
313  m_mapping->SetBoard( aBoard );
314 
315  STRING_FORMATTER formatter;
316 
317  m_out = &formatter;
318 
319  m_out->Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n", SEXPR_BOARD_FILE_VERSION );
320 
321  Format( aBoard, 1 );
322 
323  m_out->Print( 0, ")\n" );
324 
325  auto clipboard = wxTheClipboard;
326  wxClipboardLocker clipboardLock( clipboard );
327 
328  if( !clipboardLock )
329  return;
330 
331  clipboard->SetData( new wxTextDataObject(
332  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
333  clipboard->Flush();
334 
335  // This section exists to return the clipboard data, ensuring it has fully
336  // been processed by the system clipboard. This appears to be needed for
337  // extremely large clipboard copies on asynchronous linux clipboard managers
338  // such as KDE's Klipper
339  {
340  wxTextDataObject data;
341  clipboard->GetData( data );
342  ( void )data.GetText(); // Keep unused variable
343  }
344 }
345 
346 
347 BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe,
348  const PROPERTIES* aProperties, PROJECT* aProject )
349 {
350  std::string result;
351 
352  auto clipboard = wxTheClipboard;
353  wxClipboardLocker clipboardLock( clipboard );
354 
355  if( !clipboardLock )
356  return nullptr;
357 
358  if( clipboard->IsSupported( wxDF_TEXT ) )
359  {
360  wxTextDataObject data;
361  clipboard->GetData( data );
362 
363  result = data.GetText().mb_str();
364  }
365 
366  STRING_LINE_READER reader(result, wxT( "clipboard" ) );
367 
368  init( aProperties );
369 
370  m_parser->SetLineReader( &reader );
371  m_parser->SetBoard( aAppendToMe );
372 
373  BOARD_ITEM* item;
374  BOARD* board;
375 
376  try
377  {
378  item = m_parser->Parse();
379  }
380  catch( const FUTURE_FORMAT_ERROR& )
381  {
382  // Don't wrap a FUTURE_FORMAT_ERROR in another
383  throw;
384  }
385  catch( const PARSE_ERROR& parse_error )
386  {
387  if( m_parser->IsTooRecent() )
388  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
389  else
390  throw;
391  }
392 
393  if( item->Type() != PCB_T )
394  {
395  // The parser loaded something that was valid, but wasn't a board.
396  THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ),
397  m_parser->CurSource(), m_parser->CurLine(),
398  m_parser->CurLineNumber(), m_parser->CurOffset() );
399  }
400  else
401  {
402  board = dynamic_cast<BOARD*>( item );
403  }
404 
405  // Give the filename to the board if it's new
406  if( board && !aAppendToMe )
407  board->SetFileName( aFileName );
408 
409  return board;
410 }
VECTOR2I GetReferencePoint() const
Definition: selection.h:259
BOARD_ITEM * Parse()
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
Definition: typeinfo.h:84
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
Container for project specific data.
Definition: project.h:62
void formatBoardLayers(const BOARD *aBoard, int aNestLevel=0) const
formats the board layer information
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
void CopyText(const EDA_TEXT &aSrc)
Definition: eda_text.cpp:129
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:194
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
const wxString GetValue() const
Function GetValue.
Definition: footprint.h:467
void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PLUGIN implementation knows about or it can be u...
PCB_GROUP is a set of BOARD_ITEMs (i.e., without duplicates)
Definition: pcb_group.h:50
PCB_PARSER reads a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD...
Definition: pcb_parser.h:69
void init(const PROPERTIES *aProperties)
void SetEffects(const EDA_TEXT &aSrc)
Set the text effects from another instance.
Definition: eda_text.cpp:137
PCB_GROUP * DeepClone() const
Definition: pcb_group.cpp:136
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:257
STRING_FORMATTER m_formatter
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
A name/value tuple with unique names and optional values.
Definition: properties.h:33
void SetBoard(BOARD *aBoard)
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:97
void SetBoard(const BOARD *aBoard)
Function SetBoard Sets a BOARD object that is used to prepare the net code map.
Definition: netinfo.h:202
#define CTL_FOR_CLIPBOARD
Format output for the clipboard instead of footprint library or BOARD.
Definition: kiid.h:44
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:184
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
void SetBoard(BOARD *aBoard)
Definition: pcb_parser.h:359
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
void SetPos0(const wxPoint &aPos)
Definition: pad.h:228
virtual void Move(const wxPoint &aMoveVector)
Move this object.
Definition: board_item.h:277
FOOTPRINTS & Footprints()
Definition: board.h:286
void formatNetInformation(const BOARD *aBoard, int aNestLevel=0) const
formats the Nets and Netclasses
void InitDataFromSrcInCopyCtor(const ZONE &aZone)
Copy aZone data to me.
Definition: zone.cpp:105
void MoveAnchorPosition(const wxPoint &aMoveVector)
Function MoveAnchorPosition Move the reference point of the footprint It looks like a move footprint:...
Definition: footprint.cpp:1405
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
const std::string & GetString()
Definition: richio.h:435
const wxString GetReference() const
Function GetReference.
Definition: footprint.h:442
void SetFileName(const wxString &aFileName)
Definition: board.h:279
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PLUGIN implementation knows about into either ...
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:473
NETINFO_MAPPING * m_mapping
mapping for net codes, so only not empty net codes are stored with consecutive integers as net codes
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one,...
Definition: pcb_parser.h:352
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:122
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:209
void Format(const BOARD_ITEM *aItem, int aNestLevel=0) const
Output aItem to aFormatter in s-expression format.
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:380
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
bool HasReferencePoint() const
Definition: selection.h:254
wxPoint GetPosition() const override
Definition: pad.h:176
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:189
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
#define _(s)
Definition: 3d_actions.cpp:33
class ZONE, managed by a footprint
Definition: typeinfo.h:94
BOARD * m_board
which BOARD, no ownership here
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
wxPoint GetPosition() const override
Definition: footprint.h:200
Pcbnew s-expression file format parser definition.
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:174
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Definition: footprint.cpp:445
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:408
Definition: pad.h:60
void SetPosition(const wxPoint &aPos) override
Definition: footprint.cpp:1362
void SaveSelection(const PCB_SELECTION &selected, bool isFootprintEditor)
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:237
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:411
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:173
PCB_PARSER * m_parser
EDA_ITEM * Front() const
Definition: selection.h:203
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161