~ubuntu-branches/ubuntu/saucy/bluefish/saucy

« back to all changes in this revision

Viewing changes to .pc/fix_segfault_blocksync.patch/src/file_dialogs.c

  • Committer: Package Import Robot
  • Author(s): Daniel Leidert
  • Date: 2013-05-09 14:36:58 UTC
  • mfrom: (17.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130509143658-kgqxj5c23oi0lk20
Tags: 2.2.4-2
* debian/control (Standards-Version): Bumped to 3.9.4.
* debian/copyright: Updated.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Bluefish HTML Editor
2
 
 * file_dialogs.c - file dialogs
3
 
 *
4
 
 * Copyright (C) 2005-2011 Olivier Sessink
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 3 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
/* indented with indent -ts4 -kr -l110   */
21
 
/*#define DEBUG*/
22
 
 
23
 
#include <gtk/gtk.h>
24
 
#include <string.h>                             /* memcpy */
25
 
#include <time.h>                               /* strftime() */
26
 
 
27
 
#include "bluefish.h"
28
 
#include "file_dialogs.h"
29
 
#include "bfwin.h"
30
 
#include "bookmark.h"
31
 
#include "dialog_utils.h"
32
 
#include "document.h"
33
 
#include "file_autosave.h"
34
 
#include "file.h"
35
 
#include "filebrowser2.h"
36
 
#include "gtk_easy.h"
37
 
#include "snr3.h"                               /* snr3_run_extern_replace() */
38
 
#include "stringlist.h"
39
 
#include "undo_redo.h"
40
 
 
41
 
static gchar *modified_on_disk_warning_string(const gchar * filename, GFileInfo * oldfinfo,
42
 
                                                                                          GFileInfo * newfinfo);
43
 
 
44
 
/**************************************************************************/
45
 
/* the start of the callback functions for the menu, acting on a document */
46
 
/**************************************************************************/
47
 
typedef struct {
48
 
        GtkWidget *dialog;
49
 
        GtkWidget *basedir;
50
 
        GtkWidget *find_pattern;
51
 
        GtkWidget *matchname;
52
 
        GtkWidget *recursive;
53
 
        GtkWidget *max_recursion;
54
 
        GtkWidget *grep_pattern;
55
 
        GtkWidget *is_regex;
56
 
        GtkWidget *regexwarn;
57
 
        Tbfwin *bfwin;
58
 
} Tfiles_advanced;
59
 
 
60
 
static void
61
 
files_advanced_win_findpattern_changed(GtkComboBox * combobox, Tfiles_advanced * tfs)
62
 
{
63
 
        if (strlen(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tfs->find_pattern))))) > 0) {
64
 
                gtk_dialog_set_response_sensitive(GTK_DIALOG(tfs->dialog), GTK_RESPONSE_ACCEPT, TRUE);
65
 
        } else {
66
 
                gtk_dialog_set_response_sensitive(GTK_DIALOG(tfs->dialog), GTK_RESPONSE_ACCEPT, FALSE);
67
 
        }
68
 
}
69
 
 
70
 
static gboolean
71
 
files_advanced_win_ok_clicked(Tfiles_advanced * tfs)
72
 
{
73
 
        GFile *baseuri;
74
 
        gchar *basedir, *content_filter, *extension_filter;
75
 
        gboolean retval;
76
 
        GError *gerror = NULL;
77
 
        extension_filter =
78
 
                gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(tfs->find_pattern))), 0, -1);
79
 
        basedir = gtk_editable_get_chars(GTK_EDITABLE(tfs->basedir), 0, -1);
80
 
        baseuri = g_file_new_for_uri(basedir);
81
 
        content_filter = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(tfs->grep_pattern));
82
 
        if (content_filter && content_filter[0]!='\0')
83
 
                tfs->bfwin->session->searchlist = add_to_history_stringlist(tfs->bfwin->session->searchlist, content_filter, FALSE, TRUE);
84
 
        if (extension_filter && extension_filter[0] != '\0') 
85
 
                tfs->bfwin->session->filegloblist = add_to_history_stringlist(tfs->bfwin->session->filegloblist, extension_filter,FALSE, TRUE);
86
 
 
87
 
        retval =
88
 
                open_advanced(tfs->bfwin, baseuri, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tfs->recursive))
89
 
                                          , 500, !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tfs->matchname))
90
 
                                          ,
91
 
                                          strlen(extension_filter) == 0 ? NULL : extension_filter,
92
 
                                          strlen(content_filter) == 0 ? NULL : content_filter,
93
 
                                          gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tfs->is_regex)), &gerror);
94
 
        if (!retval && gerror) {
95
 
                gtk_label_set_line_wrap(GTK_LABEL(tfs->regexwarn), TRUE);
96
 
                gtk_label_set_text(GTK_LABEL(tfs->regexwarn), gerror->message);
97
 
                g_error_free(gerror);
98
 
        }
99
 
        g_free(basedir);
100
 
        g_free(content_filter);
101
 
        g_free(extension_filter);
102
 
        g_object_unref(baseuri);
103
 
 
104
 
        tfs->bfwin->session->adv_open_recursive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tfs->recursive));
105
 
        tfs->bfwin->session->adv_open_matchname =
106
 
                !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tfs->matchname));
107
 
        if (retval)
108
 
                bfwin_statusbar_message(tfs->bfwin,_("Started open advanced..."), 1);
109
 
        return retval;
110
 
}
111
 
 
112
 
static void
113
 
files_advanced_win_select_basedir_lcb(GtkWidget * widget, Tfiles_advanced * tfs)
114
 
{
115
 
        gchar *newdir = NULL;
116
 
        GtkWidget *dialog;
117
 
 
118
 
        dialog =
119
 
                file_chooser_dialog(tfs->bfwin, _("Select basedir"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, (gchar *)
120
 
                                                        gtk_entry_get_text(GTK_ENTRY(tfs->basedir)), TRUE, FALSE, NULL, FALSE);
121
 
        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
122
 
                newdir = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
123
 
        }
124
 
        gtk_widget_destroy(dialog);
125
 
 
126
 
        if (newdir) {
127
 
                gtk_entry_set_text(GTK_ENTRY(tfs->basedir), newdir);
128
 
                g_free(newdir);
129
 
        }
130
 
}
131
 
 
132
 
void
133
 
files_advanced_win(Tbfwin * bfwin, gchar * basedir)
134
 
