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.

244 lines
8.2 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <confirm.h>
  26. #include <string_utils.h>
  27. #include <kiface_base.h>
  28. #include <sch_edit_frame.h>
  29. #include <wildcards_and_files_ext.h>
  30. #include <sch_sheet_path.h>
  31. #include <sch_symbol.h>
  32. #include <sch_reference_list.h>
  33. #include <schematic.h>
  34. #include <dsnlexer.h>
  35. #include <ptree.h>
  36. #include <boost/property_tree/ptree.hpp>
  37. #include <tools/sch_editor_control.h>
  38. #include <wx/choicdlg.h>
  39. #include <wx/filedlg.h>
  40. void SCH_EDITOR_CONTROL::AssignFootprints( const std::string& aChangedSetOfReferences )
  41. {
  42. // Build a flat list of symbols in schematic:
  43. SCH_REFERENCE_LIST refs;
  44. SCH_SHEET_LIST sheets = m_frame->Schematic().GetSheets();
  45. bool isChanged = false;
  46. sheets.GetSymbols( refs, false );
  47. DSNLEXER lexer( aChangedSetOfReferences, FROM_UTF8( __func__ ) );
  48. PTREE doc;
  49. try
  50. {
  51. Scan( &doc, &lexer );
  52. CPTREE& back_anno = doc.get_child( "cvpcb_netlist" );
  53. wxString footprint;
  54. for( PTREE::const_iterator ref = back_anno.begin(); ref != back_anno.end(); ++ref )
  55. {
  56. wxASSERT( ref->first == "ref" );
  57. wxString reference = (UTF8&) ref->second.front().first;
  58. // Ensure the "fpid" node contains a footprint name, and get it if exists
  59. if( ref->second.get_child( "fpid" ).size() )
  60. {
  61. wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first;
  62. footprint = tmp;
  63. }
  64. else
  65. footprint.Empty();
  66. // Search the symbol in the flat list
  67. for( unsigned ii = 0; ii < refs.GetCount(); ++ii )
  68. {
  69. if( reference == refs[ii].GetRef() )
  70. {
  71. // We have found a candidate.
  72. // Note: it can be not unique (multiple parts per package)
  73. // So we *do not* stop the search here
  74. SCH_SYMBOL* symbol = refs[ ii ].GetSymbol();
  75. // For backwards-compatibility CvPcb currently updates all instances of a
  76. // symbol (even though it lists these instances separately).
  77. SCH_SHEET_PATH* sheetPath = nullptr; // &refs[ii].GetSheetPath();
  78. wxString oldfp = refs[ii].GetFootprint();
  79. if( oldfp.IsEmpty() && symbol->GetField( FOOTPRINT_FIELD )->IsVisible() )
  80. symbol->GetField( FOOTPRINT_FIELD )->SetVisible( false );
  81. if( oldfp != footprint )
  82. {
  83. isChanged = true;
  84. symbol->SetFootprint( sheetPath, footprint );
  85. }
  86. }
  87. }
  88. }
  89. }
  90. catch( const PTREE_ERROR& ex )
  91. {
  92. // remap the exception to something the caller is likely to understand.
  93. THROW_IO_ERROR( ex.what() );
  94. }
  95. if( isChanged )
  96. {
  97. m_frame->SyncView();
  98. m_frame->GetCanvas()->Refresh();
  99. m_frame->OnModify();
  100. }
  101. }
  102. bool SCH_EDITOR_CONTROL::processCmpToFootprintLinkFile( const wxString& aFullFilename,
  103. bool aForceVisibilityState,
  104. bool aVisibilityState )
  105. {
  106. // Build a flat list of symbols in schematic:
  107. SCH_REFERENCE_LIST referencesList;
  108. SCH_SHEET_LIST sheetList = m_frame->Schematic().GetSheets();
  109. sheetList.GetSymbols( referencesList, false );
  110. FILE* cmpFile = wxFopen( aFullFilename, wxT( "rt" ) );
  111. if( cmpFile == nullptr )
  112. return false;
  113. // cmpFileReader dtor will close cmpFile
  114. FILE_LINE_READER cmpFileReader( cmpFile, aFullFilename );
  115. // Now, for each symbol found in file,
  116. // replace footprint field value by the new value:
  117. wxString reference;
  118. wxString footprint;
  119. wxString buffer;
  120. wxString value;
  121. while( cmpFileReader.ReadLine() )
  122. {
  123. buffer = FROM_UTF8( cmpFileReader.Line() );
  124. if( !buffer.StartsWith( wxT( "BeginCmp" ) ) )
  125. continue;
  126. // Begin symbol description.
  127. reference.Empty();
  128. footprint.Empty();
  129. while( cmpFileReader.ReadLine() )
  130. {
  131. buffer = FROM_UTF8( cmpFileReader.Line() );
  132. if( buffer.StartsWith( wxT( "EndCmp" ) ) )
  133. break;
  134. // store string value, stored between '=' and ';' delimiters.
  135. value = buffer.AfterFirst( '=' );
  136. value = value.BeforeLast( ';' );
  137. value.Trim(true);
  138. value.Trim(false);
  139. if( buffer.StartsWith( wxT( "Reference" ) ) )
  140. reference = value;
  141. else if( buffer.StartsWith( wxT( "IdModule" ) ) )
  142. footprint = value;
  143. }
  144. // A block is read: initialize the footprint field of the corresponding symbol
  145. // if the footprint name is not empty
  146. if( reference.IsEmpty() )
  147. continue;
  148. // Search the symbol in the flat list
  149. for( unsigned ii = 0; ii < referencesList.GetCount(); ii++ )
  150. {
  151. if( reference == referencesList[ii].GetRef() )
  152. {
  153. // We have found a candidate.
  154. // Note: it can be not unique (multiple units per part)
  155. // So we *do not* stop the search here
  156. SCH_SYMBOL* symbol = referencesList[ ii ].GetSymbol();
  157. SCH_SHEET_PATH* sheetPath = &referencesList[ii].GetSheetPath();
  158. symbol->SetFootprint( sheetPath, footprint );
  159. if( aForceVisibilityState )
  160. symbol->GetField( FOOTPRINT_FIELD )->SetVisible( aVisibilityState );
  161. }
  162. }
  163. }
  164. return true;
  165. }
  166. int SCH_EDITOR_CONTROL::ImportFPAssignments( const TOOL_EVENT& aEvent )
  167. {
  168. wxString path = wxPathOnly( m_frame->Prj().GetProjectFullName() );
  169. wxFileDialog dlg( m_frame, _( "Load Symbol Footprint Link File" ),
  170. path, wxEmptyString,
  171. FootprintAssignmentFileWildcard(),
  172. wxFD_OPEN | wxFD_FILE_MUST_EXIST );
  173. if( dlg.ShowModal() == wxID_CANCEL )
  174. return 0;
  175. wxString filename = dlg.GetPath();
  176. wxArrayString choices;
  177. choices.Add( _( "Keep existing footprint field visibility" ) );
  178. choices.Add( _( "Show all footprint fields" ) );
  179. choices.Add( _( "Hide all footprint fields" ) );
  180. wxSingleChoiceDialog choiceDlg( m_frame, _( "Select the footprint field visibility setting." ),
  181. _( "Change Visibility" ), choices );
  182. if( choiceDlg.ShowModal() == wxID_CANCEL )
  183. return 0;
  184. bool forceVisibility = (choiceDlg.GetSelection() != 0 );
  185. bool visibilityState = (choiceDlg.GetSelection() == 1 );
  186. if( !processCmpToFootprintLinkFile( filename, forceVisibility, visibilityState ) )
  187. {
  188. wxString msg = wxString::Format( _( "Failed to open symbol-footprint link file '%s'." ),
  189. filename.GetData() );
  190. DisplayError( m_frame, msg );
  191. return 0;
  192. }
  193. m_frame->SyncView();
  194. m_frame->GetCanvas()->Refresh();
  195. m_frame->OnModify();
  196. return 0;
  197. }