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.

393 lines
13 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 <connectivity.h>
  33. #include <functional>
  34. using namespace std::placeholders;
  35. #include "pcb_draw_panel_gal.h"
  36. BOARD_COMMIT::BOARD_COMMIT( PCB_TOOL* aTool )
  37. {
  38. m_toolMgr = aTool->GetManager();
  39. m_editModules = aTool->EditingModules();
  40. }
  41. BOARD_COMMIT::BOARD_COMMIT( PCB_BASE_FRAME* aFrame )
  42. {
  43. m_toolMgr = aFrame->GetToolManager();
  44. m_editModules = aFrame->IsType( FRAME_PCB_MODULE_EDITOR );
  45. }
  46. BOARD_COMMIT::~BOARD_COMMIT()
  47. {
  48. }
  49. void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry )
  50. {
  51. // Objects potentially interested in changes:
  52. PICKED_ITEMS_LIST undoList;
  53. KIGFX::VIEW* view = m_toolMgr->GetView();
  54. BOARD* board = (BOARD*) m_toolMgr->GetModel();
  55. PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame();
  56. auto connectivity = board->GetConnectivity();
  57. std::set<EDA_ITEM*> savedModules;
  58. if( Empty() )
  59. return;
  60. for( COMMIT_LINE& ent : m_changes )
  61. {
  62. int changeType = ent.m_type & CHT_TYPE;
  63. int changeFlags = ent.m_type & CHT_FLAGS;
  64. BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
  65. // Module items need to be saved in the undo buffer before modification
  66. if( m_editModules )
  67. {
  68. // Be sure that we are storing a module
  69. if( ent.m_item->Type() != PCB_MODULE_T )
  70. ent.m_item = ent.m_item->GetParent();
  71. // We have not saved the module yet, so let's create an entry
  72. if( savedModules.count( ent.m_item ) == 0 )
  73. {
  74. if( !ent.m_copy )
  75. {
  76. assert( changeType != CHT_MODIFY ); // too late to make a copy..
  77. ent.m_copy = ent.m_item->Clone();
  78. }
  79. assert( ent.m_item->Type() == PCB_MODULE_T );
  80. assert( ent.m_copy->Type() == PCB_MODULE_T );
  81. if( aCreateUndoEntry )
  82. {
  83. ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED );
  84. itemWrapper.SetLink( ent.m_copy );
  85. undoList.PushItem( itemWrapper );
  86. frame->SaveCopyInUndoList( undoList, UR_CHANGED );
  87. }
  88. savedModules.insert( ent.m_item );
  89. static_cast<MODULE*>( ent.m_item )->SetLastEditTime();
  90. }
  91. }
  92. switch( changeType )
  93. {
  94. case CHT_ADD:
  95. {
  96. if( !m_editModules )
  97. {
  98. if( aCreateUndoEntry )
  99. {
  100. undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) );
  101. }
  102. if( !( changeFlags & CHT_DONE ) )
  103. board->Add( boardItem );
  104. //ratsnest->Add( boardItem ); // TODO currently done by BOARD::Add()
  105. if( boardItem->Type() == PCB_MODULE_T )
  106. {
  107. MODULE* mod = static_cast<MODULE*>( boardItem );
  108. mod->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1, -1 ) );
  109. }
  110. }
  111. else
  112. {
  113. // modules inside modules are not supported yet
  114. assert( boardItem->Type() != PCB_MODULE_T );
  115. boardItem->SetParent( board->m_Modules.GetFirst() );
  116. if( !( changeFlags & CHT_DONE ) )
  117. board->m_Modules->Add( boardItem );
  118. }
  119. view->Add( boardItem );
  120. break;
  121. }
  122. case CHT_REMOVE:
  123. {
  124. if( !m_editModules && aCreateUndoEntry )
  125. {
  126. undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) );
  127. }
  128. switch( boardItem->Type() )
  129. {
  130. // Module items
  131. case PCB_PAD_T:
  132. case PCB_MODULE_EDGE_T:
  133. case PCB_MODULE_TEXT_T:
  134. {
  135. // Do not allow footprint text removal when not editing a module
  136. if( !m_editModules )
  137. break;
  138. bool remove = true;
  139. if( boardItem->Type() == PCB_MODULE_TEXT_T )
  140. {
  141. TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem );
  142. switch( text->GetType() )
  143. {
  144. case TEXTE_MODULE::TEXT_is_REFERENCE:
  145. //DisplayError( frame, _( "Cannot delete component reference." ) );
  146. remove = false;
  147. break;
  148. case TEXTE_MODULE::TEXT_is_VALUE:
  149. //DisplayError( frame, _( "Cannot delete component value." ) );
  150. remove = false;
  151. break;
  152. case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings
  153. break;
  154. default:
  155. assert( false );
  156. break;
  157. }
  158. }
  159. if( remove )
  160. {
  161. view->Remove( boardItem );
  162. if( !( changeFlags & CHT_DONE ) )
  163. {
  164. MODULE* module = static_cast<MODULE*>( boardItem->GetParent() );
  165. assert( module && module->Type() == PCB_MODULE_T );
  166. module->Delete( boardItem );
  167. }
  168. board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?)
  169. }
  170. break;
  171. }
  172. // Board items
  173. case PCB_LINE_T: // a segment not on copper layers
  174. case PCB_TEXT_T: // a text on a layer
  175. case PCB_TRACE_T: // a track segment (segment on a copper layer)
  176. case PCB_VIA_T: // a via (like track segment on a copper layer)
  177. case PCB_DIMENSION_T: // a dimension (graphic item)
  178. case PCB_TARGET_T: // a target (graphic item)
  179. case PCB_MARKER_T: // a marker used to show something
  180. case PCB_ZONE_T: // SEG_ZONE items are now deprecated
  181. case PCB_ZONE_AREA_T:
  182. view->Remove( boardItem );
  183. if( !( changeFlags & CHT_DONE ) )
  184. board->Remove( boardItem );
  185. break;
  186. case PCB_MODULE_T:
  187. {
  188. // There are no modules inside a module yet
  189. assert( !m_editModules );
  190. MODULE* module = static_cast<MODULE*>( boardItem );
  191. module->ClearFlags();
  192. module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  193. view->Remove( module );
  194. if( !( changeFlags & CHT_DONE ) )
  195. board->Remove( module );
  196. // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore
  197. board->m_Status_Pcb = 0;
  198. }
  199. break;
  200. default: // other types do not need to (or should not) be handled
  201. assert( false );
  202. break;
  203. }
  204. break;
  205. }
  206. case CHT_MODIFY:
  207. {
  208. if( !m_editModules && aCreateUndoEntry )
  209. {
  210. ITEM_PICKER itemWrapper( boardItem, UR_CHANGED );
  211. assert( ent.m_copy );
  212. itemWrapper.SetLink( ent.m_copy );
  213. undoList.PushItem( itemWrapper );
  214. }
  215. if( boardItem->Type() == PCB_MODULE_T )
  216. {
  217. MODULE* module = static_cast<MODULE*>( boardItem );
  218. module->RunOnChildren( [&view] ( BOARD_ITEM* aItem ) { view->Update( aItem ); } );
  219. }
  220. view->Update ( boardItem );
  221. connectivity->MarkItemNetAsDirty( static_cast<BOARD_ITEM*>( ent.m_copy ) );
  222. connectivity->Update( boardItem );
  223. break;
  224. }
  225. default:
  226. assert( false );
  227. break;
  228. }
  229. }
  230. if( !m_editModules && aCreateUndoEntry )
  231. frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED );
  232. if( TOOL_MANAGER* toolMgr = frame->GetToolManager() )
  233. toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );
  234. if ( !m_editModules )
  235. {
  236. auto panel = static_cast<PCB_DRAW_PANEL_GAL*>( frame->GetGalCanvas() );
  237. connectivity->RecalculateRatsnest();
  238. panel->RedrawRatsnest();
  239. }
  240. frame->OnModify();
  241. frame->UpdateMsgPanel();
  242. clear();
  243. }
  244. EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const
  245. {
  246. switch( aItem->Type() )
  247. {
  248. case PCB_PAD_T:
  249. case PCB_MODULE_EDGE_T:
  250. case PCB_MODULE_TEXT_T:
  251. return aItem->GetParent();
  252. default:
  253. return aItem;
  254. }
  255. return aItem;
  256. }
  257. void BOARD_COMMIT::Revert()
  258. {
  259. PICKED_ITEMS_LIST undoList;
  260. KIGFX::VIEW* view = m_toolMgr->GetView();
  261. BOARD* board = (BOARD*) m_toolMgr->GetModel();
  262. auto connectivity = board->GetConnectivity();
  263. for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it )
  264. {
  265. COMMIT_LINE& ent = *it;
  266. BOARD_ITEM* item = static_cast<BOARD_ITEM*>( ent.m_item );
  267. BOARD_ITEM* copy = static_cast<BOARD_ITEM*>( ent.m_copy );
  268. switch( ent.m_type )
  269. {
  270. case CHT_ADD:
  271. if( item->Type() == PCB_MODULE_T )
  272. {
  273. MODULE* oldModule = static_cast<MODULE*>( item );
  274. oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  275. }
  276. view->Remove( item );
  277. connectivity->Remove( item );
  278. break;
  279. case CHT_REMOVE:
  280. if( item->Type() == PCB_MODULE_T )
  281. {
  282. MODULE* newModule = static_cast<MODULE*>( item );
  283. newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) );
  284. newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1, -1 ) );
  285. }
  286. view->Add( item );
  287. connectivity->Add( item );
  288. break;
  289. case CHT_MODIFY:
  290. {
  291. if( item->Type() == PCB_MODULE_T )
  292. {
  293. MODULE* oldModule = static_cast<MODULE*>( item );
  294. oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  295. }
  296. view->Remove( item );
  297. connectivity->Remove( item );
  298. item->SwapData( copy );
  299. item->ClearFlags( SELECTED );
  300. // Update all pads/drawings/texts, as they become invalid
  301. // for the VIEW after SwapData() called for modules
  302. if( item->Type() == PCB_MODULE_T )
  303. {
  304. MODULE* newModule = static_cast<MODULE*>( item );
  305. newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) );
  306. newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1, -1 ) );
  307. }
  308. view->Add( item );
  309. connectivity->Add( item );
  310. delete copy;
  311. break;
  312. }
  313. default:
  314. assert( false );
  315. break;
  316. }
  317. }
  318. if ( !m_editModules )
  319. connectivity->RecalculateRatsnest();
  320. clear();
  321. }