{
135
 
        GtkWidget *alignment, *button, *carea, *table, *vbox, *vbox2;
136
 
        Tfiles_advanced *tfs;
137
 
 
138
 
        tfs = g_new(Tfiles_advanced, 1);
139
 
        tfs->bfwin = bfwin;
140
 
 
141
 
        tfs->dialog = gtk_dialog_new_with_buttons(_("Advanced open file selector"),
142
 
                                                                                          GTK_WINDOW(tfs->bfwin->main_window),
143
 
                                                                                          GTK_DIALOG_DESTROY_WITH_PARENT,
144
 
                                                                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
145
 
                                                                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
146
 
 
147
 
#if !GTK_CHECK_VERSION(3, 0, 0)
148
 
        gtk_dialog_set_has_separator(GTK_DIALOG(tfs->dialog), FALSE);
149
 
#endif /* gtk3 */
150
 
        carea = gtk_dialog_get_content_area(GTK_DIALOG(tfs->dialog));
151
 
 
152
 
        alignment = gtk_alignment_new(0, 0, 1, 1);
153
 
        gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 12, 0, 12, 6);
154
 
        gtk_box_pack_start(GTK_BOX(carea), alignment, FALSE, FALSE, 0);
155
 
        vbox = gtk_vbox_new(FALSE, 0);
156
 
        gtk_container_add(GTK_CONTAINER(alignment), vbox);
157
 
 
158
 
        vbox2 = dialog_vbox_labeled(_("<b>Files</b>"), vbox);
159
 
 
160
 
        table = dialog_table_in_vbox(2, 6, 0, vbox2, FALSE, FALSE, 6);
161
 
 
162
 
        if (!basedir) {
163
 
                tfs->basedir = dialog_entry_in_table(bfwin->session->opendir, table, 1, 5, 0, 1);
164
 
        } else {
165
 
                tfs->basedir = dialog_entry_in_table(basedir, table, 1, 5, 0, 1);
166
 
        }
167
 
        dialog_mnemonic_label_in_table(_("Base _Dir:"), tfs->basedir, table, 0, 1, 0, 1);
168
 
 
169
 
        button =
170
 
                dialog_button_new_with_image_in_table(NULL, GTK_STOCK_OPEN, G_CALLBACK(files_advanced_win_select_basedir_lcb), tfs, 
171
 
                                                TRUE, FALSE,
172
 
                                                table, 5, 6, 0,1);
173
 
 
174
 
 
175
 
        /*lstore = gtk_list_store_new(1, G_TYPE_STRING);
176
 
        for (tmplist = g_list_first(bfwin->session->filegloblist); tmplist; tmplist = g_list_next(tmplist)) {
177
 
                gtk_list_store_append(GTK_LIST_STORE(lstore), &iter);
178
 
                gtk_list_store_set(GTK_LIST_STORE(lstore), &iter, 0, tmplist->data, -1);
179
 
        }
180
 
        tfs->find_pattern = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(lstore), 0);
181
 
        g_object_unref(lstore);*/
182
 
        tfs->find_pattern = combobox_with_popdown("", bfwin->session->filegloblist, TRUE);
183
 
        dialog_mnemonic_label_in_table(_("_Pattern:"), tfs->find_pattern, table, 0, 1, 1, 2);
184
 
        gtk_table_attach_defaults(GTK_TABLE(table), tfs->find_pattern, 1, 5, 1, 2);
185
 
        g_signal_connect(G_OBJECT(tfs->find_pattern), "changed",
186
 
                                         G_CALLBACK(files_advanced_win_findpattern_changed), tfs);
187
 
 
188
 
        table = dialog_table_in_vbox(3, 2, 0, vbox2, FALSE, FALSE, 0);
189
 
 
190
 
        tfs->matchname = checkbut_with_value(NULL, tfs->bfwin ? !tfs->bfwin->session->adv_open_matchname : FALSE);
191
 
        dialog_mnemonic_label_in_table(_("Pattern matches _full path:"), tfs->matchname, table, 0, 1, 0, 1);
192
 
        gtk_table_attach(GTK_TABLE(table), tfs->matchname, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
193
 
 
194
 
        tfs->recursive = checkbut_with_value(NULL, tfs->bfwin ? tfs->bfwin->session->adv_open_recursive : TRUE);
195
 
        dialog_mnemonic_label_in_table(_("_Recursive:"), tfs->recursive, table, 0, 1, 1, 2);
196
 
        gtk_table_attach(GTK_TABLE(table), tfs->recursive, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
197
 
 
198
 
        tfs->max_recursion = spinbut_with_value("100", 1, 100000, 1, 10);
199
 
        dialog_mnemonic_label_in_table(_("Ma_x recursion:"), tfs->max_recursion, table, 0, 1, 2, 3);
200
 
        gtk_table_attach(GTK_TABLE(table), tfs->max_recursion, 1, 2, 2, 3, GTK_SHRINK, GTK_SHRINK, 0, 0);
201
 
 
202
 
        alignment = gtk_alignment_new(0, 0, 1, 1);
203
 
        gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 12, 18, 12, 6);
204
 
        gtk_box_pack_start(GTK_BOX(carea), alignment, FALSE, FALSE, 0);
205
 
        vbox = gtk_vbox_new(FALSE, 0);
206
 
        gtk_container_add(GTK_CONTAINER(alignment), vbox);
207
 
 
208
 
        vbox2 = dialog_vbox_labeled(_("<b>Contains</b>"), vbox);
209
 
 
210
 
        table = dialog_table_in_vbox(2, 4, 0, vbox2, FALSE, FALSE, 6);
211
 
 
212
 
        tfs->grep_pattern = combobox_with_popdown("", bfwin->session->searchlist, TRUE);
213
 
        dialog_mnemonic_label_in_table(_("Pa_ttern:"), tfs->grep_pattern, table, 0, 1, 0, 1);
214
 
        gtk_table_attach_defaults(GTK_TABLE(table), tfs->grep_pattern, 1, 4, 0, 1);
215
 
 
216
 
        tfs->is_regex = checkbut_with_value(NULL, 0);
217
 
        dialog_mnemonic_label_in_table(_("Is rege_x:"), tfs->is_regex, table, 0, 1, 1, 2);
218
 
        gtk_table_attach(GTK_TABLE(table), tfs->is_regex, 1, 2, 1, 2, GTK_FILL, GTK_SHRINK, 0, 0);
219
 
 
220
 
        tfs->regexwarn = gtk_label_new(NULL);
221
 
        gtk_table_attach(GTK_TABLE(table), tfs->regexwarn, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
222
 
 
223
 
        gtk_dialog_set_response_sensitive(GTK_DIALOG(tfs->dialog), GTK_RESPONSE_ACCEPT, FALSE);
224
 
        gtk_widget_show_all(carea);
225
 
 
226
 
        while (gtk_dialog_run(GTK_DIALOG(tfs->dialog)) == GTK_RESPONSE_ACCEPT) {
227
 
                if (files_advanced_win_ok_clicked(tfs))
228
 
                        break;
229
 
        }
230
 
 
231
 
        gtk_widget_destroy(tfs->dialog);
232
 
        g_free(tfs);
233
 
}
234
 
 
235
 
void
236
 
file_open_advanced_cb(GtkWidget * widget, Tbfwin * bfwin)
237
 
{
238
 
        files_advanced_win(bfwin, NULL);
239
 
}
240
 
 
241
 
/*************** end of advanced open code *************/
242
 
 
243
 
static void
244
 
file_open_ok_lcb(GtkDialog * dialog, gint response, Tbfwin * bfwin)
245
 
{
246
 
        if (response == GTK_RESPONSE_ACCEPT) {
247
 
                GSList *slist, *tmpslist;
248
 
                GtkComboBox *combo;
249
 
                bfwin->focus_next_new_doc = TRUE;
250
 
                combo = g_object_get_data(G_OBJECT(dialog), "encodings");
251
 
                if (combo) {
252
 
                        GtkTreeIter iter;
253
 
                        if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) {
254
 
                                GtkTreeModel *model;
255
 
                                gchar **arr;
256
 
                                model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
257
 
                                gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &arr, -1);
258
 
                                if (bfwin->session->encoding)
259
 
                                        g_free(bfwin->session->encoding);
260
 
                                if (arr) {
261
 
                                        bfwin->session->encoding = g_strdup(arr[1]);
262
 
                                } else {
263
 
                                        bfwin->session->encoding = NULL;
264
 
                                }
265
 
                                DEBUG_MSG("file_open_ok_lcb, session encoding is set to %s\n", bfwin->session->encoding);
266
 
                        }
267
 
                }
268
 
#if GTK_CHECK_VERSION(2,14,0)
269
 
                tmpslist = slist = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
270
 
                while (tmpslist) {
271
 
                        doc_new_from_uri(bfwin, (GFile *) tmpslist->data, NULL, (slist->next != NULL), FALSE, -1, -1);
272
 
                        g_object_unref((GFile *) tmpslist->data);
273
 
                        tmpslist = tmpslist->next;
274
 
                }
275
 
                g_slist_free(slist);
276
 
#else
277
 
                tmpslist = slist = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(dialog));
278
 
                while (tmpslist) {
279
 
                        GFile *file;
280
 
                        file = g_file_new_for_uri((gchar *) tmpslist->data);
281
 
                        doc_new_from_uri(bfwin, file, NULL, (slist->next != NULL), FALSE, -1, -1);
282
 
                        g_object_unref(file);
283
 
                        g_free((gchar *) tmpslist->data);
284
 
                        tmpslist = tmpslist->next;
285
 
                }
286
 
                g_slist_free(slist);
287
 
#endif
288
 
        }
289
 
        gtk_widget_destroy(GTK_WIDGET(dialog));
290
 
}
291
 
 
292
 
void
293
 
file_open_doc(Tbfwin * bfwin)
294
 
{
295
 
        GtkWidget *dialog;
296
 
 
297
 
        dialog =
298
 
                file_chooser_dialog(bfwin, _("Select files"), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, FALSE, TRUE, NULL,
299
 
                                                        TRUE);
300
 
        g_signal_connect(dialog, "response", G_CALLBACK(file_open_ok_lcb), bfwin);
301
 
        gtk_widget_show_all(dialog);
302
 
}
303
 
 
304
 
/**
305
 
 * file_open_cb:
306
 
 * @widget: unused #GtkWidget
307
 
 * @bfwin: #Tbfwin* with the current window
308
 
 *
309
 
 * Prompt user for files to open.
310
 
 *
311
 
 * Return value: void
312
 
 **/
313
 
void
314
 
file_open_cb(GtkWidget * widget, Tbfwin * bfwin)
315
 
{
316
 
        GtkWidget *dialog;
317
 
        dialog =
318
 
                file_chooser_dialog(bfwin, _("Select files"), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, FALSE, TRUE, NULL,
319
 
                                                        TRUE);
320
 
        g_signal_connect(dialog, "response", G_CALLBACK(file_open_ok_lcb), bfwin);
321
 
        gtk_widget_show_all(dialog);
322
 
/*  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
323
 
    GSList *slist;
324
 
    bfwin->focus_next_new_doc = TRUE;
325
 
    slist = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(dialog));
326
 
    docs_new_from_uris(bfwin, slist, FALSE);
327
 
    g_slist_free(slist);
328
 
  }
329
 
  gtk_widget_destroy(dialog);*/
330
 
}
331
 
 
332
 
typedef struct {
333
 
        Tbfwin *bfwin;
334
 
        GtkWidget *win;
335
 
        GtkWidget *entry;
336
 
} Tou;
337
 
static void
338
 
open_url_destroy_lcb(GtkWidget * widget, Tou * ou)
339
 
{
340
 
        g_free(ou);
341
 
}
342
 
 
343
 
static void
344
 
open_url_cancel_lcb(GtkWidget * widget, Tou * ou)
345
 
{
346
 
        gtk_widget_destroy(ou->win);
347
 
}
348
 
 
349
 
static void
350
 
open_url_ok_lcb(GtkWidget * widget, Tou * ou)
351
 
{
352
 
        gchar *url = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(ou->entry));
353
 
        DEBUG_MSG("open_url_ok_lcb, url=%s\n", url);
354
 
        doc_new_from_input(ou->bfwin, url, FALSE, FALSE, -1);
355
 
        g_free(url);
356
 
        gtk_widget_destroy(ou->win);
357
 
}
358
 
 
359
 
/**
360
 
 * file_open_url_cb:
361
 
 * @widget: #GtkWidget* ignored
362
 
 * @bfwin: #Tbfwin* bfwin pointer
363
 
 *
364
 
 * opens a dialog where you can enter an URL to open of any kind
365
 
 * supported by gnome-vfs
366
 
 *
367
 
 * Return value: void
368
 
 **/
369
 
void
370
 
file_open_url_cb(GtkAction * action, Tbfwin * bfwin)
371
 
