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  LOCALE_IO toggle; // toggles on, then off, the C locale.
65  VECTOR2I refPoint( 0, 0 );
66 
67  // dont even start if the selection is empty
68  if( aSelected.Empty() )
69  return;
70 
71  if( aSelected.HasReferencePoint() )
72  refPoint = aSelected.GetReferencePoint();
73 
74  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
76 
77  // Differentiate how it is formatted depending on what selection contains
78  bool onlyModuleParts = true;
79  for( const auto i : aSelected )
80  {
81  // check if it not one of the module primitives
82  if( ( i->Type() != PCB_MODULE_EDGE_T ) &&
83  ( i->Type() != PCB_MODULE_TEXT_T ) &&
84  ( i->Type() != PCB_PAD_T ) )
85  {
86  onlyModuleParts = false;
87  continue;
88  }
89  }
90 
91  // if there is only parts of a module selected, format it as a new module else
92  // format it as an entire board
93  MODULE partialModule( m_board );
94 
95  // only a module selected.
96  if( aSelected.Size() == 1 && aSelected.Front()->Type() == PCB_MODULE_T )
97  {
98  // make the module safe to transfer to other pcbs
99  const MODULE* mod = static_cast<MODULE*>( aSelected.Front() );
100  // Do not modify existing board
101  MODULE newModule(*mod);
102 
103  for( D_PAD* pad = newModule.PadsList().begin(); pad; pad = pad->Next() )
104  {
105  pad->SetNetCode( 0, 0 );
106  }
107 
108  // locate the reference point at (0, 0) in the copied items
109  newModule.Move( wxPoint( -refPoint.x, -refPoint.y ) );
110 
111  Format( static_cast<BOARD_ITEM*>( &newModule ) );
112  }
113  // partial module selected.
114  else if( onlyModuleParts )
115  {
116  for( const auto item : aSelected )
117  {
118  auto clone = static_cast<BOARD_ITEM*>( item->Clone() );
119 
120  // Do not add reference/value - convert them to the common type
121  if( TEXTE_MODULE* text = dyn_cast<TEXTE_MODULE*>( clone ) )
122  text->SetType( TEXTE_MODULE::TEXT_is_DIVERS );
123 
124  // If it is only a module, clear the nets from the pads
125  if( clone->Type() == PCB_PAD_T )
126  {
127  D_PAD* pad = static_cast<D_PAD*>( clone );
128  pad->SetNetCode( 0, 0 );
129  }
130 
131  // locate the reference point at (0, 0) in the copied items
132  clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
133 
134  partialModule.Add( clone );
135  }
136 
137  // Set the new relative internal local coordinates of copied items
138  MODULE* editedModule = m_board->m_Modules;
139  wxPoint moveVector = partialModule.GetPosition() + editedModule->GetPosition();
140 
141  partialModule.MoveAnchorPosition( moveVector );
142 
143  Format( &partialModule, 0 );
144 
145  }
146  // lots of stuff selected
147  else
148  {
149  // we will fake being a .kicad_pcb to get the full parser kicking
150  // This means we also need layers and nets
151  m_formatter.Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n",
153 
154 
155  m_formatter.Print( 0, "\n" );
156 
159 
160  m_formatter.Print( 0, "\n" );
161 
162 
163  for( const auto i : aSelected )
164  {
165  // Dont format stuff that cannot exist standalone!
166  if( ( i->Type() != PCB_MODULE_EDGE_T ) &&
167  ( i->Type() != PCB_MODULE_TEXT_T ) &&
168  ( i->Type() != PCB_PAD_T ) )
169  {
170  auto item = static_cast<BOARD_ITEM*>( i );
171  std::unique_ptr<BOARD_ITEM> clone( static_cast<BOARD_ITEM*> ( item->Clone() ) );
172 
173  // locate the reference point at (0, 0) in the copied items
174  clone->Move( wxPoint(-refPoint.x, -refPoint.y ) );
175 
176  Format( clone.get(), 1 );
177  }
178 
179  }
180  m_formatter.Print( 0, "\n)" );
181  }
182  if( wxTheClipboard->Open() )
183  {
184  wxTheClipboard->SetData( new wxTextDataObject(
185  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
186  wxTheClipboard->Close();
187  }
188 }
189 
190 
192 {
193  BOARD_ITEM* item;
194  wxString result;
195 
196  if( wxTheClipboard->Open() )
197  {
198  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
199  {
200  wxTextDataObject data;
201  wxTheClipboard->GetData( data );
202  result = data.GetText();
203  }
204 
205  wxTheClipboard->Close();
206  }
207 
208  try
209  {
210  item = PCB_IO::Parse( result );
211  }
212  catch (...)
213  {
214  item = nullptr;
215  }
216 
217  return item;
218 }
219 
220 
221 void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
222  const PROPERTIES* aProperties )
223 {
224  LOCALE_IO toggle; // toggles on, then off, the C locale.
225 
226  init( aProperties );
227 
228  m_board = aBoard; // after init()
229 
230  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
231  m_mapping->SetBoard( aBoard );
232 
233  STRING_FORMATTER formatter;
234 
235  m_out = &formatter;
236 
237  m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
238  formatter.Quotew( GetBuildVersion() ).c_str() );
239 
240  Format( aBoard, 1 );
241 
242  m_out->Print( 0, ")\n" );
243 
244  if( wxTheClipboard->Open() )
245  {
246  wxTheClipboard->SetData( new wxTextDataObject(
247  wxString( m_formatter.GetString().c_str(), wxConvUTF8 ) ) );
248  wxTheClipboard->Close();
249  }
250 
251 }
252 
253 
254 BOARD* CLIPBOARD_IO::Load( const wxString& aFileName,
255  BOARD* aAppendToMe, const PROPERTIES* aProperties )
256 {
257  std::string result;
258 
259  if( wxTheClipboard->Open() )
260  {
261  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
262  {
263  wxTextDataObject data;
264  wxTheClipboard->GetData( data );
265 
266  result = data.GetText().mb_str();
267  }
268 
269  wxTheClipboard->Close();
270  }
271 
272  STRING_LINE_READER reader(result, wxT( "clipboard" ) );
273 
274  init( aProperties );
275 
276  m_parser->SetLineReader( &reader );
277  m_parser->SetBoard( aAppendToMe );
278 
279  BOARD_ITEM* item;
280  BOARD* board;
281 
282  try
283  {
284  item = m_parser->Parse();
285  }
286  catch( const FUTURE_FORMAT_ERROR& )
287  {
288  // Don't wrap a FUTURE_FORMAT_ERROR in another
289  throw;
290  }
291  catch( const PARSE_ERROR& parse_error )
292  {
293  if( m_parser->IsTooRecent() )
294  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
295  else
296  throw;
297  }
298 
299  if( item->Type() != PCB_T )
300  {
301  // The parser loaded something that was valid, but wasn't a board.
302  THROW_PARSE_ERROR( _( "Clipboard content is not KiCad compatible" ),
303  m_parser->CurSource(), m_parser->CurLine(),
304  m_parser->CurLineNumber(), m_parser->CurOffset() );
305  }
306  else
307  {
308  board = dynamic_cast<BOARD*>( item );
309  }
310 
311  // Give the filename to the board if it's new
312  if( board && !aAppendToMe )
313  board->SetFileName( aFileName );
314 
315  return board;
316 }
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:179
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:300
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:235
#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:293
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:318
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:170
DLIST< MODULE > m_Modules
Definition: class_board.h:248
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:163
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:184
#define mod(a, n)
Definition: greymap.cpp:24