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 <class_board.h>
29 #include <class_track.h>
30 #include <class_drawsegment.h>
31 #include <class_pcb_text.h>
32 #include <class_text_mod.h>
33 #include <common.h>
34 #include <netinfo.h>
35 #include <pcb_parser.h>
36 
37 #include <kicad_plugin.h>
38 #include <kicad_clipboard.h>
39 
42  m_formatter(),
43  m_parser( new CLIPBOARD_PARSER() )
44 {
45  m_out = &m_formatter;
46 }
47 
48 
50 {
51  delete m_parser;
52 }
53 
54 
56 {
57  return &m_formatter;
58 }
59 
60 
62 {
63  m_board = aBoard;
64 }
65 
66 
67 void CLIPBOARD_IO::SaveSelection( const PCBNEW_SELECTION& aSelected, bool isModEdit )
68 {
69  VECTOR2I refPoint( 0, 0 );
70 
71  // dont even start if the selection is empty
72  if( aSelected.Empty() )
73  return;
74 
75  if( aSelected.HasReferencePoint() )
76  refPoint = aSelected.GetReferencePoint();
77 
78  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
80 
81  if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_MODULE_T )
82  {
83  // make the module safe to transfer to other pcbs
84  const MODULE* mod = static_cast<MODULE*>( aSelected.Front() );
85  // Do not modify existing board
86  MODULE newModule( *mod );
87 
88  for( D_PAD* pad : newModule.Pads() )
89  pad->SetNetCode( 0 );
90 
91  // locked means "locked in place"; copied items therefore can't be locked
92  newModule.SetLocked( false );
93 
94  // locate the reference point at (0, 0) in the copied items
95  newModule.Move( wxPoint( -refPoint.x, -refPoint.y ) );
96 
97  Format( static_cast<BOARD_ITEM*>( &newModule ) );
98  }
99  else if( isModEdit )
100  {
101  MODULE partialModule( m_board );
102 
103  for( const EDA_ITEM* item : aSelected )
104  {
105  BOARD_ITEM* clone = static_cast<BOARD_ITEM*>( item->Clone() );
106 
107  // Do not add reference/value - convert them to the common type
108  if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) )
109  text->SetType( TEXTE_MODULE::TEXT_is_DIVERS );
110 
111  // If it is only a module, clear the nets from the pads
112  if( D_PAD* pad = dyn_cast<D_PAD*>( clone ) )
113  pad->SetNetCode( 0 );
114 
115  // Add the pad to the new module before moving to ensure the local coords are correct
116  partialModule.Add( clone );
117 
118  // locate the reference point at (0, 0) in the copied items
119  clone->Move( (wxPoint) -refPoint );
120  }
121 
122  // Set the new relative internal local coordinates of copied items
123  MODULE* editedModule = m_board->Modules().front();
124  wxPoint moveVector = partialModule.GetPosition() + editedModule->GetPosition();
125 
126  partialModule.MoveAnchorPosition( moveVector );
127 
128  Format( &partialModule, 0 );
129  }
130  else
131  {
132  // we will fake being a .kicad_pcb to get the full parser kicking
133  // This means we also need layers and nets
134  LOCALE_IO io;
135 
136  m_formatter.Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n",
138 
139  m_formatter.Print( 0, "\n" );
140 
143 
144  m_formatter.Print( 0, "\n" );
145 
146  for( EDA_ITEM* i : aSelected )
147  {
148  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
149  BOARD_ITEM* copy = nullptr;
150 
151  if( item->Type() == PCB_MODULE_EDGE_T )
152  {
153  // Convert to PCB_LINE_T
154  copy = (BOARD_ITEM*) reinterpret_cast<DRAWSEGMENT*>( item )->Clone();
155  copy->SetLayer( item->GetLayer() );
156  }
157  else if( item->Type() == PCB_MODULE_TEXT_T )
158  {
159  // Convert to PCB_TEXT_T
160  MODULE* mod = static_cast<MODULE*>( item->GetParent() );
161  TEXTE_MODULE* mod_text = static_cast<TEXTE_MODULE*>( item );
162  TEXTE_PCB* pcb_text = new TEXTE_PCB( m_board );
163 
164  if( mod_text->GetText() == "${VALUE}" )
165  pcb_text->SetText( mod->GetValue() );
166  else if( mod_text->GetText() == "${REFERENCE}" )
167  pcb_text->SetText( mod->GetReference() );
168  else
169  pcb_text->CopyText( *mod_text );
170 
171  pcb_text->SetEffects( *mod_text );
172  pcb_text->SetLayer( mod_text->GetLayer() );
173  copy = pcb_text;
174  }
175  else if( item->Type() == PCB_PAD_T )
176  {
177  // Create a parent to own the copied pad
178  MODULE* mod = new MODULE( m_board );
179  D_PAD* pad = (D_PAD*) item->Clone();
180 
181  mod->SetPosition( pad->GetPosition() );
182  pad->SetPos0( wxPoint() );
183  mod->Add( pad );
184  copy = mod;
185  }
186  else if( item->Type() == PCB_MODULE_ZONE_AREA_T )
187  {
188  // Convert to PCB_ZONE_AREA_T
189  ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
190  zone->InitDataFromSrcInCopyCtor( *static_cast<ZONE_CONTAINER*>( item ) );
191  copy = zone;
192  }
193  else if( item->Type() == PCB_GROUP_T )
194  {
195  copy = static_cast<PCB_GROUP*>( item )->DeepClone();
196  }
197  else
198  {
199  copy = static_cast<BOARD_ITEM*>( item->Clone() );
200  }
201 
202  auto prepItem = [&]( BOARD_ITEM* titem ) {
203  // locked means "locked in place"; copied items therefore can't be locked
204  if( MODULE* module = dyn_cast<MODULE*>( titem ) )
205  module->SetLocked( false );
206  else if( TRACK* track = dyn_cast<TRACK*>( titem ) )
207  track->SetLocked( false );
208  };
209 
210  if( copy )
211  {
212  prepItem( copy );
213 
214  // locate the reference point at (0, 0) in the copied items
215  copy->Move( (wxPoint) -refPoint );
216 
217  Format( copy, 1 );
218 
219  if( copy->Type() == PCB_GROUP_T )
220  {
221  static_cast<PCB_GROUP*>( copy )->RunOnDescendants( prepItem );
222  static_cast<PCB_GROUP*>( copy )->RunOnDescendants( [&]( BOARD_ITEM* titem ) {
223  Format( titem, 1 );
224  } );
225  }
226 
227  delete copy;
228  }
229  }
230  m_formatter.Print( 0, "\n)" );
231  }
232 
233  // These are placed at the end to minimize the open time of the clipboard
234  auto clipboard = wxTheClipboard;
235  wxClipboardLocker clipboardLock( clipboard );
236 
237  if( !clipboardLock || !clipboard->IsOpened() )
238  return;
239 
240  clipboard->SetData( new wxTextDataObject(
241  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
242 
243  clipboard->Flush();
244 
245  #ifndef __WXOSX__
246  // This section exists to return the clipboard data, ensuring it has fully
247  // been processed by the system clipboard. This appears to be needed for
248  // extremely large clipboard copies on asynchronous linux clipboard managers
249  // such as KDE's Klipper. However, a read back of the data on OSX before the
250  // clipboard is closed seems to cause an ASAN error (heap-buffer-overflow)
251  // since it uses the cached version of the clipboard data and not the system
252  // clipboard data.
253  {
254  wxTextDataObject data;
255  clipboard->GetData( data );
256  ( void )data.GetText(); // Keep unused variable
257  }
258  #endif
259 }
260 
261 
263 {
264  BOARD_ITEM* item;
265  wxString result;
266 
267  auto clipboard = wxTheClipboard;
268  wxClipboardLocker clipboardLock( clipboard );
269 
270  if( !clipboardLock )
271  return nullptr;
272 
273 
274  if( clipboard->IsSupported( wxDF_TEXT ) )
275  {
276  wxTextDataObject data;
277  clipboard->GetData( data );
278  result = data.GetText();
279  }
280 
281  try
282  {
283  item = PCB_IO::Parse( result );
284  }
285  catch (...)
286  {
287  item = nullptr;
288  }
289 
290  return item;
291 }
292 
293 
294 void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
295  const PROPERTIES* aProperties )
296 {
297  init( aProperties );
298 
299  m_board = aBoard; // after init()
300 
301  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
302  m_mapping->SetBoard( aBoard );
303 
304  STRING_FORMATTER formatter;
305 
306  m_out = &formatter;
307 
308  m_out->Print( 0, "(kicad_pcb (version %d) (generator pcbnew)\n", SEXPR_BOARD_FILE_VERSION );
309 
310  Format( aBoard, 1 );
311 
312  m_out->Print( 0, ")\n" );
313 
314  auto clipboard = wxTheClipboard;
315  wxClipboardLocker clipboardLock( clipboard );
316 
317  if( !clipboardLock )
318  return;
319 
320  clipboard->SetData( new wxTextDataObject(
321  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
322  clipboard->Flush();
323 
324  // This section exists to return the clipboard data, ensuring it has fully
325  // been processed by the system clipboard. This appears to be needed for
326  // extremely large clipboard copies on asynchronous linux clipboard managers
327  // such as KDE's Klipper
328  {
329  wxTextDataObject data;
330  clipboard->GetData( data );
331  ( void )data.GetText(); // Keep unused variable
332  }
333 }
334 
335 
336 BOARD* CLIPBOARD_IO::Load( const wxString& aFileName,
337  BOARD* aAppendToMe, const PROPERTIES* aProperties )
338 {
339  std::string result;
340 
341  auto clipboard = wxTheClipboard;
342  wxClipboardLocker clipboardLock( clipboard );
343 
344  if( !clipboardLock )
345  return nullptr;
346 
347  if( clipboard->IsSupported( wxDF_TEXT ) )
348  {
349  wxTextDataObject data;
350  clipboard->GetData( data );
351 
352  result = data.GetText().mb_str();
353  }
354 
355  STRING_LINE_READER reader(result, wxT( "clipboard" ) );
356 
357  init( aProperties );
358 
359  m_parser->SetLineReader( &reader );
360  m_parser->SetBoard( aAppendToMe );
361 
362  BOARD_ITEM* item;
363  BOARD* board;
364 
365  try
366  {
367  item = m_parser->Parse();
368  }
369  catch( const FUTURE_FORMAT_ERROR& )
370  {
371  // Don't wrap a FUTURE_FORMAT_ERROR in another
372  throw;
373  }
374  catch( const PARSE_ERROR& parse_error )
375  {
376  if( m_parser->IsTooRecent() )
377  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
378  else
379  throw;
380  }
381 
382  if( item->Type() != PCB_T )
383  {
384  // The parser loaded something that was valid, but wasn't a board.
385  THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ),
386  m_parser->CurSource(), m_parser->CurLine(),
387  m_parser->CurLineNumber(), m_parser->CurOffset() );
388  }
389  else
390  {
391  board = dynamic_cast<BOARD*>( item );
392  }
393 
394  // Give the filename to the board if it's new
395  if( board && !aAppendToMe )
396  board->SetFileName( aFileName );
397 
398  return board;
399 }
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL) override
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
VECTOR2I GetReferencePoint() const
Definition: selection.h:240
BOARD_ITEM * Parse()
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
STRING_FORMATTER * GetFormatter()
Definition: typeinfo.h:85
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
PCB_IO is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void InitDataFromSrcInCopyCtor(const ZONE_CONTAINER &aZone)
Copy aZone data to me.
Definition: class_zone.cpp:103
TEXTE_PCB class definition.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
void CopyText(const EDA_TEXT &aSrc)
Definition: eda_text.cpp:129
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:109
wxPoint GetPosition() const override
Definition: class_pad.h:165
void init(const PROPERTIES *aProperties)
void SetEffects(const EDA_TEXT &aSrc)
Set the text effects from another instance.
Definition: eda_text.cpp:137
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:476
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
void formatNetInformation(BOARD *aBoard, int aNestLevel=0) const
formats the Nets and Netclasses
void SaveSelection(const PCBNEW_SELECTION &selected, bool isModEdit)
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
virtual void SetLocked(bool aLocked)
Function SetLocked modifies 'lock' status for of the item.
STRING_FORMATTER m_formatter
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void MoveAnchorPosition(const wxPoint &aMoveVector)
Function MoveAnchorPosition Move the reference point of the footprint It looks like a move footprint:...
void SetBoard(BOARD *aBoard)
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:451
void SetBoard(const BOARD *aBoard)
Function SetBoard Sets a BOARD object that is used to prepare the net code map.
Definition: netinfo.h:296
class MODULE, a footprint
Definition: typeinfo.h:89
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:196
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:162
Footprint text class description.
void SetBoard(BOARD *aBoard)
Definition: pcb_parser.h:368
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
MODULES & Modules()
Definition: class_board.h:247
virtual void Move(const wxPoint &aMoveVector)
Function Move move this object.
#define CTL_FOR_CLIPBOARD
Format output for the clipboard instead of footprint library or BOARD.
void SetPos0(const wxPoint &aPos)
Definition: class_pad.h:217
void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=NULL) override
Function Save will write aBoard to a storage file in a format that this PLUGIN implementation knows a...
const std::string & GetString()
Definition: richio.h:475
void SetFileName(const wxString &aFileName)
Definition: class_board.h:240
void SetPosition(const wxPoint &aPos) override
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:484
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:361
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:121
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
CLIPBOARD_PARSER * m_parser
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
void formatBoardLayers(BOARD *aBoard, int aNestLevel=0) const
formats the board layer information
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:389
Struct PARSE_ERROR contains a filename or source description, a problem input line,...
Definition: ki_exception.h:123
bool HasReferencePoint() const
Definition: selection.h:235
Class to handle a graphic segment.
Information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:176
#define _(s)
Definition: 3d_actions.cpp:33
BOARD * m_board
which BOARD, no ownership here
int Size() const
Returns the number of selected parts.
Definition: selection.h:127
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
The common library.
Pcbnew s-expression file format parser definition.
wxPoint GetPosition() const override
Definition: class_module.h:219
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:172
class ZONE_CONTAINER, managed by a footprint
Definition: typeinfo.h:95
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
void Format(BOARD_ITEM *aItem, int aNestLevel=0) const
Output aItem to aFormatter in s-expression format.
BOARD_ITEM_CONTAINER * GetParent() const
STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
EDA_ITEM * Front() const
Definition: selection.h:184
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193