{
372
 
        GtkWidget *align, *vbox, *hbox, *but;
373
 
        Tou *ou;
374
 
        GList *urlhistory = NULL, *tmplist = NULL;
375
 
        ou = g_new(Tou, 1);
376
 
        ou->bfwin = bfwin;
377
 
        ou->win =
378
 
                window_full2(_("Open URL"), GTK_WIN_POS_CENTER_ON_PARENT, 12, G_CALLBACK(open_url_destroy_lcb), ou,
379
 
                                         TRUE, bfwin->main_window);
380
 
        gtk_widget_set_size_request(ou->win, 450, -1);
381
 
        vbox = gtk_vbox_new(FALSE, 5);
382
 
#if !GLIB_CHECK_VERSION(2, 18, 0)
383
 
        if (glib_major_version == 2 && glib_minor_version < 18) {
384
 
                gchar *message;
385
 
                GtkWidget *label = gtk_label_new(NULL);
386
 
                message =
387
 
                        g_strdup_printf(_
388
 
                                                        ("<b>Your glib version (%d.%d.%d) works unreliable with remote files (smb, ftp, sftp, webdav etc.). Please upgrade to a glib version newer than 2.18.0 if you rely on remote file support.</b>"),
389
 
                                                        glib_major_version, glib_minor_version, glib_micro_version);
390
 
                gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
391
 
                gtk_label_set_markup(GTK_LABEL(label), message);
392
 
                g_free(message);
393
 
                gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 4);
394
 
        }
395
 
#endif
396
 
/*      gtk_box_pack_start(GTK_BOX(vbox), bf_label_with_markup(_("<b>Open URL</b>")), FALSE, FALSE, 5);*/
397
 
        gtk_container_add(GTK_CONTAINER(ou->win), vbox);
398
 
        tmplist = g_list_first(bfwin->session->recent_files);
399
 
        while (tmplist) {
400
 
                if (tmplist->data && strlen(tmplist->data) > 5 && strncmp(tmplist->data, "file:", 5) != 0) {
401
 
                        urlhistory = g_list_prepend(urlhistory, g_strdup(tmplist->data));
402
 
                }
403
 
                tmplist = g_list_next(tmplist);
404
 
        }
405
 
        ou->entry = boxed_combobox_with_popdown("", urlhistory, TRUE, vbox);
406
 
        free_stringlist(urlhistory);
407
 
/*  ou->entry = boxed_entry_with_text("", 255, vbox); */
408
 
 
409
 
        align = gtk_alignment_new(0.0, 1.0, 1.0, 0.0);
410
 
        gtk_alignment_set_padding(GTK_ALIGNMENT(align), 12, 0 ,0, 0);
411
 
        gtk_box_pack_start(GTK_BOX(vbox), align, FALSE, FALSE, 0);
412
 
 
413
 
#if GTK_CHECK_VERSION(3,0,0)
414
 
        hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
415
 
#else
416
 
        hbox = gtk_hbutton_box_new();
417
 
#endif
418
 
        gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
419
 
        gtk_box_set_spacing(GTK_BOX(hbox), 6);
420
 
        gtk_container_add(GTK_CONTAINER(align), hbox);
421
 
        but = bf_stock_cancel_button(G_CALLBACK(open_url_cancel_lcb), ou);
422
 
        gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, TRUE, 0);
423
 
        but = bf_stock_ok_button(G_CALLBACK(open_url_ok_lcb), ou);
424
 
        gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, TRUE, 0);
425
 
        gtk_window_set_default(GTK_WINDOW(ou->win), but);
426
 
        gtk_widget_show_all(ou->win);
427
 
}
428
 
 
429
 
/***********************************/
430
 
/*        async save code          */
431
 
 
432
 
typedef struct {
433
 
        Tdocument *doc;
434
 
        GFile *unlink_uri;
435
 
        GFile *fbrefresh_uri;
436
 
} Tdocsavebackend;
437
 
 
438
 
static void
439
 
docsavebackend_cleanup(Tdocsavebackend * dsb)
440
 
{
441
 
        if (dsb->unlink_uri)
442
 
                g_object_unref(dsb->unlink_uri);
443
 
        if (dsb->fbrefresh_uri)
444
 
                g_object_unref(dsb->fbrefresh_uri);
445
 
        g_free(dsb);
446
 
}
447
 
 
448
 
static void
449
 
docsavebackend_async_unlink_lcb(gpointer data)
450
 
{
451
 
        Tdocsavebackend *dsb = data;
452
 
        fb2_refresh_parent_of_uri(dsb->unlink_uri);
453
 
        docsavebackend_cleanup(dsb);
454
 
}
455
 
 
456
 
static TcheckNsave_return
457
 
doc_checkNsave_lcb(TcheckNsave_status status, GError * gerror, gpointer data)
458
 
{
459
 
        Tdocsavebackend *dsb = data;
460
 
        Tdocument *doc = dsb->doc;
461
 
        gchar *errmessage;
462
 
        DEBUG_MSG("doc_checkNsave_lcb, doc=%p, status=%d\n", doc, status);
463
 
        switch (status) {
464
 
        case CHECKANDSAVE_ERROR_NOBACKUP:
465
 
                if (main_v->props.backup_abort_action == 0) {
466
 
                        return CHECKNSAVE_CONT;
467
 
                } else if (main_v->props.backup_abort_action == 1) {
468
 
                        doc->save = NULL;
469
 
                        gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
470
 
                        return CHECKNSAVE_STOP;
471
 
                } else {                                /* if (main_v->props.backup_abort_action == 2) */
472
 
 
473
 
                        /* we have to ask the user */
474
 
                        const gchar *buttons[] = { _("_Abort save"), _("_Continue save"), NULL };
475
 
                        gint retval;
476
 
                        gchar *tmpstr =
477
 
                                g_strdup_printf(_
478
 
                                                                ("A backupfile for %s could not be created. If you continue, this file will be overwritten."),
479
 
gtk_label_get_text(GTK_LABEL(doc->tab_label)));
480
 
                        retval =
481
 
                                message_dialog_new_multi(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_WARNING, buttons,
482
 
                                                                                 _("File backup failure"), tmpstr);
483
 
                        g_free(tmpstr);
484
 
                        DEBUG_MSG("doc_checkNsave_lcb, retval=%d, returning %d\n", retval,
485
 
                                          (retval == 0) ? CHECKNSAVE_STOP : CHECKNSAVE_CONT);
486
 
                        if (retval == 0) {
487
 
                                doc->save = NULL;
488
 
                                gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
489
 
                                return CHECKNSAVE_STOP;
490
 
                        }
491
 
                        return CHECKNSAVE_CONT;
492
 
                }
493
 
                break;
494
 
        case CHECKANDSAVE_ERROR:
495
 
        case CHECKANDSAVE_ERROR_NOWRITE:
496
 
                {
497
 
                        errmessage =
498
 
                                g_strconcat(_("Could not save file "), gtk_label_get_text(GTK_LABEL(doc->tab_label)), NULL);
499
 
                        message_dialog_new(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
500
 
                                                           errmessage, gerror->message);
501
 
                        g_free(errmessage);
502
 
                }
503
 
                /* no break - fall through */
504
 
        case CHECKANDSAVE_ERROR_CANCELLED:
505
 
                doc->save = NULL;
506
 
                gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
507
 
                docsavebackend_cleanup(dsb);
508
 
                break;
509
 
        case CHECKANDSAVE_ERROR_MODIFIED:
510
 
                {
511
 
                        /* we have to ask the user what to do */
512
 
                        const gchar *buttons[] = { _("_Abort save"), _("_Continue save"), NULL };
513
 
                        GFileInfo *newfinfo;
514
 
                        GError *gerror = NULL;
515
 
                        gint retval;
516
 
                        gchar *tmpstr, *utf8uri;
517
 
 
518
 
                        newfinfo =
519
 
                                g_file_query_info(doc->uri, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_TIME_MODIFIED,
520
 
                                                                  0, NULL, &gerror);
521
 
                        if (gerror) {
522
 
                                g_warning("file was modified on disk, but now an error??");
523
 
                                g_error_free(gerror);
524
 
                                return CHECKNSAVE_CONT;
525
 
                        }
526
 
                        utf8uri = g_file_get_uri(doc->uri);
527
 
                        tmpstr = modified_on_disk_warning_string(utf8uri, doc->fileinfo, newfinfo);
528
 
                        /*g_strdup_printf(_("File %s has been modified on disk, overwrite?"), utf8uri); */
529
 
                        g_free(utf8uri);
530
 
                        g_object_unref(newfinfo);
531
 
                        retval =
532
 
                                message_dialog_new_multi(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_WARNING, buttons,
533
 
                                                                                 _("File changed on disk\n"), tmpstr);
534
 
                        g_free(tmpstr);
535
 
                        if (retval == 0) {
536
 
                                doc->save = NULL;
537
 
                                gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
538
 
                                return CHECKNSAVE_STOP;
539
 
                        }
540
 
                        return CHECKNSAVE_CONT;
541
 
                }
542
 
        case CHECKANDSAVE_FINISHED:
543
 
                if (dsb->unlink_uri) {
544
 
                        file_delete_async(dsb->unlink_uri, FALSE, docsavebackend_async_unlink_lcb, dsb);
545
 
                }
546
 
                /* if the user wanted to close the doc we should do very diffferent things here !! */
547
 
                doc->save = NULL;
548
 
                if (doc->close_doc) {
549
 
                        Tbfwin *bfwin = doc->bfwin;
550
 
                        gboolean close_window = doc->close_window;
551
 
                        doc_destroy(doc, doc->close_window);
552
 
                        if (close_window && test_only_empty_doc_left(bfwin->documentlist)) {
553
 
                                bfwin_destroy_and_cleanup(bfwin);
554
 
                        }
555
 
                        return CHECKNSAVE_STOP; /* it actually doesn't matter what we return, this was the last callback anyway */
556
 
                } else {
557
 
                        /* YES! we're done! update the fileinfo ! */
558
 
                        gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
559
 
                        DEBUG_MSG("doc_checkNsave_lcb, re-set async doc->fileinfo (current=%p)\n", doc->fileinfo);
560
 
                        if (doc->fileinfo)
561
 
                                g_object_unref(doc->fileinfo);
562
 
                        doc->fileinfo = NULL;
563
 
                        file_doc_fill_fileinfo(doc, doc->uri);
564
 
                        if (main_v->props.clear_undo_on_save) {
565
 
                                doc_unre_clear_all(doc);
566
 
                        }
567
 
                        doc_set_modified(doc, 0);
568
 
                        /* in fact the filebrowser should also be refreshed if the document was closed, but
569
 
                           when a document is closed, the filebrowser is anyway refreshed (hmm perhaps only if 
570
 
                           'follow document focus' is set). */
571
 
                        if (dsb->unlink_uri && dsb->fbrefresh_uri) {
572
 
                                GFile *parent1, *parent2;
573
 
                                parent1 = g_file_get_parent(dsb->unlink_uri);
574
 
                                parent2 = g_file_get_parent(dsb->fbrefresh_uri);
575
 
                                if (!g_file_equal(parent1, parent2)) {
576
 
                                        /* if they are equal, the directory will be refreshed by the unlink callback */
577
 
                                        fb2_refresh_dir_from_uri(parent2);
578
 
                                }
579
 
                                g_object_unref(parent1);
580
 
                                g_object_unref(parent2);
581
 
                        } else if (dsb->fbrefresh_uri) {
582
 
                                fb2_refresh_parent_of_uri(dsb->fbrefresh_uri);
583
 
                        }
584
 
                }
585
 
                if (!dsb->unlink_uri) {
586
 
                        /* if there is an unlink uri, that means the unlink callback will free the dsb structure */
587
 
                        docsavebackend_cleanup(dsb);
588
 
                }
589
 
                break;
590
 
        }
591
 
        return CHECKNSAVE_CONT;
592
 
}
593
 
 
594
 
