messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

files.c (8161B)


      1 /*
      2    This file is part of GNUnet.
      3    Copyright (C) 2024 GNUnet e.V.
      4 
      5    GNUnet is free software: you can redistribute it and/or modify it
      6    under the terms of the GNU Affero General Public License as published
      7    by the Free Software Foundation, either version 3 of the License,
      8    or (at your option) any later version.
      9 
     10    GNUnet is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18    SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 /*
     21  * @author Tobias Frisch
     22  * @file ui/files.c
     23  */
     24 
     25 #include "files.h"
     26 
     27 #include "file_entry.h"
     28 #include "../application.h"
     29 #include "../ui.h"
     30 #include <gnunet/gnunet_chat_lib.h>
     31 #include <gnunet/gnunet_common.h>
     32 
     33 static void
     34 handle_back_button_click(GtkButton *button,
     35                          gpointer user_data)
     36 {
     37   g_assert(user_data);
     38 
     39   UI_FILES_Handle *handle = (UI_FILES_Handle*) user_data;
     40   
     41   gtk_stack_set_visible_child(handle->dialog_stack, handle->list_box);
     42   gtk_widget_set_visible(GTK_WIDGET(button), false);
     43 }
     44 
     45 static void
     46 handle_close_button_click(UNUSED GtkButton *button,
     47                           gpointer user_data)
     48 {
     49   g_assert(user_data);
     50 
     51   GtkDialog *dialog = GTK_DIALOG(user_data);
     52   gtk_window_close(GTK_WINDOW(dialog));
     53 }
     54 
     55 static void
     56 handle_files_listbox_row_activated(UNUSED GtkListBox* listbox,
     57                                    GtkListBoxRow* row,
     58                                    gpointer user_data)
     59 {
     60   g_assert((row) && (user_data));
     61 
     62   MESSENGER_Application *app = (MESSENGER_Application*) user_data;
     63 
     64   if (!gtk_list_box_row_get_selectable(row))
     65     return;
     66 
     67   UI_FILES_Handle *handle = &(app->ui.files);
     68 
     69   struct GNUNET_CHAT_File *file = (struct GNUNET_CHAT_File*) (
     70     g_object_get_qdata(G_OBJECT(row), app->quarks.data)
     71   );
     72 
     73   application_chat_lock(app);
     74 
     75   const gdouble progress = (
     76     (gdouble) GNUNET_CHAT_file_get_local_size(file) /
     77     GNUNET_CHAT_file_get_size(file)
     78   );
     79 
     80   gtk_progress_bar_set_fraction(handle->storage_progress_bar, progress);
     81 
     82   if (GNUNET_YES == GNUNET_CHAT_file_is_downloading(file))
     83     gtk_stack_set_visible_child(handle->play_icon_stack, handle->pause_icon_image);
     84   else
     85     gtk_stack_set_visible_child(handle->play_icon_stack, handle->play_icon_image);
     86 
     87   gtk_widget_set_visible(
     88     GTK_WIDGET(handle->play_pause_button),
     89     GNUNET_YES != GNUNET_CHAT_file_is_ready(file)
     90   );
     91 
     92   application_chat_unlock(app);
     93 
     94   UI_FILE_ENTRY_Handle *entry = (UI_FILE_ENTRY_Handle*) (
     95     g_object_get_qdata(G_OBJECT(row), app->quarks.ui)
     96   );
     97 
     98   const gchar *name = gtk_label_get_text(entry->name_label);
     99   const gchar *size = gtk_label_get_text(entry->size_label);
    100 
    101   gtk_label_set_text(handle->name_label, name);
    102   gtk_progress_bar_set_text(handle->storage_progress_bar, size);
    103 
    104   gtk_stack_set_visible_child(handle->dialog_stack, handle->info_box);
    105   gtk_widget_set_visible(GTK_WIDGET(handle->back_button), true);
    106 }
    107 
    108 static gboolean
    109 handle_files_listbox_filter_func(GtkListBoxRow *row,
    110                                  gpointer user_data)
    111 {
    112   g_assert((row) && (user_data));
    113 
    114   MESSENGER_Application *app = (MESSENGER_Application*) user_data;
    115 
    116   if (!gtk_list_box_row_get_selectable(row))
    117     return TRUE;
    118 
    119   const gchar *filter = gtk_entry_get_text(
    120     GTK_ENTRY(app->ui.files.file_search_entry)
    121   );
    122 
    123   if (!filter)
    124     return TRUE;
    125 
    126   UI_FILE_ENTRY_Handle *entry = (UI_FILE_ENTRY_Handle*) (
    127     g_object_get_qdata(G_OBJECT(row), app->quarks.ui)
    128   );
    129 
    130   if (!entry)
    131     return FALSE;
    132 
    133   const gchar *name = gtk_label_get_text(entry->name_label);
    134 
    135   if (!name)
    136     return FALSE;
    137 
    138   return g_str_match_string(filter, name, TRUE);
    139 }
    140 
    141 static void
    142 handle_file_search_entry_search_changed(UNUSED GtkSearchEntry* search_entry,
    143                                         gpointer user_data)
    144 {
    145   g_assert(user_data);
    146 
    147   GtkListBox *listbox = GTK_LIST_BOX(user_data);
    148 
    149   gtk_list_box_invalidate_filter(listbox);
    150 }
    151 
    152 static void
    153 handle_dialog_destroy(UNUSED GtkWidget *window,
    154                       gpointer user_data)
    155 {
    156   g_assert(user_data);
    157 
    158   ui_files_dialog_cleanup((UI_FILES_Handle*) user_data);
    159 }
    160 
    161 static enum GNUNET_GenericReturnValue
    162 _iterate_files(void *cls,
    163                UNUSED struct GNUNET_CHAT_Handle *handle,
    164                struct GNUNET_CHAT_File *file)
    165 {
    166   g_assert((cls) && (file));
    167 
    168   MESSENGER_Application *app = (MESSENGER_Application*) cls;
    169   GtkListBox *listbox = app->ui.files.files_listbox;
    170 
    171   UI_FILE_ENTRY_Handle* entry = ui_file_entry_new(app);
    172   ui_file_entry_update(entry, file);
    173 
    174   gtk_list_box_prepend(listbox, entry->entry_box);
    175 
    176   GtkListBoxRow *row = GTK_LIST_BOX_ROW(
    177     gtk_widget_get_parent(entry->entry_box)
    178   );
    179 
    180   g_object_set_qdata(G_OBJECT(row), app->quarks.data, file);
    181   g_object_set_qdata_full(
    182     G_OBJECT(row),
    183     app->quarks.ui,
    184     entry,
    185     (GDestroyNotify) ui_file_entry_delete
    186   );
    187 
    188   return GNUNET_YES;
    189 }
    190 
    191 void
    192 ui_files_dialog_init(MESSENGER_Application *app,
    193                      UI_FILES_Handle *handle)
    194 {
    195   g_assert((app) && (handle));
    196 
    197   handle->builder = ui_builder_from_resource(
    198     application_get_resource_path(app, "ui/files.ui")
    199   );
    200 
    201   handle->dialog = GTK_DIALOG(
    202     gtk_builder_get_object(handle->builder, "files_dialog")
    203   );
    204 
    205   gtk_window_set_transient_for(
    206     GTK_WINDOW(handle->dialog),
    207     GTK_WINDOW(app->ui.messenger.main_window)
    208   );
    209 
    210   handle->dialog_stack = GTK_STACK(
    211     gtk_builder_get_object(handle->builder, "dialog_stack")
    212   );
    213 
    214   handle->list_box = GTK_WIDGET(
    215     gtk_builder_get_object(handle->builder, "list_box")
    216   );
    217 
    218   handle->info_box = GTK_WIDGET(
    219     gtk_builder_get_object(handle->builder, "info_box")
    220   );
    221 
    222   handle->file_search_entry = GTK_SEARCH_ENTRY(
    223     gtk_builder_get_object(handle->builder, "file_search_entry")
    224   );
    225 
    226   handle->files_listbox = GTK_LIST_BOX(
    227     gtk_builder_get_object(handle->builder, "files_listbox")
    228   );
    229 
    230   gtk_list_box_set_filter_func(
    231     handle->files_listbox,
    232     handle_files_listbox_filter_func,
    233     app,
    234     NULL
    235   );
    236 
    237   g_signal_connect(
    238     handle->file_search_entry,
    239     "search-changed",
    240     G_CALLBACK(handle_file_search_entry_search_changed),
    241     handle->files_listbox
    242   );
    243 
    244   g_signal_connect(
    245     handle->files_listbox,
    246     "row-activated",
    247     G_CALLBACK(handle_files_listbox_row_activated),
    248     app
    249   );
    250 
    251   handle->name_label = GTK_LABEL(
    252     gtk_builder_get_object(handle->builder, "name_label")
    253   );
    254 
    255   handle->storage_progress_bar = GTK_PROGRESS_BAR(
    256     gtk_builder_get_object(handle->builder, "storage_progress_bar")
    257   );
    258 
    259   handle->delete_file_button = GTK_BUTTON(
    260     gtk_builder_get_object(handle->builder, "delete_file_button")
    261   );
    262 
    263   handle->play_pause_button = GTK_BUTTON(
    264     gtk_builder_get_object(handle->builder, "play_pause_button")
    265   );
    266 
    267   handle->play_icon_stack = GTK_STACK(
    268     gtk_builder_get_object(handle->builder, "play_icon_stack")
    269   );
    270 
    271   handle->play_icon_image = GTK_WIDGET(
    272     gtk_builder_get_object(handle->builder, "play_icon_image")
    273   );
    274 
    275   handle->pause_icon_image = GTK_WIDGET(
    276     gtk_builder_get_object(handle->builder, "pause_icon_image")
    277   );
    278 
    279   handle->back_button = GTK_BUTTON(
    280     gtk_builder_get_object(handle->builder, "back_button")
    281   );
    282 
    283   g_signal_connect(
    284     handle->back_button,
    285     "clicked",
    286     G_CALLBACK(handle_back_button_click),
    287     handle
    288   );
    289 
    290   handle->close_button = GTK_BUTTON(
    291     gtk_builder_get_object(handle->builder, "close_button")
    292   );
    293 
    294   g_signal_connect(
    295     handle->close_button,
    296     "clicked",
    297     G_CALLBACK(handle_close_button_click),
    298     handle->dialog
    299   );
    300 
    301   g_signal_connect(
    302     handle->dialog,
    303     "destroy",
    304     G_CALLBACK(handle_dialog_destroy),
    305     handle
    306   );
    307 
    308   GNUNET_CHAT_iterate_files(
    309     app->chat.messenger.handle,
    310     _iterate_files,
    311     app
    312   );
    313 
    314   gtk_list_box_invalidate_filter(handle->files_listbox);
    315 }
    316 
    317 void
    318 ui_files_dialog_cleanup(UI_FILES_Handle *handle)
    319 {
    320   g_assert(handle);
    321 
    322   if (handle->builder)
    323     g_object_unref(handle->builder);
    324 
    325   memset(handle, 0, sizeof(*handle));
    326 }