File: | home/HaikuArchives/ArtPaint/artpaint/application/UndoQueue.cpp |
Warning: | line 476, column 13 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||||||||
2 | * Copyright 2003, Heikki Suhonen | ||||||||||
3 | * Distributed under the terms of the MIT License. | ||||||||||
4 | * | ||||||||||
5 | * Authors: | ||||||||||
6 | * Heikki Suhonen <heikki.suhonen@gmail.com> | ||||||||||
7 | * Dale Cieslak <dcieslak@yahoo.com> | ||||||||||
8 | * | ||||||||||
9 | */ | ||||||||||
10 | |||||||||||
11 | #include "UndoQueue.h" | ||||||||||
12 | |||||||||||
13 | #include "Image.h" | ||||||||||
14 | #include "Selection.h" | ||||||||||
15 | #include "SettingsServer.h" | ||||||||||
16 | |||||||||||
17 | |||||||||||
18 | #include <Alert.h> | ||||||||||
19 | #include <Catalog.h> | ||||||||||
20 | #include <MenuItem.h> | ||||||||||
21 | |||||||||||
22 | |||||||||||
23 | #include <new> | ||||||||||
24 | #include <stdio.h> | ||||||||||
25 | |||||||||||
26 | |||||||||||
27 | #undef B_TRANSLATION_CONTEXT"UndoQueue" | ||||||||||
28 | #define B_TRANSLATION_CONTEXT"UndoQueue" "UndoQueue" | ||||||||||
29 | |||||||||||
30 | int32 UndoQueue::maximum_queue_depth = 10; | ||||||||||
31 | BList* UndoQueue::queue_list = new BList(); | ||||||||||
32 | |||||||||||
33 | |||||||||||
34 | UndoQueue::UndoQueue(BMenuItem *undo_item,BMenuItem *redo_item,ImageView *iv) | ||||||||||
35 | { | ||||||||||
36 | image_view = iv; | ||||||||||
37 | layer_bitmaps = NULL__null; | ||||||||||
38 | layer_bitmap_count = 0; | ||||||||||
39 | |||||||||||
40 | undo_menu_item = undo_item; | ||||||||||
41 | redo_menu_item = redo_item; | ||||||||||
42 | current_event = NULL__null; | ||||||||||
43 | first_event = NULL__null; | ||||||||||
44 | last_event = NULL__null; | ||||||||||
45 | |||||||||||
46 | current_queue_depth = 0; | ||||||||||
47 | |||||||||||
48 | queue_list->AddItem(this); | ||||||||||
49 | |||||||||||
50 | selection_data = new SelectionData(); | ||||||||||
51 | |||||||||||
52 | UpdateMenuItems(); | ||||||||||
53 | } | ||||||||||
54 | |||||||||||
55 | |||||||||||
56 | UndoQueue::UndoQueue(BFile&) | ||||||||||
57 | { | ||||||||||
58 | } | ||||||||||
59 | |||||||||||
60 | |||||||||||
61 | UndoQueue::~UndoQueue() | ||||||||||
62 | { | ||||||||||
63 | UndoEvent *spare_event = first_event; | ||||||||||
64 | while (spare_event != NULL__null) { | ||||||||||
65 | first_event = spare_event->next_event; | ||||||||||
66 | delete spare_event; | ||||||||||
67 | spare_event = first_event; | ||||||||||
68 | } | ||||||||||
69 | |||||||||||
70 | queue_list->RemoveItem(this); | ||||||||||
71 | |||||||||||
72 | for (int32 i=0;i<layer_bitmap_count;i++) { | ||||||||||
73 | delete layer_bitmaps[i]; | ||||||||||
74 | layer_bitmaps[i] = NULL__null; | ||||||||||
75 | } | ||||||||||
76 | delete[] layer_bitmaps; | ||||||||||
77 | |||||||||||
78 | delete selection_data; | ||||||||||
79 | } | ||||||||||
80 | |||||||||||
81 | |||||||||||
82 | UndoEvent* UndoQueue::AddUndoEvent(const char *name,const BBitmap *thumbnail,bool remove_tail) | ||||||||||
83 | { | ||||||||||
84 | if (maximum_queue_depth == 0) | ||||||||||
85 | return NULL__null; | ||||||||||
86 | |||||||||||
87 | UndoEvent *event = new UndoEvent(name,thumbnail); | ||||||||||
88 | current_queue_depth++; | ||||||||||
89 | |||||||||||
90 | if (remove_tail == FALSE0) { | ||||||||||
91 | // Insert the new event in between. | ||||||||||
92 | if (current_event != NULL__null) { | ||||||||||
93 | event->next_event = current_event->next_event; | ||||||||||
94 | event->previous_event = current_event; | ||||||||||
95 | event->next_event->previous_event = event; | ||||||||||
96 | current_event->next_event = event; | ||||||||||
97 | } | ||||||||||
98 | } | ||||||||||
99 | else { | ||||||||||
100 | UndoEvent *spare_event; | ||||||||||
101 | if (current_event != NULL__null) | ||||||||||
102 | spare_event = current_event->next_event; | ||||||||||
103 | else { | ||||||||||
104 | spare_event = first_event; | ||||||||||
105 | first_event = NULL__null; | ||||||||||
106 | } | ||||||||||
107 | // Delete the rest of the events | ||||||||||
108 | while (spare_event != NULL__null) { | ||||||||||
109 | UndoEvent *another_spare_event = spare_event->next_event; | ||||||||||
110 | delete spare_event; | ||||||||||
111 | spare_event = another_spare_event; | ||||||||||
112 | current_queue_depth--; | ||||||||||
113 | } | ||||||||||
114 | |||||||||||
115 | if (current_event != NULL__null) { | ||||||||||
116 | current_event->next_event = event; | ||||||||||
117 | event->previous_event = current_event; | ||||||||||
118 | } | ||||||||||
119 | } | ||||||||||
120 | |||||||||||
121 | if (first_event == NULL__null) | ||||||||||
122 | first_event = event; | ||||||||||
123 | current_event = event; | ||||||||||
124 | |||||||||||
125 | event->SetQueue(this); | ||||||||||
126 | |||||||||||
127 | TruncateQueue(); | ||||||||||
128 | |||||||||||
129 | UpdateMenuItems(); | ||||||||||
130 | return event; | ||||||||||
131 | } | ||||||||||
132 | |||||||||||
133 | |||||||||||
134 | status_t UndoQueue::RemoveEvent(UndoEvent *event) | ||||||||||
135 | { | ||||||||||
136 | current_queue_depth--; | ||||||||||
137 | |||||||||||
138 | UndoEvent *spare_event = first_event; | ||||||||||
139 | while ((spare_event != event) && (spare_event != NULL__null)) { | ||||||||||
140 | spare_event = spare_event->next_event; | ||||||||||
141 | } | ||||||||||
142 | if (spare_event == NULL__null) | ||||||||||
143 | return B_ERROR(-1); | ||||||||||
144 | |||||||||||
145 | |||||||||||
146 | // If the current event is the event that is removed we must change the | ||||||||||
147 | // current event also. At the moment this should happen always. | ||||||||||
148 | if (current_event == spare_event) { | ||||||||||
149 | if (event->previous_event != NULL__null) | ||||||||||
150 | current_event = spare_event->previous_event; | ||||||||||
151 | else | ||||||||||
152 | current_event = spare_event->next_event; | ||||||||||
153 | } | ||||||||||
154 | |||||||||||
155 | |||||||||||
156 | // If the first event is the removed one, we should also update its | ||||||||||
157 | // status. | ||||||||||
158 | if (first_event == spare_event) { | ||||||||||
159 | first_event = spare_event->next_event; | ||||||||||
160 | } | ||||||||||
161 | |||||||||||
162 | // Unlink the event | ||||||||||
163 | if (spare_event->previous_event != NULL__null) { | ||||||||||
164 | spare_event->previous_event->next_event = spare_event->next_event; | ||||||||||
165 | } | ||||||||||
166 | if (spare_event->next_event != NULL__null) { | ||||||||||
167 | spare_event->next_event->previous_event = spare_event->previous_event; | ||||||||||
168 | } | ||||||||||
169 | |||||||||||
170 | |||||||||||
171 | UpdateMenuItems(); | ||||||||||
172 | return B_OK((int)0); | ||||||||||
173 | } | ||||||||||
174 | |||||||||||
175 | BBitmap* UndoQueue::ReturnLayerSpareBitmap(int32 layer_id,BBitmap *layer_bitmap) | ||||||||||
176 | { | ||||||||||
177 | if (layer_id > layer_bitmap_count-1) { | ||||||||||
178 | BBitmap **new_bitmaps = new BBitmap*[layer_id+1]; | ||||||||||
179 | for (int32 i=0;i<layer_id+1;i++) | ||||||||||
180 | new_bitmaps[i] = NULL__null; | ||||||||||
181 | |||||||||||
182 | for (int32 i=0;i<layer_bitmap_count;i++) { | ||||||||||
183 | new_bitmaps[i] = layer_bitmaps[i]; | ||||||||||
184 | layer_bitmaps[i] = NULL__null; | ||||||||||
185 | } | ||||||||||
186 | |||||||||||
187 | delete[] layer_bitmaps; | ||||||||||
188 | layer_bitmaps = new_bitmaps; | ||||||||||
189 | layer_bitmap_count = layer_id+1; | ||||||||||
190 | } | ||||||||||
191 | |||||||||||
192 | if (layer_bitmaps[layer_id] == NULL__null) { | ||||||||||
193 | if (layer_bitmap != NULL__null) { | ||||||||||
194 | layer_bitmaps[layer_id] = new BBitmap(layer_bitmap->Bounds(),B_RGB32); | ||||||||||
195 | if (layer_bitmaps[layer_id]->IsValid() == FALSE0) | ||||||||||
196 | throw std::bad_alloc(); | ||||||||||
197 | } | ||||||||||
198 | } | ||||||||||
199 | |||||||||||
200 | return layer_bitmaps[layer_id]; | ||||||||||
201 | } | ||||||||||
202 | |||||||||||
203 | |||||||||||
204 | status_t UndoQueue::ChangeLayerSpareBitmap(int32 layer_id, BBitmap *layer_bitmap) | ||||||||||
205 | { | ||||||||||
206 | // This function doesn't delete the old bitmap. | ||||||||||
207 | if (layer_id > layer_bitmap_count-1) { | ||||||||||
208 | BBitmap **new_bitmaps = new BBitmap*[layer_id+1]; | ||||||||||
209 | for (int32 i=0;i<layer_id+1;i++) | ||||||||||
210 | new_bitmaps[i] = NULL__null; | ||||||||||
211 | |||||||||||
212 | for (int32 i=0;i<layer_bitmap_count;i++) { | ||||||||||
213 | new_bitmaps[i] = layer_bitmaps[i]; | ||||||||||
214 | layer_bitmaps[i] = NULL__null; | ||||||||||
215 | } | ||||||||||
216 | delete[] layer_bitmaps; | ||||||||||
217 | layer_bitmaps = new_bitmaps; | ||||||||||
218 | layer_bitmap_count = layer_id+1; | ||||||||||
219 | } | ||||||||||
220 | |||||||||||
221 | if (layer_bitmap != NULL__null) { | ||||||||||
222 | layer_bitmaps[layer_id] = new BBitmap(layer_bitmap->Bounds(),B_RGB32); | ||||||||||
223 | if (layer_bitmaps[layer_id]->IsValid() == FALSE0) | ||||||||||
224 | throw std::bad_alloc(); | ||||||||||
225 | |||||||||||
226 | uint32 *spare_bits = (uint32*)layer_bitmaps[layer_id]->Bits(); | ||||||||||
227 | uint32 *bits = (uint32*)layer_bitmap->Bits(); | ||||||||||
228 | uint32 bitslength = layer_bitmap->BitsLength()/4; | ||||||||||
229 | for (uint32 i = 0; i < bitslength; i++) | ||||||||||
230 | *spare_bits++ = *bits++; | ||||||||||
231 | } | ||||||||||
232 | else { | ||||||||||
233 | layer_bitmaps[layer_id] = NULL__null; | ||||||||||
234 | } | ||||||||||
235 | return B_OK((int)0); | ||||||||||
236 | } | ||||||||||
237 | |||||||||||
238 | |||||||||||
239 | |||||||||||
240 | void UndoQueue::RegisterLayer(int32 layer_id,BBitmap *layer_bitmap) | ||||||||||
241 | { | ||||||||||
242 | if ((maximum_queue_depth > 0) || (maximum_queue_depth == INFINITE_QUEUE_DEPTH-1)) { | ||||||||||
243 | if (layer_id > layer_bitmap_count-1) { | ||||||||||
244 | BBitmap **new_bitmaps = new BBitmap*[layer_id+1]; | ||||||||||
245 | for (int32 i=0;i<layer_id+1;i++) | ||||||||||
246 | new_bitmaps[i] = NULL__null; | ||||||||||
247 | |||||||||||
248 | for (int32 i=0;i<layer_bitmap_count;i++) { | ||||||||||
249 | new_bitmaps[i] = layer_bitmaps[i]; | ||||||||||
250 | layer_bitmaps[i] = NULL__null; | ||||||||||
251 | } | ||||||||||
252 | delete[] layer_bitmaps; | ||||||||||
253 | layer_bitmaps = new_bitmaps; | ||||||||||
254 | layer_bitmap_count = layer_id+1; | ||||||||||
255 | |||||||||||
256 | } | ||||||||||
257 | |||||||||||
258 | if (layer_bitmaps[layer_id] == NULL__null) { | ||||||||||
259 | if (layer_bitmap != NULL__null) { | ||||||||||
260 | layer_bitmaps[layer_id] = new BBitmap(layer_bitmap->Bounds(),B_RGB32); | ||||||||||
261 | if (layer_bitmaps[layer_id]->IsValid() == FALSE0) | ||||||||||
262 | throw std::bad_alloc(); | ||||||||||
263 | |||||||||||
264 | uint32 *source_bits = (uint32*)layer_bitmap->Bits(); | ||||||||||
265 | uint32 *target_bits = (uint32*)layer_bitmaps[layer_id]->Bits(); | ||||||||||
266 | int32 bitslength = layer_bitmap->BitsLength()/4; | ||||||||||
267 | |||||||||||
268 | for (int32 i=0;i<bitslength;i++) | ||||||||||
269 | *target_bits++ = *source_bits++; | ||||||||||
270 | } | ||||||||||
271 | } | ||||||||||
272 | } | ||||||||||
273 | } | ||||||||||
274 | |||||||||||
275 | |||||||||||
276 | UndoEvent* UndoQueue::Undo() | ||||||||||
277 | { | ||||||||||
278 | UndoEvent *returned_event = NULL__null; | ||||||||||
279 | |||||||||||
280 | if (current_event != NULL__null) { | ||||||||||
281 | returned_event = current_event; | ||||||||||
282 | current_event = current_event->previous_event; | ||||||||||
283 | if (returned_event->ActionCount() == 1) { | ||||||||||
284 | if (returned_event->ReturnActions()[0]->type == ADD_LAYER_ACTION) { | ||||||||||
285 | // This event should be removed. | ||||||||||
286 | current_event = returned_event; | ||||||||||
287 | returned_event = NULL__null; | ||||||||||
288 | } | ||||||||||
289 | } | ||||||||||
290 | } | ||||||||||
291 | |||||||||||
292 | UpdateMenuItems(); | ||||||||||
293 | return returned_event; | ||||||||||
294 | } | ||||||||||
295 | |||||||||||
296 | |||||||||||
297 | UndoEvent* UndoQueue::Redo() | ||||||||||
298 | { | ||||||||||
299 | UndoEvent *returned_event = NULL__null; | ||||||||||
300 | if (current_event == NULL__null) | ||||||||||
301 | returned_event = current_event = first_event; | ||||||||||
302 | else { | ||||||||||
303 | if (current_event->next_event != NULL__null) { | ||||||||||
304 | current_event = current_event->next_event; | ||||||||||
305 | returned_event = current_event; | ||||||||||
306 | } | ||||||||||
307 | } | ||||||||||
308 | UpdateMenuItems(); | ||||||||||
309 | return returned_event; | ||||||||||
310 | } | ||||||||||
311 | |||||||||||
312 | |||||||||||
313 | |||||||||||
314 | const char* UndoQueue::ReturnUndoEventName() | ||||||||||
315 | { | ||||||||||
316 | const char *name = NULL__null; | ||||||||||
317 | |||||||||||
318 | UndoEvent *named_event = current_event; | ||||||||||
319 | if (named_event != NULL__null) { | ||||||||||
320 | UndoAction **actions = named_event->ReturnActions(); | ||||||||||
321 | if (actions != NULL__null) { | ||||||||||
322 | if ((named_event->ActionCount() > 1) || (actions[0]->type != ADD_LAYER_ACTION)) { | ||||||||||
323 | name = named_event->ReturnName(); | ||||||||||
324 | } | ||||||||||
325 | } | ||||||||||
326 | else | ||||||||||
327 | name = named_event->ReturnName(); | ||||||||||
328 | } | ||||||||||
329 | |||||||||||
330 | return name; | ||||||||||
331 | } | ||||||||||
332 | |||||||||||
333 | |||||||||||
334 | const char* UndoQueue::ReturnRedoEventName() | ||||||||||
335 | { | ||||||||||
336 | const char *name = NULL__null; | ||||||||||
337 | |||||||||||
338 | UndoEvent *named_event; | ||||||||||
339 | if (current_event != NULL__null) { | ||||||||||
340 | named_event = current_event->next_event; | ||||||||||
341 | } | ||||||||||
342 | else | ||||||||||
343 | named_event = first_event; | ||||||||||
344 | |||||||||||
345 | if (named_event != NULL__null) | ||||||||||
346 | name = named_event->ReturnName(); | ||||||||||
347 | |||||||||||
348 | return name; | ||||||||||
349 | } | ||||||||||
350 | |||||||||||
351 | |||||||||||
352 | |||||||||||
353 | void UndoQueue::UpdateMenuItems() | ||||||||||
354 | { | ||||||||||
355 | const char *event_name; | ||||||||||
356 | event_name = ReturnUndoEventName(); | ||||||||||
357 | |||||||||||
358 | if (undo_menu_item != NULL__null) { | ||||||||||
359 | if (event_name != NULL__null) { | ||||||||||
360 | char menu_text[256]; | ||||||||||
361 | sprintf(menu_text,"%s %s",B_TRANSLATE("Undo")BLocaleRoster::Default()->GetCatalog()->GetString(("Undo" ), "UndoQueue"),event_name); | ||||||||||
362 | undo_menu_item->SetLabel(menu_text); | ||||||||||
363 | undo_menu_item->SetEnabled(TRUE1); | ||||||||||
364 | } | ||||||||||
365 | else { | ||||||||||
366 | undo_menu_item->SetLabel(B_TRANSLATE("Undo not available")BLocaleRoster::Default()->GetCatalog()->GetString(("Undo not available" ), "UndoQueue")); | ||||||||||
367 | undo_menu_item->SetEnabled(FALSE0); | ||||||||||
368 | } | ||||||||||
369 | } | ||||||||||
370 | |||||||||||
371 | event_name = ReturnRedoEventName(); | ||||||||||
372 | if (redo_menu_item != NULL__null) { | ||||||||||
373 | if (event_name != NULL__null) { | ||||||||||
374 | char menu_text[256]; | ||||||||||
375 | sprintf(menu_text,"%s %s",B_TRANSLATE("Redo")BLocaleRoster::Default()->GetCatalog()->GetString(("Redo" ), "UndoQueue"),event_name); | ||||||||||
376 | redo_menu_item->SetLabel(menu_text); | ||||||||||
377 | redo_menu_item->SetEnabled(TRUE1); | ||||||||||
378 | } | ||||||||||
379 | else { | ||||||||||
380 | redo_menu_item->SetLabel(B_TRANSLATE("Redo not available")BLocaleRoster::Default()->GetCatalog()->GetString(("Redo not available" ), "UndoQueue")); | ||||||||||
381 | redo_menu_item->SetEnabled(FALSE0); | ||||||||||
382 | } | ||||||||||
383 | } | ||||||||||
384 | } | ||||||||||
385 | |||||||||||
386 | |||||||||||
387 | void UndoQueue::SetMenuItems(BMenuItem *undo_item,BMenuItem *redo_item) | ||||||||||
388 | { | ||||||||||
389 | undo_menu_item = undo_item; | ||||||||||
390 | redo_menu_item = redo_item; | ||||||||||
391 | UpdateMenuItems(); | ||||||||||
392 | } | ||||||||||
393 | |||||||||||
394 | |||||||||||
395 | void UndoQueue::HandleLowMemorySituation() | ||||||||||
396 | { | ||||||||||
397 | BAlert *memory_alert = new BAlert("memory_alert", B_TRANSLATE(BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue") | ||||||||||
398 | "The undo-mechanism has run out of memory.\n"BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue") | ||||||||||
399 | "The depth of undo will be limited so that the most recent events can be kept in memory. "BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue") | ||||||||||
400 | "It is advisable to save your work at this point to avoid any loss of data in case the "BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue") | ||||||||||
401 | "memory runs out completely.\n"BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue") | ||||||||||
402 | "You may also want to adjust the undo-depth in the settings-window.")BLocaleRoster::Default()->GetCatalog()->GetString(("The undo-mechanism has run out of memory.\n" "The depth of undo will be limited so that the most recent events can be kept in memory. " "It is advisable to save your work at this point to avoid any loss of data in case the " "memory runs out completely.\n" "You may also want to adjust the undo-depth in the settings-window." ), "UndoQueue"), | ||||||||||
403 | B_TRANSLATE("Bummer")BLocaleRoster::Default()->GetCatalog()->GetString(("Bummer" ), "UndoQueue"), NULL__null, NULL__null, B_WIDTH_AS_USUAL,B_WARNING_ALERT); | ||||||||||
404 | memory_alert->Go(); | ||||||||||
405 | |||||||||||
406 | // We may have to delete either redo-events or undo-events. Currently this function is called | ||||||||||
407 | // only when there are no redo events so we only delete undo-events. This may change in the | ||||||||||
408 | // future however. | ||||||||||
409 | int32 deleted_event_count = 0; | ||||||||||
410 | UndoEvent *deleted_event = first_event; | ||||||||||
411 | while ((deleted_event_count < 5) && (deleted_event != NULL__null) && (deleted_event != current_event)) { | ||||||||||
412 | first_event = deleted_event->next_event; | ||||||||||
413 | first_event->previous_event = NULL__null; | ||||||||||
414 | delete deleted_event; | ||||||||||
415 | deleted_event = first_event; | ||||||||||
416 | deleted_event_count++; | ||||||||||
417 | current_queue_depth--; | ||||||||||
418 | } | ||||||||||
419 | } | ||||||||||
420 | |||||||||||
421 | |||||||||||
422 | void | ||||||||||
423 | UndoQueue::SetQueueDepth(int32 depth) | ||||||||||
424 | { | ||||||||||
425 | if ((depth != INFINITE_QUEUE_DEPTH-1) | ||||||||||
| |||||||||||
426 | && ((depth < maximum_queue_depth) | ||||||||||
427 | || (maximum_queue_depth == INFINITE_QUEUE_DEPTH-1))) { | ||||||||||
428 | maximum_queue_depth = depth; | ||||||||||
429 | for (int32 i = 0; i < queue_list->CountItems(); i++) { | ||||||||||
430 | UndoQueue *queue = (UndoQueue*)queue_list->ItemAt(i); | ||||||||||
431 | queue->TruncateQueue(); | ||||||||||
432 | } | ||||||||||
433 | } | ||||||||||
434 | |||||||||||
435 | if ((maximum_queue_depth == 0) && (depth != 0)) { | ||||||||||
436 | maximum_queue_depth = depth; | ||||||||||
437 | for (int32 i = 0; i < queue_list->CountItems(); i++) { | ||||||||||
438 | UndoQueue *queue = (UndoQueue*)queue_list->ItemAt(i); | ||||||||||
439 | queue->image_view->ReturnImage()->RegisterLayersWithUndo(); | ||||||||||
440 | } | ||||||||||
441 | } | ||||||||||
442 | |||||||||||
443 | maximum_queue_depth = depth; | ||||||||||
444 | |||||||||||
445 | if (SettingsServer* server = SettingsServer::Instance()) | ||||||||||
446 | server->SetValue(SettingsServer::Application, skUndoQueueDepth, depth); | ||||||||||
447 | } | ||||||||||
448 | |||||||||||
449 | |||||||||||
450 | void | ||||||||||
451 | UndoQueue::TruncateQueue() | ||||||||||
452 | { | ||||||||||
453 | if ((maximum_queue_depth != INFINITE_QUEUE_DEPTH-1) && (current_queue_depth > maximum_queue_depth)) { | ||||||||||
454 | while (current_queue_depth > maximum_queue_depth
| ||||||||||
455 | // We should remove the events so that the nearest events to the current | ||||||||||
456 | // event from both sides are removed last, and the furthest away events | ||||||||||
457 | // first. If needed the actual current event is then removed at the end. | ||||||||||
458 | |||||||||||
459 | // search the furhest away event from the current_event, or if current event | ||||||||||
460 | // is NULL, from the first_event. If both are NULL, put the current_queue_length to | ||||||||||
461 | // zero. | ||||||||||
462 | UndoEvent *furthest_event = NULL__null; | ||||||||||
463 | if (current_event
| ||||||||||
464 | UndoEvent *redo_direction=current_event; | ||||||||||
465 | UndoEvent *undo_direction=current_event; | ||||||||||
466 | while ((undo_direction
| ||||||||||
467 | undo_direction = undo_direction->previous_event; | ||||||||||
468 | redo_direction = redo_direction->next_event; | ||||||||||
469 | } | ||||||||||
470 | if (undo_direction
| ||||||||||
471 | while (undo_direction->previous_event != NULL__null) | ||||||||||
472 | undo_direction = undo_direction->previous_event; | ||||||||||
473 | furthest_event = undo_direction; | ||||||||||
474 | } | ||||||||||
475 | else if (redo_direction
| ||||||||||
476 | while (redo_direction->next_event != NULL__null) | ||||||||||
| |||||||||||
477 | redo_direction = redo_direction->next_event; | ||||||||||
478 | furthest_event = redo_direction; | ||||||||||
479 | } | ||||||||||
480 | else | ||||||||||
481 | furthest_event = first_event; | ||||||||||
482 | } | ||||||||||
483 | else if (first_event != NULL__null) { | ||||||||||
484 | furthest_event = first_event; | ||||||||||
485 | while (furthest_event->next_event != NULL__null) | ||||||||||
486 | furthest_event = furthest_event->next_event; | ||||||||||
487 | } | ||||||||||
488 | else | ||||||||||
489 | current_queue_depth = 0; | ||||||||||
490 | |||||||||||
491 | if (furthest_event == first_event) { | ||||||||||
492 | if (first_event != NULL__null) | ||||||||||
493 | first_event = first_event->next_event; | ||||||||||
494 | } | ||||||||||
495 | |||||||||||
496 | if (current_event == furthest_event) | ||||||||||
497 | current_event = NULL__null; | ||||||||||
498 | |||||||||||
499 | |||||||||||
500 | // Here we should unlink the furthest_event and delete it. | ||||||||||
501 | // Also decrease the current undo-depth by one | ||||||||||
502 | if (furthest_event
| ||||||||||
503 | if (furthest_event->next_event
| ||||||||||
504 | furthest_event->next_event->previous_event = furthest_event->previous_event; | ||||||||||
505 | if (furthest_event->previous_event != NULL__null) | ||||||||||
506 | furthest_event->previous_event->next_event = furthest_event->next_event; | ||||||||||
507 | |||||||||||
508 | furthest_event->next_event = NULL__null; | ||||||||||
509 | furthest_event->previous_event = NULL__null; | ||||||||||
510 | |||||||||||
511 | delete furthest_event; | ||||||||||
512 | } | ||||||||||
513 | current_queue_depth--; | ||||||||||
514 | } | ||||||||||
515 | } | ||||||||||
516 | |||||||||||
517 | if (maximum_queue_depth == 0) { | ||||||||||
518 | // Delete everything. | ||||||||||
519 | for (int32 i=0;i<layer_bitmap_count;i++) { | ||||||||||
520 | delete layer_bitmaps[i]; | ||||||||||
521 | layer_bitmaps[i] = NULL__null; | ||||||||||
522 | } | ||||||||||
523 | delete[] layer_bitmaps; | ||||||||||
524 | layer_bitmap_count = 0; | ||||||||||
525 | current_queue_depth = 0; | ||||||||||
526 | layer_bitmaps = NULL__null; | ||||||||||
527 | } | ||||||||||
528 | |||||||||||
529 | UpdateMenuItems(); | ||||||||||
530 | } | ||||||||||
531 | |||||||||||
532 | |||||||||||
533 | void | ||||||||||
534 | UndoQueue::SetSelectionData(const SelectionData *s) | ||||||||||
535 | { | ||||||||||
536 | delete selection_data; | ||||||||||
537 | selection_data = new SelectionData(s); | ||||||||||
538 | } |