~ubuntu-branches/ubuntu/natty/bluefish/natty-proposed

« back to all changes in this revision

Viewing changes to src/bookmark.c

  • Committer: Bazaar Package Importer
  • Author(s): Davide Puricelli (evo)
  • Date: 2005-04-23 17:05:18 UTC
  • mto: (1.1.5 upstream) (5.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050423170518-izh2k25xve7ui1jx
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Bluefish HTML Editor - bookmarks
 
2
 *
 
3
 * Copyright (C) 2003 Oskar Swida
 
4
 * modifications (C) 2004 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 2 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
/* #define DEBUG */
 
21
 
 
22
#include <gtk/gtk.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
#include <unistd.h>
 
26
#include <fcntl.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
#include "bluefish.h"
 
30
#include "gtk_easy.h"
 
31
#include "gui.h"
 
32
#include "document.h"
 
33
#include "stringlist.h"
 
34
#include "bookmark.h"
 
35
 
 
36
/*
 
37
bookmarks will be loaded and saved to an arraylist (see stringlist.c). This 
 
38
is a double linked list (GList *) with pointers to string arrays (gchar **).
 
39
 
 
40
To have the GUI work with them, we convert those arrays (gchar **) into a 
 
41
Tbmark struct. This struct will ahve a pointer to the array (gchar **) so 
 
42
on change it can directly change the array as well, without any need to 
 
43
look it up in the list.
 
44
 
 
45
For the GUI, we store everything in a Gtktreestore. The treestore will have a 
 
46
pointer to a string with the name, and it will also have a pointer to the 
 
47
Tbmark. When the user clicks in the Gtktreeview widget, we can get 
 
48
immediately a pointer to the Tbmark, and that has the Gtktextmark, so that 
 
49
is very easy, and very fast!
 
50
 
 
51
But now we have one problem: all normal windows do share the same bookmarks list. 
 
52
So it is probably the most logical to have them store the same Gtktreestore as 
 
53
well. The best way is to have the project functions create/destroy the 
 
54
gtktreestore when they convert a window (Tbfwin) into a project window.
 
55
*/
 
56
 
 
57
#define BMARK_SHOW_NUM_TEXT_CHARS 20
 
58
 
 
59
enum {
 
60
        NAME_COLUMN,                            /* bookmark name */
 
61
        PTR_COLUMN,                                     /* bookmark pointer */
 
62
        N_COLUMNS
 
63
};
 
64
 
 
65
enum {
 
66
        BMARK_ADD_PERM_DIALOG,
 
67
        BMARK_RENAME_TEMP_DIALOG,
 
68
        BMARK_RENAME_PERM_DIALOG
 
69
};
 
70
 
 
71
typedef struct {
 
72
        GtkTextMark *mark;
 
73
        gchar *filepath;
 
74
        gint offset;
 
75
        Tdocument *doc;
 
76
        GtkTreeIter iter;                       /* for tree view */
 
77
        gchar *description;
 
78
        gchar *text;
 
79
        gchar *name;
 
80
        gint len;                                       /* file length for integrity check - perhaps some hash code is needed */
 
81
        gboolean is_temp;
 
82
        gchar **strarr;                         /* this is a pointer to the location where this bookmark is stored in the sessionlist,
 
83
                                                                   so we can immediately change it _in_ the list */
 
84
} Tbmark;
 
85
#define BMARK(var) ((Tbmark *)(var))
 
86
 
 
87
typedef struct {
 
88
        Tdocument *bevent_doc;          /* last button event document */
 
89
        gint bevent_charoffset;         /* last button event location */
 
90
} Tbmarkdata;
 
91
#define BMARKDATA(var) ((Tbmarkdata *)(var))
 
92
 
 
93
#define BM_FMODE_FULL     0
 
94
#define BM_FMODE_HOME     1
 
95
#define BM_FMODE_FILE     2
 
96
 
 
97
static gchar *bmark_display_text(gchar *name, gchar *text) {
 
98
        if (name && strlen(name) > 0) {
 
99
                return g_strconcat(name, " - ", text,NULL);
 
100
        } 
 
101
        return g_strdup(text);
 
102
}
 
103
 
 
104
/* Free bookmark structure */
 
105
static void bmark_free(gpointer ptr)
 
106
{
 
107
        Tbmark *m;
 
108
        if (ptr == NULL)
 
109
                return;
 
110
        m = BMARK(ptr);
 
111
        if (m->doc && m->mark) {
 
112
                DEBUG_MSG("bmark_free, deleting mark %p\n",m->mark);
 
113
                gtk_text_buffer_delete_mark(m->doc->buffer, m->mark);
 
114
                m->doc = NULL;
 
115
        }
 
116
#ifdef DEBUG
 
117
        if (m->strarr) {
 
118
                DEBUG_MSG("bmark_free, NOT GOOD, strarr should be NULL here...\n");
 
119
        }
 
120
#endif
 
121
        g_free(m->filepath);
 
122
        g_free(m->text);
 
123
        g_free(m->name);
 
124
        g_free(m->description);
 
125
        g_free(m);
 
126
}
 
127
 
 
128
static void bmark_update_offset_from_textmark(Tbmark *b) {
 
129
        if (b->doc && b->mark) {
 
130
                GtkTextIter it;
 
131
                gtk_text_buffer_get_iter_at_mark(b->doc->buffer, &it, b->mark);
 
132
                b->offset = gtk_text_iter_get_offset(&it);
 
133
        }
 
134
}
 
135
 
 
136
/* 
 
137
 * this function should use a smart sorting algorithm to find
 
138
 * the GtkTreeIter of the bookmark *before* the place where this
 
139
 * bookmark should be added, but the same function can be used to
 
140
 * find the bookmarks we have to check to detect double bookmarks
 
141
 * at the same line.
 
142
 *
 
143
 * returns the bookmark closest before 'offset', or the bookmark exactly at 'offset'
 
144
 * 
 
145
 * returns NULL if we have to append this as first child to the parent
 
146
 * 
 
147
 */
 
148
static Tbmark *bmark_find_bookmark_before_offset(Tbfwin *bfwin, guint offset, GtkTreeIter *parent) {
 
149
        gint jumpsize, num_children, child;
 
150
        GtkTreeIter iter;
 
151
        
 
152
        num_children = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(bfwin->bookmarkstore), parent);
 
153
        if (num_children == 0) {
 
154
                return NULL;
 
155
        }
 
156
        
 
157
        if (num_children == 1) {
 
158
                gint compare;
 
159
                Tbmark *b;
 
160
                gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(bfwin->bookmarkstore), &iter, parent, 0);
 
161
                gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore),&iter,PTR_COLUMN,&b, -1);
 
162
                
 
163
                bmark_update_offset_from_textmark(b);
 
164
                DEBUG_MSG("bmark_find_bookmark_before_offset, num_children=%d\n",num_children);
 
165
                compare = (offset - b->offset);
 
166
 
 
167
                if (compare <= 0) {
 
168
                        return NULL;
 
169
                } else {
 
170
                        return b;
 
171
                }
 
172
        }
 
173
        jumpsize = (num_children+2)/2;
 
174
        child = num_children + 1 - jumpsize;
 
175
        DEBUG_MSG("bmark_find_bookmark_before_offset, num_children=%d,jumpsize=%d,child=%d\n",num_children,jumpsize,child);
 
176
        while (jumpsize > 0) {
 
177
                gint compare;
 
178
                Tbmark *b;
 
179
                
 
180
                if (child > num_children) child = num_children;
 
181
                if (child < 1) child = 1;
 
182
                /* we request child-1, NOT child*/
 
183
                gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(bfwin->bookmarkstore), &iter, parent, child-1);
 
184
                gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore),&iter,PTR_COLUMN,&b, -1);
 
185
                
 
186
                bmark_update_offset_from_textmark(b);
 
187
                compare = (offset - b->offset);
 
188
                DEBUG_MSG("in_loop: jumpsize=%2d, child=%2d, child offset=%3d, compare=%3d\n",jumpsize,child,b->offset,compare);
 
189
                if (compare == 0) {
 
190
                        return b;
 
191
                } else if (compare < 0) {
 
192
                        jumpsize = (jumpsize > 3) ? (jumpsize+1)/2 : jumpsize-1;
 
193
                        if (jumpsize <= 0) {
 
194
                                child--;
 
195
                                /* we request child-1, NOT child*/
 
196
                                if (child >= 1 && gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(bfwin->bookmarkstore), &iter, parent, child-1)) {
 
197
                                        gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore),&iter,PTR_COLUMN,&b, -1);
 
198
                                        bmark_update_offset_from_textmark(b);
 
199
                                        DEBUG_MSG("in_loop: returning bookmark (offset %d) for previous child %d\n",b->offset, child);
 
200
                                        return b;
 
201
                                } else{
 
202
                                        DEBUG_MSG("in_loop: no previous child, return NULL\n");
 
203
                                        return NULL;
 
204
                                }
 
205
                        }
 
206
                        child = child - jumpsize;
 
207
                } else { /* compare > 0 */
 
208
                        jumpsize = (jumpsize > 3) ? (jumpsize+1)/2 : jumpsize-1;
 
209
                        if (jumpsize <= 0) {
 
210
                                DEBUG_MSG("in_loop: return bookmark (offset %d) from child %d\n",b->offset, child);
 
211
                                return b;
 
212
                        }
 
213
                        child = child + jumpsize;
 
214
                }
 
215
        }
 
