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 #include <common.h>
27 #include <pcb_parser.h>
28 #include <netinfo.h>
29 #include <class_board.h>
30 #include <build_version.h>
31 
32 #include <kicad_plugin.h>
33 #include <kicad_clipboard.h>
34 
37  m_formatter(),
38  m_parser( new CLIPBOARD_PARSER() )
39 {
40  m_out = &m_formatter;
41 }
42 
43 
45 {
46  delete m_parser;
47 }
48 
49 
51 {
52  return &m_formatter;
53 }
54 
55 
57 {
58  m_board = aBoard;
59 }
60 
61 
62 void CLIPBOARD_IO::SaveSelection( const SELECTION& aSelected )
63 {
64  VECTOR2I refPoint( 0, 0 );
65 
66  // dont even start if the selection is empty
67  if( aSelected.Empty() )
68  return;
69 
70  if( aSelected.HasReferencePoint() )
71  refPoint = aSelected.GetReferencePoint();
72 
73  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
75 
76  // Differentiate how it is formatted depending on what selection contains
77  bool onlyModuleParts = true;
78  for( const auto i : aSelected )
79  {
80  // check if it not one of the module primitives
81  if( ( i->Type() != PCB_MODULE_EDGE_T ) &&
82  ( i->Type() != PCB_MODULE_TEXT_T ) &&
83  ( i->Type() != PCB_PAD_T ) )
84  {
85  onlyModuleParts = false;
86  continue;
87  }
88  }
89 
90  // if there is only parts of a module selected, format it as a new module else
91  // format it as an entire board
92  MODULE partialModule( m_board );
93 
94  // only a module selected.
95  if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_MODULE_T )
96  {
97  // make the module safe to transfer to other pcbs
98  const MODULE* mod = static_cast<MODULE*>( aSelected.Front() );
99  // Do not modify existing board
100  MODULE newModule(*mod);
101 
102  for( D_PAD* pad = newModule.PadsList().begin(); pad; pad = pad->Next() )
103  {
104  pad->SetNetCode( 0, 0 );
105  }
106 
107  // locate the reference point at (0, 0) in the copied items
108  newModule.Move( wxPoint( -refPoint.x, -refPoint.y ) );
109 
110  Format( static_cast<BOARD_ITEM*>( &newModule ) );
111  }
112  // partial module selected.
113  else if( onlyModuleParts )
114  {
115  for( const auto item : aSelected )
116  {
117  auto clone = static_cast<BOARD_ITEM*>( item->Clone() );
118 
119  // Do not add reference/value - convert them to the common type
120  if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) )
121  text->SetType( TEXTE_MODULE::TEXT_is_DIVERS );
122 
123  // If it is only a module, clear the nets from the pads
124  if( clone->Type() == PCB_PAD_T )
125  {
126  D_PAD* pad = static_cast<D_PAD*>( clone );
127  pad->SetNetCode( 0, 0 );
128  }
129 
130  // locate the reference point at (0, 0) in the copied items
131  clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
132 
133  partialModule.Add( clone );
134  }
135 
136  // Set the new relative internal local coordinates of copied items
137  MODULE* editedModule = m_board->m_Modules;
138  wxPoint moveVector = partialModule.GetPosition() + editedModule->GetPosition();
139 
140  partialModule.MoveAnchorPosition( moveVector );
141 
142  Format( &partialModule, 0 );
143 
144  }
145  // lots of stuff selected
146  else
147  {
148  // we will fake being a .kicad_pcb to get the full parser kicking
149  // This means we also need layers and nets
150  LOCALE_IO io;
151 
152  m_formatter.Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n",
154 
155 
156  m_formatter.Print( 0, "\n" );
157 
160 
161  m_formatter.Print( 0, "\n" );
162 
163 
164  for( const auto i : aSelected )
165  {
166  // Dont format stuff that cannot exist standalone!
167  if( ( i->Type() != PCB_MODULE_EDGE_T ) &&
168  ( i->Type() != PCB_MODULE_TEXT_T ) &&
169  ( i->Type() != PCB_PAD_T ) )
170  {
171  auto item = static_cast<BOARD_ITEM*>( i );
172  std::unique_ptr<BOARD_ITEM> clone( static_cast<BOARD_ITEM*> ( item->Clone() ) );
173 
174  // locate the reference point at (0, 0) in the copied items
175  clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
176 
177  Format( clone.get(), 1 );
178  }
179  }
180  m_formatter.Print( 0, "\n)" );
181  }
182 
183  // These are placed at the end to minimize the open time of the clipboard
184  auto clipboard = wxTheClipboard;
185  wxClipboardLocker clipboardLock( clipboard );
186 
187  if( !clipboardLock || !clipboard->IsOpened() )
188  return;
189 
190  clipboard->SetData( new wxTextDataObject(
191  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
192 
193  clipboard->Flush();
194 
195  // This section exists to return the clipboard data, ensuring it has fully
196  // been processed by the system clipboard. This appears to be needed for
197  // extremely large clipboard copies on asynchronous linux clipboard managers
198  // such as KDE's Klipper
199  {
200  wxTextDataObject data;
201  clipboard->GetData( data );
202  ( void )data.GetText(); // Keep unused variable
203  }
204 }
205 
206 
208 {
209  BOARD_ITEM* item;
210  wxString result;
211 
212  auto clipboard = wxTheClipboard;
213  wxClipboardLocker clipboardLock( clipboard );
214 
215  if( !clipboardLock )
216  return nullptr;
217 
218 
219  if( clipboard->IsSupported( wxDF_TEXT ) )
220  {
221  wxTextDataObject data;
222  clipboard->GetData( data );
223  result = data.GetText();
224  }
225 
226  try
227  {
228  item = PCB_IO::Parse( result );
229  }
230  catch (...)
231  {
232  item = nullptr;
233  }
234 
235  return item;
236 }
237 
238 
239 void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
240  const PROPERTIES* aProperties )
241 {
242  init( aProperties );
243 
244  m_board = aBoard; // after init()
245 
246  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
247  m_mapping->SetBoard( aBoard );
248 
249  STRING_FORMATTER formatter;
250 
251  m_out = &formatter;
252 
253  m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
254  formatter.Quotew( GetBuildVersion() ).c_str() );
255 
256  Format( aBoard, 1 );
257 
258  m_out->Print( 0, ")\n" );
259 
260  auto clipboard = wxTheClipboard;
261  wxClipboardLocker clipboardLock( clipboard );
262 
263  if( !clipboardLock )
264  return;
265 
266  clipboard->SetData( new wxTextDataObject(
267  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
268  clipboard->Flush();
269 
270  // This section exists to return the clipboard data, ensuring it has fully
271  // been processed by the system clipboard. This appears to be needed for
272  // extremely large clipboard copies on asynchronous linux clipboard managers
273  // such as KDE's Klipper
274  {
275  wxTextDataObject data;
276  clipboard->GetData( data );
277  ( void )data.GetText(); // Keep unused variable
278  }
279 }
280 
281 
282 BOARD* CLIPBOARD_IO::Load( const wxString& aFileName,
283  BOARD* aAppendToMe, const PROPERTIES* aProperties )
284 {
285  std::string result;
286 
287  auto clipboard = wxTheClipboard;
288  wxClipboardLocker clipboardLock( clipboard );
289 
290  if( !clipboardLock )
291  return nullptr;
292 
293  if( clipboard->IsSupported( wxDF_TEXT ) )
294  {
295  wxTextDataObject data;
296  clipboard->GetData( data );
297 
298  result = data.GetText().mb_str();
299  }
300 
301  STRING_LINE_READER reader(result, wxT( "clipboard" ) );
302 
303  init( aProperties );
304 
305  m_parser->SetLineReader( &reader );
306  m_parser->SetBoard( aAppendToMe );
307 
308  BOARD_ITEM* item;
309  BOARD* board;
310 
311  try
312  {
313  item = m_parser->Parse();
314  }
315  catch( const FUTURE_FORMAT_ERROR& )
316  {
317  // Don't wrap a FUTURE_FORMAT_ERROR in another
318  throw;
319  }
320  catch( const PARSE_ERROR& parse_error )
321  {
322  if( m_parser->IsTooRecent() )
323  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
324  else
325  throw;
326  }
327 
328  if( item->Type() != PCB_T )
329  {
330  // The parser loaded something that was valid, but wasn't a board.
331  THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ),
332  m_parser->CurSource(), m_parser->CurLine(),
333  m_parser->CurLineNumber(), m_parser->CurOffset() );
334  }
335  else
336  {
337  board = dynamic_cast<BOARD*>( item );
338  }
339 
340  // Give the filename to the board if it's new
341  if( board && !aAppendToMe )
342  board->SetFileName( aFileName );
343 
344  return board;
345 }
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...
BOARD_ITEM * Parse()
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:116
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
STRING_FORMATTER * GetFormatter()
VECTOR2I GetReferencePoint() const
Definition: selection.h:200
Definition: typeinfo.h:85
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
Class PCB_IO is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files...
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown...
Definition: common.h:180
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
Class BOARD to handle a board.
void init(const PROPERTIES *aProperties)
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
T * begin() const
Definition: dlist.h:218
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
STRING_FORMATTER m_formatter
void SaveSelection(const SELECTION &selected)
Class 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
void SetBoard(const BOARD *aBoard)
Function SetBoard Sets a BOARD object that is used to prepare the net code map.
Definition: netinfo.h:289
void formatBoardLayers(BOARD *aBoard, int aNestLevel=0) const
formats the board layer information
class MODULE, a footprint
Definition: typeinfo.h:89
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_INSERT) override
>
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:182
void SetBoard(BOARD *aBoard)
Definition: pcb_parser.h:301
wxString GetBuildVersion()
Function GetBuildVersion Return the build version string.
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...
void formatNetInformation(BOARD *aBoard, int aNestLevel=0) const
formats the Nets and Netclasses
D_PAD * Next() const
Definition: class_pad.h:160
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Function SetNetCode sets net using a net code.
const std::string & GetString()
Definition: richio.h:475
std::string Quotew(const wxString &aWrapee)
Definition: richio.cpp:482
void SetFileName(const wxString &aFileName)
Definition: class_board.h:236
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:442
void Format(BOARD_ITEM *aItem, int aNestLevel=0) const
Function Format outputs aItem to aFormatter in s-expression format.
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:294
CLIPBOARD_PARSER * m_parser
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:319
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller&#39;s report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:123
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:171
DLIST< MODULE > m_Modules
Definition: class_board.h:249
void Move(const wxPoint &aMoveVector) override
Function Move move this object.
#define CTL_STD_LAYER_NAMES
Use English Standard layer names.
size_t i
Definition: json11.cpp:597
BOARD * m_board
which BOARD, no ownership here
The common library.
Pcbnew s-expression file format parser definition.
DLIST< D_PAD > & PadsList()
Definition: class_module.h:162
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:172
bool HasReferencePoint() const
Definition: selection.h:195
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
Class STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
const wxPoint GetPosition() const override
Definition: class_module.h:183
#define mod(a, n)
Definition: greymap.cpp:24