gtktreeview.c 475 KB
Newer Older
1 2 3
/* gtktreeview.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
4
 * This library is free software; you can redistribute it and/or
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


21
#include "config.h"
Benjamin Otte's avatar
Benjamin Otte committed
22
#include <math.h>
Manish Singh's avatar
Manish Singh committed
23 24 25
#include <string.h>
#include <gdk/gdkkeysyms.h>

26 27
#include "gtktreeview.h"
#include "gtkrbtree.h"
Havoc Pennington's avatar
Havoc Pennington committed
28
#include "gtktreednd.h"
29 30 31
#include "gtktreeprivate.h"
#include "gtkcellrenderer.h"
#include "gtkmain.h"
32
#include "gtkmarshalers.h"
Johan Dahlin's avatar
Johan Dahlin committed
33
#include "gtkbuildable.h"
34 35 36
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
Havoc Pennington's avatar
Havoc Pennington committed
37
#include "gtkhbox.h"
Jonathan Blandford's avatar
Jonathan Blandford committed
38
#include "gtkvbox.h"
Havoc Pennington's avatar
Havoc Pennington committed
39
#include "gtkarrow.h"
40
#include "gtkintl.h"
41
#include "gtkbindings.h"
42 43
#include "gtkcontainer.h"
#include "gtkentry.h"
44
#include "gtkframe.h"
Jonathan Blandford's avatar
Jonathan Blandford committed
45
#include "gtktreemodelsort.h"
46
#include "gtktooltip.h"
Tadej Borovšak's avatar
Tadej Borovšak committed
47
#include "gtkscrollable.h"
48
#include "gtkprivate.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
49
#include "gtkwidgetprivate.h"
50
#include "gtkentryprivate.h"
51

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

/**
 * SECTION:gtktreeview
 * @Short_description: A widget for displaying both trees and lists
 * @Title: GtkTreeView
 * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
 *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
 *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
 *   #GtkCellRendererText, #GtkCellRendererToggle
 *
 * Widget that displays any object that implements the #GtkTreeModel interface.
 *
 * Please refer to the <link linkend="TreeWidget">tree widget conceptual
 * overview</link> for an overview of all the objects and data types related
 * to the tree widget and how they work together.
 *
 * Several different coordinate systems are exposed in the GtkTreeView API.
 * These are:
 *
 * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
 * <variablelist><title>Coordinate systems in GtkTreeView API</title>
 * <varlistentry><term>Widget coordinates</term>
 * <listitem>
 * <para>
 * Coordinates relative to the widget (usually <literal>widget->window</literal>).
 * </para>
 * </listitem>
 * </varlistentry>
 * <varlistentry><term>Bin window coordinates</term>
 * <listitem>
 * <para>
 * Coordinates relative to the window that GtkTreeView renders to.
 * </para>
 * </listitem>
 * </varlistentry>
 * <varlistentry><term>Tree coordinates</term>
 * <listitem>
 * <para>
 * Coordinates relative to the entire scrollable area of GtkTreeView. These
 * coordinates start at (0, 0) for row 0 of the tree.
 * </para>
 * </listitem>
 * </varlistentry>
 * </variablelist>
 *
 * Several functions are available for converting between the different
 * coordinate systems.  The most common translations are between widget and bin
 * window coordinates and between bin window and tree coordinates. For the
 * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
 * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
 * (and vice versa).
Matthias Clasen's avatar
Matthias Clasen committed
103
 *
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
 * <refsect2 id="GtkTreeView-BUILDER-UI">
 * <title>GtkTreeView as GtkBuildable</title>
 * The GtkTreeView implementation of the GtkBuildable interface accepts
 * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
 * internal #GtkTreeSelection in UI definitions.
 * <example>
 * <title>A UI definition fragment with GtkTreeView</title>
 * <programlisting><![CDATA[
 * <object class="GtkTreeView" id="treeview">
 *   <property name="model">liststore1</property>
 *   <child>
 *     <object class="GtkTreeViewColumn" id="test-column">
 *       <property name="title">Test</property>
 *       <child>
 *         <object class="GtkCellRendererText" id="test-renderer"/>
 *         <attributes>
 *           <attribute name="text">1</attribute>
 *         </attributes>
 *       </child>
 *     </object>
 *   </child>
 *   <child internal-child="selection">
 *     <object class="GtkTreeSelection" id="selection">
 *       <signal name="changed" handler="on_treeview_selection_changed"/>
 *     </object>
 *   </child>
 * </object>
 * ]]></programlisting>
 * </example>
 * </refsect2>
 */


