blob: a6b5af792609249e642d5738c0a526a3845e35d9 [file] [log] [blame]
Stepan Salenikovich9816a942015-04-22 17:49:16 -04001/*
Stepan Salenikovichbe87d2c2016-01-25 14:14:34 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Stepan Salenikovich9816a942015-04-22 17:49:16 -04003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Stepan Salenikovich9816a942015-04-22 17:49:16 -040018 */
19
20#include "historyview.h"
21
22#include <gtk/gtk.h>
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -040023#include <glib/gi18n.h>
Stepan Salenikovichf6078222016-10-03 17:31:16 -040024#include "models/gtkqtreemodel.h"
Stepan Salenikovich9816a942015-04-22 17:49:16 -040025#include <categorizedhistorymodel.h>
26#include <QtCore/QSortFilterProxyModel>
27#include <personmodel.h>
28#include "utils/calling.h"
29#include <memory>
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -040030#include <globalinstances.h>
31#include "native/pixbufmanipulator.h"
Stepan Salenikovich9816a942015-04-22 17:49:16 -040032#include "defines.h"
33#include "utils/models.h"
34#include <contactmethod.h>
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -040035#include <QtCore/QDateTime> // for date time formatting
Stepan Salenikovich9d294492015-05-14 16:34:24 -040036#include <QtCore/QItemSelectionModel>
Stepan Salenikovichf2d76c52015-07-17 17:54:56 -040037#include "utils/menus.h"
Stepan Salenikovich8eaa13e2016-08-26 16:51:48 -040038#include "contactpopupmenu.h"
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -040039#include "models/namenumberfilterproxymodel.h"
Julien Baron865676b2016-03-04 20:38:59 +010040
Stepan Salenikovich9816a942015-04-22 17:49:16 -040041struct _HistoryView
42{
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -040043 GtkTreeView parent;
Stepan Salenikovich9816a942015-04-22 17:49:16 -040044};
45
46struct _HistoryViewClass
47{
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -040048 GtkTreeViewClass parent_class;
Stepan Salenikovich9816a942015-04-22 17:49:16 -040049};
50
51typedef struct _HistoryViewPrivate HistoryViewPrivate;
52
53struct _HistoryViewPrivate
54{
Stepan Salenikovich8eaa13e2016-08-26 16:51:48 -040055 GtkWidget *popup_menu;
56
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -040057 NameNumberFilterProxy *filterproxy;
Stepan Salenikovich9d294492015-05-14 16:34:24 -040058 QMetaObject::Connection category_changed;
Stepan Salenikovich9816a942015-04-22 17:49:16 -040059};
60
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -040061G_DEFINE_TYPE_WITH_PRIVATE(HistoryView, history_view, GTK_TYPE_TREE_VIEW);
Stepan Salenikovich9816a942015-04-22 17:49:16 -040062
63#define HISTORY_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HISTORY_VIEW_TYPE, HistoryViewPrivate))
64
65static void
66render_call_direction(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
67 GtkCellRenderer *cell,
68 GtkTreeModel *tree_model,
69 GtkTreeIter *iter,
70 G_GNUC_UNUSED gpointer data)
71{
72 /* check if this is a top level item (the fuzzy date item),
73 * in this case we don't want to show a call direction */
74 gchar *render_direction = NULL;
75 GtkTreeIter parent;
76 if (gtk_tree_model_iter_parent(tree_model, &parent, iter)) {
77 /* get direction and missed values */
78 GValue value = G_VALUE_INIT;
79 gtk_tree_model_get_value(tree_model, iter, 3, &value);
80 Call::Direction direction = (Call::Direction)g_value_get_int(&value);
81 g_value_unset(&value);
82
83 gtk_tree_model_get_value(tree_model, iter, 4, &value);
84 gboolean missed = g_value_get_boolean(&value);
85 g_value_unset(&value);
86
87 switch (direction) {
88 case Call::Direction::INCOMING:
89 if (missed)
90 render_direction = g_strdup_printf("<span fgcolor=\"red\" font=\"monospace\">&#8601;</span>");
91 else
92 render_direction = g_strdup_printf("<span fgcolor=\"green\" font=\"monospace\">&#8601;</span>");
93 break;
94 case Call::Direction::OUTGOING:
95 if (missed)
96 render_direction = g_strdup_printf("<span fgcolor=\"red\" font=\"monospace\">&#8599;</span>");
97 else
98 render_direction = g_strdup_printf("<span fgcolor=\"green\" font=\"monospace\">&#8599;</span>");
99 break;
100 }
101 }
102 g_object_set(G_OBJECT(cell), "markup", render_direction, NULL);
103 g_free(render_direction);
104}
105
106static void
107activate_history_item(GtkTreeView *tree_view,
108 GtkTreePath *path,
109 G_GNUC_UNUSED GtkTreeViewColumn *column,
110 G_GNUC_UNUSED gpointer user_data)
111{
112 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
113
114 /* expand / collapse row */
115 if (gtk_tree_view_row_expanded(tree_view, path))
116 gtk_tree_view_collapse_row(tree_view, path);
117 else
118 gtk_tree_view_expand_row(tree_view, path, FALSE);
119
120 /* get iter */
121 GtkTreeIter iter;
122 if (gtk_tree_model_get_iter(model, &iter, path)) {
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400123 QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400124
125 QVariant contact_method = idx.data(static_cast<int>(Call::Role::ContactMethod));
126 /* create new call */
127 if (contact_method.value<ContactMethod*>()) {
128 place_new_call(contact_method.value<ContactMethod*>());
129 }
130 }
131}
132
133static void
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400134render_call_photo(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
135 GtkCellRenderer *cell,
136 GtkTreeModel *tree_model,
137 GtkTreeIter *iter,
138 G_GNUC_UNUSED gpointer data)
139{
140 /* check if this is a top level item (category),
141 * in this case we don't want to show a photo */
142 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
143 int depth = gtk_tree_path_get_depth(path);
144 gtk_tree_path_free(path);
145 if (depth == 2) {
146 /* get person */
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400147 QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(tree_model), iter);
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400148 if (idx.isValid()) {
149 QVariant var_c = idx.data(static_cast<int>(Call::Role::Object));
150 Call *c = var_c.value<Call *>();
151 /* get photo */
Stepan Salenikovichbbd6c132015-08-20 15:21:48 -0400152 QVariant var_p = GlobalInstances::pixmapManipulator().callPhoto(c, QSize(50, 50), false);
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400153 std::shared_ptr<GdkPixbuf> photo = var_p.value<std::shared_ptr<GdkPixbuf>>();
154 g_object_set(G_OBJECT(cell), "pixbuf", photo.get(), NULL);
155 return;
156 }
157 }
158
159 /* otherwise, make sure its an empty pixbuf */
160 g_object_set(G_OBJECT(cell), "pixbuf", NULL, NULL);
161}
162
163static void
164render_name_and_contact_method(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
165 GtkCellRenderer *cell,
166 GtkTreeModel *tree_model,
167 GtkTreeIter *iter,
Stepan Salenikoviche4981b22015-10-22 15:22:59 -0400168 GtkTreeView *treeview)
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400169{
Stepan Salenikoviche4981b22015-10-22 15:22:59 -0400170 // check if this iter is selected
171 gboolean is_selected = FALSE;
172 if (GTK_IS_TREE_VIEW(treeview)) {
173 auto selection = gtk_tree_view_get_selection(treeview);
174 is_selected = gtk_tree_selection_iter_is_selected(selection, iter);
175 }
176
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400177 /**
178 * If call, show the name and the contact method (number) underneath;
179 * otherwise just display the category.
180 */
181 GtkTreePath *path = gtk_tree_model_get_path(tree_model, iter);
182 int depth = gtk_tree_path_get_depth(path);
183 gtk_tree_path_free(path);
184
185 gchar *text = NULL;
186
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400187 QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(tree_model), iter);
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400188 if (idx.isValid()) {
189 QVariant var = idx.data(Qt::DisplayRole);
190 if (depth == 1) {
191 /* category */
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400192 text = g_markup_printf_escaped("<b>%s</b>", var.value<QString>().toUtf8().constData());
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400193 } else if (depth == 2) {
194 /* call item */
195 QVariant var_name = idx.data(static_cast<int>(Call::Role::Name));
196 QVariant var_number = idx.data(static_cast<int>(Call::Role::Number));
Stepan Salenikoviche4981b22015-10-22 15:22:59 -0400197
198 /* we want the color of the status text to be the default color if this iter is
199 * selected so that the treeview is able to invert it against the selection color */
200 if (is_selected) {
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400201 text = g_markup_printf_escaped("%s\n %s",
202 var_name.value<QString>().toUtf8().constData(),
203 var_number.value<QString>().toUtf8().constData());
Stepan Salenikoviche4981b22015-10-22 15:22:59 -0400204 } else {
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400205 text = g_markup_printf_escaped("%s\n <span fgcolor=\"gray\">%s</span>",
206 var_name.value<QString>().toUtf8().constData(),
207 var_number.value<QString>().toUtf8().constData());
Stepan Salenikoviche4981b22015-10-22 15:22:59 -0400208 }
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400209 }
210 }
211
212 g_object_set(G_OBJECT(cell), "markup", text, NULL);
213 g_free(text);
214}
215
216static void
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500217render_date_time(G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
218 GtkCellRenderer *cell,
219 GtkTreeModel *tree_model,
220 GtkTreeIter *iter,
221 GtkTreeView *treeview)
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400222{
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500223 // check if this iter is selected
224 gboolean is_selected = FALSE;
225 if (GTK_IS_TREE_VIEW(treeview)) {
226 auto selection = gtk_tree_view_get_selection(treeview);
227 is_selected = gtk_tree_selection_iter_is_selected(selection, iter);
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400228 }
229
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400230 gchar *text = NULL;
231
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400232 QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(tree_model), iter);
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500233 QVariant var_d = idx.data(static_cast<int>(Call::Role::DateTime));
234 if (idx.isValid() && var_d.isValid()) {
Stepan Salenikovich803562b2015-12-23 10:51:01 -0500235 QDateTime date_time = var_d.value<QDateTime>();
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500236
237 /* we want the color of the text to be the default color if this iter is
238 * selected so that the treeview is able to invert it against the selection color */
239 if (is_selected) {
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400240 text = g_markup_printf_escaped("%s\n%s",
241 date_time.time().toString().toUtf8().constData(),
242 date_time.date().toString().toUtf8().constData()
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500243 );
244 } else {
Stepan Salenikovich0731de02016-05-17 17:47:16 -0400245 text = g_markup_printf_escaped("%s\n<span fgcolor=\"gray\">%s</span>",
246 date_time.time().toString().toUtf8().constData(),
247 date_time.date().toString().toUtf8().constData()
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500248 );
249 }
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400250 }
251
252 g_object_set(G_OBJECT(cell), "markup", text, NULL);
253 g_free(text);
254}
255
256static void
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400257history_view_init(HistoryView *self)
258{
259 HistoryViewPrivate *priv = HISTORY_VIEW_GET_PRIVATE(self);
260
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400261 /* make headers visible to allow column resizing */
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400262 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self), TRUE);
263 /* disable default search, we will handle it ourselves;
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400264 * otherwise the search steals input focus on key presses */
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400265 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(self), FALSE);
Stepan Salenikovichb01d7362015-04-27 23:02:00 -0400266
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400267 /* instantiate history proxy model */
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400268 auto q_sorted_proxy = &CategorizedHistoryModel::SortedProxy::instance();
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400269
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400270 /* select default category (the first one, which is by date) */
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400271 q_sorted_proxy->categorySelectionModel()->setCurrentIndex(
272 q_sorted_proxy->categoryModel()->index(0, 0),
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400273 QItemSelectionModel::ClearAndSelect);
Stepan Salenikovich803562b2015-12-23 10:51:01 -0500274 /* make sure it is sorted so that newest calls are at the top */
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400275 q_sorted_proxy->model()->sort(0, Qt::AscendingOrder);
276
277 /* filter for name and number */
278 priv->filterproxy = new NameNumberFilterProxy(q_sorted_proxy->model());
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400279
Stepan Salenikovichf6078222016-10-03 17:31:16 -0400280 GtkQTreeModel *history_model = gtk_q_tree_model_new(
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400281 priv->filterproxy,
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400282 5,
aviau271bcc22016-05-27 17:25:19 -0400283 0, Qt::DisplayRole, G_TYPE_STRING,
284 0, Call::Role::Number, G_TYPE_STRING,
285 0, Call::Role::FormattedDate, G_TYPE_STRING,
286 0, Call::Role::Direction, G_TYPE_INT,
287 0, Call::Role::Missed, G_TYPE_BOOLEAN);
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400288 gtk_tree_view_set_model( GTK_TREE_VIEW(self), GTK_TREE_MODEL(history_model) );
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400289
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400290 /* call direction, photo, name/number column */
291 GtkCellArea *area = gtk_cell_area_box_new();
292 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_area(area);
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -0400293 gtk_tree_view_column_set_title(column, C_("Call history", "Call"));
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400294
295 /* call direction */
296 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400297 gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(area), renderer, FALSE, FALSE, FALSE);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400298
299 /* display the call direction with arrows */
300 gtk_tree_view_column_set_cell_data_func(
301 column,
302 renderer,
303 (GtkTreeCellDataFunc)render_call_direction,
304 NULL,
305 NULL);
306
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400307 /* photo renderer */
308 renderer = gtk_cell_renderer_pixbuf_new();
309 gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(area), renderer, FALSE, FALSE, FALSE);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400310
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400311 /* get the photo */
312 gtk_tree_view_column_set_cell_data_func(
313 column,
314 renderer,
315 (GtkTreeCellDataFunc)render_call_photo,
316 NULL,
317 NULL);
318
319 /* name and contact method renderer */
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400320 renderer = gtk_cell_renderer_text_new();
321 g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400322 gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(area), renderer, FALSE, FALSE, FALSE);
323
324 gtk_tree_view_column_set_cell_data_func(
325 column,
326 renderer,
327 (GtkTreeCellDataFunc)render_name_and_contact_method,
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400328 self,
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400329 NULL);
330
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400331 gtk_tree_view_append_column(GTK_TREE_VIEW(self), column);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400332 gtk_tree_view_column_set_resizable(column, TRUE);
Stepan Salenikoviche7c4e282015-06-11 17:22:08 -0400333 gtk_tree_view_column_set_expand(column, TRUE);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400334
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500335 /* date time column */
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400336 area = gtk_cell_area_box_new();
337 column = gtk_tree_view_column_new_with_area(area);
Stepan Salenikovicha1b8cb32015-09-11 14:58:35 -0400338 gtk_tree_view_column_set_title(column, C_("Call history", "Date"));
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400339
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500340 /* date time renderer */
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400341 renderer = gtk_cell_renderer_text_new ();
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400342 gtk_cell_area_box_pack_start(GTK_CELL_AREA_BOX(area), renderer, FALSE, FALSE, FALSE);
343 /* format the time*/
344 gtk_tree_view_column_set_cell_data_func(
345 column,
346 renderer,
Stepan Salenikovich501a7f82015-12-23 11:06:47 -0500347 (GtkTreeCellDataFunc)render_date_time,
348 self,
Stepan Salenikovich82b1acf2015-05-12 12:33:51 -0400349 NULL);
350
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400351 gtk_tree_view_append_column(GTK_TREE_VIEW(self), column);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400352 gtk_tree_view_column_set_resizable(column, TRUE);
Stepan Salenikoviche7c4e282015-06-11 17:22:08 -0400353 gtk_tree_view_column_set_expand(column, FALSE);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400354
Stepan Salenikovich4a5dd7f2015-10-29 16:35:02 -0400355 g_signal_connect(self, "row-activated", G_CALLBACK(activate_history_item), NULL);
Stepan Salenikovich8eaa13e2016-08-26 16:51:48 -0400356
357 /* init popup menu */
358 priv->popup_menu = contact_popup_menu_new(GTK_TREE_VIEW(self));
359 g_signal_connect_swapped(self, "button-press-event", G_CALLBACK(contact_popup_menu_show), priv->popup_menu);
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400360
361 gtk_widget_show_all(GTK_WIDGET(self));
362}
363
364static void
365history_view_dispose(GObject *object)
366{
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400367 HistoryViewPrivate *priv = HISTORY_VIEW_GET_PRIVATE(object);
368
369 QObject::disconnect(priv->category_changed);
Stepan Salenikovich8eaa13e2016-08-26 16:51:48 -0400370 gtk_widget_destroy(priv->popup_menu);
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400371
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400372 G_OBJECT_CLASS(history_view_parent_class)->dispose(object);
373}
374
375static void
376history_view_finalize(GObject *object)
377{
Stepan Salenikovich9816a942015-04-22 17:49:16 -0400378 G_OBJECT_CLASS(history_view_parent_class)->finalize(object);
379}
380
381static void
382history_view_class_init(HistoryViewClass *klass)
383{
384 G_OBJECT_CLASS(klass)->finalize = history_view_finalize;
385 G_OBJECT_CLASS(klass)->dispose = history_view_dispose;
386}
387
388GtkWidget *
389history_view_new()
390{
391 gpointer self = g_object_new(HISTORY_VIEW_TYPE, NULL);
392
393 return (GtkWidget *)self;
Stepan Salenikovich9d294492015-05-14 16:34:24 -0400394}
Stepan Salenikovichdcfb5032016-10-26 18:57:56 -0400395
396void
397history_view_set_filter_string(HistoryView *self, const char *text)
398{
399 auto priv = HISTORY_VIEW_GET_PRIVATE(self);
400
401 priv->filterproxy->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
402
403 // if filtering, expand all categories so we can see the calls
404 // otherwise collapse all
405 if (text && strlen(text) > 0)
406 gtk_tree_view_expand_all(GTK_TREE_VIEW(self));
407 else
408 gtk_tree_view_collapse_all(GTK_TREE_VIEW(self));
409}