OSDN Git Service

history + hotkeys(partly)
authoriev <iev@land.ru>
Wed, 24 Aug 2011 15:43:42 +0000 (19:43 +0400)
committeriev <iev@land.ru>
Wed, 24 Aug 2011 15:43:42 +0000 (19:43 +0400)
src/eb123.c
src/eb123.glade
src/history.c
src/history.h
src/hotkeys.c
src/hotkeys.h
src/mainwnd.c
src/mainwnd.h
src/prefs.c
src/textview.c
src/textview.h

index 1b11cb8..e1f706a 100644 (file)
@@ -48,7 +48,6 @@ int main(int argc, char *argv[])
 
     hooksets_init();
 
-    //history_load_words();
     //hotkeys_load();
 
     mainwnd_prepare(mainwnd);
index 08f829d..d9c4f27 100644 (file)
               <object class="GtkComboBox" id="mainwnd_search">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="model">mainwnd_search_store</property>
+                <property name="active">0</property>
                 <property name="has_entry">True</property>
+                <property name="entry_text_column">0</property>
               </object>
               <packing>
                 <property name="expand">True</property>
                 <property name="width_request">100</property>
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="model">mainwnd_search_store</property>
+                <property name="model">mainwnd_search_method_store</property>
               </object>
               <packing>
                 <property name="expand">False</property>
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="button3">
+              <object class="GtkButton" id="mainwnd_prev">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
                 <property name="use_action_appearance">False</property>
                 <property name="relief">none</property>
+                <signal name="clicked" handler="mainwnd_prev_clicked_cb" swapped="no"/>
                 <child>
                   <object class="GtkImage" id="image7">
                     <property name="visible">True</property>
       <column type="gpointer"/>
     </columns>
   </object>
-  <object class="GtkListStore" id="mainwnd_search_store">
+  <object class="GtkListStore" id="mainwnd_search_method_store">
     <columns>
       <!-- column-name text -->
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="mainwnd_search_store">
+    <columns>
+      <!-- column-name history -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <object class="GtkWindow" id="popupwnd">
     <property name="can_focus">False</property>
     <property name="type">popup</property>
                               <object class="GtkComboBox" id="popupwnd.search_method">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="model">mainwnd_search_store</property>
+                                <property name="model">mainwnd_search_method_store</property>
                               </object>
                               <packing>
                                 <property name="left_attach">1</property>
                         <property name="can_focus">False</property>
                         <property name="left_padding">12</property>
                         <child>
-                          <placeholder/>
+                          <object class="GtkHBox" id="hbox9">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkVBox" id="vbox5">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkScrolledWindow" id="scrolledwindow4">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="hscrollbar_policy">never</property>
+                                    <child>
+                                      <object class="GtkViewport" id="viewport1">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkVBox" id="hotkeys_vbox">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="spacing">10</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="checkbutton1">
+                                    <property name="label" translatable="yes">Ignore locks</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="use_action_appearance">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
                         </child>
                       </object>
                     </child>
index 5bd04aa..df31e80 100644 (file)
@@ -8,12 +8,45 @@
 extern Builder *_builder;
 extern Prefs *_prefs;
 
