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.

198 lines
5.3 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright 2016-2017 CERN
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  8. * @author Maciej Suminski <maciej.suminski@cern.ch>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include <core/kicad_algo.h>
  28. #include <commit.h>
  29. #include <eda_item.h>
  30. #include <eda_group.h>
  31. #include <macros.h>
  32. COMMIT::COMMIT()
  33. {
  34. }
  35. COMMIT::~COMMIT()
  36. {
  37. for( COMMIT_LINE& ent : m_changes )
  38. delete ent.m_copy;
  39. }
  40. COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen,
  41. RECURSE_MODE aRecurse )
  42. {
  43. // CHT_MODIFY and CHT_DONE are not compatible
  44. wxASSERT( ( aChangeType & ( CHT_MODIFY | CHT_DONE ) ) != ( CHT_MODIFY | CHT_DONE ) );
  45. int flag = aChangeType & CHT_FLAGS;
  46. switch( aChangeType & CHT_TYPE )
  47. {
  48. case CHT_ADD:
  49. makeEntry( aItem, CHT_ADD | flag, nullptr, aScreen );
  50. break;
  51. case CHT_REMOVE:
  52. wxASSERT( m_deletedItems.find( aItem ) == m_deletedItems.end() );
  53. m_deletedItems.insert( aItem );
  54. makeEntry( aItem, CHT_REMOVE | flag, makeImage( aItem ), aScreen );
  55. if( EDA_GROUP* parentGroup = aItem->GetParentGroup() )
  56. Modify( parentGroup->AsEdaItem(), aScreen );
  57. break;
  58. case CHT_MODIFY:
  59. {
  60. EDA_ITEM* parent = parentObject( aItem );
  61. createModified( parent, makeImage( parent ), flag, aScreen );
  62. break;
  63. }
  64. default:
  65. wxFAIL;
  66. }
  67. return *this;
  68. }
  69. COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType,
  70. BASE_SCREEN *aScreen )
  71. {
  72. for( EDA_ITEM* item : container )
  73. Stage( item, aChangeType, aScreen);
  74. return *this;
  75. }
  76. COMMIT& COMMIT::Stage( const PICKED_ITEMS_LIST &aItems, UNDO_REDO aModFlag, BASE_SCREEN *aScreen )
  77. {
  78. for( unsigned int i = 0; i < aItems.GetCount(); i++ )
  79. {
  80. UNDO_REDO change_type = aItems.GetPickedItemStatus( i );
  81. EDA_ITEM* item = aItems.GetPickedItem( i );
  82. if( change_type == UNDO_REDO::UNSPECIFIED )
  83. change_type = aModFlag;
  84. if( EDA_ITEM* copy = aItems.GetPickedItemLink( i ) )
  85. {
  86. assert( change_type == UNDO_REDO::CHANGED );
  87. // There was already a copy created, so use it
  88. Modified( item, copy, aScreen );
  89. }
  90. else
  91. {
  92. Stage( item, convert( change_type ), aScreen );
  93. }
  94. }
  95. return *this;
  96. }
  97. int COMMIT::GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen )
  98. {
  99. COMMIT_LINE* entry = findEntry( parentObject( aItem ), aScreen );
  100. return entry ? entry->m_type : 0;
  101. }
  102. COMMIT& COMMIT::createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags,
  103. BASE_SCREEN* aScreen )
  104. {
  105. EDA_ITEM* parent = parentObject( aItem );
  106. if( m_changedItems.find( parent ) != m_changedItems.end() )
  107. {
  108. delete aCopy;
  109. return *this; // item has been already modified once
  110. }
  111. makeEntry( parent, CHT_MODIFY | aExtraFlags, aCopy, aScreen );
  112. return *this;
  113. }
  114. void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy, BASE_SCREEN *aScreen )
  115. {
  116. COMMIT_LINE ent;
  117. ent.m_item = aItem;
  118. ent.m_type = aType;
  119. ent.m_copy = aCopy;
  120. ent.m_screen = aScreen;
  121. // N.B. Do not throw an assertion for multiple changed items. An item can be changed
  122. // multiple times in a single commit such as when importing graphics and grouping them.
  123. m_changedItems.insert( aItem );
  124. m_changes.push_back( ent );
  125. }
  126. COMMIT::COMMIT_LINE* COMMIT::findEntry( EDA_ITEM* aItem, BASE_SCREEN *aScreen )
  127. {
  128. for( COMMIT_LINE& change : m_changes )
  129. {
  130. if( change.m_item == aItem && change.m_screen == aScreen )
  131. return &change;
  132. }
  133. return nullptr;
  134. }
  135. CHANGE_TYPE COMMIT::convert( UNDO_REDO aType ) const
  136. {
  137. switch( aType )
  138. {
  139. case UNDO_REDO::NEWITEM: return CHT_ADD;
  140. case UNDO_REDO::DELETED: return CHT_REMOVE;
  141. case UNDO_REDO::CHANGED: return CHT_MODIFY;
  142. default: wxASSERT( false ); return CHT_MODIFY;
  143. }
  144. }
  145. UNDO_REDO COMMIT::convert( CHANGE_TYPE aType ) const
  146. {
  147. switch( aType )
  148. {
  149. case CHT_ADD: return UNDO_REDO::NEWITEM;
  150. case CHT_REMOVE: return UNDO_REDO::DELETED;
  151. case CHT_MODIFY: return UNDO_REDO::CHANGED;
  152. default: wxASSERT( false ); return UNDO_REDO::CHANGED;
  153. }
  154. }