216
        DEBUG_MSG("bmark_find_bookmark_before_offset, end-of-function, return NULL\n");
 
217
        return NULL;
 
218
}
 
219
 
 
220
/* this function re-uses the b->strarr if possible, otherwise it will create a new one and
 
221
append it to the list */
 
222
static void bmark_store(Tbfwin * bfwin, Tbmark * b) {
 
223
        gchar **strarr;
 
224
        if (b->is_temp) {
 
225
                DEBUG_MSG("bmark_store, called for temp bookmark %p ?!?! weird!!!! returning\n", b);
 
226
                return;
 
227
        }
 
228
 
 
229
        /* if there is a strarr already, we only update the fields, else we append a new one */
 
230
        if (b->strarr == NULL) {
 
231
                DEBUG_MSG("bmark_store, creating new strarr for bookmark %p\n",b);
 
232
                strarr = g_malloc0(sizeof(gchar *) * 7);
 
233
                DEBUG_MSG("name=%s, description=%s, filepath=%s, text=%s\n", b->name, b->description, b->filepath, b->text);
 
234
                strarr[2] = g_strdup(b->filepath);
 
235
                strarr[4] = g_strdup(b->text);
 
236
        } else {
 
237
                DEBUG_MSG("bmark_store, bookmark %p has strarr at %p\n",b,b->strarr);
 
238
                strarr = b->strarr;
 
239
                /* free the ones we are going to update */
 
240
                g_free(strarr[0]);
 
241
                g_free(strarr[1]);
 
242
                g_free(strarr[3]);
 
243
                g_free(strarr[5]);
 
244
        }
 
245
        strarr[0] = g_strdup(b->name);
 
246
        strarr[1] = g_strdup(b->description);
 
247
#ifdef HAVE_GNOME_VFS
 
248
        if (b->doc)
 
249
                b->len = b->doc->fileinfo->size;
 
250
#else
 
251
        if (b->doc)
 
252
                b->len = b->doc->statbuf.st_size;
 
253
#endif
 
254
        strarr[3] = g_strdup_printf("%d", b->offset);
 
255
        DEBUG_MSG("bmark_store, offset string=%s, offset int=%d\n",strarr[3],b->offset);
 
256
        strarr[5] = g_strdup_printf("%d", b->len);
 
257
        DEBUG_MSG("bmark_store, arracount=%d\n",count_array(strarr));
 
258
        if (b->strarr == NULL) {
 
259
                bfwin->session->bmarks = g_list_append(bfwin->session->bmarks, strarr);
 
260
                DEBUG_MSG("added new (previously unstored) bookmark to session list, list length=%d\n",
 
261
                                  g_list_length(bfwin->session->bmarks));
 
262
                b->strarr = strarr;
 
263
        }
 
264
}
 
265
 
 
266
/* when a users want to save the project, it's good to have updated bookmarks
 
267
so this function will update all arrays (strarr**)
 
268
 */
 
269
void bmark_store_all(Tbfwin *bfwin) {
 
270
        /* we loop over all filename iters, and only for the ones that are opened
 
271
         we loop over the children (the ones that are not open cannot be changed) */
 
272
        GtkTreeIter fileit;
 
273
        gboolean cont;
 
274
 
 
275
        cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &fileit,NULL);
 
276
        while (cont) {
 
277
                Tdocument *doc = NULL;
 
278
                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &fileit, PTR_COLUMN,&doc, -1);
 
279
                if (doc) {
 
280
                        /* the document is open, so the offsets could be changed, store all permanent */
 
281
                        GtkTreeIter bmit;
 
282
                        gboolean cont2 = gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &bmit,&fileit);
 
283
                        DEBUG_MSG("bmark_store_all, storing bookmarks for %s\n",doc->filename);
 
284
                        while (cont2) {
 
285
                                Tbmark *bmark;
 
286
                                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &bmit, PTR_COLUMN,&bmark, -1);
 
287
                                if (!bmark->is_temp) {
 
288
                                        bmark_update_offset_from_textmark(bmark);
 
289
                                        bmark_store(bfwin, bmark);
 
290
                                }
 
291
                                cont2 = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &bmit);
 
292
                        }
 
293
                } else {
 
294
                        DEBUG_MSG("doc not set, so not open...\n");
 
295
                }
 
296
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(bfwin)->bookmarkstore), &fileit);
 
297
        } /* cont */
 
298
}
 
299
 
 
300
/* removes the bookmark from the session, removed the b->strarr pointer and frees it */
 
301
static void bmark_unstore(Tbfwin * bfwin, Tbmark * b)
 
302
{
 
303
        if (bfwin->session->bmarks == NULL || b->strarr == NULL)
 
304
                return;
 
305
        DEBUG_MSG("bmark_remove, removing bookmark %p from sessionlist\n",b);
 
306
        bfwin->session->bmarks = g_list_remove(bfwin->session->bmarks, b->strarr);
 
307
        g_strfreev(b->strarr);
 
308
        b->strarr = NULL;
 
309
}
 
310
 
 
311
/* get value from pointer column */
 
312
static gpointer get_current_bmark(Tbfwin * bfwin)
 
313
{
 
314
        if (bfwin->bmark) {
 
315
                GtkTreePath *path;
 
316
                GtkTreeViewColumn *col;
 
317
                gtk_tree_view_get_cursor(bfwin->bmark, &path, &col);
 
318
                if (path != NULL) {
 
319
                        gpointer retval = NULL;
 
320
                        GtkTreeIter iter;
 
321
                        gtk_tree_model_get_iter(gtk_tree_view_get_model(bfwin->bmark), &iter, path);
 
322
                        gtk_tree_model_get(gtk_tree_view_get_model(bfwin->bmark),&iter,1, &retval, -1);
 
323
                        gtk_tree_path_free(path);
 
324
                        DEBUG_MSG("get_current_bmark, returning %p\n",retval);
 
325
                        return retval;
 
326
                }
 
327
        }
 
328
        return NULL;
 
329
}
 
330
/*
 
331
void bmark_name_entry_changed(GtkEntry * entry, GtkDialog * dialog)
 
332
{
 
333
        const gchar *string;
 
334
 
 
335
        string = gtk_entry_get_text(GTK_ENTRY(entry));
 
336
        if (strlen(string) <= 0)
 
337
                gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
 
338
        else
 
339
                gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, TRUE);
 
340
}*/
 
341
 
 
342
void bmark_add_rename_dialog(Tbfwin * bfwin, gchar * dialogtitle)
 
343
{
 
344
        GtkWidget *dlg, *name, *desc, *button, *table, *istemp;
 
345
        gint result;
 
346
/*      GtkTextMark *im;
 
347
        gchar *pstr;
 
348
        GtkTextIter it, sit, eit;*/
 
349
        Tbmark *m = get_current_bmark(bfwin);
 
350
        if (!m) return;
 
351
 
 
352
        dlg =
 
353
                gtk_dialog_new_with_buttons(dialogtitle, GTK_WINDOW(bfwin->main_window), GTK_DIALOG_MODAL,
 
354
                                                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
 
355
        button = gtk_button_new_from_stock(GTK_STOCK_OK);
 
356
        GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
 
357
        gtk_dialog_add_action_widget(GTK_DIALOG(dlg), button, GTK_RESPONSE_OK);
 
358
/*      gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);*/
 
359
        table = gtk_table_new(2, 3, FALSE);
 
360
        gtk_table_set_col_spacings(GTK_TABLE(table), 12);
 
361
        gtk_table_set_row_spacings(GTK_TABLE(table), 6);
 
362
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, FALSE, FALSE, 12);
 
363
 
 
364
        name = entry_with_text(m->name, 200);
 
365
        gtk_entry_set_activates_default(GTK_ENTRY(name), TRUE);
 
366
        bf_mnemonic_label_tad_with_alignment(_("_Name:"), name, 0, 0.5, table, 0, 1, 0, 1);
 
367
        gtk_table_attach_defaults(GTK_TABLE(table), name, 1, 2, 0, 1);
 
368
/*      g_signal_connect(G_OBJECT(name), "changed", G_CALLBACK(bmark_name_entry_changed), dlg);*/
 
369
        desc = entry_with_text(m->description, 200);
 
370
        gtk_entry_set_activates_default(GTK_ENTRY(desc), TRUE);
 
371
        bf_mnemonic_label_tad_with_alignment(_("_Description:"), desc, 0, 0.5, table, 0, 1, 1, 2);
 
372
        gtk_table_attach_defaults(GTK_TABLE(table), desc, 1, 2, 1, 2);
 
373
        istemp = checkbut_with_value(_("Temporary"), m->is_temp);
 
374
        gtk_table_attach_defaults(GTK_TABLE(table), istemp, 0, 2, 2, 3);
 
375
        
 
376
        gtk_window_set_default(GTK_WINDOW(dlg), button);
 
377
 
 
378
        gtk_widget_show_all(dlg);
 
379
        result = gtk_dialog_run(GTK_DIALOG(dlg));
 
380
 
 
381
        if (result == GTK_RESPONSE_OK) {
 
382
                gchar *tmpstr;
 
383
                /* check if name exists */
 
384
/*              if (bmark_name_exists
 
385
                        (DOCUMENT(bfwin->current_document), gtk_entry_get_text(GTK_ENTRY(name)))) {
 
386
                        pstr =
 
387
                                g_strdup_printf(_("You already have a bookmark named %s!"),
 
388
                                                                gtk_entry_get_text(GTK_ENTRY(name)));
 
389
                        if (dialogtype == BMARK_ADD_PERM_DIALOG) {
 
390
                                info_dialog(bfwin->main_window, dialogtitle, pstr);
 
391
                        } else {
 
392
                                info_dialog(bfwin->main_window, dialogtitle, pstr);
 
393
                        }
 
394
                        g_free(pstr);
 
395
                        gtk_widget_destroy(dlg);
 
396
                        bmark_add_rename_dialog(bfwin, dialogtitle, dialogtype);
 
397
                        return;
 
398
                } else */
 
399
/*              if (dialogtype == BMARK_ADD_PERM_DIALOG) {
 
400
                        m = g_new0(Tbmark, 1);
 
401
                        m->doc = DOCUMENT(bfwin->current_document);
 
402
                        if (!m->doc)
 
403
                                return;
 
404
                        im = gtk_text_buffer_get_insert(m->doc->buffer);
 
405
                        gtk_text_buffer_get_iter_at_mark(m->doc->buffer, &it, im);
 
406
                        m->mark =
 
407
                                gtk_text_buffer_create_mark(m->doc->buffer,
 
408
                                                                                        g_strdup(gtk_entry_get_text(GTK_ENTRY(name))), &it,
 
409
                                                                                        TRUE);
 
410
                        m->filepath = g_strdup(m->doc->filename);
 
411
                        m->is_temp = FALSE;
 
412
                        m->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(name)));
 
413
                        m->description = g_strdup(gtk_entry_get_text(GTK_ENTRY(desc)));
 
414
                        sit = eit = it;
 
415
                        gtk_text_iter_forward_to_line_end(&eit);
 
416
                        gtk_text_iter_forward_chars(&sit, 10);
 
417
                        if (!gtk_text_iter_in_range(&sit, &it, &eit))
 
418
                                sit = eit;
 
419
                        m->text = g_strdup(gtk_text_iter_get_slice(&it, &sit));
 
420
 
 
421
                        bmark_get_iter_at_tree_position(bfwin, m);
 
422
                        gtk_tree_store_set(bfwin->bookmarkstore, &m->iter, NAME_COLUMN,
 
423
                                                           g_strdup_printf("[%s] --> %s", gtk_entry_get_text(GTK_ENTRY(name)),
 
424
                                                                                           m->text), PTR_COLUMN, m, -1);
 
425
                        gtk_tree_view_expand_all(bfwin->bmark);
 
426
                        gtk_widget_grab_focus(bfwin->current_document->view);
 
427
                        bmark_store(bfwin, m);
 
428
                } else {*/
 
429
                        g_free(m->name);
 
430
                        m->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(name)));
 
