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.

314 lines
10 KiB

6 years ago
3 years ago
3 years ago
6 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 Jean-Pierre Charras, jean-pierre.charras
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 1992-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 <fp_lib_table.h>
  27. #include <dialogs/html_message_box.h>
  28. #include <kiway.h>
  29. #include <lib_id.h>
  30. #include <macros.h>
  31. #include <cvpcb_mainframe.h>
  32. #include <fp_conflict_assignment_selector.h>
  33. /**
  34. * Return true if the resultant LIB_ID has a certain nickname.
  35. *
  36. * The guess is only made if this footprint resides in only one library.
  37. *
  38. * @return int - 0 on success, 1 on not found, 2 on ambiguous i.e. multiple matches.
  39. */
  40. static int guessNickname( FP_LIB_TABLE* aTbl, LIB_ID* aFootprintId )
  41. {
  42. if( aFootprintId->GetLibNickname().size() )
  43. return 0;
  44. wxString nick;
  45. wxString fpname = aFootprintId->GetLibItemName();
  46. std::vector<wxString> nicks = aTbl->GetLogicalLibs();
  47. // Search each library going through libraries alphabetically.
  48. for( unsigned libNdx = 0; libNdx<nicks.size(); ++libNdx )
  49. {
  50. wxArrayString fpnames;
  51. aTbl->FootprintEnumerate( fpnames, nicks[libNdx], true );
  52. for( unsigned nameNdx = 0; nameNdx<fpnames.size(); ++nameNdx )
  53. {
  54. if( fpname == fpnames[nameNdx] )
  55. {
  56. if( !nick )
  57. nick = nicks[libNdx];
  58. else
  59. return 2; // duplicate, the guess would not be certain
  60. }
  61. }
  62. }
  63. if( nick.size() )
  64. {
  65. aFootprintId->SetLibNickname( nick );
  66. return 0;
  67. }
  68. return 1;
  69. }
  70. bool CVPCB_MAINFRAME::readNetListAndFpFiles( const std::string& aNetlist )
  71. {
  72. wxString msg;
  73. bool hasMissingNicks = false;
  74. readSchematicNetlist( aNetlist );
  75. if( m_symbolsListBox == nullptr )
  76. return false;
  77. wxSafeYield();
  78. LoadFootprintFiles();
  79. BuildFootprintsListBox();
  80. BuildLibrariesListBox();
  81. m_symbolsListBox->Clear();
  82. if( m_netlist.AnyFootprintsLinked() )
  83. {
  84. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  85. {
  86. COMPONENT* component = m_netlist.GetComponent( i );
  87. if( component->GetFPID().empty() )
  88. continue;
  89. if( component->GetFPID().IsLegacy() )
  90. hasMissingNicks = true;
  91. }
  92. }
  93. // Check if footprint links were generated before the footprint library table was implemented.
  94. if( hasMissingNicks )
  95. {
  96. msg = _( "Some of the assigned footprints are legacy entries with no library names. Would "
  97. "you like KiCad to attempt to convert them to the new required LIB_ID format? "
  98. "(If you answer no, then these assignments will be cleared and you will need to "
  99. "re-assign them manually.)" );
  100. if( IsOK( this, msg ) )
  101. {
  102. msg.Clear();
  103. try
  104. {
  105. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  106. {
  107. COMPONENT* component = m_netlist.GetComponent( i );
  108. if( component->GetFPID().IsLegacy() )
  109. {
  110. // get this first here, it's possibly obsoleted if we get it too soon.
  111. FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
  112. int guess = guessNickname( tbl, (LIB_ID*) &component->GetFPID() );
  113. switch( guess )
  114. {
  115. case 0:
  116. m_modified = true;
  117. break;
  118. case 1:
  119. msg += wxString::Format( _( "Component '%s' footprint '%s' <b>not "
  120. "found</b> in any library.\n" ),
  121. component->GetReference(),
  122. component->GetFPID().GetLibItemName().wx_str() );
  123. break;
  124. case 2:
  125. msg += wxString::Format( _( "Component '%s' footprint '%s' was found "
  126. "in <b>multiple</b> libraries.\n" ),
  127. component->GetReference(),
  128. component->GetFPID().GetLibItemName().wx_str() );
  129. break;
  130. }
  131. }
  132. }
  133. }
  134. catch( const IO_ERROR& ioe )
  135. {
  136. msg = ioe.What();
  137. msg += wxT( "\n\n" );
  138. msg += _( "First check your footprint library table entries." );
  139. wxMessageBox( msg, _( "Problematic Footprint Library Tables" ) );
  140. return false;
  141. }
  142. if( msg.size() )
  143. {
  144. HTML_MESSAGE_BOX dlg( this, wxEmptyString );
  145. dlg.MessageSet( _( "The following errors occurred attempting to convert the "
  146. "footprint assignments:\n\n" ) );
  147. dlg.ListSet( msg );
  148. dlg.MessageSet( _( "\nYou will need to reassign them manually if you want them "
  149. "to be updated correctly the next time you import the "
  150. "netlist in Pcbnew." ) );
  151. #if 1
  152. dlg.ShowModal();
  153. #else
  154. dlg.Fit();
  155. // Modeless lets user watch while fixing the problems, but its not working.
  156. dlg.Show( true );
  157. #endif
  158. }
  159. }
  160. else
  161. {
  162. // Clear the legacy footprint assignments.
  163. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  164. {
  165. COMPONENT* component = m_netlist.GetComponent( i );
  166. if( component->GetFPID().IsLegacy() )
  167. {
  168. component->SetFPID( LIB_ID() );
  169. m_modified = true;
  170. }
  171. }
  172. }
  173. }
  174. // Display a dialog to select footprint selection, if the netlist
  175. // and the .cmp file give 2 different valid footprints
  176. std::vector <int > m_indexes; // indexes of footprints in netlist
  177. for( unsigned ii = 0; ii < m_netlist.GetCount(); ii++ )
  178. {
  179. COMPONENT* component = m_netlist.GetComponent( ii );
  180. if( component->GetAltFPID().empty() )
  181. continue;
  182. if( component->GetFPID().IsLegacy() || component->GetAltFPID().IsLegacy() )
  183. continue;
  184. m_indexes.push_back( ii );
  185. }
  186. // If a n assignment conflict is found,
  187. // open a dialog to chose between schematic assignment
  188. // and .cmp file assignment:
  189. if( m_indexes.size() > 0 )
  190. {
  191. DIALOG_FP_CONFLICT_ASSIGNMENT_SELECTOR dlg( this );
  192. for( unsigned ii = 0; ii < m_indexes.size(); ii++ )
  193. {
  194. COMPONENT* component = m_netlist.GetComponent( m_indexes[ii] );
  195. wxString cmpfpid = component->GetFPID().Format();
  196. wxString schfpid = component->GetAltFPID().Format();
  197. dlg.Add( component->GetReference(), schfpid, cmpfpid );
  198. }
  199. if( dlg.ShowModal() == wxID_OK )
  200. {
  201. // Update the fp selection:
  202. for( unsigned ii = 0; ii < m_indexes.size(); ii++ )
  203. {
  204. COMPONENT* component = m_netlist.GetComponent( m_indexes[ii] );
  205. int choice = dlg.GetSelection( component->GetReference() );
  206. if( choice == 0 ) // the schematic (alt fpid) is chosen:
  207. component->SetFPID( component->GetAltFPID() );
  208. }
  209. }
  210. }
  211. // Populates the component list box:
  212. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  213. {
  214. COMPONENT* component = m_netlist.GetComponent( i );
  215. msg = formatSymbolDesc( m_symbolsListBox->GetCount() + 1,
  216. component->GetReference(),
  217. component->GetValue(),
  218. FROM_UTF8( component->GetFPID().Format().c_str() ) );
  219. m_symbolsListBox->AppendLine( msg );
  220. FOOTPRINT_INFO* fp =
  221. m_FootprintsList->GetFootprintInfo( component->GetFPID().Format().wx_str() );
  222. if( !fp )
  223. {
  224. m_symbolsListBox->AppendWarning( i );
  225. }
  226. }
  227. if( !m_netlist.IsEmpty() )
  228. m_symbolsListBox->SetSelection( 0, true );
  229. DisplayStatus();
  230. return true;
  231. }
  232. bool CVPCB_MAINFRAME::SaveFootprintAssociation( bool doSaveSchematic )
  233. {
  234. std::string payload;
  235. STRING_FORMATTER sf;
  236. m_netlist.FormatCvpcbNetlist( &sf );
  237. payload = sf.GetString();
  238. Kiway().ExpressMail( FRAME_SCH, MAIL_ASSIGN_FOOTPRINTS, payload );
  239. if( doSaveSchematic )
  240. {
  241. payload = "";
  242. Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_SAVE, payload );
  243. if( payload == "success" )
  244. SetStatusText( _( "Schematic saved" ), 1 );
  245. }
  246. // Changes are saved, so reset the flag
  247. m_modified = false;
  248. return true;
  249. }