~ml-launchpad/ubuntu/natty/gcompris/fix-for-777349

« back to all changes in this revision

Viewing changes to src/wordprocessor-activity/wordprocessor.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Gariepy, Marc Gariepy, Stephane Graber
  • Date: 2010-01-04 17:42:49 UTC
  • mfrom: (1.1.14 upstream)
  • Revision ID: james.westby@ubuntu.com-20100104174249-7bupatd9dtxyhvs4
Tags: 9.0-0ubuntu1
[Marc Gariepy]
* New upstream release (9.0).
* Remove cache.c from POTFILES to avoid FTBFS
* Remove unneeded rm in debian/rules (file no longer exists upstream)

[Stephane Graber]
* Bump Debian standards to 3.8.3
* Add patch system (dpatch)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gcompris - wordprocessor.c
 
2
 *
 
3
 * Copyright (C) 2006, 2008 Bruno Coudoin
 
4
 *
 
5
 *   This program is free software; you can redistribute it and/or modify
 
6
 *   it under the terms of the GNU General Public License as published by
 
7
 *   the Free Software Foundation; either version 3 of the License, or
 
8
 *   (at your option) any later version.
 
9
 *
 
10
 *   This program is distributed in the hope that it will be useful,
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *   GNU General Public License for more details.
 
14
 *
 
15
 *   You should have received a copy of the GNU General Public License
 
16
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <string.h>
 
20
#include <glib/gstdio.h>
 
21
#include <libxml/HTMLparser.h>
 
22
 
 
23
#include "gcompris/gcompris.h"
 
24
 
 
25
/*
 
26
 * Predefined styles
 
27
 * -----------------
 
28
 */
 
29
typedef struct {
 
30
  gchar *name;
 
31
  gchar *font;
 
32
  PangoWeight weight;
 
33
  GtkJustification justification;
 
34
  gint left_margin;
 
35
  gint pixels_above_lines;
 
36
  gint pixels_below_lines;
 
37
} style_t;
 
38
 
 
39
#define NUMBER_OF_STYLE 4 /* h1 h2 h3 p */
 
40
 
 
41
static GtkTextTag *tag_list[NUMBER_OF_STYLE];
 
42
 
 
43
 
 
44
/*
 
45
 * The document styles
 
46
 */
 
47
typedef struct {
 
48
  gchar *name;
 
49
  style_t style[NUMBER_OF_STYLE];
 
50
} doctype_t;
 
51
 
 
52
doctype_t type_normal =
 
53
  {
 
54
    .name = N_("Research"),
 
55
    .style = {
 
56
      { "h1", "Serif 30", PANGO_WEIGHT_ULTRABOLD,  GTK_JUSTIFY_CENTER, 0,  40, 20 },
 
57
      { "h2", "Serif 26", PANGO_WEIGHT_BOLD,       GTK_JUSTIFY_LEFT,   0,  30, 15 },
 
58
      { "h3", "Serif 20", PANGO_WEIGHT_SEMIBOLD,   GTK_JUSTIFY_LEFT,   15,  20, 12 },
 
59
      { "p",  "Serif 16", PANGO_WEIGHT_NORMAL,     GTK_JUSTIFY_LEFT,   30, 3,  3 }
 
60
    }
 
61
  };
 
62
 
 
63
doctype_t type_letter =
 
64
  {
 
65
    .name = N_("Sentimental"),
 
66
    .style = {
 
67
      { "h1", "Serif 26", PANGO_WEIGHT_ULTRABOLD,  GTK_JUSTIFY_CENTER, 0,  40, 20 },
 
68
      { "h2", "Serif 20", PANGO_WEIGHT_BOLD,       GTK_JUSTIFY_LEFT,   0,  30, 15 },
 
69
      { "h3", "Serif 16", PANGO_WEIGHT_SEMIBOLD,   GTK_JUSTIFY_LEFT,   10, 20, 12 },
 
70
      { "p",  "Serif 14", PANGO_WEIGHT_NORMAL,     GTK_JUSTIFY_LEFT,   30, 3,  3 }
 
71
    },
 
72
  };
 
73
 
 
74
doctype_t type_small =
 
75
  {
 
76
    .name = N_("Official"),
 
77
    .style = {
 
78
      { "h1", "Serif 18", PANGO_WEIGHT_ULTRABOLD,  GTK_JUSTIFY_CENTER, 0,  40, 20 },
 
79
      { "h2", "Serif 16", PANGO_WEIGHT_BOLD,       GTK_JUSTIFY_LEFT,   0,  30, 15 },
 
80
      { "h3", "Serif 14", PANGO_WEIGHT_SEMIBOLD,   GTK_JUSTIFY_LEFT,   10, 20, 12 },
 
81
      { "p",  "Serif 12", PANGO_WEIGHT_NORMAL,     GTK_JUSTIFY_LEFT,   30, 3,  3 }
 
82
    },
 
83
  };
 
84
 
 
85
doctype_t type_text =
 
86
  {
 
87
    .name = N_("Text"),
 
88
    .style = {
 
89
      { "h1", "Serif 12", PANGO_WEIGHT_ULTRABOLD,  GTK_JUSTIFY_CENTER, 0,  40, 20 },
 
90
      { "h2", "Serif 12", PANGO_WEIGHT_BOLD,       GTK_JUSTIFY_LEFT,   0,  30, 15 },
 
91
      { "h3", "Serif 12", PANGO_WEIGHT_SEMIBOLD,   GTK_JUSTIFY_LEFT,   15, 20, 12 },
 
92
      { "p",  "Serif 12", PANGO_WEIGHT_NORMAL,     GTK_JUSTIFY_LEFT,   30, 3,  3 }
 
93
    },
 
94
  };
 
95
 
 
96
doctype_t type_big =
 