Jonathan Blandford's avatar
Jonathan Blandford committed
137
#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
138
#define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
139
#define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
140
#define SCROLL_EDGE_SIZE 15
141
#define EXPANDER_EXTRA_PADDING 4
Jonathan Blandford's avatar
Jonathan Blandford committed
142
#define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
143 144
#define AUTO_EXPAND_TIMEOUT 500

Havoc Pennington's avatar
Havoc Pennington committed
145 146 147 148 149 150 151
/* The "background" areas of all rows/cells add up to cover the entire tree.
 * The background includes all inter-row and inter-cell spacing.
 * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
 * i.e. just the cells, no spacing.
 */

#define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
Kristian Rietveld's avatar
Kristian Rietveld committed
152
#define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
Havoc Pennington's avatar
Havoc Pennington committed
153

154 155 156
/* Translate from bin_window coordinates to rbtree (tree coordinates) and
 * vice versa.
 */
157 158
#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
159

160
/* This is in bin_window coordinates */
161 162
#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
163

164 165
#define ROW_HEIGHT(tree_view,height) \
  ((height > 0) ? (height) : (tree_view)->priv->expander_size)
166

167

168
typedef struct _GtkTreeViewChild GtkTreeViewChild;
169 170 171 172 173
struct _GtkTreeViewChild
{
  GtkWidget *widget;
  gint x;
  gint y;
174 175
  gint width;
  gint height;
176 177
};

Jonathan Blandford's avatar
Jonathan Blandford committed
178

179 180 181 182
typedef struct _TreeViewDragInfo TreeViewDragInfo;
struct _TreeViewDragInfo
{
  GdkModifierType start_button_mask;
183
  GtkTargetList *_unused_source_target_list;
184 185
  GdkDragAction source_actions;

186
  GtkTargetList *_unused_dest_target_list;
187 188 189 190 191 192 193

  guint source_set : 1;
  guint dest_set : 1;
};


/* Signals */
194 195 196
enum
{
  ROW_ACTIVATED,
197 198 199 200
  TEST_EXPAND_ROW,
  TEST_COLLAPSE_ROW,
  ROW_EXPANDED,
  ROW_COLLAPSED,
201
  COLUMNS_CHANGED,
202
  CURSOR_CHANGED,
203
  MOVE_CURSOR,
204
  SELECT_ALL,
205
  UNSELECT_ALL,
206
  SELECT_CURSOR_ROW,
207 208 209
  TOGGLE_CURSOR_ROW,
  EXPAND_COLLAPSE_CURSOR_ROW,
  SELECT_CURSOR_PARENT,
210
  START_INTERACTIVE_SEARCH,
211 212 213
  LAST_SIGNAL
};

214
/* Properties */
215 216 217 218 219
enum {
  PROP_0,
  PROP_MODEL,
  PROP_HADJUSTMENT,
  PROP_VADJUSTMENT,
220 221
  PROP_HSCROLL_POLICY,
  PROP_VSCROLL_POLICY,
222 223 224
  PROP_HEADERS_VISIBLE,
  PROP_HEADERS_CLICKABLE,
  PROP_EXPANDER_COLUMN,
225
  PROP_REORDERABLE,
226 227
  PROP_RULES_HINT,
  PROP_ENABLE_SEARCH,
228
  PROP_SEARCH_COLUMN,
229
  PROP_FIXED_HEIGHT_MODE,
230
  PROP_HOVER_SELECTION,
Kristian Rietveld's avatar
Kristian Rietveld committed
231 232
  PROP_HOVER_EXPAND,
  PROP_SHOW_EXPANDERS,
233
  PROP_LEVEL_INDENTATION,
234 235
  PROP_RUBBER_BANDING,
  PROP_ENABLE_GRID_LINES,
Kristian Rietveld's avatar
Kristian Rietveld committed
236
  PROP_ENABLE_TREE_LINES,
237
  PROP_TOOLTIP_COLUMN
238
};
239

240 241
/* object signals */
static void     gtk_tree_view_finalize             (GObject          *object);
242 243 244
static void     gtk_tree_view_set_property         (GObject         *object,
						    guint            prop_id,
						    const GValue    *value,
Jonathan Blandford's avatar
Jonathan Blandford committed
245
						    GParamSpec      *pspec);