-void history_prev()
+G_DEFINE_TYPE(History, history, G_TYPE_OBJECT);
+
+static gint history_selection_depth = -1;
+
+static void history_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
+{
+    History *history = HISTORY(object);
+    switch(param_id)
+    {
+       case 1:
+           history->builder = BUILDER(g_value_get_pointer(value));
+           break;
+       case 2:
+           history->prefs = PREFS(g_value_get_pointer(value));
+           break;
+       default:
+           G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+           break;
+    }
+}
+
+static void history_class_init(HistoryClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+    gobject_class->set_property = history_set_property;
+    g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("builder", _("Builder"), _("Builder"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
+    g_object_class_install_property(gobject_class, 2, g_param_spec_pointer("prefs", _("Prefs"), _("Prefs"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
+}
+
+static void history_init(History *self)
+{
+}
+
+void history_prev(History *self)
 {
     GList *hist, *hist1;
     RESULT *res;
 
-    hist = g_list_last(history.list);
+    hist = g_list_last(self->list);
     if(!hist)
         return;
 
@@ -22,27 +55,27 @@ void history_prev()
         return;
 
     result_free((RESULT *)hist->data);
-    history.list = g_list_delete_link(history.list, hist);
+    self->list = g_list_delete_link(self->list, hist);
     
     res = (RESULT *)(hist1->data);
-    //mainwnd_open(res);
+    mainwnd_open(MAINWND(mainwnd_get_wnd()), res);
 }
 
-void history_next(RESULT *res)
+void history_insert_res(History *self, RESULT *res)
 {
-    GList *hist = g_list_last(history.list);
+    GList *hist = g_list_last(self->list);
     if(hist)
     {
         RESULT *res1 = (RESULT*)hist->data;
         if((res1->binfo == res->binfo) && (res1->pos.page == res->pos.page) && (res1->pos.offset == res->pos.offset))
             return;
     }
-    history.list = g_list_append(history.list, result_duplicate(res));
+    self->list = g_list_append(self->list, result_duplicate(res));
 }
 
-RESULT *history_last_result()
+RESULT *history_last_result(History *self)
 {
-    GList *hist = g_list_last(history.list);
+    GList *hist = g_list_last(self->list);
     if(hist)
         return (RESULT*)hist->data;
     return NULL;
@@ -61,7 +94,7 @@ gboolean history_remove_word(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter
     return FALSE;
 }
 
-void history_insert_word(const gchar *word)
+void history_insert_word(History *self, const gchar *word)
 {
     gboolean b;
     GtkTreeIter iter;
@@ -71,17 +104,20 @@ void history_insert_word(const gchar *word)
 
     gtk_tree_model_foreach(model, history_remove_word, (gpointer)word);
     gtk_tree_model_foreach(model, history_remove_word, (gpointer)word);
-#if 0
-    while(gtk_tree_model_iter_n_children(model, NULL) > dictbar.word_hist)
+    gint n = prefs_get_int(self->prefs, "dictbar.word_hist");
+#if 1
+    while(gtk_tree_model_iter_n_children(model, NULL) > n)
     {
-        path = gtk_tree_path_new_from_indices(dictbar.word_hist - 1, -1);
+        path = gtk_tree_path_new_from_indices(n - 1, -1);
         b = gtk_tree_model_get_iter(model, &iter, path);
         gtk_tree_path_free(path);
         if(!b)  break;
         gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
     }
-    gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(mainwnd_search), word);
-    gtk_combo_box_set_active(mainwnd_search, 0);
+    gtk_list_store_prepend(GTK_LIST_STORE(model), &iter);
+    gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, word, -1);
+    //gtk_combo_box_text_prepend_text(GTK_COMBO_BOX_TEXT(mainwnd_search), word);
+    //gtk_combo_box_set_active(mainwnd_search, 0);
 #endif
     return;
 }
@@ -96,10 +132,10 @@ gboolean history_save_word(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *
     return FALSE;
 }
 
-void history_save_words()
+void history_save_words(History *self)
 {
     gchar filename[PATH_MAX];
-    GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(_builder), "mainwnd_search"));
+    GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search"));
     GtkTreeModel *model = gtk_combo_box_get_model(mainwnd_search);
     xmlDocPtr doc = xmlNewDoc((xmlChar*)"1.0");
     doc->children = xmlNewDocRawNode(doc, NULL, (xmlChar*)"History", NULL);
@@ -112,11 +148,20 @@ void history_save_words()
 
 void history_load_word(void *ctx, const xmlChar *name, const xmlChar **atts)
 {
+    xmlParserCtxt *ctxt = (xmlParserCtxt*)ctx;
+    xmlSAXHandler *cb = ctxt->sax;
+    History *self = HISTORY(cb->_private);
     if(!g_strcmp0((gchar*)name, "word"))
-        gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mainwnd_search), (gchar*)atts[1]);
+    {
+       GtkComboBox *mainwnd_search = GTK_COMBO_BOX(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search"));
+       GtkTreeModel *model = gtk_combo_box_get_model(mainwnd_search);
+       GtkTreeIter iter;
+       gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+       gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, (gchar*)atts[1], -1);
+    }
 }
 
-void history_load_words()
+void history_load_words(History *self)
 {
     gchar filename[PATH_MAX];
     xmlSAXHandler cb;
@@ -126,7 +171,8 @@ void history_load_words()
         return;
     memset(&cb, 0, sizeof(xmlSAXHandler));
     cb.startElement = &history_load_word;
-    xmlDocPtr doc = xmlSAXParseFile(&cb, filename, 0);
+    cb._private = self;
+    xmlDocPtr doc = xmlSAXParseFile(&cb, filename, NULL);
     xmlFreeDoc(doc);
 }
 
index 7745822..e530ab8 100644 (file)
@@ -2,13 +2,45 @@
 #ifndef __HISTORY_H_
 #define __HISTORY_H_
 
-void        history_prev();
-void        history_next(RESULT *res);
+#include "builder.h"
+#include "prefs.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_HISTORY (history_get_type ())
+#define HISTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_HISTORY, History))
+#define HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_HISTORY, HistoryClass))
+#define IS_HISTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_HISTORY))
+#define IS_HISTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_HISTORY))
+#define HISTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_HISTORY, HistoryClass))
+
+typedef struct _History History;
+typedef struct _HistoryClass HistoryClass;
+
+struct _History {
+    GObject        parent_instance;
+    GList          *list;
+    Builder        *builder;
+    Prefs          *prefs;
+};
+
+struct _HistoryClass {
+    GObjectClass    parent_class;
+};
+
+void        history_insert_word(History *self, const gchar *word);
+void       history_insert_res(History *self, RESULT *res);
+void        history_prev(History *self);
+
+void        history_save_words(History *self);
+void        history_load_words(History *self);
+
+GType      history_get_type (void);
+
+G_END_DECLS
+
 RESULT*     history_last_result();
 void        history_free_data(RESULT *res);
-void        history_insert_word(const gchar *word);
-void        history_save_words();
-void        history_load_words();
 
 RESULT*     result_new(BOOK_INFO *binfo, EB_Position *pos);
 RESULT*     result_duplicate(RESULT *res);
@@ -17,9 +49,4 @@ void        result_free(gpointer data);
 void        result_clear_all();
 gboolean    result_compare(RESULT *res1, RESULT *res2);
 
-struct _history
-{
-    GList   *list;
-} history;
-
 #endif /* __HISTORY_H_ */
index dec624e..4dcd130 100644 (file)
@@ -7,47 +7,92 @@
 #include "mainwnd.h"
 #include "prefs.h"
 
+typedef struct
+{
+    gchar *name;
+    void (* func)();
+    gboolean global;
+} HOTKEY_COMMAND;
+
+typedef struct
+{
+    guint32 mask, keyval;
+    gboolean enabled;
+} HOTKEY_EVENT;
+
 const HOTKEY_COMMAND hotkeys_list[] = {
     { _("Search"),                     mainwnd_search_, FALSE},
     { _("Go back"),                    history_prev, FALSE},
-//    { _("Clear search field"),               mainwnd_clear_combo, FALSE},
+    { _("Clear search field"),         mainwnd_clear_combo, FALSE},
 //    { _("Next hit"),                 headword_next, FALSE},
 //    { _("Previous hit"),             headword_prev, FALSE},
 //    { _("Select all dictionaries"),  dictbar_all_select, FALSE},
 //    { _("Unselect all dictionaries"),        dictbar_all_unselect, FALSE},
 //    { _("Select next group"),                dictbar_group_next, FALSE},
 //    { _("Select previous group"),    dictbar_group_prev, FALSE},
-    { _("Quit program"),               mainwnd_exit, FALSE},
-    { _("Iconify/restore main window"), mainwnd_iconify_restore, TRUE},
 //    { _("Search in main window"),    selection_search_in_mainwnd, TRUE},
 //    { _("Search in popup window"),   selection_search_in_popupwnd, TRUE},
-    {NULL, NULL, FALSE}
+    { _("Iconify/restore main window"), mainwnd_iconify_restore, TRUE},
+    { _("Quit program"),               mainwnd_exit, FALSE}
 };
 
-void hotkeys_list_init()
+G_DEFINE_TYPE(Hotkeys, hotkeys, G_TYPE_OBJECT);
+
+static Hotkeys *_hotkeys = NULL;
+
+#if 0
+static void hotkeys_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
+{   
+    Hotkeys *hotkeys = HOTKEYS(object);
+    switch(param_id)
+    {
+        case 1:
+            hotkeys->builder = BUILDER(g_value_get_pointer(value));
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+            break;
+    }
+}
+#endif
+    
+static void hotkeys_class_init(HotkeysClass *klass)
+{   
+    //GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+    //gobject_class->set_property = hotkeys_set_property;
+    //g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("builder", _("Builder"), _("Builder"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
+}   
+    
+static void hotkeys_init(Hotkeys *self)
 {
+    if(!_hotkeys)
+       _hotkeys = self;
+    else
+       g_assert(1);
     gint i;
     HOTKEY_EVENT *events = g_try_new0(HOTKEY_EVENT, sizeof(hotkeys_list));
     if(!events) return;
-    hotkeys.list = NULL;
-    for(i = 0; hotkeys_list[i].name; i++)
-       hotkeys.list = g_list_append(hotkeys.list, (gpointer)&(events[i]));
+    self->list = NULL;
+    g_printf("hotkeys list size = %d\n", SZ(hotkeys_list));
+    for(i = 0; i < SZ(hotkeys_list); i++)
+       self->list = g_list_append(self->list, (gpointer)&(events[i]));
 }
 
-static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *arg1, guint arg2, GdkModifierType arg3, gpointer user_data)
+static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *arg1, guint arg2, GdkModifierType arg3, gpointer data)
 {
     gint i;
     guint cmp;
     HOTKEY_EVENT *evt;
+    Hotkeys *self = HOTKEYS(data);
 
-    gulong keyval = (gulong)user_data;
+    gulong keyval = (gulong)arg2;
     gulong mask = arg3;
-    for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+    for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
     {
        if(!keyval) continue;
        if(evt->keyval != keyval) continue;
        cmp = (evt->mask ^ mask);
-       if(hotkeys.ignore_locks)
+       if(self->ignore_locks)
            cmp = cmp & !(GDK_MOD2_MASK | GDK_LOCK_MASK);
        if(!cmp)
        {
@@ -58,7 +103,7 @@ static gboolean hotkeys_local_activated_cb(GtkAccelGroup *accelgroup, GObject *a
     return FALSE;
 }
 
-void hotkeys_local_install()
+void hotkeys_local_install(Hotkeys *self)
 {
     static GtkAccelGroup *accel_group = NULL;
     GClosure *closure;
@@ -71,9 +116,9 @@ void hotkeys_local_install()
     }
     accel_group = gtk_accel_group_new();
     gtk_window_add_accel_group(mainwnd_get_wnd(), accel_group);
-    g_signal_connect(G_OBJECT(accel_group), "accel-activate", G_CALLBACK(hotkeys_local_activated_cb), NULL);
+    g_signal_connect(G_OBJECT(accel_group), "accel-activate", G_CALLBACK(hotkeys_local_activated_cb), self);
 
-    for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+    for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
     {
        gulong keyval = evt->keyval;
        if(!evt->enabled || hotkeys_list[i].global) continue;
@@ -90,16 +135,17 @@ static GdkFilterReturn hotkeys_global_cb(GdkXEvent *gdk_xevent, GdkEvent *event,
     const guint mods = LockMask | Mod2Mask;
     guint i;
     HOTKEY_EVENT *evt;
+    Hotkeys *self = HOTKEYS(self);
 
     switch(xevent->type)
     {
        case KeyPress:
        {
-           for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+           for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
            {
                if(!hotkeys_list[i].global) continue;
                gboolean mask_cmp;
-               if(hotkeys.ignore_locks)
+               if(self->ignore_locks)
                    mask_cmp = ((xevent->xkey.state | mods) == (evt->mask | mods));
                else
                    mask_cmp = (xevent->xkey.state == evt->mask);
@@ -118,7 +164,7 @@ static GdkFilterReturn hotkeys_global_cb(GdkXEvent *gdk_xevent, GdkEvent *event,
     return GDK_FILTER_CONTINUE;
 }
 
-void hotkeys_global_install()
+void hotkeys_global_install(Hotkeys *self)
 {
     static gboolean cb_added = FALSE;
     GdkWindow *rootwin = gdk_get_default_root_window();
@@ -128,7 +174,7 @@ void hotkeys_global_install()
 
     if(!cb_added)
     {
-       gdk_window_add_filter(rootwin, hotkeys_global_cb, NULL);
+       gdk_window_add_filter(rootwin, hotkeys_global_cb, self);
        cb_added = TRUE;
     }
     const guint mod_masks [] = {
@@ -138,17 +184,17 @@ void hotkeys_global_install()
        LockMask | Mod2Mask
     };
     // remove all hotkeys
-    for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+    for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
     {
        if(!hotkeys_list[i].global) continue;
        for(j = 0; j < G_N_ELEMENTS(mod_masks); j++)
            XUngrabKey(d, XKeysymToKeycode(d, evt->keyval), evt->mask | mod_masks[j], DefaultRootWindow(d));
     }
     // install currently assigned hotkeys
-    for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+    for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
     {
        if(!hotkeys_list[i].global) continue;
-       if(hotkeys.ignore_locks)
+       if(self->ignore_locks)
        {
            for(j = 0; j < G_N_ELEMENTS(mod_masks); j++)
                XGrabKey(d, XKeysymToKeycode(d, evt->keyval), evt->mask | mod_masks[j], DefaultRootWindow(d), True, GrabModeAsync, GrabModeAsync);
@@ -158,18 +204,18 @@ void hotkeys_global_install()
     }
 }
 
-HOTKEY_EVENT* hotkeys_find(const gchar *name)
+HOTKEY_EVENT* hotkeys_find(Hotkeys *self, const gchar *name)
 {
     gint i;
-    for(i = 0; hotkeys_list[i].name; i++)
+    for(i = 0; i < SZ(hotkeys_list); i++)
     {
        if(!g_strcmp0(hotkeys_list[i].name, name))
-           return (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i);
+           return (HOTKEY_EVENT*)g_list_nth_data(self->list, i);
     }
     return NULL;
 }
 
-void hotkeys_save()
+void hotkeys_save(Hotkeys *self)
 {
     gchar filename[PATH_MAX], buff[16];
     gint i;
@@ -178,7 +224,7 @@ void hotkeys_save()
     doc->children = xmlNewDocRawNode(doc, NULL, (xmlChar*)"hotkeys", NULL);
     gchar *userdir = prefs_get_userdir();
     sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_HOTKEYS);
-    for(i = 0; (evt = g_list_nth_data(hotkeys.list, i)); i++)
+    for(i = 0; (evt = g_list_nth_data(self->list, i)); i++)
     {
        if(!evt->enabled) continue;
        xmlNodePtr node1 = xmlAddChild((xmlNodePtr)doc->children, xmlNewNode(NULL, (xmlChar*)"hotkeys"));
@@ -195,22 +241,27 @@ void hotkeys_save()
 void hotkeys_load_item(void *ctx, const xmlChar *name, const xmlChar **atts)
 {
     if(!atts) return;
-    HOTKEY_EVENT *evt = hotkeys_find((gchar*)atts[1]);
+
+    xmlParserCtxt *ctxt = (xmlParserCtxt*)ctx;
+    xmlSAXHandler *cb = ctxt->sax;
+    Hotkeys *self = HOTKEYS(cb->_private);
+    HOTKEY_EVENT *evt = hotkeys_find(self, (gchar*)atts[1]);
     if(!evt) return;
+
     evt->mask = strtol((gchar*)atts[3], NULL, 16);
     evt->keyval = strtol((gchar*)atts[5], NULL, 16);
     evt->enabled = (evt->keyval != 0);
 }
 
 /* Add local some default hotkeys */
-void hotkeys_add_defaults()
+void hotkeys_add_defaults(Hotkeys *self)
 {
     gint i;
     for(i = 0; hotkeys_list[i].name; i++)
     {
         if(hotkeys_list[i].func == mainwnd_exit)
         {
-           HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i);
+           HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, i);
             evt->mask = 0x4;
             evt->keyval = 0x71;
            evt->enabled = TRUE;
@@ -240,7 +291,7 @@ void hotkeys_add_defaults()
 #endif
         else if(hotkeys_list[i].func == mainwnd_iconify_restore)
         {
-           HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(hotkeys.list, i);
+           HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, i);
             evt->mask = 0x4;
             evt->keyval = 0x69;
            evt->enabled = TRUE;
@@ -248,7 +299,7 @@ void hotkeys_add_defaults()
     }
 }
 
-void hotkeys_load()
+void hotkeys_load(Hotkeys *self)
 {
     gchar filename[PATH_MAX];
     xmlSAXHandler cb;
@@ -256,11 +307,12 @@ void hotkeys_load()
     sprintf(filename, "%s%s%s", userdir, G_DIR_SEPARATOR_S, FILENAME_HOTKEYS);
     if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
     {
-        hotkeys_add_defaults();
+        hotkeys_add_defaults(self);
         return;
     }
     memset(&cb, 0, sizeof(xmlSAXHandler));
     cb.startElement = &hotkeys_load_item;
+    cb._private = self;
     xmlDocPtr doc = xmlSAXParseFile(&cb, filename, 0);
     xmlFreeDoc(doc);
 }
@@ -314,3 +366,93 @@ void hotkey_to_string(guint mask, guint keyval, gchar *key)
     strcat(key, gdk_keyval_name(keyval));
 }
 
+GtkEntry* hotkeys_hbox_get_entry(GtkHBox *hbox)
+{
+    GList *list = gtk_container_get_children(GTK_CONTAINER(hbox));
+    return GTK_ENTRY(list->next->data);
+}
+
+static gboolean hotkeys_grab_key_cb(GtkDialog *dlg, GdkEventKey *evt, GtkHBox *hbox)
+{
+    gchar key[256];
+
+    switch (evt->keyval){
+    case GDK_Shift_L:
+    case GDK_Shift_R:
+    case GDK_Control_L:
+    case GDK_Control_R:
+    case GDK_Meta_L:
+    case GDK_Meta_R:
+    case GDK_Alt_L:
+    case GDK_Alt_R:
+    case GDK_Caps_Lock:
+    case GDK_Shift_Lock:
+    case GDK_Scroll_Lock:
+    case GDK_Num_Lock:
+    case GDK_Kana_Lock:
+        return(FALSE);
+        break;
+    }
+
+    if(evt->keyval == GDK_Escape)
+    {
+        gtk_dialog_response(dlg, GTK_RESPONSE_NO);
+        return TRUE;
+    }
+
+    if(_hotkeys->ignore_locks)
+        evt->state = evt->state & (~GDK_LOCK_MASK) & (~GDK_MOD2_MASK);
+    hotkey_to_string(evt->state, evt->keyval, key);
+
+    gtk_entry_set_text(hotkeys_hbox_get_entry(hbox), key);
+    gtk_dialog_response(dlg, GTK_RESPONSE_OK);
+
+    return TRUE;
+}
+
+static void hotkeys_edit_cb(GtkWidget *widget, GtkHBox *hbox)
+{
+    GtkWidget* dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE,
+                                            _("Press a key (or a key combination) to setup hotkey,\n"
+                                            "\"Clear\" button or \"Esc\" key to remove current hotkey,\n"
+                                            "\"Cancel\" to close this message."));
+    gtk_dialog_add_buttons(GTK_DIALOG(dlg), GTK_STOCK_CLEAR, GTK_RESPONSE_NO, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+    gtk_window_set_title(GTK_WINDOW(dlg), _("Grabbing a key."));
+    g_signal_connect(G_OBJECT(dlg), "key-press-event", G_CALLBACK(hotkeys_grab_key_cb), hbox);
+
+    if(gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_NO)
+        gtk_entry_set_text(hotkeys_hbox_get_entry(hbox), "");
+    gtk_widget_destroy(dlg);
+}
+
+GtkWidget* hotkeys_edit_nth(Hotkeys *self, gint n)
+{
+    if(n >= SZ(hotkeys_list))
+       return NULL;
+
+    GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
+    if(hotkeys_list[n].global)
+       gtk_widget_set_tooltip_text(hbox, _("Global hotkey"));
+
+    GtkWidget *label = gtk_label_new(hotkeys_list[n].name);
+    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+    GtkWidget *btn = gtk_button_new_with_label(_("Edit..."));
+    gtk_box_pack_end(GTK_BOX(hbox), btn, FALSE, FALSE, 0);
+    g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(hotkeys_edit_cb), hbox);
+
+    GtkWidget *entry = gtk_entry_new();
+    gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
+    gtk_box_pack_end(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
+
+    HOTKEY_EVENT *evt = (HOTKEY_EVENT*)g_list_nth_data(self->list, n);
+    gchar keystr[64];
+    if(evt ? evt->enabled : FALSE)
+    {
+       hotkey_to_string(evt->mask, evt->keyval, keystr);
+       gtk_entry_set_text(GTK_ENTRY(entry), keystr);
+    }
+    return hbox;
+}
+
index 94c70d8..d61771e 100644 (file)
@@ -2,31 +2,40 @@
 #ifndef __HOTKEYS_H__
 #define __HOTKEYS_H__
 
-struct _hotkeys
-{
-    gboolean    ignore_locks;
-    GList       *list;
-} hotkeys;
-
-typedef struct
-{
-    gchar *name;
-    void (* func)();
-    gboolean global;
-} HOTKEY_COMMAND;
-
-typedef struct
-{
-    guint32 mask, keyval;
-    gboolean enabled;
-} HOTKEY_EVENT;
-
-void           hotkeys_list_init();
+#include "builder.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_HOTKEYS (hotkeys_get_type ())
+#define HOTKEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_HOTKEYS, Hotkeys))
+#define HOTKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_HOTKEYS, HotkeysClass))
+#define IS_HOTKEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_HOTKEYS))
+#define IS_HOTKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_HOTKEYS))
+#define HOTKEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_HOTKEYS, HotkeysClass))
+
+typedef struct _Hotkeys Hotkeys;
+typedef struct _HotkeysClass HotkeysClass;
+
+struct _Hotkeys {
+    GObject         parent_instance;
+    GList          *list;
+    gboolean       ignore_locks;
+};
+
+struct _HotkeysClass {
+    GObjectClass    parent_class;
+};
+
+void               hotkeys_load(Hotkeys *self);
+void               hotkeys_save(Hotkeys *self);
+GtkWidget*         hotkeys_edit_nth(Hotkeys *self, gint n);
+
+GType               hotkeys_get_type (void);
+
+G_END_DECLS
+
 void            hotkeys_local_install();
 void            hotkeys_global_install();
-HOTKEY_EVENT*  hotkeys_find(const gchar *name);
-void            hotkeys_save();
-void            hotkeys_load();
 void           hotkey_to_string(guint mask, guint keyval, gchar *key);
 
 #endif /* __HOTKEYS_H__ */
index 370090a..3f58a73 100644 (file)
@@ -30,12 +30,14 @@ static void mainwnd_init(Mainwnd *self)
     self->builder = g_object_new(TYPE_BUILDER, NULL);
     self->prefs = g_object_new(TYPE_PREFS, "builder", self->builder, NULL);
     self->dicts = g_object_new(TYPE_DICTS, "builder", self->builder, NULL);
+    self->history = g_object_new(TYPE_HISTORY, "builder", self->builder, "prefs", self->prefs, NULL);
+    self->hotkeys = g_object_new(TYPE_HOTKEYS, NULL);
     self->results = g_sequence_new(result_free);
     gtk_builder_connect_signals(GTK_BUILDER(self->builder), self);
     GtkWidget *vbox = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(self->builder), "vbox1"));
     gtk_widget_reparent(vbox, GTK_WIDGET(self));
     GtkContainer *scroll = GTK_CONTAINER(gtk_builder_get_object(GTK_BUILDER(self->builder), "scrolledwindow2"));
-    self->text = g_object_new(TYPE_TEXTVIEW, "prefs", self->prefs, NULL);
+    self->text = g_object_new(TYPE_TEXTVIEW, "prefs", self->prefs, "history", self->history, NULL);
     gtk_container_add(scroll, GTK_WIDGET(self->text));
     self->popupwnd = g_object_new(TYPE_POPUPWND, "mainwnd", self, "type", GTK_WINDOW_POPUP, NULL);
     self->word = NULL;
@@ -105,7 +107,7 @@ void mainwnd_exit()
     w = gtk_paned_get_position(p);
     prefs_set_int(prefs, "paned.tree_width", w);
 
-    //history_save_words();
+    history_save_words(mw->history);
     prefs_save(prefs);
     dicts_save(mw->dicts);
     //hotkeys_save();
@@ -144,7 +146,7 @@ void mainwnd_search(Mainwnd *self, const gchar *word, gint method)
     if(method == -1)
        method = builder_get_int(self->builder, "mainwnd_search_method");
 
-    //history_insert_word(word);
+    history_insert_word(self->history, word);
     gint maxhits = prefs_get_int(self->prefs, "headword.maxhits");
     ebook_search(word, method, self->results, maxhits, False);
     mainwnd_update_results(self);
@@ -177,11 +179,14 @@ static void mainwnd_prev(GtkWidget *widget, gpointer data)
     history_prev();
 }
 
+#endif
+
 void mainwnd_clear_combo()
 {
+    //GtkWidget *combo = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(_mainwnd->builder), "mainwnd_search"));
+    //GtkEntry *entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo)));
     builder_set_str(_mainwnd->builder, "mainwnd_search", "");
 }
-#endif
 
 gboolean mainwnd_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
@@ -227,6 +232,7 @@ static void mainwnd_scan_start_stop(Mainwnd *self, gboolean scan)
 void mainwnd_scan_toggled_cb(GtkToggleButton *btn, gpointer data)
 {
     Mainwnd *mw = MAINWND(data);
+    if(!gtk_widget_get_visible(GTK_WIDGET(mw))) return;
     gint scan = gtk_toggle_button_get_active(btn);
     mainwnd_scan_start_stop(mw, scan);
 }
@@ -373,19 +379,20 @@ void mainwnd_dict_buttons_update(Mainwnd *self)
 
 void mainwnd_prepare(Mainwnd *self)
 {
-#if 0
-    hotkeys_local_install();
-    hotkeys_global_install();
-#endif
     GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)icon_xpm);
     gtk_window_set_default_icon(pixbuf);
     g_object_unref(pixbuf);
     gtk_widget_hide_on_delete(GTK_WIDGET(self));
 
     prefs_load(self->prefs);
+    history_load_words(self->history);
+    hotkeys_load(self->hotkeys);
+    hotkeys_local_install(self->hotkeys);
+    hotkeys_global_install(self->hotkeys);
 
     builder_install_text_cellrenderer(self->builder, "mainwnd_search_method");
     builder_install_text_cellrenderer(self->builder, "mainwnd_dict_group");
+    builder_install_text_cellrenderer(self->builder, "mainwnd_search");
 
     GtkTreeView *tree = GTK_TREE_VIEW(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_results"));
     GtkTreeSelection *select = gtk_tree_view_get_selection(tree);
@@ -407,12 +414,9 @@ void mainwnd_prepare(Mainwnd *self)
     builder_set_int(self->builder, "mainwnd_dict_group", active);
     builder_set_int(self->builder, "mainwnd_search", 0);
 
-    gboolean b = prefs_get_int(self->prefs, "selection.lookup_started");
-    builder_set_int(self->builder, "mainwnd_scan", b);
-
     gint i;
     GtkTreeIter iter;
-    GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search_store"));
+    GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(GTK_BUILDER(self->builder), "mainwnd_search_method_store"));
     for(i = 0; i < 4; i++)
     {
        const gchar *name = ebook_index_to_method_name(i);
@@ -434,6 +438,8 @@ void mainwnd_prepare(Mainwnd *self)
         gtk_window_move(GTK_WINDOW(self), x, y);
     }
     mainwnd_reset_font(self);
+    gboolean b = prefs_get_int(self->prefs, "selection.lookup_started");
+    builder_set_int(self->builder, "mainwnd_scan", b);
     builder_grab_focus(self->builder, "mainwnd_search");
 }
 
@@ -501,3 +507,9 @@ void mainwnd_dict_group_changed_cb(GtkComboBox *widget, gpointer data)
     mainwnd_dict_buttons_update(mw);
 }
 
+void mainwnd_prev_clicked_cb(GtkWidget *widget, gpointer data)
+{
+    Mainwnd *mw = MAINWND(data);
+    history_prev(mw->history);
+}
+
index 30b4818..e3bcee5 100644 (file)
@@ -5,6 +5,8 @@
 #include "builder.h"
 #include "dicts.h"
 #include "prefs.h"
+#include "history.h"
+#include "hotkeys.h"
 #include "textview.h"
 #include "popupwnd.h"
 
@@ -25,6 +27,8 @@ struct _Mainwnd {
     Builder    *builder;
     Dicts      *dicts;
     Prefs      *prefs;
+    History    *history;
+    Hotkeys    *hotkeys;
     GSequence  *results;
     TextView   *text;
     Popupwnd   *popupwnd;
@@ -52,9 +56,9 @@ GType          mainwnd_get_type (void);
 
 G_END_DECLS
 
+void            mainwnd_clear_combo();
 void            mainwnd_iconify_restore();
 void            mainwnd_search_();
-void            mainwnd_clear_combo();
 GtkWidget*      mainwnd_search_method_combo();
 
 #endif /* __MAINWND_H__ */
index 07a665c..6179b63 100644 (file)
@@ -92,8 +92,6 @@ static void prefs_init(Prefs *self)
 
     g_datalist_init(&(self->data));
 
-    hotkeys_list_init();
-
     gchar *home_dir = getenv("HOME");
     gchar *userdir = g_strdup_printf("%s%s.%s", home_dir, G_DIR_SEPARATOR_S, PACKAGE_NAME);
     prefs_set_str(self, "userdir", userdir);
@@ -255,6 +253,13 @@ void prefs_btn_clicked_cb(GtkWidget *widget, gpointer data)
        }
        GtkWidget *w = GTK_WIDGET(gtk_builder_get_object(GTK_BUILDER(mw->builder), "mainwnd.font"));
        gtk_widget_set_sensitive(w, prefs_get_int(mw->prefs, "mainwnd.custom_font"));
+
+       Hotkeys *hotkeys = mw->hotkeys;
+       GtkBox *vbox = GTK_BOX(gtk_builder_get_object(GTK_BUILDER(mw->builder), "hotkeys_vbox"));
+       for(i = 0; w = hotkeys_edit_nth(hotkeys, i); i++)
+       {
+           gtk_box_pack_start(vbox, w, FALSE, FALSE, 0);
+       }
        preparewnd = False;
     }
     if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_store), &iter1))