97
  {
 
98
    .name = N_("Flyer"),
 
99
    .style = {
 
100
      { "h1", "Serif 34", PANGO_WEIGHT_ULTRABOLD,  GTK_JUSTIFY_CENTER, 0,  40, 20 },
 
101
      { "h2", "Serif 30", PANGO_WEIGHT_BOLD,       GTK_JUSTIFY_LEFT,   0,  30, 15 },
 
102
      { "h3", "Serif 26", PANGO_WEIGHT_SEMIBOLD,   GTK_JUSTIFY_LEFT,   15, 20, 12 },
 
103
      { "p",  "Serif 18", PANGO_WEIGHT_NORMAL,     GTK_JUSTIFY_LEFT,   30, 3,  3 }
 
104
    },
 
105
  };
 
106
#define NUMBER_OF_DOCTYPE 5
 
107
static doctype_t *doctype_list[NUMBER_OF_DOCTYPE];
 
108
 
 
109
/*
 
110
 * The color styles
 
111
 */
 
112
#define NUMBER_OF_COLOR_STYLE 4
 
113
static gchar *color_style_list[NUMBER_OF_COLOR_STYLE][NUMBER_OF_STYLE+1] =
 
114
{
 
115
  {N_("Spring"), "red",  "blue",  "lightblue",  "black"},
 
116
  {N_("Summer"), "DeepPink",  "HotPink",  "MediumOrchid",  "black"},
 
117
  {N_("Autumn"), "blue",  "red",  "lightblue",  "black"},
 
118
  {N_("Winter"), "black",  "black",  "black",  "black"},
 
119
};
 
120
 
 
121
static GcomprisBoard    *gcomprisBoard = NULL;
 
122
static gboolean          board_paused = TRUE;
 
123
static GtkWidget        *gtk_combo_styles = NULL;
 
124
static GtkWidget        *gtk_combo_colors = NULL;
 
125
static GtkWidget        *gtk_button_style[NUMBER_OF_STYLE];
 
126
static GtkWidget        *sw = NULL;
 
127
 
 
128
static void      start_board (GcomprisBoard *agcomprisBoard);
 
129
static void      pause_board (gboolean pause);
 
130
static void      end_board (void);
 
131
static gboolean  is_our_board (GcomprisBoard *gcomprisBoard);
 
132
static void      set_level (guint level);
 
133
static gboolean  key_release_event (GtkWidget *text_view,
 
134
                                    GdkEventKey *event);
 
135
 
 
136
static GooCanvasItem *boardRootItem = NULL;
 
137
 
 
138
static GooCanvasItem    *wordprocessor_create(void);
 
139
static void              wordprocessor_destroy_all_items(void);
 
140
static void              item_event(GtkWidget *item, gchar *data);
 
141
static int               display_style_buttons(GooCanvasItem *boardRootItem,
 
142
                                               int x,
 
143
                                               int y);
 
144
static void              create_tags (GtkTextBuffer *buffer, doctype_t *doctype);
 
145
static void              set_default_tag (GtkTextBuffer *buffer, GtkTextTag *tag);
 
146
static void              display_style_selector(GooCanvasItem *boardRootItem, double y);
 
147
static void              display_color_style_selector(GooCanvasItem *boardRootItem, double y);
 
148
static void              item_event_style_selection (GtkComboBox *widget, void *data);
 
149
static void              item_event_color_style_selection (GtkComboBox *widget, void *data);
 
150
static gboolean          save_event (GooCanvasItem  *item,
 
151
                                     GooCanvasItem  *target,
 
152
                                     GdkEventButton *event,
 
153
                                     gchar *data);
 
154
static gboolean          load_event (GooCanvasItem  *item,
 
155
                                     GooCanvasItem  *target,
 
156
                                     GdkEventButton *event,
 
157
                                     gchar *data);
 
158
static int               get_style_index(gchar *style);
 
159
static int               get_style_current_index();
 
160
static gint              get_color_style_index(gchar *color_style);
 
161
static gint              get_color_style_current_index();
 
162
static GtkTextTag       *get_tag_from_name(gchar *name);
 
163
static void              apply_style(int style_index);
 
164
static void              apply_color_style(int style_index);
 
165
 
 
166
#define word_area_x1 120
 
167
#define word_area_y1 20
 
168
#define word_area_width 650
 
169
#define word_area_height 485
 
170
 
 
171
#define combo_style_x1 5
 
172
#define combo_style_width 105
 
173
 
 
174
static GtkTextBuffer *buffer;
 
175
static GtkWidget *view;
 
176
GtkTextTag *selected_tag;
 
177
 
 
178
/* Description of this plugin */
 
179
static BoardPlugin menu_bp =
 
180
  {
 
181
    NULL,
 
182
    NULL,
 
183
    "Wordprocessor",
 
184
    "A basic word processor",
 
185
    "Bruno Coudoin <bruno.coudoin@free.fr>",
 
186
    NULL,
 
187
    NULL,
 
188
    NULL,
 
189
    NULL,
 
190
    start_board,
 
191
    pause_board,
 
192
    end_board,
 
193
    is_our_board,
 
194
    NULL,
 
195
    NULL,
 
196
    set_level,
 
197
    NULL,
 
198
    NULL,
 
199
    NULL,
 
200
    NULL
 
201
  };
 
202
 
 
203
/*
 
204
 * Main entry point mandatory for each Gcompris's game
 
205
 * ---------------------------------------------------
 
206
 *
 
207
 */
 
208
 
 
209
GET_BPLUGIN_INFO(wordprocessor)
 
210
 
 
211
/*
 
212
 * in : boolean TRUE = PAUSE : FALSE = CONTINUE
 
213
 *
 
214
 */
 
215
static void pause_board (gboolean pause)
 