246 247 248
static void     gtk_tree_view_get_property         (GObject         *object,
						    guint            prop_id,
						    GValue          *value,
Jonathan Blandford's avatar
Jonathan Blandford committed
249
						    GParamSpec      *pspec);
250

251
/* gtkwidget signals */
252
static void     gtk_tree_view_destroy              (GtkWidget        *widget);
253 254 255
static void     gtk_tree_view_realize              (GtkWidget        *widget);
static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
static void     gtk_tree_view_map                  (GtkWidget        *widget);
256 257 258 259 260 261
static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
						    gint             *minimum,
						    gint             *natural);
static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
						    gint             *minimum,
						    gint             *natural);
262 263 264 265
static void     gtk_tree_view_size_request         (GtkWidget        *widget,
						    GtkRequisition   *requisition);
static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
						    GtkAllocation    *allocation);
Benjamin Otte's avatar
Benjamin Otte committed
266 267
static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
                                                    cairo_t          *cr);
268 269
static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
						    GdkEventKey      *event);
Jonathan Blandford's avatar
Jonathan Blandford committed
270 271
static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
						    GdkEventKey      *event);
272 273 274 275 276 277 278 279 280 281
static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
						    GdkEventMotion   *event);
static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
						    GdkEventCrossing *event);
static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
						    GdkEventCrossing *event);
static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
						    GdkEventButton   *event);
static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
						    GdkEventButton   *event);
282 283
static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
						    GdkEventGrabBroken *event);
284 285 286 287 288
#if 0
static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
						    GdkEventConfigure *event);
#endif

289 290
static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
						    GtkWidget        *child);
291 292
static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
						    GdkEventFocus    *event);
293
static gint     gtk_tree_view_focus                (GtkWidget        *widget,
294
						    GtkDirectionType  direction);
295
static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
Kristian Rietveld's avatar
Kristian Rietveld committed
296 297
static void     gtk_tree_view_style_set            (GtkWidget        *widget,
						    GtkStyle         *previous_style);
298 299
static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
						    gboolean          was_grabbed);
300 301
static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
						    GtkStateType      previous_state);
302 303 304 305 306 307 308 309 310

/* container signals */
static void     gtk_tree_view_remove               (GtkContainer     *container,
						    GtkWidget        *widget);
static void     gtk_tree_view_forall               (GtkContainer     *container,
						    gboolean          include_internals,
						    GtkCallback       callback,
						    gpointer          callback_data);

Havoc Pennington's avatar
Havoc Pennington committed
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
/* Source side drag signals */
static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void gtk_tree_view_drag_end         (GtkWidget        *widget,
                                            GdkDragContext   *context);
static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
                                            GdkDragContext   *context,
                                            GtkSelectionData *selection_data,
                                            guint             info,
                                            guint             time);
static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
                                            GdkDragContext   *context);

/* Target side drag signals */
static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  guint             time);
static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  guint             time);
static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  guint             time);
static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
                                                  GdkDragContext   *context,
                                                  gint              x,
                                                  gint              y,
                                                  GtkSelectionData *selection_data,
                                                  guint             info,
                                                  guint             time);

346
/* tree_model signals */
Tadej Borovšak's avatar
Tadej Borovšak committed
347 348 349 350
static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
                                                           GtkAdjustment   *adjustment);
static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
                                                           GtkAdjustment   *adjustment);
351
static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
352
							   GtkMovementStep  step,
353
							   gint             count);
354 355 356
static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
357
							   gboolean         start_editing);
358 359 360 361 362 363
static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
							       gboolean         logical,
							       gboolean         expand,
							       gboolean         open_all);
static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
364
static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
365 366 367
							   GtkTreePath     *path,
							   GtkTreeIter     *iter,
							   gpointer         data);
368
static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
369 370 371
							   GtkTreePath     *path,
							   GtkTreeIter     *iter,
							   gpointer         data);
372
static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
373 374 375
							   GtkTreePath     *path,
							   GtkTreeIter     *iter,
							   gpointer         data);
376
static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
377 378
							   GtkTreePath     *path,
							   gpointer         data);
379
static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
380 381 382 383 384
							   GtkTreePath     *parent,
							   GtkTreeIter     *iter,
							   gint            *new_order,
							   gpointer         data);

Jonathan Blandford's avatar
Jonathan Blandford committed
385 386 387 388 389 390 391 392
/* Incremental reflow */
static gboolean validate_row             (GtkTreeView *tree_view,
					  GtkRBTree   *tree,
					  GtkRBNode   *node,
					  GtkTreeIter *iter,
					  GtkTreePath *path);
