Update Spanish translation
[gnumeric.git] / src / dialogs / dialog-recent.c
blob47ba8cab5a506bfc8076e74b5350d7660b1e53e5
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/dialogs.h>
26 #include <wbc-gtk.h>
27 #include <gui-file.h>
28 #include <gui-util.h>
29 #include <string.h>
30 #include <goffice/goffice.h>
32 #define RECENT_KEY "recent-dialog"
34 enum {
35 RECENT_COL_INFO
38 /* ------------------------------------------------------------------------- */
40 static void
41 cb_selected (GtkTreeModel *model,
42 G_GNUC_UNUSED GtkTreePath *path,
43 GtkTreeIter *iter,
44 WBCGtk *wbcg)
46 char *uri = NULL;
47 GtkRecentInfo *info;
48 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &info, -1);
49 uri = g_strdup (gtk_recent_info_get_uri (info));
50 gtk_recent_info_unref (info);
51 if (uri) {
52 gui_file_read (wbcg, uri, NULL, NULL);
53 g_free (uri);
57 static void
58 cb_response (GtkWidget *dialog,
59 gint response_id,
60 WBCGtk *wbcg)
62 GtkBuilder *gui = g_object_get_data (G_OBJECT (dialog), "gui");
63 GtkTreeView *tv = GTK_TREE_VIEW (gtk_builder_get_object (gui, "docs_treeview"));
64 GtkTreeSelection *tsel = gtk_tree_view_get_selection (tv);
66 switch (response_id) {
67 case GTK_RESPONSE_OK:
68 gtk_tree_selection_selected_foreach (tsel, (GtkTreeSelectionForeachFunc) cb_selected, wbcg);
69 gtk_widget_destroy (dialog);
70 break;
72 default:
73 gtk_widget_destroy (dialog);
77 static void
78 cb_destroy (GtkDialog *dialog)
80 /* Trigger tear-down. */
81 g_object_set_data (G_OBJECT (dialog), "gui", NULL);
85 static gboolean
86 cb_key_press (GtkWidget *widget, GdkEventKey *event)
88 GtkTreeView *tree_view = (GtkTreeView *) widget;
90 switch (event->keyval) {
91 case GDK_KEY_KP_Delete:
92 case GDK_KEY_Delete: {
93 GtkTreeSelection *tsel = gtk_tree_view_get_selection (tree_view);
94 GtkTreeModel *model;
95 GtkTreeIter iter;
97 if (gtk_tree_selection_get_selected (tsel, &model, &iter)) {
98 GtkRecentInfo *info;
99 const char *uri;
100 GtkRecentManager *manager = gtk_recent_manager_get_default ();
102 gtk_tree_model_get (model, &iter, RECENT_COL_INFO, &info, -1);
103 uri = gtk_recent_info_get_uri (info);
105 gtk_recent_manager_remove_item (manager, uri, NULL);
106 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
107 gtk_recent_info_unref (info);
109 return TRUE;
112 default:
113 break;
116 return FALSE;
119 static gboolean
120 cb_button_press (GtkWidget *w, GdkEventButton *ev, WBCGtk *wbcg)
122 if (ev->type == GDK_2BUTTON_PRESS && ev->button == 1) {
123 GtkWidget *dlg = gtk_widget_get_toplevel (w);
124 if (GTK_IS_DIALOG (dlg)) {
125 cb_response (dlg, GTK_RESPONSE_OK, wbcg);
126 return TRUE;
129 return FALSE;
132 static void
133 url_renderer_func (GtkTreeViewColumn *tree_column,
134 GtkCellRenderer *cell,
135 GtkTreeModel *model,
136 GtkTreeIter *iter,
137 gpointer user_data)
139 GtkRecentInfo *ri = NULL;
140 const char *uri;
141 char *markup, *shortname, *filename, *longname;
143 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &ri, -1);
145 uri = gtk_recent_info_get_uri (ri);
146 filename = go_filename_from_uri (uri);
147 if (filename) {
148 shortname = g_filename_display_basename (filename);
149 } else {
150 shortname = g_filename_display_basename (uri);
153 if (filename) {
154 longname = g_strdup (filename);
155 } else {
156 char *duri = g_uri_unescape_string (uri, NULL);
157 longname = duri
158 ? g_filename_display_name (duri)
159 : g_strdup (uri);
160 g_free (duri);
163 markup = g_markup_printf_escaped (_("<b>%s</b>\n"
164 "<small>Location: %s</small>"),
165 shortname,
166 longname);
167 g_object_set (cell, "markup", markup, NULL);
168 g_free (markup);
169 g_free (shortname);
170 g_free (longname);
171 g_free (filename);
172 gtk_recent_info_unref (ri);
175 static void
176 age_renderer_func (GtkTreeViewColumn *tree_column,
177 GtkCellRenderer *cell,
178 GtkTreeModel *model,
179 GtkTreeIter *iter,
180 gpointer user_data)
182 GtkRecentInfo *ri = NULL;
183 GDateTime *now = user_data;
184 GDateTime *last_used;
185 GTimeSpan age;
186 char *text;
187 const char *date_format;
188 const char *p;
190 gtk_tree_model_get (model, iter, RECENT_COL_INFO, &ri, -1);
191 last_used = g_date_time_new_from_unix_local (gtk_recent_info_get_modified (ri));
192 gtk_recent_info_unref (ri);
194 age = g_date_time_difference (now, last_used);
195 if (age < G_TIME_SPAN_DAY &&
196 g_date_time_get_day_of_month (now) == g_date_time_get_day_of_month (last_used)) {
197 if (go_locale_24h ())
199 * xgettext: This is a time format for
200 * g_date_time_format used in locales that use a
201 * 24 hour clock. You probably do not need to change
202 * this. The default will show things like "09:50"
203 * and "21:50".
205 date_format = _("%H:%M");
206 else
208 * xgettext: This is a time format for
209 * g_date_time_format used in locales that use
210 * a 12 hour clock. You probably do not need
211 * to change this. The default will show
212 * things like " 9:50 am" and " 9:50 pm".
214 date_format = _("%l:%M %P");
215 } else {
216 date_format = "%x";
219 p = text = g_date_time_format (last_used, date_format);
220 while (g_ascii_isspace (*p))
221 p++;
222 g_object_set (cell, "text", p, "xalign", 0.5, NULL);
223 g_free (text);
225 g_date_time_unref (last_used);
228 static gint
229 by_age_uri (gconstpointer a_, gconstpointer b_)
231 GtkRecentInfo *a = (gpointer)a_;
232 GtkRecentInfo *b = (gpointer)b_;
233 int res;
235 res = gtk_recent_info_get_modified (b) - gtk_recent_info_get_modified (a);
236 if (res) return res;
238 res = strcmp (gtk_recent_info_get_uri (a), gtk_recent_info_get_uri (b));
239 return res;
243 static void
244 populate_recent_model (GtkBuilder *gui)
246 GtkListStore *list = GTK_LIST_STORE (gtk_builder_get_object (gui, "recent_model"));
247 gboolean existing_only = gtk_toggle_button_get_active
248 (GTK_TOGGLE_BUTTON (gtk_builder_get_object (gui, "existing_only_button")));
249 gboolean gnumeric_only = gtk_toggle_button_get_active
250 (GTK_TOGGLE_BUTTON (gtk_builder_get_object (gui, "gnumeric_only_button")));
251 GtkRecentManager *manager = gtk_recent_manager_get_default ();
252 GList *docs, *l;
254 gtk_list_store_clear (list);
256 docs = gtk_recent_manager_get_items (manager);
257 docs = g_list_sort (docs, by_age_uri);
258 for (l = docs; l; l = l->next) {
259 GtkRecentInfo *ri = l->data;
260 GtkTreeIter iter;
262 if (existing_only) {
263 gboolean exists = gtk_recent_info_is_local (ri)
264 ? gtk_recent_info_exists (ri)
265 : TRUE; /* Just assume so */
266 if (!exists)
267 continue;
270 if (gnumeric_only) {
271 if (!gtk_recent_info_has_application (ri, g_get_application_name ()))
272 continue;
275 gtk_list_store_append (list, &iter);
276 gtk_list_store_set (list, &iter, RECENT_COL_INFO, ri, -1);
278 g_list_free_full (docs, (GDestroyNotify)gtk_recent_info_unref);
282 void
283 dialog_recent_used (WBCGtk *wbcg)
285 GtkBuilder *gui;
286 GtkDialog *dialog;
288 /* Only pop up one copy per workbook */
289 if (gnm_dialog_raise_if_exists (wbcg, RECENT_KEY))
290 return;
292 gui = gnm_gtk_builder_load ("res:ui/recent.ui", NULL, GO_CMD_CONTEXT (wbcg));
293 if (gui == NULL)
294 return;
296 dialog = GTK_DIALOG (go_gtk_builder_get_widget (gui, "recent_dialog"));
298 g_signal_connect (G_OBJECT (dialog), "response",
299 G_CALLBACK (cb_response), wbcg);
303 GtkWidget *w;
304 int width, height, vsep;
305 PangoLayout *layout;
306 GtkTreeView *tv;
307 GtkTreeSelection *tsel;
309 w = GTK_WIDGET (wbcg_toplevel (wbcg));
310 layout = gtk_widget_create_pango_layout (w, "Mg19");
312 w = go_gtk_builder_get_widget (gui, "docs_treeview");
313 gtk_widget_style_get (w, "vertical_separator", &vsep, NULL);
314 g_signal_connect (w, "key-press-event",
315 G_CALLBACK (cb_key_press),
316 NULL);
317 g_signal_connect (w, "button-press-event",
318 G_CALLBACK (cb_button_press),
319 wbcg);
321 pango_layout_get_pixel_size (layout, &width, &height);
322 gtk_widget_set_size_request (go_gtk_builder_get_widget (gui, "docs_scrolledwindow"),
323 width * 60 / 4,
324 (2 * height + vsep) * (5 + 1));
325 g_object_unref (layout);
326 tv = GTK_TREE_VIEW (gtk_builder_get_object (gui, "docs_treeview"));
327 tsel = gtk_tree_view_get_selection (tv);
328 gtk_tree_selection_set_mode (tsel, GTK_SELECTION_MULTIPLE);
331 g_signal_connect_swapped (gtk_builder_get_object (gui, "existing_only_button"),
332 "toggled", G_CALLBACK (populate_recent_model), gui);
333 g_signal_connect_swapped (gtk_builder_get_object (gui, "gnumeric_only_button"),
334 "toggled", G_CALLBACK (populate_recent_model), gui);
336 populate_recent_model (gui);
338 gtk_tree_view_column_set_cell_data_func
339 (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui, "url_column")),
340 GTK_CELL_RENDERER (gtk_builder_get_object (gui, "url_renderer")),
341 url_renderer_func,
342 NULL,
343 NULL);
345 gtk_tree_view_column_set_cell_data_func
346 (GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (gui, "age_column")),
347 GTK_CELL_RENDERER (gtk_builder_get_object (gui, "age_renderer")),
348 age_renderer_func,
349 g_date_time_new_now_local (),
350 (GDestroyNotify)g_date_time_unref);
352 /* ---------------------------------------- */
354 g_object_set_data_full (G_OBJECT (dialog), "gui", gui, g_object_unref);
355 g_signal_connect (dialog, "destroy", G_CALLBACK (cb_destroy), NULL);
356 go_gtk_nonmodal_dialog (wbcg_toplevel (wbcg), GTK_WINDOW (dialog));
357 gtk_widget_show_all (GTK_WIDGET (dialog));
360 /* ------------------------------------------------------------------------- */