/**
595
 
 * ask_new_filename:
596
 
 * @bfwin: #Tbfwin* mainly used to set the dialog transient
597
 
 * @oldfilename: #gchar* with the old filename
598
 
 * @gui_name: #const gchar* with the name of the file used in the GUI
599
 
 * @is_move: #gboolean if the title should be move or save as
600
 
 *
601
 
 * returns a newly allocated string with a new filename
602
 
 *
603
 
 * if a file with the selected name name was
604
 
 * open already it will ask the user what to do, return NULL if
605
 
 * the user wants to abort, or will remove the name of the other file if the user wants
606
 
 * to continue
607
 
 *
608
 
 * Return value: gchar* with newly allocated string, or NULL on failure or abort
609
 
 **/
610
 
gchar *
611
 
ask_new_filename(Tbfwin * bfwin, const gchar * old_curi, const gchar * gui_name, gboolean is_move)
612
 
{
613
 
        Tdocument *exdoc;
614
 
        GList *alldocs;
615
 
        gchar *new_curi = NULL;
616
 
        GFile *uri;
617
 
        gchar *dialogtext;
618
 
        GtkWidget *dialog;
619
 
 
620
 
        dialogtext = g_strdup_printf((is_move) ? _("Move/rename %s to") : _("Save %s as"), gui_name);
621
 
        dialog =
622
 
                file_chooser_dialog(bfwin, dialogtext, GTK_FILE_CHOOSER_ACTION_SAVE, old_curi, FALSE, FALSE, NULL,
623
 
                                                        FALSE);
624
 
        g_free(dialogtext);
625
 
 
626
 
        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
627
 
                new_curi = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
628
 
        }
629
 
        gtk_widget_destroy(dialog);
630
 
 
631
 
        if (!new_curi)
632
 
                return NULL;
633
 
        if (old_curi && strcmp(old_curi, new_curi) == 0) {
634
 
                g_free(new_curi);
635
 
                return NULL;
636
 
        }
637
 
 
638
 
        alldocs = return_allwindows_documentlist();
639
 
        uri = g_file_new_for_uri(new_curi);
640
 
        exdoc = documentlist_return_document_from_uri(alldocs, uri);
641
 
        g_object_unref(uri);
642
 
        g_list_free(alldocs);
643
 
        DEBUG_MSG("ask_new_filename, exdoc=%p, newfilename=%s\n", exdoc, new_curi);
644
 
        if (exdoc) {
645
 
                gchar *tmpstr;
646
 
                gint retval;
647
 
                const gchar *buttons[] = { _("_Cancel"), _("_Overwrite"), NULL };
648
 
                tmpstr = g_strdup_printf(_("File %s exists and is open, overwrite?"), new_curi);
649
 
                retval =
650
 
                        message_dialog_new_multi(bfwin->main_window, GTK_MESSAGE_WARNING, buttons, tmpstr,
651
 
                                                                         _("The file you have selected is being edited in Bluefish."));
652
 
                g_free(tmpstr);
653
 
                if (retval == 0) {
654
 
                        g_free(new_curi);
655
 
                        return NULL;
656
 
                } else {
657
 
                        document_unset_filename(exdoc);
658
 
                }
659
 
        } else {
660
 
                GFile *tmp;
661
 
                gboolean exists;
662
 
                tmp = g_file_new_for_uri(new_curi);
663
 
                exists = g_file_query_exists(tmp, NULL);
664
 
                g_object_unref(tmp);
665
 
                if (exists) {
666
 
                        gchar *tmpstr;
667
 
                        gint retval;
668
 
                        const gchar *buttons[] = { _("_Cancel"), _("_Overwrite"), NULL };
669
 
                        tmpstr = g_strdup_printf(_("A file named \"%s\" already exists."), new_curi);
670
 
                        retval =
671
 
                                message_dialog_new_multi(bfwin->main_window, GTK_MESSAGE_WARNING, buttons, tmpstr,
672
 
                                                                                 _("Do you want to replace the existing file?"));
673
 
                        g_free(tmpstr);
674
 
                        if (retval == 0) {
675
 
                                g_free(new_curi);
676
 
                                return NULL;
677
 
                        }
678
 
                }
679
 
        }
680
 
        return new_curi;
681
 
}
682
 
 
683
 
void
684
 
doc_save_backend(Tdocument * doc, gboolean do_save_as, gboolean do_move, gboolean close_doc,
685
 
                                 gboolean close_window)
686
 
{
687
 
        gchar *tmp;
688
 
        Trefcpointer *buffer;
689
 
        gchar *curi = NULL;
690
 
        Tdocsavebackend *dsb;
691
 
        DEBUG_MSG
692
 
                ("doc_save_backend, started for doc %p, save_as=%d, do_move=%d, close_doc=%d, close_window=%d\n", doc,
693
 
                 do_save_as, do_move, close_doc, close_window);
694
 
 
695
 
        if (doc->readonly) {
696
 
                g_print("Cannot save readonly document !?!?");
697
 
                return;
698
 
        }
699
 
 
700
 
        dsb = g_new0(Tdocsavebackend, 1);
701
 
        dsb->doc = doc;
702
 
 
703
 
        /* should be moved to a plugin interface, because this is HTML specific */
704
 
        /* update author meta tag */
705
 
        if (main_v->props.auto_update_meta_author) {
706
 
                const gchar *realname = g_get_real_name();
707
 
                if (realname && strlen(realname) > 0) {
708
 
                        gchar *author_tmp;
709
 
                        author_tmp = g_strconcat("<meta name=\"author\" content=\"", realname, "\" ", NULL);
710
 
                        snr3_run_extern_replace(doc,
711
 
                                                                        "<meta[ \t\n]+name[ \t\n]*=[ \t\n]*\"author\"[ \t\n]+content[ \t\n]*=[ \t\n]*\"[^\"]*\"[ \t\n]*",
712
 
                                                                        snr3scope_doc, snr3type_pcre, FALSE, author_tmp, FALSE);
713
 
                        g_free(author_tmp);
714
 
                }
715
 
        }
716
 
 
717
 
        /* update date meta tag */
718
 
        if (main_v->props.auto_update_meta_date) {
719
 
                time_t time_var;
720
 
                struct tm *time_struct;
721
 
                gchar isotime[60];
722
 
                gchar *date_tmp;
723
 
 
724
 
                time_var = time(NULL);
725
 
                time_struct = localtime(&time_var);
726
 
#ifdef WIN32
727
 
                {
728
 
                        glong hours, mins;
729
 
                        gchar gmtsign;
730
 
                        gchar tmptime[50];
731
 
 
732
 
                        strftime(tmptime, 30, "%Y-%m-%dT%H:%M:%S", time_struct);
733
 
                        gmtsign = _timezone > 0 ? '-' : '+';
734
 
                        hours = abs(_timezone) / 3600;
735
 
                        mins = (abs(_timezone) % 3600) / 60;
736
 
                        sprintf(isotime, "%s%c%02ld%02ld", tmptime, gmtsign, hours, mins);
737
 
                }
738
 
#else                                                   /* WIN32 */
739
 
                strftime(isotime, 30, "%Y-%m-%dT%H:%M:%S%z", time_struct);
740
 
#endif                                                  /* WIN32 */
741
 
                DEBUG_MSG("doc_save_backend, ISO-8601 time %s\n", isotime);
742
 
 
743
 
                date_tmp = g_strconcat("<meta name=\"date\" content=\"", isotime, "\" ", NULL);
744
 
                snr3_run_extern_replace(doc,
745
 
                                                                "<meta[ \t\n]+name[ \t\n]*=[ \t\n]*\"date\"[ \t\n]+content[ \t\n]*=[ \t\n]*\"[^\"]*\"[ \t\n]*",
746
 
                                                                snr3scope_doc, snr3type_pcre, FALSE, date_tmp, FALSE);
747
 
                g_free(date_tmp);
748
 
        }
749
 
 
750
 
        /* update generator meta tag */
751
 
        if (main_v->props.auto_update_meta_generator) {
752
 
                snr3_run_extern_replace(doc,
753
 
                                                                "<meta[ \t\n]+name[ \t\n]*=[ \t\n]*\"generator\"[ \t\n]+content[ \t\n]*=[ \t\n]*\"[^\"]*\"[ \t\n]*",
754
 
                                                                snr3scope_doc, snr3type_pcre, FALSE,
755
 
                                                                "<meta name=\"generator\" content=\"Bluefish " VERSION "\" ", FALSE);
756
 
        }
757
 
 
758
 
        if (doc->uri)
759
 
                curi = g_file_get_uri(doc->uri);
760
 
 
761
 
        if (doc->save) {
762
 
                gchar *errmessage;
763
 
                /* this message is not in very nice english I'm afraid */
764
 
                errmessage =
765
 
                        g_strconcat(_("File:\n\""), gtk_label_get_text(GTK_LABEL(doc->tab_label)),
766
 
                                                _("\" save is in progress"), NULL);
767
 
                message_dialog_new(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
768
 
                                                   _("Save in progress!"), errmessage);
769
 
                g_free(errmessage);
770
 
                return;
771
 
        }
772
 
        if (doc->uri == NULL) {
773
 
                do_save_as = 1;
774
 
        }
775
 
        if (do_move) {
776
 
                do_save_as = 1;
777
 
        }
778
 
        if (do_save_as) {
779
 
                gchar *newfilename;
780
 
                newfilename =
781
 
                        ask_new_filename(BFWIN(doc->bfwin), curi, gtk_label_get_text(GTK_LABEL(doc->tab_label)), do_move);
782
 
                if (!newfilename) {
783
 
                        if (curi)
784
 
                                g_free(curi);
785
 
                        g_free(dsb);
786
 
                        return;
787
 
                }
788
 
                if (doc->uri) {
789
 
                        if (do_move) {
790
 
                                dsb->unlink_uri = doc->uri;     /* unlink this uri later */
791
 
                                g_object_ref(dsb->unlink_uri);
792
 
                        }
793
 
                        g_object_unref(doc->uri);
794
 
                }
795
 
 
796
 
                doc->uri = g_file_new_for_uri(newfilename);
797
 
                if (do_move)
798
 
                        bmark_doc_renamed(BFWIN(doc->bfwin), doc);
799
 
 
800
 
                if (curi)
801
 
                        g_free(curi);
802
 
                curi = newfilename;
803
 
                DEBUG_MSG("doc_save_backend, new uri=%s\n", curi);
804
 
                dsb->fbrefresh_uri = doc->uri;  /* refresh this uri later */
805
 
                g_object_ref(dsb->fbrefresh_uri);
806
 
        }
807
 
        session_set_savedir(doc->bfwin, curi);
808
 
 
809
 
        tmp = doc_get_buffer_in_encoding(doc);
810
 
        if (!tmp) {
811
 
                g_free(curi);
812
 
                return;
813
 
        }
814
 
#if !GLIB_CHECK_VERSION(2, 18, 0)
815
 
        /* check runtime glib version, check if remote file, and give warning if remote file on glib < 2.18 */
816
 
        if (glib_major_version == 2 && glib_minor_version < 18 && !g_file_is_native(doc->uri)) {
817
 
                gchar *message =
818
 
                        g_strdup_printf(_
819
 
                                                        ("Your glib version (%d.%d.%d) is unreliable with remote files. Please upgrade to 2.18.0 or newer."),
820
 
glib_major_version, glib_minor_version, glib_micro_version);
821
 
                bfwin_statusbar_message(BFWIN(doc->bfwin), message, 20);
822
 
                g_free(message);
823
 
        }
824
 
#endif
825
 
        buffer = refcpointer_new(tmp);
826
 
        doc->close_doc = close_doc;
827
 
        doc->close_window = close_window;
828
 
        gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), FALSE);