216
{
 
217
  int i;
 
218
 
 
219
  if(gcomprisBoard==NULL)
 
220
    return;
 
221
 
 
222
  /* Widgets don't like being overlapped */
 
223
  if(pause)
 
224
    {
 
225
      gtk_widget_hide(GTK_WIDGET(sw));
 
226
      gtk_widget_hide(GTK_WIDGET(gtk_combo_styles));
 
227
      gtk_widget_hide(GTK_WIDGET(gtk_combo_colors));
 
228
      for(i=0; i<NUMBER_OF_STYLE; i++)
 
229
        gtk_widget_hide(gtk_button_style[i]);
 
230
    }
 
231
  else
 
232
    {
 
233
      gtk_widget_show(GTK_WIDGET(sw));
 
234
      gtk_widget_show(GTK_WIDGET(gtk_combo_styles));
 
235
      gtk_widget_show(GTK_WIDGET(gtk_combo_colors));
 
236
      for(i=0; i<NUMBER_OF_STYLE; i++)
 
237
        gtk_widget_show(gtk_button_style[i]);
 
238
    }
 
239
 
 
240
  board_paused = pause;
 
241
}
 
242
 
 
243
/*
 
244
 */
 
245
static void start_board (GcomprisBoard *agcomprisBoard)
 
246
{
 
247
 
 
248
  if(agcomprisBoard!=NULL)
 
249
    {
 
250
      gcomprisBoard=agcomprisBoard;
 
251
      gcomprisBoard->level=1;
 
252
      gcomprisBoard->maxlevel=1;
 
253
      gcomprisBoard->sublevel=1;
 
254
      gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
 
255
      gc_bar_set(0);
 
256
      gc_bar_location(10, -1, 0.6);
 
257
 
 
258
      gc_set_default_background(goo_canvas_get_root_item(gcomprisBoard->canvas));
 
259
 
 
260
      wordprocessor_create();
 
261
 
 
262
      pause_board(FALSE);
 
263
 
 
264
    }
 
265
}
 
266
/* ======================================= */
 
267
static void end_board ()
 
268
{
 
269
  if(gcomprisBoard!=NULL)
 
270
    {
 
271
      pause_board(TRUE);
 
272
      wordprocessor_destroy_all_items();
 
273
    }
 
274
  gcomprisBoard = NULL;
 
275
}
 
276
 
 
277
/* ======================================= */
 
278
static void set_level (guint level)
 
279
{
 
280
}
 
281
/* ======================================= */
 
282
static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
 
283
{
 
284
  if (gcomprisBoard)
 
285
    {
 
286
      if(g_strcasecmp(gcomprisBoard->type, "wordprocessor")==0)
 
287
        {
 
288
          /* Set the plugin entry */
 
289
          gcomprisBoard->plugin=&menu_bp;
 
290
 
 
291
          return TRUE;
 
292
        }
 
293
    }
 
294
  return FALSE;
 
295
}
 
296
 
 
297
/*-------------------------------------------------------------------------------*/
 
298
/*-------------------------------------------------------------------------------*/
 
299
/* ==================================== */
 
300
/* Destroy all the items */
 
301
static void wordprocessor_destroy_all_items()
 
302
{
 
303
  if(boardRootItem!=NULL)
 
304
    goo_canvas_item_remove(boardRootItem);
 
305
 
 
306
  boardRootItem = NULL;
 
307
}
 
308
/* ==================================== */
 
309
static GooCanvasItem *wordprocessor_create()
 
310
{
 
311
  GooCanvasItem *item = NULL;
 
312
  GdkPixbuf *pixmap;
 
313
  double y;
 
314
 
 
315
  boardRootItem = goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas),
 
316
                                        NULL);
 
317
 
 
318
 
 
319
  selected_tag = NULL;
 
320
  view = gtk_text_view_new ();
 
321
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
 
322
  /* Change left margin throughout the widget */
 
323
  gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 1);
 
324
  g_signal_connect (view, "key-release-event",
 
325
                    G_CALLBACK (key_release_event), NULL);
 
326
 
 
327
  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
328
 
 
329
 
 
330
  sw = gtk_scrolled_window_new (NULL, NULL);
 
331
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
 
332
                                  GTK_POLICY_AUTOMATIC,
 
333
                                  GTK_POLICY_ALWAYS);
 
334
  gtk_container_add (GTK_CONTAINER (sw), view);
 
335
 
 
336
  item = goo_canvas_widget_new (boardRootItem,
 
337
                                GTK_WIDGET(sw),
 
338
                                word_area_x1,
 
339
                                word_area_y1,
 
340
                                word_area_width,
 
341
                                word_area_height,
 
342
                                "anchor", GTK_ANCHOR_NW,
 
343
                                NULL);
 
344
  gtk_widget_show(GTK_WIDGET(view));
 
345
  gtk_widget_show(GTK_WIDGET(sw));
 
346
 
 
347
  /*
 
348
   * Create the default style tags
 
349
   */
 
350
  doctype_list[0] = &type_text;
 
351
  doctype_list[1] = &type_normal;
 
352
  doctype_list[2] = &type_letter;
 
353
  doctype_list[3] = &type_small;
 
354
  doctype_list[4] = &type_big;
 
355
 
 
356
  y = 20.0;
 
357
  /*
 
358
   * The save button
 
359
   */
 
360
  pixmap = gc_pixmap_load("wordprocessor/tool-save.png");
 
361
  item = \
 
362
    goo_canvas_image_new (boardRootItem,
 
363
                          pixmap,
 
364
                          17.0,
 
365
                          y,
 
366
                          NULL);
 
367
  gdk_pixbuf_unref(pixmap);
 
368
  g_signal_connect(item, "button_press_event",
 
369
                   (GtkSignalFunc) save_event, buffer);
 
370
  gc_item_focus_init(item, NULL);
 
371
 
 
372
 
 
373
  /*
 
374
   * The load button
 
375
   */
 