static void     validate_visible_area    (GtkTreeView *tree_view);
static gboolean validate_rows_handler    (GtkTreeView *tree_view);
393 394
static gboolean do_validate_rows         (GtkTreeView *tree_view,
					  gboolean     size_request);
395
static gboolean validate_rows            (GtkTreeView *tree_view);
Jonathan Blandford's avatar
Jonathan Blandford committed
396 397
static gboolean presize_handler_callback (gpointer     data);
static void     install_presize_handler  (GtkTreeView *tree_view);
398
static void     install_scroll_sync_handler (GtkTreeView *tree_view);
399 400 401
static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
					     GtkTreePath *path,
					     gint         offset);
402
static void	gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
403
static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
404
static void     invalidate_empty_focus      (GtkTreeView *tree_view);
405

406
/* Internal functions */
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
							      GtkTreeViewColumn  *column);
static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
							      guint               keyval,
							      guint               modmask,
							      gboolean            add_shifted_binding,
							      GtkMovementStep     step,
							      gint                count);
static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
							      GtkRBTree          *tree);
static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
							      GtkTreePath        *path,
							      const GdkRectangle *clip_rect);
static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
							      GtkRBTree          *tree,
422
							      GtkRBNode          *node);
423
static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
424
                                                              cairo_t            *cr,
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
							      GtkRBTree          *tree,
							      GtkRBNode          *node,
							      gint                x,
							      gint                y);
static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
							      GtkRBTree          *tree,
							      gint               *x1,
							      gint               *x2);
static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
							      gint                i,
							      gint               *x);
static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
							      GtkTreeView        *tree_view);
static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
							      GtkRBTree          *tree,
							      GtkTreeIter        *iter,
							      gint                depth,
							      gboolean            recurse);
static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
							      GtkRBTree          *tree,
							      GtkRBNode          *node);
static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
							      GtkTreeViewColumn  *column,
							      gboolean            focus_to_cell);
static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
							      GdkEventMotion     *event);
static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
							      gint                count);
static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
							      gint                count);
static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
							      gint                count);
static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
							      gint                count);
static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
							      GtkTreePath        *path,
							      GtkRBTree          *tree,
							      GtkRBNode          *node,
							      gboolean            animate);
static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
							      GtkTreePath        *path,
							      GtkRBTree          *tree,
							      GtkRBNode          *node,
							      gboolean            open_all,
							      gboolean            animate);
static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
							      GtkTreePath        *path,
							      gboolean            clear_and_select,
							      gboolean            clamp_node);
static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
static void     column_sizing_notify                         (GObject            *object,
                                                              GParamSpec         *pspec,
                                                              gpointer            data);
static gboolean expand_collapse_timeout                      (gpointer            data);
480 481 482 483 484 485
static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
                                                              GtkRBTree          *tree,
                                                              GtkRBNode          *node,
                                                              gboolean            expand);
static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
486 487
static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
488 489 490
static void     update_prelight                              (GtkTreeView        *tree_view,
                                                              int                 x,
                                                              int                 y);
Kristian Rietveld's avatar
Kristian Rietveld committed
491

492
/* interactive search */
Jonathan Blandford's avatar
Jonathan Blandford committed
493
static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
494 495 496
static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
                                                         GtkTreeView      *tree_view,
                                                         GdkDevice        *device);
497
static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
498 499
							 GtkWidget        *search_dialog,
							 gpointer          user_data);
500 501 502
static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
							 GtkMenu          *menu,
							 gpointer          data);
Jonathan Blandford's avatar
Jonathan Blandford committed
503 504
static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
							 GtkTreeView      *tree_view);
505 506
static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
							 GtkTreeView      *tree_view);
507 508 509
static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
							 gpointer          data);
510 511 512 513 514 515
static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
							 GdkEventAny      *event,
							 GtkTreeView      *tree_view);
static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
							 GdkEventButton   *event,
							 GtkTreeView      *tree_view);
516 517 518
static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
							 GdkEventScroll   *event,
							 GtkTreeView      *tree_view);
519 520 521
static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
							 GdkEventKey      *event,
							 GtkTreeView      *tree_view);
522
static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
523 524 525 526
							 GtkTreeView      *tree_view,
							 gboolean          up);
static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
							 gint              column,
527
							 const gchar      *key,
528 529
							 GtkTreeIter      *iter,
							 gpointer          search_data);