431
                        g_free(m->description);
 
432
                        m->description = g_strdup(gtk_entry_get_text(GTK_ENTRY(desc)));
 
433
                        m->is_temp = GTK_TOGGLE_BUTTON(istemp)->active;
 
434
                        if (m->name && strlen(m->name) > 0) {
 
435
                                tmpstr = g_strconcat(m->name, " - ", m->text,NULL);
 
436
                        } else {
 
437
                                tmpstr = g_strdup(m->text);
 
438
                        }
 
439
                        gtk_tree_store_set(bfwin->bookmarkstore, &m->iter, NAME_COLUMN,
 
440
                                                           tmpstr,-1);
 
441
                        g_free(tmpstr);
 
442
                        if (m->is_temp) {
 
443
                                if (m->strarr) {
 
444
                                        /* hmm previously this was not a temporary bookmark */
 
445
                                        bmark_unstore(bfwin, m);
 
446
                                }
 
447
                        } else {
 
448
                                bmark_store(bfwin, m);
 
449
                        }
 
450
        /*      } */
 
451
        }
 
452
        gtk_widget_destroy(dlg);
 
453
}
 
454
 
 
455
static void bmark_popup_menu_goto_lcb(GtkWidget * widget, gpointer user_data)
 
456
{
 
457
        Tbmark *b;
 
458
        GtkTextIter it;
 
459
 
 
460
        if (!user_data)
 
461
                return;
 
462
        b = get_current_bmark(BFWIN(user_data));
 
463
        if (!b)
 
464
                return;
 
465
        if (b->filepath && !b->doc) {
 
466
                /* check if that document _is_ open */
 
467
                Tdocument *tmpdoc;
 
468
                GList *doclist = return_allwindows_documentlist();
 
469
                tmpdoc = documentlist_return_document_from_filename(doclist, b->filepath);
 
470
                g_list_free(doclist);
 
471
                if (tmpdoc == NULL) {
 
472
                        if (!g_file_test(b->filepath, G_FILE_TEST_EXISTS)) {
 
473
                                gchar *string = g_strdup_printf(_("Could not find the file \"%s\"."), b->filepath);
 
474
                                error_dialog(BFWIN(user_data)->main_window, string,
 
475
                                                         _("This bookmark is set in a file that no longer exists."));
 
476
                                g_free(string);
 
477
                                return;
 
478
                        }
 
479
                        tmpdoc = doc_new_with_file(BFWIN(user_data), b->filepath, FALSE, TRUE);
 
480
                }
 
481
                /* now I have to check all bookmarks */
 
482
                bmark_set_for_doc(tmpdoc);
 
483
        }
 
484
 
 
485
        if (b->doc) {
 
486
                GdkRectangle visirect;
 
487
                GtkTextIter visi_so, visi_eo;
 
488
                gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(b->doc->view),&visirect);
 
489
                gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(b->doc->view), &visi_so, visirect.x, visirect.y);
 
490
                gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(b->doc->view), &visi_eo, visirect.x + visirect.width, visirect.y + visirect.height);
 
491
                
 
492
                gtk_text_buffer_get_iter_at_mark(b->doc->buffer, &it, b->mark);
 
493
                gtk_text_buffer_place_cursor(b->doc->buffer, &it);
 
494
 
 
495
                if (!gtk_text_iter_in_range(&it,&visi_so,&visi_eo)) {
 
496
                        DEBUG_MSG("bmark_popup_menu_goto_lcb, cursor NOT visible!\n");
 
497
                        /* gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(b->doc->view), b->mark); */
 
498
                        gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(b->doc->view),b->mark,0.0,
 
499
                                             TRUE,0.5,0.5);
 
500
                }
 
501
                if (b->doc != BFWIN(user_data)->current_document)
 
502
                        switch_to_document_by_pointer(BFWIN(user_data), b->doc);
 
503
                gtk_widget_grab_focus(b->doc->view);
 
504
        }
 
505
}
 
506
/* 
 
507
 * removes the bookmark from the treestore, and if it is the last remaining bookmark
 
508
 * for the document, it will remove the parent iter (the filename) from the treestore as well
 
509
 */
 
510
static void bmark_check_remove(Tbfwin *bfwin,Tbmark *b) {
 
511
        GtkTreeIter parent;
 
512
        if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(bfwin->bookmarkstore),&parent,&b->iter)) {
 
513
                gint numchild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(bfwin->bookmarkstore), &parent);
 
514
                DEBUG_MSG("bmark_check_remove, the parent of this bookmark has %d children\n", numchild);
 
515
                gtk_tree_store_remove(bfwin->bookmarkstore, &(b->iter));
 
516
                if (numchild == 1) {
 
517
                        gpointer ptr;
 
518
                        DEBUG_MSG("bmark_check_remove, we removed the last child, now remove the parent\n");
 
519
                        gtk_tree_store_remove(bfwin->bookmarkstore,&parent);
 
520
                        /* if the document is open, it should be removed from the hastable as well */
 
521
                        ptr = g_hash_table_lookup(bfwin->bmark_files,b->filepath);
 
522
                        if (ptr) {
 
523
                                DEBUG_MSG("bmark_check_remove, removing iter from hashtable\n");
 
524
                                g_hash_table_remove(bfwin->bmark_files,b->filepath);
 
525
                                g_free(ptr);
 
526
                                if (b->doc) b->doc->bmark_parent = NULL;
 
527
                        }
 
528
                }
 
529
        } else {
 
530
                gchar *name;
 
531
                gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore), &b->iter, NAME_COLUMN,&name, -1);
 
532
                g_print("bmark_check_remove, very weird, bookmark %s for %s does not have a parent ?????\n",name,b->filepath);
 
533
                g_free(name);
 
534
                exit(123);
 
535
        }
 
536
 
 
537
/*      according to the gtk documentation this function is slow and should be used
 
538
        only for testing purposes
 
539
        if ( gtk_tree_store_iter_is_valid(bfwin->bookmarkstore, &(b->iter)) )*/
 
540
/*      DEBUG_MSG("bmark_check_remove, removing bookmark %p from treestore\n",b);
 
541
        gtk_tree_store_remove(bfwin->bookmarkstore, &(b->iter));
 
542
   if (bfwin->bmark_files) {
 
543
                ptr = g_hash_table_lookup(bfwin->bmark_files,b->filepath);
 
544
                if (ptr!=NULL) {
 
545
                        DEBUG_MSG("bmark_check_remove, %s has an entry in the hashtable\n",b->filepath);
 
546
                        if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(bfwin->bookmarkstore), (GtkTreeIter*)ptr)) {
 
547
                                re = TRUE;
 
548
                                DEBUG_MSG("bmark_check_remove, the entry in the hashtable does NOT have a child, re=%d\n", re);
 
549
                        } else {
 
550
                                DEBUG_MSG("bmark_check_remove, the entry in the hashtable does have a child\n");
 
551
                        }
 
552
                }
 
553
        }
 
554
        if (re) {
 
555
        / *if (gtk_tree_store_iter_is_valid(bfwin->bookmarkstore,(GtkTreeIter*)ptr))* /
 
556
                DEBUG_MSG("bmark_check_remove, removing the entry from the treestore\n");
 
557
                gtk_tree_store_remove(bfwin->bookmarkstore,(GtkTreeIter*)ptr);
 
558
                DEBUG_MSG("bmark_check_remove, removing the entry from the hashtable\n");
 
559
                g_hash_table_remove(bfwin->bmark_files,b->filepath);
 
560
                g_free(ptr);
 
561
                if (b->doc) b->doc->bmark_parent = NULL;
 
562
        }*/
 