376
  pixmap = gc_pixmap_load("wordprocessor/tool-load.png");
 
377
  item = \
 
378
    goo_canvas_image_new (boardRootItem,
 
379
                          pixmap,
 
380
                          60.0,
 
381
                          y,
 
382
                          NULL);
 
383
  gdk_pixbuf_unref(pixmap);
 
384
  g_signal_connect(item, "button_press_event",
 
385
                   (GtkSignalFunc) load_event, buffer);
 
386
  gc_item_focus_init(item, NULL);
 
387
 
 
388
 
 
389
  y += 45;
 
390
  /*
 
391
   * Display the style buttons
 
392
   */
 
393
  y = display_style_buttons(boardRootItem,
 
394
                            20.0,
 
395
                            y);
 
396
 
 
397
  y += 20;
 
398
  display_style_selector(boardRootItem, y);
 
399
 
 
400
  y += 40;
 
401
  display_color_style_selector(boardRootItem, y);
 
402
 
 
403
  /* Now we can create the tags */
 
404
  create_tags(buffer, doctype_list[0]);
 
405
 
 
406
  gtk_widget_grab_focus(view);
 
407
 
 
408
 return NULL;
 
409
}
 
410
 
 
411
/*
 
412
 * Display the style buttons
 
413
 *
 
414
 * \return the new y coordinate
 
415
 */
 
416
static int
 
417
display_style_buttons(GooCanvasItem *boardRootItem,
 
418
                      int x,
 
419
                      int y)
 
420
{
 
421
  int offset_y = 40;
 
422
  int i = 0;
 
423
  static gchar *styles_tab[] = { N_("Title"), "h1",
 
424
                                 N_("Heading 1"), "h2",
 
425
                                 N_("Heading 2"), "h3",
 
426
                                 N_("Text"), "p",
 
427
                                 NULL, NULL };
 
428
 
 
429
  while(styles_tab[i*2])
 
430
    {
 
431
      gtk_button_style[i] = gtk_button_new_with_label(gettext(styles_tab[i*2]));
 
432
 
 
433
      goo_canvas_widget_new (boardRootItem,
 
434
                             GTK_WIDGET(gtk_button_style[i]),
 
435
                             combo_style_x1,
 
436
                             y,
 
437
                             combo_style_width,
 
438
                             35.0,
 
439
                             "anchor", GTK_ANCHOR_NW,
 
440
                             NULL);
 
441
 
 
442
      g_signal_connect(GTK_OBJECT(gtk_button_style[i]), "pressed",
 
443
                         (GtkSignalFunc)item_event, styles_tab[i*2+1] );
 
444
 
 
445
      y += offset_y;
 
446
 
 
447
      i++;
 
448
    }
 
449
 
 
450
  return(y);
 
451
}
 
452
 
 
453
/* \brief callback on a style button (h1, h2, h3, p)
 
454
 *
 
455
 *
 
456
 */
 
457
static void
 
458
item_event(GtkWidget *button, gchar *data)
 
459
{
 
460
  GtkTextIter    iter_start, iter_end;
 
461
  gchar *current_style_name;
 
462
 
 
463
  if(board_paused)
 
464
    return;
 
465
 
 
466
  current_style_name = (char *)data;
 
467
 
 
468
  selected_tag = get_tag_from_name(current_style_name);
 
469
  set_default_tag(buffer, selected_tag);
 
470
 
 
471
  gtk_text_buffer_get_iter_at_mark(buffer,
 
472
                                   &iter_start,
 
473
                                   gtk_text_buffer_get_insert (buffer));
 
474
  gtk_text_iter_set_line_offset(&iter_start, 0);
 
475
 
 
476
  iter_end = iter_start;
 
477
  gtk_text_iter_forward_to_line_end(&iter_end);
 
478
 
 
479
  gtk_text_buffer_remove_all_tags(buffer,
 
480
                                  &iter_start,
 
481
                                  &iter_end);
 
482
 
 
483
  gtk_text_buffer_apply_tag_by_name(buffer,
 
484
                                    current_style_name,
 
485
                                    &iter_start,
 
486
                                    &iter_end);
 
487
 
 
488
  gtk_widget_grab_focus(view);
 
489
 
 
490
  return;
 
491
}
 
492
 
 
493
/* Create a bunch of tags. Note that it's also possible to
 
494
 * create tags with gtk_text_tag_new() then add them to the
 
495
 * tag table for the buffer, gtk_text_buffer_create_tag() is
 
496
 * just a convenience function. Also note that you don't have
 
497
 * to give tags a name; pass NULL for the name to create an
 
498
 * anonymous tag.
 
499
 *
 
500
 * In any real app, another useful optimization would be to create
 
501
 * a GtkTextTagTable in advance, and reuse the same tag table for
 
502
 * all the buffers with the same tag set, instead of creating
 
503
 * new copies of the same tags for every buffer.
 
504
 *
 
505
 * Tags are assigned default priorities in order of addition to the
 
506
 * tag table.    That is, tags created later that affect the same text
 
507
 * property affected by an earlier tag will override the earlier
 
508
 * tag.  You can modify tag priorities with
 
509
 * gtk_text_tag_set_priority().
 
510
 */
 
511
 
 
512
static void
 
513
create_tags (GtkTextBuffer *buffer, doctype_t *doctype)
 
