1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Johannes Schmid 2010 <jhs@gnome.org>
6 * pkg-config-chooser 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 2 of the License, or
9 * (at your option) any later version.
11 * pkg-config-chooser 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 "anjuta-pkg-config-chooser.h"
21 #include <glib/gi18n.h>
22 #include <libanjuta/anjuta-launcher.h>
24 #define PKG_CONFIG_LIST_ALL "pkg-config --list-all"
41 struct _AnjutaPkgConfigChooserPrivate
43 AnjutaLauncher
* launcher
;
45 GtkTreeModelFilter
* filter_model
;
46 GtkTreeModelSort
* sort_model
;
48 gboolean selected_only
;
51 GList
* selected_cache
;
54 static guint pkg_config_chooser_signals
[LAST_SIGNAL
] = { 0 };
56 G_DEFINE_TYPE (AnjutaPkgConfigChooser
, anjuta_pkg_config_chooser
, GTK_TYPE_TREE_VIEW
);
59 filter_visible_func (GtkTreeModel
* model
,
63 AnjutaPkgConfigChooser
* chooser
= data
;
65 if (!chooser
->priv
->selected_only
)
70 gtk_tree_model_get (model
, iter
,
71 COLUMN_ACTIVE
, &show
, -1);
77 on_listall_output (AnjutaLauncher
* launcher
,
78 AnjutaLauncherOutputType output_type
,
79 const gchar
* chars
, gpointer user_data
)
82 const gchar
*curr_line
;
84 AnjutaPkgConfigChooser
* chooser
;
87 if (output_type
== ANJUTA_LAUNCHER_OUTPUT_STDERR
)
89 /* no way. We don't like errors on stderr... */
93 chooser
= ANJUTA_PKG_CONFIG_CHOOSER (user_data
);
95 store
= GTK_LIST_STORE (chooser
->priv
->model
);
96 lines
= g_strsplit (chars
, "\n", -1);
98 while ((curr_line
= lines
[i
++]) != NULL
)
103 pkgs
= g_strsplit (curr_line
, " ", 2);
105 /* just take the first token as it's the package-name */
109 if (pkgs
[0] == NULL
|| pkgs
[1] == NULL
) {
114 gtk_list_store_append (store
, &iter
);
115 gtk_list_store_set (store
, &iter
,
116 COLUMN_ACTIVE
, FALSE
,
117 COLUMN_NAME
, pkgs
[0],
118 COLUMN_DESCRIPTION
, g_strstrip(pkgs
[1]), -1);
125 on_listall_exit (AnjutaLauncher
* launcher
, int child_pid
,
126 int exit_status
, gulong time_taken_in_seconds
,
129 AnjutaPkgConfigChooser
* chooser
= ANJUTA_PKG_CONFIG_CHOOSER (user_data
);
131 g_signal_handlers_disconnect_by_func (launcher
, on_listall_exit
,
133 chooser
->priv
->scanning
= FALSE
;
135 if (exit_status
!= 0) g_warning(PKG_CONFIG_LIST_ALL
" exit with error code %d" , exit_status
);
137 anjuta_pkg_config_chooser_set_active_packages (chooser
, chooser
->priv
->selected_cache
);
138 g_list_free_full (chooser
->priv
->selected_cache
, g_free
);
139 chooser
->priv
->selected_cache
= NULL
;
141 g_clear_object (&chooser
->priv
->launcher
);
145 on_package_toggled (GtkCellRenderer
* renderer
,
147 AnjutaPkgConfigChooser
* chooser
)
149 GtkTreeIter sort_iter
;
150 GtkTreeIter filter_iter
;
155 GtkTreePath
* tree_path
= gtk_tree_path_new_from_string (path
);
157 gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser
->priv
->sort_model
),
158 &sort_iter
, tree_path
);
159 gtk_tree_model_sort_convert_iter_to_child_iter (chooser
->priv
->sort_model
,
160 &filter_iter
, &sort_iter
);
161 gtk_tree_model_filter_convert_iter_to_child_iter (chooser
->priv
->filter_model
,
162 &iter
, &filter_iter
);
163 g_object_get (renderer
, "active", &active
, NULL
);
167 gtk_list_store_set (GTK_LIST_STORE (chooser
->priv
->model
),
168 &iter
, COLUMN_ACTIVE
, active
, -1);
169 gtk_tree_model_get (chooser
->priv
->model
, &iter
,
170 COLUMN_NAME
, &package
, -1);
173 g_signal_emit_by_name (chooser
, "package-activated", package
, NULL
);
175 g_signal_emit_by_name (chooser
, "package-deactivated", package
, NULL
);
179 anjuta_pkg_config_chooser_init (AnjutaPkgConfigChooser
*chooser
)
181 GtkTreeViewColumn
* column
;
182 GtkCellRenderer
* renderer
;
184 chooser
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (chooser
, ANJUTA_TYPE_PKG_CONFIG_CHOOSER
,
185 AnjutaPkgConfigChooserPrivate
);
188 chooser
->priv
->model
= GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS
,
192 chooser
->priv
->filter_model
= GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (chooser
->priv
->model
,
194 gtk_tree_model_filter_set_visible_func (chooser
->priv
->filter_model
,
198 chooser
->priv
->sort_model
=
199 GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(chooser
->priv
->filter_model
)));
200 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (chooser
->priv
->sort_model
),
201 COLUMN_NAME
, GTK_SORT_ASCENDING
);
203 gtk_tree_view_set_model (GTK_TREE_VIEW (chooser
),
204 GTK_TREE_MODEL (chooser
->priv
->sort_model
));
207 renderer
= gtk_cell_renderer_toggle_new ();
208 g_signal_connect (renderer
, "toggled", G_CALLBACK(on_package_toggled
), chooser
);
209 column
= gtk_tree_view_column_new_with_attributes ("",
211 "active", COLUMN_ACTIVE
,
213 gtk_tree_view_append_column (GTK_TREE_VIEW (chooser
), column
);
215 renderer
= gtk_cell_renderer_text_new ();
216 column
= gtk_tree_view_column_new_with_attributes ("",
220 gtk_tree_view_append_column (GTK_TREE_VIEW (chooser
), column
);
221 renderer
= gtk_cell_renderer_text_new ();
222 column
= gtk_tree_view_column_new_with_attributes ("",
224 "text", COLUMN_DESCRIPTION
,
226 gtk_tree_view_append_column (GTK_TREE_VIEW (chooser
), column
);
227 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (chooser
), FALSE
);
229 gtk_tree_view_set_search_column (GTK_TREE_VIEW (chooser
),
232 /* Create launcher */
233 chooser
->priv
->scanning
= TRUE
;
234 chooser
->priv
->launcher
= anjuta_launcher_new ();
235 anjuta_launcher_set_check_passwd_prompt (chooser
->priv
->launcher
,
238 g_signal_connect (G_OBJECT (chooser
->priv
->launcher
), "child-exited",
239 G_CALLBACK (on_listall_exit
), chooser
);
241 anjuta_launcher_execute (chooser
->priv
->launcher
,
242 PKG_CONFIG_LIST_ALL
, on_listall_output
,
247 anjuta_pkg_config_chooser_finalize (GObject
*object
)
249 AnjutaPkgConfigChooser
*chooser
= ANJUTA_PKG_CONFIG_CHOOSER (object
);
251 g_object_unref (chooser
->priv
->model
);
252 g_object_unref (chooser
->priv
->filter_model
);
253 g_object_unref (chooser
->priv
->sort_model
);
255 if (chooser
->priv
->launcher
)
256 g_object_unref (chooser
->priv
->launcher
);
258 g_list_free_full (chooser
->priv
->selected_cache
, g_free
);
260 G_OBJECT_CLASS (anjuta_pkg_config_chooser_parent_class
)->finalize (object
);
264 anjuta_pkg_config_chooser_class_init (AnjutaPkgConfigChooserClass
*klass
)
266 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
268 object_class
->finalize
= anjuta_pkg_config_chooser_finalize
;
271 * AnjutaPkgConfigChooser::package-activated:
272 * @widget: the AnjutaPkgConfigChooser that received the signal
273 * @package: Name of the package that was activated
275 * The ::package-activated signal is emitted when a package is activated in the list
277 pkg_config_chooser_signals
[PACKAGE_ACTIVATED
] =
278 g_signal_new ("package-activated",
279 G_OBJECT_CLASS_TYPE (klass
),
281 G_STRUCT_OFFSET (AnjutaPkgConfigChooserClass
, package_activated
),
283 g_cclosure_marshal_VOID__STRING
,
287 * AnjutaPkgConfigChooser::package-deactivated:
288 * @widget: the AnjutaPkgConfigChooser that received the signal
289 * @package: Name of the package that was deactivated
291 * The ::package-activated signal is emitted when a package is deactivated in the list
293 pkg_config_chooser_signals
[PACKAGE_DEACTIVATED
] =
294 g_signal_new ("package-deactivated",
295 G_OBJECT_CLASS_TYPE (klass
),
297 G_STRUCT_OFFSET (AnjutaPkgConfigChooserClass
, package_deactivated
),
299 g_cclosure_marshal_VOID__STRING
,
303 g_type_class_add_private (klass
, sizeof(AnjutaPkgConfigChooserPrivate
));
307 * anjuta_pkg_config_chooser_new:
309 * Returns: A new AnjutaPkgConfigChooser widget
312 anjuta_pkg_config_chooser_new (void)
314 return GTK_WIDGET (g_object_new (ANJUTA_TYPE_PKG_CONFIG_CHOOSER
, NULL
));
318 * anjuta_pkg_config_chooser_get_active_packages:
319 * @chooser: A AnjutaPkgConfigChooser
321 * Return value: (element-type utf8) (transfer full):
322 * List of packages that are activated
325 anjuta_pkg_config_chooser_get_active_packages (AnjutaPkgConfigChooser
* chooser
)
327 GList
* packages
= NULL
;
330 g_return_val_if_fail (ANJUTA_IS_PKG_CONFIG_CHOOSER (chooser
), NULL
);
332 if (gtk_tree_model_get_iter_first (chooser
->priv
->model
, &iter
))
338 gtk_tree_model_get (chooser
->priv
->model
, &iter
,
339 COLUMN_NAME
, &model_pkg
,
340 COLUMN_ACTIVE
, &active
, -1);
343 packages
= g_list_append (packages
, model_pkg
);
346 while (gtk_tree_model_iter_next (chooser
->priv
->model
,
353 * anjuta_pkg_config_chooser_get_active_packages:
354 * @chooser: A AnjutaPkgConfigChooser
355 * @packages: (element-type utf8) (transfer full): List of packages to be activated in the list
359 anjuta_pkg_config_chooser_set_active_packages (AnjutaPkgConfigChooser
* chooser
, GList
* packages
)
364 g_return_if_fail (ANJUTA_IS_PKG_CONFIG_CHOOSER (chooser
));
366 /* Deselect all packages */
367 if (gtk_tree_model_get_iter_first (chooser
->priv
->model
, &iter
))
371 gtk_list_store_set (GTK_LIST_STORE (chooser
->priv
->model
), &iter
,
372 COLUMN_ACTIVE
, FALSE
, -1);
374 while (gtk_tree_model_iter_next (chooser
->priv
->model
,
378 for (pkg
= packages
; pkg
!= NULL
; pkg
= g_list_next (pkg
))
380 if (chooser
->priv
->scanning
)
382 chooser
->priv
->selected_cache
= g_list_append (chooser
->priv
->selected_cache
,
383 g_strdup(pkg
->data
));
385 else if (gtk_tree_model_get_iter_first (chooser
->priv
->model
, &iter
))
390 gtk_tree_model_get (chooser
->priv
->model
, &iter
,
391 COLUMN_NAME
, &model_pkg
, -1);
392 if (g_str_equal (model_pkg
, pkg
->data
))
394 gtk_list_store_set (GTK_LIST_STORE (chooser
->priv
->model
), &iter
,
395 COLUMN_ACTIVE
, TRUE
, -1);
399 while (gtk_tree_model_iter_next (chooser
->priv
->model
,
406 * anjuta_pkg_config_chooser_show_active_only:
407 * @chooser: A AnjutaPkgConfigChooser
408 * @show_selected: whether to show only activated packages
410 * Show activated packages only, this is mainly useful when the tree is set
411 * insensitive but the user should be able to see which packages have been activated
414 anjuta_pkg_config_chooser_show_active_only (AnjutaPkgConfigChooser
* chooser
, gboolean show_selected
)
416 g_return_if_fail (ANJUTA_IS_PKG_CONFIG_CHOOSER (chooser
));
418 chooser
->priv
->selected_only
= show_selected
;
419 gtk_tree_model_filter_refilter (chooser
->priv
->filter_model
);
423 * anjuta_pkg_config_chooser_show_active_column:
424 * @chooser: A AnjutaPkgConfigChooser
425 * @show_column: whether the active column should be shown
427 * Can be used to hide the active column in situation where you are more interested
428 * in the selection then in the activated packages.
431 anjuta_pkg_config_chooser_show_active_column (AnjutaPkgConfigChooser
* chooser
, gboolean show_column
)
433 GtkTreeViewColumn
* column
;
435 g_return_if_fail (ANJUTA_IS_PKG_CONFIG_CHOOSER (chooser
));
437 column
= gtk_tree_view_get_column (GTK_TREE_VIEW (chooser
), COLUMN_ACTIVE
);
438 gtk_tree_view_column_set_visible (column
, show_column
);
442 * anjuta_pkg_config_chooser_get_selected_package:
443 * @chooser: A AnjutaPkgConfigChooser
445 * Return value: the currently selected packages in the list
449 anjuta_pkg_config_chooser_get_selected_package (AnjutaPkgConfigChooser
* chooser
)
451 GtkTreeIter sort_iter
;
452 GtkTreeSelection
* selection
;
454 g_return_val_if_fail (ANJUTA_IS_PKG_CONFIG_CHOOSER (chooser
), NULL
);
456 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser
));
458 if (gtk_tree_selection_get_selected (selection
, NULL
, &sort_iter
))
461 GtkTreeIter filter_iter
;
463 gtk_tree_model_sort_convert_iter_to_child_iter (chooser
->priv
->sort_model
,
464 &filter_iter
, &sort_iter
);
465 gtk_tree_model_filter_convert_iter_to_child_iter (chooser
->priv
->filter_model
,
466 &iter
, &filter_iter
);
467 gtk_tree_model_get (chooser
->priv
->model
, &iter
, COLUMN_NAME
, &package
, -1);