undo.cpp 6.2 KB

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