2020-06-27 04:38:20 +00:00
/* Lists/Words
2020-09-13 18:59:33 +00:00
* # Keywords : GtkListView , GtkFilterListModel
2020-06-27 04:38:20 +00:00
*
* This demo shows filtering a long list - of words .
*
* You should have the file ` / usr / share / dict / words ` installed for
* this demo to work .
*/
# include <gtk/gtk.h>
static GtkWidget * window = NULL ;
2020-06-30 14:38:59 +00:00
static GtkWidget * progress ;
2020-06-27 04:38:20 +00:00
const char * factory_text =
" <?xml version='1.0' encoding='UTF-8'?> \n "
" <interface> \n "
" <template class='GtkListItem'> \n "
" <property name='child'> \n "
2022-06-07 04:09:37 +00:00
" <object class='GtkInscription'> \n "
2020-06-30 11:51:59 +00:00
" <property name='xalign'>0</property> \n "
2022-06-07 04:09:37 +00:00
" <binding name='text'> \n "
2020-06-27 04:38:20 +00:00
" <lookup name='string' type='GtkStringObject'> \n "
" <lookup name='item'>GtkListItem</lookup> \n "
" </lookup> \n "
" </binding> \n "
" </object> \n "
" </property> \n "
" </template> \n "
" </interface> \n " ;
static void
2020-06-30 02:03:07 +00:00
update_title_cb ( GtkFilterListModel * model )
2020-06-27 04:38:20 +00:00
{
2020-06-30 14:38:59 +00:00
guint total ;
2020-06-27 04:38:20 +00:00
char * title ;
2020-06-30 02:03:07 +00:00
guint pending ;
2020-06-27 04:38:20 +00:00
2020-06-30 14:38:59 +00:00
total = g_list_model_get_n_items ( gtk_filter_list_model_get_model ( model ) ) ;
2020-06-30 02:03:07 +00:00
pending = gtk_filter_list_model_get_pending ( model ) ;
2020-06-30 14:38:59 +00:00
title = g_strdup_printf ( " %u lines " , g_list_model_get_n_items ( G_LIST_MODEL ( model ) ) ) ;
gtk_widget_set_visible ( progress , pending ! = 0 ) ;
gtk_progress_bar_set_fraction ( GTK_PROGRESS_BAR ( progress ) , ( total - pending ) / ( double ) total ) ;
2020-06-30 02:03:07 +00:00
gtk_window_set_title ( GTK_WINDOW ( window ) , title ) ;
2020-06-27 04:38:20 +00:00
g_free ( title ) ;
}
2020-06-30 21:31:49 +00:00
static void
read_lines_cb ( GObject * object ,
GAsyncResult * result ,
gpointer data )
{
GBufferedInputStream * stream = G_BUFFERED_INPUT_STREAM ( object ) ;
GtkStringList * stringlist = data ;
GError * error = NULL ;
gsize size ;
GPtrArray * lines ;
gssize n_filled ;
const char * buffer , * newline ;
n_filled = g_buffered_input_stream_fill_finish ( stream , result , & error ) ;
if ( n_filled < 0 )
{
g_print ( " Could not read data: %s \n " , error - > message ) ;
g_clear_error ( & error ) ;
2020-08-07 00:49:41 +00:00
g_object_unref ( stringlist ) ;
2020-06-30 21:31:49 +00:00
return ;
}
buffer = g_buffered_input_stream_peek_buffer ( stream , & size ) ;
if ( n_filled = = 0 )
{
if ( size )
gtk_string_list_take ( stringlist , g_utf8_make_valid ( buffer , size ) ) ;
2020-08-07 00:49:41 +00:00
g_object_unref ( stringlist ) ;
2020-06-30 21:31:49 +00:00
return ;
}
lines = NULL ;
while ( ( newline = memchr ( buffer , ' \n ' , size ) ) )
{
if ( newline > buffer )
{
if ( lines = = NULL )
lines = g_ptr_array_new_with_free_func ( g_free ) ;
g_ptr_array_add ( lines , g_utf8_make_valid ( buffer , newline - buffer ) ) ;
}
if ( g_input_stream_skip ( G_INPUT_STREAM ( stream ) , newline - buffer + 1 , NULL , & error ) < 0 )
{
g_clear_error ( & error ) ;
break ;
}
buffer = g_buffered_input_stream_peek_buffer ( stream , & size ) ;
}
if ( lines = = NULL )
{
g_buffered_input_stream_set_buffer_size ( stream , g_buffered_input_stream_get_buffer_size ( stream ) + 4096 ) ;
}
else
{
g_ptr_array_add ( lines , NULL ) ;
gtk_string_list_splice ( stringlist , g_list_model_get_n_items ( G_LIST_MODEL ( stringlist ) ) , 0 , ( const char * * ) lines - > pdata ) ;
g_ptr_array_free ( lines , TRUE ) ;
}
g_buffered_input_stream_fill_async ( stream , - 1 , G_PRIORITY_HIGH_IDLE , NULL , read_lines_cb , data ) ;
}
static void
file_is_open_cb ( GObject * file ,
GAsyncResult * result ,
gpointer data )
{
GError * error = NULL ;
GFileInputStream * file_stream ;
GBufferedInputStream * stream ;
file_stream = g_file_read_finish ( G_FILE ( file ) , result , & error ) ;
if ( file_stream = = NULL )
{
g_print ( " Could not open file: %s \n " , error - > message ) ;
g_error_free ( error ) ;
2020-08-07 00:49:41 +00:00
g_object_unref ( data ) ;
2020-06-30 21:31:49 +00:00
return ;
}
stream = G_BUFFERED_INPUT_STREAM ( g_buffered_input_stream_new ( G_INPUT_STREAM ( file_stream ) ) ) ;
g_buffered_input_stream_fill_async ( stream , - 1 , G_PRIORITY_HIGH_IDLE , NULL , read_lines_cb , data ) ;
g_object_unref ( stream ) ;
}
static void
load_file ( GtkStringList * list ,
GFile * file )
{
gtk_string_list_splice ( list , 0 , g_list_model_get_n_items ( G_LIST_MODEL ( list ) ) , NULL ) ;
2020-08-07 00:49:41 +00:00
g_file_read_async ( file , G_PRIORITY_HIGH_IDLE , NULL , file_is_open_cb , g_object_ref ( list ) ) ;
2020-06-30 21:31:49 +00:00
}
static void
2020-12-04 03:31:05 +00:00
open_response_cb ( GtkNativeDialog * dialog ,
int response ,
GtkStringList * stringlist )
2020-06-30 21:31:49 +00:00
{
2020-12-04 03:31:05 +00:00
gtk_native_dialog_hide ( dialog ) ;
2020-06-30 21:31:49 +00:00
2020-12-02 19:15:28 +00:00
if ( response = = GTK_RESPONSE_ACCEPT )
2020-06-30 21:31:49 +00:00
{
2020-12-02 19:15:28 +00:00
GFile * file ;
file = gtk_file_chooser_get_file ( GTK_FILE_CHOOSER ( dialog ) ) ;
2020-06-30 21:31:49 +00:00
load_file ( stringlist , file ) ;
g_object_unref ( file ) ;
}
2020-12-02 19:15:28 +00:00
2020-12-04 03:31:05 +00:00
gtk_native_dialog_destroy ( dialog ) ;
2020-12-02 19:15:28 +00:00
}
static void
file_open_cb ( GtkWidget * button ,
GtkStringList * stringlist )
{
2020-12-04 03:31:05 +00:00
GtkFileChooserNative * dialog ;
2020-12-02 19:15:28 +00:00
2020-12-04 03:31:05 +00:00
dialog = gtk_file_chooser_native_new ( " Open file " ,
2020-12-02 19:15:28 +00:00
GTK_WINDOW ( gtk_widget_get_root ( button ) ) ,
GTK_FILE_CHOOSER_ACTION_OPEN ,
2020-12-04 03:31:05 +00:00
" _Load " ,
" _Cancel " ) ;
gtk_native_dialog_set_modal ( GTK_NATIVE_DIALOG ( dialog ) , TRUE ) ;
2020-12-02 19:15:28 +00:00
g_signal_connect ( dialog , " response " , G_CALLBACK ( open_response_cb ) , stringlist ) ;
2020-12-04 03:31:05 +00:00
gtk_native_dialog_show ( GTK_NATIVE_DIALOG ( dialog ) ) ;
2020-06-30 21:31:49 +00:00
}
2020-06-27 04:38:20 +00:00
GtkWidget *
do_listview_words ( GtkWidget * do_widget )
{
if ( window = = NULL )
{
2020-06-30 14:38:59 +00:00
GtkWidget * header , * listview , * sw , * vbox , * search_entry , * open_button , * overlay ;
2020-06-27 04:38:20 +00:00
GtkFilterListModel * filter_model ;
GtkStringList * stringlist ;
GtkFilter * filter ;
2020-06-30 21:31:49 +00:00
GFile * file ;
2020-06-27 04:38:20 +00:00
2020-06-30 21:31:49 +00:00
file = g_file_new_for_path ( " /usr/share/dict/words " ) ;
if ( g_file_query_exists ( file , NULL ) )
2020-06-27 04:38:20 +00:00
{
2020-06-30 21:31:49 +00:00
stringlist = gtk_string_list_new ( NULL ) ;
load_file ( stringlist , file ) ;
2020-06-27 04:38:20 +00:00
}
else
{
2020-06-30 21:31:49 +00:00
char * * words ;
2020-06-27 04:38:20 +00:00
words = g_strsplit ( " lorem ipsum dolor sit amet consectetur adipisci elit sed eiusmod tempor incidunt labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat " , " " , - 1 ) ;
2020-06-30 21:31:49 +00:00
stringlist = gtk_string_list_new ( ( const char * * ) words ) ;
g_strfreev ( words ) ;
2020-06-27 04:38:20 +00:00
}
2020-08-07 00:53:21 +00:00
g_object_unref ( file ) ;
2020-06-27 04:38:20 +00:00
2020-08-03 19:04:33 +00:00
filter = GTK_FILTER ( gtk_string_filter_new ( gtk_property_expression_new ( GTK_TYPE_STRING_OBJECT , NULL , " string " ) ) ) ;
2020-06-27 04:38:20 +00:00
filter_model = gtk_filter_list_model_new ( G_LIST_MODEL ( stringlist ) , filter ) ;
2020-06-30 02:03:07 +00:00
gtk_filter_list_model_set_incremental ( filter_model , TRUE ) ;
2020-06-27 04:38:20 +00:00
window = gtk_window_new ( ) ;
2020-06-30 11:51:59 +00:00
gtk_window_set_default_size ( GTK_WINDOW ( window ) , 400 , 600 ) ;
2020-06-27 04:38:20 +00:00
header = gtk_header_bar_new ( ) ;
gtk_header_bar_set_show_title_buttons ( GTK_HEADER_BAR ( header ) , TRUE ) ;
2020-12-02 19:15:28 +00:00
open_button = gtk_button_new_with_mnemonic ( " _Open " ) ;
g_signal_connect ( open_button , " clicked " , G_CALLBACK ( file_open_cb ) , stringlist ) ;
2020-06-30 21:31:49 +00:00
gtk_header_bar_pack_start ( GTK_HEADER_BAR ( header ) , open_button ) ;
2020-06-27 04:38:20 +00:00
gtk_window_set_titlebar ( GTK_WINDOW ( window ) , header ) ;
gtk_window_set_display ( GTK_WINDOW ( window ) ,
gtk_widget_get_display ( do_widget ) ) ;
g_object_add_weak_pointer ( G_OBJECT ( window ) , ( gpointer * ) & window ) ;
vbox = gtk_box_new ( GTK_ORIENTATION_VERTICAL , 0 ) ;
gtk_window_set_child ( GTK_WINDOW ( window ) , vbox ) ;
search_entry = gtk_search_entry_new ( ) ;
g_object_bind_property ( search_entry , " text " , filter , " search " , 0 ) ;
gtk_box_append ( GTK_BOX ( vbox ) , search_entry ) ;
2020-06-30 14:38:59 +00:00
overlay = gtk_overlay_new ( ) ;
gtk_box_append ( GTK_BOX ( vbox ) , overlay ) ;
progress = gtk_progress_bar_new ( ) ;
gtk_widget_set_halign ( progress , GTK_ALIGN_FILL ) ;
gtk_widget_set_valign ( progress , GTK_ALIGN_START ) ;
gtk_widget_set_hexpand ( progress , TRUE ) ;
gtk_overlay_add_overlay ( GTK_OVERLAY ( overlay ) , progress ) ;
2020-06-27 04:38:20 +00:00
sw = gtk_scrolled_window_new ( ) ;
2020-07-13 21:54:27 +00:00
gtk_widget_set_vexpand ( sw , TRUE ) ;
2020-06-30 14:38:59 +00:00
gtk_overlay_set_child ( GTK_OVERLAY ( overlay ) , sw ) ;
2020-06-27 04:38:20 +00:00
2020-09-01 16:24:06 +00:00
listview = gtk_list_view_new (
2020-08-31 21:06:48 +00:00
GTK_SELECTION_MODEL ( gtk_no_selection_new ( G_LIST_MODEL ( filter_model ) ) ) ,
2020-06-27 04:38:20 +00:00
gtk_builder_list_item_factory_new_from_bytes ( NULL ,
g_bytes_new_static ( factory_text , strlen ( factory_text ) ) ) ) ;
gtk_scrolled_window_set_child ( GTK_SCROLLED_WINDOW ( sw ) , listview ) ;
2020-06-30 14:38:59 +00:00
g_signal_connect ( filter_model , " items-changed " , G_CALLBACK ( update_title_cb ) , progress ) ;
g_signal_connect ( filter_model , " notify::pending " , G_CALLBACK ( update_title_cb ) , progress ) ;
2020-06-30 02:03:07 +00:00
update_title_cb ( filter_model ) ;
2020-06-27 04:38:20 +00:00
}
if ( ! gtk_widget_get_visible ( window ) )
gtk_widget_show ( window ) ;
else
gtk_window_destroy ( GTK_WINDOW ( window ) ) ;
return window ;
}