KiCad PCB EDA Suite
page_layout_reader.cpp
Go to the documentation of this file.
1 
7 /*
8  * This program source code file is part of KiCad, a free EDA CAD application.
9  *
10  * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
11  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, you may find one here:
26  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
27  * or you may search the http://www.gnu.org website for the version 2 license,
28  * or you may write to the Free Software Foundation, Inc.,
29  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
30  */
31 
32 #include <fctsys.h>
33 #include <base_struct.h>
34 #include <ws_painter.h>
35 #include <ws_draw_item.h>
36 #include <ws_data_model.h>
37 #include <page_layout/page_layout_reader_lexer.h>
38 
39 #include <wx/file.h>
40 #include <wx/mstream.h>
41 
42 
43 using namespace TB_READER_T;
44 
50 class PAGE_LAYOUT_READER_PARSER : public PAGE_LAYOUT_READER_LEXER
51 {
52 public:
53  PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource );
54  void Parse( WS_DATA_MODEL* aLayout );
55 
56 private:
57 
65  int parseInt( int aMin, int aMax );
66 
72  double parseDouble();
73 
74  void parseSetup( WS_DATA_MODEL* aLayout );
75 
79  void parseGraphic( WS_DATA_ITEM * aItem );
80 
84  void parseText( WS_DATA_ITEM_TEXT * aItem );
85 
90  void parsePolygon( WS_DATA_ITEM_POLYGONS * aItem );
91 
95  void parsePolyOutline( WS_DATA_ITEM_POLYGONS * aItem );
96 
97 
101  void parseBitmap( WS_DATA_ITEM_BITMAP * aItem );
102 
103  void parseCoordinate( POINT_COORD& aCoord);
104  void readOption( WS_DATA_ITEM * aItem );
105  void readPngdata( WS_DATA_ITEM_BITMAP * aItem );
106 };
107 
108 // PCB_PLOT_PARAMS_PARSER
109 
110 PAGE_LAYOUT_READER_PARSER::PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource ) :
111  PAGE_LAYOUT_READER_LEXER( aLine, aSource )
112 {
113 }
114 
115 
117 {
118  WS_DATA_ITEM* item;
119  LOCALE_IO toggle;
120 
121  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
122  {
123  if( token == T_LEFT )
124  token = NextTok();
125 
126  if( token == T_page_layout )
127  continue;
128 
129  switch( token )
130  {
131  case T_setup: // Defines default values for graphic items
132  parseSetup( aLayout );
133  break;
134 
135  case T_line:
137  parseGraphic( item );
138  aLayout->Append( item );
139  break;
140 
141  case T_rect:
142  item = new WS_DATA_ITEM( WS_DATA_ITEM::WS_RECT );
143  parseGraphic( item );
144  aLayout->Append( item );
145  break;
146 
147  case T_polygon:
148  item = new WS_DATA_ITEM_POLYGONS();
150  aLayout->Append( item );
151  break;
152 
153  case T_bitmap:
154  item = new WS_DATA_ITEM_BITMAP( NULL );
155  parseBitmap( (WS_DATA_ITEM_BITMAP*) item );
156  aLayout->Append( item );
157  break;
158 
159  case T_tbtext:
160  NeedSYMBOLorNUMBER();
161  item = new WS_DATA_ITEM_TEXT( FromUTF8() );
162  parseText( (WS_DATA_ITEM_TEXT*) item );
163  aLayout->Append( item );
164  break;
165 
166  default:
167  Unexpected( CurText() );
168  break;
169  }
170  }
171 }
172 
174 {
175  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
176  {
177  switch( token )
178  {
179  case T_LEFT:
180  break;
181 
182  case T_linewidth:
183  aLayout->m_DefaultLineWidth = parseDouble();
184  NeedRIGHT();
185  break;
186 
187  case T_textsize:
188  aLayout->m_DefaultTextSize.x = parseDouble();
189  aLayout->m_DefaultTextSize.y = parseDouble();
190  NeedRIGHT();
191  break;
192 
193  case T_textlinewidth:
194  aLayout->m_DefaultTextThickness = parseDouble();
195  NeedRIGHT();
196  break;
197 
198  case T_left_margin:
199  aLayout->SetLeftMargin( parseDouble() );
200  NeedRIGHT();
201  break;
202 
203  case T_right_margin:
204  aLayout->SetRightMargin( parseDouble() );
205  NeedRIGHT();
206  break;
207 
208  case T_top_margin:
209  aLayout->SetTopMargin( parseDouble() );
210  NeedRIGHT();
211  break;
212 
213  case T_bottom_margin:
214  aLayout->SetBottomMargin( parseDouble() );
215  NeedRIGHT();
216  break;
217 
218  default:
219  Unexpected( CurText() );
220  break;
221  }
222  }
223 
224  // The file is well-formed. If it has no further items, then that's the way the
225  // user wants it.
226  aLayout->AllowVoidList( true );
227 }
228 
229 
231 {
232  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
233  {
234  if( token == T_LEFT )
235  token = NextTok();
236 
237  switch( token )
238  {
239  case T_comment:
240  NeedSYMBOLorNUMBER();
241  aItem->m_Info = FromUTF8();
242  NeedRIGHT();
243  break;
244 
245  case T_pos:
246  parseCoordinate( aItem->m_Pos );
247  break;
248 
249  case T_name:
250  NeedSYMBOLorNUMBER();
251  aItem->m_Name = FromUTF8();
252  NeedRIGHT();
253  break;
254 
255  case T_option:
256  readOption( aItem );
257  break;
258 
259  case T_pts:
260  parsePolyOutline( aItem );
261  aItem->CloseContour();
262  break;
263 
264  case T_rotate:
265  aItem->m_Orient = parseDouble();
266  NeedRIGHT();
267  break;
268 
269  case T_repeat:
270  aItem->m_RepeatCount = parseInt( -1, 100 );
271  NeedRIGHT();
272  break;
273 
274  case T_incrx:
275  aItem->m_IncrementVector.x = parseDouble();
276  NeedRIGHT();
277  break;
278 
279  case T_incry:
280  aItem->m_IncrementVector.y = parseDouble();
281  NeedRIGHT();
282  break;
283 
284  case T_linewidth:
285  aItem->m_LineWidth = parseDouble();
286  NeedRIGHT();
287  break;
288 
289  default:
290  Unexpected( CurText() );
291  break;
292  }
293  }
294 
295  aItem->SetBoundingBox();
296 }
297 
299 {
300  DPOINT corner;
301 
302  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
303  {
304  if( token == T_LEFT )
305  token = NextTok();
306 
307  switch( token )
308  {
309  case T_xy:
310  corner.x = parseDouble();
311  corner.y = parseDouble();
312  aItem->AppendCorner( corner );
313  NeedRIGHT();
314  break;
315 
316  default:
317  Unexpected( CurText() );
318  break;
319  }
320  }
321 }
322 
323 
325 {
326  BITMAP_BASE* image = new BITMAP_BASE;
327  aItem->m_ImageBitmap = image;
328 
329  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
330  {
331  if( token == T_LEFT )
332  token = NextTok();
333 
334  switch( token )
335  {
336  case T_name:
337  NeedSYMBOLorNUMBER();
338  aItem->m_Name = FromUTF8();
339  NeedRIGHT();
340  break;
341 
342  case T_pos:
343  parseCoordinate( aItem->m_Pos );
344  break;
345 
346  case T_repeat:
347  aItem->m_RepeatCount = parseInt( -1, 100 );
348  NeedRIGHT();
349  break;
350 
351  case T_incrx:
352  aItem->m_IncrementVector.x = parseDouble();
353  NeedRIGHT();
354  break;
355 
356  case T_incry:
357  aItem->m_IncrementVector.y = parseDouble();
358  NeedRIGHT();
359  break;
360 
361  case T_linewidth:
362  aItem->m_LineWidth = parseDouble();
363  NeedRIGHT();
364  break;
365 
366  case T_scale:
367  aItem->m_ImageBitmap->SetScale( parseDouble() );
368  NeedRIGHT();
369  break;
370 
371  case T_pngdata:
372  readPngdata( aItem );
373  break;
374 
375  case T_option:
376  readOption( aItem );
377  break;
378 
379  default:
380  Unexpected( CurText() );
381  break;
382  }
383  }
384 }
385 
387 {
388  std::string tmp;
389 
390  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
391  {
392  if( token == T_LEFT )
393  token = NextTok();
394 
395  switch( token )
396  {
397  case T_data:
398  NeedSYMBOLorNUMBER();
399  tmp += CurStr();
400  tmp += "\n";
401  NeedRIGHT();
402  break;
403 
404  default:
405  Unexpected( CurText() );
406  break;
407  }
408  }
409 
410  tmp += "EndData";
411 
412  wxString msg;
413  STRING_LINE_READER str_reader( tmp, wxT("Png kicad_wks data") );
414 
415  if( ! aItem->m_ImageBitmap->LoadData( str_reader, msg ) )
416  wxLogMessage(msg);
417 }
418 
419 
421 {
422  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
423  {
424  switch( token )
425  {
426  case T_page1only: aItem->SetPage1Option( FIRST_PAGE_ONLY ); break;
427  case T_notonpage1: aItem->SetPage1Option( SUBSEQUENT_PAGES ); break;
428  default: Unexpected( CurText() ); break;
429  }
430  }
431 }
432 
433 
435 {
436  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
437  {
438  if( token == T_LEFT )
439  token = NextTok();
440  else
441  {
442  // If another token than T_LEFT is read here, this is an error
443  // however, due to a old bug in kicad, the token T_end can be found
444  // without T_LEFT in a very few .wks files (perhaps only one in a demo).
445  // So this ugly hack disables the error detection.
446  if( token != T_end )
447  Unexpected( CurText() );
448  }
449 
450  switch( token )
451  {
452  case T_comment:
453  NeedSYMBOLorNUMBER();
454  aItem->m_Info = FromUTF8();
455  NeedRIGHT();
456  break;
457 
458  case T_option:
459  readOption( aItem );
460  break;
461 
462  case T_name:
463  NeedSYMBOLorNUMBER();
464  aItem->m_Name = FromUTF8();
465  NeedRIGHT();
466  break;
467 
468  case T_start:
469  parseCoordinate( aItem->m_Pos );
470  break;
471 
472  case T_end:
473  parseCoordinate( aItem->m_End );
474  break;
475 
476  case T_repeat:
477  aItem->m_RepeatCount = parseInt( -1, 100 );
478  NeedRIGHT();
479  break;
480 
481  case T_incrx:
482  aItem->m_IncrementVector.x = parseDouble();
483  NeedRIGHT();
484  break;
485 
486  case T_incry:
487  aItem->m_IncrementVector.y = parseDouble();
488  NeedRIGHT();
489  break;
490 
491  case T_linewidth:
492  aItem->m_LineWidth = parseDouble();
493  NeedRIGHT();
494  break;
495 
496  default:
497  Unexpected( CurText() );
498  break;
499  }
500  }
501 }
502 
503 
505 {
506  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
507  {
508  if( token == T_LEFT )
509  token = NextTok();
510 
511  switch( token )
512  {
513  case T_comment:
514  NeedSYMBOLorNUMBER();
515  aItem->m_Info = FromUTF8();
516  NeedRIGHT();
517  break;
518 
519  case T_option:
520  readOption( aItem );
521  break;
522 
523  case T_name:
524  NeedSYMBOLorNUMBER();
525  aItem->m_Name = FromUTF8();
526  NeedRIGHT();
527  break;
528 
529  case T_pos:
530  parseCoordinate( aItem->m_Pos );
531  break;
532 
533  case T_repeat:
534  aItem->m_RepeatCount = parseInt( -1, 100 );
535  NeedRIGHT();
536  break;
537 
538  case T_incrx:
539  aItem->m_IncrementVector.x = parseDouble();
540  NeedRIGHT();
541  break;
542 
543  case T_incry:
544  aItem->m_IncrementVector.y = parseDouble();
545  NeedRIGHT();
546  break;
547 
548  case T_incrlabel:
549  aItem->m_IncrementLabel = parseInt(INT_MIN, INT_MAX);
550  NeedRIGHT();
551  break;
552 
553  case T_maxlen:
554  aItem->m_BoundingBoxSize.x = parseDouble();
555  NeedRIGHT();
556  break;
557 
558  case T_maxheight:
559  aItem->m_BoundingBoxSize.y = parseDouble();
560  NeedRIGHT();
561  break;
562 
563  case T_font:
564  for( token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
565  {
566  switch( token )
567  {
568  case T_LEFT:
569  break;
570 
571  case T_bold:
572  aItem->m_Bold = true;
573  break;
574 
575  case T_italic:
576  aItem->m_Italic = true;
577  break;
578 
579  case T_size:
580  aItem->m_TextSize.x = parseDouble();
581  aItem->m_TextSize.y = parseDouble();
582  NeedRIGHT();
583  break;
584 
585  case T_linewidth:
586  aItem->m_LineWidth = parseDouble();
587  NeedRIGHT();
588  break;
589 
590  default:
591  Unexpected( CurText() );
592  break;
593  }
594  }
595  break;
596 
597  case T_justify:
598  for( token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
599  {
600  switch( token )
601  {
602  case T_center:
605  break;
606 
607  case T_left:
609  break;
610 
611  case T_right:
613  break;
614 
615  case T_top:
617  break;
618 
619  case T_bottom:
621  break;
622 
623  default:
624  Unexpected( CurText() );
625  break;
626  }
627  }
628  break;
629 
630  case T_rotate:
631  aItem->m_Orient = parseDouble();
632  NeedRIGHT();
633  break;
634 
635  default:
636  Unexpected( CurText() );
637  break;
638  }
639  }
640 }
641 
642 // parse an expression like " 25 1 ltcorner)"
644 {
645  aCoord.m_Pos.x = parseDouble();
646  aCoord.m_Pos.y = parseDouble();
647 
648  for( T token = NextTok(); token != T_RIGHT && token != EOF; token = NextTok() )
649  {
650  switch( token )
651  {
652  case T_ltcorner: aCoord.m_Anchor = LT_CORNER; break;
653  case T_lbcorner: aCoord.m_Anchor = LB_CORNER; break;
654  case T_rbcorner: aCoord.m_Anchor = RB_CORNER; break;
655  case T_rtcorner: aCoord.m_Anchor = RT_CORNER; break;
656  default: Unexpected( CurText() ); break;
657  }
658  }
659 }
660 
661 int PAGE_LAYOUT_READER_PARSER::parseInt( int aMin, int aMax )
662 {
663  T token = NextTok();
664 
665  if( token != T_NUMBER )
666  Expecting( T_NUMBER );
667 
668  int val = atoi( CurText() );
669 
670  if( val < aMin )
671  val = aMin;
672  else if( val > aMax )
673  val = aMax;
674 
675  return val;
676 }
677 
678 
680 {
681  T token = NextTok();
682 
683  if( token != T_NUMBER )
684  Expecting( T_NUMBER );
685 
686  double val = strtod( CurText(), NULL );
687 
688  return val;
689 }
690 
691 // defaultPageLayout is the default page layout description
692 // using the S expr.
693 // see page_layout_default_shape.cpp
694 extern const char defaultPageLayout[];
695 
697 {
698  SetPageLayout( defaultPageLayout, false, wxT( "default page" ) );
699 }
700 
701 // Returns defaultPageLayout as a string;
703 {
704  return wxString( defaultPageLayout );
705 }
706 
707 // emptyPageLayout is a "empty" page layout description
708 // there is a 0 length line to fool something somewhere.
709 // using the S expr.
710 // see page_layout_empty_description.cpp
711 extern const char emptyPageLayout[];
712 
714 {
715  SetPageLayout( emptyPageLayout, false, wxT( "empty page" ) );
716 }
717 
718 
720 {
721  return wxString( emptyPageLayout );
722 }
723 
724 
725 void WS_DATA_MODEL::SetPageLayout( const char* aPageLayout, bool Append, const wxString& aSource )
726 {
727  if( ! Append )
728  ClearList();
729 
730  PAGE_LAYOUT_READER_PARSER lp_parser( aPageLayout, wxT( "Sexpr_string" ) );
731 
732  try
733  {
734  lp_parser.Parse( this );
735  }
736  catch( const IO_ERROR& ioe )
737  {
738  wxLogMessage( ioe.What() );
739  }
740 }
741 
742 
743 void WS_DATA_MODEL::SetPageLayout( const wxString& aFullFileName, bool Append )
744 {
745  wxString fullFileName = aFullFileName;
746 
747  if( !Append )
748  {
749  if( fullFileName.IsEmpty() )
750  wxGetEnv( wxT( "KICAD_WKSFILE" ), &fullFileName );
751 
752  if( fullFileName.IsEmpty() || !wxFileExists( fullFileName ) )
753  {
754  #if 0
755  if( !fullFileName.IsEmpty() )
756  wxLogMessage( wxT( "Page layout file <%s> not found" ), fullFileName.GetData() );
757  #endif
759  return;
760  }
761  }
762 
763  wxFile wksFile( fullFileName );
764 
765  if( ! wksFile.IsOpened() )
766  {
767  if( !Append )
769  return;
770  }
771 
772  int filelen = wksFile.Length();
773  char * buffer = new char[filelen+10];
774 
775  if( wksFile.Read( buffer, filelen ) != filelen )
776  wxLogMessage( _("The file \"%s\" was not fully read"), fullFileName.GetData() );
777  else
778  {
779  buffer[filelen]=0;
780 
781  if( ! Append )
782  ClearList();
783 
784  PAGE_LAYOUT_READER_PARSER pl_parser( buffer, fullFileName );
785 
786  try
787  {
788  pl_parser.Parse( this );
789  }
790  catch( const IO_ERROR& ioe )
791  {
792  wxLogMessage( ioe.What() );
793  }
794  }
795 
796  delete[] buffer;
797 }
wxString m_Name
Definition: ws_data_item.h:111
WS_DATA_MODEL handles the graphic items list to draw/plot the frame and title block.
Definition: ws_data_model.h:39
void parseText(WS_DATA_ITEM_TEXT *aItem)
parse a text item starting by "(tbtext" and read parameters.
void parseCoordinate(POINT_COORD &aCoord)
int parseInt(int aMin, int aMax)
Function parseInt parses an integer and constrains it between two values.
Work sheet structure type definitions.
Definition: ws_data_item.h:93
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:154
const char emptyPageLayout[]
void AppendCorner(const DPOINT &aCorner)
add a corner in corner list
Definition: ws_data_item.h:237
void Parse(void *yyp, int yymajor, ParseTOKENTYPE yyminor ParseARG_PDECL)
void Parse(WS_DATA_MODEL *aLayout)
void SetScale(double aScale)
Definition: bitmap_base.h:93
static double parseDouble(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...
BITMAP_BASE * m_ImageBitmap
Definition: ws_data_item.h:366
POINT_COORD m_End
Definition: ws_data_item.h:116
void SetPage1Option(PAGE_OPTION aChoice)
Definition: ws_data_item.h:154
void SetPageLayout(const wxString &aFullFileName=wxEmptyString, bool Append=false)
Populates the list with a custom layout, or the default layout, if no custom layout available.
double parseDouble()
Function parseDouble parses a double.
static wxString EmptyLayout()
Returns a string containing the empty layout shape.
wxString m_Info
Definition: ws_data_item.h:113
DSIZE m_DefaultTextSize
Definition: ws_data_model.h:56
EDA_TEXT_HJUSTIFY_T m_Hjustify
Definition: ws_data_item.h:304
PAGE_LAYOUT_READER_PARSER(const char *aLine, const wxString &aSource)
void ClearList()
erase the list of items
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
const char defaultPageLayout[]
void readPngdata(WS_DATA_ITEM_BITMAP *aItem)
void CloseContour()
Closes the current contour, by storing the index of the last corner of the current polygon in m_polyI...
Definition: ws_data_item.h:246
void AllowVoidList(bool Allow)
In Kicad applications, a page layout description is needed So if the list is empty,...
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
DPOINT m_Pos
Definition: ws_data_item.h:71
void SetLeftMargin(double aMargin)
Definition: ws_data_model.h:85
void SetTopMargin(double aMargin)
Definition: ws_data_model.h:91
EDA_TEXT_VJUSTIFY_T m_Vjustify
Definition: ws_data_item.h:305
void parsePolyOutline(WS_DATA_ITEM_POLYGONS *aItem)
parse a list of corners starting by "( pts" and read coordinates.
Class PAGE_LAYOUT_READER_PARSER holds data and functions pertinent to parsing a S-expression file for...
A coordinate point The position is always relative to the corner anchor Note the coordinate is from t...
Definition: ws_data_item.h:68
void parseBitmap(WS_DATA_ITEM_BITMAP *aItem)
parse a bitmap item starting by "( bitmap" and read parameters.
#define _(s)
DPOINT m_IncrementVector
Definition: ws_data_item.h:119
static wxString DefaultLayout()
Returns a string containing the empty layout shape.
double m_LineWidth
Definition: ws_data_item.h:117
void SetBottomMargin(double aMargin)
Definition: ws_data_model.h:94
void readOption(WS_DATA_ITEM *aItem)
double m_DefaultLineWidth
Definition: ws_data_model.h:55
bool LoadData(LINE_READER &aLine, wxString &aErrorMsg)
Load an image data saved by SaveData (png, in Hexadecimal form)
double m_DefaultTextThickness
Definition: ws_data_model.h:57
void Append(WS_DATA_ITEM *aItem)
void SetBoundingBox()
calculate the bounding box of the set polygons
void parseGraphic(WS_DATA_ITEM *aItem)
parse a graphic item starting by "(line" or "(rect" and read parameters.
int m_IncrementLabel
Definition: ws_data_item.h:121
void parsePolygon(WS_DATA_ITEM_POLYGONS *aItem)
parse a polygon item starting by "( polygon" and read parameters.
POINT_COORD m_Pos
Definition: ws_data_item.h:115
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
void parseSetup(WS_DATA_MODEL *aLayout)
void SetRightMargin(double aMargin)
Definition: ws_data_model.h:88
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:52