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.

251 lines
8.3 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 2013-2016 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2022 KiCad Developers, see change_log.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <functional>
  27. using namespace std::placeholders;
  28. #include <confirm.h>
  29. #include <kiway.h>
  30. #include <pcb_edit_frame.h>
  31. #include <netlist_reader/pcb_netlist.h>
  32. #include <netlist_reader/netlist_reader.h>
  33. #include <reporter.h>
  34. #include <lib_id.h>
  35. #include <fp_lib_table.h>
  36. #include <board.h>
  37. #include <footprint.h>
  38. #include <spread_footprints.h>
  39. #include <ratsnest/ratsnest_data.h>
  40. #include <io_mgr.h>
  41. #include "board_netlist_updater.h"
  42. #include <tool/tool_manager.h>
  43. #include <tools/pcb_actions.h>
  44. #include <tools/pcb_selection_tool.h>
  45. #include <project/project_file.h> // LAST_PATH_TYPE
  46. bool PCB_EDIT_FRAME::ReadNetlistFromFile( const wxString &aFilename, NETLIST& aNetlist,
  47. REPORTER& aReporter )
  48. {
  49. wxString msg;
  50. try
  51. {
  52. std::unique_ptr<NETLIST_READER> netlistReader( NETLIST_READER::GetNetlistReader(
  53. &aNetlist, aFilename, wxEmptyString ) );
  54. if( !netlistReader.get() )
  55. {
  56. msg.Printf( _( "Cannot open netlist file '%s'." ), aFilename );
  57. DisplayErrorMessage( this, msg );
  58. return false;
  59. }
  60. SetLastPath( LAST_PATH_NETLIST, aFilename );
  61. netlistReader->LoadNetlist();
  62. LoadFootprints( aNetlist, aReporter );
  63. }
  64. catch( const IO_ERROR& ioe )
  65. {
  66. msg.Printf( _( "Error loading netlist.\n%s" ), ioe.What().GetData() );
  67. DisplayErrorMessage( this, msg );
  68. return false;
  69. }
  70. SetLastPath( LAST_PATH_NETLIST, aFilename );
  71. return true;
  72. }
  73. void PCB_EDIT_FRAME::OnNetlistChanged( BOARD_NETLIST_UPDATER& aUpdater, bool* aRunDragCommand )
  74. {
  75. BOARD* board = GetBoard();
  76. SetMsgPanel( board );
  77. // Update rendered track/via/pad net labels, and any text items that might reference a
  78. // netName or netClass
  79. int netNamesCfg = GetPcbNewSettings()->m_Display.m_NetNames;
  80. GetCanvas()->GetView()->UpdateAllItemsConditionally(
  81. [&]( KIGFX::VIEW_ITEM* aItem ) -> int
  82. {
  83. if( dynamic_cast<PCB_TRACK*>( aItem ) )
  84. {
  85. if( netNamesCfg == 2 || netNamesCfg == 3 )
  86. return KIGFX::REPAINT;
  87. }
  88. else if( dynamic_cast<PAD*>( aItem ) )
  89. {
  90. if( netNamesCfg == 1 || netNamesCfg == 3 )
  91. return KIGFX::REPAINT;
  92. }
  93. EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
  94. if( text && text->HasTextVars() )
  95. {
  96. text->ClearRenderCache();
  97. text->ClearBoundingBoxCache();
  98. return KIGFX::GEOMETRY | KIGFX::REPAINT;
  99. }
  100. return 0;
  101. } );
  102. // Spread new footprints.
  103. std::vector<FOOTPRINT*> newFootprints = aUpdater.GetAddedFootprints();
  104. GetToolManager()->RunAction( PCB_ACTIONS::selectionClear );
  105. SpreadFootprints( &newFootprints, { 0, 0 }, true );
  106. // Start drag command for new footprints
  107. if( !newFootprints.empty() )
  108. {
  109. for( FOOTPRINT* footprint : newFootprints )
  110. GetToolManager()->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, footprint );
  111. *aRunDragCommand = true;
  112. }
  113. Compile_Ratsnest( true );
  114. GetCanvas()->Refresh();
  115. }
  116. void PCB_EDIT_FRAME::LoadFootprints( NETLIST& aNetlist, REPORTER& aReporter )
  117. {
  118. wxString msg;
  119. LIB_ID lastFPID;
  120. COMPONENT* component;
  121. FOOTPRINT* footprint = nullptr;
  122. FOOTPRINT* fpOnBoard = nullptr;
  123. if( aNetlist.IsEmpty() || Prj().PcbFootprintLibs()->IsEmpty() )
  124. return;
  125. aNetlist.SortByFPID();
  126. for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
  127. {
  128. component = aNetlist.GetComponent( ii );
  129. // The FPID is ok as long as there is a footprint portion coming from eeschema.
  130. if( !component->GetFPID().GetLibItemName().size() )
  131. {
  132. msg.Printf( _( "No footprint defined for symbol %s." ),
  133. component->GetReference() );
  134. aReporter.Report( msg, RPT_SEVERITY_ERROR );
  135. continue;
  136. }
  137. // Check if component footprint is already on BOARD and only load the footprint from
  138. // the library if it's needed. Nickname can be blank.
  139. if( aNetlist.IsFindByTimeStamp() )
  140. {
  141. for( const KIID& uuid : component->GetKIIDs() )
  142. {
  143. KIID_PATH path = component->GetPath();
  144. path.push_back( uuid );
  145. if( ( fpOnBoard = m_pcb->FindFootprintByPath( path ) ) != nullptr )
  146. break;
  147. }
  148. }
  149. else
  150. fpOnBoard = m_pcb->FindFootprintByReference( component->GetReference() );
  151. bool footprintMisMatch = fpOnBoard && fpOnBoard->GetFPID() != component->GetFPID();
  152. if( footprintMisMatch && !aNetlist.GetReplaceFootprints() )
  153. {
  154. msg.Printf( _( "Footprint of %s changed: board footprint '%s', netlist footprint '%s'." ),
  155. component->GetReference(),
  156. fpOnBoard->GetFPID().Format().wx_str(),
  157. component->GetFPID().Format().wx_str() );
  158. aReporter.Report( msg, RPT_SEVERITY_WARNING );
  159. continue;
  160. }
  161. if( !aNetlist.GetReplaceFootprints() )
  162. footprintMisMatch = false;
  163. if( fpOnBoard && !footprintMisMatch ) // nothing else to do here
  164. continue;
  165. if( component->GetFPID() != lastFPID )
  166. {
  167. footprint = nullptr;
  168. // The LIB_ID is ok as long as there is a footprint portion coming the library if
  169. // it's needed. Nickname can be blank.
  170. if( !component->GetFPID().GetLibItemName().size() )
  171. {
  172. msg.Printf( _( "%s footprint ID '%s' is not valid." ),
  173. component->GetReference(),
  174. component->GetFPID().Format().wx_str() );
  175. aReporter.Report( msg, RPT_SEVERITY_ERROR );
  176. continue;
  177. }
  178. // loadFootprint() can find a footprint with an empty nickname in fpid.
  179. footprint = PCB_BASE_FRAME::loadFootprint( component->GetFPID() );
  180. if( footprint )
  181. {
  182. lastFPID = component->GetFPID();
  183. }
  184. else
  185. {
  186. msg.Printf( _( "%s footprint '%s' not found in any libraries in the footprint "
  187. "library table." ),
  188. component->GetReference(),
  189. component->GetFPID().GetLibItemName().wx_str() );
  190. aReporter.Report( msg, RPT_SEVERITY_ERROR );
  191. continue;
  192. }
  193. }
  194. else
  195. {
  196. // Footprint already loaded from a library, duplicate it (faster)
  197. if( !footprint )
  198. continue; // Footprint does not exist in any library.
  199. footprint = new FOOTPRINT( *footprint );
  200. const_cast<KIID&>( footprint->m_Uuid ) = KIID();
  201. }
  202. if( footprint )
  203. component->SetFootprint( footprint );
  204. }
  205. }