Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: chrome/browser/ui/gtk/gtk_tree.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/ui/gtk/gtk_tree.h"
6
7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
10 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "ui/base/models/table_model.h"
12 #include "ui/gfx/gtk_util.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/image/image_skia.h"
15
16 namespace gtk_tree {
17
18 gint GetRowNumForPath(GtkTreePath* path) {
19 gint* indices = gtk_tree_path_get_indices(path);
20 if (!indices) {
21 NOTREACHED();
22 return -1;
23 }
24 return indices[0];
25 }
26
27 gint GetRowNumForIter(GtkTreeModel* model, GtkTreeIter* iter) {
28 GtkTreePath* path = gtk_tree_model_get_path(model, iter);
29 int row = GetRowNumForPath(path);
30 gtk_tree_path_free(path);
31 return row;
32 }
33
34 gint GetTreeSortChildRowNumForPath(GtkTreeModel* sort_model,
35 GtkTreePath* sort_path) {
36 GtkTreePath *child_path = gtk_tree_model_sort_convert_path_to_child_path(
37 GTK_TREE_MODEL_SORT(sort_model), sort_path);
38 int row = GetRowNumForPath(child_path);
39 gtk_tree_path_free(child_path);
40 return row;
41 }
42
43 void SelectAndFocusRowNum(int row, GtkTreeView* tree_view) {
44 GtkTreeModel* model = gtk_tree_view_get_model(tree_view);
45 if (!model) {
46 NOTREACHED();
47 return;
48 }
49 GtkTreeIter iter;
50 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
51 NOTREACHED();
52 return;
53 }
54 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
55 gtk_tree_view_set_cursor(tree_view, path, NULL, FALSE);
56 gtk_tree_path_free(path);
57 }
58
59 bool RemoveRecursively(GtkTreeStore* tree_store, GtkTreeIter* iter) {
60 GtkTreeIter child;
61 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(tree_store), &child, iter)) {
62 while (true) {
63 if (!RemoveRecursively(tree_store, &child))
64 break;
65 }
66 }
67 return gtk_tree_store_remove(tree_store, iter);
68 }
69
70 void GetSelectedIndices(GtkTreeSelection* selection, std::set<int>* out) {
71 GList* list = gtk_tree_selection_get_selected_rows(
72 selection, NULL);
73 GList* node;
74 for (node = list; node != NULL; node = node->next) {
75 out->insert(
76 gtk_tree::GetRowNumForPath(static_cast<GtkTreePath*>(node->data)));
77 }
78 g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL);
79 g_list_free(list);
80 }
81
82 ////////////////////////////////////////////////////////////////////////////////
83 // TableAdapter
84
85 TableAdapter::TableAdapter(Delegate* delegate, GtkListStore* list_store,
86 ui::TableModel* table_model)
87 : delegate_(delegate), list_store_(list_store), table_model_(table_model) {
88 if (table_model)
89 table_model->SetObserver(this);
90 }
91
92 void TableAdapter::SetModel(ui::TableModel* table_model) {
93 table_model_ = table_model;
94 table_model_->SetObserver(this);
95 }
96
97 bool TableAdapter::IsGroupRow(GtkTreeIter* iter) const {
98 if (!table_model_->HasGroups())
99 return false;
100 gboolean is_header = false;
101 gboolean is_separator = false;
102 gtk_tree_model_get(GTK_TREE_MODEL(list_store_),
103 iter,
104 COL_IS_HEADER,
105 &is_header,
106 COL_IS_SEPARATOR,
107 &is_separator,
108 -1);
109 return is_header || is_separator;
110 }
111
112 static int OffsetForGroupIndex(size_t group_index) {
113 // Every group consists of a header and a separator row, and there is a blank
114 // row between groups.
115 return 3 * group_index + 2;
116 }
117
118 void TableAdapter::MapListStoreIndicesToModelRows(
119 const std::set<int>& list_store_indices,
120 RemoveRowsTableModel::Rows* model_rows) {
121 if (!table_model_->HasGroups()) {
122 for (std::set<int>::const_iterator it = list_store_indices.begin();
123 it != list_store_indices.end();
124 ++it) {
125 model_rows->insert(*it);
126 }
127 return;
128 }
129
130 const ui::TableModel::Groups& groups = table_model_->GetGroups();
131 ui::TableModel::Groups::const_iterator group_it = groups.begin();
132 for (std::set<int>::const_iterator list_store_it = list_store_indices.begin();
133 list_store_it != list_store_indices.end();
134 ++list_store_it) {
135 int list_store_index = *list_store_it;
136 GtkTreeIter iter;
137 bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
138 &iter,
139 NULL,
140 list_store_index);
141 if (!rv) {
142 NOTREACHED();
143 return;
144 }
145 int group = -1;
146 gtk_tree_model_get(GTK_TREE_MODEL(list_store_),
147 &iter,
148 COL_GROUP_ID,
149 &group,
150 -1);
151 while (group_it->id != group) {
152 ++group_it;
153 if (group_it == groups.end()) {
154 NOTREACHED();
155 return;
156 }
157 }
158 int offset = OffsetForGroupIndex(group_it - groups.begin());
159 model_rows->insert(list_store_index - offset);
160 }
161 }
162
163 int TableAdapter::GetListStoreIndexForModelRow(int model_row) const {
164 if (!table_model_->HasGroups())
165 return model_row;
166 int group = table_model_->GetGroupID(model_row);
167 const ui::TableModel::Groups& groups = table_model_->GetGroups();
168 for (ui::TableModel::Groups::const_iterator it = groups.begin();
169 it != groups.end(); ++it) {
170 if (it->id == group) {
171 return model_row + OffsetForGroupIndex(it - groups.begin());
172 }
173 }
174 NOTREACHED();
175 return -1;
176 }
177
178 void TableAdapter::AddNodeToList(int row) {
179 GtkTreeIter iter;
180 int list_store_index = GetListStoreIndexForModelRow(row);
181 if (list_store_index == 0) {
182 gtk_list_store_prepend(list_store_, &iter);
183 } else {
184 GtkTreeIter sibling;
185 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &sibling, NULL,
186 list_store_index - 1);
187 gtk_list_store_insert_after(list_store_, &iter, &sibling);
188 }
189
190 if (table_model_->HasGroups()) {
191 gtk_list_store_set(list_store_,
192 &iter,
193 COL_WEIGHT, PANGO_WEIGHT_NORMAL,
194 COL_WEIGHT_SET, TRUE,
195 COL_GROUP_ID, table_model_->GetGroupID(row),
196 -1);
197 }
198 delegate_->SetColumnValues(row, &iter);
199 }
200
201 void TableAdapter::OnModelChanged() {
202 delegate_->OnAnyModelUpdateStart();
203 gtk_list_store_clear(list_store_);
204 delegate_->OnModelChanged();
205
206 if (table_model_->HasGroups()) {
207 const ui::TableModel::Groups& groups = table_model_->GetGroups();
208 for (ui::TableModel::Groups::const_iterator it = groups.begin();
209 it != groups.end(); ++it) {
210 GtkTreeIter iter;
211 if (it != groups.begin()) {
212 // Blank row between groups.
213 gtk_list_store_append(list_store_, &iter);
214 gtk_list_store_set(list_store_, &iter, COL_IS_HEADER, TRUE, -1);
215 }
216 // Group title.
217 gtk_list_store_append(list_store_, &iter);
218 gtk_list_store_set(list_store_,
219 &iter,
220 COL_WEIGHT,
221 PANGO_WEIGHT_BOLD,
222 COL_WEIGHT_SET,
223 TRUE,
224 COL_TITLE,
225 base::UTF16ToUTF8(it->title).c_str(),
226 COL_IS_HEADER,
227 TRUE,
228 -1);
229 // Group separator.
230 gtk_list_store_append(list_store_, &iter);
231 gtk_list_store_set(list_store_,
232 &iter,
233 COL_IS_HEADER,
234 TRUE,
235 COL_IS_SEPARATOR,
236 TRUE,
237 -1);
238 }
239 }
240
241 for (int i = 0; i < table_model_->RowCount(); ++i)
242 AddNodeToList(i);
243 delegate_->OnAnyModelUpdate();
244 }
245
246 void TableAdapter::OnItemsChanged(int start, int length) {
247 if (length == 0)
248 return;
249 delegate_->OnAnyModelUpdateStart();
250 int list_store_index = GetListStoreIndexForModelRow(start);
251 GtkTreeIter iter;
252 bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
253 &iter,
254 NULL,
255 list_store_index);
256 for (int i = 0; i < length; ++i) {
257 if (!rv) {
258 NOTREACHED();
259 return;
260 }
261 while (IsGroupRow(&iter)) {
262 rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
263 if (!rv) {
264 NOTREACHED();
265 return;
266 }
267 }
268 delegate_->SetColumnValues(start + i, &iter);
269 rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
270 }
271 delegate_->OnAnyModelUpdate();
272 }
273
274 void TableAdapter::OnItemsAdded(int start, int length) {
275 delegate_->OnAnyModelUpdateStart();
276 for (int i = 0; i < length; ++i) {
277 AddNodeToList(start + i);
278 }
279 delegate_->OnAnyModelUpdate();
280 }
281
282 void TableAdapter::OnItemsRemoved(int start, int length) {
283 if (length == 0)
284 return;
285 delegate_->OnAnyModelUpdateStart();
286 // When this method is called, the model has already removed the items, so
287 // accessing items in the model from |start| on may not be possible anymore.
288 // Therefore we use the item right before that, if it exists.
289 int list_store_index = 0;
290 if (start > 0)
291 list_store_index = GetListStoreIndexForModelRow(start - 1) + 1;
292 GtkTreeIter iter;
293 bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
294 &iter,
295 NULL,
296 list_store_index);
297 if (!rv) {
298 NOTREACHED();
299 return;
300 }
301 for (int i = 0; i < length; ++i) {
302 while (IsGroupRow(&iter)) {
303 rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
304 if (!rv) {
305 NOTREACHED();
306 return;
307 }
308 }
309 gtk_list_store_remove(list_store_, &iter);
310 }
311 delegate_->OnAnyModelUpdate();
312 }
313
314 // static
315 gboolean TableAdapter::OnCheckRowIsSeparator(GtkTreeModel* model,
316 GtkTreeIter* iter,
317 gpointer user_data) {
318 gboolean is_separator;
319 gtk_tree_model_get(model,
320 iter,
321 COL_IS_SEPARATOR,
322 &is_separator,
323 -1);
324 return is_separator;
325 }
326
327 // static
328 gboolean TableAdapter::OnSelectionFilter(GtkTreeSelection* selection,
329 GtkTreeModel* model,
330 GtkTreePath* path,
331 gboolean path_currently_selected,
332 gpointer user_data) {
333 GtkTreeIter iter;
334 if (!gtk_tree_model_get_iter(model, &iter, path)) {
335 NOTREACHED();
336 return TRUE;
337 }
338 gboolean is_header;
339 gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header, -1);
340 return !is_header;
341 }
342
343 ////////////////////////////////////////////////////////////////////////////////
344 // TreeAdapter
345
346 TreeAdapter::TreeAdapter(Delegate* delegate, ui::TreeModel* tree_model)
347 : delegate_(delegate),
348 tree_model_(tree_model) {
349 tree_store_ = gtk_tree_store_new(COL_COUNT,
350 GDK_TYPE_PIXBUF,
351 G_TYPE_STRING,
352 G_TYPE_POINTER);
353 tree_model->AddObserver(this);
354
355 std::vector<gfx::ImageSkia> icons;
356 tree_model->GetIcons(&icons);
357 for (size_t i = 0; i < icons.size(); ++i) {
358 pixbufs_.push_back(gfx::GdkPixbufFromSkBitmap(*icons[i].bitmap()));
359 }
360 }
361
362 TreeAdapter::~TreeAdapter() {
363 g_object_unref(tree_store_);
364 for (size_t i = 0; i < pixbufs_.size(); ++i)
365 g_object_unref(pixbufs_[i]);
366 }
367
368 void TreeAdapter::Init() {
369 gtk_tree_store_clear(tree_store_);
370 Fill(NULL, tree_model_->GetRoot());
371 }
372
373
374 ui::TreeModelNode* TreeAdapter::GetNode(GtkTreeIter* iter) {
375 ui::TreeModelNode* node;
376 gtk_tree_model_get(GTK_TREE_MODEL(tree_store_), iter,
377 COL_NODE_PTR, &node,
378 -1);
379 return node;
380 }
381
382 void TreeAdapter::FillRow(GtkTreeIter* iter, ui::TreeModelNode* node) {
383 GdkPixbuf* pixbuf = NULL;
384 int icon_index = tree_model_->GetIconIndex(node);
385 if (icon_index >= 0 && icon_index < static_cast<int>(pixbufs_.size()))
386 pixbuf = pixbufs_[icon_index];
387 else
388 pixbuf = GtkThemeService::GetFolderIcon(true).ToGdkPixbuf();
389 gtk_tree_store_set(tree_store_, iter,
390 COL_ICON, pixbuf,
391 COL_TITLE, base::UTF16ToUTF8(node->GetTitle()).c_str(),
392 COL_NODE_PTR, node,
393 -1);
394 }
395
396 void TreeAdapter::Fill(GtkTreeIter* parent_iter,
397 ui::TreeModelNode* parent_node) {
398 if (parent_iter)
399 FillRow(parent_iter, parent_node);
400 GtkTreeIter iter;
401 int child_count = tree_model_->GetChildCount(parent_node);
402 for (int i = 0; i < child_count; ++i) {
403 ui::TreeModelNode* node = tree_model_->GetChild(parent_node, i);
404 gtk_tree_store_append(tree_store_, &iter, parent_iter);
405 Fill(&iter, node);
406 }
407 }
408
409 GtkTreePath* TreeAdapter::GetTreePath(ui::TreeModelNode* node) {
410 GtkTreePath* path = gtk_tree_path_new();
411 ui::TreeModelNode* parent = node;
412 while (parent) {
413 parent = tree_model_->GetParent(parent);
414 if (parent) {
415 int idx = tree_model_->GetIndexOf(parent, node);
416 gtk_tree_path_prepend_index(path, idx);
417 node = parent;
418 }
419 }
420 return path;
421 }
422
423 bool TreeAdapter::GetTreeIter(ui::TreeModelNode* node, GtkTreeIter* iter) {
424 GtkTreePath* path = GetTreePath(node);
425 bool rv = false;
426 // Check the path ourselves since gtk_tree_model_get_iter prints a warning if
427 // given an empty path. The path will be empty when it points to the root
428 // node and we are using SetRootShown(false).
429 if (gtk_tree_path_get_depth(path) > 0)
430 rv = gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store_), iter, path);
431 gtk_tree_path_free(path);
432 return rv;
433 }
434
435 void TreeAdapter::TreeNodesAdded(ui::TreeModel* model,
436 ui::TreeModelNode* parent,
437 int start,
438 int count) {
439 delegate_->OnAnyModelUpdateStart();
440 GtkTreeIter parent_iter;
441 GtkTreeIter* parent_iter_ptr = NULL;
442 GtkTreeIter iter;
443 if (GetTreeIter(parent, &parent_iter))
444 parent_iter_ptr = &parent_iter;
445 for (int i = 0; i < count; ++i) {
446 gtk_tree_store_insert(tree_store_, &iter, parent_iter_ptr, start + i);
447 Fill(&iter, tree_model_->GetChild(parent, start + i));
448 }
449 delegate_->OnAnyModelUpdate();
450 }
451
452 void TreeAdapter::TreeNodesRemoved(ui::TreeModel* model,
453 ui::TreeModelNode* parent,
454 int start,
455 int count) {
456 delegate_->OnAnyModelUpdateStart();
457 GtkTreeIter iter;
458 GtkTreePath* path = GetTreePath(parent);
459 gtk_tree_path_append_index(path, start);
460 gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store_), &iter, path);
461 gtk_tree_path_free(path);
462 for (int i = 0; i < count; ++i) {
463 RemoveRecursively(tree_store_, &iter);
464 }
465 delegate_->OnAnyModelUpdate();
466 }
467
468 void TreeAdapter::TreeNodeChanged(ui::TreeModel* model,
469 ui::TreeModelNode* node) {
470 delegate_->OnAnyModelUpdateStart();
471 GtkTreeIter iter;
472 if (GetTreeIter(node, &iter))
473 FillRow(&iter, node);
474 delegate_->OnAnyModelUpdate();
475 }
476
477 } // namespace gtk_tree
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698