1 /*
2  * Copyright © 2004 Noah Levitt
3  * Copyright © 2007 Christian Persch
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program 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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
18  */
19 
20 #include <config.h>
21 #include <glib/gi18n-lib.h>
22 
23 #include "gucharmap.h"
24 #include "gucharmap-private.h"
25 
26 #include "unicode-blocks.h"
27 
28 enum
29 {
30   BLOCK_CHAPTERS_MODEL_ID = 0,
31   BLOCK_CHAPTERS_MODEL_LABEL = GUCHARMAP_CHAPTERS_MODEL_COLUMN_LABEL,
32   BLOCK_CHAPTERS_MODEL_LABEL_ATTRS = _GUCHARMAP_CHAPTERS_MODEL_COLUMN_LABEL_ATTRS,
33   BLOCK_CHAPTERS_MODEL_BLOCK,
34   BLOCK_CHAPTERS_MODEL_UNICODE_BLOCK_PTR,
35   BLOCK_CHAPTERS_MODEL_NUM_COLUMNS
36 };
37 
38 static void
sort_column_changed_cb(GtkTreeSortable * sortable,gpointer user_data)39 sort_column_changed_cb (GtkTreeSortable *sortable,
40 			gpointer user_data)
41 {
42   GucharmapChaptersModel *model = GUCHARMAP_CHAPTERS_MODEL (sortable);
43 
44   if (model->priv->sort_column == BLOCK_CHAPTERS_MODEL_BLOCK)
45     model->priv->sort_column = BLOCK_CHAPTERS_MODEL_LABEL;
46   else
47     model->priv->sort_column = BLOCK_CHAPTERS_MODEL_BLOCK;
48 
49   g_signal_handlers_block_by_func(sortable, G_CALLBACK(sort_column_changed_cb), NULL);
50   gtk_tree_sortable_set_sort_column_id (sortable,
51                                         model->priv->sort_column,
52                                         GTK_SORT_ASCENDING);
53   g_signal_handlers_unblock_by_func(sortable, G_CALLBACK(sort_column_changed_cb), NULL);
54 }
55 
56 static void
gucharmap_block_chapters_model_init(GucharmapBlockChaptersModel * model)57 gucharmap_block_chapters_model_init (GucharmapBlockChaptersModel *model)
58 {
59   GucharmapChaptersModel *chapters_model = GUCHARMAP_CHAPTERS_MODEL (model);
60   GtkListStore *store = GTK_LIST_STORE (model);
61   GtkTreeIter iter;
62   guint i;
63   GType types[] = {
64     G_TYPE_STRING,
65     G_TYPE_STRING,
66     PANGO_TYPE_ATTR_LIST,
67     G_TYPE_STRING,
68     G_TYPE_POINTER
69   };
70   PangoAttrList *attr_list;
71 
72   attr_list = pango_attr_list_new ();
73   pango_attr_list_insert (attr_list, pango_attr_style_new (PANGO_STYLE_ITALIC));
74 
75   gtk_list_store_set_column_types (store, G_N_ELEMENTS (types), types);
76 
77   gtk_list_store_append (store, &iter);
78   gtk_list_store_set (store, &iter,
79                       BLOCK_CHAPTERS_MODEL_ID, "All",
80                       BLOCK_CHAPTERS_MODEL_LABEL, _("All"),
81                       BLOCK_CHAPTERS_MODEL_LABEL_ATTRS, attr_list,
82                       BLOCK_CHAPTERS_MODEL_BLOCK, "",
83                       BLOCK_CHAPTERS_MODEL_UNICODE_BLOCK_PTR, NULL,
84                       -1);
85 
86   pango_attr_list_unref (attr_list);
87 
88   for (i = 0;  i < G_N_ELEMENTS (unicode_blocks); i++)
89     {
90       static gchar block_start[12];
91       const char *block_name;
92 
93       g_snprintf (block_start, sizeof (block_start), "%012" G_GUINT32_FORMAT, unicode_blocks[i].start);
94       block_name = unicode_blocks_strings + unicode_blocks[i].block_name_index;
95 
96       gtk_list_store_append (store, &iter);
97       gtk_list_store_set (store, &iter,
98                           BLOCK_CHAPTERS_MODEL_ID, block_name,
99                           BLOCK_CHAPTERS_MODEL_LABEL, _(block_name),
100                           BLOCK_CHAPTERS_MODEL_LABEL_ATTRS, NULL,
101                           BLOCK_CHAPTERS_MODEL_BLOCK, block_start,
102                           BLOCK_CHAPTERS_MODEL_UNICODE_BLOCK_PTR, unicode_blocks + i,
103                           -1);
104     }
105 
106   g_signal_connect (model, "sort-column-changed", G_CALLBACK (sort_column_changed_cb), NULL);
107 
108   /* This will switch to its default BLOCK_CHAPTERS_MODEL_BLOCK when
109    * gucharmap_chapters_view_set_model() calls
110    * gtk_tree_sortable_set_sort_column_id() and triggers
111    * "sort-column-changed". */
112   chapters_model->priv->sort_column = BLOCK_CHAPTERS_MODEL_LABEL;
113 }
114 
115 static GucharmapCodepointList *
get_codepoint_list(GucharmapChaptersModel * chapters,GtkTreeIter * iter)116 get_codepoint_list (GucharmapChaptersModel *chapters,
117                     GtkTreeIter *iter)
118 {
119   GtkTreeModel *model = GTK_TREE_MODEL (chapters);
120   UnicodeBlock *unicode_block;
121 
122   gtk_tree_model_get (model, iter, BLOCK_CHAPTERS_MODEL_UNICODE_BLOCK_PTR, &unicode_block, -1);
123 
124   /* special "All" block */
125   if (unicode_block == NULL)
126     return gucharmap_block_codepoint_list_new (0, UNICHAR_MAX);
127 
128   return gucharmap_block_codepoint_list_new (unicode_block->start, unicode_block->end);
129 }
130 
131 static GucharmapCodepointList *
get_book_codepoint_list(GucharmapChaptersModel * model)132 get_book_codepoint_list (GucharmapChaptersModel *model)
133 {
134   GucharmapChaptersModelPrivate *model_priv = model->priv;
135 
136   if (model_priv->book_list == NULL) {
137     model_priv->book_list = gucharmap_block_codepoint_list_new (0, UNICHAR_MAX);
138   }
139 
140   return g_object_ref (model_priv->book_list);
141 }
142 
143 /* XXX linear search */
144 static gboolean
character_to_iter(GucharmapChaptersModel * chapters,gunichar wc,GtkTreeIter * _iter)145 character_to_iter (GucharmapChaptersModel *chapters,
146                    gunichar           wc,
147                    GtkTreeIter       *_iter)
148 {
149   GtkTreeModel *model = GTK_TREE_MODEL (chapters);
150   GtkTreeIter iter, all_iter;
151   gboolean all_iter_set = TRUE;
152 
153   if (wc > UNICHAR_MAX)
154     return FALSE;
155 
156   if (!gtk_tree_model_get_iter_first (model, &iter))
157     return FALSE;
158 
159   do
160     {
161       UnicodeBlock *unicode_block;
162 
163       gtk_tree_model_get (model, &iter, BLOCK_CHAPTERS_MODEL_UNICODE_BLOCK_PTR, &unicode_block, -1);
164 
165       /* skip "All" block */
166       if (unicode_block == NULL)
167         {
168           all_iter = iter;
169           all_iter_set = TRUE;
170           continue;
171         }
172 
173       if (wc >= unicode_block->start && wc <= unicode_block->end)
174         {
175           *_iter = iter;
176           return TRUE;
177         }
178     }
179   while (gtk_tree_model_iter_next (model, &iter));
180 
181   /* "All" is the last resort */
182   g_assert (all_iter_set);
183   *_iter = all_iter;
184   return TRUE;
185 }
186 
187 static void
gucharmap_block_chapters_model_class_init(GucharmapBlockChaptersModelClass * clazz)188 gucharmap_block_chapters_model_class_init (GucharmapBlockChaptersModelClass *clazz)
189 {
190   GucharmapChaptersModelClass *chapters_class = GUCHARMAP_CHAPTERS_MODEL_CLASS (clazz);
191 
192   _gucharmap_intl_ensure_initialized ();
193 
194   chapters_class->title = _("Unicode Block");
195   chapters_class->character_to_iter = character_to_iter;
196   chapters_class->get_codepoint_list = get_codepoint_list;
197   chapters_class->get_book_codepoint_list = get_book_codepoint_list;
198 }
199 
G_DEFINE_TYPE(GucharmapBlockChaptersModel,gucharmap_block_chapters_model,GUCHARMAP_TYPE_CHAPTERS_MODEL)200 G_DEFINE_TYPE (GucharmapBlockChaptersModel, gucharmap_block_chapters_model, GUCHARMAP_TYPE_CHAPTERS_MODEL)
201 
202 GucharmapChaptersModel *
203 gucharmap_block_chapters_model_new (void)
204 {
205   return g_object_new (gucharmap_block_chapters_model_get_type (), NULL);
206 }
207