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.

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