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

Side by Side Diff: views/controls/table/native_table_gtk.cc

Issue 8655001: views: Move table and tree directories to ui/views/controls/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: exclude native_widget_win_unittest too Created 9 years, 1 month 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
« no previous file with comments | « views/controls/table/native_table_gtk.h ('k') | views/controls/table/native_table_win.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "views/controls/table/native_table_gtk.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "base/utf_string_conversions.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "ui/gfx/gtk_util.h"
13 #include "ui/views/widget/widget.h"
14 #include "views/controls/table/table_view2.h"
15 #include "views/controls/table/table_view_observer.h"
16
17 namespace views {
18
19 ////////////////////////////////////////////////////////////////////////////////
20 // NativeTableGtk, public:
21
22 NativeTableGtk::NativeTableGtk(TableView2* table)
23 : table_(table),
24 gtk_model_(NULL),
25 tree_view_(NULL),
26 tree_selection_(NULL) {
27 // Associates the actual GtkWidget with the table so the table is the one
28 // considered as having the focus (not the wrapper) when the HWND is
29 // focused directly (with a click for example).
30 set_focus_view(table);
31 }
32
33 NativeTableGtk::~NativeTableGtk() {
34 }
35
36 ////////////////////////////////////////////////////////////////////////////////
37 // NativeTableGtk, NativeTableWrapper implementation:
38
39 int NativeTableGtk::GetRowCount() const {
40 if (!tree_view_)
41 return 0;
42
43 GtkTreeIter iter;
44 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(gtk_model_), &iter))
45 return 0; // Empty tree.
46
47 int count = 1;
48 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(gtk_model_), &iter))
49 count++;
50 return count;
51 }
52
53 View* NativeTableGtk::GetView() {
54 return this;
55 }
56
57 void NativeTableGtk::SetFocus() {
58 // Focus the associated widget.
59 OnFocus();
60 }
61
62 gfx::NativeView NativeTableGtk::GetTestingHandle() const {
63 // Note that we are returning the tree view, not the scrolled window as
64 // arguably the tests need to access the tree view.
65 return GTK_WIDGET(tree_view_);
66 }
67
68 void NativeTableGtk::InsertColumn(const ui::TableColumn& column, int index) {
69 NOTIMPLEMENTED();
70 }
71
72 void NativeTableGtk::RemoveColumn(int column_index) {
73 if (!native_view())
74 return;
75
76 GtkTreeViewColumn* column = gtk_tree_view_get_column(tree_view_,
77 column_index);
78 if (column) {
79 gtk_tree_view_remove_column(tree_view_, column);
80
81 if (table_->model()->RowCount() > 0)
82 OnRowsChanged(0, table_->model()->RowCount() - 1);
83 }
84 }
85
86 int NativeTableGtk::GetColumnWidth(int column_index) const {
87 GtkTreeViewColumn* column = gtk_tree_view_get_column(tree_view_,
88 column_index);
89 return column ? gtk_tree_view_column_get_width(column) : -1;
90 }
91
92 void NativeTableGtk::SetColumnWidth(int column_index, int width) {
93 GtkTreeViewColumn* column = gtk_tree_view_get_column(tree_view_,
94 column_index);
95 column->width = width;
96 column->resized_width = width;
97 column->use_resized_width = TRUE;
98 // Needed for use_resized_width to be effective.
99 gtk_widget_queue_resize(GTK_WIDGET(tree_view_));
100 }
101
102 int NativeTableGtk::GetSelectedRowCount() const {
103 return gtk_tree_selection_count_selected_rows(tree_selection_);
104 }
105
106 int NativeTableGtk::GetFirstSelectedRow() const {
107 int result = -1;
108 GList* selected_rows =
109 gtk_tree_selection_get_selected_rows(tree_selection_, NULL);
110 if (g_list_length(selected_rows) > 0) {
111 GtkTreePath* tree_path =
112 static_cast<GtkTreePath*>(g_list_first(selected_rows)->data);
113 gint* indices = gtk_tree_path_get_indices(tree_path);
114 CHECK(indices);
115 result = indices[0];
116 }
117
118 g_list_foreach(selected_rows, reinterpret_cast<GFunc>(gtk_tree_path_free),
119 NULL);
120 g_list_free(selected_rows);
121 return result;
122 }
123
124 int NativeTableGtk::GetFirstFocusedRow() const {
125 NOTIMPLEMENTED();
126 return -1;
127 }
128
129 bool NativeTableGtk::IsRowFocused(int model_row) const {
130 NOTIMPLEMENTED();
131 return false;
132 }
133
134 void NativeTableGtk::ClearRowFocus() {
135 NOTIMPLEMENTED();
136 }
137
138 void NativeTableGtk::ClearSelection() {
139 gtk_tree_selection_unselect_all(tree_selection_);
140 }
141
142 void NativeTableGtk::SetSelectedState(int model_row, bool state) {
143 GtkTreeIter iter;
144 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtk_model_), &iter, NULL,
145 model_row)) {
146 NOTREACHED();
147 return;
148 }
149 if (state)
150 gtk_tree_selection_select_iter(tree_selection_, &iter);
151 else
152 gtk_tree_selection_unselect_iter(tree_selection_, &iter);
153 }
154
155 void NativeTableGtk::SetFocusState(int model_row, bool state) {
156 NOTIMPLEMENTED();
157 }
158
159 bool NativeTableGtk::IsRowSelected(int model_row) const {
160 GtkTreeIter iter;
161 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtk_model_), &iter, NULL,
162 model_row)) {
163 NOTREACHED();
164 return false;
165 }
166 return gtk_tree_selection_iter_is_selected(tree_selection_, &iter);
167 }
168
169 void NativeTableGtk::OnRowsChanged(int start, int length) {
170 GtkTreeIter iter;
171 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtk_model_), &iter, NULL,
172 start)) {
173 NOTREACHED();
174 return;
175 }
176 for (int i = start; i < start + length; i++) {
177 GtkTreePath* tree_path =
178 gtk_tree_model_get_path(GTK_TREE_MODEL(gtk_model_), &iter);
179 gtk_tree_model_row_changed(GTK_TREE_MODEL(gtk_model_), tree_path, &iter);
180 gtk_tree_path_free(tree_path);
181 SetRowData(i, &iter);
182 gboolean r = gtk_tree_model_iter_next(GTK_TREE_MODEL(gtk_model_), &iter);
183 DCHECK(r || i == start + length - 1); // (start + length - 1) might be the
184 // last item, in which case we won't
185 // get a next iterator.
186 }
187 }
188
189 void NativeTableGtk::OnRowsAdded(int start, int length) {
190 GtkTreeIter iter;
191 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtk_model_), &iter,
192 NULL, start);
193 for (int i = start; i < start + length; i++) {
194 gtk_list_store_append(gtk_model_, &iter);
195 SetRowData(i, &iter);
196 }
197 }
198
199 void NativeTableGtk::OnRowsRemoved(int start, int length) {
200 GtkTreeIter iter;
201 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(gtk_model_), &iter,
202 NULL, start);
203 for (int i = start; i < start + length; i++) {
204 gboolean r = gtk_list_store_remove(gtk_model_, &iter);
205 DCHECK(r || i == start + length - 1); // (start + length - 1) might be the
206 // last item, in which case we won't
207 // get a next iterator.
208 }
209 }
210
211 gfx::Rect NativeTableGtk::GetBounds() const {
212 NOTIMPLEMENTED();
213 return gfx::Rect();
214 }
215
216 void NativeTableGtk::CreateNativeControl() {
217 if (table_->type() == CHECK_BOX_AND_TEXT) {
218 // We are not supporting checkbox in tables on Gtk yet, as it is not used
219 // in Chrome at this point in time
220 NOTREACHED();
221 }
222
223 tree_view_ = GTK_TREE_VIEW(gtk_tree_view_new());
224 g_signal_connect(tree_view_, "cursor-changed",
225 G_CALLBACK(OnCursorChangedThunk), this);
226
227 // The tree view must be wrapped in a scroll-view to be scrollable.
228 GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
229 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
230 GTK_SHADOW_ETCHED_IN);
231 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
232 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
233 gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(tree_view_));
234 NativeControlCreated(scrolled);
235 // native_view() is now available.
236
237 // Set the selection mode, single or multiple.
238 tree_selection_ = gtk_tree_view_get_selection(tree_view_);
239 gtk_tree_selection_set_mode(
240 tree_selection_, table_->single_selection() ? GTK_SELECTION_SINGLE :
241 GTK_SELECTION_MULTIPLE);
242
243 // Don't make the header clickable until we support sorting.
244 gtk_tree_view_set_headers_clickable(tree_view_, FALSE);
245
246 // Show grid lines based on the options.
247 GtkTreeViewGridLines grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
248 if (table_->horizontal_lines() && table_->vertical_lines()) {
249 grid_lines = GTK_TREE_VIEW_GRID_LINES_BOTH;
250 } else if (table_->horizontal_lines()) {
251 grid_lines = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
252 } else if (table_->vertical_lines()) {
253 grid_lines = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
254 }
255 gtk_tree_view_set_grid_lines(tree_view_, grid_lines);
256
257 int gtk_column_index = 0;
258 size_t column_index = 0;
259 if (table_->type() == ICON_AND_TEXT) {
260 InsertIconAndTextColumn(table_->GetVisibleColumnAt(0), 0);
261 column_index = 1;
262 gtk_column_index = 2;
263 }
264
265 for (; column_index < table_->GetVisibleColumnCount();
266 ++column_index, gtk_column_index++) {
267 InsertTextColumn(table_->GetVisibleColumnAt(column_index),
268 gtk_column_index);
269 }
270
271 // Now create the model.
272 int column_count = table_->GetVisibleColumnCount();
273 scoped_array<GType> types(
274 new GType[column_count + 1]); // One extra column for the icon (if any).
275 for (int i = 0; i < column_count + 1; i++)
276 types[i] = G_TYPE_STRING;
277
278 if (table_->type() == ICON_AND_TEXT) {
279 types[0] = GDK_TYPE_PIXBUF;
280 gtk_model_ = gtk_list_store_newv(column_count + 1, types.get());
281 } else {
282 gtk_model_ = gtk_list_store_newv(column_count, types.get());
283 }
284
285 gtk_tree_view_set_model(tree_view_, GTK_TREE_MODEL(gtk_model_));
286 g_object_unref(gtk_model_); // Now the tree owns the model.
287
288 // Updates the gtk model with the actual model.
289 if (table_->model())
290 OnRowsAdded(0, table_->model()->RowCount());
291
292 gtk_widget_show_all(native_view());
293 }
294
295 void NativeTableGtk::InsertTextColumn(const ui::TableColumn& column,
296 int index) {
297 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
298 gtk_tree_view_insert_column_with_attributes(tree_view_, -1,
299 UTF16ToUTF8(column.title).c_str(),
300 renderer, "text", index, NULL);
301 }
302
303 void NativeTableGtk::InsertIconAndTextColumn(const ui::TableColumn& column,
304 int index) {
305 // If necessary we could support more than 1 icon and text column and we could
306 // make it so it does not have to be the 1st column.
307 DCHECK_EQ(0, index) << "The icon and text column can only be the first column"
308 " at this point.";
309
310 GtkTreeViewColumn* gtk_column = gtk_tree_view_column_new();
311 gtk_tree_view_column_set_title(gtk_column, UTF16ToUTF8(column.title).c_str());
312 GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new();
313 gtk_tree_view_column_pack_start(gtk_column, renderer, FALSE);
314 // First we set the icon renderer at index 0.
315 gtk_tree_view_column_set_attributes(gtk_column, renderer, "pixbuf", 0, NULL);
316
317 renderer = gtk_cell_renderer_text_new();
318 gtk_tree_view_column_pack_start(gtk_column, renderer, TRUE);
319 // Then we set the text renderer at index 1.
320 gtk_tree_view_column_set_attributes(gtk_column, renderer, "text", 1, NULL);
321
322 gtk_tree_view_append_column(tree_view_, gtk_column);
323 }
324
325 void NativeTableGtk::SetRowData(int row_index, GtkTreeIter* iter) {
326 int gtk_column_index = 0;
327 if (table_->type() == ICON_AND_TEXT) {
328 GdkPixbuf* icon = GetModelIcon(row_index);
329 gtk_list_store_set(gtk_model_, iter, 0, icon, -1);
330 g_object_unref(icon);
331 gtk_column_index++;
332 }
333 for (size_t i = 0; i < table_->GetVisibleColumnCount();
334 ++i, ++gtk_column_index) {
335 std::string text =
336 UTF16ToUTF8(table_->model()->GetText(row_index,
337 table_->GetVisibleColumnAt(i).id));
338 gtk_list_store_set(gtk_model_, iter, gtk_column_index, text.c_str(), -1);
339 }
340 }
341
342 void NativeTableGtk::OnCursorChanged(GtkWidget* widget) {
343 // Ignore the signal if no row is selected. This can occur when GTK
344 // first opens a window (i.e. no row is selected but the cursor is set
345 // to the first row). When a user clicks on a row, the row is selected,
346 // and then "cursor-changed" signal is emitted, hence the selection
347 // count will be 1 here.
348 if (gtk_tree_selection_count_selected_rows(tree_selection_) == 0) {
349 return;
350 }
351 GtkTreePath *tree_path = NULL;
352 gtk_tree_view_get_cursor(tree_view_, &tree_path, NULL);
353 if (tree_path) {
354 const gint* indices = gtk_tree_path_get_indices(tree_path);
355 CHECK(indices);
356 table_->SelectRow(indices[0]);
357 gtk_tree_path_free(tree_path);
358 }
359 }
360
361 GdkPixbuf* NativeTableGtk::GetModelIcon(int row) {
362 SkBitmap icon = table_->model()->GetIcon(row);
363 return gfx::GdkPixbufFromSkBitmap(&icon);
364 }
365
366 // static
367 NativeTableWrapper* NativeTableWrapper::CreateNativeWrapper(TableView2* table) {
368 return new NativeTableGtk(table);
369 }
370
371 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/table/native_table_gtk.h ('k') | views/controls/table/native_table_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698