anastasis-gtk

Demonstrator GUI for Anastasis
Log | Files | Refs | README | LICENSE

anastasis-gtk_autocomplete.c (6649B)


      1 /*
      2      This file is part of anastasis-gtk.
      3      Copyright (C) 2021 Anastasis SARL
      4 
      5      Anastasis is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      Anastasis 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      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with Anastasis; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 */
     20 /**
     21  * @file src/anastasis/anastasis-gtk_autocomplete.c
     22  * @brief Autocomplete logic for GtkEntry widgets
     23  * @author Christian Grothoff
     24  */
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include "anastasis-gtk_attributes.h"
     27 #include "anastasis-gtk_dispatch.h"
     28 #include "anastasis-gtk_helper.h"
     29 #include <jansson.h>
     30 
     31 
     32 /**
     33  * Lookup autocompletion string for @a editable widget.
     34  *
     35  * @param editable widget to lookup
     36  * @return NULL if not found
     37  */
     38 static const char *
     39 lookup_autocomplete (GtkEditable *editable)
     40 {
     41   json_t *a;
     42   size_t index;
     43   json_t *ra = json_object_get (AG_redux_state,
     44                                 "required_attributes");
     45   if (NULL == ra)
     46   {
     47     GNUNET_break (0);
     48     return NULL;
     49   }
     50   json_array_foreach (ra, index, a)
     51   {
     52     const char *autocomplete = NULL;
     53     const char *widget_name = NULL;
     54     const char *type = NULL;
     55     char *data_name;
     56     bool match;
     57     struct GNUNET_JSON_Specification spec[] = {
     58       GNUNET_JSON_spec_mark_optional (
     59         GNUNET_JSON_spec_string ("widget",
     60                                  &widget_name),
     61         NULL),
     62       GNUNET_JSON_spec_mark_optional (
     63         GNUNET_JSON_spec_string ("autocomplete",
     64                                  &autocomplete),
     65         NULL),
     66       GNUNET_JSON_spec_string ("type",
     67                                &type),
     68       GNUNET_JSON_spec_end ()
     69     };
     70 
     71     if (GNUNET_OK !=
     72         GNUNET_JSON_parse (a,
     73                            spec,
     74                            NULL, NULL))
     75     {
     76       GNUNET_break (0);
     77       continue;
     78     }
     79     if ( (NULL == autocomplete) ||
     80          (NULL == widget_name) )
     81       continue;
     82     data_name = AG_expand_name (widget_name,
     83                                 type);
     84     match = (editable ==
     85              GTK_EDITABLE (GCG_get_main_window_object (data_name)));
     86     GNUNET_free (data_name);
     87     if (match)
     88       return autocomplete;
     89   }
     90   GNUNET_break (0);
     91   return NULL;
     92 }
     93 
     94 
     95 /**
     96  * Function called from an auto-completed entry widget up on upon text
     97  * deletion.
     98  *
     99  * @param editable the widget
    100  * @param start_pos starting position
    101  * @param end_pos end position
    102  * @param user_data unused
    103  */
    104 void
    105 anastasis_gtk_autocomplete_delete_text (GtkEditable *editable,
    106                                         int start_pos,
    107                                         int end_pos,
    108                                         void *user_data)
    109 {
    110   const char *ac;
    111   (void) user_data;
    112 
    113   ac = lookup_autocomplete (editable);
    114   if (NULL == ac)
    115     return;
    116   if (0 == start_pos)
    117     return;
    118 #if CONFUSING_UX_DESIRED
    119   if (ac[start_pos] != '?')
    120   {
    121     g_signal_stop_emission_by_name (editable,
    122                                     "delete-text");
    123     gtk_editable_delete_text (editable,
    124                               start_pos - 1,
    125                               end_pos);
    126   }
    127 #endif
    128 }
    129 
    130 
    131 /**
    132  * Function called from an auto-completed widget upon text insertion.
    133  *
    134  * @param editable the widget
    135  * @param new_text inserted text
    136  * @param new_text_length number of bytes in @a new_text
    137  * @param position insertion position
    138  * @param user_data unused
    139  */
    140 void
    141 anastasis_gtk_autocomplete_insert_text (GtkEditable *editable,
    142                                         const char *new_text,
    143                                         int new_text_length,
    144                                         gpointer position,
    145                                         void *user_data)
    146 {
    147   const char *ac;
    148   gint pos;
    149   char *replacement;
    150 
    151   (void) user_data;
    152   ac = lookup_autocomplete (editable);
    153   if (NULL == ac)
    154     return;
    155   pos = gtk_editable_get_position (editable);
    156   if (strlen (ac) <= pos + new_text_length)
    157     return;
    158   if (ac[pos + new_text_length] != '?')
    159   {
    160     g_signal_stop_emission_by_name (editable,
    161                                     "insert-text");
    162     GNUNET_asprintf (&replacement,
    163                      "%.*s%c",
    164                      new_text_length,
    165                      new_text,
    166                      ac[pos + new_text_length]);
    167     gtk_editable_insert_text (editable,
    168                               replacement,
    169                               -1,
    170                               position);
    171     GNUNET_free (replacement);
    172   }
    173 }
    174 
    175 
    176 /**
    177  * Function called from an auto-completed PIN widget upon text insertion.
    178  *
    179  * @param editable the widget
    180  * @param new_text inserted text
    181  * @param new_text_length number of bytes in @a new_text
    182  * @param position insertion position
    183  * @param user_data unused
    184  */
    185 void
    186 anastasis_gtk_pin_autocomplete_insert_text (GtkEditable *editable,
    187                                             const char *new_text,
    188                                             int new_text_length,
    189                                             gpointer position,
    190                                             void *user_data)
    191 {
    192   /* Use \? to break up trigraphs */
    193   const char *acn =   "????\?-??\?-???\?-??\?";
    194   const char *aca = "A-????\?-??\?-???\?-??\?";
    195   const char *ac;
    196   gint pos;
    197   char *replacement;
    198   gchar *pfx;
    199 
    200   (void) user_data;
    201   pfx = gtk_editable_get_chars (editable,
    202                                 0,
    203                                 2);
    204   if (0 == strncasecmp (pfx,
    205                         "A-",
    206                         2))
    207     ac = aca;
    208   else
    209     ac = acn;
    210   g_free (pfx);
    211 
    212   pos = gtk_editable_get_position (editable);
    213   if (strlen (ac) <= pos + new_text_length)
    214     return;
    215   if (ac[pos + new_text_length] != '?')
    216   {
    217     g_signal_stop_emission_by_name (editable,
    218                                     "insert-text");
    219     GNUNET_asprintf (&replacement,
    220                      "%.*s%c",
    221                      new_text_length,
    222                      new_text,
    223                      ac[pos + new_text_length]);
    224     gtk_editable_insert_text (editable,
    225                               replacement,
    226                               -1,
    227                               position);
    228     GNUNET_free (replacement);
    229   }
    230 }