829
 
        DEBUG_MSG("doc_save_backend, calling file_checkNsave_uri_async for %zd bytes\n", strlen(buffer->data));
830
 
        doc->save =
831
 
                file_checkNsave_uri_async(doc->uri, doc->fileinfo, buffer, strlen(buffer->data), !do_save_as,
832
 
                                                                  main_v->props.backup_file, doc_checkNsave_lcb, dsb);
833
 
 
834
 
        if (do_save_as) {
835
 
                doc->readonly = FALSE;
836
 
                doc_reset_filetype(doc, doc->uri, buffer->data, strlen(buffer->data));
837
 
                doc_set_title(doc);
838
 
                doc_force_activate(doc);
839
 
        }
840
 
        refcpointer_unref(buffer);
841
 
 
842
 
        g_free(curi);
843
 
}
844
 
 
845
 
/**
846
 
 * file_save_cb:
847
 
 * @widget: unused #GtkWidget
848
 
 * @bfwin: #Tbfwin* with the current window
849
 
 *
850
 
 * Save the current document.
851
 
 *
852
 
 * Return value: void
853
 
 **/
854
 
void
855
 
file_save_cb(GtkWidget * widget, Tbfwin * bfwin)
856
 
{
857
 
        if (bfwin->current_document)
858
 
                doc_save_backend(bfwin->current_document, FALSE, FALSE, FALSE, FALSE);
859
 
}
860
 
 
861
 
/**
862
 
 * file_save_as_cb:
863
 
 * @widget: unused #GtkWidget
864
 
 * @bfwin: #Tbfwin* with the current window
865
 
 *
866
 
 * Save current document, let user choose filename.
867
 
 *
868
 
 * Return value: void
869
 
 **/
870
 
void
871
 
file_save_as_cb(GtkWidget * widget, Tbfwin * bfwin)
872
 
{
873
 
        if (bfwin->current_document)
874
 
                doc_save_backend(bfwin->current_document, TRUE, FALSE, FALSE, FALSE);
875
 
}
876
 
 
877
 
/**
878
 
 * file_move_to_cb:
879
 
 * @widget: unused #GtkWidget
880
 
 * @bfwin: #Tbfwin* with the current window
881
 
 *
882
 
 * Move current document, let user choose filename.
883
 
 *
884
 
 * Return value: void
885
 
 **/
886
 
void
887
 
file_move_to_cb(GtkWidget * widget, Tbfwin * bfwin)
888
 
{
889
 
        if (bfwin->current_document)
890
 
                doc_save_backend(bfwin->current_document, TRUE, TRUE, FALSE, FALSE);
891
 
}
892
 
 
893
 
void
894
 
file_save_all(Tbfwin * bfwin)
895
 
{
896
 
        GList *tmplist;
897
 
        Tdocument *tmpdoc;
898
 
 
899
 
        tmplist = g_list_first(bfwin->documentlist);
900
 
        while (tmplist) {
901
 
                tmpdoc = (Tdocument *) tmplist->data;
902
 
                if (tmpdoc->modified) {
903
 
                        doc_save_backend(tmpdoc, FALSE, FALSE, FALSE, FALSE);
904
 
                }
905
 
                tmplist = g_list_next(tmplist);
906
 
        }
907
 
}
908
 
 
909
 
/**
910
 
 * file_save_all_cb:
911
 
 * @widget: unused #GtkWidget
912
 
 * @bfwin: the #Tbfwin* window pointer
913
 
 *
914
 
 *  Save all editor notebooks
915
 
 *
916
 
 * Return value: void
917
 
 **/
918
 
void
919
 
file_save_all_cb(GtkWidget * widget, Tbfwin * bfwin)
920
 
{
921
 
        GList *tmplist;
922
 
        Tdocument *tmpdoc;
923
 
 
924
 
        tmplist = g_list_first(bfwin->documentlist);
925
 
        while (tmplist) {
926
 
                tmpdoc = (Tdocument *) tmplist->data;
927
 
                if (tmpdoc->modified) {
928
 
                        doc_save_backend(tmpdoc, FALSE, FALSE, FALSE, FALSE);
929
 
                }
930
 
                tmplist = g_list_next(tmplist);
931
 
        }
932
 
}
933
 
 
934
 
void
935
 
doc_save_all_close(Tbfwin * bfwin)
936
 
{
937
 
        GList *tmplist = g_list_first(bfwin->documentlist);
938
 
        while (tmplist) {
939
 
                Tdocument *tmpdoc = (Tdocument *) tmplist->data;
940
 
                doc_save_backend(tmpdoc, FALSE, FALSE, TRUE, TRUE);
941
 
                tmplist = g_list_next(tmplist);
942
 
        }
943
 
}
944
 
 
945
 
 
946
 
gint
947
 
doc_modified_dialog(Tdocument * doc)
948
 
{
949
 
        const gchar *buttons[] = { _("Close _Without Saving"), GTK_STOCK_CANCEL, GTK_STOCK_SAVE, NULL };
950
 
        gchar *text;
951
 
        gint retval;
952
 
        text = g_strdup_printf(_("Save changes to \"%s\" before closing?"),
953
 
                                                   gtk_label_get_text(GTK_LABEL(doc->tab_label)));
954
 
        retval = message_dialog_new_multi(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_QUESTION, buttons, text,
955
 
                                                                          _("If you don't save your changes they will be lost."));
956
 
        g_free(text);
957
 
        return retval;
958
 
}
959
 
 
960
 
Tclose_mode
961
 
multiple_files_modified_dialog(Tbfwin * bfwin)
962
 
{
963
 
        const gchar *buttons[] = { _("Choose per _File"), _("Close _All"), _("_Cancel"), _("_Save All"), NULL };
964
 
        int retval = message_dialog_new_multi(bfwin->main_window,
965
 
                                                                                  GTK_MESSAGE_QUESTION, buttons,
966
 
                                                                                  _("One or more open files have been changed."),
967
 
                                                                                  _("If you don't save your changes they will be lost."));
968
 
        return (Tclose_mode) retval;
969
 
}
970
 
 
971
 
/* return TRUE if all are either closed or saved 
972
 
return FALSE on cancel*/
973
 
gboolean
974
 
choose_per_file(Tbfwin * bfwin, gboolean close_window)
975
 
