2006-03-29 20:19:01 +00:00
|
|
|
<chapter id="gtk-migrating-GtkRecentChooser">
|
|
|
|
<chapterinfo>
|
|
|
|
<author>
|
|
|
|
<firstname>Emmanuele</firstname>
|
|
|
|
<lastname>Bassi</lastname>
|
|
|
|
<affiliation>
|
|
|
|
<address>
|
|
|
|
<email>ebassi@gmail.com</email>
|
|
|
|
</address>
|
|
|
|
</affiliation>
|
|
|
|
</author>
|
|
|
|
</chapterinfo>
|
|
|
|
|
|
|
|
<title>Migrating from EggRecent to GtkRecentChooser</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Since version 2.10, GTK+ provides a way of handling the recently used
|
|
|
|
documents. It is similar to the code that has lived inside the libegg
|
|
|
|
library and has been incorporated by many applications. The GTK+ version
|
|
|
|
aims to completely replace that code, and offers many distinctive features
|
|
|
|
that improve the registration and visualization of the recently used
|
|
|
|
documents, such as:
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>
|
|
|
|
Better performances while reading and writing the list of recently used
|
|
|
|
files
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
More meta-data available for each recent document, like the
|
|
|
|
applications that have registered a document inside the list, the last
|
|
|
|
time and the number of times the same application did register a
|
|
|
|
document inside the list, an optional user readable name and
|
|
|
|
description of the document
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
Improved the ability to sort and filter the documents, also using
|
|
|
|
custom sorting and filtering functions
|
|
|
|
</para></listitem>
|
|
|
|
<listitem><para>
|
|
|
|
New widgets for displaying the list, and better integration with
|
|
|
|
current #GtkFileChooser and #GtkUIManager widgets
|
|
|
|
</para></listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<section id="gtkrecent-manager">
|
|
|
|
<title>Managing the Recently Used Documents</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
#GtkRecentManager is used to manage the Recently Used Documents. To
|
|
|
|
create a new #GtkRecentManager, you simply call gtk_recent_manager_new().
|
|
|
|
Like the <structname>EggRecentModel</structname> inside EggRecent, the
|
|
|
|
#GtkRecentManager loads the list of the recent documents and notifies
|
|
|
|
you of changes inside the list.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
To add a document to the list, you can use gtk_recent_manager_add_item(),
|
|
|
|
like:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GtkRecentManager *manager;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
2006-04-16 04:08:54 +00:00
|
|
|
manager = gtk_recent_manager_new (<!-- -->);
|
2006-03-29 20:19:01 +00:00
|
|
|
|
|
|
|
gtk_recent_manager_add_item (manager, document_uri, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
g_warning ("Unable to add '%s' to the list of recently used documents: %s\n",
|
|
|
|
document_uri,
|
|
|
|
error->message);
|
|
|
|
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (manager);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
The gtk_recent_manager_add_item() function will try and guess some of the
|
|
|
|
meta-data associated to a URI. If you know some of meta-data about the
|
|
|
|
document yourself, set the desired fields of a #GtkRecentData structure
|
|
|
|
and pass it to the gtk_recent_manager_add_full() function instead:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GtkRecentManager *manager;
|
|
|
|
GtkRecentData *recent_data;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
2006-04-16 04:08:54 +00:00
|
|
|
manager = gtk_recent_manager_new (<!-- -->);
|
2006-03-29 20:19:01 +00:00
|
|
|
|
|
|
|
recent_data = g_new0 (GtkRecentData, 1);
|
|
|
|
/* the user visible name of the document (maybe its title); should
|
|
|
|
* be preferred when displaying the item into the list
|
|
|
|
*/
|
|
|
|
recent_data->display_name = document_name;
|
|
|
|
|
|
|
|
/* the MIME type is mandatory */
|
|
|
|
recent_data->mime_type = document_mime_type;
|
|
|
|
|
|
|
|
/* the name of the application that is registering the document
|
|
|
|
* (also mandatory); usually, the same name you used with
|
2006-04-16 04:08:54 +00:00
|
|
|
* the g_set_application_name (<!-- -->) function.
|
2006-03-29 20:19:01 +00:00
|
|
|
*/
|
|
|
|
recent_data-&app_name = APP_NAME;
|
|
|
|
|
|
|
|
/* the command to open a file; the %u string will be automagically
|
|
|
|
* expanded to the document's URI when getting the application's
|
|
|
|
* command line from the GtkRecentInfo object with
|
2006-04-16 04:08:54 +00:00
|
|
|
* gtk_recent_info_get_application_info (<!-- -->)
|
2006-03-29 20:19:01 +00:00
|
|
|
*/
|
2006-04-16 04:08:54 +00:00
|
|
|
recent_data-&app_exec = g_strjoin (" ", g_get_prgname (<!-- -->), "--open-file", "%u", NULL);
|
2006-03-29 20:19:01 +00:00
|
|
|
|
|
|
|
gtk_recent_manager_add_full (manager, document_uri, recent_data, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
/* warn about the error */
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (recent_data->app_exec);
|
|
|
|
g_free (recent_data);
|
|
|
|
g_object_unref (manager);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Getting the list of items is also similar to
|
|
|
|
<structname>EggRecentModel</structname>; the GtkRecentInfo data is
|
|
|
|
allocated at look up time in order not to waste memory keeping it
|
|
|
|
around, so you must remember to free the data inside the list and then
|
|
|
|
the list itself when you are done using it:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GList *recent_items, *l;
|
|
|
|
|
|
|
|
recent_items = gtk_recent_manager_get_items (manager);
|
|
|
|
for (l = recent_items; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
GtkRecentInfo *recent_info = l->data;
|
|
|
|
|
|
|
|
do_something_with_the_item (recent_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free everything and the list */
|
|
|
|
g_list_foreach (recent_items, (GFunc) gtk_recent_info_unref, NULL);
|
|
|
|
g_list_free (recent_items);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
You can also look up a single item:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GtkRecentInfo *recent_info;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
recent_info = gtk_recent_manager_lookup_item (manager, document_uri, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
display_error (error);
|
|
|
|
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do_something_with_the_item (recent_info);
|
|
|
|
|
|
|
|
gtk_recent_info_unref (recent_info);
|
|
|
|
}
|
|
|
|
</programlisting></informalexample>
|
|
|
|
The #GtkRecentInfo is a reference counted boxed type, and it holds all
|
|
|
|
the meta-data of a recently used document, like its display name, its
|
|
|
|
description, the list of each application that has registered the
|
|
|
|
document or the list of groups to which the document belong.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</section> <!-- gtkrecent-manager -->
|
|
|
|
|
|
|
|
<section id="gtkrecent-chooser">
|
|
|
|
<title>Displaying the Recently Used Documents</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Displaying the Recently Used Documents list is handled by any widget
|
|
|
|
implementing the #GtkRecentChooser interface. These widgets also handle
|
|
|
|
the sorting and filtering of the list; they will create their own
|
|
|
|
#GtkRecentManager objects by default:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GtkWidget *chooser;
|
|
|
|
gint response;
|
|
|
|
|
|
|
|
/* create a new dialog with the recently used documents list shown
|
|
|
|
* using a GtkTreeView widget
|
|
|
|
*/
|
|
|
|
chooser = gtk_recent_chooser_dialog_new ("Recent Documents",
|
|
|
|
parent_window,
|
|
|
|
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
|
|
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
/* set the sorting order to "most recently used first" */
|
|
|
|
gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_MRU);
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (chooser));
|
|
|
|
if (response == GTK_RESPONSE_OK)
|
|
|
|
{
|
|
|
|
GtkRecentInfo *info;
|
|
|
|
|
|
|
|
info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (chooser));
|
|
|
|
do_something_with_the_item (info);
|
|
|
|
|
|
|
|
gtk_recent_info_unref (info);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_destroy (chooser);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</section> <!-- gtkrecent-chooser -->
|
|
|
|
|
|
|
|
<section id="gtkrecent-advanced">
|
|
|
|
<title>Advanced usage</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The #GtkRecentChooser widgets might display items sorted and filtered,
|
|
|
|
either with already supplied or custom sorting and filtering functions.
|
|
|
|
The biggest difference from the <structname>EggRecentView</structname>
|
|
|
|
widgets in EggRecent is that the #GtkRecentChooser widgets will use
|
|
|
|
their own copy of the list and will apply the sorting and filtering
|
|
|
|
functions only on the copy; this allows the creation of many viewers
|
|
|
|
with a single controller, like using many #GtkTreeView with a single
|
|
|
|
#GtkTreeModel instance.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Available sorting methods are:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
/* no sorting */
|
|
|
|
gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_NONE);
|
|
|
|
|
|
|
|
/* most recently used first */
|
|
|
|
gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_MRU);
|
|
|
|
|
|
|
|
/* most recently used last */
|
|
|
|
gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser), GTK_RECENT_SORT_LRU);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
You can create your own sorting function, and the use the
|
|
|
|
GTK_RECENT_SORT_CUSTOM method:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
/* custom sorting function, based on the registration count
|
|
|
|
* (most used first)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sort_by_usage_count (GtkRecentInfo *a,
|
|
|
|
GtkRecentInfo *b,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
gint count_a, count_b;
|
|
|
|
|
|
|
|
count_a = count_b = 0;
|
|
|
|
|
|
|
|
if (gtk_recent_info_has_application (a, APP_NAME))
|
|
|
|
gtk_recent_info_get_application_info (a, APP_NAME, NULL, &count_a, NULL);
|
|
|
|
|
|
|
|
if (gtk_recent_info_has_application (b, APP_NAME))
|
|
|
|
gtk_recent_info_get_application_info (b, APP_NAME, NULL, &count_b, NULL);
|
|
|
|
|
|
|
|
return count_a < count_b;
|
|
|
|
}
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
/* set custom sorting and set the custom sorting function */
|
|
|
|
gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (chooser),
|
|
|
|
GTK_RECENT_SORT_CUSTOM);
|
|
|
|
gtk_recent_chooser_set_sort_func (GTK_RECENT_CHOOSER,
|
|
|
|
sort_by_usage_count,
|
|
|
|
NULL, /* sort function data */
|
|
|
|
NULL /* destroy notify for the data */);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
Filtering is done using the #GtkRecentFilter object, similar to the
|
|
|
|
#GtkFileFilter object used by the #GtkFileChooser widgets. The
|
|
|
|
#GtkRecentFilter object has a set of pre-defined options based on the
|
|
|
|
meta-data exposed by the #GtkRecentInfo object. It also allows custom
|
|
|
|
filtering function:
|
|
|
|
<informalexample><programlisting>
|
|
|
|
GtkRecentFilter *filter;
|
|
|
|
|
2006-04-16 04:08:54 +00:00
|
|
|
filter = gtk_recent_filter_new (<!-- -->);
|
2006-03-29 20:19:01 +00:00
|
|
|
|
|
|
|
/* set the user visible name of the filter */
|
|
|
|
gtk_recent_filter_set_name (filter, "Since Last Month");
|
|
|
|
|
|
|
|
/* set the maximum age of a recently used document */
|
|
|
|
gtk_recent_filter_set_age (filter, 31);
|
|
|
|
|
|
|
|
/* the chooser takes the ownership of the object */
|
|
|
|
gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (chooser), filter);
|
|
|
|
|
|
|
|
/* set the currently used filter */
|
|
|
|
gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (chooser), filter);
|
|
|
|
|
2006-04-16 04:08:54 +00:00
|
|
|
filter = gtk_recent_filter_new (<!-- -->);
|
2006-03-29 20:19:01 +00:00
|
|
|
gtk_recent_filter_set_name (filter, "Every text file");
|
|
|
|
gtk_recent_filter_set_mime_type (filter, "text/plain");
|
|
|
|
|
|
|
|
gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (chooser), filter);
|
|
|
|
</programlisting></informalexample>
|
|
|
|
The #GtkRecentChooserWidget and #GtkRecentChooserDialog widgets allow
|
|
|
|
multiple filters and the selection of an appropriate one; the
|
|
|
|
#GtkRecentChooserMenu widget allows just a single filter object.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</section> <!-- gtkrecent-advanced -->
|
|
|
|
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Local variables:
|
|
|
|
mode: sgml
|
|
|
|
sgml-parent-document: ("gtk-docs.sgml" "book" "part" "chapter")
|
|
|
|
End:
|
|
|
|
-->
|