undo.cpp 5.4 KB

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