563
        DEBUG_MSG("bmark_check_remove, finished\n");
 
564
}
 
565
 
 
566
static void bmark_del_children_backend(Tbfwin *bfwin, GtkTreeIter *parent) {
 
567
        GtkTreeIter tmpiter;
 
568
        while (gtk_tree_model_iter_children(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter, parent)) {
 
569
                Tbmark *b;
 
570
                gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter, PTR_COLUMN,&b,-1);
 
571
                if (b) {
 
572
                        DEBUG_MSG("bmark_del_children_backend, found b=%p\n",b);
 
573
                        bmark_check_remove(bfwin,b);
 
574
                        if (!b->is_temp)
 
575
                                bmark_unstore(bfwin, b);
 
576
                        bmark_free(b);
 
577
                } else {
 
578
                        DEBUG_MSG("bmark_del_children_backend, iter without bookmark ??? LOOP WARNING!\n");
 
579
                }
 
580
        }
 
581
}
 
582
 
 
583
 
 
584
static void bmark_popup_menu_deldoc_lcb(GtkWidget * widget, Tbfwin *bfwin) {
 
585
        if (bfwin->bmark) {
 
586
                GtkTreePath *path;
 
587
                GtkTreeViewColumn *col;
 
588
                gtk_tree_view_get_cursor(bfwin->bmark, &path, &col);
 
589
                if (path != NULL) {
 
590
                        gchar *name;
 
591
                        gchar *pstr;
 
592
                        gchar *btns[] = { GTK_STOCK_NO, GTK_STOCK_YES, NULL };
 
593
                        GtkTreeIter iter;
 
594
                        gint depth, ret;
 
595
                        depth = gtk_tree_path_get_depth(path);
 
596
                        if (depth == 2) {
 
597
                                /* go up to parent */
 
598
                                gtk_tree_path_up(path);
 
599
                        } else if (depth != 1) {
 
600
                                g_print("a bug in function bmark_popup_menu_deldoc_lcb()\n");
 
601
#ifdef DEVELOPMENT
 
602
                                exit(124);
 
603
#endif
 
604
                                return;
 
605
                        }
 
606
                        gtk_tree_model_get_iter(gtk_tree_view_get_model(bfwin->bmark), &iter, path);
 
607
                        gtk_tree_path_free(path);
 
608
                        gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore), &iter, NAME_COLUMN,&name, -1);
 
609
                
 
610
                        pstr = g_strdup_printf(_("Do you really want to delete all bookmarks for %s?"), name);
 
611
                        ret =   multi_query_dialog(bfwin->main_window, _("Delete bookmarks?"), pstr,
 
612
                                                           0, 0, btns);
 
613
                        g_free(pstr);
 
614
                        if (ret == 0)
 
615
                                return;
 
616
                        bmark_del_children_backend(bfwin, &iter);
 
617
                }
 
618
        }
 
619
        gtk_widget_grab_focus(bfwin->current_document->view);
 
620
}
 
621
 
 
622
static void bmark_popup_menu_del_lcb(GtkWidget * widget, gpointer user_data)
 
623
{
 
624
        Tbmark *b;
 
625
        gint ret;
 
626
        gchar *pstr;
 
627
        gchar *btns[] = { GTK_STOCK_NO, GTK_STOCK_YES, NULL };
 
628
 
 
629
        if (!user_data)
 
630
                return;
 
631
        b = get_current_bmark(BFWIN(user_data));
 
632
        if (!b)
 
633
                return;
 
634
        /* check if it is temp mark */
 
635
        if (b->is_temp) {
 
636
                /* gtk_tree_store_remove(BFWIN(user_data)->bookmarkstore, &(b->iter)); */
 
637
                bmark_check_remove(BFWIN(user_data),b); /* check  if we should remove a filename too */ 
 
638
                /* bmark_unstore(BFWIN(user_data), b); */
 
639
                bmark_free(b);
 
640
        } else {
 
641
                pstr = g_strdup_printf(_("Do you really want to delete %s?"), b->name);
 
642
                ret =
 
643
                        multi_query_dialog(BFWIN(user_data)->main_window, _("Delete permanent bookmark."), pstr,
 
644
                                                           0, 0, btns);
 
645
                g_free(pstr);
 
646
                if (ret == 0)
 
647
                        return;
 
648
                bmark_check_remove(BFWIN(user_data),b); /* check  if we should remove a filename too */ 
 
649
                bmark_unstore(BFWIN(user_data), b);
 
650
                bmark_free(b);
 
651
                
 
652
        }
 
653
        gtk_widget_grab_focus(BFWIN(user_data)->current_document->view);
 
654
}
 
655
 
 
656
static void bmark_popup_menu_rename_lcb(GtkWidget * widget, Tbfwin * bfwin)
 
657
{
 
658
        Tbmark *m = get_current_bmark(bfwin);
 
659
        if (!m) return;
 
660
        bmark_add_rename_dialog(bfwin, _("Edit bookmark"));
 
661
}
 
662
 
 
663
static void bmark_popup_menu_delall_lcb(GtkWidget * widget, Tbfwin * bfwin)
 
664
{
 
665
        bmark_del_all(bfwin,TRUE);
 
666
}
 
667
 
 
668
 
 
669
static GtkWidget *bmark_popup_menu(Tbfwin * bfwin, gboolean show_bmark_specific, gboolean show_file_specific) {
 
670
        GtkWidget *menu, *menu_item;
 
671
 
 
672
        menu = gtk_menu_new();
 
673
        if (show_bmark_specific) {
 
674
                menu_item = gtk_menu_item_new_with_label(_("Goto bookmark"));
 
675
                g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(bmark_popup_menu_goto_lcb),
 
676
                                                 bfwin);
 
677
                gtk_menu_append(GTK_MENU(menu), menu_item);
 
678
        
 
679
                menu_item = gtk_separator_menu_item_new();
 
680
                gtk_menu_append(GTK_MENU(menu), menu_item);
 
681
        
 
682
                menu_item = gtk_menu_item_new_with_label(_("Edit"));
 
683
                g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(bmark_popup_menu_rename_lcb),
 
684
                                                 bfwin);
 
685
                gtk_menu_append(GTK_MENU(menu), menu_item);
 
686
                menu_item = gtk_menu_item_new_with_label(_("Delete"));
 
687
                g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(bmark_popup_menu_del_lcb),
 
688
                                                 bfwin);
 
689
                gtk_menu_append(GTK_MENU(menu), menu_item);
 
690
        }
 
691
        if (show_file_specific) {
 
692
                menu_item = gtk_menu_item_new_with_label(_("Delete all in document"));
 
693
                g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(bmark_popup_menu_deldoc_lcb),
 
694
                                                 bfwin);
 
695
                gtk_menu_append(GTK_MENU(menu), menu_item);
 
696
        }
 
697
        menu_item = gtk_menu_item_new_with_label(_("Delete all"));
 
698
        g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(bmark_popup_menu_delall_lcb),
 
699
                                         bfwin);
 
700
        gtk_menu_append(GTK_MENU(menu), menu_item);
 
701
 
 
702
        gtk_widget_show_all(menu);
 
703
        g_signal_connect_after(G_OBJECT(menu), "destroy", G_CALLBACK(destroy_disposable_menu_cb), menu);
 
704
 
 
705
        return menu;
 
706
}
 
707
 
 
708
 
 
709
/* right mouse click */
 
710
static gboolean bmark_event_mouseclick(GtkWidget * widget, GdkEventButton * event, Tbfwin * bfwin) {
 
711
        GtkTreePath *path;
 
712
        gboolean show_bmark_specific = FALSE, show_file_specific = FALSE;
 
713
        if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(bfwin->bmark), event->x, event->y, &path, NULL, NULL, NULL)) {
 
714
                if (path) {
 
715
                        gint depth = gtk_tree_path_get_depth(path);
 
716
                        gtk_tree_path_free(path);
 
717
                        if (depth==2) {
 
718
                                show_bmark_specific = TRUE;
 
719
                                show_file_specific = TRUE;
 
720
                                if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {   /* double click  */
 
721
                                        bmark_popup_menu_goto_lcb(NULL, bfwin);
 
722
                                        return TRUE;
 
723
                                }
 
724
                        } else if (depth == 1) {
 
725
                                show_file_specific = TRUE;
 
726
                        }
 
727
                }
 
728
        }
 
729
        if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {    /* right mouse click */
 
730
                gtk_menu_popup(GTK_MENU(bmark_popup_menu(bfwin, show_bmark_specific, show_file_specific)), NULL, NULL, NULL, NULL,
 
731
                                   event->button, event->time);
 
732
        }
 
733
        return FALSE;
 
734
}
 
735
 
 
736
/* Initialize bookmarks gui for window */
 
737
 
 
738
GtkWidget *bmark_gui(Tbfwin * bfwin)
 
