thunar-usagebars/thunar/thunar-chooser-model.c

439 lines
12 KiB
C
Raw Permalink Normal View History

/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>.
* Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "thunar/thunar-chooser-model.h"
#include "thunar/thunar-gobject-extensions.h"
#include "thunar/thunar-icon-factory.h"
#include "thunar/thunar-private.h"
/* Property identifiers */
enum
{
PROP_0,
PROP_CONTENT_TYPE,
};
static void
thunar_chooser_model_constructed (GObject *object);
static void
thunar_chooser_model_finalize (GObject *object);
static void
thunar_chooser_model_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void
thunar_chooser_model_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void
thunar_chooser_model_reload (ThunarChooserModel *model);
struct _ThunarChooserModelClass
{
GtkTreeStoreClass __parent__;
};
struct _ThunarChooserModel
{
GtkTreeStore __parent__;
gchar *content_type;
};
G_DEFINE_TYPE (ThunarChooserModel, thunar_chooser_model, GTK_TYPE_TREE_STORE)
static void
thunar_chooser_model_class_init (ThunarChooserModelClass *klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunar_chooser_model_finalize;
gobject_class->constructed = thunar_chooser_model_constructed;
gobject_class->get_property = thunar_chooser_model_get_property;
gobject_class->set_property = thunar_chooser_model_set_property;
/**
* ThunarChooserModel::content-type:
*
* The content type for the model.
**/
g_object_class_install_property (gobject_class,
PROP_CONTENT_TYPE,
g_param_spec_string ("content-type",
"content-type",
"content-type",
NULL,
G_PARAM_CONSTRUCT_ONLY | EXO_PARAM_READWRITE));
}
static void
thunar_chooser_model_init (ThunarChooserModel *model)
{
/* allocate the types array for the columns */
GType column_types[THUNAR_CHOOSER_MODEL_N_COLUMNS] = {
G_TYPE_STRING,
G_TYPE_ICON,
G_TYPE_APP_INFO,
PANGO_TYPE_STYLE,
PANGO_TYPE_WEIGHT,
};
/* register the column types */
gtk_tree_store_set_column_types (GTK_TREE_STORE (model),
G_N_ELEMENTS (column_types),
column_types);
}
static void
thunar_chooser_model_constructed (GObject *object)
{
ThunarChooserModel *model = THUNAR_CHOOSER_MODEL (object);
/* start to load the applications installed on the system */
thunar_chooser_model_reload (model);
}
static void
thunar_chooser_model_finalize (GObject *object)
{
ThunarChooserModel *model = THUNAR_CHOOSER_MODEL (object);
/* free the content type */
g_free (model->content_type);
(*G_OBJECT_CLASS (thunar_chooser_model_parent_class)->finalize) (object);
}
static void
thunar_chooser_model_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ThunarChooserModel *model = THUNAR_CHOOSER_MODEL (object);
switch (prop_id)
{
case PROP_CONTENT_TYPE:
g_value_set_string (value, thunar_chooser_model_get_content_type (model));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
thunar_chooser_model_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ThunarChooserModel *model = THUNAR_CHOOSER_MODEL (object);
switch (prop_id)
{
case PROP_CONTENT_TYPE:
model->content_type = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
thunar_chooser_model_append (ThunarChooserModel *model,
const gchar *title,
const gchar *icon_name,
GList *app_infos)
{
GtkTreeIter child_iter;
GtkTreeIter parent_iter;
GIcon *icon;
GList *lp;
gboolean inserted_infos = FALSE;
_thunar_return_if_fail (THUNAR_IS_CHOOSER_MODEL (model));
_thunar_return_if_fail (title != NULL);
_thunar_return_if_fail (icon_name != NULL);
icon = g_themed_icon_new (icon_name);
gtk_tree_store_append (GTK_TREE_STORE (model), &parent_iter, NULL);
gtk_tree_store_set (GTK_TREE_STORE (model), &parent_iter,
THUNAR_CHOOSER_MODEL_COLUMN_NAME, title,
THUNAR_CHOOSER_MODEL_COLUMN_ICON, icon,
THUNAR_CHOOSER_MODEL_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
g_object_unref (icon);
if (G_LIKELY (app_infos != NULL))
{
/* insert the program items */
for (lp = app_infos; lp != NULL; lp = lp->next)
{
if (!thunar_g_app_info_should_show (lp->data))
continue;
/* append the tree row with the program data */
gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &parent_iter);
gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter,
THUNAR_CHOOSER_MODEL_COLUMN_NAME, g_app_info_get_name (lp->data),
THUNAR_CHOOSER_MODEL_COLUMN_ICON, g_app_info_get_icon (lp->data),
THUNAR_CHOOSER_MODEL_COLUMN_APPLICATION, lp->data,
THUNAR_CHOOSER_MODEL_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
-1);
inserted_infos = TRUE;
}
}
if (!inserted_infos)
{
/* tell the user that we don't have any applications for this category */
gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &parent_iter);
gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter,
THUNAR_CHOOSER_MODEL_COLUMN_NAME, _("None available"),
THUNAR_CHOOSER_MODEL_COLUMN_STYLE, PANGO_STYLE_ITALIC,
THUNAR_CHOOSER_MODEL_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
-1);
}
}
static gint
compare_app_infos (gconstpointer a,
gconstpointer b)
{
return g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b)) ? 0 : 1;
}
static gint
sort_app_infos (gconstpointer a,
gconstpointer b)
{
return g_utf8_collate (g_app_info_get_name (G_APP_INFO (a)),
g_app_info_get_name (G_APP_INFO (b)));
}
static void
thunar_chooser_model_reload (ThunarChooserModel *model)
{
GList *all;
GList *lp;
GList *other = NULL;
GList *recommended;
GList *default_app = NULL;
_thunar_return_if_fail (THUNAR_IS_CHOOSER_MODEL (model));
_thunar_return_if_fail (model->content_type != NULL);
gtk_tree_store_clear (GTK_TREE_STORE (model));
/* get default application for this type and append it in @default_app */
default_app = g_list_prepend (default_app, g_app_info_get_default_for_type (model->content_type, FALSE));
/* If default application was already selected, then display it in Treeview */
if (default_app->data)
{
thunar_chooser_model_append (model,
_("Default Application"),
"org.xfce.settings.default-applications",
default_app);
}
/* check if we have any applications for this type */
recommended = g_app_info_get_all_for_type (model->content_type);
/* append them as recommended */
recommended = g_list_sort (recommended, sort_app_infos);
thunar_chooser_model_append (model,
_("Recommended Applications"),
"org.xfce.settings.default-applications",
recommended);
all = g_app_info_get_all ();
for (lp = all; lp != NULL; lp = lp->next)
{
if (g_list_find_custom (recommended,
lp->data,
compare_app_infos)
== NULL)
{
other = g_list_prepend (other, lp->data);
}
}
/* append the other applications */
other = g_list_sort (other, sort_app_infos);
thunar_chooser_model_append (model,
_("Other Applications"),
"gnome-applications",
other);
if (default_app->data != NULL)
g_object_unref (default_app->data);
g_list_free (default_app);
g_list_free_full (recommended, g_object_unref);
g_list_free_full (all, g_object_unref);
g_list_free (other);
}
/**
* thunar_chooser_model_new:
* @content_type : the content type for this model.
*
* Allocates a new #ThunarChooserModel for @content_type.
*
* Return value: the newly allocated #ThunarChooserModel.
**/
ThunarChooserModel *
thunar_chooser_model_new (const gchar *content_type)
{
return g_object_new (THUNAR_TYPE_CHOOSER_MODEL,
"content-type", content_type,
NULL);
}
/**
* thunar_chooser_model_get_content_type:
* @model : a #ThunarChooserModel.
*
* Returns the content type for @model.
*
* Return value: the content type for @model.
**/
const gchar *
thunar_chooser_model_get_content_type (ThunarChooserModel *model)
{
_thunar_return_val_if_fail (THUNAR_IS_CHOOSER_MODEL (model), NULL);
return model->content_type;
}
/**
* thunar_chooser_model_remove:
* @model : a #ThunarChooserModel.
* @iter : the #GtkTreeIter for the application to remove.
* @delete : whether delete or just dissociate the application.
* @error : return location for errors or %NULL.
*
* Tries to remove or dissociate the application at the specified
* @iter from the systems application database.
*
* Return value: %TRUE on success, %FALSE otherwise.
**/
gboolean
thunar_chooser_model_remove (ThunarChooserModel *model,
GtkTreeIter *iter,
gboolean delete,
GError **error)
{
GAppInfo *app_info;
gboolean succeed;
_thunar_return_val_if_fail (THUNAR_IS_CHOOSER_MODEL (model), FALSE);
_thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
_thunar_return_val_if_fail (gtk_tree_store_iter_is_valid (GTK_TREE_STORE (model), iter), FALSE);
/* determine the app info for the iter */
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
THUNAR_CHOOSER_MODEL_COLUMN_APPLICATION, &app_info,
-1);
if (G_UNLIKELY (app_info == NULL))
return TRUE;
/* try to remove support for this content type */
succeed = g_app_info_remove_supports_type (app_info,
model->content_type,
error);
/* try to delete the file */
if (delete &&succeed && g_app_info_delete (app_info))
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Failed to remove \"%s\"."),
g_app_info_get_id (app_info));
}
/* clean up */
g_object_unref (app_info);
/* if the removal was successfull, delete the row from the model */
if (G_LIKELY (succeed))
gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
return succeed;
}