530 531 532
static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
							 GtkTreeSelection *selection,
							 GtkTreeIter      *iter,
533
							 const gchar      *text,
534 535 536 537
							 gint             *count,
							 gint              n);
static void     gtk_tree_view_search_init               (GtkWidget        *entry,
							 GtkTreeView      *tree_view);
538 539 540 541 542 543
static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
							 GtkWidget        *child_widget,
							 gint              x,
							 gint              y,
							 gint              width,
							 gint              height);
544 545 546 547 548 549 550 551 552
static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
							 GtkTreePath      *cursor_path);
static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
					      GtkTreeViewColumn *column,
					      GtkTreePath       *path,
					      GtkCellEditable   *cell_editable,
					      GdkRectangle      *cell_area,
					      GdkEvent          *event,
					      guint              flags);
Jonathan Blandford's avatar
Jonathan Blandford committed
553 554
static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
							 gboolean     cancel_editing);
Jonathan Blandford's avatar
Jonathan Blandford committed
555
static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
556
                                                             GdkDevice   *device,
Jonathan Blandford's avatar
Jonathan Blandford committed
557 558
							     gboolean     keybinding);
static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
559 560 561
static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
							 GtkTreeViewColumn *column,
							 gint               drop_position);
562

Johan Dahlin's avatar
Johan Dahlin committed
563
/* GtkBuildable */
564 565 566 567 568 569 570 571
static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
							    GtkBuilder        *builder,
							    GObject           *child,
							    const gchar       *type);
static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
							    GtkBuilder        *builder,
							    const gchar       *childname);
static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
Johan Dahlin's avatar
Johan Dahlin committed
572 573


574 575 576
static gboolean scroll_row_timeout                   (gpointer     data);
static void     add_scroll_timeout                   (GtkTreeView *tree_view);
static void     remove_scroll_timeout                (GtkTreeView *tree_view);
577

578
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
579

580 581 582 583 584


/* GType Methods
 */

Johan Dahlin's avatar
Johan Dahlin committed
585 586
G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
Tadej Borovšak's avatar
Tadej Borovšak committed
587 588
						gtk_tree_view_buildable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
589 590 591 592