739
{
 
740
        GtkWidget *vbox, *scroll;
 
741
        GtkCellRenderer *cell;
 
742
        GtkTreeViewColumn *column;
 
743
        DEBUG_MSG("bmark_gui, building gui for bfwin=%p\n",bfwin);
 
744
        /* Tree Store is in bfwin->bookmarkstore 
 
745
           Tree View is in bfwin->bmark 
 
746
         */
 
747
        vbox = gtk_vbox_new(FALSE, 1);
 
748
        bfwin->bmark = gtk_tree_view_new_with_model(GTK_TREE_MODEL(bfwin->bookmarkstore));
 
749
        cell = gtk_cell_renderer_text_new();
 
750
        column = gtk_tree_view_column_new_with_attributes("", cell, "text", NAME_COLUMN, NULL);
 
751
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 
752
        gtk_tree_view_append_column(GTK_TREE_VIEW(bfwin->bmark), column);
 
753
        gtk_widget_show_all(bfwin->bmark);
 
754
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(bfwin->bmark), FALSE);
 
755
        /*gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(bfwin->bmark), TRUE);*/
 
756
        scroll = gtk_scrolled_window_new(NULL, NULL);
 
757
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
 
758
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), bfwin->bmark);
 
759
        gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
 
760
        g_signal_connect(G_OBJECT(bfwin->bmark), "button-press-event",
 
761
                                         G_CALLBACK(bmark_event_mouseclick), bfwin);
 
762
        gtk_tree_view_expand_all(bfwin->bmark);
 
763
        return vbox;
 
764
}
 
765
 
 
766
 
 
767
/**
 
768
 * bmark_get_iter_at_tree_position:
 
769
 *
 
770
 * determine bookmark's location in the tree and  insert - result GtkTreeIter is stored in m->iter 
 
771
 */
 
772
static void bmark_get_iter_at_tree_position(Tbfwin * bfwin, Tbmark * m) {
 
773
        GtkTreeIter *parent;
 
774
        gpointer ptr;
 
775
        DEBUG_MSG("bmark_get_iter_at_tree_position, started for filepath=%s\n",m->filepath);
 
776
        if (!bfwin->bmark_files) {
 
777
                DEBUG_MSG("bmark_get_iter_at_tree_position, creating hashtable for bfwin=%p\n",bfwin);
 
778
                bfwin->bmark_files = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
779
        }
 
780
        ptr = g_hash_table_lookup(bfwin->bmark_files, m->filepath);
 
781
        if (ptr == NULL) {                      /* closed document or bookmarks never set */
 
782
                gchar *title = NULL;
 
783
                parent = g_new0(GtkTreeIter, 1);
 
784
                gtk_tree_store_append(bfwin->bookmarkstore, parent, NULL);
 
785
                switch (main_v->props.bookmarks_filename_mode) {
 
786
                case BM_FMODE_FULL:
 
787
                        g_strdup(m->filepath);
 
788
                        break;
 
789
                case BM_FMODE_HOME:     /* todo */
 
790
                        if (bfwin->project != NULL && bfwin->project->basedir && strlen(bfwin->project->basedir)) {
 
791
                                gint baselen = strlen(bfwin->project->basedir);
 
792
                                if (strncmp(m->filepath, bfwin->project->basedir, baselen)==0) {
 
793
                                        title = g_strdup(m->filepath + baselen);
 
794
                                }
 
795
                        }
 
796
                        break;
 
797
/*              case BM_FMODE_FILE:
 
798
                        title = g_path_get_basename(m->filepath);
 
799
                        break;*/
 
800
                }
 
801
                if (title == NULL) {
 
802
                        title = g_path_get_basename(m->filepath);
 
803
                }
 
804
                gtk_tree_store_set(bfwin->bookmarkstore, parent, NAME_COLUMN, title, PTR_COLUMN, m->doc, -1);
 
805
                g_free (title);
 
806
                  
 
807
                if (m->doc != NULL) {
 
808
                        DEBUG_MSG("bmark_get_iter_at_tree_position, setting parent iter %p for doc%p\n",parent,m->doc);
 
809
                        m->doc->bmark_parent = parent;
 
810
                }
 
811
                DEBUG_MSG("bmark_get_iter_at_tree_position, appending parent %p in hashtable for filepath=%s\n",parent, m->filepath);
 
812
                /* the hash table frees the key, but not the value, on destroy */
 
813
                g_hash_table_insert(bfwin->bmark_files, g_strdup(m->filepath), parent);
 
814
        } else
 
815
                parent = (GtkTreeIter *) ptr;
 
816
 
 
817
        {
 
818
                Tbmark *bef = bmark_find_bookmark_before_offset(bfwin, m->offset, parent);
 
819
                if (bef == NULL) {
 
820
                        gtk_tree_store_prepend(bfwin->bookmarkstore, &m->iter, parent);
 
821
                        return;
 
822
                } else {
 
823
                        gtk_tree_store_insert_after(GTK_TREE_STORE(bfwin->bookmarkstore),&m->iter,parent,&bef->iter);
 
824
                        return;
 
825
                }
 
826
        }
 
827
}
 
828
 
 
829
/*
 
830
because we don't store them in a hashtable anymore, it's no problem to have 
 
831
bookmarks with the same name
 
832
static gboolean bmark_name_exists(Tdocument * doc, const gchar * name)
 
833
{
 
834
        GtkTreeIter tmpiter;
 
835
        gboolean cont;
 
836
 
 
837
        if (doc->bmark_parent == NULL)
 
838
                return FALSE;
 
839
        cont =
 
840
                gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter,
 
841
                                                                         doc->bmark_parent);
 
842
        while (cont) {
 
843
                Tbmark *mark = NULL;
 
844
                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN,
 
845
                                                   &mark, -1);
 
846
                if (mark) {
 
847
                        if (strcmp(mark->name, name) == 0)
 
848
                                return TRUE;
 
849
                }
 
850
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter);
 
851
        }                                                       
 
852
        return FALSE;
 
853
}
 
854
*/
 
855
 
 
856
/*
 
857
 * this function should create the global
 
858
 * main_v->bookmarkstore
 
859
 */
 
860
void bmark_init()
 
861
{
 
862
        main_v->bookmarkstore = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
 
863
        DEBUG_MSG("bmark_init, created main_v->bookmarkstore at %p\n", main_v->bookmarkstore);
 
864
        main_v->bmarkdata = g_new0(Tbmarkdata, 1);
 
865
}
 
866
 
 
867
 
 
868
/* this function will load the bookmarks
 
869
 * from bfwin->session->bmarks and parse
 
870
 * them into treestore bfwin->bookmarkstore
 
871
 *
 
872
 * this function should ALSO check all dcouments that are
 
873
 * opened (bfwin->documentlist) if they have bookmarks !!
 
874
 */
 
875
void bmark_reload(Tbfwin * bfwin)
 
876
{
 
877
        GList *tmplist = g_list_first(bfwin->session->bmarks);
 
878
        DEBUG_MSG("bmark_reload for bfwin %p\n",bfwin);
 
879
        if (bfwin->bmark_files != NULL)
 
880
                g_hash_table_destroy(bfwin->bmark_files);
 
881
        bfwin->bmark_files = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
882
        while (tmplist) {
 
883
                gchar **items = (gchar **) tmplist->data;
 
884
                if (items && count_array(items) == 6) {
 
885
                        gchar *ptr;
 
886
                        Tbmark *b;
 
887
                        b = g_new0(Tbmark, 1);
 
888
                        b->name = g_strdup(items[0]);
 
889
                        b->description = g_strdup(items[1]);
 
890
                        b->filepath = g_strdup(items[2]);
 
891
                        b->offset = atoi(items[3]);
 
892
                        b->text = g_strdup(items[4]);
 
893
                        b->len = atoi(items[5]);
 
894
                        b->strarr = items;
 
895
                        bmark_get_iter_at_tree_position(bfwin, b);
 
896
                        if (b->name && strlen(b->name)>0) {
 
897
                                ptr = g_strconcat(b->name, " - ", b->text, NULL);
 
898
                        } else {
 
899
                                ptr = g_strdup(b->text);
 
900
                        }
 
901
                        gtk_tree_store_set(bfwin->bookmarkstore, &(b->iter), NAME_COLUMN, ptr, PTR_COLUMN, b,
 
902
                                                           -1);
 
903
                        g_free(ptr);
 
904
                }
 
905
                tmplist = g_list_next(tmplist);
 
906
        }
 
907
        
 
908
        tmplist = g_list_first(bfwin->documentlist);
 
909
        while (tmplist) {
 
910
                DEBUG_MSG("bmark_reload, calling bmark_set_for_doc for doc=%p\n",tmplist->data);
 
911
                bmark_set_for_doc(DOCUMENT(tmplist->data));
 
912
                bmark_check_length(bfwin, DOCUMENT(tmplist->data));
 
913
                tmplist = g_list_next(tmplist);
 
914
        }
 
915
}
 
916
 
 
917
/*
 
918
 * this function will simply call
 
919
 * gtk_tree_view_set_model() to connect the treeview
 
920
 * to the new treestore, used in unloading and
 
921
 * loading of projects
 
922
 */
 
923
void bmark_set_store(Tbfwin * bfwin) {
 
924
        DEBUG_MSG("bmark_set_store set store %p for bfwin %p\n",bfwin->bookmarkstore,bfwin);
 
925
        if (bfwin->bookmarkstore && bfwin->bmark) {
 
926
                gtk_tree_view_set_model(bfwin->bmark, GTK_TREE_MODEL(bfwin->bookmarkstore));
 
927
        }
 
928
}
 