514
{
 
515
  gint i;
 
516
  gint c = get_color_style_current_index();
 
517
 
 
518
  for(i=0; i<NUMBER_OF_STYLE; i++)
 
519
    {
 
520
      GtkTextTag *tag;
 
521
 
 
522
      tag = gtk_text_buffer_create_tag (buffer, doctype->style[i].name,
 
523
                                        "weight", doctype->style[i].weight,
 
524
                                        "font", doctype->style[i].font,
 
525
                                        "justification", doctype->style[i].justification,
 
526
                                        "left-margin", doctype->style[i].left_margin,
 
527
                                        "pixels-above-lines", doctype->style[i].pixels_above_lines,
 
528
                                        "pixels-below-lines", doctype->style[i].pixels_below_lines,
 
529
                                        "foreground",color_style_list[c][i+1],
 
530
                                        NULL);
 
531
      tag_list[i] = tag;
 
532
      g_object_set_data (G_OBJECT (tag), "style", &doctype->style[i]);
 
533
    }
 
534
 
 
535
  /* Point to the last style */
 
536
  i--;
 
537
 
 
538
  set_default_tag(buffer, tag_list[i]);
 
539
}
 
540
 
 
541
/*
 
542
 * Set the default style
 
543
 */
 
544
static void
 
545
set_default_tag (GtkTextBuffer *buffer, GtkTextTag *tag)
 
546
{
 
547
  PangoFontDescription *font_desc;
 
548
  GdkColor *color = (GdkColor *)g_malloc(sizeof(GdkColor));
 
549
  int val;
 
550
  GtkJustification justification;
 
551
 
 
552
  if(!tag)
 
553
    return;
 
554
 
 
555
  g_object_get (G_OBJECT (tag), "foreground-gdk", &color, NULL);
 
556
  g_object_get (G_OBJECT (tag), "font-desc", &font_desc, NULL);
 
557
 
 
558
  gtk_widget_modify_font (view, font_desc);
 
559
  gtk_widget_modify_text (view, GTK_STATE_NORMAL, color);
 
560
 
 
561
  g_object_get (G_OBJECT (tag), "left-margin", &val, NULL);
 
562
  gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), val);
 
563
 
 
564
  g_object_get (G_OBJECT (tag), "justification", &justification, NULL);
 
565
  gtk_text_view_set_justification(GTK_TEXT_VIEW (view), justification);
 
566
 
 
567
  g_object_get (G_OBJECT (tag), "pixels-below-lines", &val, NULL);
 
568
  gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW (view), val);
 
569
 
 
570
  g_object_get (G_OBJECT (tag), "pixels-above-lines", &val, NULL);
 
571
  gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW (view), val);
 
572
}
 
573
 
 
574
static GtkTextTag *
 
575
get_tag_from_name(gchar *tag_name)
 
576
{
 
577
  gint i;
 
578
 
 
579
  for(i=0; i<NUMBER_OF_STYLE; i++)
 
580
    {
 
581
      gchar *name;
 
582
      g_object_get(G_OBJECT (tag_list[i]), "name", &name, NULL);
 
583
      if(strcmp(name, tag_name)==0)
 
584
        return(tag_list[i]);
 
585
 
 
586
    }
 
587
  return(tag_list[i-1]);
 
588
}
 
589
 
 
590
/*
 
591
 * Create the combo with the styles
 
592
 * --------------------------------
 
593
 */
 
594
static void
 
595
display_style_selector(GooCanvasItem *boardRootItem, double y)
 
596
{
 
597
  int i = 0;
 
598
 
 
599
  gtk_combo_styles = gtk_combo_box_new_text();
 
600
 
 
601
  while (i < NUMBER_OF_DOCTYPE)
 
602
    gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_combo_styles),
 
603
                              gettext(doctype_list[i++]->name));
 
604
 
 
605
  goo_canvas_widget_new (boardRootItem,
 
606
                         GTK_WIDGET(gtk_combo_styles),
 
607
                         combo_style_x1,
 
608
                         y,
 
609
                         combo_style_width,
 
610
                         35.0,
 
611
                         "anchor", GTK_ANCHOR_NW,
 
612
                         NULL);
 
613
 
 
614
  gtk_widget_show(GTK_WIDGET(gtk_combo_styles));
 
615
  gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_combo_styles), 0);
 
616
 
 
617
  g_signal_connect(G_OBJECT(gtk_combo_styles),
 
618
                   "changed",
 
619
                   G_CALLBACK(item_event_style_selection),
 
620
                   NULL);
 
621
}
 
622
 
 
623
/*
 
624
 * Create the combo with the color styles
 
625
 * --------------------------------------
 
626
 */
 
627
static void
 
628
display_color_style_selector(GooCanvasItem *boardRootItem, double y)
 
629
{
 
630
  int i = 0;
 
631
 
 
632
  gtk_combo_colors = gtk_combo_box_new_text();
 
633
 
 
634
  while (i < NUMBER_OF_COLOR_STYLE)
 
635
    gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_combo_colors),
 
636
                              gettext(color_style_list[i++][0]));
 
637
 
 
638
  goo_canvas_widget_new (boardRootItem,
 
639
                         GTK_WIDGET(gtk_combo_colors),
 
640
                         combo_style_x1,
 
641
                         y,
 
642
                         combo_style_width,
 
643
                         35.0,
 
644
                         "anchor", GTK_ANCHOR_NW,
 
645
                         NULL);
 
646
 
 
647
  gtk_widget_show(GTK_WIDGET(gtk_combo_colors));
 
648
  gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_combo_colors), 0);
 
649
 
 
650
  g_signal_connect(G_OBJECT(gtk_combo_colors),
 
651
                   "changed",
 
652
                   G_CALLBACK(item_event_color_style_selection),
 
653
                   NULL);
 
654
}
 
655
 
 
656
static int
 
657
get_style_index(gchar *style)
 
658
{
 
659
  int i;
 
660
 
 
661
  /* Search the doctype */
 
662
  for(i=0; i<NUMBER_OF_DOCTYPE; i++)
 
663
    if(strcmp(gettext(doctype_list[i]->name), style)==0)
 
664
      return(i);
 
665
 
 
666
  return(0);
 
667
}
 
668
 
 
669
static int
 
670
get_style_current_index()
 
