1
/* Bluefish HTML Editor
2
* file_dialogs.c - file dialogs
4
* Copyright (C) 2005-2011 Olivier Sessink
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.
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.
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/>.
20
/* indented with indent -ts4 -kr -l110 */
24
#include <string.h> /* memcpy */
25
#include <time.h> /* strftime() */
28
#include "file_dialogs.h"
31
#include "dialog_utils.h"
33
#include "file_autosave.h"
35
#include "filebrowser2.h"
37
#include "snr3.h" /* snr3_run_extern_replace() */
38
#include "stringlist.h"
39
#include "undo_redo.h"
41
static gchar *modified_on_disk_warning_string(const gchar * filename, GFileInfo * oldfinfo,
42
GFileInfo * newfinfo);
44
/**************************************************************************/
45
/* the start of the callback functions for the menu, acting on a document */
46
/**************************************************************************/
50
GtkWidget *find_pattern;
53
GtkWidget *max_recursion;
54
GtkWidget *grep_pattern;
61
files_advanced_win_findpattern_changed(GtkComboBox * combobox, Tfiles_advanced * tfs)
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);
66
gtk_dialog_set_response_sensitive(GTK_DIALOG(tfs->dialog), GTK_RESPONSE_ACCEPT, FALSE);
71
files_advanced_win_ok_clicked(Tfiles_advanced * tfs)
74
gchar *basedir, *content_filter, *extension_filter;
76
GError *gerror = NULL;
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);
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))
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);
100
g_free(content_filter);
101
g_free(extension_filter);
102
g_object_unref(baseuri);
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));
108
bfwin_statusbar_message(tfs->bfwin,_("Started open advanced..."), 1);
113
files_advanced_win_select_basedir_lcb(GtkWidget * widget, Tfiles_advanced * tfs)
115
gchar *newdir = NULL;
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));
124
gtk_widget_destroy(dialog);
127
gtk_entry_set_text(GTK_ENTRY(tfs->basedir), newdir);
133
files_advanced_win(Tbfwin * bfwin, gchar * basedir)
135
GtkWidget *alignment, *button, *carea, *table, *vbox, *vbox2;
136
Tfiles_advanced *tfs;
138
tfs = g_new(Tfiles_advanced, 1);
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);
147
#if !GTK_CHECK_VERSION(3, 0, 0)
148
gtk_dialog_set_has_separator(GTK_DIALOG(tfs->dialog), FALSE);
150
carea = gtk_dialog_get_content_area(GTK_DIALOG(tfs->dialog));
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);
158
vbox2 = dialog_vbox_labeled(_("<b>Files</b>"), vbox);
160
table = dialog_table_in_vbox(2, 6, 0, vbox2, FALSE, FALSE, 6);
163
tfs->basedir = dialog_entry_in_table(bfwin->session->opendir, table, 1, 5, 0, 1);
165
tfs->basedir = dialog_entry_in_table(basedir, table, 1, 5, 0, 1);
167
dialog_mnemonic_label_in_table(_("Base _Dir:"), tfs->basedir, table, 0, 1, 0, 1);
170
dialog_button_new_with_image_in_table(NULL, GTK_STOCK_OPEN, G_CALLBACK(files_advanced_win_select_basedir_lcb), tfs,
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);
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);
188
table = dialog_table_in_vbox(3, 2, 0, vbox2, FALSE, FALSE, 0);
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);
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);
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);
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);
208
vbox2 = dialog_vbox_labeled(_("<b>Contains</b>"), vbox);
210
table = dialog_table_in_vbox(2, 4, 0, vbox2, FALSE, FALSE, 6);
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);
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);
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);
223
gtk_dialog_set_response_sensitive(GTK_DIALOG(tfs->dialog), GTK_RESPONSE_ACCEPT, FALSE);
224
gtk_widget_show_all(carea);
226
while (gtk_dialog_run(GTK_DIALOG(tfs->dialog)) == GTK_RESPONSE_ACCEPT) {
227
if (files_advanced_win_ok_clicked(tfs))
231
gtk_widget_destroy(tfs->dialog);
236
file_open_advanced_cb(GtkWidget * widget, Tbfwin * bfwin)
238
files_advanced_win(bfwin, NULL);
241
/*************** end of advanced open code *************/
244
file_open_ok_lcb(GtkDialog * dialog, gint response, Tbfwin * bfwin)
246
if (response == GTK_RESPONSE_ACCEPT) {
247
GSList *slist, *tmpslist;
249
bfwin->focus_next_new_doc = TRUE;
250
combo = g_object_get_data(G_OBJECT(dialog), "encodings");
253
if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) {
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);
261
bfwin->session->encoding = g_strdup(arr[1]);
263
bfwin->session->encoding = NULL;
265
DEBUG_MSG("file_open_ok_lcb, session encoding is set to %s\n", bfwin->session->encoding);
268
#if GTK_CHECK_VERSION(2,14,0)
269
tmpslist = slist = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
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;
277
tmpslist = slist = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(dialog));
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;
289
gtk_widget_destroy(GTK_WIDGET(dialog));
293
file_open_doc(Tbfwin * bfwin)
298
file_chooser_dialog(bfwin, _("Select files"), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, FALSE, TRUE, NULL,
300
g_signal_connect(dialog, "response", G_CALLBACK(file_open_ok_lcb), bfwin);
301
gtk_widget_show_all(dialog);
306
* @widget: unused #GtkWidget
307
* @bfwin: #Tbfwin* with the current window
309
* Prompt user for files to open.
314
file_open_cb(GtkWidget * widget, Tbfwin * bfwin)
318
file_chooser_dialog(bfwin, _("Select files"), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, FALSE, TRUE, NULL,
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) {
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);
329
gtk_widget_destroy(dialog);*/
338
open_url_destroy_lcb(GtkWidget * widget, Tou * ou)
344
open_url_cancel_lcb(GtkWidget * widget, Tou * ou)
346
gtk_widget_destroy(ou->win);
350
open_url_ok_lcb(GtkWidget * widget, Tou * ou)
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);
356
gtk_widget_destroy(ou->win);
361
* @widget: #GtkWidget* ignored
362
* @bfwin: #Tbfwin* bfwin pointer
364
* opens a dialog where you can enter an URL to open of any kind
365
* supported by gnome-vfs
370
file_open_url_cb(GtkAction * action, Tbfwin * bfwin)
372
GtkWidget *align, *vbox, *hbox, *but;
374
GList *urlhistory = NULL, *tmplist = NULL;
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) {
385
GtkWidget *label = gtk_label_new(NULL);
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);
393
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 4);
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);
400
if (tmplist->data && strlen(tmplist->data) > 5 && strncmp(tmplist->data, "file:", 5) != 0) {
401
urlhistory = g_list_prepend(urlhistory, g_strdup(tmplist->data));
403
tmplist = g_list_next(tmplist);
405
ou->entry = boxed_combobox_with_popdown("", urlhistory, TRUE, vbox);
406
free_stringlist(urlhistory);
407
/* ou->entry = boxed_entry_with_text("", 255, vbox); */
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);
413
#if GTK_CHECK_VERSION(3,0,0)
414
hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
416
hbox = gtk_hbutton_box_new();
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);
429
/***********************************/
430
/* async save code */
435
GFile *fbrefresh_uri;
439
docsavebackend_cleanup(Tdocsavebackend * dsb)
442
g_object_unref(dsb->unlink_uri);
443
if (dsb->fbrefresh_uri)
444
g_object_unref(dsb->fbrefresh_uri);
449
docsavebackend_async_unlink_lcb(gpointer data)
451
Tdocsavebackend *dsb = data;
452
fb2_refresh_parent_of_uri(dsb->unlink_uri);
453
docsavebackend_cleanup(dsb);
456
static TcheckNsave_return
457
doc_checkNsave_lcb(TcheckNsave_status status, GError * gerror, gpointer data)
459
Tdocsavebackend *dsb = data;
460
Tdocument *doc = dsb->doc;
462
DEBUG_MSG("doc_checkNsave_lcb, doc=%p, status=%d\n", doc, 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) {
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) */
473
/* we have to ask the user */
474
const gchar *buttons[] = { _("_Abort save"), _("_Continue save"), NULL };
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)));
481
message_dialog_new_multi(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_WARNING, buttons,
482
_("File backup failure"), tmpstr);
484
DEBUG_MSG("doc_checkNsave_lcb, retval=%d, returning %d\n", retval,
485
(retval == 0) ? CHECKNSAVE_STOP : CHECKNSAVE_CONT);
488
gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
489
return CHECKNSAVE_STOP;
491
return CHECKNSAVE_CONT;
494
case CHECKANDSAVE_ERROR:
495
case CHECKANDSAVE_ERROR_NOWRITE:
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);
503
/* no break - fall through */
504
case CHECKANDSAVE_ERROR_CANCELLED:
506
gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
507
docsavebackend_cleanup(dsb);
509
case CHECKANDSAVE_ERROR_MODIFIED:
511
/* we have to ask the user what to do */
512
const gchar *buttons[] = { _("_Abort save"), _("_Continue save"), NULL };
514
GError *gerror = NULL;
516
gchar *tmpstr, *utf8uri;
519
g_file_query_info(doc->uri, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_TIME_MODIFIED,
522
g_warning("file was modified on disk, but now an error??");
523
g_error_free(gerror);
524
return CHECKNSAVE_CONT;
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); */
530
g_object_unref(newfinfo);
532
message_dialog_new_multi(BFWIN(doc->bfwin)->main_window, GTK_MESSAGE_WARNING, buttons,
533
_("File changed on disk\n"), tmpstr);
537
gtk_text_view_set_editable(GTK_TEXT_VIEW(doc->view), TRUE);
538
return CHECKNSAVE_STOP;
540
return CHECKNSAVE_CONT;
542
case CHECKANDSAVE_FINISHED:
543
if (dsb->unlink_uri) {
544
file_delete_async(dsb->unlink_uri, FALSE, docsavebackend_async_unlink_lcb, dsb);
546
/* if the user wanted to close the doc we should do very diffferent things here !! */
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);
555
return CHECKNSAVE_STOP; /* it actually doesn't matter what we return, this was the last callback anyway */
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);
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);
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);
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);
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);
591
return CHECKNSAVE_CONT;
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
601
* returns a newly allocated string with a new filename
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
608
* Return value: gchar* with newly allocated string, or NULL on failure or abort
611
ask_new_filename(Tbfwin * bfwin, const gchar * old_curi, const gchar * gui_name, gboolean is_move)
615
gchar *new_curi = NULL;
620
dialogtext = g_strdup_printf((is_move) ? _("Move/rename %s to") : _("Save %s as"), gui_name);
622
file_chooser_dialog(bfwin, dialogtext, GTK_FILE_CHOOSER_ACTION_SAVE, old_curi, FALSE, FALSE, NULL,
626
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
627
new_curi = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
629
gtk_widget_destroy(dialog);
633
if (old_curi && strcmp(old_curi, new_curi) == 0) {
638
alldocs = return_allwindows_documentlist();
639
uri = g_file_new_for_uri(new_curi);
640
exdoc = documentlist_return_document_from_uri(alldocs, uri);
642
g_list_free(alldocs);
643
DEBUG_MSG("ask_new_filename, exdoc=%p, newfilename=%s\n", exdoc, new_curi);
647
const gchar *buttons[] = { _("_Cancel"), _("_Overwrite"), NULL };
648
tmpstr = g_strdup_printf(_("File %s exists and is open, overwrite?"), new_curi);
650
message_dialog_new_multi(bfwin->main_window, GTK_MESSAGE_WARNING, buttons, tmpstr,
651
_("The file you have selected is being edited in Bluefish."));
657
document_unset_filename(exdoc);
662
tmp = g_file_new_for_uri(new_curi);
663
exists = g_file_query_exists(tmp, NULL);
668
const gchar *buttons[] = { _("_Cancel"), _("_Overwrite"), NULL };
669
tmpstr = g_strdup_printf(_("A file named \"%s\" already exists."), new_curi);
671
message_dialog_new_multi(bfwin->main_window, GTK_MESSAGE_WARNING, buttons, tmpstr,
672
_("Do you want to replace the existing file?"));
684
doc_save_backend(Tdocument * doc, gboolean do_save_as, gboolean do_move, gboolean close_doc,
685
gboolean close_window)
688
Trefcpointer *buffer;
690
Tdocsavebackend *dsb;
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);
696
g_print("Cannot save readonly document !?!?");
700
dsb = g_new0(Tdocsavebackend, 1);
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) {
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);
717
/* update date meta tag */
718
if (main_v->props.auto_update_meta_date) {
720
struct tm *time_struct;
724
time_var = time(NULL);
725
time_struct = localtime(&time_var);
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);
739
strftime(isotime, 30, "%Y-%m-%dT%H:%M:%S%z", time_struct);
741
DEBUG_MSG("doc_save_backend, ISO-8601 time %s\n", isotime);
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);
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);
759
curi = g_file_get_uri(doc->uri);
763
/* this message is not in very nice english I'm afraid */
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);
772
if (doc->uri == NULL) {
781
ask_new_filename(BFWIN(doc->bfwin), curi, gtk_label_get_text(GTK_LABEL(doc->tab_label)), do_move);
790
dsb->unlink_uri = doc->uri; /* unlink this uri later */
791
g_object_ref(dsb->unlink_uri);
793
g_object_unref(doc->uri);
796
doc->uri = g_file_new_for_uri(newfilename);
798
bmark_doc_renamed(BFWIN(doc->bfwin), doc);
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);
807
session_set_savedir(doc->bfwin, curi);
809
tmp = doc_get_buffer_in_encoding(doc);
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)) {
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);
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));
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);
835
doc->readonly = FALSE;
836
doc_reset_filetype(doc, doc->uri, buffer->data, strlen(buffer->data));
838
doc_force_activate(doc);
840
refcpointer_unref(buffer);
847
* @widget: unused #GtkWidget
848
* @bfwin: #Tbfwin* with the current window
850
* Save the current document.
855
file_save_cb(GtkWidget * widget, Tbfwin * bfwin)
857
if (bfwin->current_document)
858
doc_save_backend(bfwin->current_document, FALSE, FALSE, FALSE, FALSE);
863
* @widget: unused #GtkWidget
864
* @bfwin: #Tbfwin* with the current window
866
* Save current document, let user choose filename.
871
file_save_as_cb(GtkWidget * widget, Tbfwin * bfwin)
873
if (bfwin->current_document)
874
doc_save_backend(bfwin->current_document, TRUE, FALSE, FALSE, FALSE);
879
* @widget: unused #GtkWidget
880
* @bfwin: #Tbfwin* with the current window
882
* Move current document, let user choose filename.
887
file_move_to_cb(GtkWidget * widget, Tbfwin * bfwin)
889
if (bfwin->current_document)
890
doc_save_backend(bfwin->current_document, TRUE, TRUE, FALSE, FALSE);
894
file_save_all(Tbfwin * bfwin)
899
tmplist = g_list_first(bfwin->documentlist);
901
tmpdoc = (Tdocument *) tmplist->data;
902
if (tmpdoc->modified) {
903
doc_save_backend(tmpdoc, FALSE, FALSE, FALSE, FALSE);
905
tmplist = g_list_next(tmplist);
911
* @widget: unused #GtkWidget
912
* @bfwin: the #Tbfwin* window pointer
914
* Save all editor notebooks
919
file_save_all_cb(GtkWidget * widget, Tbfwin * bfwin)
924
tmplist = g_list_first(bfwin->documentlist);
926
tmpdoc = (Tdocument *) tmplist->data;
927
if (tmpdoc->modified) {
928
doc_save_backend(tmpdoc, FALSE, FALSE, FALSE, FALSE);
930
tmplist = g_list_next(tmplist);
935
doc_save_all_close(Tbfwin * bfwin)
937
GList *tmplist = g_list_first(bfwin->documentlist);
939
Tdocument *tmpdoc = (Tdocument *) tmplist->data;
940
doc_save_backend(tmpdoc, FALSE, FALSE, TRUE, TRUE);
941
tmplist = g_list_next(tmplist);
947
doc_modified_dialog(Tdocument * doc)
949
const gchar *buttons[] = { _("Close _Without Saving"), GTK_STOCK_CANCEL, GTK_STOCK_SAVE, NULL };
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."));
961
multiple_files_modified_dialog(Tbfwin * bfwin)
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;
971
/* return TRUE if all are either closed or saved
972
return FALSE on cancel*/
974
choose_per_file(Tbfwin * bfwin, gboolean close_window)
976
GList *duplist, *tmplist;
977
duplist = g_list_copy(bfwin->documentlist);
978
tmplist = g_list_first(duplist);
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);
987
DEBUG_MSG("choose_per_file, call doc_close\n");
988
tmpdoc->modified = FALSE;
989
doc_close_single_backend(tmpdoc, TRUE, close_window);
995
DEBUG_MSG("choose_per_file, call doc_save\n");
996
doc_save_backend(tmpdoc, FALSE, FALSE, TRUE, close_window);
1000
doc_close_single_backend(tmpdoc, TRUE, close_window);
1002
tmplist = g_list_next(tmplist);
1004
g_list_free(duplist);
1009
doc_close_single_backend(Tdocument * doc, gboolean delay_activate, gboolean close_window)
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;
1023
file_asyncfileinfo_cancel(doc->info);
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");
1031
if (doc->autosaved || doc->autosave_progress || doc->need_autosave) {
1032
remove_autosave(doc);
1034
if (doc_is_empty_non_modified_and_nameless(doc)
1035
&& g_list_length(BFWIN(doc->bfwin)->documentlist) <= 1) {
1037
bfwin_destroy_and_cleanup(BFWIN(doc->bfwin));
1041
if (doc->modified) {
1042
gint retval = doc_modified_dialog(doc);
1045
doc_destroy(doc, close_window || delay_activate);
1051
doc_save_backend(doc, FALSE, FALSE, TRUE, close_window);
1055
doc_destroy(doc, close_window || delay_activate);
1057
if (close_window && bfwin->documentlist == NULL) { /* the documentlist is empty */
1058
bfwin_destroy_and_cleanup(bfwin);
1060
DEBUG_MSG("doc_close_single_backend, finished!\n");
1066
* @widget: unused #GtkWidget
1067
* @data: unused #gpointer
1069
* Close the current document.
1071
* Return value: void
1074
file_close_cb(GtkWidget * widget, Tbfwin * bfwin)
1076
if (bfwin->current_document)
1077
doc_close_single_backend(bfwin->current_document, FALSE, FALSE);
1081
doc_close_multiple_backend(Tbfwin * bfwin, gboolean close_window, Tclose_mode close_mode)
1083
GList *tmplist, *duplist;
1086
/* if (g_list_length(bfwin->documentlist) == 1) {
1087
return doc_close_single_backend(bfwin->current_document, FALSE, close_window);
1089
if (have_modified_documents(bfwin->documentlist)) {
1090
retval = multiple_files_modified_dialog(bfwin);
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
1099
duplist = g_list_copy(bfwin->documentlist);
1100
tmplist = g_list_first(duplist);
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);
1110
tmplist = g_list_next(tmplist);
1112
g_list_free(duplist);
1113
DEBUG_MSG("doc_close_multiple_backend, finished\n");
1115
bfwin_notebook_changed(bfwin, -1);
1119
file_close_all(Tbfwin * bfwin)
1121
if (have_modified_documents(bfwin->documentlist)) {
1122
Tclose_mode retval = multiple_files_modified_dialog(bfwin);
1124
case close_mode_cancel:
1127
case close_mode_per_file:
1128
choose_per_file(bfwin, FALSE);
1130
case close_mode_save_all:
1131
case close_mode_close_all:
1132
doc_close_multiple_backend(bfwin, FALSE, retval);
1136
doc_close_multiple_backend(bfwin, FALSE, close_mode_close_all);
1141
* file_close_all_cb:
1142
* @widget: unused #GtkWidget
1145
* Close all open files. Prompt user when neccessary.
1147
* Return value: void
1150
file_close_all_cb(GtkWidget * widget, Tbfwin * bfwin)
1152
if (have_modified_documents(bfwin->documentlist)) {
1153
Tclose_mode retval = multiple_files_modified_dialog(bfwin);
1155
case close_mode_cancel:
1158
case close_mode_per_file:
1159
choose_per_file(bfwin, FALSE);
1161
case close_mode_save_all:
1162
case close_mode_close_all:
1163
doc_close_multiple_backend(bfwin, FALSE, retval);
1167
doc_close_multiple_backend(bfwin, FALSE, close_mode_close_all);
1172
file_new_doc(Tbfwin * bfwin)
1175
GFile *template = NULL;
1177
if (bfwin->session->template && bfwin->session->template[0]) {
1178
template = g_file_new_for_commandline_arg(bfwin->session->template);
1180
doc = doc_new_with_template(bfwin, template, TRUE);
1181
bfwin_switch_to_document_by_pointer(bfwin, doc);
1186
* @windget: #GtkWidget* ignored
1187
* @bfwin: Tbfwin* where to open the new document
1189
* Create a new, empty file in window bfwin
1191
* Return value: void
1194
file_new_cb(GtkWidget * widget, Tbfwin * bfwin)
1197
GFile *template = NULL;
1198
if (bfwin->session->template && bfwin->session->template[0]) {
1199
template = g_file_new_for_commandline_arg(bfwin->session->template);
1201
doc = doc_new_with_template(bfwin, template, TRUE);
1202
bfwin_switch_to_document_by_pointer(bfwin, doc);
1206
file_reload_all_modified_check_lcb(Tcheckmodified_status status, GError * gerror,
1207
GFileInfo * orig, GFileInfo * new, gpointer user_data)
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);
1216
file_reload_all_modified(Tbfwin * bfwin)
1218
GList *tmplist = g_list_first(bfwin->documentlist);
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);
1225
tmplist = g_list_next(tmplist);
1232
GtkWidget *entry_local;
1233
GtkWidget *entry_remote;
1234
GtkWidget *delete_deprecated;
1235
GtkWidget *include_hidden;
1236
GtkWidget *progress;
1237
GtkWidget *messagelabel;
1242
sync_progress(GFile *uri, gint total, gint done, gint failed, gpointer user_data)
1244
Tsyncdialog *sd = user_data;
1247
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->progress), 1.0 * done / total);
1249
gchar * curi = g_file_get_uri(uri);
1250
text = g_strdup_printf("%s (%d / %d)", curi, done, total);
1253
text = g_strdup_printf("%d / %d", done, total);
1255
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), text);
1256
/* g_print("%s\n",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);
1267
} else if (total == -1) {
1268
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->progress), 1);
1270
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), _("incomplete finished"));
1272
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->progress), _("completed"));
1274
g_signal_handler_unblock(sd->dialog, sd->signal_id);
1279
sync_dialog_response_lcb(GtkDialog * dialog, gint response_id, gpointer user_data)
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,
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,
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));
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);
1311
g_object_unref(local);
1312
g_object_unref(remote);
1314
gtk_widget_destroy(sd->dialog);
1315
g_slice_free(Tsyncdialog, sd);
1320
sync_dialog(Tbfwin * bfwin)
1323
GtkWidget *carea, *table;
1325
sd = g_slice_new0(Tsyncdialog);
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);
1333
carea = gtk_dialog_get_content_area(GTK_DIALOG(sd->dialog));
1335
#if !GLIB_CHECK_VERSION(2, 18, 0)
1336
if (glib_major_version == 2 && glib_minor_version < 18) {
1338
GtkWidget *label = gtk_label_new(NULL);
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);
1346
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(sd->dialog))), label, FALSE, FALSE,
1350
table = dialog_table_in_vbox(4, 3, 6, carea, TRUE,TRUE, 3);
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,
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);
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,
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);
1364
sd->delete_deprecated = dialog_check_button_in_table(_("Delete deprecated files"),
1365
bfwin->session->sync_delete_deprecated, table,
1368
sd->include_hidden = dialog_check_button_in_table(_("Include hidden files"),
1369
bfwin->session->sync_include_hidden, table,
1372
sd->messagelabel = gtk_label_new(NULL);
1373
gtk_box_pack_start(GTK_BOX(carea), sd->messagelabel, FALSE, FALSE, 4);
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);
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);
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);
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);
1396
modified_on_disk_warning_string(const gchar * filename, GFileInfo * oldfinfo, GFileInfo * newfinfo)
1398
gchar *tmpstr, *oldtimestr, *newtimestr;
1399
time_t newtime, oldtime;
1400
gsize oldsize, newsize;
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);
1420
doc_activate_modified_lcb(Tcheckmodified_status status, GError * gerror, GFileInfo * orig, GFileInfo * new,
1421
gpointer callback_data)
1423
Tdocument *doc = callback_data;
1425
case CHECKMODIFIED_ERROR:
1426
DEBUG_MSG("doc_activate_modified_lcb, CHECKMODIFIED_ERROR ??\n");
1427
if (gerror->code == G_IO_ERROR_NOT_FOUND) {
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);
1437
if (retval == 1) { /* save */
1438
doc_save_backend(doc, FALSE, FALSE, FALSE, FALSE);
1439
} else { /* unset */
1440
document_unset_filename(doc);
1443
/* TODO: warn the user */
1446
case CHECKMODIFIED_CANCELLED:
1447
DEBUG_MSG("doc_activate_modified_lcb, CHECKMODIFIED_CANCELLED\n");
1449
case CHECKMODIFIED_MODIFIED:
1451
gchar *tmpstr /*, *oldtimestr, *newtimestr */ ;
1453
const gchar *buttons[] =
1454
{ _("_Ignore"), _("_Reload"), _("Check and reload all documents"), NULL };
1455
/*time_t newtime,origtime;
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);
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);
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);
1473
/*g_free(newtimestr);
1474
g_free(oldtimestr); */
1475
if (retval == 0) { /* ignore */
1476
/*if (doc->fileinfo) {
1477
g_object_unref(doc->fileinfo);
1479
doc->fileinfo = new;
1480
g_object_ref(doc->fileinfo); */
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);
1495
case CHECKMODIFIED_OK:
1499
doc->checkmodified = NULL;
1503
doc_start_modified_check(Tdocument * doc)
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);
1512
modified_on_disk_check_lcb(gpointer data)
1514
GList *tmplist = g_list_first(main_v->bfwinlist);
1516
Tbfwin *bfwin = tmplist->data;
1517
if (bfwin->current_document) {
1518
doc_start_modified_check(bfwin->current_document);
1520
tmplist = g_list_next(tmplist);
1526
modified_on_disk_check_init(void)
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;