{
976
 
        GList *duplist, *tmplist;
977
 
        duplist = g_list_copy(bfwin->documentlist);
978
 
        tmplist = g_list_first(duplist);
979
 
        while (tmplist) {
980
 
                gint retval;
981
 
                Tdocument *tmpdoc = (Tdocument *) tmplist->data;
982
 
                DEBUG_MSG("choose_per_file, tmpdoc=%p\n", tmpdoc);
983
 
                if (tmpdoc->modified) {
984
 
                        retval = doc_modified_dialog(tmpdoc);
985
 
                        switch (retval) {
986
 
                        case 0:                 /* close */
987
 
                                DEBUG_MSG("choose_per_file, call doc_close\n");
988
 
                                tmpdoc->modified = FALSE;
989
 
                                doc_close_single_backend(tmpdoc, TRUE, close_window);
990
 
                                break;
991
 
                        case 1:                 /* cancel */
992
 
                                return FALSE;
993
 
                                break;
994
 
                        case 2:                 /* save */
995
 
                                DEBUG_MSG("choose_per_file, call doc_save\n");
996
 
                                doc_save_backend(tmpdoc, FALSE, FALSE, TRUE, close_window);
997
 
                                break;
998
 
                        }
999
 
                } else {
1000
 
                        doc_close_single_backend(tmpdoc, TRUE, close_window);
1001
 
                }
1002
 
                tmplist = g_list_next(tmplist);
1003
 
        }
1004
 
        g_list_free(duplist);
1005
 
        return TRUE;
1006
 
}
1007
 
 
1008
 
gboolean
1009
 
doc_close_single_backend(Tdocument * doc, gboolean delay_activate, gboolean close_window)
1010
 
{
1011
 
        Tbfwin *bfwin = doc->bfwin;
1012
 
        if (doc->checkmodified)
1013
 
                checkmodified_cancel(doc->checkmodified);
1014
 
        if (doc->autosave_progress || doc->autosaved || doc->need_autosave)
1015
 
                remove_autosave(doc);
1016
 
        if (doc->load != NULL || doc->info != NULL) {
1017
 
                /* we should cancel the action now..., and then let the callbacks close it...
1018
 
                   the order is important, because the info callback will not close the document, 
1019
 
                   only the load callback will call doc_close_single_backend */
1020
 
                doc->close_doc = TRUE;
1021
 
                doc->close_window = close_window;
1022
 
                if (doc->info)
1023
 
                        file_asyncfileinfo_cancel(doc->info);
1024
 
                if (doc->load)
1025
 
                        file2doc_cancel(doc->load);
1026
 
                /* we will not cancel save operations, because it might corrupt the file, let 
1027
 
                   them just timeout */
1028
 
                DEBUG_MSG("doc_close_single_backend, cancelled load/info and set close_doc to TRUE, returning now\n");
1029
 
                return FALSE;
1030
 
        }
1031
 
        if (doc->autosaved || doc->autosave_progress || doc->need_autosave) {
1032
 
                remove_autosave(doc);
1033
 
        }
1034
 
        if (doc_is_empty_non_modified_and_nameless(doc)
1035
 
                && g_list_length(BFWIN(doc->bfwin)->documentlist) <= 1) {
1036
 
                if (close_window) {
1037
 
                        bfwin_destroy_and_cleanup(BFWIN(doc->bfwin));
1038
 
                }
1039
 
                return TRUE;
1040
 
        }
1041
 
        if (doc->modified) {
1042
 
                gint retval = doc_modified_dialog(doc);
1043
 
                switch (retval) {
1044
 
                case 0:
1045
 
                        doc_destroy(doc, close_window || delay_activate);
1046
 
                        break;
1047
 
                case 1:
1048
 
                        return FALSE;
1049
 
                        break;
1050
 
                case 2:
1051
 
                        doc_save_backend(doc, FALSE, FALSE, TRUE, close_window);
1052
 
                        break;
1053
 
                }
1054
 
        } else {
1055
 
                doc_destroy(doc, close_window || delay_activate);
1056
 
        }
1057
 
        if (close_window && bfwin->documentlist == NULL) {      /* the documentlist is empty */
1058
 
                bfwin_destroy_and_cleanup(bfwin);
1059
 
        }
1060
 
        DEBUG_MSG("doc_close_single_backend, finished!\n");
1061
 
        return TRUE;
1062
 
}
1063
 
 
1064
 
/**
1065
 
 * file_close_cb:
1066
 
 * @widget: unused #GtkWidget
1067
 
 * @data: unused #gpointer
1068
 
 *
1069
 
 * Close the current document.
1070
 
 *
1071
 
 * Return value: void
1072
 
 **/
1073
 
void
1074
 
file_close_cb(GtkWidget * widget, Tbfwin * bfwin)
1075
 
{
1076
 
        if (bfwin->current_document)
1077
 
                doc_close_single_backend(bfwin->current_document, FALSE, FALSE);
1078
 
}
1079
 
 
1080
 
void
1081
 
doc_close_multiple_backend(Tbfwin * bfwin, gboolean close_window, Tclose_mode close_mode)
1082
 
{
1083
 
        GList *tmplist, *duplist;
1084
 
        Tdocument *tmpdoc;
1085
 
 
1086
 
/*      if (g_list_length(bfwin->documentlist) == 1) {
1087
 
                return doc_close_single_backend(bfwin->current_document, FALSE, close_window);
1088
 
        }
1089
 
        if (have_modified_documents(bfwin->documentlist)) {
1090
 
                retval = multiple_files_modified_dialog(bfwin);
1091
 
                if (retval == 2) {
1092
 
                        return FALSE;
1093
 
                }
1094
 
        }*/
1095
 
 
1096
 
        /* we duplicate the documentlist so we can safely walk trough the list, in 
1097
 
           our duplicate list there is no chance that the list is changed during the time
1098
 
           we walk the list */
1099
 
        duplist = g_list_copy(bfwin->documentlist);
1100
 
        tmplist = g_list_first(duplist);
1101
 
        while (tmplist) {
1102
 
                tmpdoc = (Tdocument *) tmplist->data;
1103
 
                if (close_mode == close_mode_close_all) {
1104
 
                        /* fake that this document was not modified */
1105
 
                        tmpdoc->modified = FALSE;
1106
 
                        doc_close_single_backend(tmpdoc, TRUE, close_window);
1107
 
                } else if (close_mode == close_mode_save_all) {
1108
 
                        doc_save_backend(tmpdoc, FALSE, FALSE, TRUE, close_window);
1109
 
                }
1110
 
                tmplist = g_list_next(tmplist);
1111
 
        }
1112
 
        g_list_free(duplist);
1113
 
        DEBUG_MSG("doc_close_multiple_backend, finished\n");
1114
 
        if (!close_window)
1115
 
                bfwin_notebook_changed(bfwin, -1);
1116
 
}
1117
 
 
1118
 
void
1119
 
file_close_all(Tbfwin * bfwin)
1120
 
{
1121
 
        if (have_modified_documents(bfwin->documentlist)) {
1122
 
                Tclose_mode retval = multiple_files_modified_dialog(bfwin);
1123
 
                switch (retval) {
1124
 
                case close_mode_cancel:
1125
 
                        return;
1126
 
                        break;
1127
 
                case close_mode_per_file:
1128
 
                        choose_per_file(bfwin, FALSE);
1129
 
                        break;
1130
 
                case close_mode_save_all:
1131
 
                case close_mode_close_all:
1132
 
                        doc_close_multiple_backend(bfwin, FALSE, retval);
1133
 
                        break;
1134
 
                }
1135
 
        } else {
1136
 
                doc_close_multiple_backend(bfwin, FALSE, close_mode_close_all);
1137
 
        }
1138
 
}
1139
 
 
1140
 
/**
1141
 
 * file_close_all_cb:
1142
 
 * @widget: unused #GtkWidget
1143
 
 * @bfwin: #Tbfwin* 
1144
 
 *
1145
 
 * Close all open files. Prompt user when neccessary.
1146
 
 *
1147
 
 * Return value: void
1148
 
 **/
1149
 
void
1150
 
file_close_all_cb(GtkWidget * widget, Tbfwin * bfwin)
1151
 
{
1152
 
        if (have_modified_documents(bfwin->documentlist)) {
1153
 
                Tclose_mode retval = multiple_files_modified_dialog(bfwin);
1154
 
                switch (retval) {
1155
 
                case close_mode_cancel:
1156
 
                        return;
1157
 
                        break;
1158
 
                case close_mode_per_file:
1159
 
                        choose_per_file(bfwin, FALSE);
1160
 
                        break;
1161
 
                case close_mode_save_all:
1162
 
                case close_mode_close_all:
1163
 
                        doc_close_multiple_backend(bfwin, FALSE, retval);
1164
 
                        break;
1165
 
                }
1166
 
        } else {
1167
 
                doc_close_multiple_backend(bfwin, FALSE, close_mode_close_all);
1168
 
        }
1169
 
}
1170
 
 
1171
 
void
1172
 
file_new_doc(Tbfwin * bfwin)
1173
 
{
1174
 
        Tdocument *doc;
1175
 
        GFile *template = NULL;
1176
 
 
1177
 
        if (bfwin->session->template && bfwin->session->template[0]) {
1178
 
                template = g_file_new_for_commandline_arg(bfwin->session->template);
1179
 
        }
1180
 
        doc = doc_new_with_template(bfwin, template, TRUE);
1181
 
        bfwin_switch_to_document_by_pointer(bfwin, doc);
1182
 
}
1183
 
 
1184
 
/**
1185
 
 * file_new_cb:
1186
 
 * @windget: #GtkWidget* ignored
1187
 
 * @bfwin: Tbfwin* where to open the new document
1188
 
 *
1189
 
 * Create a new, empty file in window bfwin
1190
 
 *
1191
 
 * Return value: void
1192
 
 **/
1193
 
void
1194
 
file_new_cb(GtkWidget * widget, Tbfwin * bfwin)
1195
 