929
 
 
930
void bmark_clean_for_doc(Tdocument * doc) {
 
931
        GtkTreeIter tmpiter;
 
932
        gboolean cont;
 
933
 
 
934
        if (doc->bmark_parent == NULL)
 
935
                return;
 
936
        DEBUG_MSG("bmark_clean_for_doc, getting children for parent_iter=%p\n",doc->bmark_parent);
 
937
        cont =
 
938
                gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter,
 
939
                                                                         doc->bmark_parent);
 
940
        while (cont) {
 
941
                Tbmark *b = NULL;
 
942
                DEBUG_MSG("bmark_clean_for_doc, getting bookmark for first child\n");
 
943
                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN,
 
944
                                                   &b, -1);
 
945
                if (b) {
 
946
                        bmark_update_offset_from_textmark(b);
 
947
                        DEBUG_MSG("bmark_clean_for_doc, bookmark=%p, new offset=%d, now deleting GtkTextMark from TextBuffer\n",b,b->offset);
 
948
                        gtk_text_buffer_delete_mark(doc->buffer, b->mark);
 
949
                        b->mark = NULL;
 
950
                        b->doc = NULL;
 
951
                        if (!b->is_temp) {
 
952
                                bmark_store(doc->bfwin, b);
 
953
                        }
 
954
                }
 
955
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter);
 
956
        }                                                       /* cont */
 
957
        /* now unset the Tdocument* in the second column */
 
958
        DEBUG_MSG("bmark_clean_for_doc, unsetting and freeing parent_iter %p for doc %p\n",doc->bmark_parent,doc);
 
959
        gtk_tree_store_set(GTK_TREE_STORE(BFWIN(doc->bfwin)->bookmarkstore), doc->bmark_parent, PTR_COLUMN, NULL, -1);
 
960
        /* remove the pointer from the hastable */
 
961
        g_hash_table_remove(BFWIN(doc->bfwin)->bmark_files,doc->filename);
 
962
        g_free(doc->bmark_parent);
 
963
        doc->bmark_parent = NULL;
 
964
}
 
965
 
 
966
/*
 
967
 * this function will check is this document needs any bookmarks, and set the
 
968
 * doc->bmark_parent if needed
 
969
 */
 
970
void bmark_set_for_doc(Tdocument * doc) {
 
971
        GtkTreeIter tmpiter;
 
972
        GtkTextIter it;
 
973
        gboolean cont;
 
974
        if (!doc->filename) {
 
975
                DEBUG_MSG("bmark_set_for_doc, document %p does not have a filename, returning\n", doc);
 
976
                return;
 
977
        }
 
978
        DEBUG_MSG("bmark_set_for_doc, doc=%p, filename=%s\n",doc,doc->filename);
 
979
/*      if (!BFWIN(doc->bfwin)->bmark) {
 
980
                DEBUG_MSG("bmark_set_for_doc, no leftpanel, not implemented yet!!\n");
 
981
                return;
 
982
        }*/
 
983
        if (doc->bmark_parent) {
 
984
                DEBUG_MSG("this document (%p) already has a bmark_parent (%p) why is this function called?\n",doc,doc->bmark_parent);
 
985
                return;
 
986
        }
 
987
        
 
988
        cont =
 
989
                gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter,
 
990
                                                                         NULL);
 
991
        while (cont) {
 
992
                GtkTreeIter child;
 
993
                if (gtk_tree_model_iter_children
 
994
                        (GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &child, &tmpiter)) {
 
995
                        Tbmark *mark = NULL;
 
996
                        gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &child, PTR_COLUMN,
 
997
                                                           &mark, -1);
 
998
                        if (mark) {
 
999
                                if (strcmp(mark->filepath, doc->filename) == 0) {       /* this is it */
 
1000
                                        gboolean cont2;
 
1001
                                        DEBUG_MSG("bmark_set_for_doc, we found a bookmark for document %s at offset=%d!\n",doc->filename,mark->offset);
 
1002
                                        /* we will now first set the Tdocument * into the second column of the parent */
 
1003
                                        gtk_tree_store_set(GTK_TREE_STORE(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN, doc, -1);
 
1004
                                        
 
1005
                                        mark->doc = doc;
 
1006
                                        gtk_text_buffer_get_iter_at_offset(doc->buffer, &it, mark->offset);
 
1007
                                        mark->mark = gtk_text_buffer_create_mark(doc->buffer, NULL, &it, TRUE);
 
1008
                                        cont2 =
 
1009
                                                gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore),
 
1010
                                                                                                 &child);
 
1011
                                        while (cont2) {
 
1012
                                                mark = NULL;
 
1013
                                                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &child,
 
1014
                                                                                   PTR_COLUMN, &mark, -1);
 
1015
                                                if (mark) {
 
1016
                                                        mark->doc = doc;
 
1017
                                                        DEBUG_MSG("bmark_set_for_doc, next bookmark at offset=%d!\n",mark->offset);
 
1018
                                                        gtk_text_buffer_get_iter_at_offset(doc->buffer, &it, mark->offset);
 
1019
                                                        mark->mark =
 
1020
                                                                gtk_text_buffer_create_mark(doc->buffer, NULL, &it, TRUE);
 
1021
                                                }
 
1022
                                                cont2 =
 
1023
                                                        gtk_tree_model_iter_next(GTK_TREE_MODEL
 
1024
                                                                                                         (BFWIN(doc->bfwin)->bookmarkstore), &child);
 
1025
                                        }
 
1026
                                        doc->bmark_parent = g_memdup(&tmpiter, sizeof(GtkTreeIter));
 
1027
                                        DEBUG_MSG("bmark_set_for_doc, added parent_iter %p to doc %p\n",doc->bmark_parent,doc);
 
1028
                                        return;
 
1029
                                }
 
1030
                        }
 
1031
                }
 
1032
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter);
 
1033
        }                                                       /* cont */
 
1034
        DEBUG_MSG("bmark_set_for_doc, no bookmarks found for document %s\n", doc->filename);
 
1035
}
 
1036
 
 
1037
/**
 
1038
 * bmark_get_bookmarked_lines:
 
1039
 * @doc: Tdocument *
 
1040
 * @ fromit: GtkTextIter *
 
1041
 * @ toit: GtkTextIter *
 
1042
 *
 
1043
 * this function returns a hash table with all bookmarks between fromit and toit
 
1044
 *
 
1045
 * this function is called VERY OFTEN (might be 20X per second!!!!) by document.c
 
1046
 * to redraw the bookmarks at the sides
 
1047
 * so we obviously need to keep this function VERY FAST 
 
1048
 *
 
1049
 * the function will return NULL if no bookmarks for this document are 
 
1050
 * known (this is faster then looking in an empty hash table)
 
1051
 *
 
1052
 * Return value: #GHashTable * pointer or NULL
 
1053
 */
 
1054
GHashTable *bmark_get_bookmarked_lines(Tdocument * doc, GtkTextIter *fromit, GtkTextIter *toit) {
 
1055
        if (doc->bmark_parent) {
 
1056
                gboolean cont = TRUE;
 
1057
                guint offset;
 
1058
                Tbmark *mark;
 
1059
                GtkTreeIter tmpiter;
 
1060
 
 
1061
                GHashTable *ret = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
 
1062
 
 
1063
                /* because the bookmarks are sorted by line number, we don't have to scan trough all 
 
1064
                bookmarks, we can start at the bookmark *before* fromit, and continue until the 
 
1065
                first bookmark > toit */
 
1066
                offset = gtk_text_iter_get_offset(fromit);
 
1067
                mark = bmark_find_bookmark_before_offset(BFWIN(doc->bfwin), offset, doc->bmark_parent);
 
1068
                if (mark) {
 
1069
                        tmpiter = mark->iter;
 
1070
                } else {
 
1071
                        cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), 
 
1072
                                                                        &tmpiter, doc->bmark_parent);
 
1073
                }
 
1074
                
 
1075
                while (cont) {
 
1076
                        Tbmark *mark;
 
1077
                        gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN,
 
1078
                                                           &mark, -1);
 
1079
                        if (mark && mark->mark) {
 
1080
                                GtkTextIter it;
 
1081
                                gint *iaux;
 
1082
                                gtk_text_buffer_get_iter_at_mark(doc->buffer, &it, mark->mark);
 
1083
                                if (gtk_text_iter_compare(toit,&it) < 0) {
 
1084
                                        break;
 
1085
                                } else if (gtk_text_iter_compare(fromit,&it) < 0) {
 
1086
                                        iaux = g_new(gint, 1);
 
1087
                                        *iaux = gtk_text_iter_get_line(&it);
 
1088
                                        g_hash_table_insert(ret, iaux, g_strdup(mark->is_temp ? "1" : "0"));
 
1089
                                }
 
1090
                        }
 
1091
                        cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter);
 
1092
                } /* cont */
 
1093
                return ret;
 
1094
        }
 
1095
        return NULL;
 
1096
}
 
1097
 
 
1098
/* this function will simply add the bookmark as defined in the arguments
 
1099
 *
 
1100
 * will use offset if itoffset is NULL
 
1101
 * will use itoffset if not NULL
 
1102
 */
 
