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 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>
34 #include <math/vector2d.h>
35 #include <drawing_sheet/drawing_sheet_reader_lexer.h>
36 
37 #include <wx/msgdlg.h>
38 
39 using namespace TB_READER_T;
40 
41 #define double2Str Double2Str
42 
43 // A helper function to write tokens:
44 static const char* getTokenName( T aTok )
45 {
46  return DRAWING_SHEET_READER_LEXER::TokenName( aTok );
47 }
48 
49 // A basic helper class to write a page layout description
50 // Not used alone, a file writer or a string writer should be derived to use it.
51 // Therefore the constructor is protected.
53 {
54 protected:
56 
57  DS_DATA_MODEL_IO() { m_out = NULL; }
58  virtual ~DS_DATA_MODEL_IO() {}
59 
60 public:
61  void Format( DS_DATA_MODEL* aModel ) const;
62 
63  void Format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const;
64 
65 private:
66  void format( DS_DATA_ITEM_TEXT* aItem, int aNestLevel ) const;
67  void format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const;
68  void format( DS_DATA_ITEM_POLYGONS* aItem, int aNestLevel )
69  const;
70  void format( DS_DATA_ITEM_BITMAP* aItem, int aNestLevel ) const;
71  void formatCoordinate( const char * aToken, POINT_COORD & aCoord ) const;
72  void formatRepeatParameters( DS_DATA_ITEM* aItem ) const;
73  void formatOptions( DS_DATA_ITEM* aItem ) const;
74 };
75 
76 
77 // A helper class to write a page layout description to a file
79 {
81 
82 public:
83  DS_DATA_MODEL_FILEIO( const wxString& aFilename ) :
85  {
86  try
87  {
88  m_fileout = new FILE_OUTPUTFORMATTER( aFilename );
89  m_out = m_fileout;
90  }
91  catch( const IO_ERROR& ioe )
92  {
93  wxMessageBox( ioe.What(), _( "Error writing page layout design file" ) );
94  }
95  }
96 
98  {
99  delete m_fileout;
100  }
101 };
102 
103 
104 // A helper class to write a page layout description to a string
106 {
108  wxString & m_output;
109 
110 public:
111  DS_DATA_MODEL_STRINGIO( wxString& aOutputString ) :
112  DS_DATA_MODEL_IO(), 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 page layout design file" ) );
122  }
123  }
124 
126  {
127  m_output = FROM_UTF8( m_writer->GetString().c_str() );
128  delete m_writer;
129  }
130 };
131 
132 
133 /*
134  * Save the description in a file
135  */
136 void DS_DATA_MODEL::Save( const wxString& aFullFileName )
137 {
138  DS_DATA_MODEL_FILEIO writer( aFullFileName );
139  writer.Format( this );
140 }
141 
142 
143 /* Save the description in a buffer
144  */
145 void DS_DATA_MODEL::SaveInString( wxString& aOutputString )
146 {
147  DS_DATA_MODEL_STRINGIO writer( aOutputString );
148  writer.Format( this );
149 }
150 
151 
152 void DS_DATA_MODEL::SaveInString( std::vector<DS_DATA_ITEM*> aItemsList, wxString& aOutputString )
153 {
154  DS_DATA_MODEL_STRINGIO writer( aOutputString );
155 
156  LOCALE_IO toggle; // switch on/off the locale "C" notation
157 
158  for( DS_DATA_ITEM* item : aItemsList )
159  writer.Format( this, item, 0 );
160 }
161 
162 
163 void DS_DATA_MODEL_IO::Format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const
164 {
165  switch( aItem->GetType() )
166  {
168  format( (DS_DATA_ITEM_TEXT*) aItem, aNestLevel );
169  break;
170 
173  format( aModel, aItem, aNestLevel );
174  break;
175 
177  format( (DS_DATA_ITEM_POLYGONS*) aItem, aNestLevel );
178  break;
179 
181  format( (DS_DATA_ITEM_BITMAP*) aItem, aNestLevel );
182  break;
183 
184  default:
185  wxFAIL_MSG( wxT( "Cannot format item" ) );
186  }
187 }
188 
189 
190 void DS_DATA_MODEL_IO::Format( DS_DATA_MODEL* aPageLayout ) const
191 {
192  LOCALE_IO toggle; // switch on/off the locale "C" notation
193 
194  m_out->Print( 0, "(drawing_sheet\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( aPageLayout->m_DefaultTextSize.x ).c_str(),
202  double2Str( aPageLayout->m_DefaultTextSize.y ).c_str() );
203  m_out->Print( 0, "(linewidth %s)",
204  double2Str( aPageLayout->m_DefaultLineWidth ).c_str() );
205  m_out->Print( 0, "(textlinewidth %s)",
206  double2Str( aPageLayout->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( aPageLayout->GetLeftMargin() ).c_str() );
212  m_out->Print( 0, "(%s %s)", getTokenName( T_right_margin ),
213  double2Str( aPageLayout->GetRightMargin() ).c_str() );
214  m_out->Print( 0, "(%s %s)", getTokenName( T_top_margin ),
215  double2Str( aPageLayout->GetTopMargin() ).c_str() );
216  m_out->Print( 0, "(%s %s)", getTokenName( T_bottom_margin ),
217  double2Str( aPageLayout->GetBottomMargin() ).c_str() );
218  m_out->Print( 0, ")\n" );
219 
220  // Save the graphical items on the page layout
221  for( unsigned ii = 0; ii < aPageLayout->GetCount(); ii++ )
222  {
223  DS_DATA_ITEM* item = aPageLayout->GetItem( ii );
224  Format( aPageLayout, 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 void DS_DATA_MODEL_IO::format( DS_DATA_MODEL* aModel, DS_DATA_ITEM* aItem, int aNestLevel ) const
315 {
316  if( aItem->GetType() == DS_DATA_ITEM::DS_RECT )
317  m_out->Print( aNestLevel, "(%s", getTokenName( T_rect ) );
318  else
319  m_out->Print( aNestLevel, "(%s", getTokenName( T_line ) );
320 
321  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
322  m_out->Quotew( aItem->m_Name ).c_str() );
323 
324  formatCoordinate( getTokenName( T_start ), aItem->m_Pos );
325  formatCoordinate( getTokenName( T_end ), aItem->m_End );
326  formatOptions( aItem );
327 
328  if( aItem->m_LineWidth && aItem->m_LineWidth != aModel->m_DefaultLineWidth )
329  m_out->Print( 0, " (linewidth %s)", double2Str( aItem->m_LineWidth ).c_str() );
330 
331  formatRepeatParameters( aItem );
332 
333  if( !aItem->m_Info.IsEmpty() )
334  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
335 
336  m_out->Print( 0, ")\n" );
337 }
338 
339 
340 void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_POLYGONS* aItem, int aNestLevel ) const
341 {
342  m_out->Print( aNestLevel, "(%s", getTokenName( T_polygon ) );
343  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
344  m_out->Quotew( aItem->m_Name ).c_str() );
345  formatCoordinate( getTokenName( T_pos ), aItem->m_Pos );
346  formatOptions( aItem );
347 
348  formatRepeatParameters( aItem );
349 
350  if( aItem->m_Orient )
351  m_out->Print( 0, " (%s %s)", getTokenName( T_rotate ),
352  double2Str(aItem->m_Orient ).c_str() );
353 
354  if( aItem->m_LineWidth )
355  m_out->Print( 0, " (linewidth %s)\n", double2Str( aItem->m_LineWidth ).c_str() );
356 
357  if( !aItem->m_Info.IsEmpty() )
358  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
359 
360  // Write polygon corners list
361  for( int kk = 0; kk < aItem->GetPolyCount(); kk++ )
362  {
363  m_out->Print( aNestLevel+1, "(%s", getTokenName( T_pts ) );
364  // Create current polygon corners list
365  unsigned ist = aItem->GetPolyIndexStart( kk );
366  unsigned iend = aItem->GetPolyIndexEnd( kk );
367  int ii = 0;
368 
369  while( ist <= iend )
370  {
371  DPOINT pos = aItem->m_Corners[ist++];
372  int nestLevel = 0;
373 
374  if( ii++ > 4)
375  {
376  m_out->Print( 0, "\n" );
377  nestLevel = aNestLevel+2;
378  ii = 0;
379  }
380 
381  m_out->Print( nestLevel, " (%s %s %s)", getTokenName( T_xy ),
382  double2Str( pos.x ).c_str(),
383  double2Str( pos.y ).c_str() );
384  }
385 
386  m_out->Print( 0, ")\n" );
387  }
388 
389  m_out->Print( aNestLevel, ")\n" );
390 }
391 
392 
393 void DS_DATA_MODEL_IO::format( DS_DATA_ITEM_BITMAP* aItem, int aNestLevel ) const
394 {
395  m_out->Print( aNestLevel, "(%s", getTokenName( T_bitmap ) );
396  m_out->Print( 0, " (%s %s)", getTokenName( T_name ),
397  m_out->Quotew( aItem->m_Name ).c_str() );
398  formatCoordinate( getTokenName( T_pos ), aItem->m_Pos );
399  formatOptions( aItem );
400 
401  m_out->Print( 0, " (%s %s)", getTokenName( T_scale ),
402  double2Str( aItem->m_ImageBitmap->GetScale() ).c_str() );
403 
404  formatRepeatParameters( aItem );
405  m_out->Print( 0,"\n");
406 
407  if( !aItem->m_Info.IsEmpty() )
408  m_out->Print( 0, " (comment %s)\n", m_out->Quotew( aItem->m_Info ).c_str() );
409 
410  // Write image in png readable format
411  m_out->Print( aNestLevel, "(%s\n", getTokenName( T_pngdata ) );
412  wxArrayString pngStrings;
413  aItem->m_ImageBitmap->SaveData( pngStrings );
414 
415  for( unsigned ii = 0; ii < pngStrings.GetCount(); ii++ )
416  m_out->Print( aNestLevel+1, "(data \"%s\")\n", TO_UTF8(pngStrings[ii]) );
417 
418  m_out->Print( aNestLevel+1, ")\n" );
419 
420  m_out->Print( aNestLevel, ")\n" );
421 }
422 
423 
424 void DS_DATA_MODEL_IO::formatCoordinate( const char * aToken,
425  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:208
unsigned GetPolyIndexStart(unsigned aContour) const
Definition: ds_data_item.h:256
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:344
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:63
void Format(DS_DATA_MODEL *aModel) const
int GetPolyCount() const
Definition: ds_data_item.h:250
double m_DefaultLineWidth
double GetScale() const
Definition: bitmap_base.h:79
double GetTopMargin()
Definition: ds_data_model.h:66
DS_DATA_MODEL_STRINGIO(wxString &aOutputString)
static const char * getTokenName(T aTok)
An interface used to output 8 bit text in a convenient way.
Definition: richio.h:306
double GetLeftMargin()
Definition: ds_data_model.h:60
std::vector< DPOINT > m_Corners
Definition: ds_data_item.h:292
POINT_COORD m_End
Definition: ds_data_item.h:210
unsigned GetPolyIndexEnd(unsigned aContour) const
Definition: ds_data_item.h:268
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:343
#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:213
OUTPUTFORMATTER * m_out
double m_LineWidth
Definition: ds_data_item.h:211
DS_ITEM_TYPE GetType() const
Definition: ds_data_item.h:129
virtual ~DS_DATA_MODEL_IO()
#define NULL
DSIZE m_DefaultTextSize
BITMAP_BASE * m_ImageBitmap
Definition: ds_data_item.h:373
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
DPOINT m_Pos
Definition: ds_data_item.h:80
double GetBottomMargin()
Definition: ds_data_model.h:69
int m_IncrementLabel
Definition: ds_data_item.h:215
DS_DATA_MODEL_FILEIO(const wxString &aFilename)
STRING_FORMATTER * m_writer
const std::string & GetString()
Definition: richio.h:435
A coordinate point.
Definition: ds_data_item.h:69
void SaveInString(wxString &aOutputString)
Save the description in a buffer.
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:209
DS_DATA_ITEM * GetItem(unsigned aIdx) const
Drawing sheet structure type definitions.
Definition: ds_data_item.h:95
#define _(s)
Definition: 3d_actions.cpp:33
void formatRepeatParameters(DS_DATA_ITEM *aItem) const
unsigned GetCount() const
Used for text file output.
Definition: richio.h:453
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:411
wxString m_Name
Definition: ds_data_item.h:206
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:134
void formatOptions(DS_DATA_ITEM *aItem) const