00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00029 
00030 #include <string.h>
00031 #include <ctype.h>
00032 #include <gtk/gtk.h>
00033 
00034 
00035 
00036 
00037 #include "ergtklog.h"
00038 #include "erGtkEntry.h"
00039 #include "erGtkEntryFilter.h"
00040 
00041 
00042 #undef gtk_entry_set_text
00043 
00044 
00045 
00046 static GtkEntryClass* g_parent_class = NULL;
00047 
00048 
00049 enum
00050 {
00051     SIGNAL_CHANGED_STABLE = 0,       
00052     SIGNAL_SCREEN_REFRESH,           
00053     LAST_SIGNAL
00054 };
00055 static gint g_signals[LAST_SIGNAL];  
00056 
00057 
00058 
00059 static void     ergtk_entry_grab_focus(GtkWidget* widget);
00060 
00061 
00062 static void     ergtk_entry_notify(GObject* object, GParamSpec* pspec);
00063 static gboolean ergtk_entry_focus_in(GtkWidget* widget, GdkEventFocus* event);
00064 static gboolean ergtk_entry_focus_out(GtkWidget* widget, GdkEventFocus* event);
00065 static gboolean ergtk_entry_focus(GtkWidget* widget, GtkDirectionType arg1);
00066 static gboolean ergtk_entry_button_release(GtkWidget* widget, GdkEventButton* event);
00067 static void     ergtk_entry_move_cursor(GtkEntry* widget, GtkMovementStep arg1, gint arg2, gboolean arg3);
00068 static void     ergtk_entry_changed(GtkEditable* widget);
00069 
00070 
00071 static void     ergtk_entry_real_set_text(erGtkEntry* er_entry, const gchar* text);
00072 
00073 
00074 static void     ergtk_entry_class_init(erGtkEntryClass* klass);
00075 static void     ergtk_entry_editable_init(GtkEditableClass*iface);
00076 static void     ergtk_entry_init(erGtkEntry* input_entry);
00077 static gboolean ergtk_entry_delayed_changed_or_movecursor(gpointer user_data);
00078 
00079 
00080 GtkWidget* ergtk_entry_new()
00081 {
00082     erGtkEntry* item = (erGtkEntry*) g_object_new(ERGTK_ENTRY_TYPE, NULL);
00083 
00084     return GTK_WIDGET(item);
00085 }
00086 
00087 void ergtk_entry_set_ipv4_filter(erGtkEntry* er_entry)
00088 {
00089     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00090 
00091     er_entry->filter = ipAddress_e;
00092     ipv4_filter_init(GTK_ENTRY(er_entry));
00093 }
00094 
00095 void ergtk_entry_set_integer_filter(erGtkEntry* er_entry)
00096 {
00097     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00098 
00099     er_entry->filter = integer_e;
00100     integer_filter_init(GTK_ENTRY(er_entry));
00101 }
00102 
00103 gboolean ergtk_entry_check_field(erGtkEntry *er_entry)
00104 {
00105     GtkEntry    *entry;
00106     const gchar *text;
00107     gint         i, len, ret;
00108     gboolean     valid = FALSE;
00109 
00110     g_return_val_if_fail(ERGTK_IS_ENTRY(er_entry), FALSE);
00111 
00112     entry = GTK_ENTRY(er_entry);
00113     text = gtk_entry_get_text(entry);
00114     if (text && (text[0] != '\0'))
00115     {
00116         switch (er_entry->filter)
00117         {
00118             case ipAddress_e:
00119                 ret = ipv4_filter_check_address(text);
00120                 if (ret == ipv4Complete_e)
00121                 {
00122                     valid = TRUE;
00123                 }
00124                 break;
00125 
00126             case integer_e:
00127                 valid = TRUE;
00128                 len = strlen(text);
00129                 for (i = 0; i < len; i++)
00130                 {
00131                     if (!isdigit(text[i]))
00132                     {
00133                         valid = FALSE;
00134                         break;
00135                     }
00136                 }
00137                 break;
00138             case string_e:
00139             default:
00140                 valid = TRUE;
00141                 break;
00142         }
00143     }
00144 
00145     LOGPRINTF("return %d", valid);
00146     return valid;
00147 }
00148 
00149 GType ergtk_entry_get_type(void)
00150 {
00151     static GType class_type = 0;
00152 
00153     if (class_type == 0)
00154     {
00155         static const GTypeInfo class_info =
00156         {
00157             sizeof(erGtkEntryClass),
00158             NULL,               
00159             NULL,               
00160             (GClassInitFunc) ergtk_entry_class_init,
00161             NULL,               
00162             NULL,               
00163             sizeof(erGtkEntry),
00164             0,                  
00165             (GInstanceInitFunc) ergtk_entry_init,
00166         };
00167         class_type = g_type_register_static(GTK_TYPE_ENTRY, "erGtkEntry", &class_info, 0);
00168 
00169         static const GInterfaceInfo editable_info =
00170         {
00171             (GInterfaceInitFunc)ergtk_entry_editable_init, 
00172             NULL, 
00173             NULL  
00174         };
00175         g_type_add_interface_static(class_type, GTK_TYPE_EDITABLE, &editable_info);
00176     }
00177 
00178     return class_type;
00179 }
00180 
00181 
00182 static void ergtk_entry_class_init(erGtkEntryClass* klass)
00183 {
00184     LOGPRINTF("entry");
00185 
00186     GObjectClass*   object_class = (GObjectClass*  )klass;
00187     GtkWidgetClass* widget_class = (GtkWidgetClass*)klass;
00188     GtkEntryClass*  entry_class  = (GtkEntryClass* )klass;
00189 
00190     
00191     g_parent_class = g_type_class_peek_parent(klass);
00192 
00193     
00194     object_class->notify = ergtk_entry_notify;
00195     
00196     widget_class->button_release_event = ergtk_entry_button_release;
00197     widget_class->focus_in_event       = ergtk_entry_focus_in;
00198     widget_class->focus_out_event      = ergtk_entry_focus_out;
00199     widget_class->focus                = ergtk_entry_focus;
00200     widget_class->grab_focus           = ergtk_entry_grab_focus;
00201     
00202     entry_class->move_cursor = ergtk_entry_move_cursor;
00203     
00204     klass->set_text          = ergtk_entry_real_set_text;
00205 
00206     
00207     g_signals[SIGNAL_CHANGED_STABLE] = g_signal_new( "changed-stable",
00208                                                      G_OBJECT_CLASS_TYPE(object_class),
00209                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
00210                                                      G_STRUCT_OFFSET(erGtkEntryClass, changed_stable),   
00211                                                      NULL,         
00212                                                      NULL,         
00213                                                      gtk_marshal_VOID__VOID,
00214                                                      G_TYPE_NONE,  
00215                                                      0,            
00216                                                      0 );          
00217     
00218     g_signals[SIGNAL_SCREEN_REFRESH] = g_signal_new( "screen-refresh",
00219                                                      G_OBJECT_CLASS_TYPE(object_class),
00220                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
00221                                                      G_STRUCT_OFFSET(erGtkEntryClass, screen_refresh),   
00222                                                      NULL,         
00223                                                      NULL,         
00224                                                      gtk_marshal_VOID__VOID,
00225                                                      G_TYPE_NONE,  
00226                                                      0,            
00227                                                      0 );          
00228 }
00229 
00230 
00231 static void ergtk_entry_editable_init(GtkEditableClass* iface)
00232 {
00233     iface->changed = ergtk_entry_changed;
00234 }
00235 
00236 
00237 static void ergtk_entry_init(erGtkEntry* er_entry)
00238 {
00239     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00240 
00241     GtkEntry*  entry  = (GtkEntry*) er_entry;
00242     GtkWidget* widget = (GtkWidget*)er_entry;
00243     
00244     
00245     g_object_set(gtk_widget_get_settings(widget), "gtk-cursor-blink", FALSE, NULL);
00246     
00247     
00248     gtk_entry_set_editable(entry, TRUE);
00249     gtk_widget_set_size_request(widget, ERGTK_ENTRY_DEFAULT_WIDTH, ERGTK_ENTRY_DEFAULT_HEIGHT);
00250     gtk_entry_set_visibility(entry, TRUE);
00251    
00252     
00253     er_entry->timeout_id          = 0;
00254     er_entry->changed_pending     = FALSE;
00255     er_entry->changed_occurred    = FALSE;
00256     er_entry->movecursor_occurred = FALSE;
00257     er_entry->visible             = TRUE;
00258     er_entry->filter              = string_e;
00259 }
00260 
00261 
00262 
00263 void ergtk_entry_set_text(erGtkEntry* er_entry, const gchar* text)
00264 {
00265     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00266 
00267     erGtkEntryClass* klass = ERGTK_ENTRY_GET_CLASS(er_entry);
00268 
00269     
00270     if (klass->set_text)
00271     {
00272         klass->set_text(er_entry, text);
00273     }
00274 }
00275 
00276 static void ergtk_entry_real_set_text(erGtkEntry* er_entry, const gchar* text)
00277 {
00278     g_return_if_fail(ERGTK_IS_ENTRY(er_entry));
00279     g_return_if_fail(text != NULL);
00280 
00281     GtkEntry* entry = (GtkEntry*)er_entry;
00282 
00283     if (strcmp(text, gtk_entry_get_text(entry)) != 0)
00284     {
00285         
00286         
00287         
00288         er_entry->changed_pending = TRUE;
00289 
00290         
00291         gtk_entry_set_text(entry, text);
00292     }
00293 }
00294 
00295 
00296 
00297 static void ergtk_entry_notify(GObject* object, GParamSpec* pspec)
00298 {
00299     g_return_if_fail(ERGTK_IS_ENTRY(object));
00300 
00301     GtkWidget* widget = (GtkWidget*)object;
00302 
00303     
00304     GObjectClass* parent_object_class = G_OBJECT_CLASS(g_parent_class);
00305     if (parent_object_class->notify)
00306     {
00307         parent_object_class->notify(object, pspec);
00308     }
00309 
00310     gboolean     b;
00311     const gchar* name = pspec->name;
00312 
00313     if (strcmp(name, "editable") == 0)
00314     {
00315         g_object_get(object, name, &b, NULL);
00316         gtk_widget_set_sensitive(widget, b);
00317     }
00318 }
00319 
00320 static gboolean ergtk_entry_focus_in(GtkWidget* widget, GdkEventFocus* event)
00321 {
00322     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00323 
00324     gboolean    rc = FALSE;
00325     GtkEntry*   entry    = (GtkEntry*)widget;
00326     erGtkEntry* er_entry = (erGtkEntry*)widget;
00327 
00328     
00329     if (g_parent_class->parent_class.focus_in_event)
00330     {
00331         rc = g_parent_class->parent_class.focus_in_event(widget, event);
00332     }
00333 
00334     
00335     er_entry->visible = gtk_entry_get_visibility(entry);
00336     if (er_entry->visible == FALSE)
00337     {
00338         const gchar* text = gtk_entry_get_text(entry);
00339         if (text[0] == '\0')
00340         {
00341             gtk_entry_set_visibility(entry, TRUE);
00342         }
00343     }
00344     
00345     return rc;
00346 }
00347 
00348 static gboolean ergtk_entry_focus_out(GtkWidget* widget, GdkEventFocus* event)
00349 {
00350     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00351 
00352     gboolean    rc = FALSE;
00353     GtkEntry*   entry    = GTK_ENTRY(widget);
00354     erGtkEntry* er_entry = ERGTK_ENTRY(widget);
00355 
00356     
00357     if (g_parent_class->parent_class.focus_out_event)
00358     {
00359         rc = g_parent_class->parent_class.focus_out_event(widget, event);
00360     }
00361 
00362     
00363     gtk_editable_select_region(GTK_EDITABLE(entry), -1, -1);
00364 
00365     
00366     if (er_entry->visible == FALSE)
00367     {
00368         gtk_entry_set_visibility(entry, FALSE);
00369     }
00370     
00371     return rc;
00372 }
00373 
00374 static gboolean ergtk_entry_focus(GtkWidget* widget, GtkDirectionType arg1)
00375 {
00376     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00377 
00378     gboolean    rc = FALSE;
00379     erGtkEntry* er_entry = (erGtkEntry*)widget;
00380 
00381     
00382     if (g_parent_class->parent_class.focus)
00383     {
00384         rc = g_parent_class->parent_class.focus(widget, arg1);
00385     }
00386 
00387     g_signal_emit(er_entry, g_signals[SIGNAL_SCREEN_REFRESH], 0, GTK_WIDGET(er_entry), NULL);
00388     return rc;
00389 }
00390 
00391 static void ergtk_entry_grab_focus(GtkWidget* widget)
00392 {
00393     g_return_if_fail(ERGTK_IS_ENTRY(widget));
00394 
00395     
00396     if (   gtk_widget_is_focus(widget) == FALSE
00397         && g_parent_class->parent_class.grab_focus )
00398     {
00399         g_parent_class->parent_class.grab_focus(widget);
00400     }
00401 }
00402 
00403 static void ergtk_entry_changed(GtkEditable* editable)
00404 {
00405     g_return_if_fail(ERGTK_IS_ENTRY(editable));
00406 
00407     erGtkEntry* er_entry = (erGtkEntry*)editable;
00408     GtkEntry*   entry    = (GtkEntry*)editable;
00409     GtkWidget*  widget   = (GtkWidget*)editable;
00410 
00411     
00412     if (   er_entry->visible == FALSE
00413         && gtk_widget_is_focus(widget) )
00414     {
00415         const gchar* text = gtk_entry_get_text(entry);
00416         if (text[0] == '\0')
00417         {
00418             gtk_entry_set_visibility(entry, TRUE);
00419         }
00420     }
00421 
00422     if (er_entry->changed_pending)
00423     {
00424         
00425         er_entry->changed_pending = FALSE;
00426     }
00427     else
00428     {
00429         
00430         if (er_entry->timeout_id > 0)
00431         {
00432             g_source_remove(er_entry->timeout_id);
00433         }
00434         er_entry->timeout_id = g_timeout_add(300, ergtk_entry_delayed_changed_or_movecursor, er_entry);
00435         er_entry->changed_occurred = TRUE;
00436     }
00437 }
00438 
00439 static void ergtk_entry_move_cursor(GtkEntry* widget, GtkMovementStep arg1, gint arg2, gboolean arg3)
00440 {
00441     g_return_if_fail(ERGTK_IS_ENTRY(widget));
00442 
00443     erGtkEntry* er_entry = (erGtkEntry*)widget;
00444 
00445     
00446     if (g_parent_class->move_cursor)
00447     {
00448         g_parent_class->move_cursor(widget, arg1, arg2, arg3);
00449     }
00450 
00451     
00452     if (er_entry->timeout_id > 0)
00453     {
00454         g_source_remove(er_entry->timeout_id);
00455     }
00456     er_entry->timeout_id = g_timeout_add(300, ergtk_entry_delayed_changed_or_movecursor, er_entry);
00457     er_entry->movecursor_occurred = TRUE;
00458 }
00459 
00460 static gboolean ergtk_entry_button_release(GtkWidget* widget, GdkEventButton* event)
00461 {
00462     g_return_val_if_fail(ERGTK_IS_ENTRY(widget), FALSE);
00463 
00464     gboolean    rc = FALSE;
00465     erGtkEntry* er_entry = (erGtkEntry*)widget;
00466 
00467     
00468     if (g_parent_class->parent_class.button_release_event)
00469     {
00470         rc = g_parent_class->parent_class.button_release_event(widget, event);
00471     }
00472     
00473     g_signal_emit(er_entry, g_signals[SIGNAL_SCREEN_REFRESH], 0, GTK_WIDGET(er_entry), NULL);
00474     return rc;
00475 }
00476 
00477 static gboolean ergtk_entry_delayed_changed_or_movecursor(gpointer user_data)
00478 {
00479     g_assert(ERGTK_IS_ENTRY(user_data));
00480 
00481     erGtkEntry* er_entry = (erGtkEntry*)user_data;
00482 
00483     
00484     if (er_entry->movecursor_occurred)
00485     {
00486         er_entry->movecursor_occurred = FALSE; 
00487         g_signal_emit(er_entry, g_signals[SIGNAL_SCREEN_REFRESH], 0, GTK_WIDGET(er_entry), NULL);
00488     }
00489     if (er_entry->changed_occurred)
00490     {
00491         er_entry->changed_occurred = FALSE;
00492         g_signal_emit(er_entry, g_signals[SIGNAL_CHANGED_STABLE], 0, GTK_WIDGET(er_entry), NULL);
00493         g_signal_emit(er_entry, g_signals[SIGNAL_SCREEN_REFRESH], 0, GTK_WIDGET(er_entry), NULL);
00494     }
00495 
00496     er_entry->timeout_id = 0;
00497     return FALSE;  
00498 }
00499