{
1196
 
        Tdocument *doc;
1197
 
        GFile *template = NULL;
1198
 
        if (bfwin->session->template && bfwin->session->template[0]) {
1199
 
                template = g_file_new_for_commandline_arg(bfwin->session->template);
1200
 
        }
1201
 
        doc = doc_new_with_template(bfwin, template, TRUE);
1202
 
        bfwin_switch_to_document_by_pointer(bfwin, doc);
1203
 
}
1204
 
 
1205
 
static void
1206
 
file_reload_all_modified_check_lcb(Tcheckmodified_status status, GError * gerror,
1207
 
                                                                   GFileInfo * orig, GFileInfo * new, gpointer user_data)
1208
 
{
1209
 
        if (status == CHECKMODIFIED_MODIFIED) {
1210
 
                DEBUG_MSG("file_reload_all_modified_check_lcb, reload %p\n", user_data);
1211
 
                doc_reload(DOCUMENT(user_data), new, FALSE);
1212
 
        }
1213
 
}
1214
 
 
1215
 
void
1216
 
file_reload_all_modified(Tbfwin * bfwin)
1217
 
{
1218
 
        GList *tmplist = g_list_first(bfwin->documentlist);
1219
 
        while (tmplist) {
1220
 
                if (DOCUMENT(tmplist->data)->uri && DOCUMENT(tmplist->data)->status == DOC_STATUS_COMPLETE) {
1221
 
                        DEBUG_MSG("file_reload_all_modified, check %p\n", tmplist->data);
1222
 
                        file_checkmodified_uri_async(DOCUMENT(tmplist->data)->uri, DOCUMENT(tmplist->data)->fileinfo,
1223
 
                                                                                 file_reload_all_modified_check_lcb, tmplist->data);
1224
 
                }
1225
 
                tmplist = g_list_next(tmplist);
1226
 
        }
1227
 
}
1228
 
 
1229
 
typedef struct {
1230
 
        GtkWidget *dialog;
1231
 
        Tbfwin *bfwin;
1232
 
        GtkWidget *entry_local;
1233
 
        GtkWidget *entry_remote;
1234
 
        GtkWidget *delete_deprecated;
1235
 
        GtkWidget *include_hidden;
1236
 
        GtkWidget *progress;
1237
 
        GtkWidget *messagelabel;
1238
 
        gulong signal_id;
1239
 
} Tsyncdialog;
1240
 
 
1241
 
static void
1242
 
sync_progress(GFile *uri, gint total, gint done, gint failed, gpointer user_data)
1243
 
{
1244
 
        Tsyncdialog *sd = user_data;
1245
 
        if (total > 0) {
1246
 
                gchar *text;
1247
 
                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->progress), 1.0 * done / total);
1248
 
                if (uri) {
1249
 
                        gchar * curi = g_file_get_uri(uri);
1250
 
                        text = g_strdup_printf("%s (%d / %d)", curi, done, total);
1251
 
                        g_free(curi);
1252
 
                } else {
1253
 
                        text = g_strdup_printf("%d / %d", done, total);
1254
 
                }
1255
 
                gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), text);
1256
 
/*              g_print("%s\n",text);*/
1257
 
                g_free(text);
1258
 
                if (failed > 0) {
1259
 
                        text =
1260
 
                                g_strdup_printf(ngettext
1261
 
                                                                ("<span color=\"red\">%d failure</span>",
1262
 
                                                                 "<span color=\"red\">%d failures</span>", failed), failed);
1263
 
                        gtk_label_set_markup(GTK_LABEL(sd->messagelabel), text);
1264
 
                        gtk_widget_show(sd->messagelabel);
1265
 
                        g_free(text);
1266
 
                }
1267
 
        } else if (total == -1) {
1268
 
                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->progress), 1);
1269
 
                if (failed > 0) {
1270
 
                        gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), _("incomplete finished"));
1271
 
                } else {
1272
 
                        gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), _("completed"));
1273
 
                }
1274
 
                g_signal_handler_unblock(sd->dialog, sd->signal_id);
1275
 
        }
1276
 
}
1277
 
 
1278
 
static void
1279
 
sync_dialog_response_lcb(GtkDialog * dialog, gint response_id, gpointer user_data)
1280
 
{
1281
 
        Tsyncdialog *sd = user_data;
1282
 
        DEBUG_MSG("sync_dialog_response_lcb, response=%d\n", response_id);
1283
 
        if (response_id > 0) {
1284
 
                GFile *local, *remote;
1285
 
                gtk_label_set_text(GTK_LABEL(sd->messagelabel), "");
1286
 
                gtk_widget_hide(sd->messagelabel);
1287
 
                local = g_file_new_for_commandline_arg(gtk_entry_get_text(GTK_ENTRY(sd->entry_local)));
1288
 
                remote = g_file_new_for_commandline_arg(gtk_entry_get_text(GTK_ENTRY(sd->entry_remote)));
1289
 
                if (response_id == 1) {
1290
 
                        sync_directory(local, remote,
1291
 
                                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->delete_deprecated)),
1292
 
                                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->include_hidden)), sync_progress,
1293
 
                                                   sd);
1294
 
                } else if (response_id == 2) {
1295
 
                        sync_directory(remote, local,
1296
 
                                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->delete_deprecated)),
1297
 
                                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->include_hidden)), sync_progress,
1298
 
                                                   sd);
1299
 
                }
1300
 
                sd->bfwin->session->sync_delete_deprecated =
1301
 
                        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->delete_deprecated));
1302
 
                sd->bfwin->session->sync_include_hidden =
1303
 
                        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sd->include_hidden));
1304
 
 
1305
 
                g_signal_handler_block(sd->dialog, sd->signal_id);
1306
 
                g_free(sd->bfwin->session->sync_local_uri);
1307
 
                sd->bfwin->session->sync_local_uri = g_file_get_uri(local);
1308
 
                g_free(sd->bfwin->session->sync_remote_uri);
1309
 
                sd->bfwin->session->sync_remote_uri = g_file_get_uri(remote);
1310
 
 
1311
 
                g_object_unref(local);
1312
 
                g_object_unref(remote);
1313
 
        } else {
1314
 
                gtk_widget_destroy(sd->dialog);
1315
 
                g_slice_free(Tsyncdialog, sd);
1316
 
        }
1317
 
}
1318
 
 
1319
 
void
1320
 
sync_dialog(Tbfwin * bfwin)
1321
 
{
1322
 
        Tsyncdialog *sd;
1323
 
        GtkWidget *carea, *table;
1324
 
 
1325
 
        sd = g_slice_new0(Tsyncdialog);
1326
 
        sd->bfwin = bfwin;
1327
 
        sd->dialog = gtk_dialog_new_with_buttons(_("Upload / Download"),
1328
 
                                                                                         GTK_WINDOW(bfwin->main_window),
1329
 
                                                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
1330
 
                                                                                         _("Upload"), 1, _("Download"), 2,
1331
 
                                                                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
1332
 
 
1333
 
        carea = gtk_dialog_get_content_area(GTK_DIALOG(sd->dialog));
1334
 
 
1335
 
#if !GLIB_CHECK_VERSION(2, 18, 0)
1336
 
        if (glib_major_version == 2 && glib_minor_version < 18) {
1337
 
                gchar *message;
1338
 
                GtkWidget *label = gtk_label_new(NULL);
1339
 
                message =
1340
 
                        g_strdup_printf(_
1341
 
                                                        ("<b>Your glib version (%d.%d.%d) works unreliable with remote files (smb, ftp, sftp, webdav etc.). Please upgrade to a glib version newer than 2.18.0 if you rely on remote file support.</b>"),
1342
 
                                                        glib_major_version, glib_minor_version, glib_micro_version);
1343
 
                gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1344
 
                gtk_label_set_markup(GTK_LABEL(label), message);
1345
 
                g_free(message);
1346
 
                gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sd->dialog))), label, FALSE, FALSE,
1347
 
                                                   4);
1348
 
        }
1349
 
#endif
1350
 
        table = dialog_table_in_vbox(4, 3, 6, carea, TRUE,TRUE, 3);
1351
 
 
1352
 
        sd->entry_local = dialog_entry_in_table(NULL, table, 1, 2,0, 1);
1353
 
        dialog_mnemonic_label_in_table(_("Local directory"), sd->entry_local, table,
1354
 
                                                                        0, 1, 0,1);
1355
 
        gtk_table_attach(GTK_TABLE(table), file_but_new2(sd->entry_local, 1, bfwin, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER),
1356
 
                                                                        2, 3, 0, 1, GTK_FILL, GTK_FILL, 3, 3);
1357
 
 
1358
 
        sd->entry_remote = dialog_entry_in_table(NULL, table, 1, 2,1, 2);
1359
 
        dialog_mnemonic_label_in_table(_("Remote directory"), sd->entry_remote, table,
1360
 
                                                                        0, 1, 1,2);
1361
 
        gtk_table_attach(GTK_TABLE(table), file_but_new2(sd->entry_remote, 1, bfwin, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER),
1362
 
                                                                        2, 3, 1, 2, GTK_FILL, GTK_FILL, 3, 3);
1363
 
 
1364
 
        sd->delete_deprecated = dialog_check_button_in_table(_("Delete deprecated files"), 
1365
 
                                                bfwin->session->sync_delete_deprecated, table,
1366
 
                                                0, 3, 2, 3);
1367
 
        
1368
 
        sd->include_hidden = dialog_check_button_in_table(_("Include hidden files"), 
1369
 
                                                bfwin->session->sync_include_hidden, table,
1370
 
                                                0, 3, 3, 4);
1371
 
        
1372
 
        sd->messagelabel = gtk_label_new(NULL);
1373
 
        gtk_box_pack_start(GTK_BOX(carea), sd->messagelabel, FALSE, FALSE, 4);
1374
 
 
1375
 
        sd->progress = gtk_progress_bar_new();
1376
 
        gtk_progress_bar_set_ellipsize(GTK_PROGRESS_BAR(sd->progress), PANGO_ELLIPSIZE_MIDDLE);