1103
static void bmark_add_backend(Tdocument *doc, GtkTextIter *itoffset, gint offset, const gchar *name, const gchar *text, gboolean is_temp) {
 
1104
        Tbmark *m;
 
1105
        gchar *displaytext = NULL;
 
1106
        GtkTextIter it;
 
1107
        m = g_new0(Tbmark, 1);
 
1108
        m->doc = doc;
 
1109
        
 
1110
        if (itoffset) {
 
1111
                it = *itoffset;
 
1112
                m->offset = gtk_text_iter_get_offset(&it);
 
1113
        } else {
 
1114
                gtk_text_buffer_get_iter_at_offset(doc->buffer,&it,offset);
 
1115
                m->offset = offset;
 
1116
        }
 
1117
        
 
1118
        m->mark = gtk_text_buffer_create_mark(doc->buffer, NULL, &it, TRUE);
 
1119
        m->filepath = g_strdup(doc->filename);
 
1120
        m->is_temp = is_temp;
 
1121
        m->text = g_strdup(text);
 
1122
        m->name = (name) ? g_strdup(name) : g_strdup("");
 
1123
        m->description = g_strdup("");
 
1124
        
 
1125
        /* insert into tree */
 
1126
        bmark_get_iter_at_tree_position(doc->bfwin, m);
 
1127
        displaytext = bmark_display_text(m->name, m->text);
 
1128
        gtk_tree_store_set(BFWIN(doc->bfwin)->bookmarkstore, &m->iter, NAME_COLUMN, displaytext, PTR_COLUMN, m, -1);
 
1129
        g_free (displaytext);
 
1130
        
 
1131
        /* and store */
 
1132
        if (!m->is_temp) {
 
1133
                bmark_store(BFWIN(doc->bfwin), m);
 
1134
        }       
 
1135
}
 
1136
 
 
1137
/**
 
1138
 * bmark_text_for_offset:
 
1139
 *
 
1140
 * will use offset if itoffset is NULL
 
1141
 * will use itoffset if not NULL
 
1142
 */
 
1143
static gchar *bmark_text_for_offset(Tdocument *doc, GtkTextIter *itoffset, gint offset) {
 
1144
        GtkTextIter it, eit, sit;
 
1145
        if (itoffset) {
 
1146
                it = *itoffset;
 
1147
        } else {
 
1148
                gtk_text_buffer_get_iter_at_offset(doc->buffer,&it,offset);
 
1149
        }
 
1150
        sit = eit = it;
 
1151
        gtk_text_iter_forward_to_line_end(&eit);
 
1152
        gtk_text_iter_forward_chars(&sit, BMARK_SHOW_NUM_TEXT_CHARS);
 
1153
        if (!gtk_text_iter_in_range(&sit, &it, &eit))
 
1154
                sit = eit;
 
1155
#ifdef DEBUG
 
1156
        {
 
1157
                gchar *tmp = gtk_text_iter_get_text(&it, &sit);
 
1158
                DEBUG_MSG("bmark_text_for_offset, text=%s\n",tmp);
 
1159
                g_free(tmp);
 
1160
        }
 
1161
#endif
 
1162
        return gtk_text_iter_get_text(&it, &sit);
 
1163
}
 
1164
 
 
1165
/* this function will add a bookmark to the current document at current cursor / selection */
 
1166
static void bmark_add_current_doc_backend(Tbfwin *bfwin, const gchar *name, gint offset, gboolean is_temp) {
 
1167
        GtkTextIter it, eit, sit;
 
1168
        DEBUG_MSG("bmark_add_backend, adding bookmark at offset=%d for bfwin=%p\n",offset,bfwin);
 
1169
        /* create bookmark */
 
1170
        gtk_text_buffer_get_iter_at_offset(DOCUMENT(bfwin->current_document)->buffer,&it,offset);
 
1171
        /* if there is a selection, and the offset is within the selection, we'll use it as text content */
 
1172
        if (gtk_text_buffer_get_selection_bounds(DOCUMENT(bfwin->current_document)->buffer,&sit,&eit) 
 
1173
                                && gtk_text_iter_in_range(&it,&sit,&eit)) {
 
1174
                gchar *text = gtk_text_iter_get_text(&sit, &eit);
 
1175
                bmark_add_backend(DOCUMENT(bfwin->current_document), &sit, offset, name, text, is_temp);
 
1176
                g_free(text);
 
1177
                
 
1178
        } else {
 
1179
                gchar *text;
 
1180
                text = bmark_text_for_offset(DOCUMENT(bfwin->current_document), &it, offset);
 
1181
                bmark_add_backend(DOCUMENT(bfwin->current_document), &it, offset, name, text, is_temp);
 
1182
                g_free(text);
 
1183
        }
 
1184
        if (bfwin->bmark) {
 
1185
                /* only if there is a left panel we should do this */
 
1186
                gtk_tree_view_expand_all(bfwin->bmark);
 
1187
                gtk_widget_grab_focus(bfwin->current_document->view);
 
1188
        }
 
1189
}
 
1190
 
 
1191
/* 
 
1192
can we make this function faster? when adding bookmarks from a search this function uses
 
1193
a lot of time, perhaps that can be improved
 
1194
*/
 
1195
static Tbmark *bmark_get_bmark_at_line(Tdocument *doc, gint offset) {
 
1196
        GtkTextIter sit, eit;
 
1197
        GtkTreeIter tmpiter;
 
1198
        gint linenum;
 
1199
        gtk_text_buffer_get_iter_at_offset(doc->buffer,&sit,offset);
 
1200
        linenum = gtk_text_iter_get_line(&sit);
 
1201
        eit = sit;
 
1202
        gtk_text_iter_set_line_offset(&sit, 0);
 
1203
        gtk_text_iter_forward_to_line_end(&eit);
 
1204
#ifdef DEBUG
 
1205
        {
 
1206
                gchar *tmp = gtk_text_buffer_get_text(doc->buffer, &sit,&eit,FALSE);
 
1207
                DEBUG_MSG("bmark_get_bmark_at_line, searching bookmarks at line %d between offsets %d - %d --> '%s'\n",linenum,gtk_text_iter_get_offset(&sit),gtk_text_iter_get_offset(&eit),tmp);
 
1208
                g_free(tmp);
 
1209
        }
 
1210
#endif
 
1211
        /* check for existing bookmark in this place */
 
1212
        if (DOCUMENT(doc)->bmark_parent) {
 
1213
                GtkTextIter testit;
 
1214
                Tbmark *m, *m2;
 
1215
                m = bmark_find_bookmark_before_offset(BFWIN(doc->bfwin), offset, doc->bmark_parent);
 
1216
                if (m == NULL) {
 
1217
                        DEBUG_MSG("bmark_get_bmark_at_line, m=NULL, get first child\n");
 
1218
                        if (gtk_tree_model_iter_children(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter,doc->bmark_parent)) {
 
1219
                                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN, &m2, -1);
 
1220
                                gtk_text_buffer_get_iter_at_mark(doc->buffer, &testit,m2->mark);
 
1221
                                if (gtk_text_iter_get_line(&testit) == linenum) {
 
1222
                                        return m2;
 
1223
                                }
 
1224
                        }
 
1225
                } else {
 
1226
                        gtk_text_buffer_get_iter_at_mark(doc->buffer, &testit,m->mark);
 
1227
                        DEBUG_MSG("bmark_get_bmark_at_line, m=%p, has linenum=%d\n",m,gtk_text_iter_get_line(&testit));
 
1228
                        if (gtk_text_iter_get_line(&testit) == linenum) {
 
1229
                                return m;
 
1230
                        }
 
1231
                        tmpiter = m->iter;
 
1232
                        if (gtk_tree_model_iter_next(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore),&tmpiter)) {
 
1233
                                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN, &m2, -1);
 
1234
                                gtk_text_buffer_get_iter_at_mark(doc->buffer, &testit,m2->mark);
 
1235
                                if (gtk_text_iter_get_line(&testit) == linenum) {
 
1236
                                                return m2;
 
1237
                                }
 
1238
                        }
 
1239
                }
 
1240
                DEBUG_MSG("bmark_get_bmark_at_line, nothing found at this line, return NULL\n");
 
1241
                return NULL;
 
1242
 
 
1243
        }
 
1244
        DEBUG_MSG("bmark_get_bmark_at_line, no existing bookmark found, return NULL\n");
 
1245
        return NULL;
 
1246
}
 
1247
 
 
1248
/**
 
1249
 * bmark_add_extern
 
1250
 * @doc: a #Tdocument* with the document
 
1251
 * @offset: the character position where to set the bookmark
 
1252
 * @name: a name to set for the bookmark, or NULL for no name
 
1253
 * @text: the text for the bookmark, or NULL to have it set automatically
 
1254
 *
 
1255
 * Code in bluefish that want to set a bookmark, not related to 
 
1256
 * the cursor location or a mouse position should use
 
1257
 * this function.
 
1258
 */
 
1259
void bmark_add_extern(Tdocument *doc, gint offset, const gchar *name, const gchar *text, gboolean is_temp) {
 
1260
        DEBUG_MSG("adding bookmark at offset %d with name %s\n",offset,name); /* dummy */
 
1261
        if (!bmark_get_bmark_at_line(doc, offset)) {
 
1262
                if (text) {
 
1263
                        bmark_add_backend(doc, NULL, offset, (name) ? name : "", text, is_temp);
 
1264
                } else {
 
1265
                        gchar *tmp = bmark_text_for_offset(doc, NULL, offset);
 
1266
                        bmark_add_backend(doc, NULL, offset, (name) ? name : "", tmp, is_temp);
 
1267
                        g_free(tmp);
 
1268
                }
 
1269
        }
 
1270
}
 
