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.

376 lines
12 KiB

9 years ago
9 years ago
9 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 CERN
  5. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <class_board.h>
  25. #include <class_module.h>
  26. #include <wxPcbStruct.h>
  27. #include <tool/tool_manager.h>
  28. #include <ratsnest_data.h>
  29. #include <view/view.h>
  30. #include <board_commit.h>
  31. #include <tools/pcb_tool.h>
  32. #include <functional>
  33. using namespace std::placeholders;
  34. BOARD_COMMIT::BOARD_COMMIT( PCB_TOOL* aTool )
  35. {
  36. m_toolMgr = aTool->GetManager();
  37. m_editModules = aTool->EditingModules();
  38. }
  39. BOARD_COMMIT::BOARD_COMMIT( PCB_BASE_FRAME* aFrame )
  40. {
  41. m_toolMgr = aFrame->GetToolManager();
  42. m_editModules = aFrame->IsType( FRAME_PCB_MODULE_EDITOR );
  43. }
  44. BOARD_COMMIT::~BOARD_COMMIT()
  45. {
  46. }
  47. void BOARD_COMMIT::Push( const wxString& aMessage )
  48. {
  49. // Objects potentially interested in changes:
  50. PICKED_ITEMS_LIST undoList;
  51. KIGFX::VIEW* view = m_toolMgr->GetView();
  52. BOARD* board = (BOARD*) m_toolMgr->GetModel();
  53. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame();
  54. RN_DATA* ratsnest = board->GetRatsnest();
  55. std::set<EDA_ITEM*> savedModules;
  56. if( Empty() )
  57. return;
  58. for( COMMIT_LINE& ent : m_changes )
  59. {
  60. int changeType = ent.m_type & CHT_TYPE;
  61. int changeFlags = ent.m_type & CHT_FLAGS;
  62. BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
  63. // Module items need to be saved in the undo buffer before modification
  64. if( m_editModules )
  65. {
  66. // Be sure that we are storing a module
  67. if( ent.m_item->Type() != PCB_MODULE_T )
  68. ent.m_item = ent.m_item->GetParent();
  69. // We have not saved the module yet, so let's create an entry
  70. if( savedModules.count( ent.m_item ) == 0 )
  71. {
  72. if( !ent.m_copy )
  73. {
  74. assert( changeType != CHT_MODIFY ); // too late to make a copy..
  75. ent.m_copy = ent.m_item->Clone();
  76. }
  77. assert( ent.m_item->Type() == PCB_MODULE_T );
  78. assert( ent.m_copy->Type() == PCB_MODULE_T );
  79. ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED );
  80. itemWrapper.SetLink( ent.m_copy );
  81. undoList.PushItem( itemWrapper );
  82. frame->SaveCopyInUndoList( undoList, UR_CHANGED );
  83. savedModules.insert( ent.m_item );
  84. static_cast<MODULE*>( ent.m_item )->SetLastEditTime();
  85. }
  86. }
  87. switch( changeType )
  88. {
  89. case CHT_ADD:
  90. {
  91. if( !m_editModules )
  92. {
  93. undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) );
  94. if( !( changeFlags & CHT_DONE ) )
  95. board->Add( boardItem );
  96. //ratsnest->Add( boardItem ); // TODO currently done by BOARD::Add()
  97. if( boardItem->Type() == PCB_MODULE_T )
  98. {
  99. MODULE* mod = static_cast<MODULE*>( boardItem );
  100. mod->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) );
  101. }
  102. }
  103. else
  104. {
  105. // modules inside modules are not supported yet
  106. assert( boardItem->Type() != PCB_MODULE_T );
  107. if( !( changeFlags & CHT_DONE ) )
  108. board->m_Modules->Add( boardItem );
  109. }
  110. view->Add( boardItem );
  111. break;
  112. }
  113. case CHT_REMOVE:
  114. {
  115. if( !m_editModules )
  116. {
  117. undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) );
  118. }
  119. switch( boardItem->Type() )
  120. {
  121. // Module items
  122. case PCB_PAD_T:
  123. case PCB_MODULE_EDGE_T:
  124. case PCB_MODULE_TEXT_T:
  125. {
  126. // Do not allow footprint text removal when not editing a module
  127. if( !m_editModules )
  128. break;
  129. bool remove = true;
  130. if( boardItem->Type() == PCB_MODULE_TEXT_T )
  131. {
  132. TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem );
  133. switch( text->GetType() )
  134. {
  135. case TEXTE_MODULE::TEXT_is_REFERENCE:
  136. //DisplayError( frame, _( "Cannot delete component reference." ) );
  137. remove = false;
  138. break;
  139. case TEXTE_MODULE::TEXT_is_VALUE:
  140. //DisplayError( frame, _( "Cannot delete component value." ) );
  141. remove = false;
  142. break;
  143. case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings
  144. break;
  145. default:
  146. assert( false );
  147. break;
  148. }
  149. }
  150. if( remove )
  151. {
  152. view->Remove( boardItem );
  153. if( !( changeFlags & CHT_DONE ) )
  154. {
  155. MODULE* module = static_cast<MODULE*>( boardItem->GetParent() );
  156. assert( module && module->Type() == PCB_MODULE_T );
  157. module->Delete( boardItem );
  158. }
  159. board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?)
  160. }
  161. break;
  162. }
  163. // Board items
  164. case PCB_LINE_T: // a segment not on copper layers
  165. case PCB_TEXT_T: // a text on a layer
  166. case PCB_TRACE_T: // a track segment (segment on a copper layer)
  167. case PCB_VIA_T: // a via (like track segment on a copper layer)
  168. case PCB_DIMENSION_T: // a dimension (graphic item)
  169. case PCB_TARGET_T: // a target (graphic item)
  170. case PCB_MARKER_T: // a marker used to show something
  171. case PCB_ZONE_T: // SEG_ZONE items are now deprecated
  172. case PCB_ZONE_AREA_T:
  173. view->Remove( boardItem );
  174. if( !( changeFlags & CHT_DONE ) )
  175. board->Remove( boardItem );
  176. //ratsnest->Remove( boardItem ); // currently done by BOARD::Remove()
  177. break;
  178. case PCB_MODULE_T:
  179. {
  180. // There are no modules inside a module yet
  181. assert( !m_editModules );
  182. MODULE* module = static_cast<MODULE*>( boardItem );
  183. module->ClearFlags();
  184. module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  185. view->Remove( module );
  186. if( !( changeFlags & CHT_DONE ) )
  187. board->Remove( module );
  188. // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore
  189. board->m_Status_Pcb = 0;
  190. }
  191. break;
  192. default: // other types do not need to (or should not) be handled
  193. assert( false );
  194. break;
  195. }
  196. break;
  197. }
  198. case CHT_MODIFY:
  199. {
  200. if( !m_editModules )
  201. {
  202. ITEM_PICKER itemWrapper( boardItem, UR_CHANGED );
  203. assert( ent.m_copy );
  204. itemWrapper.SetLink( ent.m_copy );
  205. undoList.PushItem( itemWrapper );
  206. }
  207. if( boardItem->Type() == PCB_MODULE_T )
  208. {
  209. MODULE* module = static_cast<MODULE*>( boardItem );
  210. module->RunOnChildren( [&view] ( BOARD_ITEM* aItem ) { view->Update( aItem ); } );
  211. }
  212. view->Update ( boardItem );
  213. ratsnest->Update( boardItem );
  214. break;
  215. }
  216. default:
  217. assert( false );
  218. break;
  219. }
  220. }
  221. if( !m_editModules )
  222. frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED );
  223. if( TOOL_MANAGER* toolMgr = frame->GetToolManager() )
  224. toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );
  225. ratsnest->Recalculate();
  226. frame->OnModify();
  227. frame->UpdateMsgPanel();
  228. clear();
  229. }
  230. EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const
  231. {
  232. switch( aItem->Type() )
  233. {
  234. case PCB_PAD_T:
  235. case PCB_MODULE_EDGE_T:
  236. case PCB_MODULE_TEXT_T:
  237. return aItem->GetParent();
  238. default:
  239. return aItem;
  240. }
  241. return aItem;
  242. }
  243. void BOARD_COMMIT::Revert()
  244. {
  245. PICKED_ITEMS_LIST undoList;
  246. KIGFX::VIEW* view = m_toolMgr->GetView();
  247. BOARD* board = (BOARD*) m_toolMgr->GetModel();
  248. RN_DATA* ratsnest = board->GetRatsnest();
  249. for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it )
  250. {
  251. COMMIT_LINE& ent = *it;
  252. BOARD_ITEM* item = static_cast<BOARD_ITEM*>( ent.m_item );
  253. BOARD_ITEM* copy = static_cast<BOARD_ITEM*>( ent.m_copy );
  254. switch( ent.m_type )
  255. {
  256. case CHT_ADD:
  257. if( item->Type() == PCB_MODULE_T )
  258. {
  259. MODULE* oldModule = static_cast<MODULE*>( item );
  260. oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  261. }
  262. view->Remove( item );
  263. ratsnest->Remove( item );
  264. break;
  265. case CHT_REMOVE:
  266. if( item->Type() == PCB_MODULE_T )
  267. {
  268. MODULE* newModule = static_cast<MODULE*>( item );
  269. newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) );
  270. newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) );
  271. }
  272. view->Add( item );
  273. ratsnest->Add( item );
  274. break;
  275. case CHT_MODIFY:
  276. {
  277. if( item->Type() == PCB_MODULE_T )
  278. {
  279. MODULE* oldModule = static_cast<MODULE*>( item );
  280. oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  281. }
  282. view->Remove( item );
  283. ratsnest->Remove( item );
  284. item->SwapData( copy );
  285. item->ClearFlags( SELECTED );
  286. // Update all pads/drawings/texts, as they become invalid
  287. // for the VIEW after SwapData() called for modules
  288. if( item->Type() == PCB_MODULE_T )
  289. {
  290. MODULE* newModule = static_cast<MODULE*>( item );
  291. newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) );
  292. newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) );
  293. }
  294. view->Add( item );
  295. ratsnest->Add( item );
  296. delete copy;
  297. break;
  298. }
  299. default:
  300. assert( false );
  301. break;
  302. }
  303. }
  304. ratsnest->Recalculate();
  305. clear();
  306. }