@@ -290,7 +295,8 @@ void prefs_save(Prefs *self)
             break;
         case G_TYPE_STRING:
            str = prefs_get_str(self, p->name);
-            sprintf(buff, "%s", str);
+           if(str)
+               sprintf(buff, "%s", str);
             break;
         }
         xmlNodePtr node = xmlAddChild(doc->children, xmlNewNode(NULL, (xmlChar*)prefs_list[i].name));
index 8ff52c9..64ede98 100644 (file)
@@ -149,9 +149,8 @@ void textview_open(TextView *self, RESULT *res, gboolean clear, const gchar *wor
     render_content(res->binfo, self, text, self->prefs);
     g_free(text);
 
-    TextViewClass *klass = TEXTVIEW_GET_CLASS(self);
-    if(klass->history_next)
-       klass->history_next(res);
+    if(self->history)
+       history_insert_res(self->history, res);
     if(word && prefs_get_int(self->prefs, "highlight_all_keywords"))
        textview_highlight_word(self, word);
 }
@@ -166,6 +165,9 @@ static void textview_set_property(GObject *object, guint param_id, const GValue
            text->prefs = PREFS(g_value_get_pointer(value));
            g_signal_connect(G_OBJECT(text), "populate_popup", G_CALLBACK(textview_populate_popup_cb), text);
            break;
+       case 2:
+           text->history = HISTORY(g_value_get_pointer(value));
+           break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
            break;
@@ -174,10 +176,10 @@ static void textview_set_property(GObject *object, guint param_id, const GValue
 
 static void textview_class_init(TextViewClass *klass)
 {
-    klass->history_next = NULL;
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
     gobject_class->set_property = textview_set_property;
     g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("prefs", _("Prefs"), _("Prefs"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
+    g_object_class_install_property(gobject_class, 2, g_param_spec_pointer("history", _("History"), _("History"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
 }
 
 static void textview_init(TextView *self)
@@ -192,6 +194,7 @@ static void textview_init(TextView *self)
     gtk_text_view_set_right_margin(GTK_TEXT_VIEW(self), 10);
     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(self), GTK_WRAP_WORD);
     gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(self), FALSE);
+    self->history = NULL;
 }
 
 void textview_clear_textbuf(TextView *self)
index 23f83e2..e917299 100644 (file)
@@ -20,11 +20,11 @@ struct _TextView {
     GtkTextView            parent_instance;
     GtkTextTag     *tag;
     Prefs          *prefs;
+    History        *history;
 };
 
 struct _TextViewClass {
     GtkTextViewClass    parent_class;
-    void               (*history_next)(RESULT *res);
 };
 
 void       textview_open(TextView *self, RESULT *res, gboolean clear, const gchar *word);