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.

317 lines
10 KiB

6 years ago
6 years ago
6 years ago
6 years ago
  1. /**
  2. * @file cvpcb/readwrite_dlgs.cpp
  3. */
  4. /*
  5. * This program source code file is part of KiCad, a free EDA CAD application.
  6. *
  7. * Copyright (C) 2018 Jean-Pierre Charras, jean-pierre.charras
  8. * Copyright (C) 2011-2016 Wayne Stambaugh <stambaughw@verizon.net>
  9. * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, you may find one here:
  23. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  24. * or you may search the http://www.gnu.org website for the version 2 license,
  25. * or you may write to the Free Software Foundation, Inc.,
  26. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  27. */
  28. #include <build_version.h>
  29. #include <common.h>
  30. #include <confirm.h>
  31. #include <fctsys.h>
  32. #include <fp_lib_table.h>
  33. #include <html_messagebox.h>
  34. #include <kiway.h>
  35. #include <lib_id.h>
  36. #include <macros.h>
  37. #include <cvpcb.h>
  38. #include <cvpcb_mainframe.h>
  39. #include <listboxes.h>
  40. #include <fp_conflict_assignment_selector.h>
  41. /// Return true if the resultant LIB_ID has a certain nickname. The guess
  42. /// is only made if this footprint resides in only one library.
  43. /// @return int - 0 on success, 1 on not found, 2 on ambiguous i.e. multiple matches
  44. static int guessNickname( FP_LIB_TABLE* aTbl, LIB_ID* aFootprintId )
  45. {
  46. if( aFootprintId->GetLibNickname().size() )
  47. return 0;
  48. wxString nick;
  49. wxString fpname = aFootprintId->GetLibItemName();
  50. std::vector<wxString> nicks = aTbl->GetLogicalLibs();
  51. // Search each library going through libraries alphabetically.
  52. for( unsigned libNdx = 0; libNdx<nicks.size(); ++libNdx )
  53. {
  54. wxArrayString fpnames;
  55. aTbl->FootprintEnumerate( fpnames, nicks[libNdx] );
  56. for( unsigned nameNdx = 0; nameNdx<fpnames.size(); ++nameNdx )
  57. {
  58. if( fpname == fpnames[nameNdx] )
  59. {
  60. if( !nick )
  61. nick = nicks[libNdx];
  62. else
  63. return 2; // duplicate, the guess would not be certain
  64. }
  65. }
  66. }
  67. if( nick.size() )
  68. {
  69. aFootprintId->SetLibNickname( nick );
  70. return 0;
  71. }
  72. return 1;
  73. }
  74. bool CVPCB_MAINFRAME::ReadNetListAndFpFiles( const std::string& aNetlist )
  75. {
  76. wxString msg;
  77. bool hasMissingNicks = false;
  78. ReadSchematicNetlist( aNetlist );
  79. if( m_compListBox == NULL )
  80. return false;
  81. LoadProjectFile();
  82. wxSafeYield();
  83. LoadFootprintFiles();
  84. BuildFOOTPRINTS_LISTBOX();
  85. BuildLIBRARY_LISTBOX();
  86. m_compListBox->Clear();
  87. if( m_netlist.AnyFootprintsLinked() )
  88. {
  89. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  90. {
  91. COMPONENT* component = m_netlist.GetComponent( i );
  92. if( component->GetFPID().empty() )
  93. continue;
  94. if( component->GetFPID().IsLegacy() )
  95. hasMissingNicks = true;
  96. }
  97. }
  98. // Check if footprint links were generated before the footprint library table was implemented.
  99. if( hasMissingNicks )
  100. {
  101. msg = _(
  102. "Some of the assigned footprints are legacy entries (are missing lib nicknames). "
  103. "Would you like CvPcb to attempt to convert them to the new required LIB_ID format? "
  104. "(If you answer no, then these assignments will be cleared out and you will "
  105. "have to re-assign these footprints yourself.)"
  106. );
  107. if( IsOK( this, msg ) )
  108. {
  109. msg.Clear();
  110. try
  111. {
  112. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  113. {
  114. COMPONENT* component = m_netlist.GetComponent( i );
  115. if( component->GetFPID().IsLegacy() )
  116. {
  117. // get this first here, it's possibly obsoleted if we get it too soon.
  118. FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs( Kiway() );
  119. int guess = guessNickname( tbl, (LIB_ID*) &component->GetFPID() );
  120. switch( guess )
  121. {
  122. case 0:
  123. DBG(printf("%s: guessed OK ref:%s fpid:%s\n", __func__,
  124. TO_UTF8( component->GetReference() ), component->GetFPID().Format().c_str() );)
  125. m_modified = true;
  126. break;
  127. case 1:
  128. msg += wxString::Format( _(
  129. "Component \"%s\" footprint \"%s\" was <b>not found</b> in any library.\n" ),
  130. GetChars( component->GetReference() ),
  131. GetChars( component->GetFPID().GetLibItemName() )
  132. );
  133. break;
  134. case 2:
  135. msg += wxString::Format( _(
  136. "Component \"%s\" footprint \"%s\" was found in <b>multiple</b> libraries.\n" ),
  137. GetChars( component->GetReference() ),
  138. GetChars( component->GetFPID().GetLibItemName() )
  139. );
  140. break;
  141. }
  142. }
  143. }
  144. }
  145. catch( const IO_ERROR& ioe )
  146. {
  147. msg = ioe.What();
  148. msg += wxT( "\n\n" );
  149. msg += _( "First check your footprint library table entries." );
  150. wxMessageBox( msg, _( "Problematic Footprint Library Tables" ) );
  151. return false;
  152. }
  153. if( msg.size() )
  154. {
  155. HTML_MESSAGE_BOX dlg( this, wxEmptyString );
  156. dlg.MessageSet( _( "The following errors occurred attempting to convert the "
  157. "footprint assignments:\n\n" ) );
  158. dlg.ListSet( msg );
  159. dlg.MessageSet( _( "\nYou will need to reassign them manually if you want them "
  160. "to be updated correctly the next time you import the "
  161. "netlist in Pcbnew." ) );
  162. #if 1
  163. dlg.ShowModal();
  164. #else
  165. dlg.Fit();
  166. dlg.Show( true ); // modeless lets user watch while fixing the problems, but its not working.
  167. #endif
  168. }
  169. }
  170. else
  171. {
  172. // Clear the legacy footprint assignments.
  173. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  174. {
  175. COMPONENT* component = m_netlist.GetComponent( i );
  176. if( component->GetFPID().IsLegacy() )
  177. {
  178. component->SetFPID( LIB_ID() /* empty */ );
  179. m_modified = true;
  180. }
  181. }
  182. }
  183. }
  184. // Display a dialog to select footprint selection, if the netlist
  185. // and the .cmp file give 2 different valid footprints
  186. std::vector <int > m_indexes; // indexes of footprints in netlist
  187. for( unsigned ii = 0; ii < m_netlist.GetCount(); ii++ )
  188. {
  189. COMPONENT* component = m_netlist.GetComponent( ii );
  190. if( component->GetAltFPID().empty() )
  191. continue;
  192. if( component->GetFPID().IsLegacy() || component->GetAltFPID().IsLegacy())
  193. continue;
  194. m_indexes.push_back( ii );
  195. }
  196. // If a n assignment conflict is found,
  197. // open a dialog to chose between schematic assignment
  198. // and .cmp file assignment:
  199. if( m_indexes.size() > 0 )
  200. {
  201. DIALOG_FP_CONFLICT_ASSIGNMENT_SELECTOR dlg( this );
  202. for( unsigned ii = 0; ii < m_indexes.size(); ii++ )
  203. {
  204. COMPONENT* component = m_netlist.GetComponent( m_indexes[ii] );
  205. wxString cmpfpid = component->GetFPID().Format();
  206. wxString schfpid = component->GetAltFPID().Format();
  207. dlg.Add( component->GetReference(), schfpid, cmpfpid );
  208. }
  209. if( dlg.ShowModal() == wxID_OK )
  210. {
  211. // Update the fp selection:
  212. for( unsigned ii = 0; ii < m_indexes.size(); ii++ )
  213. {
  214. COMPONENT* component = m_netlist.GetComponent( m_indexes[ii] );
  215. int choice = dlg.GetSelection( component->GetReference() );
  216. if( choice == 0 ) // the schematic (alt fpid) is chosen:
  217. component->SetFPID( component->GetAltFPID() );
  218. }
  219. }
  220. }
  221. // Populates the component list box:
  222. for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
  223. {
  224. COMPONENT* component = m_netlist.GetComponent( i );
  225. msg.Printf( CMP_FORMAT, m_compListBox->GetCount() + 1,
  226. GetChars( component->GetReference() ),
  227. GetChars( component->GetValue() ),
  228. GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
  229. m_compListBox->AppendLine( msg );
  230. }
  231. if( !m_netlist.IsEmpty() )
  232. m_compListBox->SetSelection( 0, true );
  233. DisplayStatus();
  234. return true;
  235. }
  236. bool CVPCB_MAINFRAME::SaveFootprintAssociation( bool doSaveSchematic )
  237. {
  238. std::string payload;
  239. STRING_FORMATTER sf;
  240. m_netlist.FormatBackAnnotation( &sf );
  241. payload = sf.GetString();
  242. Kiway().ExpressMail( FRAME_SCH, MAIL_BACKANNOTATE_FOOTPRINTS, payload );
  243. if( doSaveSchematic )
  244. {
  245. payload = "";
  246. Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_SAVE, payload );
  247. if( payload == "success" )
  248. SetStatusText( _( "Schematic saved" ), 1 );
  249. }
  250. // Changes are saved, so reset the flag
  251. m_modified = false;
  252. return true;
  253. }