GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / dialogs / dialog-recent.c
blob111998d42e18f7069d09e25a7d938cc3d4017c6b
1 /*
2 * dialog-recent.c:
3 * Dialog for selecting from recently used files.
5 * Author:
6 * Morten Welinder (terra@gnome.org)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gnumeric.h>
25 #include "dialogs.h"
26 #include <wbc-gtk.h>
27 #include <gui-file.h>
28 #include <gui-util.h>
29 #include <gtk/gtk.h>
30 #include <string.h>
31 #include <goffice/goffice.h>
33 #define RECENT_KEY "recent-dialog"
35 enum {
36 RECENT_COL_INFO
39 /* ------------------------------------------------------------------------- */
41 static void
42 cb_selected (GtkTreeModel *model,
43 G_GNUC_UNUSED GtkTreePath *path,
44 GtkTreeIter *iter,
45 WBCGtk *wbcg)
47 char *uri = NULL;
48 GtkRecentInfo *info;
49 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &info, -1);
50 uri = g_strdup (gtk_recent_info_get_uri (info));
51 gtk_recent_info_unref (info);
52 if (uri) {
53 gui_file_read (wbcg, uri, NULL, NULL);
54 g_free (uri);
58 static void
59 cb_response (GtkWidget *dialog,
60 gint response_id,
61 WBCGtk *wbcg)
63 GtkBuilder *gui = g_object_get_data (G_OBJECT (dialog), "gui");
64 GtkTreeView *tv = GTK_TREE_VIEW (gtk_builder_get_object (gui, "docs_treeview"));
65 GtkTreeSelection *tsel = gtk_tree_view_get_selection (tv);
67 switch (response_id) {
68 case GTK_RESPONSE_OK:
69 gtk_tree_selection_selected_foreach (tsel, (GtkTreeSelectionForeachFunc) cb_selected, wbcg);
70 gtk_widget_destroy (dialog);
71 break;
73 default:
74 gtk_widget_destroy (dialog);
78 static void
79 cb_destroy (GtkDialog *dialog)
81 /* Trigger tear-down. */
82 g_object_set_data (G_OBJECT (dialog), "gui", NULL);
86 static gboolean
87 cb_key_press (GtkWidget *widget, GdkEventKey *event)
89 GtkTreeView *tree_view = (GtkTreeView *) widget;
91 switch (event->keyval) {
92 case GDK_KEY_KP_Delete:
93 case GDK_KEY_Delete: {
94 GtkTreeSelection *tsel = gtk_tree_view_get_selection (tree_view);
95 GtkTreeModel *model;
96 GtkTreeIter iter;
98 if (gtk_tree_selection_get_selected (tsel, &model, &iter)) {
99 GtkRecentInfo *info;
100 const char *uri;
101 GtkRecentManager *manager = gtk_recent_manager_get_default ();
103 gtk_tree_model_get (model, &iter, RECENT_COL_INFO, &info, -1);
104 uri = gtk_recent_info_get_uri (info);
106 gtk_recent_manager_remove_item (manager, uri, NULL);
107 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
108 gtk_recent_info_unref (info);
110 return TRUE;
113 default:
114 break;
117 return FALSE;
120 static gboolean
121 cb_button_press (GtkWidget *w, GdkEventButton *ev, WBCGtk *wbcg)
123 if (ev->type == GDK_2BUTTON_PRESS && ev->button == 1) {
124 GtkWidget *dlg = gtk_widget_get_toplevel (w);
125 if (GTK_IS_DIALOG (dlg)) {
126 cb_response (dlg, GTK_RESPONSE_OK, wbcg);
127 return TRUE;
130 return FALSE;
133 static void
134 url_renderer_func (GtkTreeViewColumn *tree_column,
135 GtkCellRenderer *cell,
136 GtkTreeModel *model,
137 GtkTreeIter *iter,
138 gpointer user_data)
140 GtkRecentInfo *ri = NULL;
141 const char *uri;
142 char *markup, *shortname, *filename, *longname;
144 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &ri, -1);
146 uri = gtk_recent_info_get_uri (ri);
147 filename = go_filename_from_uri (uri);
148 if (filename) {
149 shortname = g_filename_display_basename (filename);
150 } else {
151 shortname = g_filename_display_basename (uri);
154 if (filename) {
155 longname = g_strdup (filename);
156 } else {
157 char *duri = g_uri_unescape_string (uri, NULL);
158 longname = duri
159 ? g_filename_display_name (duri)
160 : g_strdup (uri);
161 g_free (duri);
164 markup = g_markup_printf_escaped (_("<b>%s</b>\n"
165 "<small>Location: %s</small>"),
166 shortname,
167 longname);
168 g_object_set (cell, "markup", markup, NULL);
169 g_free (markup);
170 g_free (shortname);
171 g_free (longname);
172 g_free (filename);
173 gtk_recent_info_unref (ri);
176 static void
177 age_renderer_func (GtkTreeViewColumn *tree_column,
178 GtkCellRenderer *cell,
179 GtkTreeModel *model,
180 GtkTreeIter *iter,
181 gpointer user_data)
183 GtkRecentInfo *ri = NULL;
184 GDateTime *now = user_data;
185 GDateTime *last_used;
186 GTimeSpan age;
187 char *text;
188 const char *date_format;
189 const char *p;
191 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &ri, -1);
192 last_used = g_date_time_new_from_unix_local (gtk_recent_info_get_modified (ri));
193 gtk_recent_info_unref (ri);
195 age = g_date_time_difference (now, last_used);
196 if (age < G_TIME_SPAN_DAY &&
197 g_date_time_get_day_of_month (now) == g_date_time_get_day_of_month (last_used)) {
198 if (go_locale_24h ())
200 * xgettext: This is a time format for
201 * g_date_time_format used in locales that use a
202 * 24 hour clock. You probably do not need to change
203 * this. The default will show things like "09:50"
204 * and "21:50".
206 date_format = _("%H:%M");
207 else
209 * xgettext: This is a time format for
210 * g_date_time_format used in locales that use
211 * a 12 hour clock. You probably do not need
212 * to change this. The default will show
213 * things like " 9:50 am" and " 9:50 pm".
215 date_format = _("%l:%M %P");
216 } else {
217 date_format = "%x";
220 p = text = g_date_time_format (last_used, date_format);
221 while (g_ascii_isspace (*p))
222 p++;
223 g_object_set (cell, "text", p, "xalign", 0.5, NULL);
224 g_free (text);
226 g_date_time_unref (last_used);
229 static gint
230 by_age_uri (gconstpointer a_, gconstpointer b_)
232 GtkRecentInfo *a = (gpointer)a_;
233 GtkRecentInfo *b = (gpointer)b_;
234 int res;
236 res = gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a);
237 if (res) return res;
239 res = strcmp (gtk_recent_info_get_uri (a), gtk_recent_info_get_uri (b));
240 return res;
244 static void
245 populate_recent_model (GtkBuilder *gui)
247 GtkListStore *list = GTK_LIST_STORE (gtk_builder_get_object (gui, "recent_model"));
248 gboolean existing_only = gtk_toggle_button_get_active
249 (GTK_TOGGLE_BUTTON (gtk_builder_get_object (gui, "existing_only_button")));
250 gboolean gnumeric_only = gtk_toggle_button_get_active
251 (GTK_TOGGLE_BUTTON (gtk_builder_get_object (gui, "gnumeric_only_button")));
252 GtkRecentManager *manager = gtk_recent_manager_get_default ();
253 GList *docs, *l;
255 gtk_list_store_clear (list);
257 docs = gtk_recent_manager_get_items (manager);
258 docs = g_list_sort (docs, by_age_uri);
259 for (l = docs; l; l = l->next) {
260 GtkRecentInfo *ri = l->data;
261 GtkTreeIter iter;
263 if (existing_only) {
264 gboolean exists = gtk_recent_info_is_local (ri)
265 ? gtk_recent_info_exists (ri)
266 : TRUE; /* Just assume so */
267 if (!exists)
268 continue;
271 if (gnumeric_only) {
272 if (!gtk_recent_info_has_application (ri, g_get_application_name ()))
273 continue;
276 gtk_list_store_append (list, &iter);
277 gtk_list_store_set (list, &iter, RECENT_COL_INFO, ri, -1);
279 g_list_free_full (docs, (GDestroyNotify)gtk_recent_info_unref);
283 void
284 dialog_recent_used (WBCGtk *wbcg)
286 GtkBuilder *gui;
287 GtkDialog *dialog;
289 /* Only pop up one copy per workbook */
290 if (gnm_dialog_raise_if_exists (wbcg, RECENT_KEY))
291 return;
293 gui = gnm_gtk_builder_load ("res:ui/recent.ui", NULL, GO_CMD_CONTEXT (wbcg));
294 if (gui == NULL)
295 return;
297 dialog = GTK_DIALOG (go_gtk_builder_get_widget (gui, "recent_dialog"));
299 g_signal_connect (G_OBJECT (dialog), "response",
300 G_CALLBACK (cb_response), wbcg);
304 GtkWidget *w;
305 int width, height, vsep;
306 PangoLayout *layout;
307 GtkTreeView *tv;
308 GtkTreeSelection *tsel;
310 w = GTK_WIDGET (wbcg_toplevel (wbcg));
311 layout = gtk_widget_create_pango_layout (w, "Mg19");
313 w = go_gtk_builder_get_widget (gui, "docs_treeview");
314 gtk_widget_style_get (w, "vertical_separator", &vsep, NULL);
315 g_signal_connect (w, "key-press-event",
316 G_CALLBACK (cb_key_press),
317 NULL);
318 g_signal_connect (w, "button-press-event",
319 G_CALLBACK (cb_button_press),
320 wbcg);
322 pango_layout_get_pixel_size (layout, &width, &height);
323 gtk_widget_set_size_request (go_gtk_builder_get_widget (gui, "docs_scrolledwindow"),
324 width * 60 / 4,
325 (2 * height + vsep) * (5 + 1));
326 g_object_unref (layout);
327 tv = GTK_TREE_VIEW (gtk_builder_get_object (gui, "docs_treeview"));
328 tsel = gtk_tree_view_get_selection (tv);
329 gtk_tree_selection_set_mode (tsel, GTK_SELECTION_MULTIPLE);
332 g_signal_connect_swapped (gtk_builder_get_object (gui, "existing_only_button"),
333 "toggled", G_CALLBACK (populate_recent_model), gui);
334 g_signal_connect_swapped (gtk_builder_get_object (gui, "gnumeric_only_button"),
335 "toggled", G_CALLBACK (populate_recent_model), gui);
337 populate_recent_model (gui);
339 gtk_tree_view_column_set_cell_data_func
340 (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui, "url_column")),
341 GTK_CELL_RENDERER (gtk_builder_get_object (gui, "url_renderer")),
342 url_renderer_func,
343 NULL,
344 NULL);
346 gtk_tree_view_column_set_cell_data_func
347 (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui, "age_column")),
348 GTK_CELL_RENDERER (gtk_builder_get_object (gui, "age_renderer")),
349 age_renderer_func,
350 g_date_time_new_now_local (),
351 (GDestroyNotify)g_date_time_unref);
353 /* ---------------------------------------- */
355 g_object_set_data_full (G_OBJECT (dialog), "gui", gui, g_object_unref);
356 g_signal_connect (dialog, "destroy", G_CALLBACK (cb_destroy), NULL);
357 go_gtk_nonmodal_dialog (wbcg_toplevel (wbcg), GTK_WINDOW (dialog));
358 gtk_widget_show_all (GTK_WIDGET (dialog));
361 /* ------------------------------------------------------------------------- */