671
{
 
672
  return( get_style_index(gtk_combo_box_get_active_text(GTK_COMBO_BOX(gtk_combo_styles))) );
 
673
}
 
674
 
 
675
static void
 
676
apply_style(int style_index)
 
677
{
 
678
  int i = style_index;
 
679
  int j;
 
680
 
 
681
  for(j=0; j<NUMBER_OF_STYLE; j++)
 
682
    {
 
683
      g_object_set(tag_list[j],
 
684
                   "weight", doctype_list[i]->style[j].weight,
 
685
                   "font", doctype_list[i]->style[j].font,
 
686
                   "justification", doctype_list[i]->style[j].justification,
 
687
                   "left-margin", doctype_list[i]->style[j].left_margin,
 
688
                   "pixels-above-lines", doctype_list[i]->style[j].pixels_above_lines,
 
689
                   "pixels-below-lines", doctype_list[i]->style[j].pixels_below_lines,
 
690
                   NULL);
 
691
    }
 
692
}
 
693
 
 
694
/* Set a new style from the combo box selection
 
695
 *
 
696
 */
 
697
static void
 
698
item_event_style_selection (GtkComboBox *widget,
 
699
                            void *data)
 
700
{
 
701
 
 
702
  apply_style(get_style_current_index());
 
703
 
 
704
  gtk_widget_grab_focus(view);
 
705
}
 
706
 
 
707
static gint
 
708
get_color_style_index(gchar *color_style)
 
709
{
 
710
  int i;
 
711
 
 
712
  /* Search the color style */
 
713
  for(i=0; i<NUMBER_OF_COLOR_STYLE; i++)
 
714
    if(strcmp(gettext(color_style_list[i][0]), color_style)==0)
 
715
      return(i);
 
716
 
 
717
  return(0);
 
718
}
 
719
 
 
720
static gint
 
721
get_color_style_current_index()
 
722
{
 
723
  return( get_color_style_index(gtk_combo_box_get_active_text(GTK_COMBO_BOX(gtk_combo_colors))) );
 
724
}
 
725
 
 
726
static void
 
727
apply_color_style(int color_style_index)
 
728
{
 
729
  int i = color_style_index;
 
730
  int j;
 
731
 
 
732
  /* Change the color */
 
733
  for(j=0; j<NUMBER_OF_STYLE; j++)
 
734
    g_object_set(tag_list[j],
 
735
                 "foreground",color_style_list[i][j+1],
 
736
                 NULL);
 
737
}
 
738
 
 
739
/* Set a new color style from the combo box selection
 
740
 *
 
741
 */
 
742
static void
 
743
item_event_color_style_selection (GtkComboBox *widget,
 
744
                                  void *data)
 
745
{
 
746
  apply_color_style(get_color_style_current_index());
 
747
  gtk_widget_grab_focus(view);
 
748
}
 
749
 
 
750
 
 
751
/* Catch all typing events to apply the proper tags
 
752
 *
 
753
 */
 
754
static gboolean
 
755
key_release_event (GtkWidget *text_view,
 
756
                   GdkEventKey *event)
 
757
{
 
758
  GtkTextIter iter_start, iter_end;
 
759
  GtkTextBuffer *buffer;
 
760
 
 
761
  {
 
762
    GSList *tags = NULL, *tagp = NULL;
 
763
 
 
764
    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
 
765
 
 
766
    gtk_text_buffer_get_iter_at_mark(buffer,
 
767
                                     &iter_start,
 
768
                                     gtk_text_buffer_get_insert (buffer));
 
769
    gtk_text_iter_set_line_offset(&iter_start, 0);
 
770
 
 
771
    iter_end = iter_start;
 
772
    gtk_text_iter_forward_to_line_end(&iter_end);
 
773
 
 
774
    tags = gtk_text_iter_get_tags (&iter_start);
 
775
 
 
776
    if(g_slist_length(tags) == 0)
 
777
      {
 
778
        gtk_text_iter_backward_char (&iter_end);
 
779
        tags = gtk_text_iter_get_tags (&iter_end);
 
780
        gtk_text_iter_forward_char (&iter_end);
 
781
      }
 
782
 
 
783
    for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
 
784
      {
 
785
        GtkTextTag *tag = tagp->data;
 
786
        gchar *name;
 
787
        g_object_get (G_OBJECT (tag), "name", &name, NULL);
 
788
 
 
789
        set_default_tag(buffer, tag);
 
790
        gtk_text_buffer_apply_tag_by_name(buffer,
 
791
                                          name,
 
792
                                          &iter_start,
 
793
                                          &iter_end);
 
794
        g_free(name);
 
795
        selected_tag = NULL;
 
796
      }
 
797
 
 
798
    if (tags)
 
799
      g_slist_free (tags);
 
800
    else
 
801
      {
 
802
        /* Set the default style */
 
803
        if(selected_tag)
 
804
          {
 
805
            set_default_tag(buffer, selected_tag);
 
806
 
 
807
            gtk_text_buffer_apply_tag(buffer,
 
808
                                      selected_tag,
 
809
                                      &iter_start,
 
810
                                      &iter_end);
 
811
          }
 
812
        else
 
813
          {
 
814
            set_default_tag(buffer, tag_list[NUMBER_OF_STYLE-1]);
 
815
 
 
816
            gtk_text_buffer_apply_tag(buffer,
 
817
                                      tag_list[NUMBER_OF_STYLE-1],
 
818
                                      &iter_start,
 
819
                                      &iter_end);
 
820
          }
 
821
      }
 
822
  }
 
823
 
 
824
  return FALSE;
 
825
}
 
826
 
 
827
// assumes UTF-8 or UTF-16 as encoding,
 
828
static char *
 
829
escape(char *input)
 
