KiCad PCB EDA Suite
ds_data_model_io.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) 2013-2016 CERN
5  * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Jean-Pierre Charras, jp.charras at wanadoo.fr
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <kicad_string.h>
28 #include <locale_io.h>
29 #include <macros.h>
30 #include <math/vector2d.h>
35 #include <drawing_sheet/drawing_sheet_reader_lexer.h>
37 
38 #include <wx/msgdlg.h>
39 
40 using namespace TB_READER_T;
41 
42 #define double2Str Double2Str
43 
44 // A helper function to write tokens:
45 static const char* getTokenName( T aTok )
46 {
47  return DRAWING_SHEET_READER_LEXER::TokenName( aTok );
48 }
49 
50 // A basic helper class to write a drawing sheet file
51 // Not used alone, a file writer or a string writer should be derived to use it.
52 // Therefore the constructor is protected.
54 {
55 public:
56  void Format( DS_DATA_MODEL* aDrawingSheet ) const;
57 
58  void Format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const;
59 
60 protected:
61  DS_DATA_MODEL_IO() { m_out = NULL; }
62  virtual ~DS_DATA_MODEL_IO() {}
63 
64 private:
65  void format( DS_DATA_ITEM_TEXT* aItem, int aNestLevel ) const;
66  void format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const;
67  void format( DS_DATA_ITEM_POLYGONS* aItem, int aNestLevel ) const;
68  void format( DS_DATA_ITEM_BITMAP* aItem, int aNestLevel ) const;
69  void formatCoordinate( const char* aToken, POINT_COORD& aCoord ) const;
70  void formatRepeatParameters( DS_DATA_ITEM* aItem ) const;
71  void formatOptions( DS_DATA_ITEM* aItem ) const;
72 
73 protected:
75 };
76 
77 
78 // A helper class to write a drawing sheet to a file
80 {
81 public:
82  DS_DATA_MODEL_FILEIO( const wxString& aFilename ) :
84  {
85  try
86  {
87  m_fileout = new FILE_OUTPUTFORMATTER( aFilename );
88  m_out = m_fileout;
89  }
90  catch( const IO_ERROR& ioe )
91  {
92  wxMessageBox( ioe.What(), _( "Error writing drawing sheet file" ) );
93  }
94  }
95 
97  {
98  delete m_fileout;
99  }
100 
101 private:
103 };
104 
105 
106 // A helper class to write a drawing sheet to a string
108 {
109 public:
110  DS_DATA_MODEL_STRINGIO( wxString* aOutputString ) :
112  m_output( aOutputString )
113  {
114  try
115  {
116  m_writer = new STRING_FORMATTER();
117  m_out = m_writer;
118  }
119  catch( const IO_ERROR& ioe )
120  {
121  wxMessageBox( ioe.What(), _( "Error writing drawing sheet file" ) );
122  }
123  }
124 
126  {
127  *m_output = FROM_UTF8( m_writer->GetString().c_str() );
128  delete m_writer;
129  }
130 
131 private:
133  wxString* m_output;
134 };
135 
136 
137 void DS_DATA_MODEL::Save( const wxString& aFullFileName )
138 {
139  DS_DATA_MODEL_FILEIO writer( aFullFileName );
140  writer.Format( this );
141 }
142 
143 
144 void DS_DATA_MODEL::SaveInString( wxString* aOutputString )
145 {
146  DS_DATA_MODEL_STRINGIO writer( aOutputString );
147  writer.Format( this );
148 }
149 
150 
151 void DS_DATA_MODEL::SaveInString( std::vector<DS_DATA_ITEM*>& aItemsList, wxString* aOutputString )
152 {
153  DS_DATA_MODEL_STRINGIO writer( aOutputString );
154 
155  LOCALE_IO toggle; // switch on/off the locale "C" notation
156 
157  for( DS_DATA_ITEM* item : aItemsList )
158  writer.Format( this, item, 0 );
159 }
160 
161 
162 void DS_DATA_MODEL_IO::Format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const
163 {
164  switch( aItem->GetType() )
165  {
167  format( (DS_DATA_ITEM_TEXT*) aItem, aNestLevel );
168  break;
169 
172  format( aModel, aItem, aNestLevel );
173  break;
174 
176  format( (DS_DATA_ITEM_POLYGONS*) aItem, aNestLevel );
177  break;
178 
180  format( (DS_DATA_ITEM_BITMAP*) aItem, aNestLevel );
181  break;
182 
183  default:
184  wxFAIL_MSG( wxT( "Cannot format item" ) );
185  }
186 }
187 
188 
189 void DS_DATA_MODEL_IO::Format( DS_DATA_MODEL* aDrawingSheet ) const
190 {
191  LOCALE_IO toggle; // switch on/off the locale "C" notation
192 
193  m_out->Print( 0, "(kicad_wks (version %d) (generator pl_editor)\n",
195 
196  // Setup
197  int nestLevel = 1;
198  // Write default values:
199  m_out->Print( nestLevel, "(%s ", getTokenName( T_setup ) );
200  m_out->Print( 0, "(textsize %s %s)",
201  double2Str( aDrawingSheet->m_DefaultTextSize.x ).c_str(),
202  double2Str( aDrawingSheet->m_DefaultTextSize.y ).c_str() );
203  m_out->Print( 0, "(linewidth %s)",
204  double2Str( aDrawingSheet->m_DefaultLineWidth ).c_str() );
205  m_out->Print( 0, "(textlinewidth %s)",
206  double2Str( aDrawingSheet->m_DefaultTextThickness ).c_str() );
207  m_out->Print( 0, "\n" );
208 
209  // Write margin values
210  m_out->Print( nestLevel, "(%s %s)", getTokenName( T_left_margin ),
211  double2Str( aDrawingSheet->GetLeftMargin() ).c_str() );
212  m_out->Print( 0, "(%s %s)", getTokenName( T_right_margin ),
213  double2Str( aDrawingSheet->GetRightMargin() ).c_str() );
214  m_out->Print( 0, "(%s %s)", getTokenName( T_top_margin ),
215  double2Str( aDrawingSheet->GetTopMargin() ).c_str() );
216  m_out->Print( 0, "(%s %s)", getTokenName( T_bottom_margin ),
217  double2Str( aDrawingSheet->GetBottomMargin() ).c_str() );
218  m_out->Print( 0, ")\n" );
219 
220  // Save the graphical items on the drawing sheet
221  for( unsigned ii = 0; ii < aDrawingSheet->GetCount(); ii++ )
222  {
223  DS_DATA_ITEM* item = aDrawingSheet->GetItem( ii );
224  Format( aDrawingSheet, item, nestLevel );
225  }
226 
227  m_out->Print( 0, ")\n" );
228 }
229 
230 
231 void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_TEXT* aItem, int aNestLevel ) const
232 {
233  m_out->Print( aNestLevel, "(%s", getTokenName( T_tbtext ) );
234  m_out->Print( 0, " %s", m_out->Quotew( aItem->m_TextBase ).c_str() );
235  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
236  m_out->Quotew( aItem->m_Name ).c_str() );
237 
238  formatCoordinate( getTokenName( T_pos ), aItem->m_Pos );
239  formatOptions( aItem );
240 
241  if( aItem->m_Orient )
242  m_out->Print( 0, " (%s %s)", getTokenName( T_rotate ),
243  double2Str(aItem->m_Orient ).c_str() );
244 
245  // Write font info, only if it is not the default setup
246  bool write_size = aItem->m_TextSize.x != 0.0 || aItem->m_TextSize.y != 0.0;
247  bool write_thickness = aItem->m_LineWidth != 0.0;
248 
249  if( write_thickness || write_size || aItem->m_Bold || aItem->m_Italic )
250  {
251  m_out->Print( 0, " (%s", getTokenName( T_font ) );
252 
253  if( write_thickness )
254  {
255  m_out->Print( 0, " (%s %s)", getTokenName( T_linewidth ),
256  double2Str(aItem->m_LineWidth ).c_str() );
257  }
258 
259  if( write_size )
260  {
261  m_out->Print( 0, " (%s %s %s)", getTokenName( T_size ),
262  double2Str(aItem->m_TextSize.x ).c_str(),
263  double2Str(aItem->m_TextSize.y ).c_str() );
264  }
265  if( aItem->m_Bold )
266  m_out->Print( 0, " %s", getTokenName( T_bold ) );
267 
268  if( aItem->m_Italic )
269  m_out->Print( 0, " %s", getTokenName( T_italic ) );
270 
271  m_out->Print( 0, ")" );
272  }
273 
274  // Write text justification
275  if( aItem->m_Hjustify != GR_TEXT_HJUSTIFY_LEFT ||
277  {
278  m_out->Print( 0, " (%s", getTokenName( T_justify ) );
279 
280  // Write T_center opt first, because it is
281  // also a center for both m_Hjustify and m_Vjustify
282  if( aItem->m_Hjustify == GR_TEXT_HJUSTIFY_CENTER )
283  m_out->Print( 0, " %s", getTokenName( T_center ) );
284 
285  if( aItem->m_Hjustify == GR_TEXT_HJUSTIFY_RIGHT )
286  m_out->Print( 0, " %s", getTokenName( T_right ) );
287 
288  if( aItem->m_Vjustify == GR_TEXT_VJUSTIFY_TOP )
289  m_out->Print( 0, " %s", getTokenName( T_top ) );
290 
291  if( aItem->m_Vjustify == GR_TEXT_VJUSTIFY_BOTTOM )
292  m_out->Print( 0, " %s", getTokenName( T_bottom ) );
293 
294  m_out->Print( 0, ")" );
295  }
296 
297  // write constraints
298  if( aItem->m_BoundingBoxSize.x )
299  m_out->Print( 0, " (%s %s)", getTokenName( T_maxlen ),
300  double2Str(aItem->m_BoundingBoxSize.x ).c_str() );
301 
302  if( aItem->m_BoundingBoxSize.y )
303  m_out->Print( 0, " (%s %s)", getTokenName( T_maxheight ),
304  double2Str(aItem->m_BoundingBoxSize.y ).c_str() );
305 
306  formatRepeatParameters( aItem );
307 
308  if( !aItem->m_Info.IsEmpty() )
309  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
310 
311  m_out->Print( 0, ")\n" );
312 }
313 
314 
315 void DS_DATA_MODEL_IO::format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const
316 {
317  if( aItem->GetType() == DS_DATA_ITEM::DS_RECT )
318  m_out->Print( aNestLevel, "(%s", getTokenName( T_rect ) );
319  else
320  m_out->Print( aNestLevel, "(%s", getTokenName( T_line ) );
321 
322  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
323  m_out->Quotew( aItem->m_Name ).c_str() );
324 
325  formatCoordinate( getTokenName( T_start ), aItem->m_Pos );
326  formatCoordinate( getTokenName( T_end ), aItem->m_End );
327  formatOptions( aItem );
328 
329  if( aItem->m_LineWidth && aItem->m_LineWidth != aModel->m_DefaultLineWidth )
330  m_out->Print( 0, " (linewidth %s)", double2Str( aItem->m_LineWidth ).c_str() );
331 
332  formatRepeatParameters( aItem );
333 
334  if( !aItem->m_Info.IsEmpty() )
335  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
336 
337  m_out->Print( 0, ")\n" );
338 }
339 
340 
341 void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_POLYGONS* aItem, int aNestLevel ) const
342 {
343  m_out->Print( aNestLevel, "(%s", getTokenName( T_polygon ) );
344  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
345  m_out->Quotew( aItem->m_Name ).c_str() );
346  formatCoordinate( getTokenName( T_pos ), aItem->m_Pos );
347  formatOptions( aItem );
348 
349  formatRepeatParameters( aItem );
350 
351  if( aItem->m_Orient )
352  m_out->Print( 0, " (%s %s)", getTokenName( T_rotate ),
353  double2Str(aItem->m_Orient ).c_str() );
354 
355  if( aItem->m_LineWidth )
356  m_out->Print( 0, " (linewidth %s)\n", double2Str( aItem->m_LineWidth ).c_str() );
357 
358  if( !aItem->m_Info.IsEmpty() )
359  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
360 
361  // Write polygon corners list
362  for( int kk = 0; kk < aItem->GetPolyCount(); kk++ )
363  {
364  m_out->Print( aNestLevel+1, "(%s", getTokenName( T_pts ) );
365  // Create current polygon corners list
366  unsigned ist = aItem->GetPolyIndexStart( kk );
367  unsigned iend = aItem->GetPolyIndexEnd( kk );
368  int ii = 0;
369 
370  while( ist <= iend )
371  {
372  DPOINT pos = aItem->m_Corners[ist++];
373  int nestLevel = 0;
374 
375  if( ii++ > 4)
376  {
377  m_out->Print( 0, "\n" );
378  nestLevel = aNestLevel+2;
379  ii = 0;
380  }
381 
382  m_out->Print( nestLevel, " (%s %s %s)", getTokenName( T_xy ),
383  double2Str( pos.x ).c_str(),
384  double2Str( pos.y ).c_str() );
385  }
386 
387  m_out->Print( 0, ")\n" );
388  }
389 
390  m_out->Print( aNestLevel, ")\n" );
391 }
392 
393 
394 void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_BITMAP* aItem, int aNestLevel ) const
395 {
396  m_out->Print( aNestLevel, "(%s", getTokenName( T_bitmap ) );
397  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
398  m_out->Quotew( aItem->m_Name ).c_str() );
399  formatCoordinate( getTokenName( T_pos ), aItem->m_Pos );
400  formatOptions( aItem );
401 
402  m_out->Print( 0, " (%s %s)", getTokenName( T_scale ),
403  double2Str( aItem->m_ImageBitmap->GetScale() ).c_str() );
404 
405  formatRepeatParameters( aItem );
406  m_out->Print( 0,"\n");
407 
408  if( !aItem->m_Info.IsEmpty() )
409  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
410 
411  // Write image in png readable format
412  m_out->Print( aNestLevel, "(%s\n", getTokenName( T_pngdata ) );
413  wxArrayString pngStrings;
414  aItem->m_ImageBitmap->SaveData( pngStrings );
415 
416  for( unsigned ii = 0; ii < pngStrings.GetCount(); ii++ )
417  m_out->Print( aNestLevel+1, "(data \"%s\")\n", TO_UTF8(pngStrings[ii]) );
418 
419  m_out->Print( aNestLevel+1, ")\n" );
420 
421  m_out->Print( aNestLevel, ")\n" );
422 }
423 
424 
425 void DS_DATA_MODEL_IO::formatCoordinate( const char * aToken, POINT_COORD & aCoord ) const
426 {
427  m_out->Print( 0, " (%s %s %s", aToken,
428  double2Str( aCoord.m_Pos.x ).c_str(),
429  double2Str( aCoord.m_Pos.y ).c_str() );
430 
431  switch( aCoord.m_Anchor )
432  {
433  case RB_CORNER: break;
434  case LT_CORNER: m_out->Print( 0, " %s", getTokenName( T_ltcorner ) ); break;
435  case LB_CORNER: m_out->Print( 0, " %s", getTokenName( T_lbcorner ) ); break;
436  case RT_CORNER: m_out->Print( 0, " %s", getTokenName( T_rtcorner ) ); break;
437  }
438 
439  m_out->Print( 0, ")" );
440 }
441 
442 
444 {
445  if( aItem->m_RepeatCount <= 1 )
446  return;
447 
448  m_out->Print( 0, " (repeat %d)", aItem->m_RepeatCount );
449 
450  if( aItem->m_IncrementVector.x )
451  m_out->Print( 0, " (incrx %s)", double2Str(aItem-> m_IncrementVector.x ).c_str() );
452 
453  if( aItem->m_IncrementVector.y )
454  m_out->Print( 0, " (incry %s)", double2Str( aItem->m_IncrementVector.y ).c_str() );
455 
456  if( aItem->m_IncrementLabel != 1 && aItem->GetType() == DS_DATA_ITEM::DS_TEXT )
457  m_out->Print( 0, " (incrlabel %d)", aItem->m_IncrementLabel );
458 }
459 
460 
462 {
463  if( aItem->GetPage1Option() == FIRST_PAGE_ONLY )
464  m_out->Print( 0, " (%s %s)", getTokenName( T_option ), getTokenName(T_page1only ) );
465  else if( aItem->GetPage1Option() == SUBSEQUENT_PAGES )
466  m_out->Print( 0, " (%s %s)", getTokenName( T_option ), getTokenName( T_notonpage1 ) );
467 }
void formatCoordinate(const char *aToken, POINT_COORD &aCoord) const
wxString m_Info
Definition: ds_data_item.h:199
unsigned GetPolyIndexStart(unsigned aContour) const
Definition: ds_data_item.h:252
Handle the graphic items list to draw/plot the frame and title block.
Definition: ds_data_model.h:38
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
EDA_TEXT_VJUSTIFY_T m_Vjustify
Definition: ds_data_item.h:339
bool SaveData(FILE *aFile) const
Write the bitmap data to aFile.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
double GetRightMargin()
Definition: ds_data_model.h:66
int GetPolyCount() const
Definition: ds_data_item.h:246
double m_DefaultLineWidth
double GetScale() const
Definition: bitmap_base.h:79
double GetTopMargin()
Definition: ds_data_model.h:69
static const char * getTokenName(T aTok)
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:309
double GetLeftMargin()
Definition: ds_data_model.h:63
std::vector< DPOINT > m_Corners
Definition: ds_data_item.h:288
POINT_COORD m_End
Definition: ds_data_item.h:201
unsigned GetPolyIndexEnd(unsigned aContour) const
Definition: ds_data_item.h:264
void Save(const wxString &aFullFileName)
Save the description in a file.
double m_DefaultTextThickness
This file contains miscellaneous commonly used macros and functions.
FILE_OUTPUTFORMATTER * m_fileout
EDA_TEXT_HJUSTIFY_T m_Hjustify
Definition: ds_data_item.h:338
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
DPOINT m_IncrementVector
Definition: ds_data_item.h:204
OUTPUTFORMATTER * m_out
double m_LineWidth
Definition: ds_data_item.h:202
DS_ITEM_TYPE GetType() const
Definition: ds_data_item.h:128
virtual ~DS_DATA_MODEL_IO()
#define NULL
DSIZE m_DefaultTextSize
BITMAP_BASE * m_ImageBitmap
Definition: ds_data_item.h:368
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
DPOINT m_Pos
Definition: ds_data_item.h:80
double GetBottomMargin()
Definition: ds_data_model.h:72
int m_IncrementLabel
Definition: ds_data_item.h:205
#define SEXPR_WORKSHEET_FILE_VERSION
This file contains the file format version information for the s-expression drawing sheet file format...
#define _(s)
DS_DATA_MODEL_FILEIO(const wxString &aFilename)
STRING_FORMATTER * m_writer
A coordinate point.
Definition: ds_data_item.h:69
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void format(DS_DATA_ITEM_TEXT *aItem, int aNestLevel) const
POINT_COORD m_Pos
Definition: ds_data_item.h:200
DS_DATA_ITEM * GetItem(unsigned aIdx) const
Drawing sheet structure type definitions.
Definition: ds_data_item.h:95
void Format(DS_DATA_MODEL *aDrawingSheet) const
void formatRepeatParameters(DS_DATA_ITEM *aItem) const
DS_DATA_MODEL_STRINGIO(wxString *aOutputString)
void SaveInString(wxString *aOutputString)
Save the description in a buffer.
unsigned GetCount() const
Used for text file output.
Definition: richio.h:456
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:414
wxString m_Name
Definition: ds_data_item.h:198
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
#define double2Str
PAGE_OPTION GetPage1Option() const
Definition: ds_data_item.h:133
void formatOptions(DS_DATA_ITEM *aItem) const