OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/undo/bookmark_undo_service.h" | |
6 | |
7 #include "chrome/browser/bookmarks/bookmark_model.h" | |
8 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
9 #include "chrome/browser/bookmarks/bookmark_node_data.h" | |
10 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/browser/undo/bookmark_undo_service_factory.h" | |
13 #include "chrome/browser/undo/undo_manager_utils.h" | |
14 #include "chrome/browser/undo/undo_operation.h" | |
15 | |
16 namespace { | |
17 | |
18 // BookmarkUndoOperation ------------------------------------------------------ | |
19 | |
20 // Base class for all bookmark related UndoOperations that facilitates access to | |
21 // the BookmarkUndoService. | |
22 class BookmarkUndoOperation : public UndoOperation { | |
23 public: | |
24 explicit BookmarkUndoOperation(Profile* profile); | |
25 virtual ~BookmarkUndoOperation() {} | |
26 | |
27 // If a bookmark node id is renumbered due to an undo operation, the | |
28 // BookmarkUndoOperation should be updated with the new id in order to | |
29 // properly locate the bookmark node during execution of Undo. | |
30 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) = 0; | |
31 | |
32 BookmarkModel* GetBookmarkModel() const; | |
33 BookmarkUndoService* GetBookmarkUndoService() const; | |
34 | |
35 private: | |
36 Profile* profile_; | |
37 }; | |
38 | |
39 BookmarkUndoOperation::BookmarkUndoOperation(Profile* profile) | |
40 : profile_(profile) { | |
41 } | |
42 | |
43 BookmarkModel* BookmarkUndoOperation::GetBookmarkModel() const { | |
44 return BookmarkModelFactory::GetForProfile(profile_); | |
45 } | |
46 | |
47 BookmarkUndoService* BookmarkUndoOperation::GetBookmarkUndoService() const { | |
48 return BookmarkUndoServiceFactory::GetForProfile(profile_); | |
49 } | |
50 | |
51 // BookmarkAddOperation ------------------------------------------------------- | |
52 | |
53 // Handles the undo of the insertion of a bookmark or folder. | |
54 class BookmarkAddOperation : public BookmarkUndoOperation { | |
55 public: | |
56 BookmarkAddOperation(Profile* profile, const BookmarkNode* parent, int index); | |
57 virtual ~BookmarkAddOperation() {} | |
58 | |
59 // UndoOperation: | |
60 virtual void Undo() OVERRIDE; | |
61 | |
62 // BookmarkUndoOperation: | |
63 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
64 | |
65 private: | |
66 int64 parent_id_; | |
67 const int index_; | |
68 | |
69 DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation); | |
70 }; | |
71 | |
72 BookmarkAddOperation::BookmarkAddOperation(Profile* profile, | |
73 const BookmarkNode* parent, | |
74 int index) | |
75 : BookmarkUndoOperation(profile), | |
76 parent_id_(parent->id()), | |
77 index_(index) { | |
78 } | |
79 | |
80 void BookmarkAddOperation::Undo() { | |
81 BookmarkModel* model = GetBookmarkModel(); | |
82 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
83 DCHECK(parent); | |
84 | |
85 model->Remove(parent, index_); | |
86 } | |
87 | |
88 void BookmarkAddOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
89 if (parent_id_ == old_id) | |
90 parent_id_ = new_id; | |
91 } | |
92 | |
93 // BookmarkRemoveOperation ---------------------------------------------------- | |
94 | |
95 // Handles the undo of the deletion of a bookmark node. For a bookmark folder, | |
96 // the information for all descendant bookmark nodes is maintained. | |
97 // | |
98 // The BookmarkModel allows only single bookmark node to be removed. | |
99 class BookmarkRemoveOperation : public BookmarkUndoOperation { | |
100 public: | |
101 BookmarkRemoveOperation(Profile* profile, | |
102 const BookmarkNode* parent, | |
103 int old_index, | |
104 const BookmarkNode* node); | |
105 virtual ~BookmarkRemoveOperation() {} | |
106 | |
107 // UndoOperation: | |
108 virtual void Undo() OVERRIDE; | |
109 | |
110 // BookmarkUndoOperation: | |
111 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
112 | |
113 private: | |
114 void UpdateBookmarkIds(const BookmarkNodeData::Element& element, | |
115 const BookmarkNode* parent, | |
116 int index_added_at) const; | |
117 | |
118 int64 parent_id_; | |
119 const int old_index_; | |
120 BookmarkNodeData removed_node_; | |
121 | |
122 DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation); | |
123 }; | |
124 | |
125 BookmarkRemoveOperation::BookmarkRemoveOperation(Profile* profile, | |
126 const BookmarkNode* parent, | |
127 int old_index, | |
128 const BookmarkNode* node) | |
129 : BookmarkUndoOperation(profile), | |
130 parent_id_(parent->id()), | |
131 old_index_(old_index), | |
132 removed_node_(node) { | |
133 } | |
134 | |
135 void BookmarkRemoveOperation::Undo() { | |
136 DCHECK(removed_node_.is_valid()); | |
137 BookmarkModel* model = GetBookmarkModel(); | |
138 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
139 DCHECK(parent); | |
140 | |
141 bookmark_utils::CloneBookmarkNode(model, removed_node_.elements, parent, | |
142 old_index_, false); | |
143 UpdateBookmarkIds(removed_node_.elements[0], parent, old_index_); | |
144 } | |
145 | |
146 void BookmarkRemoveOperation::UpdateBookmarkIds( | |
147 const BookmarkNodeData::Element& element, | |
148 const BookmarkNode* parent, | |
149 int index_added_at) const { | |
150 BookmarkModel* model = GetBookmarkModel(); | |
151 BookmarkUndoService* undo_service = GetBookmarkUndoService(); | |
152 | |
153 const BookmarkNode* node = parent->GetChild(index_added_at); | |
154 if (element.id() != node->id()) | |
155 undo_service->OnBookmarkRenumbered(element.id(), node->id()); | |
156 | |
157 if (!element.is_url) { | |
158 for (int i = 0; i < static_cast<int>(element.children.size()); ++i) | |
159 UpdateBookmarkIds(element.children[i], node, 0); | |
160 } | |
161 } | |
162 | |
163 void BookmarkRemoveOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
164 if (parent_id_ == old_id) | |
165 parent_id_ = new_id; | |
166 } | |
167 | |
168 // BookmarkEditOperation ------------------------------------------------------ | |
169 | |
170 // Handles the undo of the modification of a bookmark node. | |
171 class BookmarkEditOperation : public BookmarkUndoOperation { | |
172 public: | |
173 BookmarkEditOperation(Profile* profile, | |
174 const BookmarkNode* node); | |
175 virtual ~BookmarkEditOperation() {} | |
176 | |
177 // UndoOperation: | |
178 virtual void Undo() OVERRIDE; | |
179 | |
180 // BookmarkUndoOperation: | |
181 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
182 | |
183 private: | |
184 int64 node_id_; | |
185 BookmarkNodeData original_bookmark_; | |
186 | |
187 DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation); | |
188 }; | |
189 | |
190 BookmarkEditOperation::BookmarkEditOperation(Profile* profile, | |
191 const BookmarkNode* node) | |
192 : BookmarkUndoOperation(profile), | |
193 node_id_(node->id()), | |
194 original_bookmark_(node) { | |
195 } | |
196 | |
197 void BookmarkEditOperation::Undo() { | |
198 DCHECK(original_bookmark_.is_valid()); | |
199 BookmarkModel* model = GetBookmarkModel(); | |
200 const BookmarkNode* node = model->GetNodeByID(node_id_); | |
201 DCHECK(node); | |
202 | |
203 model->SetTitle(node, original_bookmark_.elements[0].title); | |
204 if (original_bookmark_.elements[0].is_url) | |
205 model->SetURL(node, original_bookmark_.elements[0].url); | |
sky
2013/08/27 22:24:18
nit: spacing is off.
Tom Cassiotis
2013/09/04 13:44:43
Done.
| |
206 } | |
207 | |
208 void BookmarkEditOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
209 if (node_id_ == old_id) | |
210 node_id_ = new_id; | |
211 } | |
212 | |
213 // BookmarkMoveOperation ------------------------------------------------------ | |
214 | |
215 // Handles the undo of a bookmark being moved to a new location. | |
216 class BookmarkMoveOperation : public BookmarkUndoOperation { | |
217 public: | |
218 BookmarkMoveOperation(Profile* profile, | |
219 const BookmarkNode* old_parent, | |
220 int old_index, | |
221 const BookmarkNode* new_parent, | |
222 int new_index); | |
223 virtual ~BookmarkMoveOperation() {} | |
224 | |
225 // UndoOperation: | |
226 virtual void Undo() OVERRIDE; | |
227 | |
228 // BookmarkUndoOperation: | |
229 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
230 | |
231 private: | |
232 int64 old_parent_id_; | |
233 int64 new_parent_id_; | |
234 int old_index_; | |
235 int new_index_; | |
236 | |
237 DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation); | |
238 }; | |
239 | |
240 BookmarkMoveOperation::BookmarkMoveOperation(Profile* profile, | |
241 const BookmarkNode* old_parent, | |
242 int old_index, | |
243 const BookmarkNode* new_parent, | |
244 int new_index) | |
245 : BookmarkUndoOperation(profile), | |
246 old_parent_id_(old_parent->id()), | |
247 old_index_(old_index), | |
248 new_parent_id_(new_parent->id()), | |
249 new_index_(new_index) { | |
250 } | |
251 | |
252 void BookmarkMoveOperation::Undo() { | |
253 BookmarkModel* model = GetBookmarkModel(); | |
254 const BookmarkNode* old_parent = model->GetNodeByID(old_parent_id_); | |
255 const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id_); | |
256 DCHECK(old_parent); | |
257 DCHECK(new_parent); | |
258 | |
259 const BookmarkNode* node = new_parent->GetChild(new_index_); | |
260 int destination_index = old_index_; | |
261 | |
262 // If the bookmark was moved up within the same parent then the destination | |
263 // index needs to be incremented since the old index did not account for the | |
264 // moved bookmark. | |
265 if (old_parent == new_parent && new_index_ < old_index_) | |
266 ++destination_index; | |
267 | |
268 model->Move(node, old_parent, destination_index); | |
269 } | |
270 | |
271 void BookmarkMoveOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
272 if (old_parent_id_ == old_id) | |
273 old_parent_id_ = new_id; | |
274 if (new_parent_id_ == old_id) | |
275 new_parent_id_ = new_id; | |
276 } | |
277 | |
278 // BookmarkReorderOperation --------------------------------------------------- | |
279 | |
280 // Handle the undo of reordering of bookmarks that can happen as a result of | |
281 // sorting a bookmark folder by name or the undo of that operation. The change | |
282 // of order is not recursive so only the order of the immediate children of the | |
283 // folder need to be restored. | |
284 class BookmarkReorderOperation : public BookmarkUndoOperation { | |
285 public: | |
286 BookmarkReorderOperation(Profile* profile, | |
287 const BookmarkNode* parent); | |
288 virtual ~BookmarkReorderOperation(); | |
289 | |
290 // UndoOperation: | |
291 virtual void Undo() OVERRIDE; | |
292 | |
293 // BookmarkUndoOperation: | |
294 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
295 | |
296 private: | |
297 int64 parent_id_; | |
298 std::vector<int64> ordered_bookmarks_; | |
299 | |
300 DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation); | |
301 }; | |
302 | |
303 BookmarkReorderOperation::BookmarkReorderOperation(Profile* profile, | |
304 const BookmarkNode* parent) | |
305 : BookmarkUndoOperation(profile), | |
306 parent_id_(parent->id()) { | |
307 ordered_bookmarks_.resize(parent->child_count()); | |
308 for (int i = 0; i < parent->child_count(); ++i) | |
309 ordered_bookmarks_[i] = parent->GetChild(i)->id(); | |
310 } | |
311 | |
312 BookmarkReorderOperation::~BookmarkReorderOperation() { | |
313 } | |
314 | |
315 void BookmarkReorderOperation::Undo() { | |
316 BookmarkModel* model = GetBookmarkModel(); | |
317 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
318 DCHECK(parent); | |
319 | |
320 std::vector<const BookmarkNode*> ordered_nodes; | |
321 for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) | |
322 ordered_nodes.push_back(model->GetNodeByID(ordered_bookmarks_[i])); | |
323 | |
324 model->ReorderChildren(parent, ordered_nodes); | |
325 } | |
326 | |
327 void BookmarkReorderOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
328 if (parent_id_ == old_id) | |
329 parent_id_ = new_id; | |
330 for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) { | |
331 if (ordered_bookmarks_[i] == old_id) | |
332 ordered_bookmarks_[i] = new_id; | |
333 } | |
334 } | |
335 | |
336 } // namespace | |
337 | |
338 // BookmarkUndoService -------------------------------------------------------- | |
339 | |
340 BookmarkUndoService::BookmarkUndoService(Profile* profile) : profile_(profile) { | |
341 BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); | |
342 } | |
343 | |
344 BookmarkUndoService::~BookmarkUndoService() { | |
345 BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); | |
346 } | |
347 | |
348 void BookmarkUndoService::OnBookmarkRenumbered(int64 old_id, int64 new_id) { | |
349 std::vector<UndoOperation*> all_operations = | |
350 undo_manager()->GetAllUndoOperations(); | |
351 for (std::vector<UndoOperation*>::iterator it = all_operations.begin(); | |
352 it != all_operations.end(); ++it) { | |
353 static_cast<BookmarkUndoOperation*>(*it)->RenumberBookmarkId(old_id, | |
354 new_id); | |
355 } | |
356 } | |
357 | |
358 void BookmarkUndoService::Loaded(BookmarkModel* model, bool ids_reassigned) { | |
359 undo_manager_.RemoveAllOperations(); | |
360 } | |
361 | |
362 void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel* model) { | |
363 undo_manager_.RemoveAllOperations(); | |
364 } | |
365 | |
366 void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel* model, | |
367 const BookmarkNode* old_parent, | |
368 int old_index, | |
369 const BookmarkNode* new_parent, | |
370 int new_index) { | |
371 scoped_ptr<UndoOperation> op(new BookmarkMoveOperation(profile_, | |
372 old_parent, | |
373 old_index, | |
374 new_parent, | |
375 new_index)); | |
376 undo_manager()->AddUndoOperation(op.Pass()); | |
377 } | |
378 | |
379 void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, | |
380 const BookmarkNode* parent, | |
381 int index) { | |
382 scoped_ptr<UndoOperation> op(new BookmarkAddOperation(profile_, | |
383 parent, | |
384 index)); | |
385 undo_manager()->AddUndoOperation(op.Pass()); | |
386 } | |
387 | |
388 void BookmarkUndoService::OnWillRemoveBookmarks(BookmarkModel* model, | |
389 const BookmarkNode* parent, | |
390 int old_index, | |
391 const BookmarkNode* node) { | |
392 scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, | |
393 parent, | |
394 old_index, | |
395 node)); | |
396 undo_manager()->AddUndoOperation(op.Pass()); | |
397 } | |
398 | |
399 void BookmarkUndoService::OnWillRemoveAllBookmarks(BookmarkModel* model) { | |
400 ScopedGroupingAction merge_removes(undo_manager()); | |
401 for (int i = 0; i < model->root_node()->child_count(); ++i) { | |
402 const BookmarkNode* permanent_node = model->root_node()->GetChild(i); | |
403 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { | |
404 scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, | |
405 permanent_node, j, permanent_node->GetChild(j))); | |
406 undo_manager()->AddUndoOperation(op.Pass()); | |
407 } | |
408 } | |
409 } | |
410 | |
411 void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel* model, | |
412 const BookmarkNode* node) { | |
413 scoped_ptr<UndoOperation> op(new BookmarkEditOperation(profile_, node)); | |
414 undo_manager()->AddUndoOperation(op.Pass()); | |
415 } | |
416 | |
417 void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel* model, | |
418 const BookmarkNode* node) { | |
419 scoped_ptr<UndoOperation> op(new BookmarkReorderOperation(profile_, node)); | |
420 undo_manager()->AddUndoOperation(op.Pass()); | |
421 } | |
OLD | NEW |