830
{
 
831
  gsize size = strlen(input)*6; /* 6 is the most increase we can get */
 
832
  gchar *result = g_malloc(size);
 
833
  int i;
 
834
  int o = 0;
 
835
 
 
836
  result[0] = '\0';
 
837
 
 
838
  for(i = 0; i < strlen(input); i++)
 
839
    {
 
840
      char c = input[i];
 
841
      if(c == '<')
 
842
        o = g_strlcat(result, "&lt;", size);
 
843
      else if(c == '>')
 
844
        o = g_strlcat(result, "&gt;", size);
 
845
      else if(c == '&')
 
846
        o = g_strlcat(result, "&amp;", size);
 
847
      else if(c == '"')
 
848
        o = g_strlcat(result, "&quot;", size);
 
849
      else if(c == '\'')
 
850
        o = g_strlcat(result, "&apos;", size);
 
851
      else
 
852
        {
 
853
          result[o++] = c;
 
854
          result[o+1] = '\0';
 
855
        }
 
856
    }
 
857
  g_free(input);
 
858
  return result;
 
859
}
 
860
 
 
861
static void
 
862
save_buffer(gchar *file, gchar *file_type, void *unused)
 
863
{
 
864
  GtkTextIter iter_start, iter_end;
 
865
  GSList *tags = NULL, *tagp = NULL;
 
866
  gchar *tag_name;
 
867
  FILE *filefd;
 
868
  int style_index = get_style_current_index();
 
869
  int color_index = get_color_style_current_index();
 
870
 
 
871
  filefd = g_fopen(file, "w+");
 
872
 
 
873
  /*
 
874
   * XHTML Header
 
875
   */
 
876
  fprintf(filefd,
 
877
          "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
 
878
          "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
 
879
          "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
 
880
          "<head>\n"
 
881
          "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
 
882
          "<meta http-equiv=\"GCompris-doctype\" content=\"%s\" />\n"
 
883
          "<meta http-equiv=\"GCompris-color-style\" content=\"%s\" />\n"
 
884
          "<title>GCompris</title>\n",
 
885
          doctype_list[style_index]->name,
 
886
          color_style_list[color_index][0]);
 
887
 
 
888
  /*
 
889
   * HTML Style
 
890
   */
 
891
  fprintf(filefd,
 
892
          "<style type=\"text/css\">\n");
 
893
 
 
894
  {
 
895
    int i;
 
896
    int font_size[NUMBER_OF_STYLE] = { 28, 22, 16, 12 };
 
897
    char *align[NUMBER_OF_STYLE] = { "center", "left", "left", "justify" };
 
898
    int left_margin[NUMBER_OF_STYLE] = { 0, 10, 20, 30 };
 
899
 
 
900
    for(i=0; i<NUMBER_OF_STYLE; i++)
 
901
      {
 
902
        style_t style = doctype_list[style_index]->style[i];
 
903
        fprintf(filefd,
 
904
                "%s {\n"
 
905
                "  color : %s;\n"
 
906
                "  font-size : %dpx;\n"
 
907
                "  text-align : %s;\n"
 
908
                "  margin-left : %dpx;\n"
 
909
                "}\n",
 
910
                style.name,
 
911
                color_style_list[color_index][i+1],
 
912
                font_size[i],
 
913
                align[i],
 
914
                left_margin[i]);
 
915
      }
 
916
 
 
917
  }
 
918
  fprintf(filefd,
 
919
          "</style>\n"
 
920
          "</head>\n");
 
921
 
 
922
  /*
 
923
   * Header end
 
924
   */
 
925
  fprintf(filefd,
 
926
          "<body>\n");
 
927
 
 
928
  gtk_text_buffer_get_iter_at_offset(buffer,
 
929
                                     &iter_start,
 
930
                                     0);
 
931
 
 
932
  do
 
933
    {
 
934
      iter_end = iter_start;
 
935
      gtk_text_iter_forward_to_line_end(&iter_end);
 
936
 
 
937
      if(gtk_text_iter_ends_line(&iter_start))
 
938
        continue;
 
939
 
 
940
      tags = gtk_text_iter_get_tags (&iter_start);
 
941
      if(g_slist_length(tags) == 0)
 
942
        {
 
943
          gtk_text_iter_backward_char (&iter_end);
 
944
          tags = gtk_text_iter_get_tags (&iter_end);
 
945
          gtk_text_iter_forward_char (&iter_end);
 
946
        }
 
947
 
 
948
      tag_name = "p";
 
949
      for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
 
950
        {
 
951
          GtkTextTag *tag = tagp->data;
 
952
          g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
 
953
 
 
954
        }
 
955
      fprintf(filefd, "<%s>", tag_name);
 
956
 
 
957
      char *result = escape(gtk_text_buffer_get_text(buffer,
 
958
                                                     &iter_start,
 
959
                                                     &iter_end,
 
960
                                                     0));
 
961
 
 
962
      for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
 
963
        {
 
964
          GtkTextTag *tag = tagp->data;
 
965
          g_object_get (G_OBJECT (tag), "name", &tag_name, NULL);
 
966
 
 
967
        }
 
968
      fprintf(filefd, "%s</%s>\n", result, tag_name);
 
969
      g_free(result);
 
970
 
 
971
      if (tags)
 
972
        g_slist_free (tags);
 
973
 
 
974
    } while(gtk_text_iter_forward_line(&iter_start));
 
975
 
 
976
  /*
 
977
   * HTML Footer
 
978
   */
 
979
  fprintf(filefd, ""
 
980
          "</body>\n"
 
981
          "</html>\n");
 
982
 
 
983
  fclose(filefd);
 
984
 
 
985
  pause_board(FALSE);
 
986
 
 
987
}
 
988
 
 
989
static gboolean
 
990
save_event (GooCanvasItem  *item,
 
991
            GooCanvasItem  *target,
 
992
            GdkEventButton *event,
 
993
            gchar *data)
 