1271
 
 
1272
void bmark_add(Tbfwin * bfwin) {
 
1273
        GtkTextMark *im;
 
1274
        GtkTextIter it;
 
1275
        gint offset;
 
1276
        /* check for unnamed document */
 
1277
        if (!DOCUMENT(bfwin->current_document)->filename) {
 
1278
                error_dialog(bfwin->main_window, _("Add bookmark"),
 
1279
                                         _("Cannot add bookmarks in unnamed files."));
 
1280
                                         /*\nPlease save the file first. A Save button in this dialog would be cool -- Alastair*/
 
1281
                return;
 
1282
        }
 
1283
        /* if the left panel is disabled, we simply should add the bookmark to the list, and do nothing else */
 
1284
/*      if (bfwin->bmark == NULL) {
 
1285
                DEBUG_MSG("no left panel, this is not implemented yet\n");
 
1286
        } else */ {
 
1287
                gboolean has_mark;
 
1288
                im = gtk_text_buffer_get_insert(DOCUMENT(bfwin->current_document)->buffer);
 
1289
                gtk_text_buffer_get_iter_at_mark(DOCUMENT(bfwin->current_document)->buffer, &it, im);
 
1290
                offset = gtk_text_iter_get_offset(&it);
 
1291
        
 
1292
                /* check for existing bookmark in this place */
 
1293
                has_mark = (bmark_get_bmark_at_line(DOCUMENT(bfwin->current_document), offset) != NULL);
 
1294
                if (has_mark) {
 
1295
                        info_dialog(bfwin->main_window, _("Add bookmark"),
 
1296
                                                _("You already have a bookmark here!"));
 
1297
                        return;
 
1298
                }
 
1299
                bmark_add_current_doc_backend(bfwin, "", offset, !main_v->props.bookmarks_default_store);
 
1300
        }
 
1301
}
 
1302
 
 
1303
gboolean bmark_have_bookmark_at_stored_bevent(Tdocument * doc) {
 
1304
        if (BMARKDATA(main_v->bmarkdata)->bevent_doc == doc) {
 
1305
                return (bmark_get_bmark_at_line(doc, BMARKDATA(main_v->bmarkdata)->bevent_charoffset) != NULL);
 
1306
        }
 
1307
        return FALSE;
 
1308
}
 
1309
 
 
1310
void bmark_store_bevent_location(Tdocument * doc, gint charoffset) {
 
1311
        DEBUG_MSG("bmark_store_bevent_location, storing offset=%d for doc=%p\n",charoffset,doc);
 
1312
        BMARKDATA(main_v->bmarkdata)->bevent_doc = doc;
 
1313
        BMARKDATA(main_v->bmarkdata)->bevent_charoffset = charoffset;
 
1314
}
 
1315
 
 
1316
void bmark_del_at_bevent(Tdocument *doc) {
 
1317
        if (BMARKDATA(main_v->bmarkdata)->bevent_doc == doc) {
 
1318
                Tbmark *b = bmark_get_bmark_at_line(doc, BMARKDATA(main_v->bmarkdata)->bevent_charoffset);
 
1319
                if (b) {
 
1320
                        DEBUG_MSG("bmark_del_at_bevent, deleting bookmark %p\n",b);
 
1321
                        bmark_check_remove(BFWIN(doc->bfwin),b); /* check  if we should remove a filename too */        
 
1322
                        bmark_unstore(BFWIN(doc->bfwin), b);
 
1323
                        bmark_free(b);          
 
1324
                }
 
1325
        }
 
1326
}
 
1327
 
 
1328
void bmark_add_at_bevent(Tdocument *doc) {
 
1329
                /* check for unnamed document */
 
1330
        if (!doc->filename) {
 
1331
                error_dialog(BFWIN(doc->bfwin)->main_window, _("Add bookmark"),
 
1332
                                         _("Cannot add bookmarks in unnamed files."));
 
1333
                return;
 
1334
        }
 
1335
        if (BMARKDATA(main_v->bmarkdata)->bevent_doc == doc) {
 
1336
                gint offset = BMARKDATA(main_v->bmarkdata)->bevent_charoffset;
 
1337
                /* we have the location */
 
1338
                /*if (BFWIN(doc->bfwin)->bmark == NULL) {
 
1339
                        DEBUG_MSG("adding bookmarks without left panel is not implemented yet\n");
 
1340
                } else */ {
 
1341
                        bmark_add_current_doc_backend(doc->bfwin, "", offset, !main_v->props.bookmarks_default_store);
 
1342
                }
 
1343
        }
 
1344
}
 
1345
 
 
1346
/* not used yet
 
1347
void bmark_del_for_filename(Tbfwin *bfwin, gchar *filename) {
 
1348
        GtkTreeIter *parent = (GtkTreeIter *)g_hash_table_lookup(bfwin->bmark_files,filename);
 
1349
        if (parent) {
 
1350
                bmark_del_children_backend(bfwin, parent);
 
1351
        }
 
1352
}
 
1353
*/
 
1354
 
 
1355
void bmark_del_for_document(Tbfwin *bfwin, Tdocument *doc) {
 
1356
        if (doc->bmark_parent) {
 
1357
                bmark_del_children_backend(bfwin, doc->bmark_parent);
 
1358
        }
 
1359
}
 
1360
 
 
1361
void bmark_del_all(Tbfwin *bfwin,gboolean ask) {
 
1362
        gint ret;
 
1363
        gchar *btns[]={GTK_STOCK_NO,GTK_STOCK_YES,NULL};
 
1364
        GtkTreeIter tmpiter;
 
1365
 
 
1366
        if (bfwin==NULL) return;
 
1367
                        
 
1368
        if (ask)        {
 
1369
          ret = multi_query_dialog(bfwin->main_window,_("Delete all bookmarks."), _("Are you sure?"), 0, 0, btns);
 
1370
          if (ret==0) return;
 
1371
        }
 
1372
        DEBUG_MSG("bmark_del_all, deleting all bookmarks!\n");
 
1373
        while (gtk_tree_model_iter_children(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter, NULL) ) {
 
1374
#ifdef DEBUG
 
1375
                gchar *name;
 
1376
                gtk_tree_model_get(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter, NAME_COLUMN,&name, -1);
 
1377
                DEBUG_MSG("bmark_del_all, the toplevel has child '%s'\n", name);
 
1378
#endif
 
1379
                bmark_del_children_backend(bfwin, &tmpiter);
 
1380
        }
 
1381
        gtk_widget_grab_focus(bfwin->current_document->view);
 
1382
}       
 
1383
 
 
1384
void bmark_check_length(Tbfwin * bfwin, Tdocument * doc) {
 
1385
        GtkTreeIter tmpiter;
 
1386
        gboolean cont;
 
1387
        if (!doc || !doc->bmark_parent) {
 
1388
                DEBUG_MSG("bmark_check_length, no bmark_parent iter => no bookmarks, returning\n");
 
1389
                return;
 
1390
        }
 
1391
        DEBUG_MSG("bmark_check_length, doc %p, filename %s\n\n", doc, doc->filename);
 
1392
 
 
1393
        cont =
 
1394
                gtk_tree_model_iter_children(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter,
 
1395
                                                                         doc->bmark_parent);
 
1396
        while (cont) {
 
1397
                Tbmark *mark = NULL;
 
1398
                gtk_tree_model_get(GTK_TREE_MODEL(BFWIN(doc->bfwin)->bookmarkstore), &tmpiter, PTR_COLUMN,
 
1399
                                                   &mark, -1);
 
1400
                if (mark) {
 
1401
                        glong size;
 
1402
#ifdef HAVE_GNOME_VFS
 
1403
                        size = doc->fileinfo->size;
 
1404
#else
 
1405
                        size = doc->statbuf.st_size;
 
1406
#endif
 
1407
                        DEBUG_MSG("bmark_check_length, bmark has %d, file has %ld\n",mark->len, size);
 
1408
                        if (mark->len != size) {
 
1409
                                gint ret;
 
1410
                                gchar *btns[]={GTK_STOCK_NO,GTK_STOCK_YES,NULL};
 
1411
                                gchar *str;
 
1412
                                str = g_strconcat(_("File size changed in file\n"),doc->filename,NULL);
 
1413
                                ret = multi_query_dialog(bfwin->main_window,_("Bookmarks positions could be incorrect. Delete bookmarks?"), str, 0, 0, btns);
 
1414
                                if (ret==1) {
 
1415
                                        bmark_del_for_document(bfwin, doc);
 
1416
                                }
 
1417
                                return;
 
1418
                        }
 
1419
                } else {
 
1420
                        DEBUG_MSG("bmark_check_length, NOT GOOD no mark in the treestore??\n");
 
1421
                }
 
1422
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(bfwin->bookmarkstore), &tmpiter);
 
1423
        }
 
1424
        DEBUG_MSG("bmark_check_length, all bookmarks OK, returning\n");
 
1425
}
 
1426
 
 
1427
void bmark_cleanup(Tbfwin * bfwin) {
 
1428
        DEBUG_MSG("bmark_cleanup, cleanup for bfwin=%p\n",bfwin);
 
1429
/* we are not destroying a store, so let's not destroy tree positions, it seems, they 
 
1430
   are recovered from store - Oskar */  
 
1431
/*      if (bfwin->bmark_files) g_hash_table_destroy(bfwin->bmark_files);
 
1432
        bfwin->bmark_files = NULL; */ 
 
1433
 
 
1434
        bfwin->bmark = NULL;
 
1435
}