1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Johannes Schmid 2012 <jhs@gnome.org>
6 * anjuta is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "search-files.h"
21 #include "search-file-command.h"
22 #include <libanjuta/anjuta-command-queue.h>
23 #include <libanjuta/interfaces/ianjuta-project-manager.h>
24 #include <libanjuta/interfaces/ianjuta-project-chooser.h>
26 #define BUILDER_FILE PACKAGE_DATA_DIR"/glade/anjuta-document-manager.ui"
28 struct _SearchFilesPrivate
34 GtkWidget
* search_button
;
35 GtkWidget
* replace_button
;
36 GtkWidget
* find_files_button
;
38 GtkWidget
* search_entry
;
39 GtkWidget
* replace_entry
;
41 GtkWidget
* files_combo
;
42 GtkWidget
* project_combo
;
43 GtkWidget
* file_type_combo
;
45 GtkWidget
* case_check
;
46 GtkWidget
* regex_check
;
48 GtkWidget
* spinner_busy
;
50 GtkWidget
* files_tree
;
51 GtkTreeModel
* files_model
;
53 GtkWidget
* files_tree_check
;
56 SearchBox
* search_box
;
59 /* Saved from last search */
60 gboolean case_sensitive
;
62 gchar
* last_search_string
;
63 gchar
* last_replace_string
;
81 G_DEFINE_TYPE (SearchFiles
, search_files
, G_TYPE_OBJECT
);
83 void search_files_search_clicked (SearchFiles
* sf
);
84 void search_files_replace_clicked (SearchFiles
* sf
);
85 void search_files_find_files_clicked (SearchFiles
* sf
);
86 void search_files_update_ui (SearchFiles
* sf
);
90 search_files_update_ui (SearchFiles
* sf
)
93 gboolean can_search
= FALSE
;
97 gtk_spinner_stop(GTK_SPINNER (sf
->priv
->spinner_busy
));
98 gtk_widget_hide (sf
->priv
->spinner_busy
);
100 if (strlen(gtk_entry_get_text (GTK_ENTRY (sf
->priv
->search_entry
))) > 0
101 && gtk_tree_model_get_iter_first(sf
->priv
->files_model
, &iter
))
106 gtk_tree_model_get (sf
->priv
->files_model
, &iter
,
107 COLUMN_SELECTED
, &selected
, -1);
114 while (gtk_tree_model_iter_next(sf
->priv
->files_model
, &iter
));
119 gtk_spinner_start(GTK_SPINNER (sf
->priv
->spinner_busy
));
120 gtk_widget_show (sf
->priv
->spinner_busy
);
123 gtk_widget_set_sensitive (sf
->priv
->search_button
, can_search
);
124 gtk_widget_set_sensitive (sf
->priv
->replace_button
, can_search
);
125 gtk_widget_set_sensitive (sf
->priv
->find_files_button
, !sf
->priv
->busy
);
129 search_files_get_files (GFile
* parent
, GList
** files
, IAnjutaProjectManager
* pm
)
132 GList
* children
= ianjuta_project_manager_get_children(pm
, parent
, NULL
);
133 for (node
= children
;node
!= NULL
; node
= g_list_next(node
))
135 search_files_get_files(G_FILE(node
), files
, pm
);
136 g_message (g_file_get_path (G_FILE(node
)));
138 g_list_foreach (children
, (GFunc
)g_object_unref
, NULL
);
139 g_list_free(children
);
143 search_files_check_column_toggled (GtkCellRendererToggle
* renderer
,
147 GtkTreePath
* tree_path
;
154 tree_path
= gtk_tree_path_new_from_string(path
);
155 gtk_tree_model_get_iter (sf
->priv
->files_model
, &iter
, tree_path
);
157 gtk_tree_path_free(tree_path
);
159 gtk_tree_model_get (sf
->priv
->files_model
, &iter
,
160 COLUMN_SELECTED
, &state
, -1);
162 gtk_list_store_set (GTK_LIST_STORE (sf
->priv
->files_model
), &iter
,
163 COLUMN_SELECTED
, !state
,
168 search_files_finished (SearchFiles
* sf
, AnjutaCommandQueue
* queue
)
170 sf
->priv
->busy
= FALSE
;
171 g_object_unref (queue
);
173 search_files_update_ui(sf
);
177 search_files_command_finished (SearchFileCommand
* cmd
,
182 GtkTreeRowReference
* tree_ref
;
185 tree_ref
= g_object_get_data (G_OBJECT (cmd
),
187 path
= gtk_tree_row_reference_get_path(tree_ref
);
189 gtk_tree_model_get_iter(sf
->priv
->files_model
, &iter
, path
);
190 gtk_list_store_set (GTK_LIST_STORE (sf
->priv
->files_model
),
192 COLUMN_COUNT
, search_file_command_get_n_matches(cmd
),
193 COLUMN_ERROR_CODE
, return_code
,
194 COLUMN_ERROR_TOOLTIP
, NULL
,
196 gtk_tree_row_reference_free(tree_ref
);
197 gtk_tree_path_free(path
);
201 gtk_list_store_set (GTK_LIST_STORE (sf
->priv
->files_model
),
203 COLUMN_ERROR_CODE
, return_code
,
204 COLUMN_ERROR_TOOLTIP
,
205 anjuta_command_get_error_message(cmd
),
209 g_object_unref (cmd
);
213 search_files_search_clicked (SearchFiles
* sf
)
217 if (gtk_tree_model_get_iter_first(sf
->priv
->files_model
, &iter
))
219 AnjutaCommandQueue
* queue
= anjuta_command_queue_new(ANJUTA_COMMAND_QUEUE_EXECUTE_MANUAL
);
220 const gchar
* pattern
=
221 gtk_entry_get_text (GTK_ENTRY (sf
->priv
->search_entry
));
227 /* Save the current values */
229 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (sf
->priv
->regex_check
));
230 sf
->priv
->case_sensitive
=
231 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (sf
->priv
->case_check
));
233 g_free (sf
->priv
->last_search_string
);
234 sf
->priv
->last_search_string
= g_strdup(pattern
);
235 g_free (sf
->priv
->last_replace_string
);
236 sf
->priv
->last_replace_string
= NULL
;
238 gtk_tree_model_get (sf
->priv
->files_model
, &iter
,
240 COLUMN_SELECTED
, &selected
, -1);
244 GtkTreeRowReference
* ref
;
246 path
= gtk_tree_model_get_path(sf
->priv
->files_model
, &iter
);
247 ref
= gtk_tree_row_reference_new(sf
->priv
->files_model
,
249 gtk_tree_path_free(path
);
252 SearchFileCommand
* cmd
= search_file_command_new(file
,
255 sf
->priv
->case_sensitive
,
257 g_object_set_data (G_OBJECT (cmd
), "__tree_ref",
260 g_signal_connect (cmd
, "command-finished",
261 G_CALLBACK(search_files_command_finished
), sf
);
263 anjuta_command_queue_push(queue
,
264 ANJUTA_COMMAND(cmd
));
266 g_object_unref (file
);
268 while (gtk_tree_model_iter_next(sf
->priv
->files_model
, &iter
));
270 g_signal_connect_swapped (queue
, "finished", G_CALLBACK (search_files_finished
), sf
);
272 anjuta_command_queue_start (queue
);
273 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE (sf
->priv
->files_model
),
275 GTK_SORT_DESCENDING
);
277 sf
->priv
->busy
= TRUE
;
278 search_files_update_ui(sf
);
283 search_files_replace_clicked (SearchFiles
* sf
)
287 if (gtk_tree_model_get_iter_first(sf
->priv
->files_model
, &iter
))
289 AnjutaCommandQueue
* queue
= anjuta_command_queue_new(ANJUTA_COMMAND_QUEUE_EXECUTE_MANUAL
);
290 const gchar
* pattern
=
291 gtk_entry_get_text (GTK_ENTRY (sf
->priv
->search_entry
));
292 const gchar
* replace
=
293 gtk_entry_get_text (GTK_ENTRY (sf
->priv
->replace_entry
));
299 /* Save the current values */
301 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (sf
->priv
->regex_check
));
302 sf
->priv
->case_sensitive
=
303 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (sf
->priv
->case_check
));
305 g_free (sf
->priv
->last_search_string
);
306 sf
->priv
->last_search_string
= g_strdup(pattern
);
307 g_free (sf
->priv
->last_replace_string
);
308 sf
->priv
->last_replace_string
= g_strdup(replace
);
310 gtk_tree_model_get (sf
->priv
->files_model
, &iter
,
312 COLUMN_SELECTED
, &selected
, -1);
316 GtkTreeRowReference
* ref
;
318 path
= gtk_tree_model_get_path(sf
->priv
->files_model
, &iter
);
319 ref
= gtk_tree_row_reference_new(sf
->priv
->files_model
,
321 gtk_tree_path_free(path
);
324 SearchFileCommand
* cmd
= search_file_command_new(file
,
327 sf
->priv
->case_sensitive
,
329 g_object_set_data (G_OBJECT (cmd
), "__tree_ref",
332 g_signal_connect (cmd
, "command-finished",
333 G_CALLBACK(search_files_command_finished
), sf
);
335 anjuta_command_queue_push(queue
,
336 ANJUTA_COMMAND(cmd
));
338 g_object_unref (file
);
340 while (gtk_tree_model_iter_next(sf
->priv
->files_model
, &iter
));
342 g_signal_connect_swapped (queue
, "finished", G_CALLBACK (search_files_finished
), sf
);
344 anjuta_command_queue_start (queue
);
345 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE (sf
->priv
->files_model
),
347 GTK_SORT_DESCENDING
);
349 sf
->priv
->busy
= TRUE
;
350 search_files_update_ui(sf
);
355 search_files_find_files_clicked (SearchFiles
* sf
)
358 IAnjutaProjectManager
* pm
;
362 gchar
* project_uri
= NULL
;
363 GFile
* project_file
= NULL
;
365 g_return_if_fail (sf
!= NULL
&& SEARCH_IS_FILES (sf
));
367 gtk_list_store_clear(GTK_LIST_STORE (sf
->priv
->files_model
));
369 pm
= anjuta_shell_get_interface (sf
->priv
->docman
->shell
,
370 IAnjutaProjectManager
,
372 files
= ianjuta_project_manager_get_elements(pm
,
373 ANJUTA_PROJECT_SOURCE
,
375 anjuta_shell_get (sf
->priv
->docman
->shell
,
376 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI
,
381 project_file
= g_file_new_for_uri (project_uri
);
382 g_free (project_uri
);
384 for (file
= files
; file
!= NULL
; file
= g_list_next (file
))
388 gchar
* display_name
= NULL
;
392 display_name
= g_file_get_relative_path (project_file
,
393 G_FILE (file
->data
));
399 display_name
= g_file_get_path (G_FILE (file
->data
));
401 display_name
= g_file_get_uri (G_FILE (file
->data
));
403 gtk_list_store_append(GTK_LIST_STORE (sf
->priv
->files_model
),
405 gtk_list_store_set (GTK_LIST_STORE (sf
->priv
->files_model
), &iter
,
406 COLUMN_SELECTED
, TRUE
,
407 COLUMN_FILENAME
, display_name
,
408 COLUMN_FILE
, file
->data
,
410 COLUMN_SPINNER
, FALSE
,
411 COLUMN_PULSE
, FALSE
, -1);
413 g_object_unref (project_file
);
415 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE (sf
->priv
->files_model
),
417 GTK_SORT_DESCENDING
);
419 g_list_foreach (files
, (GFunc
) g_object_unref
, NULL
);
424 search_files_render_count (GtkTreeViewColumn
*tree_column
,
425 GtkCellRenderer
*cell
,
426 GtkTreeModel
*tree_model
,
433 gtk_tree_model_get (tree_model
, iter
,
434 COLUMN_COUNT
, &count
,
436 count_str
= g_strdup_printf("%d", count
);
437 g_object_set (cell
, "text", count_str
, NULL
);
442 search_files_editor_loaded (SearchFiles
* sf
, IAnjutaEditor
* editor
)
444 search_box_set_search_string(sf
->priv
->search_box
,
445 sf
->priv
->last_search_string
);
446 if (sf
->priv
->last_replace_string
)
448 search_box_set_replace_string(sf
->priv
->search_box
,
449 sf
->priv
->last_replace_string
);
450 search_box_set_replace(sf
->priv
->search_box
,
455 search_box_set_replace(sf
->priv
->search_box
,
458 search_box_toggle_case_sensitive(sf
->priv
->search_box
,
459 sf
->priv
->case_sensitive
);
460 search_box_toggle_highlight(sf
->priv
->search_box
,
462 search_box_toggle_regex(sf
->priv
->search_box
,
464 search_box_search_highlight_all(sf
->priv
->search_box
, TRUE
);
465 search_box_incremental_search(sf
->priv
->search_box
, TRUE
, FALSE
);
467 gtk_widget_show (GTK_WIDGET(sf
->priv
->search_box
));
472 search_files_result_activated (GtkTreeView
* files_tree
,
474 GtkTreeViewColumn
* column
,
477 IAnjutaDocument
* editor
;
481 gtk_tree_model_get_iter (sf
->priv
->files_model
, &iter
, path
);
482 gtk_tree_model_get (sf
->priv
->files_model
, &iter
,
483 COLUMN_FILE
, &file
, -1);
485 /* Check if document is open */
486 editor
= anjuta_docman_get_document_for_file(sf
->priv
->docman
, file
);
488 if (editor
&& IANJUTA_IS_EDITOR(editor
))
490 search_files_editor_loaded (sf
, IANJUTA_EDITOR(editor
));
494 IAnjutaEditor
* real_editor
=
495 anjuta_docman_goto_file_line(sf
->priv
->docman
, file
, 0);
497 g_signal_connect_swapped (real_editor
, "opened",
498 G_CALLBACK (search_files_editor_loaded
), sf
);
501 g_object_unref (file
);
505 search_files_init_tree (SearchFiles
* sf
)
507 GtkTreeViewColumn
* column_select
;
508 GtkTreeViewColumn
* column_filename
;
509 GtkTreeViewColumn
* column_count
;
511 GtkCellRenderer
* selection_renderer
;
512 GtkCellRenderer
* filename_renderer
;
513 GtkCellRenderer
* count_renderer
;
514 GtkCellRenderer
* error_renderer
;
516 column_select
= gtk_tree_view_column_new();
517 sf
->priv
->files_tree_check
= gtk_check_button_new();
518 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sf
->priv
->files_tree_check
),
520 gtk_widget_show (sf
->priv
->files_tree_check
);
521 gtk_tree_view_column_set_widget(column_select
,
522 sf
->priv
->files_tree_check
);
523 selection_renderer
= gtk_cell_renderer_toggle_new ();
524 gtk_tree_view_column_pack_start(column_select
,
527 gtk_tree_view_column_add_attribute(column_select
,
531 g_signal_connect (selection_renderer
, "toggled",
532 G_CALLBACK(search_files_check_column_toggled
), sf
);
533 gtk_tree_view_column_set_sort_column_id(column_count
,
536 column_filename
= gtk_tree_view_column_new();
537 gtk_tree_view_column_set_expand(column_filename
,
539 gtk_tree_view_column_set_title (column_filename
, _("Filename"));
540 filename_renderer
= gtk_cell_renderer_text_new();
541 gtk_tree_view_column_pack_start(column_filename
,
544 gtk_tree_view_column_add_attribute (column_filename
,
548 gtk_tree_view_column_add_attribute (column_filename
,
552 gtk_tree_view_column_set_sort_column_id(column_filename
,
554 error_renderer
= gtk_cell_renderer_pixbuf_new();
555 g_object_set (error_renderer
, "stock-id", GTK_STOCK_DIALOG_ERROR
, NULL
);
556 gtk_tree_view_column_pack_start(column_filename
,
559 gtk_tree_view_column_add_attribute (column_filename
,
564 column_count
= gtk_tree_view_column_new();
565 gtk_tree_view_column_set_title (column_count
, "#");
566 count_renderer
= gtk_cell_renderer_text_new();
567 gtk_tree_view_column_pack_start(column_count
,
570 gtk_tree_view_column_add_attribute (column_count
,
574 gtk_tree_view_column_set_cell_data_func(column_count
,
576 search_files_render_count
,
579 gtk_tree_view_column_set_sort_column_id(column_count
,
582 sf
->priv
->files_model
= GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS
,
591 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE (sf
->priv
->files_model
),
593 GTK_SORT_DESCENDING
);
595 g_signal_connect_swapped (sf
->priv
->files_model
,
597 G_CALLBACK (search_files_update_ui
),
599 g_signal_connect_swapped (sf
->priv
->files_model
,
601 G_CALLBACK (search_files_update_ui
),
603 g_signal_connect_swapped (sf
->priv
->files_model
,
605 G_CALLBACK (search_files_update_ui
),
608 gtk_tree_view_set_model (GTK_TREE_VIEW (sf
->priv
->files_tree
), sf
->priv
->files_model
);
609 gtk_tree_view_append_column(GTK_TREE_VIEW (sf
->priv
->files_tree
),
611 gtk_tree_view_append_column(GTK_TREE_VIEW (sf
->priv
->files_tree
),
613 gtk_tree_view_append_column(GTK_TREE_VIEW (sf
->priv
->files_tree
),
615 gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW (sf
->priv
->files_tree
),
616 COLUMN_ERROR_TOOLTIP
);
617 g_signal_connect (sf
->priv
->files_tree
, "row-activated",
618 G_CALLBACK (search_files_result_activated
), sf
);
622 search_files_init (SearchFiles
* sf
)
624 GError
* error
= NULL
;
625 GtkCellRenderer
* combo_renderer
;
628 G_TYPE_INSTANCE_GET_PRIVATE (sf
, SEARCH_TYPE_FILES
, SearchFilesPrivate
);
630 sf
->priv
->builder
= gtk_builder_new();
631 gtk_builder_add_from_file(sf
->priv
->builder
, BUILDER_FILE
, &error
);
635 g_warning("Could load ui file for search files: %s",
641 combo_renderer
= gtk_cell_renderer_text_new();
643 sf
->priv
->main_box
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
645 sf
->priv
->search_button
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
647 sf
->priv
->replace_button
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
649 sf
->priv
->find_files_button
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
650 "find_files_button"));
651 sf
->priv
->search_entry
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
653 sf
->priv
->replace_entry
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
655 sf
->priv
->project_combo
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
657 sf
->priv
->file_type_combo
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
659 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (sf
->priv
->file_type_combo
),
660 combo_renderer
, TRUE
);
661 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (sf
->priv
->file_type_combo
),
662 combo_renderer
, "text", 0);
664 sf
->priv
->case_check
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
666 sf
->priv
->regex_check
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
668 sf
->priv
->spinner_busy
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
671 sf
->priv
->files_tree
= GTK_WIDGET (gtk_builder_get_object(sf
->priv
->builder
,
674 search_files_init_tree(sf
);
676 gtk_builder_connect_signals(sf
->priv
->builder
, sf
);
678 g_object_ref (sf
->priv
->main_box
);
679 gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (sf
->priv
->main_box
)),
684 search_files_finalize (GObject
* object
)
686 SearchFiles
* sf
= SEARCH_FILES(object
);
688 g_object_unref (sf
->priv
->main_box
);
689 g_object_unref (sf
->priv
->builder
);
691 G_OBJECT_CLASS (search_files_parent_class
)->finalize (object
);
695 search_files_class_init (SearchFilesClass
* klass
)
697 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
698 GObjectClass
* parent_class
= G_OBJECT_CLASS (klass
);
700 object_class
->finalize
= search_files_finalize
;
702 g_type_class_add_private(klass
, sizeof(SearchFilesPrivate
));
706 search_files_project_loaded (SearchFiles
* sf
, IAnjutaProjectManager
*pm
, GError
* e
)
710 ianjuta_project_chooser_set_project_model(IANJUTA_PROJECT_CHOOSER(sf
->priv
->project_combo
),
712 ANJUTA_PROJECT_GROUP
,
718 search_files_new (AnjutaDocman
* docman
, SearchBox
* search_box
)
720 AnjutaShell
* shell
= docman
->shell
;
721 GObject
* obj
= g_object_new (SEARCH_TYPE_FILES
, NULL
);
722 SearchFiles
* sf
= SEARCH_FILES(obj
);
723 IAnjutaProjectManager
* pm
= anjuta_shell_get_interface(shell
,
724 IAnjutaProjectManager
,
726 search_files_project_loaded(sf
, pm
, NULL
);
727 g_signal_connect_swapped (pm
, "project-loaded",
728 G_CALLBACK (search_files_project_loaded
), NULL
);
730 anjuta_shell_add_widget(shell
, sf
->priv
->main_box
,
733 GTK_STOCK_FIND_AND_REPLACE
,
734 ANJUTA_SHELL_PLACEMENT_BOTTOM
, NULL
);
736 sf
->priv
->docman
= docman
;
737 sf
->priv
->search_box
= search_box
;
739 gtk_widget_show (sf
->priv
->main_box
);
741 search_files_update_ui(sf
);
746 void search_files_present (SearchFiles
* sf
)
748 g_return_if_fail (sf
!= NULL
&& SEARCH_IS_FILES(sf
));
750 gtk_entry_set_text (GTK_ENTRY (sf
->priv
->search_entry
),
751 search_box_get_search_string(sf
->priv
->search_box
));
752 gtk_entry_set_text (GTK_ENTRY (sf
->priv
->replace_entry
),
753 search_box_get_replace_string(sf
->priv
->search_box
));
755 anjuta_shell_present_widget(sf
->priv
->docman
->shell
,