1377
 
        gtk_box_pack_start(GTK_BOX(carea), sd->progress, FALSE, FALSE, 4);
1378
 
 
1379
 
        if (bfwin->session->sync_local_uri && bfwin->session->sync_local_uri[0] != '\0') {
1380
 
                gtk_entry_set_text(GTK_ENTRY(sd->entry_local), bfwin->session->sync_local_uri);
1381
 
        } else if (bfwin->session->recent_dirs && bfwin->session->recent_dirs->data
1382
 
                           && *(gchar *) bfwin->session->recent_dirs->data != '\0') {
1383
 
                gtk_entry_set_text(GTK_ENTRY(sd->entry_local), bfwin->session->recent_dirs->data);
1384
 
        }
1385
 
 
1386
 
        if (bfwin->session->sync_remote_uri && bfwin->session->sync_remote_uri[0] != '\0') {
1387
 
                gtk_entry_set_text(GTK_ENTRY(sd->entry_remote), bfwin->session->sync_remote_uri);
1388
 
        }
1389
 
 
1390
 
        sd->signal_id = g_signal_connect(sd->dialog, "response", G_CALLBACK(sync_dialog_response_lcb), sd);
1391
 
        gtk_widget_show_all(sd->dialog);
1392
 
        gtk_widget_hide(sd->messagelabel);
1393
 
}
1394
 
 
1395
 
static gchar *
1396
 
modified_on_disk_warning_string(const gchar * filename, GFileInfo * oldfinfo, GFileInfo * newfinfo)
1397
 
{
1398
 
        gchar *tmpstr, *oldtimestr, *newtimestr;
1399
 
        time_t newtime, oldtime;
1400
 
        gsize oldsize, newsize;
1401
 
 
1402
 
        newtime = (time_t) g_file_info_get_attribute_uint64(newfinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED);
1403
 
        oldtime = (time_t) g_file_info_get_attribute_uint64(oldfinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED);
1404
 
        newtimestr = bf_portable_time(&newtime);
1405
 
        oldtimestr = bf_portable_time(&oldtime);
1406
 
        newsize = g_file_info_get_size(newfinfo);
1407
 
        oldsize = g_file_info_get_size(oldfinfo);
1408
 
        /*g_print("oldtimestr=%s, newtimestr=%s\n",oldtimestr,newtimestr); */
1409
 
        tmpstr = g_strdup_printf(_("Filename:%s changed on disk.\n\n"
1410
 
                                                           "Original modification time was %s\n"
1411
 
                                                           "New modification time is %s\n"
1412
 
                                                           "Original size was %lu\n"
1413
 
                                                           "New size is %lu"), filename, oldtimestr, newtimestr, (long unsigned int)oldsize, (long unsigned int)newsize);
1414
 
        g_free(newtimestr);
1415
 
        g_free(oldtimestr);
1416
 
        return tmpstr;
1417
 
}
1418
 
 
1419
 
static void
1420
 
doc_activate_modified_lcb(Tcheckmodified_status status, GError * gerror, GFileInfo * orig, GFileInfo * new,
1421
 
                                                  gpointer callback_data)
1422
 
{
1423
 
        Tdocument *doc = callback_data;
1424
 
        switch (status) {
1425
 
        case CHECKMODIFIED_ERROR:
1426
 
                DEBUG_MSG("doc_activate_modified_lcb, CHECKMODIFIED_ERROR ??\n");
1427
 
                if (gerror->code == G_IO_ERROR_NOT_FOUND) {
1428
 
                        gchar *tmpstr;
1429
 
                        gint retval;
1430
 
                        const gchar *buttons[] = { _("_Unset file name"), _("_Save"), NULL };
1431
 
                        /* file is deleted on disk, what do we do now ? */
1432
 
                        tmpstr = g_strdup_printf(_("File name: %s"), gtk_label_get_text(GTK_LABEL(doc->tab_menu)));
1433
 
                        retval = message_dialog_new_multi(BFWIN(doc->bfwin)->main_window,
1434
 
                                                                                          GTK_MESSAGE_WARNING,
1435
 
                                                                                          buttons, _("File disappeared from disk\n"), tmpstr);
1436
 
                        g_free(tmpstr);
1437
 
                        if (retval == 1) {      /* save */
1438
 
                                doc_save_backend(doc, FALSE, FALSE, FALSE, FALSE);
1439
 
                        } else {                        /* unset */
1440
 
                                document_unset_filename(doc);
1441
 
                        }
1442
 
                } else {
1443
 
                        /* TODO: warn the user */
1444
 
                }
1445
 
                break;
1446
 
        case CHECKMODIFIED_CANCELLED:
1447
 
                DEBUG_MSG("doc_activate_modified_lcb, CHECKMODIFIED_CANCELLED\n");
1448
 
                break;
1449
 
        case CHECKMODIFIED_MODIFIED:
1450
 
                {
1451
 
                        gchar *tmpstr /*, *oldtimestr, *newtimestr */ ;
1452
 
                        gint retval;
1453
 
                        const gchar *buttons[] =
1454
 
                                { _("_Ignore"), _("_Reload"), _("Check and reload all documents"), NULL };
1455
 
                        /*time_t newtime,origtime;
1456
 
 
1457
 
                           newtime = (time_t)g_file_info_get_attribute_uint64(new,G_FILE_ATTRIBUTE_TIME_MODIFIED);
1458
 
                           origtime = (time_t)g_file_info_get_attribute_uint64(orig,G_FILE_ATTRIBUTE_TIME_MODIFIED);
1459
 
                           g_print("doc_activate_modified_lcb, newtime=%ld,%d origtime=%ld,%d newsize=%"G_GOFFSET_FORMAT" origsize=%"G_GOFFSET_FORMAT"\n",
1460
 
                           newtime,g_file_info_get_attribute_uint32(new,G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC),
1461
 
                           origtime,g_file_info_get_attribute_uint32(orig,G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC),
1462
 
                           g_file_info_get_size(new),g_file_info_get_size(orig));
1463
 
                           newtimestr = bf_portable_time(&newtime);
1464
 
                           oldtimestr = bf_portable_time(&origtime);
1465
 
 
1466
 
                           tmpstr = g_strdup_printf(_("Filename: %s\n\nNew modification time is: %s\nOld modification time is: %s"), gtk_label_get_text(GTK_LABEL(doc->tab_menu)), newtimestr, oldtimestr);
1467
 
                         */
1468
 
                        tmpstr = modified_on_disk_warning_string(gtk_label_get_text(GTK_LABEL(doc->tab_menu)), orig, new);
1469
 
                        retval = message_dialog_new_multi(BFWIN(doc->bfwin)->main_window,
1470
 
                                                                                          GTK_MESSAGE_WARNING,
1471
 
                                                                                          buttons, _("File changed on disk\n"), tmpstr);
1472
 
                        g_free(tmpstr);
1473
 
                        /*g_free(newtimestr);
1474
 
                           g_free(oldtimestr); */
1475
 
                        if (retval == 0) {      /* ignore */
1476
 
                                /*if (doc->fileinfo) {
1477
 
                                   g_object_unref(doc->fileinfo);
1478
 
                                   }
1479
 
                                   doc->fileinfo = new;
1480
 
                                   g_object_ref(doc->fileinfo); */
1481
 
                                GTimeVal mtime;
1482
 
                                g_file_info_set_size(doc->fileinfo, g_file_info_get_size(new));
1483
 
                                g_file_info_get_modification_time(new, &mtime);
1484
 
                                g_file_info_set_modification_time(doc->fileinfo, &mtime);
1485
 
                                g_file_info_set_attribute_string(doc->fileinfo, "etag::value",
1486
 
                                                                                                 g_file_info_get_attribute_string(new, "etag::value"));
1487
 
                                doc_set_tooltip(doc);
1488
 
                        } else if (retval == 1) {       /* reload */
1489
 
                                doc_reload(doc, new, FALSE);
1490
 
                        } else {                        /* reload all modified documents */
1491
 
                                file_reload_all_modified(doc->bfwin);
1492
 
                        }
1493
 
                }
1494
 
                break;
1495
 
        case CHECKMODIFIED_OK:
1496
 
                /* do nothing */
1497
 
                break;
1498
 
        }
1499
 
        doc->checkmodified = NULL;
1500
 
}
1501
 
 
1502
 
void
1503
 
doc_start_modified_check(Tdocument * doc)
1504
 
{
1505
 
        if (doc->uri && doc->fileinfo && !doc->checkmodified && !doc->save) {   /* don't check during another check, or during save */
1506
 
                doc->checkmodified =
1507
 
                        file_checkmodified_uri_async(doc->uri, doc->fileinfo, doc_activate_modified_lcb, doc);
1508
 
        }
1509
 
}
1510
 
 
1511
 
static gboolean
1512
 
modified_on_disk_check_lcb(gpointer data)
1513
 
{
1514
 
        GList *tmplist = g_list_first(main_v->bfwinlist);
1515
 
        while (tmplist) {
1516
 
                Tbfwin *bfwin = tmplist->data;
1517
 
                if (bfwin->current_document) {
1518
 
                        doc_start_modified_check(bfwin->current_document);
1519
 
                }
1520
 
                tmplist = g_list_next(tmplist);
1521
 
        }
1522
 
        return TRUE;
1523
 
}
1524
 
 
1525
 
void
1526
 
modified_on_disk_check_init(void)
1527
 
{
1528
 
        if (main_v->props.do_periodic_check && !main_v->periodic_check_id)
1529
 
                main_v->periodic_check_id =
1530
 
                        g_timeout_add_seconds_full(G_PRIORITY_LOW, 15, modified_on_disk_check_lcb, NULL, NULL);
1531
 
        else if (!main_v->props.do_periodic_check && main_v->periodic_check_id) {
1532
 
                g_source_remove(main_v->periodic_check_id);
1533
 
                main_v->periodic_check_id = 0;
1534
 
        }
1535
 
}