You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
7.4 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2015-2020 KiCad Developers, see CHANGELOG.TXT for contributors.
  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. #include <template_fieldnames.h>
  25. #include <dsnlexer.h>
  26. #include <fctsys.h>
  27. #include <macros.h>
  28. #include <pgm_base.h>
  29. using namespace TFIELD_T;
  30. const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx )
  31. {
  32. static void* locale = nullptr;
  33. static wxString referenceDefault;
  34. static wxString valueDefault;
  35. static wxString footprintDefault;
  36. static wxString datasheetDefault;
  37. static wxString fieldDefault;
  38. // Fetching translations can take a surprising amount of time when loading libraries,
  39. // so only do it when necessary.
  40. if( Pgm().GetLocale() != locale )
  41. {
  42. referenceDefault = _( "Reference" );
  43. valueDefault = _( "Value" );
  44. footprintDefault = _( "Footprint" );
  45. datasheetDefault = _( "Datasheet" );
  46. fieldDefault = _( "Field%d" );
  47. locale = Pgm().GetLocale();
  48. }
  49. // Fixed values for the mandatory fields
  50. switch( aFieldNdx )
  51. {
  52. case REFERENCE: return referenceDefault; // The component reference, R1, C1, etc.
  53. case VALUE: return valueDefault; // The component value + name
  54. case FOOTPRINT: return footprintDefault; // The footprint for use with Pcbnew
  55. case DATASHEET: return datasheetDefault; // Link to a datasheet for component
  56. default: return wxString::Format( fieldDefault, aFieldNdx );
  57. }
  58. }
  59. void TEMPLATE_FIELDNAME::Format( OUTPUTFORMATTER* out, int nestLevel ) const
  60. {
  61. out->Print( nestLevel, "(field (name %s)", out->Quotew( m_Name ).c_str() );
  62. if( m_Visible )
  63. out->Print( 0, " visible" );
  64. if( m_URL )
  65. out->Print( 0, " url" );
  66. out->Print( 0, ")\n" );
  67. }
  68. void TEMPLATE_FIELDNAME::Parse( TEMPLATE_FIELDNAMES_LEXER* in )
  69. {
  70. T tok;
  71. in->NeedLEFT(); // begin (name ...)
  72. if( (tok = in->NextTok()) != T_name )
  73. in->Expecting( T_name );
  74. in->NeedSYMBOLorNUMBER();
  75. m_Name = FROM_UTF8( in->CurText() );
  76. in->NeedRIGHT(); // end (name ...)
  77. while( (tok = in->NextTok() ) != T_RIGHT && tok != T_EOF )
  78. {
  79. // "visible" has no '(' prefix, "value" does, so T_LEFT is optional.
  80. if( tok == T_LEFT )
  81. tok = in->NextTok();
  82. switch( tok )
  83. {
  84. case T_value:
  85. // older format; silently skip
  86. in->NeedSYMBOLorNUMBER();
  87. in->NeedRIGHT();
  88. break;
  89. case T_visible:
  90. m_Visible = true;
  91. break;
  92. case T_url:
  93. m_URL = true;
  94. break;
  95. default:
  96. in->Expecting( "value|url|visible" );
  97. break;
  98. }
  99. }
  100. }
  101. void TEMPLATES::Format( OUTPUTFORMATTER* out, int nestLevel, bool aGlobal ) const
  102. {
  103. // We'll keep this general, and include the \n, even though the only known
  104. // use at this time will not want the newlines or the indentation.
  105. out->Print( nestLevel, "(templatefields" );
  106. const TEMPLATE_FIELDNAMES& source = aGlobal ? m_globals : m_project;
  107. for( const TEMPLATE_FIELDNAME& temp : source )
  108. temp.Format( out, nestLevel+1 );
  109. out->Print( 0, ")\n" );
  110. }
  111. void TEMPLATES::Parse( TEMPLATE_FIELDNAMES_LEXER* in, bool aGlobal )
  112. {
  113. T tok;
  114. while( ( tok = in->NextTok() ) != T_RIGHT && tok != T_EOF )
  115. {
  116. if( tok == T_LEFT )
  117. tok = in->NextTok();
  118. switch( tok )
  119. {
  120. case T_templatefields: // a token indicating class TEMPLATES.
  121. // Be flexible regarding the starting point of the TEMPLATE_FIELDNAMES_LEXER
  122. // stream. Caller may not have read the first two tokens out of the
  123. // stream: T_LEFT and T_templatefields, so ignore them if seen here.
  124. break;
  125. case T_field:
  126. {
  127. // instantiate on stack, so if exception is thrown,
  128. // destructor runs
  129. TEMPLATE_FIELDNAME field;
  130. field.Parse( in );
  131. // add the field
  132. AddTemplateFieldName( field, aGlobal );
  133. }
  134. break;
  135. default:
  136. in->Unexpected( in->CurText() );
  137. break;
  138. }
  139. }
  140. }
  141. /*
  142. * Flatten project and global templates into a single list. (Project templates take
  143. * precedence.)
  144. */
  145. void TEMPLATES::resolveTemplates()
  146. {
  147. m_resolved = m_project;
  148. // Note: order N^2 algorithm. Would need changing if fieldname template sets ever
  149. // get large.
  150. for( const TEMPLATE_FIELDNAME& global : m_globals )
  151. {
  152. for( const TEMPLATE_FIELDNAME& project : m_project )
  153. {
  154. if( global.m_Name == project.m_Name )
  155. continue;
  156. }
  157. m_resolved.push_back( global );
  158. }
  159. m_resolvedDirty = false;
  160. }
  161. void TEMPLATES::AddTemplateFieldName( const TEMPLATE_FIELDNAME& aFieldName, bool aGlobal )
  162. {
  163. // Ensure that the template fieldname does not match a fixed fieldname.
  164. for( int i = 0; i < MANDATORY_FIELDS; ++i )
  165. {
  166. if( TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) == aFieldName.m_Name )
  167. return;
  168. }
  169. TEMPLATE_FIELDNAMES& target = aGlobal ? m_globals : m_project;
  170. // ensure uniqueness, overwrite any template fieldname by the same name.
  171. for( TEMPLATE_FIELDNAME& temp : target )
  172. {
  173. if( temp.m_Name == aFieldName.m_Name )
  174. {
  175. temp = aFieldName;
  176. m_resolvedDirty = true;
  177. return;
  178. }
  179. }
  180. // the name is legal and not previously added to the config container, append
  181. // it and return its index within the container.
  182. target.push_back( aFieldName );
  183. m_resolvedDirty = true;
  184. }
  185. void TEMPLATES::DeleteAllFieldNameTemplates( bool aGlobal )
  186. {
  187. if( aGlobal )
  188. {
  189. m_globals.clear();
  190. m_resolved = m_project;
  191. }
  192. else
  193. {
  194. m_project.clear();
  195. m_resolved = m_globals;
  196. }
  197. m_resolvedDirty = false;
  198. }
  199. const TEMPLATE_FIELDNAMES& TEMPLATES::GetTemplateFieldNames()
  200. {
  201. if( m_resolvedDirty )
  202. resolveTemplates();
  203. return m_resolved;
  204. }
  205. const TEMPLATE_FIELDNAMES& TEMPLATES::GetTemplateFieldNames( bool aGlobal )
  206. {
  207. if( aGlobal )
  208. return m_globals;
  209. else
  210. return m_project;
  211. }
  212. const TEMPLATE_FIELDNAME* TEMPLATES::GetFieldName( const wxString& aName )
  213. {
  214. if( m_resolvedDirty )
  215. resolveTemplates();
  216. for( const TEMPLATE_FIELDNAME& field : m_resolved )
  217. {
  218. if( field.m_Name == aName )
  219. return &field;
  220. }
  221. return nullptr;
  222. }