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.

701 lines
22 KiB

14 years ago
14 years ago
14 years ago
12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2012 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 <functional>
  26. using namespace std::placeholders;
  27. #include <fctsys.h>
  28. #include <class_drawpanel.h>
  29. #include <class_draw_panel_gal.h>
  30. #include <macros.h>
  31. #include <pcbnew.h>
  32. #include <wxPcbStruct.h>
  33. #include <class_board.h>
  34. #include <class_track.h>
  35. #include <class_drawsegment.h>
  36. #include <class_pcb_text.h>
  37. #include <class_mire.h>
  38. #include <class_module.h>
  39. #include <class_dimension.h>
  40. #include <class_zone.h>
  41. #include <class_edge_mod.h>
  42. #include <ratsnest_data.h>
  43. #include <tools/selection_tool.h>
  44. #include <tool/tool_manager.h>
  45. /* Functions to undo and redo edit commands.
  46. * commands to undo are stored in CurrentScreen->m_UndoList
  47. * commands to redo are stored in CurrentScreen->m_RedoList
  48. *
  49. * m_UndoList and m_RedoList handle a std::vector of PICKED_ITEMS_LIST
  50. * Each PICKED_ITEMS_LIST handle a std::vector of pickers (class ITEM_PICKER),
  51. * that store the list of schematic items that are concerned by the command to undo or redo
  52. * and is created for each command to undo (handle also a command to redo).
  53. * each picker has a pointer pointing to an item to undo or redo (in fact: deleted, added or
  54. * modified),
  55. * and has a pointer to a copy of this item, when this item has been modified
  56. * (the old values of parameters are therefore saved)
  57. *
  58. * there are 3 cases:
  59. * - delete item(s) command
  60. * - change item(s) command
  61. * - add item(s) command
  62. * and 3 cases for block:
  63. * - move list of items
  64. * - mirror (Y) list of items
  65. * - Flip list of items
  66. *
  67. * Undo command
  68. * - delete item(s) command:
  69. * => deleted items are moved in undo list
  70. *
  71. * - change item(s) command
  72. * => A copy of item(s) is made (a DrawPickedStruct list of wrappers)
  73. * the .m_Link member of each wrapper points the modified item.
  74. * the .m_Item member of each wrapper points the old copy of this item.
  75. *
  76. * - add item(s) command
  77. * =>A list of item(s) is made. The .m_Item member of each wrapper points the new item.
  78. *
  79. * Redo command
  80. * - delete item(s) old command:
  81. * => deleted items are moved in EEDrawList list, and in
  82. *
  83. * - change item(s) command
  84. * => the copy of item(s) is moved in Undo list
  85. *
  86. * - add item(s) command
  87. * => The list of item(s) is used to create a deleted list in undo list(same as a delete
  88. * command)
  89. *
  90. * Some block operations that change items can be undone without memorize items, just the
  91. * coordinates of the transform:
  92. * move list of items (undo/redo is made by moving with the opposite move vector)
  93. * mirror (Y) and flip list of items (undo/redo is made by mirror or flip items)
  94. * so they are handled specifically.
  95. *
  96. */
  97. /**
  98. * Function TestForExistingItem
  99. * test if aItem exists somewhere in lists of items
  100. * This is a function used by PutDataInPreviousState to be sure an item was not deleted
  101. * since an undo or redo.
  102. * This could be possible:
  103. * - if a call to SaveCopyInUndoList was forgotten in Pcbnew
  104. * - in zones outlines, when a change in one zone merges this zone with an other
  105. * This function avoids a Pcbnew crash
  106. * Before using this function to test existence of items,
  107. * it must be called with aItem = NULL to prepare the list
  108. * @param aPcb = board to test
  109. * @param aItem = item to find
  110. * = NULL to build the list of existing items
  111. */
  112. static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
  113. {
  114. static std::vector<BOARD_ITEM*> itemsList;
  115. if( aItem == NULL ) // Build list
  116. {
  117. // Count items to store in itemsList:
  118. int icnt = 0;
  119. BOARD_ITEM* item;
  120. // Count tracks:
  121. for( item = aPcb->m_Track; item != NULL; item = item->Next() )
  122. icnt++;
  123. // Count modules:
  124. for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
  125. icnt++;
  126. // Count drawings
  127. for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
  128. icnt++;
  129. // Count zones outlines
  130. icnt += aPcb->GetAreaCount();
  131. // Count zones segm (now obsolete):
  132. for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
  133. icnt++;
  134. NETINFO_LIST& netInfo = aPcb->GetNetInfo();
  135. icnt += netInfo.GetNetCount();
  136. // Build candidate list:
  137. itemsList.clear();
  138. itemsList.reserve(icnt);
  139. // Store items in list:
  140. // Append tracks:
  141. for( item = aPcb->m_Track; item != NULL; item = item->Next() )
  142. itemsList.push_back( item );
  143. // Append modules:
  144. for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
  145. itemsList.push_back( item );
  146. // Append drawings
  147. for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
  148. itemsList.push_back( item );
  149. // Append zones outlines
  150. for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
  151. itemsList.push_back( aPcb->GetArea( ii ) );
  152. // Append zones segm:
  153. for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
  154. itemsList.push_back( item );
  155. for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i )
  156. itemsList.push_back( *i );
  157. // Sort list
  158. std::sort( itemsList.begin(), itemsList.end() );
  159. return false;
  160. }
  161. // search in list:
  162. return std::binary_search( itemsList.begin(), itemsList.end(), aItem );
  163. }
  164. void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
  165. {
  166. if( aImage == NULL )
  167. return;
  168. // Remark: to create images of edited items to undo, we are using Clone method
  169. // which can duplication of items foe copy, but does not clone all members
  170. // mainly pointers in chain and time stamp, which is set to new, unique value.
  171. // So we have to use the current values of these parameters.
  172. EDA_ITEM * pnext = Next();
  173. EDA_ITEM * pback = Back();
  174. DHEAD* mylist = m_List;
  175. time_t timestamp = GetTimeStamp();
  176. switch( Type() )
  177. {
  178. case PCB_MODULE_T:
  179. std::swap( *((MODULE*) this), *((MODULE*) aImage) );
  180. break;
  181. case PCB_ZONE_AREA_T:
  182. std::swap( *((ZONE_CONTAINER*) this), *((ZONE_CONTAINER*) aImage) );
  183. break;
  184. case PCB_LINE_T:
  185. std::swap( *((DRAWSEGMENT*) this), *((DRAWSEGMENT*) aImage) );
  186. break;
  187. case PCB_TRACE_T:
  188. std::swap( *((TRACK*) this), *((TRACK*) aImage) );
  189. break;
  190. case PCB_VIA_T:
  191. std::swap( *((VIA*) this), *((VIA*) aImage) );
  192. break;
  193. case PCB_TEXT_T:
  194. std::swap( *((TEXTE_PCB*) this), *((TEXTE_PCB*) aImage) );
  195. break;
  196. case PCB_TARGET_T:
  197. std::swap( *((PCB_TARGET*) this), *((PCB_TARGET*) aImage) );
  198. break;
  199. case PCB_DIMENSION_T:
  200. std::swap( *((DIMENSION*) this), *((DIMENSION*) aImage) );
  201. break;
  202. case PCB_ZONE_T:
  203. default:
  204. wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() );
  205. break;
  206. }
  207. // Restore pointers and time stamp, to be sure they are not broken
  208. Pnext = pnext;
  209. Pback = pback;
  210. m_List = mylist;
  211. SetTimeStamp( timestamp );
  212. }
  213. void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem,
  214. UNDO_REDO_T aCommandType,
  215. const wxPoint& aTransformPoint )
  216. {
  217. if( aItem == NULL ) // Nothing to save
  218. return;
  219. // For texts belonging to modules, we need to save state of the parent module
  220. if( aItem->Type() == PCB_MODULE_TEXT_T )
  221. {
  222. aItem = aItem->GetParent();
  223. wxASSERT( aItem->Type() == PCB_MODULE_T );
  224. aCommandType = UR_CHANGED;
  225. if( aItem == NULL )
  226. return;
  227. }
  228. PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
  229. commandToUndo->m_TransformPoint = aTransformPoint;
  230. ITEM_PICKER itemWrapper( aItem, aCommandType );
  231. switch( aCommandType )
  232. {
  233. case UR_CHANGED: // Create a copy of item
  234. if( itemWrapper.GetLink() == NULL ) // When not null, the copy is already done
  235. itemWrapper.SetLink( aItem->Clone() );
  236. commandToUndo->PushItem( itemWrapper );
  237. break;
  238. case UR_NEW:
  239. case UR_DELETED:
  240. #ifdef USE_WX_OVERLAY
  241. // Avoid to redraw when autoplacing
  242. if( aItem->Type() == PCB_MODULE_T )
  243. if( ((MODULE*)aItem)->GetFlags() & MODULE_to_PLACE )
  244. break;
  245. m_canvas->Refresh();
  246. #endif
  247. case UR_MOVED:
  248. case UR_FLIPPED:
  249. case UR_ROTATED:
  250. case UR_ROTATED_CLOCKWISE:
  251. commandToUndo->PushItem( itemWrapper );
  252. break;
  253. default:
  254. {
  255. wxString msg;
  256. msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), aCommandType );
  257. wxMessageBox( msg );
  258. }
  259. break;
  260. }
  261. if( commandToUndo->GetCount() )
  262. {
  263. /* Save the copy in undo list */
  264. GetScreen()->PushCommandToUndoList( commandToUndo );
  265. /* Clear redo list, because after new save there is no redo to do */
  266. GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
  267. }
  268. else
  269. {
  270. delete commandToUndo;
  271. }
  272. }
  273. void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
  274. UNDO_REDO_T aTypeCommand,
  275. const wxPoint& aTransformPoint )
  276. {
  277. PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
  278. commandToUndo->m_TransformPoint = aTransformPoint;
  279. // First, filter unnecessary stuff from the list (i.e. for multiple pads / labels modified),
  280. // take the first occurence of the module.
  281. for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
  282. {
  283. ITEM_PICKER picker = aItemsList.GetItemWrapper(ii);
  284. BOARD_ITEM* item = (BOARD_ITEM*) aItemsList.GetPickedItem( ii );
  285. // For texts belonging to modules, we need to save state of the parent module
  286. if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_PAD_T )
  287. {
  288. item = item->GetParent();
  289. wxASSERT( item->Type() == PCB_MODULE_T );
  290. if( item == NULL )
  291. continue;
  292. bool found = false;
  293. for( unsigned j = 0; j < commandToUndo->GetCount(); j++ )
  294. {
  295. if( commandToUndo->GetPickedItem( j ) == item && commandToUndo->GetPickedItemStatus( j ) == UR_CHANGED )
  296. {
  297. found = true;
  298. break;
  299. }
  300. }
  301. if( !found )
  302. commandToUndo->PushItem( ITEM_PICKER( item, UR_CHANGED ) );
  303. else
  304. continue;
  305. } else {
  306. commandToUndo->PushItem( picker );
  307. }
  308. }
  309. for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
  310. {
  311. BOARD_ITEM* item = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );
  312. UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );
  313. if( command == UR_UNSPECIFIED )
  314. {
  315. command = aTypeCommand;
  316. commandToUndo->SetPickedItemStatus( command, ii );
  317. }
  318. wxASSERT( item );
  319. switch( command )
  320. {
  321. case UR_CHANGED:
  322. /* If needed, create a copy of item, and put in undo list
  323. * in the picker, as link
  324. * If this link is not null, the copy is already done
  325. */
  326. if( commandToUndo->GetPickedItemLink( ii ) == NULL )
  327. {
  328. EDA_ITEM* cloned = item->Clone();
  329. commandToUndo->SetPickedItemLink( cloned, ii );
  330. }
  331. break;
  332. case UR_MOVED:
  333. case UR_ROTATED:
  334. case UR_ROTATED_CLOCKWISE:
  335. case UR_FLIPPED:
  336. case UR_NEW:
  337. case UR_DELETED:
  338. break;
  339. default:
  340. {
  341. wxString msg;
  342. msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), command );
  343. wxMessageBox( msg );
  344. }
  345. break;
  346. }
  347. }
  348. if( commandToUndo->GetCount() )
  349. {
  350. /* Save the copy in undo list */
  351. GetScreen()->PushCommandToUndoList( commandToUndo );
  352. /* Clear redo list, because after a new command one cannot redo a command */
  353. GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
  354. }
  355. else // Should not occur
  356. {
  357. delete commandToUndo;
  358. }
  359. }
  360. void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
  361. bool aRebuildRatsnet )
  362. {
  363. BOARD_ITEM* item;
  364. bool not_found = false;
  365. bool reBuild_ratsnest = false;
  366. bool deep_reBuild_ratsnest = false;
  367. KIGFX::VIEW* view = GetGalCanvas()->GetView();
  368. RN_DATA* ratsnest = GetBoard()->GetRatsnest();
  369. // Undo in the reverse order of list creation: (this can allow stacked changes
  370. // like the same item can be changes and deleted in the same complex command
  371. bool build_item_list = true; // if true the list of existing items must be rebuilt
  372. for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- )
  373. {
  374. item = (BOARD_ITEM*) aList->GetPickedItem( ii );
  375. wxASSERT( item );
  376. /* Test for existence of item on board.
  377. * It could be deleted, and no more on board:
  378. * - if a call to SaveCopyInUndoList was forgotten in Pcbnew
  379. * - in zones outlines, when a change in one zone merges this zone with an other
  380. * This test avoids a Pcbnew crash
  381. * Obviously, this test is not made for deleted items
  382. */
  383. UNDO_REDO_T status = aList->GetPickedItemStatus( ii );
  384. if( status != UR_DELETED )
  385. {
  386. if( build_item_list )
  387. // Build list of existing items, for integrity test
  388. TestForExistingItem( GetBoard(), NULL );
  389. build_item_list = false;
  390. if( !TestForExistingItem( GetBoard(), item ) )
  391. {
  392. // Remove this non existent item
  393. aList->RemovePicker( ii );
  394. ii++; // the current item was removed, ii points now the next item
  395. // decrement it because it will be incremented later
  396. not_found = true;
  397. continue;
  398. }
  399. }
  400. item->ClearFlags();
  401. // see if we must rebuild ratsnets and pointers lists
  402. switch( item->Type() )
  403. {
  404. case PCB_MODULE_T:
  405. case PCB_ZONE_AREA_T:
  406. case PCB_TRACE_T:
  407. case PCB_VIA_T:
  408. reBuild_ratsnest = true;
  409. break;
  410. case PCB_NETINFO_T:
  411. reBuild_ratsnest = true;
  412. deep_reBuild_ratsnest = true;
  413. break;
  414. default:
  415. break;
  416. }
  417. switch( aList->GetPickedItemStatus( ii ) )
  418. {
  419. case UR_CHANGED: /* Exchange old and new data for each item */
  420. {
  421. BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
  422. // Remove all pads/drawings/texts, as they become invalid
  423. // for the VIEW after SwapData() called for modules
  424. if( item->Type() == PCB_MODULE_T )
  425. {
  426. MODULE* oldModule = static_cast<MODULE*>( item );
  427. oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  428. }
  429. view->Remove( item );
  430. ratsnest->Remove( item );
  431. item->SwapData( image );
  432. // Update all pads/drawings/texts, as they become invalid
  433. // for the VIEW after SwapData() called for modules
  434. if( item->Type() == PCB_MODULE_T )
  435. {
  436. MODULE* newModule = static_cast<MODULE*>( item );
  437. newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) );
  438. newModule->RunOnChildren( std::bind( &BOARD_ITEM::ClearFlags, _1, EDA_ITEM_ALL_FLAGS ));
  439. }
  440. view->Add( item );
  441. ratsnest->Add( item );
  442. item->ClearFlags();
  443. item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
  444. }
  445. break;
  446. case UR_NEW: /* new items are deleted */
  447. aList->SetPickedItemStatus( UR_DELETED, ii );
  448. GetBoard()->Remove( item );
  449. if( item->Type() == PCB_MODULE_T )
  450. {
  451. MODULE* module = static_cast<MODULE*>( item );
  452. module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) );
  453. }
  454. view->Remove( item );
  455. item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  456. break;
  457. case UR_DELETED: /* deleted items are put in List, as new items */
  458. aList->SetPickedItemStatus( UR_NEW, ii );
  459. GetBoard()->Add( item );
  460. if( item->Type() == PCB_MODULE_T )
  461. {
  462. MODULE* module = static_cast<MODULE*>( item );
  463. module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1) );
  464. }
  465. view->Add( item );
  466. item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  467. build_item_list = true;
  468. break;
  469. case UR_MOVED:
  470. item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
  471. item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  472. ratsnest->Update( item );
  473. break;
  474. case UR_ROTATED:
  475. item->Rotate( aList->m_TransformPoint,
  476. aRedoCommand ? m_rotationAngle : -m_rotationAngle );
  477. item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  478. ratsnest->Update( item );
  479. break;
  480. case UR_ROTATED_CLOCKWISE:
  481. item->Rotate( aList->m_TransformPoint,
  482. aRedoCommand ? -m_rotationAngle : m_rotationAngle );
  483. item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
  484. ratsnest->Update( item );
  485. break;
  486. case UR_FLIPPED:
  487. item->Flip( aList->m_TransformPoint );
  488. item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
  489. ratsnest->Update( item );
  490. break;
  491. default:
  492. {
  493. wxString msg;
  494. msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
  495. aList->GetPickedItemStatus( ii ) );
  496. wxMessageBox( msg );
  497. }
  498. break;
  499. }
  500. }
  501. if( not_found )
  502. wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );
  503. // Rebuild pointers and ratsnest that can be changed.
  504. if( reBuild_ratsnest )
  505. {
  506. Compile_Ratsnest( NULL, true );
  507. if( IsGalCanvasActive() )
  508. {
  509. if( deep_reBuild_ratsnest )
  510. ratsnest->ProcessBoard();
  511. else
  512. ratsnest->Recalculate();
  513. }
  514. }
  515. }
  516. void PCB_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent )
  517. {
  518. if( UndoRedoBlocked() )
  519. return;
  520. if( GetScreen()->GetUndoCommandCount() <= 0 )
  521. return;
  522. // Inform tools that undo command was issued
  523. TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL );
  524. m_toolManager->ProcessEvent( event );
  525. /* Get the old list */
  526. PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList();
  527. /* Undo the command */
  528. PutDataInPreviousState( List, false );
  529. /* Put the old list in RedoList */
  530. List->ReversePickersListOrder();
  531. GetScreen()->PushCommandToRedoList( List );
  532. OnModify();
  533. m_canvas->Refresh();
  534. }
  535. void PCB_EDIT_FRAME::RestoreCopyFromRedoList( wxCommandEvent& aEvent )
  536. {
  537. if( UndoRedoBlocked() )
  538. return;
  539. if( GetScreen()->GetRedoCommandCount() == 0 )
  540. return;
  541. // Inform tools that redo command was issued
  542. TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL );
  543. m_toolManager->ProcessEvent( event );
  544. /* Get the old list */
  545. PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList();
  546. /* Redo the command: */
  547. PutDataInPreviousState( List, true );
  548. /* Put the old list in UndoList */
  549. List->ReversePickersListOrder();
  550. GetScreen()->PushCommandToUndoList( List );
  551. OnModify();
  552. m_canvas->Refresh();
  553. }
  554. void PCB_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount )
  555. {
  556. if( aItemCount == 0 )
  557. return;
  558. unsigned icnt = aList.m_CommandsList.size();
  559. if( aItemCount > 0 )
  560. icnt = aItemCount;
  561. for( unsigned ii = 0; ii < icnt; ii++ )
  562. {
  563. if( aList.m_CommandsList.size() == 0 )
  564. break;
  565. PICKED_ITEMS_LIST* curr_cmd = aList.m_CommandsList[0];
  566. aList.m_CommandsList.erase( aList.m_CommandsList.begin() );
  567. curr_cmd->ClearListAndDeleteItems();
  568. delete curr_cmd; // Delete command
  569. }
  570. }