994
{
 
995
  if (event->button != 1)
 
996
    return FALSE;
 
997
 
 
998
  pause_board(TRUE);
 
999
 
 
1000
  gc_selector_file_save(gcomprisBoard,
 
1001
                        "wordprocessor",
 
1002
                        ".xhtml",
 
1003
                        save_buffer, NULL);
 
1004
 
 
1005
  return FALSE;
 
1006
}
 
1007
 
 
1008
static void
 
1009
load_buffer(gchar *file, gchar *file_type, void *unused)
 
1010
{
 
1011
  GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
1012
  xmlDocPtr doc;
 
1013
  xmlNodePtr node;
 
1014
  GtkTextIter iter_start, iter_end;
 
1015
 
 
1016
  /* parse the new file and put the result into newdoc */
 
1017
  doc = xmlParseFile(file);
 
1018
 
 
1019
  /* in case something went wrong */
 
1020
  if(!doc)
 
1021
    return;
 
1022
 
 
1023
  /* Get the root element node */
 
1024
  node = xmlDocGetRootElement(doc);
 
1025
 
 
1026
  for(node = node; node != NULL; node = node->next)
 
1027
    if ( g_strcasecmp((char *)node->name, "html") == 0 &&
 
1028
         node->children )
 
1029
      break;
 
1030
 
 
1031
  if(!node)
 
1032
    goto done;
 
1033
 
 
1034
  for(node = node->children; node != NULL; node = node->next)
 
1035
    {
 
1036
      if ( g_strcasecmp((char *)node->name, "head") == 0 &&
 
1037
           node->children )
 
1038
        {
 
1039
          /* Search and apply the saved style in the META */
 
1040
          xmlNodePtr snode;
 
1041
          for(snode = node->children; snode != NULL; snode = snode->next)
 
1042
            {
 
1043
              if ( ( g_strcasecmp((char *)snode->name, "meta") == 0 ) &&
 
1044
                   xmlHasProp(snode, BAD_CAST "http-equiv") )
 
1045
                {
 
1046
                  xmlChar *key = xmlGetProp(snode, BAD_CAST "http-equiv");
 
1047
                  xmlChar *content = xmlGetProp(snode, BAD_CAST "content");
 
1048
 
 
1049
                  if(g_strcasecmp((char *)key, "GCompris-doctype") == 0)
 
1050
                    {
 
1051
                      int style_index = get_style_index(gettext((char *)content));
 
1052
                      apply_style(style_index);
 
1053
                      gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_combo_styles),
 
1054
                                               style_index);
 
1055
                    }
 
1056
 
 
1057
                  if(g_strcasecmp((char *)key, "GCompris-color-style") == 0)
 
1058
                    {
 
1059
                      int cstyle_index = get_color_style_index(gettext((char *)content));
 
1060
                      apply_color_style(cstyle_index);
 
1061
                      gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_combo_colors),
 
1062
                                               cstyle_index);
 
1063
                    }
 
1064
 
 
1065
                  xmlFree(key);
 
1066
                  xmlFree(content);
 
1067
                }
 
1068
            }
 
1069
        }
 
1070
 
 
1071
      if ( g_strcasecmp((char *)node->name, "body") == 0 &&
 
1072
           node->children )
 
1073
        break;
 
1074
    }
 
1075
 
 
1076
  if(!node)
 
1077
    goto done;
 
1078
 
 
1079
  gtk_text_buffer_get_start_iter(buffer,
 
1080
                                 &iter_start);
 
1081
  gtk_text_buffer_get_end_iter(buffer,
 
1082
                               &iter_end);
 
1083
  gtk_text_buffer_delete(buffer,
 
1084
                         &iter_start,
 
1085
                         &iter_end);
 
1086
 
 
1087
  gtk_text_buffer_get_start_iter(buffer,
 
1088
                                 &iter_start);
 
1089
 
 
1090
  for(node = node->children; node != NULL; node = node->next)
 
1091
    {
 
1092
 
 
1093
      if ( g_strcasecmp((char *)node->name, "h1") == 0 ||
 
1094
           g_strcasecmp((char *)node->name, "h2") == 0 ||
 
1095
           g_strcasecmp((char *)node->name, "h3") == 0 ||
 
1096
           g_strcasecmp((char *)node->name, "p") == 0 )
 
1097
        {
 
1098
          xmlChar *content;
 
1099
          content = xmlNodeGetContent(node);
 
1100
          gtk_text_buffer_insert_with_tags_by_name(buffer,
 
1101
                                                   &iter_start,
 
1102
                                                   (char *)content,
 
1103
                                                   strlen((char *)content),
 
1104
                                                   (char *)node->name,
 
1105
                                                   NULL);
 
1106
          xmlFree(content);
 
1107
          gtk_text_buffer_get_end_iter(buffer,
 
1108
                                       &iter_start);
 
1109
          gtk_text_buffer_insert(buffer,&iter_start, "\n", 1);
 
1110
 
 
1111
          gtk_text_buffer_get_end_iter(buffer,
 
1112
                                         &iter_start);
 
1113
 
 
1114
        }
 
1115
 
 
1116
    }
 
1117
 
 
1118
 done:
 
1119
  xmlFreeDoc(doc);
 
1120
}
 
1121
 
 
1122
static gboolean
 
1123
load_event (GooCanvasItem  *item,
 
1124
            GooCanvasItem  *target,
 
1125
            GdkEventButton *event,
 
1126
            gchar *data)
 
1127
{
 
1128
  if (event->button != 1)
 
1129
    return FALSE;
 
1130
 
 
1131
  pause_board(TRUE);
 
1132
 
 
1133
  gc_selector_file_load(gcomprisBoard,
 
1134
                        "wordprocessor",
 
1135
                        ".xhtml",
 
1136
                        load_buffer, NULL);
 
1137
 
 
1138
  return FALSE;
 
1139
}
 
1140