Mark all plugin API functions to have "default" (public) visibility
[geany-mirror.git] / src / navqueue.c
blobd6ea01fe48c3c7610a0e6f9fbe7a5897e1b42166
1 /*
2 * navqueue.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2007 Dave Moore <wrex006(at)gmail(dot)com>
5 * Copyright 2007-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
6 * Copyright 2007-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * Simple code navigation
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include "navqueue.h"
33 #include "document.h"
34 #include "geanyobject.h"
35 #include "pluginexport.h"
36 #include "sciwrappers.h"
37 #include "toolbar.h"
38 #include "utils.h"
40 #include "gtkcompat.h"
43 /* for the navigation history queue */
44 typedef struct
46 const gchar *file; /* This is the document's filename, in UTF-8 */
47 gint pos;
48 } filepos;
50 static GQueue *navigation_queue;
51 static guint nav_queue_pos;
53 static GtkAction *navigation_buttons[2];
57 void navqueue_init(void)
59 navigation_queue = g_queue_new();
60 nav_queue_pos = 0;
62 navigation_buttons[0] = toolbar_get_action_by_name("NavBack");
63 navigation_buttons[1] = toolbar_get_action_by_name("NavFor");
65 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
66 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
70 void navqueue_free(void)
72 while (! g_queue_is_empty(navigation_queue))
74 g_free(g_queue_pop_tail(navigation_queue));
76 g_queue_free(navigation_queue);
80 static void adjust_buttons(void)
82 if (g_queue_get_length(navigation_queue) < 2)
84 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
85 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
86 return;
88 if (nav_queue_pos == 0)
90 gtk_action_set_sensitive(navigation_buttons[0], TRUE);
91 gtk_action_set_sensitive(navigation_buttons[1], FALSE);
92 return;
94 /* forward should be sensitive since where not at the start */
95 gtk_action_set_sensitive(navigation_buttons[1], TRUE);
97 /* back should be sensitive if there's a place to go back to */
98 (nav_queue_pos < g_queue_get_length(navigation_queue) - 1) ?
99 gtk_action_set_sensitive(navigation_buttons[0], TRUE) :
100 gtk_action_set_sensitive(navigation_buttons[0], FALSE);
104 static gboolean
105 queue_pos_matches(guint queue_pos, const gchar *fname, gint pos)
107 if (queue_pos < g_queue_get_length(navigation_queue))
109 filepos *fpos = g_queue_peek_nth(navigation_queue, queue_pos);
111 return (utils_str_equal(fpos->file, fname) && fpos->pos == pos);
113 return FALSE;
117 static void add_new_position(const gchar *utf8_filename, gint pos)
119 filepos *npos;
120 guint i;
122 if (queue_pos_matches(nav_queue_pos, utf8_filename, pos))
123 return; /* prevent duplicates */
125 npos = g_new0(filepos, 1);
126 npos->file = utf8_filename;
127 npos->pos = pos;
129 /* if we've jumped to a new position from inside the queue rather than going forward */
130 if (nav_queue_pos > 0)
132 for (i = 0; i < nav_queue_pos; i++)
134 g_free(g_queue_pop_head(navigation_queue));
136 nav_queue_pos = 0;
138 g_queue_push_head(navigation_queue, npos);
139 adjust_buttons();
144 * Adds old file position and new file position to the navqueue, then goes to the new position.
146 * @param old_doc The document of the previous position, if set as invalid (@c NULL) then no old
147 * position is set
148 * @param new_doc The document of the new position, must be valid.
149 * @param line the line number of the new position. It is counted with 1 as the first line, not 0.
151 * @return @c TRUE if the cursor has changed the position to @a line or @c FALSE otherwise.
153 GEANY_API_SYMBOL
154 gboolean navqueue_goto_line(GeanyDocument *old_doc, GeanyDocument *new_doc, gint line)
156 gint pos;
158 g_return_val_if_fail(old_doc == NULL || old_doc->is_valid, FALSE);
159 g_return_val_if_fail(DOC_VALID(new_doc), FALSE);
160 g_return_val_if_fail(line >= 1, FALSE);
162 pos = sci_get_position_from_line(new_doc->editor->sci, line - 1);
164 /* first add old file position */
165 if (old_doc != NULL && old_doc->file_name)
167 gint cur_pos = sci_get_current_position(old_doc->editor->sci);
169 add_new_position(old_doc->file_name, cur_pos);
172 /* now add new file position */
173 if (new_doc->file_name)
175 add_new_position(new_doc->file_name, pos);
178 return editor_goto_pos(new_doc->editor, pos, TRUE);
182 static gboolean goto_file_pos(const gchar *file, gint pos)
184 GeanyDocument *doc = document_find_by_filename(file);
186 if (doc == NULL)
187 return FALSE;
189 return editor_goto_pos(doc->editor, pos, TRUE);
193 void navqueue_go_back(void)
195 filepos *fprev;
197 /* return if theres no place to go back to */
198 if (g_queue_is_empty(navigation_queue) ||
199 nav_queue_pos >= g_queue_get_length(navigation_queue) - 1)
200 return;
202 /* jump back */
203 fprev = g_queue_peek_nth(navigation_queue, nav_queue_pos + 1);
204 if (goto_file_pos(fprev->file, fprev->pos))
206 nav_queue_pos++;
208 else
210 /** TODO: add option to re open the file */
211 g_free(g_queue_pop_nth(navigation_queue, nav_queue_pos + 1));
213 adjust_buttons();
217 void navqueue_go_forward(void)
219 filepos *fnext;
221 if (nav_queue_pos < 1 ||
222 nav_queue_pos >= g_queue_get_length(navigation_queue))
223 return;
225 /* jump forward */
226 fnext = g_queue_peek_nth(navigation_queue, nav_queue_pos - 1);
227 if (goto_file_pos(fnext->file, fnext->pos))
229 nav_queue_pos--;
231 else
233 /** TODO: add option to re open the file */
234 g_free(g_queue_pop_nth(navigation_queue, nav_queue_pos - 1));
237 adjust_buttons();
241 static gint find_by_filename(gconstpointer a, gconstpointer b)
243 if (utils_str_equal(((const filepos*)a)->file, (const gchar*) b))
244 return 0;
245 else
246 return 1;
250 /* Remove all elements with the given filename */
251 void navqueue_remove_file(const gchar *filename)
253 GList *match;
255 if (filename == NULL)
256 return;
258 while ((match = g_queue_find_custom(navigation_queue, filename, find_by_filename)))
260 g_free(match->data);
261 g_queue_delete_link(navigation_queue, match);
264 adjust_buttons();