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.

303 lines
9.7 KiB

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