LCOV - code coverage report
Current view: top level - src/plugins/share - valent-share-dialog.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 46.7 % 360 168
Test Date: 2024-05-12 19:03:18 Functions: 58.6 % 29 17
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 23.6 % 178 42

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-share-target-chooser"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <adwaita.h>
       9                 :             : #include <glib/gi18n.h>
      10                 :             : #include <gtk/gtk.h>
      11                 :             : #include <valent.h>
      12                 :             : 
      13                 :             : #include "valent-share-dialog.h"
      14                 :             : #include "valent-share-dialog-row.h"
      15                 :             : 
      16                 :             : 
      17                 :             : struct _ValentShareDialog
      18                 :             : {
      19                 :             :   AdwWindow            parent_instance;
      20                 :             : 
      21                 :             :   ValentDeviceManager *manager;
      22                 :             :   GListModel          *files;
      23                 :             :   unsigned int         refresh_id;
      24                 :             :   unsigned int         selection_mode : 1;
      25                 :             : 
      26                 :             :   GPtrArray           *rows;
      27                 :             :   GCancellable        *cancellable;
      28                 :             :   guint64              total_size;
      29                 :             :   unsigned int         n_files;
      30                 :             :   unsigned int         n_links;
      31                 :             : 
      32                 :             :   /* template */
      33                 :             :   AdwNavigationView   *view;
      34                 :             :   AdwActionRow        *single_row;
      35                 :             :   GtkImage            *single_icon;
      36                 :             :   AdwExpanderRow      *multiple_row;
      37                 :             :   GtkImage            *multiple_icon;
      38                 :             :   GtkListBox          *device_list;
      39                 :             :   AdwEntryRow         *uri_entry;
      40                 :             : };
      41                 :             : 
      42   [ +  +  +  - ]:          13 : G_DEFINE_FINAL_TYPE (ValentShareDialog, valent_share_dialog, ADW_TYPE_WINDOW)
      43                 :             : 
      44                 :             : enum {
      45                 :             :   PROP_0,
      46                 :             :   PROP_FILES,
      47                 :             :   PROP_SELECTION_MODE,
      48                 :             :   N_PROPERTIES
      49                 :             : };
      50                 :             : 
      51                 :             : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      52                 :             : 
      53                 :             : static void   valent_share_dialog_set_files (ValentShareDialog    *self,
      54                 :             :                                              GListModel           *files);
      55                 :             : static void   valent_share_dialog_share     (ValentShareDialog    *self,
      56                 :             :                                              ValentShareDialogRow *row);
      57                 :             : 
      58                 :             : 
      59                 :             : /*
      60                 :             :  * Summary
      61                 :             :  */
      62                 :             : typedef struct
      63                 :             : {
      64                 :             :   ValentShareDialog *self;
      65                 :             :   GtkWidget         *row;
      66                 :             :   GtkImage          *icon;
      67                 :             : } EntryData;
      68                 :             : 
      69                 :             : static void
      70                 :           0 : g_file_query_info_cb (GFile        *file,
      71                 :             :                       GAsyncResult *result,
      72                 :             :                       gpointer      user_data)
      73                 :             : {
      74                 :           0 :   g_autofree EntryData *data = (EntryData *)user_data;
      75                 :           0 :   GIcon *icon = NULL;
      76                 :           0 :   g_autoptr (GFileInfo) info = NULL;
      77                 :           0 :   g_autoptr (GError) error = NULL;
      78   [ #  #  #  # ]:           0 :   g_autofree char *size_str = NULL;
      79                 :           0 :   g_autofree char *size_label = NULL;
      80                 :           0 :   gsize size = 0;
      81                 :             : 
      82         [ #  # ]:           0 :   if ((info = g_file_query_info_finish (file, result, &error)) == NULL)
      83                 :             :     {
      84         [ #  # ]:           0 :       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
      85                 :             :         return;
      86                 :             : 
      87         [ #  # ]:           0 :       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
      88                 :             :         {
      89                 :           0 :           gtk_widget_add_css_class (GTK_WIDGET (data->row), "error");
      90                 :             :         }
      91                 :             : 
      92                 :           0 :       return;
      93                 :             :     }
      94                 :             : 
      95         [ #  # ]:           0 :   if ((icon = g_file_info_get_icon (info)) != NULL)
      96                 :             :     {
      97                 :           0 :       gtk_image_set_from_gicon (data->icon, icon);
      98                 :           0 :       gtk_widget_add_css_class (GTK_WIDGET (data->icon), "lowres-icon");
      99                 :             :     }
     100                 :             :   else
     101                 :             :     {
     102                 :           0 :       gtk_image_set_from_icon_name (data->icon, "share-file-symbolic");
     103                 :           0 :       gtk_widget_remove_css_class (GTK_WIDGET (data->icon), "lowres-icon");
     104                 :             :     }
     105                 :             : 
     106                 :           0 :   size = g_file_info_get_size (info);
     107                 :           0 :   size_str = g_format_size (size);
     108                 :           0 :   size_label = g_strdup_printf (_("Size: %s"), size_str);
     109                 :           0 :   g_object_set (data->row, "subtitle", size_label, NULL);
     110                 :             : 
     111         [ #  # ]:           0 :   if (data->self->n_files > 1)
     112                 :             :     {
     113                 :           0 :       g_autofree char *total_str = NULL;
     114                 :           0 :       g_autofree char *total_label = NULL;
     115                 :             : 
     116         [ #  # ]:           0 :       if ((G_MAXUINT64 - data->self->total_size) < size)
     117                 :           0 :         data->self->total_size = G_MAXUINT64;
     118                 :             :       else
     119                 :           0 :         data->self->total_size += size;
     120                 :             : 
     121                 :           0 :       total_str = g_format_size (data->self->total_size);
     122                 :           0 :       total_label = g_strdup_printf (_("Total size: %s"), total_str);
     123                 :           0 :       g_object_set (data->self->multiple_row, "subtitle", total_label, NULL);
     124                 :             :     }
     125                 :             : }
     126                 :             : 
     127                 :             : static void
     128                 :           0 : valent_share_dialog_add_entry (ValentShareDialog *self,
     129                 :             :                                GFile             *file,
     130                 :             :                                GCancellable      *cancellable)
     131                 :             : {
     132                 :           0 :   g_autofree char *title = NULL;
     133                 :           0 :   const char *icon_name = NULL;
     134                 :           0 :   gboolean is_file  = FALSE;
     135                 :           0 :   GtkWidget *row;
     136                 :           0 :   GtkWidget *icon;
     137                 :             : 
     138                 :           0 :   is_file = g_file_has_uri_scheme (file, "file");
     139                 :             : 
     140         [ #  # ]:           0 :   if (is_file)
     141                 :             :     {
     142                 :           0 :       self->n_files += 1;
     143                 :           0 :       title = g_file_get_basename (file);
     144                 :           0 :       icon_name = "share-file-symbolic";
     145                 :             :     }
     146                 :             :   else
     147                 :             :     {
     148                 :           0 :       g_autofree char *uri = NULL;
     149                 :             : 
     150                 :           0 :       uri = g_file_get_uri (file);
     151                 :             : 
     152                 :           0 :       self->n_links += 1;
     153                 :           0 :       title = g_strdup_printf ("<a href=\"%s\">%s</a>", uri, uri);
     154                 :           0 :       icon_name = "share-link-symbolic";
     155                 :             :     }
     156                 :             : 
     157                 :           0 :   row = g_object_new (ADW_TYPE_ACTION_ROW,
     158                 :             :                       "title",       title,
     159                 :             :                       "title-lines", 1,
     160                 :             :                       NULL);
     161                 :           0 :   icon = g_object_new (GTK_TYPE_IMAGE,
     162                 :             :                        "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
     163                 :             :                        "icon-name",       icon_name,
     164                 :             :                        NULL);
     165                 :           0 :   adw_action_row_add_prefix (ADW_ACTION_ROW (row), icon);
     166                 :           0 :   adw_expander_row_add_row (self->multiple_row, row);
     167                 :           0 :   g_ptr_array_add (self->rows, row);
     168                 :             : 
     169         [ #  # ]:           0 :   if (is_file)
     170                 :             :     {
     171                 :           0 :       EntryData *data = NULL;
     172                 :             : 
     173                 :           0 :       data = g_new0 (EntryData, 1);
     174                 :           0 :       data->self = self;
     175                 :           0 :       data->row = (GtkWidget *)row;
     176                 :           0 :       data->icon = (GtkImage *)icon;
     177                 :             : 
     178                 :           0 :       g_file_query_info_async (file,
     179                 :             :                                G_FILE_ATTRIBUTE_STANDARD_SIZE","
     180                 :             :                                G_FILE_ATTRIBUTE_STANDARD_ICON,
     181                 :             :                                G_FILE_QUERY_INFO_NONE,
     182                 :             :                                G_PRIORITY_DEFAULT_IDLE,
     183                 :             :                                cancellable,
     184                 :             :                                (GAsyncReadyCallback)g_file_query_info_cb,
     185                 :             :                                g_steal_pointer (&data));
     186                 :             :     }
     187                 :           0 : }
     188                 :             : 
     189                 :             : static void
     190                 :           2 : valent_share_dialog_reset (ValentShareDialog *self)
     191                 :             : {
     192         [ +  - ]:           2 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     193                 :             : 
     194                 :           2 :   g_cancellable_cancel (self->cancellable);
     195         [ +  + ]:           2 :   g_clear_object (&self->cancellable);
     196                 :           2 :   self->cancellable = g_cancellable_new ();
     197                 :           2 :   self->n_files = 0;
     198                 :           2 :   self->n_links = 0;
     199                 :           2 :   self->total_size = 0;
     200                 :             : 
     201                 :           2 :   g_object_set (self->single_row,
     202                 :             :                 "title",    NULL,
     203                 :             :                 "subtitle", NULL,
     204                 :             :                 NULL);
     205                 :           2 :   g_object_set (self->multiple_row,
     206                 :             :                 "title",    NULL,
     207                 :             :                 "subtitle", NULL,
     208                 :             :                 NULL);
     209                 :           2 :   gtk_editable_set_text (GTK_EDITABLE (self->uri_entry), "");
     210                 :             : 
     211         [ -  + ]:           2 :   if (self->rows != NULL)
     212                 :             :     {
     213         [ #  # ]:           0 :       for (unsigned int i = 0; i < self->rows->len; i++)
     214                 :             :         {
     215                 :           0 :           adw_expander_row_remove (self->multiple_row,
     216                 :           0 :                                    g_ptr_array_index (self->rows, i));
     217                 :             :         }
     218                 :           0 :       g_clear_pointer (&self->rows, g_ptr_array_unref);
     219                 :             :     }
     220                 :           2 : }
     221                 :             : 
     222                 :             : static void
     223                 :           1 : on_files_changed (GListModel        *list,
     224                 :             :                   unsigned int       position,
     225                 :             :                   unsigned int       removed,
     226                 :             :                   unsigned int       added,
     227                 :             :                   ValentShareDialog *self)
     228                 :             : {
     229                 :           1 :   unsigned int n_items = 0;
     230                 :             : 
     231         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     232                 :             : 
     233                 :           1 :   valent_share_dialog_reset (self);
     234                 :             : 
     235         [ +  - ]:           1 :   if (self->files != NULL)
     236                 :           1 :     n_items = g_list_model_get_n_items (self->files);
     237                 :             : 
     238         [ -  + ]:           1 :   if (n_items > 1)
     239                 :             :     {
     240                 :           0 :       g_autofree char *title = NULL;
     241                 :             : 
     242                 :           0 :       self->rows = g_ptr_array_sized_new (n_items);
     243                 :             : 
     244         [ #  # ]:           0 :       for (unsigned int i = 0; i < n_items; i++)
     245                 :             :         {
     246                 :           0 :           g_autoptr (GFile) file = NULL;
     247                 :             : 
     248                 :           0 :           file = g_list_model_get_item (self->files, i);
     249         [ #  # ]:           0 :           valent_share_dialog_add_entry (self, file, self->cancellable);
     250                 :             :         }
     251                 :             : 
     252   [ #  #  #  # ]:           0 :       if (self->n_files > 0 && self->n_links > 0)
     253                 :           0 :         title = g_strdup_printf (_("%u files and links"), n_items);
     254         [ #  # ]:           0 :       else if (self->n_files > 0)
     255                 :           0 :         title = g_strdup_printf (_("%u files"), n_items);
     256         [ #  # ]:           0 :       else if (self->n_links > 0)
     257                 :           0 :         title = g_strdup_printf (_("%u links"), n_items);
     258                 :             : 
     259                 :           0 :       g_object_set (self->multiple_row,
     260                 :             :                     "title",   title,
     261                 :             :                     "visible", TRUE,
     262                 :             :                     NULL);
     263                 :             :     }
     264         [ +  - ]:           1 :   else if (n_items > 0)
     265                 :             :     {
     266                 :           1 :       g_autofree char *title = NULL;
     267                 :           1 :       g_autoptr (GFile) entry = NULL;
     268                 :           1 :       const char *icon_name = NULL;
     269                 :             : 
     270                 :           1 :       entry = g_list_model_get_item (self->files, 0);
     271                 :             : 
     272         [ -  + ]:           1 :       if (g_file_has_uri_scheme (entry, "file"))
     273                 :             :         {
     274                 :           0 :           EntryData *data;
     275                 :             : 
     276                 :           0 :           data = g_new0 (EntryData, 1);
     277                 :           0 :           data->self = self;
     278                 :           0 :           data->row = (GtkWidget *)self->single_row;
     279                 :           0 :           data->icon = self->single_icon;
     280                 :             : 
     281                 :           0 :           g_file_query_info_async (entry,
     282                 :             :                                    G_FILE_ATTRIBUTE_STANDARD_SIZE","
     283                 :             :                                    G_FILE_ATTRIBUTE_STANDARD_ICON,
     284                 :             :                                    G_FILE_QUERY_INFO_NONE,
     285                 :             :                                    G_PRIORITY_DEFAULT_IDLE,
     286                 :             :                                    self->cancellable,
     287                 :             :                                    (GAsyncReadyCallback)g_file_query_info_cb,
     288                 :             :                                    g_steal_pointer (&data));
     289                 :             : 
     290                 :           0 :           title = g_file_get_basename (entry);
     291                 :           0 :           icon_name = "share-symbolic";
     292                 :             :         }
     293                 :             :       else
     294                 :             :         {
     295                 :           1 :           g_autofree char *uri = NULL;
     296                 :             : 
     297                 :           1 :           uri = g_file_get_uri (entry);
     298                 :             : 
     299                 :           1 :           title = g_strdup_printf ("<a href=\"%s\">%s</a>", uri, uri);
     300                 :           1 :           icon_name = "share-link-symbolic";
     301                 :             :         }
     302                 :             : 
     303                 :           1 :       g_object_set (self->single_row,
     304                 :             :                     "title",   title,
     305                 :             :                     "visible", TRUE,
     306                 :             :                     NULL);
     307                 :           1 :       gtk_image_set_from_icon_name (self->single_icon, icon_name);
     308         [ +  - ]:           1 :       gtk_widget_remove_css_class (GTK_WIDGET (self->single_icon), "lowres-icon");
     309                 :             :     }
     310                 :           1 : }
     311                 :             : 
     312                 :             : /*
     313                 :             :  * Devices
     314                 :             :  */
     315                 :             : static void
     316                 :           1 : on_action_added (GActionGroup *action_group,
     317                 :             :                  const char   *action_name,
     318                 :             :                  GtkWidget    *widget)
     319                 :             : {
     320                 :           1 :   gboolean visible = FALSE;
     321                 :             : 
     322         [ -  + ]:           1 :   if (g_action_group_get_action_enabled (action_group, action_name))
     323                 :           0 :     visible = TRUE;
     324                 :             : 
     325                 :           1 :   gtk_widget_set_visible (widget, visible);
     326                 :           1 : }
     327                 :             : 
     328                 :             : static void
     329                 :           0 : on_action_removed (GActionGroup *action_group,
     330                 :             :                    const char   *action_name,
     331                 :             :                    GtkWidget    *widget)
     332                 :             : {
     333                 :           0 :   gtk_widget_set_visible (widget, FALSE);
     334                 :           0 : }
     335                 :             : 
     336                 :             : static void
     337                 :           0 : on_action_enabled_changed (GActionGroup *action_group,
     338                 :             :                            const char   *action_name,
     339                 :             :                            gboolean      enabled,
     340                 :             :                            GtkWidget    *widget)
     341                 :             : {
     342                 :           0 :   gtk_widget_set_visible (widget, enabled);
     343                 :           0 : }
     344                 :             : 
     345                 :             : static void
     346                 :           0 : on_device_activated (GtkListBox           *box,
     347                 :             :                      ValentShareDialogRow *row,
     348                 :             :                      ValentShareDialog    *self)
     349                 :             : {
     350   [ #  #  #  #  :           0 :   g_assert (GTK_IS_LIST_BOX (box));
             #  #  #  # ]
     351         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_DIALOG_ROW (row));
     352         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     353                 :             : 
     354         [ #  # ]:           0 :   if (self->selection_mode)
     355                 :             :     {
     356                 :           0 :       gboolean selected;
     357                 :             : 
     358                 :           0 :       selected = valent_share_dialog_row_get_selected (row);
     359                 :           0 :       valent_share_dialog_row_set_selected (row, !selected);
     360                 :             :     }
     361                 :             :   else
     362                 :             :     {
     363                 :           0 :       valent_share_dialog_share (self, row);
     364                 :             :     }
     365                 :           0 : }
     366                 :             : 
     367                 :             : static void
     368                 :           4 : on_selected_changed (ValentShareDialog *self)
     369                 :             : {
     370                 :           4 :   GtkWidget *child;
     371                 :           4 :   gboolean enabled = FALSE;
     372                 :             : 
     373         [ +  - ]:           4 :   if (!self->selection_mode)
     374                 :             :     {
     375                 :           4 :       gtk_widget_action_set_enabled (GTK_WIDGET (self),
     376                 :             :                                      "chooser.share",
     377                 :             :                                      enabled);
     378                 :           4 :       return;
     379                 :             :     }
     380                 :             : 
     381                 :           0 :   for (child = gtk_widget_get_first_child (GTK_WIDGET (self->device_list));
     382         [ #  # ]:           0 :        child != NULL;
     383                 :           0 :        child = gtk_widget_get_next_sibling (child))
     384                 :             :     {
     385         [ #  # ]:           0 :       if (!VALENT_IS_SHARE_DIALOG_ROW (child))
     386                 :           0 :         continue;
     387                 :             : 
     388         [ #  # ]:           0 :       if (valent_share_dialog_row_get_selected (VALENT_SHARE_DIALOG_ROW (child)))
     389                 :             :         {
     390                 :             :           enabled = TRUE;
     391                 :             :           break;
     392                 :             :         }
     393                 :             :     }
     394                 :             : 
     395                 :           0 :   gtk_widget_action_set_enabled (GTK_WIDGET (self), "chooser.share", enabled);
     396                 :             : }
     397                 :             : 
     398                 :             : static GtkWidget *
     399                 :           1 : valent_share_dialog_create_row (gpointer item,
     400                 :             :                                 gpointer user_data)
     401                 :             : {
     402                 :           1 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (user_data);
     403                 :           1 :   ValentDevice *device = VALENT_DEVICE (item);
     404                 :           1 :   GtkWidget *row;
     405                 :             : 
     406         [ +  - ]:           1 :   g_assert (VALENT_IS_DEVICE (device));
     407                 :             : 
     408                 :           1 :   row = g_object_new (VALENT_TYPE_SHARE_DIALOG_ROW,
     409                 :             :                       "device",         device,
     410                 :           1 :                       "selection-mode", self->selection_mode,
     411                 :             :                       NULL);
     412                 :           1 :   g_object_bind_property (self, "selection-mode",
     413                 :             :                           row,  "selection-mode",
     414                 :             :                           G_BINDING_SYNC_CREATE);
     415                 :           1 :   g_signal_connect_object (row,
     416                 :             :                            "notify::selected",
     417                 :             :                            G_CALLBACK (on_selected_changed),
     418                 :             :                            self, G_CONNECT_SWAPPED);
     419                 :           1 :   g_signal_connect_object (device,
     420                 :             :                            "action-added::share.uris",
     421                 :             :                            G_CALLBACK (on_action_added),
     422                 :             :                            row, 0);
     423                 :           1 :   g_signal_connect_object (device,
     424                 :             :                            "action-removed::share.uris",
     425                 :             :                            G_CALLBACK (on_action_removed),
     426                 :             :                            row, 0);
     427                 :           1 :   g_signal_connect_object (device,
     428                 :             :                            "action-enabled-changed::share.uris",
     429                 :             :                            G_CALLBACK (on_action_enabled_changed),
     430                 :             :                            row, 0);
     431                 :           1 :   on_action_added (G_ACTION_GROUP (device), "share.uris", row);
     432                 :             : 
     433                 :           1 :   return row;
     434                 :             : }
     435                 :             : 
     436                 :             : static void
     437                 :           4 : on_items_changed (GListModel        *list,
     438                 :             :                   unsigned int       position,
     439                 :             :                   unsigned int       removed,
     440                 :             :                   unsigned int       added,
     441                 :             :                   ValentShareDialog *self)
     442                 :             : {
     443         [ +  - ]:           4 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     444                 :             : 
     445         [ +  + ]:           5 :   while (removed--)
     446                 :             :     {
     447                 :           1 :       GtkListBoxRow *row;
     448                 :             : 
     449                 :           1 :       row = gtk_list_box_get_row_at_index (self->device_list, position);
     450                 :           1 :       gtk_list_box_remove (self->device_list, GTK_WIDGET (row));
     451                 :             :     }
     452                 :             : 
     453         [ +  + ]:           5 :   for (unsigned int i = 0; i < added; i++)
     454                 :             :     {
     455                 :           1 :       g_autoptr (GObject) item = NULL;
     456         [ +  - ]:           1 :       g_autoptr (GtkWidget) widget = NULL;
     457                 :             : 
     458                 :           1 :       item = g_list_model_get_item (list, position + i);
     459                 :           1 :       widget = valent_share_dialog_create_row (item, self);
     460                 :             : 
     461         [ +  - ]:           1 :       if (g_object_is_floating (widget))
     462                 :           1 :         g_object_ref_sink (widget);
     463                 :             : 
     464         [ +  - ]:           1 :       gtk_list_box_insert (self->device_list, widget, position + i);
     465                 :             :     }
     466                 :             : 
     467                 :           4 :   on_selected_changed (self);
     468                 :           4 : }
     469                 :             : 
     470                 :             : static gboolean
     471                 :           0 : valent_share_dialog_refresh (gpointer data)
     472                 :             : {
     473                 :           0 :   ValentDeviceManager *manager = VALENT_DEVICE_MANAGER (data);
     474                 :             : 
     475         [ #  # ]:           0 :   g_assert (VALENT_IS_DEVICE_MANAGER (manager));
     476                 :             : 
     477                 :           0 :   valent_device_manager_refresh (manager);
     478                 :             : 
     479                 :           0 :   return G_SOURCE_CONTINUE;
     480                 :             : }
     481                 :             : 
     482                 :             : /*
     483                 :             :  * URI Selector
     484                 :             :  */
     485                 :             : static void
     486                 :           0 : on_uri_activated (GtkEditable       *editable,
     487                 :             :                   ValentShareDialog *self)
     488                 :             : {
     489                 :           0 :   const char *text = NULL;
     490                 :             : 
     491         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     492                 :             : 
     493                 :           0 :   text = gtk_editable_get_text (editable);
     494   [ #  #  #  # ]:           0 :   if (text == NULL || *text == '\0')
     495                 :             :     return;
     496                 :             : 
     497         [ #  # ]:           0 :   if (!gtk_widget_has_css_class (GTK_WIDGET (self->uri_entry), "error"))
     498                 :             :     {
     499                 :           0 :       g_autoptr (GListStore) files = NULL;
     500         [ #  # ]:           0 :       g_autoptr (GFile) file = NULL;
     501                 :             : 
     502                 :           0 :       file = g_file_new_for_uri (text);
     503                 :           0 :       files = g_list_store_new (G_TYPE_FILE);
     504                 :           0 :       g_list_store_append (files, file);
     505                 :             : 
     506         [ #  # ]:           0 :       valent_share_dialog_set_files (self, G_LIST_MODEL (files));
     507                 :             :     }
     508                 :             : }
     509                 :             : 
     510                 :             : static void
     511                 :           0 : on_uri_changed (GtkEditable       *editable,
     512                 :             :                 ValentShareDialog *self)
     513                 :             : {
     514                 :           0 :   const char *text = NULL;
     515                 :           0 :   const char *scheme = NULL;
     516                 :             : 
     517         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     518                 :             : 
     519                 :           0 :   text = gtk_editable_get_text (editable);
     520   [ #  #  #  # ]:           0 :   if (text == NULL || *text == '\0')
     521                 :             :     {
     522                 :           0 :       gtk_widget_remove_css_class (GTK_WIDGET (self->uri_entry), "error");
     523                 :           0 :       gtk_accessible_reset_state (GTK_ACCESSIBLE (self->uri_entry),
     524                 :             :                                   GTK_ACCESSIBLE_STATE_INVALID);
     525                 :           0 :       return;
     526                 :             :     }
     527                 :             : 
     528                 :           0 :   scheme = g_uri_peek_scheme (text);
     529   [ #  #  #  # ]:           0 :   if (scheme != NULL && !g_str_equal (scheme, "file"))
     530                 :             :     {
     531                 :           0 :       gtk_widget_remove_css_class (GTK_WIDGET (self->uri_entry), "error");
     532                 :           0 :       gtk_accessible_reset_state (GTK_ACCESSIBLE (self->uri_entry),
     533                 :             :                                   GTK_ACCESSIBLE_STATE_INVALID);
     534                 :             :     }
     535                 :             :   else
     536                 :             :     {
     537                 :           0 :       gtk_widget_add_css_class (GTK_WIDGET (self->uri_entry), "error");
     538                 :           0 :       gtk_accessible_update_state (GTK_ACCESSIBLE (self->uri_entry),
     539                 :             :                                    GTK_ACCESSIBLE_STATE_INVALID, TRUE,
     540                 :             :                                    -1);
     541                 :             :     }
     542                 :             : }
     543                 :             : 
     544                 :             : /*
     545                 :             :  * GAction
     546                 :             :  */
     547                 :             : static void
     548                 :           0 : gtk_file_dialog_open_multiple_cb (GtkFileDialog     *dialog,
     549                 :             :                                   GAsyncResult      *result,
     550                 :             :                                   ValentShareDialog *self)
     551                 :             : {
     552                 :           0 :   g_autoptr (GListModel) files = NULL;
     553                 :           0 :   g_autoptr (GError) error = NULL;
     554                 :             : 
     555                 :           0 :   files = gtk_file_dialog_open_multiple_finish (dialog, result, &error);
     556                 :             : 
     557         [ #  # ]:           0 :   if (files == NULL)
     558                 :             :     {
     559   [ #  #  #  # ]:           0 :       if (!g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED) &&
     560                 :           0 :           !g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED))
     561                 :           0 :         g_warning ("%s(): %s", G_STRFUNC, error->message);
     562                 :             : 
     563         [ #  # ]:           0 :       return;
     564                 :             :     }
     565                 :             : 
     566         [ #  # ]:           0 :   valent_share_dialog_set_files (self, files);
     567                 :             : }
     568                 :             : 
     569                 :             : static void
     570                 :           0 : chooser_select_files_action (GtkWidget  *widget,
     571                 :             :                              const char *action_name,
     572                 :             :                              GVariant   *parameter)
     573                 :             : {
     574                 :           0 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (widget);
     575                 :           0 :   g_autoptr (GtkFileDialog) dialog = NULL;
     576                 :             : 
     577         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     578                 :             : 
     579                 :           0 :   dialog = gtk_file_dialog_new ();
     580         [ #  # ]:           0 :   gtk_file_dialog_open_multiple (dialog,
     581                 :             :                                  GTK_WINDOW (self),
     582                 :             :                                  NULL,
     583                 :             :                                  (GAsyncReadyCallback)gtk_file_dialog_open_multiple_cb,
     584                 :             :                                  self);
     585                 :           0 : }
     586                 :             : 
     587                 :             : static void
     588                 :           0 : chooser_share_action (GtkWidget  *widget,
     589                 :             :                       const char *action_name,
     590                 :             :                       GVariant   *parameter)
     591                 :             : {
     592                 :           0 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (widget);
     593                 :           0 :   GtkWidget *child;
     594                 :             : 
     595                 :           0 :   for (child = gtk_widget_get_first_child (GTK_WIDGET (self->device_list));
     596         [ #  # ]:           0 :        child != NULL;
     597                 :           0 :        child = gtk_widget_get_next_sibling (child))
     598                 :             :     {
     599         [ #  # ]:           0 :       if (!VALENT_IS_SHARE_DIALOG_ROW (child))
     600                 :           0 :         continue;
     601                 :             : 
     602         [ #  # ]:           0 :       if (!valent_share_dialog_row_get_selected (VALENT_SHARE_DIALOG_ROW (child)))
     603                 :           0 :         continue;
     604                 :             : 
     605                 :           0 :       valent_share_dialog_share (self, VALENT_SHARE_DIALOG_ROW (child));
     606                 :             :     }
     607                 :           0 : }
     608                 :             : 
     609                 :             : /*
     610                 :             :  * ValentShareDialog
     611                 :             :  */
     612                 :             : static void
     613                 :           1 : valent_share_dialog_set_files (ValentShareDialog *self,
     614                 :             :                                GListModel        *files)
     615                 :             : {
     616                 :           1 :   unsigned int n_items = 0;
     617                 :             : 
     618         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     619   [ +  -  -  + ]:           1 :   g_assert (files == NULL || G_IS_LIST_MODEL (files));
     620                 :             : 
     621         [ +  - ]:           1 :   if (!g_set_object (&self->files, files))
     622                 :             :     return;
     623                 :             : 
     624                 :           1 :   valent_share_dialog_reset (self);
     625                 :             : 
     626         [ +  - ]:           1 :   if (self->files != NULL)
     627                 :             :     {
     628                 :           1 :       n_items = g_list_model_get_n_items (files);
     629                 :           1 :       g_signal_connect_object (self->files,
     630                 :             :                                "items-changed",
     631                 :             :                                G_CALLBACK (on_files_changed),
     632                 :             :                                self,
     633                 :             :                                G_CONNECT_DEFAULT);
     634                 :           1 :       on_files_changed (self->files,
     635                 :             :                         0,
     636                 :           1 :                         self->n_links + self->n_files,
     637                 :             :                         n_items,
     638                 :             :                         self);
     639                 :             :     }
     640                 :             : 
     641         [ +  - ]:           1 :   if (n_items > 0)
     642                 :           1 :     adw_navigation_view_push_by_tag (self->view, "device");
     643                 :             :   else
     644                 :           0 :     adw_navigation_view_pop (self->view);
     645                 :             : 
     646                 :           1 :   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_FILES]);
     647                 :             : }
     648                 :             : 
     649                 :             : static void
     650                 :           1 : valent_share_dialog_set_selection_mode (ValentShareDialog *self,
     651                 :             :                                         gboolean           selection_mode)
     652                 :             : {
     653         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_DIALOG (self));
     654                 :             : 
     655                 :           1 :   selection_mode = !!selection_mode;
     656         [ -  + ]:           1 :   if (self->selection_mode == selection_mode)
     657                 :             :     return;
     658                 :             : 
     659         [ #  # ]:           0 :   gtk_list_box_set_selection_mode (self->device_list,
     660                 :             :                                    selection_mode
     661                 :             :                                     ? GTK_SELECTION_MULTIPLE
     662                 :             :                                     : GTK_SELECTION_NONE);
     663                 :             : 
     664                 :           0 :   self->selection_mode = selection_mode;
     665                 :           0 :   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTION_MODE]);
     666                 :             : }
     667                 :             : 
     668                 :             : static void
     669                 :           0 : valent_share_dialog_share (ValentShareDialog    *self,
     670                 :             :                            ValentShareDialogRow *row)
     671                 :             : {
     672                 :           0 :   ValentDevice *device = NULL;
     673                 :           0 :   GVariantBuilder builder;
     674                 :           0 :   unsigned int n_files = 0;
     675                 :             : 
     676                 :           0 :   g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
     677                 :           0 :   n_files = g_list_model_get_n_items (self->files);
     678                 :             : 
     679         [ #  # ]:           0 :   for (unsigned int i = 0; i < n_files; i++)
     680                 :             :     {
     681                 :           0 :       g_autoptr (GFile) file = g_list_model_get_item (self->files, i);
     682                 :           0 :       GVariant *uri = g_variant_new_take_string (g_file_get_uri (file));
     683                 :             : 
     684         [ #  # ]:           0 :       g_variant_builder_add_value (&builder, uri);
     685                 :             :     }
     686                 :             : 
     687                 :           0 :   device = valent_share_dialog_row_get_device (row);
     688                 :           0 :   g_action_group_activate_action (G_ACTION_GROUP (device),
     689                 :             :                                   "share.uris",
     690                 :             :                                   g_variant_builder_end (&builder));
     691                 :             : 
     692                 :           0 :   gtk_window_close (GTK_WINDOW (self));
     693                 :           0 : }
     694                 :             : 
     695                 :             : /*
     696                 :             :  * GObject
     697                 :             :  */
     698                 :             : static void
     699                 :           1 : valent_share_dialog_constructed (GObject *object)
     700                 :             : {
     701                 :           1 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (object);
     702                 :             : 
     703                 :           1 :   self->manager = valent_device_manager_get_default ();
     704                 :           1 :   g_signal_connect_object (self->manager,
     705                 :             :                            "items-changed",
     706                 :             :                            G_CALLBACK (on_items_changed),
     707                 :             :                            self, 0);
     708                 :           1 :   on_items_changed (G_LIST_MODEL (self->manager),
     709                 :             :                     0,
     710                 :             :                     0,
     711                 :           1 :                     g_list_model_get_n_items (G_LIST_MODEL (self->manager)),
     712                 :             :                     self);
     713                 :             : 
     714                 :             :   /* Broadcast every 5 seconds to re-connect devices that may have gone idle */
     715                 :           1 :   valent_device_manager_refresh (self->manager);
     716                 :           1 :   self->refresh_id = g_timeout_add_seconds_full (G_PRIORITY_LOW,
     717                 :             :                                                  5,
     718                 :             :                                                  valent_share_dialog_refresh,
     719                 :           1 :                                                  g_object_ref (self->manager),
     720                 :             :                                                  g_object_unref);
     721                 :             : 
     722                 :           1 :   G_OBJECT_CLASS (valent_share_dialog_parent_class)->constructed (object);
     723                 :           1 : }
     724                 :             : 
     725                 :             : static void
     726                 :           1 : valent_share_dialog_dispose (GObject *object)
     727                 :             : {
     728                 :           1 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (object);
     729                 :             : 
     730         [ +  - ]:           1 :   g_clear_handle_id (&self->refresh_id, g_source_remove);
     731                 :             : 
     732         [ +  - ]:           1 :   if (self->manager != NULL)
     733                 :             :     {
     734                 :           1 :       g_signal_handlers_disconnect_by_data (self->manager, self);
     735                 :           1 :       self->manager = NULL;
     736                 :             :     }
     737                 :             : 
     738         [ +  - ]:           1 :   if (self->cancellable != NULL)
     739                 :             :     {
     740                 :           1 :       g_cancellable_cancel (self->cancellable);
     741         [ +  - ]:           1 :       g_clear_object (&self->cancellable);
     742                 :             :     }
     743                 :             : 
     744         [ +  - ]:           1 :   g_clear_object (&self->files);
     745         [ -  + ]:           1 :   g_clear_pointer (&self->rows, g_ptr_array_unref);
     746                 :             : 
     747                 :           1 :   gtk_widget_dispose_template (GTK_WIDGET (object),
     748                 :             :                                VALENT_TYPE_SHARE_DIALOG);
     749                 :             : 
     750                 :           1 :   G_OBJECT_CLASS (valent_share_dialog_parent_class)->dispose (object);
     751                 :           1 : }
     752                 :             : 
     753                 :             : static void
     754                 :           4 : valent_share_dialog_get_property (GObject    *object,
     755                 :             :                                   guint       prop_id,
     756                 :             :                                   GValue     *value,
     757                 :             :                                   GParamSpec *pspec)
     758                 :             : {
     759                 :           4 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (object);
     760                 :             : 
     761      [ +  +  - ]:           4 :   switch (prop_id)
     762                 :             :     {
     763                 :           1 :     case PROP_FILES:
     764                 :           1 :       g_value_set_object (value, self->files);
     765                 :           1 :       break;
     766                 :             : 
     767                 :           3 :     case PROP_SELECTION_MODE:
     768                 :           3 :       g_value_set_boolean (value, self->selection_mode);
     769                 :           3 :       break;
     770                 :             : 
     771                 :           0 :     default:
     772                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     773                 :             :     }
     774                 :           4 : }
     775                 :             : 
     776                 :             : static void
     777                 :           2 : valent_share_dialog_set_property (GObject      *object,
     778                 :             :                                   guint         prop_id,
     779                 :             :                                   const GValue *value,
     780                 :             :                                   GParamSpec   *pspec)
     781                 :             : {
     782                 :           2 :   ValentShareDialog *self = VALENT_SHARE_DIALOG (object);
     783                 :             : 
     784      [ +  +  - ]:           2 :   switch (prop_id)
     785                 :             :     {
     786                 :           1 :     case PROP_FILES:
     787                 :           1 :       valent_share_dialog_set_files (self, g_value_get_object (value));
     788                 :           1 :       break;
     789                 :             : 
     790                 :           1 :     case PROP_SELECTION_MODE:
     791                 :           1 :       valent_share_dialog_set_selection_mode (self, g_value_get_boolean (value));
     792                 :           1 :       break;
     793                 :             : 
     794                 :           0 :     default:
     795                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     796                 :             :     }
     797                 :           2 : }
     798                 :             : 
     799                 :             : static void
     800                 :           1 : valent_share_dialog_class_init (ValentShareDialogClass *klass)
     801                 :             : {
     802                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     803                 :           1 :   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
     804                 :             : 
     805                 :           1 :   object_class->constructed = valent_share_dialog_constructed;
     806                 :           1 :   object_class->dispose = valent_share_dialog_dispose;
     807                 :           1 :   object_class->get_property = valent_share_dialog_get_property;
     808                 :           1 :   object_class->set_property = valent_share_dialog_set_property;
     809                 :             : 
     810                 :           1 :   gtk_widget_class_set_template_from_resource (widget_class, "/plugins/share/valent-share-dialog.ui");
     811                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, view);
     812                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, device_list);
     813                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, single_row);
     814                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, single_icon);
     815                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, multiple_row);
     816                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, multiple_icon);
     817                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentShareDialog, uri_entry);
     818                 :           1 :   gtk_widget_class_bind_template_callback (widget_class, on_device_activated);
     819                 :           1 :   gtk_widget_class_bind_template_callback (widget_class, on_uri_activated);
     820                 :           1 :   gtk_widget_class_bind_template_callback (widget_class, on_uri_changed);
     821                 :             : 
     822                 :           1 :   gtk_widget_class_install_action (widget_class, "chooser.share", NULL, chooser_share_action);
     823                 :           1 :   gtk_widget_class_install_action (widget_class, "chooser.select-files", NULL, chooser_select_files_action);
     824                 :             : 
     825                 :             :   /**
     826                 :             :    * ValentShareDialog:files:
     827                 :             :    *
     828                 :             :    * The URIs to share.
     829                 :             :    */
     830                 :           2 :   properties [PROP_FILES] =
     831                 :           1 :     g_param_spec_object ("files", NULL, NULL,
     832                 :             :                          G_TYPE_LIST_MODEL,
     833                 :             :                          (G_PARAM_READWRITE |
     834                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     835                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     836                 :             :                           G_PARAM_STATIC_STRINGS));
     837                 :             : 
     838                 :             :   /**
     839                 :             :    * ValentShareDialog:selection-mode:
     840                 :             :    *
     841                 :             :    * Whether multiple devices can be selected.
     842                 :             :    */
     843                 :           2 :   properties [PROP_SELECTION_MODE] =
     844                 :           1 :     g_param_spec_boolean ("selection-mode", NULL, NULL,
     845                 :             :                           FALSE,
     846                 :             :                           (G_PARAM_READWRITE |
     847                 :             :                            G_PARAM_CONSTRUCT |
     848                 :             :                            G_PARAM_EXPLICIT_NOTIFY |
     849                 :             :                            G_PARAM_STATIC_STRINGS));
     850                 :             : 
     851                 :           1 :   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
     852                 :           1 : }
     853                 :             : 
     854                 :             : static void
     855                 :           1 : valent_share_dialog_init (ValentShareDialog *self)
     856                 :             : {
     857                 :           1 :   gtk_widget_init_template (GTK_WIDGET (self));
     858                 :           1 : }
     859                 :             : 
        

Generated by: LCOV version 2.0-1