undo.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /**
  2. \file undo.cpp
  3. \brief wxvdigit - Undo/Redo functionality
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. (C) 2008-2009 by Martin Landa, and the GRASS development team
  8. \author Martin Landa <landa.martin gmail.com>
  9. */
  10. #include "driver.h"
  11. #include "digit.h"
  12. /**
  13. \brief Undo/Redo changes in geometry
  14. level=0 to revert all changes
  15. \param level level for undo/redo
  16. \return id of current chanset
  17. \return -2 on error
  18. */
  19. int Digit::Undo(int level)
  20. {
  21. int changesetLast;
  22. changesetLast = (int) changesets.size() - 1;
  23. if (changesetLast < 0)
  24. return changesetLast;
  25. if (changesetCurrent == -2) { /* value uninitialized */
  26. changesetCurrent = changesetLast;
  27. }
  28. if (level > 0 && changesetCurrent < 0) {
  29. changesetCurrent = 0;
  30. }
  31. if (level == 0) {
  32. /* 0 -> undo all */
  33. level = -changesetLast;
  34. }
  35. G_debug(2, "Digit.Undo(): changeset_last=%d, changeset_current=%d, level=%d",
  36. changesetLast, changesetCurrent, level);
  37. if (level < 0) { /* undo */
  38. if (changesetCurrent + level < -1)
  39. return changesetCurrent;
  40. for (int changeset = changesetCurrent; changeset > changesetCurrent + level; --changeset) {
  41. ApplyChangeset(changeset, true);
  42. }
  43. }
  44. else if (level > 0) { /* redo */
  45. if (changesetCurrent + level > (int) changesets.size())
  46. return changesetCurrent;
  47. for (int changeset = changesetCurrent; changeset < changesetCurrent + level; ++changeset) {
  48. ApplyChangeset(changeset, false);
  49. }
  50. }
  51. changesetCurrent += level;
  52. G_debug(2, "Digit.Undo(): changeset_current=%d, changeset_last=%d, changeset_end=%d",
  53. changesetCurrent, changesetLast, changesetEnd);
  54. if (changesetCurrent == changesetEnd) {
  55. changesetEnd = changesetLast;
  56. return -1;
  57. }
  58. return changesetCurrent;
  59. }
  60. /**
  61. \brief Apply changeset (undo/redo changeset)
  62. \param changeset changeset id
  63. \param undo if true -> undo otherwise redo
  64. \return 1 changeset applied
  65. \return 0 changeset not applied
  66. \return -1 on error
  67. */
  68. int Digit::ApplyChangeset(int changeset, bool undo)
  69. {
  70. int ret, line, type;
  71. if (changeset < 0 || changeset > (int) changesets.size())
  72. return -1;
  73. if (changesetEnd < 0)
  74. changesetEnd = changeset;
  75. ret = 0;
  76. std::vector<action_meta> action = changesets[changeset];
  77. for (std::vector<action_meta>::const_reverse_iterator i = action.rbegin(), e = action.rend();
  78. i != e; ++i) {
  79. type = (*i).type;
  80. line = (*i).line;
  81. if ((undo && type == ADD) ||
  82. (!undo && type == DEL)) {
  83. if (Vect_line_alive(display->mapInfo, line)) {
  84. G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d -> deleted",
  85. changeset, line);
  86. Vect_delete_line(display->mapInfo, line);
  87. if (!ret)
  88. ret = 1;
  89. }
  90. else {
  91. G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
  92. changeset, (*i).line);
  93. }
  94. }
  95. else { /* DELETE */
  96. long offset = (*i).offset;
  97. if (!Vect_line_alive(display->mapInfo, line)) {
  98. G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
  99. changeset, line);
  100. if (Vect_restore_line(display->mapInfo, line, offset) < 0)
  101. return -1;
  102. if (!ret)
  103. ret = 1;
  104. }
  105. else {
  106. G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
  107. changeset, line);
  108. }
  109. }
  110. }
  111. return ret;
  112. }
  113. /**
  114. \brief Add action to changeset
  115. \param type action type (ADD, DEL)
  116. \return 0 on success
  117. \return -1 on error
  118. */
  119. int Digit::AddActionToChangeset(int changeset, Digit::action_type type, int line)
  120. {
  121. long offset;
  122. if (!display->mapInfo) {
  123. display->DisplayMsg();
  124. return -1;
  125. }
  126. if (!Vect_line_alive(display->mapInfo, line)) {
  127. // display->DeadLineMsg(line);
  128. return -1;
  129. }
  130. offset = Vect_get_line_offset(display->mapInfo, line);
  131. action_meta data = { type, line, offset };
  132. if (changesets.find(changeset) == changesets.end()) {
  133. changesets[changeset] = std::vector<action_meta>();
  134. changesetCurrent = changeset;
  135. }
  136. changesets[changeset].push_back(data);
  137. G_debug (3, "Digit.AddActionToChangeset(): changeset=%d, type=%d, line=%d, offset=%ld",
  138. changeset, type, line, offset);
  139. return 0;
  140. }
  141. /**
  142. \brief Free changeset structures
  143. \param changeset changeset id
  144. */
  145. void Digit::FreeChangeset(int changeset)
  146. {
  147. if (changesets.find(changeset) == changesets.end())
  148. return;
  149. std::vector<action_meta> action = changesets[changeset];
  150. for (std::vector<action_meta>::iterator i = action.begin(), e = action.end();
  151. i != e; ++i) {
  152. ;
  153. }
  154. return;
  155. }
  156. /**
  157. \brief Remove action from changeset
  158. \param changeset changeset id
  159. \param type action type (ADD, DEL)
  160. \param line line id
  161. \return number of actions in changeset
  162. \return -1 on error
  163. */
  164. int Digit::RemoveActionFromChangeset(int changeset, Digit::action_type type, int line)
  165. {
  166. if (changesets.find(changeset) == changesets.end())
  167. return -1;
  168. std::vector<action_meta>& action = changesets[changeset];
  169. for (std::vector<action_meta>::iterator i = action.begin(); i != action.end(); ++i) {
  170. if ((*i).type == type && (*i).line == line) {
  171. G_debug (3, "Digit.RemoveActionFromChangeset(): changeset=%d, type=%d, line=%d",
  172. changeset, type, line);
  173. action.erase(i--);
  174. }
  175. }
  176. return action.size();
  177. }
  178. /**
  179. \brief Get undo level (number of active changesets)
  180. \return number
  181. */
  182. int Digit::GetUndoLevel()
  183. {
  184. return changesetCurrent;
  185. }