static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
{
593
  GObjectClass *o_class;
594 595
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
596
  GtkBindingSet *binding_set;
597

598
  binding_set = gtk_binding_set_by_class (class);
599

600 601 602 603
  o_class = (GObjectClass *) class;
  widget_class = (GtkWidgetClass *) class;
  container_class = (GtkContainerClass *) class;

604
  /* GObject signals */
605 606
  o_class->set_property = gtk_tree_view_set_property;
  o_class->get_property = gtk_tree_view_get_property;
607
  o_class->finalize = gtk_tree_view_finalize;
608

609
  /* GtkWidget signals */
610
  widget_class->destroy = gtk_tree_view_destroy;
611
  widget_class->map = gtk_tree_view_map;
612 613
  widget_class->realize = gtk_tree_view_realize;
  widget_class->unrealize = gtk_tree_view_unrealize;
614 615
  widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
  widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
616
  widget_class->size_allocate = gtk_tree_view_size_allocate;
617 618
  widget_class->button_press_event = gtk_tree_view_button_press;
  widget_class->button_release_event = gtk_tree_view_button_release;
619
  widget_class->grab_broken_event = gtk_tree_view_grab_broken;
620
  /*widget_class->configure_event = gtk_tree_view_configure;*/
621
  widget_class->motion_notify_event = gtk_tree_view_motion;
Benjamin Otte's avatar
Benjamin Otte committed
622
  widget_class->draw = gtk_tree_view_draw;
623
  widget_class->key_press_event = gtk_tree_view_key_press;
Jonathan Blandford's avatar
Jonathan Blandford committed
624
  widget_class->key_release_event = gtk_tree_view_key_release;
625 626 627
  widget_class->enter_notify_event = gtk_tree_view_enter_notify;
  widget_class->leave_notify_event = gtk_tree_view_leave_notify;
  widget_class->focus_out_event = gtk_tree_view_focus_out;
Havoc Pennington's avatar
Havoc Pennington committed
628 629 630 631 632 633 634 635
  widget_class->drag_begin = gtk_tree_view_drag_begin;
  widget_class->drag_end = gtk_tree_view_drag_end;
  widget_class->drag_data_get = gtk_tree_view_drag_data_get;
  widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
  widget_class->drag_leave = gtk_tree_view_drag_leave;
  widget_class->drag_motion = gtk_tree_view_drag_motion;
  widget_class->drag_drop = gtk_tree_view_drag_drop;
  widget_class->drag_data_received = gtk_tree_view_drag_data_received;
636
  widget_class->focus = gtk_tree_view_focus;
637
  widget_class->grab_focus = gtk_tree_view_grab_focus;
Kristian Rietveld's avatar
Kristian Rietveld committed
638
  widget_class->style_set = gtk_tree_view_style_set;
639
  widget_class->grab_notify = gtk_tree_view_grab_notify;
640
  widget_class->state_changed = gtk_tree_view_state_changed;
641

642
  /* GtkContainer signals */
643
  container_class->remove = gtk_tree_view_remove;
644 645
  container_class->forall = gtk_tree_view_forall;
  container_class->set_focus_child = gtk_tree_view_set_focus_child;
646

647
  class->move_cursor = gtk_tree_view_real_move_cursor;
648
  class->select_all = gtk_tree_view_real_select_all;
649
  class->unselect_all = gtk_tree_view_real_unselect_all;
650
  class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
651 652 653
  class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
  class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
  class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
Jonathan Blandford's avatar
Jonathan Blandford committed
654
  class->start_interactive_search = gtk_tree_view_start_interactive_search;
655

656
  /* Properties */
657

658 659
  g_object_class_install_property (o_class,
                                   PROP_MODEL,
Tim Janik's avatar
Tim Janik committed
660
                                   g_param_spec_object ("model",
661 662
							P_("TreeView Model"),
							P_("The model for the tree view"),
Tim Janik's avatar
Tim Janik committed
663
							GTK_TYPE_TREE_MODEL,
664
							GTK_PARAM_READWRITE));
Jonathan Blandford's avatar
Jonathan Blandford committed
665

666 667 668 669
  g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
  g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
  g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
  g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
670 671 672

  g_object_class_install_property (o_class,
                                   PROP_HEADERS_VISIBLE,
Matthias Clasen's avatar
x  
Matthias Clasen committed
673
                                   g_param_spec_boolean ("headers-visible",
674
							 P_("Headers Visible"),
675
							 P_("Show the column header buttons"),
676
							 TRUE,
677
							 GTK_PARAM_READWRITE));
678 679 680

  g_object_class_install_property (o_class,
                                   PROP_HEADERS_CLICKABLE,
Matthias Clasen's avatar
x  
Matthias Clasen committed
681
                                   g_param_spec_boolean ("headers-clickable",
682 683
							 P_("Headers Clickable"),
							 P_("Column headers respond to click events"),
684
							 TRUE,
685
							 GTK_PARAM_READWRITE));
686 687 688

  g_object_class_install_property (o_class,
                                   PROP_EXPANDER_COLUMN,
Matthias Clasen's avatar
x  
Matthias Clasen committed
689
                                   g_param_spec_object ("expander-column",
690 691
							P_("Expander Column"),
							P_("Set the column for the expander column"),
692
							GTK_TYPE_TREE_VIEW_COLUMN,
693
							GTK_PARAM_READWRITE));
694

695 696 697
  g_object_class_install_property (o_class,
                                   PROP_REORDERABLE,
                                   g_param_spec_boolean ("reorderable",
698 699
							 P_("Reorderable"),
							 P_("View is reorderable"),
700
							 FALSE,
701
							 GTK_PARAM_READWRITE));
702

703 704
  g_object_class_install_property (o_class,
                                   PROP_RULES_HINT,
Matthias Clasen's avatar
x  
Matthias Clasen committed
705
                                   g_param_spec_boolean ("rules-hint",
706 707
							 P_("Rules Hint"),
							 P_("Set a hint to the theme engine to draw rows in alternating colors"),
708
							 FALSE,
709
							 GTK_PARAM_READWRITE));
710

711 712
    g_object_class_install_property (o_class,
				     PROP_ENABLE_SEARCH,
Matthias Clasen's avatar
x  
Matthias Clasen committed
713
				     g_param_spec_boolean ("enable-search",
714 715
							   P_("Enable Search"),
							   P_("View allows user to search through columns interactively"),
716
							   TRUE,
717
							   GTK_PARAM_READWRITE));
718

719 720
    g_object_class_install_property (o_class,
				     PROP_SEARCH_COLUMN,
Matthias Clasen's avatar
x  
Matthias Clasen committed
721
				     g_param_spec_int ("search-column",
722
						       P_("Search Column"),
723
						       P_("Model column to search through during interactive search"),
724 725
						       -1,
						       G_MAXINT,
726
						       -1,
727
						       GTK_PARAM_READWRITE));
728

729 730 731 732 733 734 735 736 737 738 739
    /**
     * GtkTreeView:fixed-height-mode:
     *
     * Setting the ::fixed-height-mode property to %TRUE speeds up 
     * #GtkTreeView by assuming that all rows have the same height. 
     * Only enable this option if all rows are the same height.  
     * Please see gtk_tree_view_set_fixed_height_mode() for more 
     * information on this option.
     *
     * Since: 2.4
     **/
740 741
    g_object_class_install_property (o_class,
                                     PROP_FIXED_HEIGHT_MODE,
Matthias Clasen's avatar
x  
Matthias Clasen committed
742
                                     g_param_spec_boolean ("fixed-height-mode",
743 744
                                                           P_("Fixed Height Mode"),
                                                           P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
745
                                                           FALSE,
746
                                                           GTK_PARAM_READWRITE));
747 748 749 750
    
    /**
     * GtkTreeView:hover-selection:
     * 
Matthias Clasen's avatar
Matthias Clasen committed
751
     * Enables or disables the hover selection mode of @tree_view.
752
     * Hover selection makes the selected row follow the pointer.
Matthias Clasen's avatar
Matthias Clasen committed
753 754 755
     * Currently, this works only for the selection modes 
     * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
     *
Matthias Clasen's avatar
Matthias Clasen committed
756
     * This mode is primarily intended for treeviews in popups, e.g.
757 758 759 760 761 762
     * in #GtkComboBox or #GtkEntryCompletion.
     *
     * Since: 2.6
     */
    g_object_class_install_property (o_class,
                                     PROP_HOVER_SELECTION,
Matthias Clasen's avatar
x  
Matthias Clasen committed
763
                                     g_param_spec_boolean ("hover-selection",
764 765 766
                                                           P_("Hover Selection"),
                                                           P_("Whether the selection should follow the pointer"),
                                                           FALSE,
767
                                                           GTK_PARAM_READWRITE));
768

769 770 771
    /**
     * GtkTreeView:hover-expand:
     * 
Matthias Clasen's avatar
Matthias Clasen committed
772
     * Enables or disables the hover expansion mode of @tree_view.
Matthias Clasen's avatar
Matthias Clasen committed
773
     * Hover expansion makes rows expand or collapse if the pointer moves 
774 775
     * over them.
     *
Matthias Clasen's avatar
Matthias Clasen committed
776
     * This mode is primarily intended for treeviews in popups, e.g.
777 778 779 780 781 782
     * in #GtkComboBox or #GtkEntryCompletion.
     *
     * Since: 2.6
     */
    g_object_class_install_property (o_class,
                                     PROP_HOVER_EXPAND,
Matthias Clasen's avatar
x  
Matthias Clasen committed
783
                                     g_param_spec_boolean ("hover-expand",
784
                                                           P_("Hover Expand"),
785
                                                           P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
786
                                                           FALSE,
787
                                                           GTK_PARAM_READWRITE));
788

Matthias Clasen's avatar
Matthias Clasen committed
789 790 791 792 793 794 795
    /**
     * GtkTreeView:show-expanders:
     *
     * %TRUE if the view has expanders.
     *
     * Since: 2.12
     */
Kristian Rietveld's avatar
Kristian Rietveld committed
796 797 798 799 800 801 802 803
    g_object_class_install_property (o_class,
				     PROP_SHOW_EXPANDERS,
				     g_param_spec_boolean ("show-expanders",
							   P_("Show Expanders"),
							   P_("View has expanders"),
							   TRUE,
							   GTK_PARAM_READWRITE));

Matthias Clasen's avatar
Matthias Clasen committed
804 805 806 807 808 809 810
    /**
     * GtkTreeView:level-indentation:
     *
     * Extra indentation for each level.
     *
     * Since: 2.12
     */
Kristian Rietveld's avatar
Kristian Rietveld committed
811 812 813 814 815 816 817 818 819 820
    g_object_class_install_property (o_class,
				     PROP_LEVEL_INDENTATION,
				     g_param_spec_int ("level-indentation",
						       P_("Level Indentation"),
						       P_("Extra indentation for each level"),
						       0,
						       G_MAXINT,
						       0,
						       GTK_PARAM_READWRITE));

821 822 823 824 825 826 827 828
    g_object_class_install_property (o_class,
                                     PROP_RUBBER_BANDING,
                                     g_param_spec_boolean ("rubber-banding",
                                                           P_("Rubber Banding"),
                                                           P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
                                                           FALSE,
                                                           GTK_PARAM_READWRITE));

829 830
    g_object_class_install_property (o_class,
                                     PROP_ENABLE_GRID_LINES,
831 832 833 834 835 836
                                     g_param_spec_enum ("enable-grid-lines",
							P_("Enable Grid Lines"),
							P_("Whether grid lines should be drawn in the tree view"),
							GTK_TYPE_TREE_VIEW_GRID_LINES,
							GTK_TREE_VIEW_GRID_LINES_NONE,
							GTK_PARAM_READWRITE));
837 838 839 840 841 842 843 844 845

    g_object_class_install_property (o_class,
                                     PROP_ENABLE_TREE_LINES,
                                     g_param_spec_boolean ("enable-tree-lines",
                                                           P_("Enable Tree Lines"),
                                                           P_("Whether tree lines should be drawn in the tree view"),
                                                           FALSE,
                                                           GTK_PARAM_READWRITE));

Kristian Rietveld's avatar
Kristian Rietveld committed
846 847 848 849 850 851 852 853 854 855
    g_object_class_install_property (o_class,
				     PROP_TOOLTIP_COLUMN,
				     g_param_spec_int ("tooltip-column",
						       P_("Tooltip Column"),
						       P_("The column in the model containing the tooltip texts for the rows"),
						       -1,
						       G_MAXINT,
						       -1,
						       GTK_PARAM_READWRITE));

856
  /* Style properties */
857
#define _TREE_VIEW_EXPANDER_SIZE 12
858
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
859
#define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
860

861
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
862
					   g_param_spec_int ("expander-size",
863 864
							     P_("Expander Size"),
							     P_("Size of the expander arrow"),
865 866
							     0,
							     G_MAXINT,
867
							     _TREE_VIEW_EXPANDER_SIZE,
868
							     GTK_PARAM_READABLE));
