OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkListPeer.c
1 /* GtkListPeer.c -- implements GtkListPeer's native methods
2    Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
3
4    This file is part of GNU Classpath.
5
6    GNU Classpath is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    GNU Classpath is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GNU Classpath; see the file COPYING.  If not, write to the
18    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301 USA.
20
21    Linking this library statically or dynamically with other modules is
22    making a combined work based on this library.  Thus, the terms and
23    conditions of the GNU General Public License cover the whole
24    combination.
25
26    As a special exception, the copyright holders of this library give you
27    permission to link this library with independent modules to produce an
28    executable, regardless of the license terms of these independent
29    modules, and to copy and distribute the resulting executable under
30    terms of your choice, provided that you also meet, for each linked
31    independent module, the terms and conditions of the license of that
32    module.  An independent module is a module which is not derived from
33    or based on this library.  If you modify this library, you may extend
34    this exception to your version of the library, but you are not
35    obligated to do so.  If you do not wish to do so, delete this
36    exception statement from your version. */
37
38 #include "gtkpeer.h"
39 #include "gnu_java_awt_peer_gtk_GtkListPeer.h"
40
41 static jmethodID postListItemEventID;
42 static GtkWidget *list_get_widget (GtkWidget *widget);
43
44 void
45 cp_gtk_list_init_jni (void)
46 {
47   jclass gtklistpeer;
48
49   gtklistpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(),
50                                          "gnu/java/awt/peer/gtk/GtkListPeer");
51
52   postListItemEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtklistpeer,
53                                                    "postItemEvent",
54                                                    "(II)V");
55 }
56
57 enum
58   {
59     COLUMN_STRING,
60     N_COLUMNS
61   };
62
63 static gboolean item_highlighted_cb (GtkTreeSelection *selection,
64                                      GtkTreeModel *model,
65                                      GtkTreePath *path,
66                                      gboolean path_currently_selected,
67                                      jobject peer);
68
69
70 JNIEXPORT void JNICALL
71 Java_gnu_java_awt_peer_gtk_GtkListPeer_create
72   (JNIEnv *env, jobject obj, jint rows)
73 {
74   GtkWidget *sw;
75   GtkWidget *list;
76   GtkWidget *eventbox;
77   GtkCellRenderer *renderer;
78   GtkTreeViewColumn *column;
79   GtkListStore *list_store;
80   GtkTreeIter iter;
81   GtkRequisition req;
82   gint i;
83
84   gdk_threads_enter ();
85
86   /* Create global reference and save it for future use */
87   NSA_SET_GLOBAL_REF (env, obj);
88
89   list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING);
90   /* Add the number of rows so that we can calculate the tree view's
91      size request. */
92   for (i = 0; i < rows; i++)
93     {
94       gtk_list_store_append (list_store, &iter);
95       gtk_list_store_set (list_store, &iter,
96                           COLUMN_STRING, "",
97                           -1);
98     }
99   list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
100   renderer = gtk_cell_renderer_text_new ();
101   column = gtk_tree_view_column_new_with_attributes (NULL,
102                                      renderer,
103                                      "text",
104                                      COLUMN_STRING,
105                                      NULL);
106
107   eventbox = gtk_event_box_new ();
108   sw = gtk_scrolled_window_new (NULL, NULL);
109   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
110                                   GTK_POLICY_AUTOMATIC,
111                                   GTK_POLICY_AUTOMATIC);
112   gtk_container_add (GTK_CONTAINER (eventbox), sw);
113   
114   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
115
116   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
117
118   gtk_widget_size_request (GTK_WIDGET (list), &req);
119
120   gtk_widget_set_size_request (GTK_WIDGET (list), req.width, req.height);
121
122   gtk_container_add (GTK_CONTAINER (sw), list);
123
124   /* Remove the blank rows. */
125   gtk_list_store_clear (list_store);
126
127   gtk_widget_show (list);
128   gtk_widget_show (sw);
129
130   NSA_SET_PTR (env, obj, eventbox);
131
132   gdk_threads_leave ();
133 }
134
135 JNIEXPORT void JNICALL 
136 Java_gnu_java_awt_peer_gtk_GtkListPeer_connectSignals
137   (JNIEnv *env, jobject obj)
138 {
139   void *ptr;
140   jobject *gref;
141   GtkWidget *list;
142   GtkTreeSelection *selection;
143
144   gdk_threads_enter ();
145
146   ptr = NSA_GET_PTR (env, obj);
147   gref = NSA_GET_GLOBAL_REF (env, obj);
148
149   list = list_get_widget (GTK_WIDGET (ptr));
150
151   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
152   gtk_tree_selection_set_select_function (selection, item_highlighted_cb,
153                                           *gref, NULL);
154
155   cp_gtk_component_connect_signals (G_OBJECT (list), gref);
156
157   gdk_threads_leave ();
158 }
159
160 JNIEXPORT void JNICALL
161 Java_gnu_java_awt_peer_gtk_GtkListPeer_gtkWidgetModifyFont
162   (JNIEnv *env, jobject obj, jstring name, jint style, jint size)
163 {
164   const char *font_name;
165   void *ptr;
166   GtkWidget *list;
167   PangoFontDescription *font_desc;
168
169   gdk_threads_enter();
170
171   ptr = NSA_GET_PTR (env, obj);
172
173   list = list_get_widget (GTK_WIDGET (ptr));
174
175   font_name = (*env)->GetStringUTFChars (env, name, NULL);
176
177   font_desc = pango_font_description_from_string (font_name);
178   pango_font_description_set_size (font_desc,
179                                    size * cp_gtk_dpi_conversion_factor);
180
181   if (style & AWT_STYLE_BOLD)
182     pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD);
183
184   if (style & AWT_STYLE_ITALIC)
185     pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE);
186
187   gtk_widget_modify_font (GTK_WIDGET (list), font_desc);
188
189   pango_font_description_free (font_desc);
190
191   (*env)->ReleaseStringUTFChars (env, name, font_name);
192
193   gdk_threads_leave();
194 }
195
196 JNIEXPORT void JNICALL
197 Java_gnu_java_awt_peer_gtk_GtkListPeer_gtkWidgetRequestFocus
198   (JNIEnv *env, jobject obj)
199 {
200   void *ptr;
201   GtkWidget *list;
202
203   gdk_threads_enter ();
204
205   ptr = NSA_GET_PTR (env, obj);
206   
207   list = list_get_widget (GTK_WIDGET (ptr));
208   gtk_widget_grab_focus (list);
209
210   gdk_threads_leave ();
211 }
212
213 JNIEXPORT void JNICALL
214 Java_gnu_java_awt_peer_gtk_GtkListPeer_append
215   (JNIEnv *env, jobject obj, jobjectArray items)
216 {
217   void *ptr;
218   GtkWidget *list;
219   GtkTreeIter iter;
220   GtkTreeModel *list_store;
221   jint count;
222   jint i;
223
224   gdk_threads_enter ();
225
226   ptr = NSA_GET_PTR (env, obj);
227
228   count = (*env)->GetArrayLength (env, items);
229
230   list = list_get_widget (GTK_WIDGET (ptr));
231   list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
232
233   for (i = 0; i < count; i++)
234     {
235       const char *text;
236       jobject item;
237
238       item = (*env)->GetObjectArrayElement (env, items, i);
239
240       text = (*env)->GetStringUTFChars (env, item, NULL);
241       gtk_list_store_append (GTK_LIST_STORE (list_store), &iter);
242       gtk_list_store_set (GTK_LIST_STORE (list_store), &iter,
243                           COLUMN_STRING, text,
244                           -1);
245       (*env)->ReleaseStringUTFChars (env, item, text);
246       (*env)->DeleteLocalRef(env, item);
247     }
248
249   gdk_threads_leave ();
250 }
251
252 JNIEXPORT void JNICALL
253 Java_gnu_java_awt_peer_gtk_GtkListPeer_add
254   (JNIEnv *env, jobject obj, jstring text, jint index)
255 {
256   void *ptr;
257   const char *str;
258   GtkWidget *list;
259   GtkTreeIter iter;
260   GtkTreeModel *list_store;
261
262   gdk_threads_enter ();
263
264   ptr = NSA_GET_PTR (env, obj);
265   str = (*env)->GetStringUTFChars (env, text, NULL);
266
267   list = list_get_widget (GTK_WIDGET (ptr));
268   list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
269
270   if (index == -1)
271     gtk_list_store_append (GTK_LIST_STORE (list_store), &iter);
272   else
273     gtk_list_store_insert (GTK_LIST_STORE (list_store), &iter, index);
274
275   gtk_list_store_set (GTK_LIST_STORE (list_store), &iter,
276                       COLUMN_STRING, str, -1);
277
278   (*env)->ReleaseStringUTFChars (env, text, str);
279
280   gdk_threads_leave ();
281 }
282
283
284 JNIEXPORT void JNICALL
285 Java_gnu_java_awt_peer_gtk_GtkListPeer_delItems
286   (JNIEnv *env, jobject obj, jint start, jint end)
287 {
288   void *ptr;
289   GtkWidget *list;
290   GtkTreeIter iter;
291   GtkTreeModel *list_store;
292   jint i;
293   jint num_items;
294     
295   gdk_threads_enter ();
296
297   ptr = NSA_GET_PTR (env, obj);
298
299   list = list_get_widget (GTK_WIDGET (ptr));
300   list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
301
302   /* Special case: remove all rows. */
303   if (end == -1)
304     gtk_list_store_clear (GTK_LIST_STORE (list_store));
305   else
306     {
307       i = 0;
308       num_items = end - start + 1;
309       gtk_tree_model_iter_nth_child (list_store, &iter, NULL, start);
310       while (i < num_items)
311         {
312           gtk_list_store_remove (GTK_LIST_STORE (list_store), &iter);
313           i++;
314         }
315     }
316
317   gdk_threads_leave ();
318 }
319
320 JNIEXPORT void JNICALL
321 Java_gnu_java_awt_peer_gtk_GtkListPeer_select
322   (JNIEnv *env, jobject obj, jint index)
323 {
324   void *ptr;
325   GtkWidget *list;
326   GtkTreePath *path;
327     
328   gdk_threads_enter ();
329
330   ptr = NSA_GET_PTR (env, obj);
331
332   list = list_get_widget (GTK_WIDGET (ptr));
333   path = gtk_tree_path_new_from_indices (index, -1);
334   gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE);
335
336   gdk_threads_leave ();
337 }
338
339 JNIEXPORT void JNICALL
340 Java_gnu_java_awt_peer_gtk_GtkListPeer_deselect
341   (JNIEnv *env, jobject obj, jint index)
342 {
343   void *ptr;
344   GtkWidget *list;
345   GtkTreeSelection *selection;
346   GtkTreePath *path;
347
348   gdk_threads_enter ();
349
350   ptr = NSA_GET_PTR (env, obj);
351
352   list = list_get_widget (GTK_WIDGET (ptr));
353   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
354   path = gtk_tree_path_new_from_indices (index, -1);
355   gtk_tree_selection_unselect_path (selection, path);
356
357   gdk_threads_leave ();
358 }
359
360 JNIEXPORT void JNICALL
361 Java_gnu_java_awt_peer_gtk_GtkListPeer_getSize
362   (JNIEnv *env, jobject obj, jint rows, jint visible_rows, jintArray jdims)
363 {
364   void *ptr;
365   jint *dims;
366   GtkRequisition current_req;
367   GtkRequisition natural_req;
368   GtkWidget* bin;
369
370   gdk_threads_enter ();
371
372   dims = (*env)->GetIntArrayElements (env, jdims, NULL);
373   dims[0] = dims[1] = 0;
374
375   ptr = NSA_GET_PTR (env, obj);
376   bin = list_get_widget (GTK_WIDGET (ptr));
377   
378   /* Save the widget's current size request. */
379   gtk_widget_size_request (bin, &current_req);
380       
381   /* Get the widget's "natural" size request. */
382   gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1);
383   gtk_widget_size_request (bin, &natural_req);
384
385   /* Reset the widget's size request. */
386   gtk_widget_set_size_request (bin,
387                                current_req.width, current_req.height);
388
389   dims[0] = natural_req.width;
390
391   /* Calculate the final height, by comparing the number of rows
392      in the list to the number of rows requested by the caller.
393      FIXME: Is there a GTK method that counts the number of rows
394      in the list? If so, we don't need to bring visible_rows from
395      the Java peer. */
396   if (rows == visible_rows)
397     dims[1] = natural_req.height;
398   else
399     dims[1] = natural_req.height / visible_rows * rows;
400
401   (*env)->ReleaseIntArrayElements (env, jdims, dims, 0);
402
403   gdk_threads_leave ();
404 }
405
406
407 JNIEXPORT jintArray JNICALL
408 Java_gnu_java_awt_peer_gtk_GtkListPeer_getSelectedIndexes
409   (JNIEnv *env, jobject obj)
410 {
411   void *ptr;
412   GtkWidget *list;
413   GtkTreeSelection *selection;
414   jintArray result_array;
415   jint *result_array_iter;
416   GList *current_row;
417   GList *rows;
418   gint *indices;
419   jint count;
420   jint i;
421
422   gdk_threads_enter ();
423
424   ptr = NSA_GET_PTR (env, obj);
425
426   list = list_get_widget (GTK_WIDGET (ptr));
427   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
428   count = gtk_tree_selection_count_selected_rows (selection);
429   if (count > 0)
430     {
431       current_row = rows = gtk_tree_selection_get_selected_rows (selection, NULL);
432
433       result_array = (*env)->NewIntArray (env, count);
434
435       result_array_iter = (*env)->GetIntArrayElements (env, result_array, NULL);
436
437       for (i = 0; i < count; i++)
438         {
439           indices = gtk_tree_path_get_indices (current_row->data);
440           result_array_iter[i] = indices ? indices[0] : -1;
441           current_row = g_list_next (current_row);
442         }
443
444       if (rows)
445         {
446           g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
447           g_list_free (rows);
448         }
449
450       (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0);
451     }
452   else
453     result_array = NULL;
454
455   gdk_threads_leave ();
456
457   return result_array;
458 }
459
460 JNIEXPORT void JNICALL
461 Java_gnu_java_awt_peer_gtk_GtkListPeer_makeVisible
462   (JNIEnv *env, jobject obj, jint index)
463 {
464   void *ptr;
465   GtkWidget *list;
466   GtkTreePath *path;
467
468   gdk_threads_enter ();
469
470   ptr = NSA_GET_PTR (env, obj);
471
472   list = list_get_widget (GTK_WIDGET (ptr));
473   path = gtk_tree_path_new_from_indices (index, -1);
474   gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list), path,
475                                 NULL, FALSE, 0.0, 0.0);
476
477   gdk_threads_leave ();
478 }
479
480 JNIEXPORT void JNICALL
481 Java_gnu_java_awt_peer_gtk_GtkListPeer_setMultipleMode
482   (JNIEnv *env, jobject obj, jboolean mode)
483 {
484   void *ptr;
485   GtkWidget *list;
486   GtkTreeSelection *selection;
487
488   gdk_threads_enter ();
489
490   ptr = NSA_GET_PTR (env, obj);
491
492   list = list_get_widget (GTK_WIDGET (ptr));
493   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
494   gtk_tree_selection_set_mode (selection,
495                                mode ? GTK_SELECTION_MULTIPLE
496                                : GTK_SELECTION_SINGLE);
497
498   gdk_threads_leave ();
499 }
500
501 static gboolean
502 item_highlighted_cb (GtkTreeSelection *selection __attribute__((unused)),
503                      GtkTreeModel *model,
504                      GtkTreePath *path,
505                      gboolean path_currently_selected,
506                      jobject peer)
507 {
508   GtkTreeIter iter;
509   jint row;
510   gint *indices;
511
512   if (gtk_tree_model_get_iter (model, &iter, path))
513     {
514       indices = gtk_tree_path_get_indices (path);
515       row = indices ? indices[0] : -1;
516
517       if (!path_currently_selected)
518         {
519           (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
520                                         postListItemEventID,
521                                         row,
522                                         (jint) AWT_ITEM_SELECTED);
523         }
524       else
525         {
526           (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
527                                         postListItemEventID,
528                                         row,
529                                         (jint) AWT_ITEM_DESELECTED);
530         }
531     }
532
533   return TRUE;
534 }
535
536 static GtkWidget *
537 list_get_widget (GtkWidget *widget)
538 {
539    GtkWidget *wid;
540    g_assert (GTK_IS_EVENT_BOX (widget));
541
542    wid = gtk_bin_get_child (GTK_BIN (widget));
543    g_assert (GTK_IS_SCROLLED_WINDOW (wid));
544
545    wid = gtk_bin_get_child (GTK_BIN (wid));
546
547    return wid;
548 }
549