2 * geanyprj - Alternative project support for geany light IDE.
4 * Copyright 2008 Yura Siamashka <yurand2@gmail.com>
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/>.
22 #include <gdk/gdkkeysyms.h>
27 #include "plugindata.h"
29 #include "filetypes.h"
30 #include "keybindings.h"
33 #include "pluginmacros.h"
39 extern GeanyData
*geany_data
;
40 extern GeanyFunctions
*geany_functions
;
42 static GtkWidget
*file_view_vbox
;
43 static GtkWidget
*file_view
;
44 static GtkListStore
*file_store
;
48 FILEVIEW_COLUMN_NAME
= 0,
54 GtkWidget
*new_project
;
55 GtkWidget
*delete_project
;
58 GtkWidget
*remove_files
;
60 GtkWidget
*preferences
;
62 GtkWidget
*find_in_files
;
66 /* Returns: the full filename in locale encoding. */
68 get_tree_path_filename(GtkTreePath
* treepath
)
70 GtkTreeModel
*model
= GTK_TREE_MODEL(file_store
);
74 gtk_tree_model_get_iter(model
, &iter
, treepath
);
75 gtk_tree_model_get(model
, &iter
, FILEVIEW_COLUMN_NAME
, &name
, -1);
76 setptr(name
, p_utils
->get_locale_from_utf8(name
));
77 setptr(name
, get_full_path(g_current_project
->path
, name
));
81 /* We use documents->open_files() as it's more efficient. */
83 open_selected_files(GList
* list
)
88 for (item
= list
; item
!= NULL
; item
= g_list_next(item
))
90 GtkTreePath
*treepath
= item
->data
;
91 gchar
*fname
= get_tree_path_filename(treepath
);
92 files
= g_slist_append(files
, fname
);
94 p_document
->open_files(files
, FALSE
, NULL
, NULL
);
95 g_slist_foreach(files
, (GFunc
) g_free
, NULL
); // free filenames
100 on_open_clicked(G_GNUC_UNUSED GtkMenuItem
* menuitem
, G_GNUC_UNUSED gpointer user_data
)
102 GtkTreeSelection
*treesel
;
106 treesel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(file_view
));
108 list
= gtk_tree_selection_get_selected_rows(treesel
, &model
);
109 open_selected_files(list
);
110 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
115 on_button_press(G_GNUC_UNUSED GtkWidget
* widget
, GdkEventButton
* event
,
116 G_GNUC_UNUSED gpointer user_data
)
118 if (event
->button
== 1 && event
->type
== GDK_2BUTTON_PRESS
)
119 on_open_clicked(NULL
, NULL
);
128 toolbar
= gtk_toolbar_new();
129 gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar
), GTK_ICON_SIZE_MENU
);
130 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
136 remove_selected_files(GList
* list
)
139 for (item
= list
; item
!= NULL
; item
= g_list_next(item
))
141 GtkTreePath
*treepath
= item
->data
;
142 gchar
*fname
= get_tree_path_filename(treepath
);
143 xproject_remove_file(fname
);
149 on_remove_files(G_GNUC_UNUSED GtkMenuItem
* menuitem
, G_GNUC_UNUSED gpointer user_data
)
151 GtkTreeSelection
*treesel
;
155 treesel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(file_view
));
157 list
= gtk_tree_selection_get_selected_rows(treesel
, &model
);
158 remove_selected_files(list
);
159 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
164 on_key_press(G_GNUC_UNUSED GtkWidget
* widget
, GdkEventKey
* event
, G_GNUC_UNUSED gpointer data
)
166 if (event
->keyval
== GDK_Return
167 || event
->keyval
== GDK_ISO_Enter
168 || event
->keyval
== GDK_KP_Enter
|| event
->keyval
== GDK_space
)
169 on_open_clicked(NULL
, NULL
);
176 GtkWidget
*item
, *menu
, *image
;
178 menu
= gtk_menu_new();
180 image
= gtk_image_new_from_stock(GTK_STOCK_NEW
, GTK_ICON_SIZE_MENU
);
181 gtk_widget_show(image
);
182 item
= gtk_image_menu_item_new_with_mnemonic(_("New Project"));
183 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
184 gtk_widget_show(item
);
185 gtk_container_add(GTK_CONTAINER(menu
), item
);
186 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_new_project
), NULL
);
187 popup_items
.new_project
= item
;
189 image
= gtk_image_new_from_stock(GTK_STOCK_DELETE
, GTK_ICON_SIZE_MENU
);
190 gtk_widget_show(image
);
191 item
= gtk_image_menu_item_new_with_mnemonic(_("Delete Project"));
192 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
193 gtk_widget_show(item
);
194 gtk_container_add(GTK_CONTAINER(menu
), item
);
195 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_delete_project
), NULL
);
196 popup_items
.delete_project
= item
;
198 item
= gtk_separator_menu_item_new();
199 gtk_widget_show(item
);
200 gtk_container_add(GTK_CONTAINER(menu
), item
);
202 image
= gtk_image_new_from_stock(GTK_STOCK_ADD
, GTK_ICON_SIZE_MENU
);
203 gtk_widget_show(image
);
204 item
= gtk_image_menu_item_new_with_mnemonic(_("Add File"));
205 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
206 gtk_widget_show(item
);
207 gtk_container_add(GTK_CONTAINER(menu
), item
);
208 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_add_file
), NULL
);
209 popup_items
.add_file
= item
;
211 image
= gtk_image_new_from_stock(GTK_STOCK_REMOVE
, GTK_ICON_SIZE_MENU
);
212 gtk_widget_show(image
);
213 item
= gtk_image_menu_item_new_with_mnemonic(_("Remove File"));
214 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
215 gtk_widget_show(item
);
216 gtk_container_add(GTK_CONTAINER(menu
), item
);
217 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_remove_files
), NULL
);
218 popup_items
.remove_files
= item
;
220 item
= gtk_separator_menu_item_new();
221 gtk_widget_show(item
);
222 gtk_container_add(GTK_CONTAINER(menu
), item
);
224 image
= gtk_image_new_from_stock(GTK_STOCK_PREFERENCES
, GTK_ICON_SIZE_MENU
);
225 gtk_widget_show(image
);
226 item
= gtk_image_menu_item_new_with_mnemonic(_("Preferences"));
227 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
228 gtk_widget_show(item
);
229 gtk_container_add(GTK_CONTAINER(menu
), item
);
230 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_preferences
), NULL
);
231 popup_items
.preferences
= item
;
233 item
= gtk_separator_menu_item_new();
234 gtk_widget_show(item
);
235 gtk_container_add(GTK_CONTAINER(menu
), item
);
237 image
= gtk_image_new_from_stock(GTK_STOCK_FIND
, GTK_ICON_SIZE_MENU
);
238 gtk_widget_show(image
);
239 item
= gtk_image_menu_item_new_with_mnemonic(_("Find in Project"));
240 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
241 gtk_widget_show(item
);
242 gtk_container_add(GTK_CONTAINER(menu
), item
);
243 g_signal_connect((gpointer
) item
, "activate", G_CALLBACK(on_find_in_project
), NULL
);
244 popup_items
.find_in_files
= item
;
246 item
= gtk_separator_menu_item_new();
247 gtk_widget_show(item
);
248 gtk_container_add(GTK_CONTAINER(menu
), item
);
250 item
= gtk_image_menu_item_new_with_mnemonic(_("H_ide Sidebar"));
251 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
252 gtk_image_new_from_stock("gtk-close", GTK_ICON_SIZE_MENU
));
253 gtk_widget_show(item
);
254 gtk_container_add(GTK_CONTAINER(menu
), item
);
255 g_signal_connect_swapped((gpointer
) item
, "activate",
256 G_CALLBACK(p_keybindings
->send_command
),
257 GINT_TO_POINTER(GEANY_KEYS_VIEW_SIDEBAR
));
263 update_popup_menu(G_GNUC_UNUSED GtkWidget
* popup_menu
)
266 gboolean cur_file_exists
;
269 idx
= p_document
->get_cur_idx();
271 cur_file_exists
= DOC_IDX_VALID(idx
) &&
272 doc_list
[idx
].file_name
!= NULL
&& g_path_is_absolute(doc_list
[idx
].file_name
);
274 badd_file
= (g_current_project
? TRUE
: FALSE
) &&
275 !g_current_project
->regenerate
&&
277 !g_hash_table_lookup(g_current_project
->tags
, doc_list
[idx
].file_name
);
279 GtkTreeSelection
*treesel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(file_view
));
280 gboolean bremove_file
= (g_current_project
? TRUE
: FALSE
) &&
281 !g_current_project
->regenerate
&&
282 (gtk_tree_selection_count_selected_rows(treesel
) > 0);
284 gtk_widget_set_sensitive(popup_items
.new_project
, TRUE
);
285 gtk_widget_set_sensitive(popup_items
.delete_project
, g_current_project
? TRUE
: FALSE
);
287 gtk_widget_set_sensitive(popup_items
.add_file
, badd_file
);
288 gtk_widget_set_sensitive(popup_items
.remove_files
, bremove_file
);
290 gtk_widget_set_sensitive(popup_items
.preferences
, g_current_project
? TRUE
: FALSE
);
292 gtk_widget_set_sensitive(popup_items
.find_in_files
, g_current_project
? TRUE
: FALSE
);
295 // delay updating popup menu until the selection has been set
297 on_button_release(G_GNUC_UNUSED GtkWidget
* widget
, GdkEventButton
* event
,
298 G_GNUC_UNUSED gpointer user_data
)
300 if (event
->button
== 3)
302 static GtkWidget
*popup_menu
= NULL
;
304 if (popup_menu
== NULL
)
305 popup_menu
= create_popup_menu();
307 update_popup_menu(popup_menu
);
309 gtk_menu_popup(GTK_MENU(popup_menu
), NULL
, NULL
, NULL
, NULL
,
310 event
->button
, event
->time
);
318 GtkCellRenderer
*text_renderer
;
319 GtkTreeViewColumn
*column
;
320 GtkTreeSelection
*select
;
321 PangoFontDescription
*pfd
;
323 file_store
= gtk_list_store_new(FILEVIEW_N_COLUMNS
, G_TYPE_STRING
, G_TYPE_STRING
);
325 gtk_tree_view_set_model(GTK_TREE_VIEW(file_view
), GTK_TREE_MODEL(file_store
));
327 text_renderer
= gtk_cell_renderer_text_new();
328 column
= gtk_tree_view_column_new();
329 gtk_tree_view_column_pack_start(column
, text_renderer
, TRUE
);
330 gtk_tree_view_column_set_attributes(column
, text_renderer
, "text", FILEVIEW_COLUMN_NAME
,
332 gtk_tree_view_append_column(GTK_TREE_VIEW(file_view
), column
);
333 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(file_view
), FALSE
);
335 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(file_view
), TRUE
);
336 gtk_tree_view_set_search_column(GTK_TREE_VIEW(file_view
), FILEVIEW_COLUMN_NAME
);
338 pfd
= pango_font_description_from_string(geany_data
->interface_prefs
->tagbar_font
);
339 gtk_widget_modify_font(file_view
, pfd
);
340 pango_font_description_free(pfd
);
342 // selection handling
343 select
= gtk_tree_view_get_selection(GTK_TREE_VIEW(file_view
));
344 gtk_tree_selection_set_mode(select
, GTK_SELECTION_SINGLE
);
346 g_signal_connect(G_OBJECT(file_view
), "button-release-event",
347 G_CALLBACK(on_button_release
), NULL
);
348 g_signal_connect(G_OBJECT(file_view
), "button-press-event",
349 G_CALLBACK(on_button_press
), NULL
);
351 g_signal_connect(G_OBJECT(file_view
), "key-press-event", G_CALLBACK(on_key_press
), NULL
);
357 gtk_list_store_clear(file_store
);
361 mycmp(const gchar
* a
, const gchar
* b
)
371 if (*p1
== G_DIR_SEPARATOR_S
[0])
378 if (*p2
== G_DIR_SEPARATOR_S
[0])
393 if (*p1
== G_DIR_SEPARATOR_S
[0])
395 else if (*p2
== G_DIR_SEPARATOR_S
[0])
402 if (*p1
== 0 && *p2
== 0)
410 add_item(gpointer name
, G_GNUC_UNUSED gpointer value
, gpointer user_data
)
413 GSList
**lst
= (GSList
**) user_data
;
415 item
= get_relative_path(g_current_project
->path
, name
);
416 *lst
= g_slist_prepend(*lst
, item
);
419 // recreate the tree model from current_dir.
429 if (!g_current_project
)
432 g_hash_table_foreach(g_current_project
->tags
, add_item
, &lst
);
433 lst
= g_slist_sort(lst
, (GCompareFunc
) strcmp
);
434 for (tmp
= lst
; tmp
!= NULL
; tmp
= g_slist_next(tmp
))
436 gtk_list_store_append(file_store
, &iter
);
437 gtk_list_store_set(file_store
, &iter
, FILEVIEW_COLUMN_NAME
, tmp
->data
, -1);
439 g_slist_foreach(lst
, (GFunc
) g_free
, NULL
);
446 GtkWidget
*scrollwin
, *toolbar
;
448 file_view_vbox
= gtk_vbox_new(FALSE
, 0);
449 toolbar
= make_toolbar();
450 gtk_box_pack_start(GTK_BOX(file_view_vbox
), toolbar
, FALSE
, FALSE
, 0);
452 file_view
= gtk_tree_view_new();
455 scrollwin
= gtk_scrolled_window_new(NULL
, NULL
);
456 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin
),
457 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
458 gtk_container_add(GTK_CONTAINER(scrollwin
), file_view
);
459 gtk_container_add(GTK_CONTAINER(file_view_vbox
), scrollwin
);
461 gtk_widget_show_all(file_view_vbox
);
462 gtk_notebook_append_page(GTK_NOTEBOOK(app
->treeview_notebook
), file_view_vbox
,
463 gtk_label_new(_("Project")));
469 gtk_widget_destroy(file_view_vbox
);