869

870
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
871
					   g_param_spec_int ("vertical-separator",
872 873
							     P_("Vertical Separator Width"),
							     P_("Vertical space between cells.  Must be an even number"),
874 875 876
							     0,
							     G_MAXINT,
							     _TREE_VIEW_VERTICAL_SEPARATOR,
877
							     GTK_PARAM_READABLE));
878

879
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
880
					   g_param_spec_int ("horizontal-separator",
881 882
							     P_("Horizontal Separator Width"),
							     P_("Horizontal space between cells.  Must be an even number"),
883 884 885
							     0,
							     G_MAXINT,
							     _TREE_VIEW_HORIZONTAL_SEPARATOR,
886
							     GTK_PARAM_READABLE));
887

888
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
889
					   g_param_spec_boolean ("allow-rules",
890 891
								 P_("Allow Rules"),
								 P_("Allow drawing of alternating color rows"),
892
								 TRUE,
893
								 GTK_PARAM_READABLE));
894

895
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
896
					   g_param_spec_boolean ("indent-expanders",
897 898
								 P_("Indent Expanders"),
								 P_("Make the expanders indented"),
899
								 TRUE,
900
								 GTK_PARAM_READABLE));
Manish Singh's avatar
Manish Singh committed
901

902
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
903
                                           g_param_spec_boxed ("even-row-color",
904 905
                                                               P_("Even Row Color"),
                                                               P_("Color to use for even rows"),
906
							       GDK_TYPE_COLOR,
907
							       GTK_PARAM_READABLE));
908 909

  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
910
                                           g_param_spec_boxed ("odd-row-color",
911 912
                                                               P_("Odd Row Color"),
                                                               P_("Color to use for odd rows"),
913
							       GDK_TYPE_COLOR,
914
							       GTK_PARAM_READABLE));
915

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("grid-line-width",
							     P_("Grid line width"),
							     P_("Width, in pixels, of the tree view grid lines"),
							     0, G_MAXINT, 1,
							     GTK_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("tree-line-width",
							     P_("Tree line width"),
							     P_("Width, in pixels, of the tree view lines"),
							     0, G_MAXINT, 1,
							     GTK_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_string ("grid-line-pattern",
								P_("Grid line pattern"),
								P_("Dash pattern used to draw the tree view grid lines"),
								"\1\1",
								GTK_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,