1 /*
2 * new-label-dialog.c
3 * Copyright (C) 2006-2009 Jim Evins <evins@snaught.com>.
4 *
5 * This file is part of gLabels.
6 *
7 * gLabels is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * gLabels is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include "new-label-dialog.h"
24
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27
28 #include "marshal.h"
29 #include "builder-util.h"
30 #include "prefs.h"
31 #include "media-select.h"
32 #include "mini-label-preview.h"
33 #include "mini-preview.h"
34
35 #include "debug.h"
36
37
38 #define LABEL_PREVIEW_WIDTH 96
39 #define LABEL_PREVIEW_HEIGHT 96
40
41 #define MINI_PREVIEW_MIN_WIDTH 300
42 #define MINI_PREVIEW_MIN_HEIGHT 360
43
44
45 /*===========================================*/
46 /* Private data types */
47 /*===========================================*/
48
49 struct _glNewLabelDialogPrivate {
50
51 GtkBuilder *builder;
52
53 GtkWidget *template_page_vbox;
54 GtkWidget *combo_hbox;
55 GtkWidget *combo;
56
57 GtkWidget *rotate_page_vbox;
58 GtkWidget *normal_radio;
59 GtkWidget *rotated_radio;
60 GtkWidget *normal_preview_hbox;
61 GtkWidget *rotated_preview_hbox;
62 GtkWidget *normal_preview;
63 GtkWidget *rotated_preview;
64
65 GtkWidget *confirm_page_vbox;
66 GtkWidget *preview_vbox;
67 GtkWidget *preview;
68 GtkWidget *desc_label;
69 GtkWidget *page_size_label;
70 GtkWidget *label_size_label;
71 GtkWidget *layout_label;
72 GtkWidget *vendor_label;
73 GtkWidget *part_label;
74 GtkWidget *similar_label;
75 };
76
77 /* Page numbers for traversing GtkAssistant */
78 enum {
79 TEMPLATE_PAGE_NUM = 0,
80 ROTATE_PAGE_NUM,
81 CONFIRM_PAGE_NUM
82 };
83
84 enum {
85 COMPLETE,
86 LAST_SIGNAL
87 };
88
89
90 /*===========================================*/
91 /* Private globals */
92 /*===========================================*/
93
94 static gint signals[LAST_SIGNAL] = { 0 };
95
96
97 /*===========================================*/
98 /* Local function prototypes */
99 /*===========================================*/
100
101 static void gl_new_label_dialog_finalize (GObject *object);
102
103 static void cancel_cb (glNewLabelDialog *this);
104 static void apply_cb (glNewLabelDialog *this);
105 static void close_cb (glNewLabelDialog *this);
106
107 static gint forward_page_function (gint current_page,
108 glNewLabelDialog *this);
109
110 static void combo_changed_cb (glNewLabelDialog *this);
111 static void rotate_toggled_cb (glNewLabelDialog *this);
112
113 static void set_info (glNewLabelDialog *this,
114 const gchar *name);
115
116
117 /*****************************************************************************/
118 /* Boilerplate object stuff. */
119 /*****************************************************************************/
G_DEFINE_TYPE(glNewLabelDialog,gl_new_label_dialog,GTK_TYPE_ASSISTANT)120 G_DEFINE_TYPE (glNewLabelDialog, gl_new_label_dialog, GTK_TYPE_ASSISTANT)
121
122
123 /*****************************************************************************/
124 /* Class Init Function. */
125 /*****************************************************************************/
126 static void
127 gl_new_label_dialog_class_init (glNewLabelDialogClass *class)
128 {
129 GObjectClass *object_class = G_OBJECT_CLASS (class);
130
131 gl_debug (DEBUG_FILE, "");
132
133 gl_new_label_dialog_parent_class = g_type_class_peek_parent (class);
134
135 object_class->finalize = gl_new_label_dialog_finalize;
136
137 signals[COMPLETE] =
138 g_signal_new ("complete",
139 G_OBJECT_CLASS_TYPE(object_class),
140 G_SIGNAL_RUN_LAST,
141 G_STRUCT_OFFSET (glNewLabelDialogClass, complete),
142 NULL, NULL,
143 gl_marshal_VOID__VOID,
144 G_TYPE_NONE, 0);
145
146 }
147
148
149 /*****************************************************************************/
150 /* Object Instance Init Function. */
151 /*****************************************************************************/
152 static void
gl_new_label_dialog_init(glNewLabelDialog * this)153 gl_new_label_dialog_init (glNewLabelDialog *this)
154 {
155 GdkRGBA banner_color = { 0, 0.5, 1.0, 1.0 };
156 GtkWidget *page_1_banner_eventbox, *page_2_banner_eventbox, *page_3_banner_eventbox;
157 GtkWidget *page_1_image, *page_2_image, *page_3_image;
158 gchar *logo_filename;
159 GdkPixbuf *logo;
160 GtkBuilder *builder;
161 gchar *builder_filename;
162 static gchar *object_ids[] = { "template_page_vbox",
163 "rotate_page_vbox",
164 "confirm_page_vbox",
165 NULL };
166 GError *error = NULL;
167
168 gl_debug (DEBUG_FILE, "START");
169
170 g_return_if_fail (GL_IS_NEW_LABEL_DIALOG (this));
171
172 this->priv = g_new0 (glNewLabelDialogPrivate, 1);
173
174 builder = gtk_builder_new ();
175 builder_filename = g_build_filename (GLABELS_DATA_DIR, "ui", "new-label-dialog.ui", NULL);
176 gtk_builder_add_objects_from_file (builder, builder_filename, object_ids, &error);
177 g_free (builder_filename);
178 if (error) {
179 g_critical ("%s\n\ngLabels may not be installed correctly!", error->message);
180 g_error_free (error);
181 return;
182 }
183
184 gl_builder_util_get_widgets (builder,
185 "page_1_banner_eventbox", &page_1_banner_eventbox,
186 "page_2_banner_eventbox", &page_2_banner_eventbox,
187 "page_3_banner_eventbox", &page_3_banner_eventbox,
188 "page_1_image", &page_1_image,
189 "page_2_image", &page_2_image,
190 "page_3_image", &page_3_image,
191 "template_page_vbox", &this->priv->template_page_vbox,
192 "combo_hbox", &this->priv->combo_hbox,
193 "rotate_page_vbox", &this->priv->rotate_page_vbox,
194 "normal_radio", &this->priv->normal_radio,
195 "rotated_radio", &this->priv->rotated_radio,
196 "normal_preview_hbox", &this->priv->normal_preview_hbox,
197 "rotated_preview_hbox", &this->priv->rotated_preview_hbox,
198 "confirm_page_vbox", &this->priv->confirm_page_vbox,
199 "preview_vbox", &this->priv->preview_vbox,
200 "desc_label", &this->priv->desc_label,
201 "page_size_label", &this->priv->page_size_label,
202 "label_size_label", &this->priv->label_size_label,
203 "layout_label", &this->priv->layout_label,
204 "vendor_label", &this->priv->vendor_label,
205 "part_label", &this->priv->part_label,
206 "similar_label", &this->priv->similar_label,
207 NULL);
208
209 this->priv->builder = builder;
210
211 gtk_assistant_append_page (GTK_ASSISTANT (this), this->priv->template_page_vbox);
212 gtk_assistant_set_page_title (GTK_ASSISTANT (this), this->priv->template_page_vbox,
213 C_("Title of dialog page to select a stationary product",
214 "Select Product"));
215 gtk_assistant_set_page_type (GTK_ASSISTANT (this), this->priv->template_page_vbox, GTK_ASSISTANT_PAGE_INTRO);
216 gtk_widget_override_background_color (page_1_banner_eventbox, GTK_STATE_NORMAL, &banner_color);
217 logo_filename = g_build_filename (GLABELS_DATA_DIR, "pixmaps", "new-select.png", NULL);
218 logo = gdk_pixbuf_new_from_file (logo_filename, NULL);
219 gtk_image_set_from_pixbuf (GTK_IMAGE (page_1_image), logo);
220 g_free (logo_filename);
221 g_object_unref (logo);
222
223 this->priv->combo = gl_media_select_new ();
224 gtk_container_add (GTK_CONTAINER (this->priv->combo_hbox), this->priv->combo);
225
226 gtk_assistant_append_page (GTK_ASSISTANT (this), this->priv->rotate_page_vbox);
227 gtk_assistant_set_page_title (GTK_ASSISTANT (this), this->priv->rotate_page_vbox, _("Choose Orientation"));
228 gtk_assistant_set_page_complete (GTK_ASSISTANT (this), this->priv->rotate_page_vbox, TRUE);
229 gtk_widget_override_background_color (page_2_banner_eventbox, GTK_STATE_NORMAL, &banner_color);
230 logo_filename = g_build_filename (GLABELS_DATA_DIR, "pixmaps", "new-rotate.png", NULL);
231 logo = gdk_pixbuf_new_from_file (logo_filename, NULL);
232 gtk_image_set_from_pixbuf (GTK_IMAGE (page_2_image), logo);
233 g_free (logo_filename);
234 g_object_unref (logo);
235
236 this->priv->normal_preview = gl_mini_label_preview_new (LABEL_PREVIEW_WIDTH, LABEL_PREVIEW_HEIGHT);
237 gtk_container_add (GTK_CONTAINER (this->priv->normal_preview_hbox), this->priv->normal_preview);
238 this->priv->rotated_preview = gl_mini_label_preview_new (LABEL_PREVIEW_WIDTH, LABEL_PREVIEW_HEIGHT);
239 gtk_container_add (GTK_CONTAINER (this->priv->rotated_preview_hbox), this->priv->rotated_preview);
240
241 gtk_assistant_append_page (GTK_ASSISTANT (this), this->priv->confirm_page_vbox);
242 gtk_assistant_set_page_title (GTK_ASSISTANT (this), this->priv->confirm_page_vbox, _("Review"));
243 gtk_assistant_set_page_type (GTK_ASSISTANT (this), this->priv->confirm_page_vbox, GTK_ASSISTANT_PAGE_CONFIRM);
244 gtk_assistant_set_page_complete (GTK_ASSISTANT (this), this->priv->confirm_page_vbox, TRUE);
245 gtk_widget_override_background_color (page_3_banner_eventbox, GTK_STATE_NORMAL, &banner_color);
246 logo_filename = g_build_filename (GLABELS_DATA_DIR, "pixmaps", "new-confirm.png", NULL);
247 logo = gdk_pixbuf_new_from_file (logo_filename, NULL);
248 gtk_image_set_from_pixbuf (GTK_IMAGE (page_3_image), logo);
249 g_free (logo_filename);
250 g_object_unref (logo);
251
252 this->priv->preview = gl_mini_preview_new (MINI_PREVIEW_MIN_HEIGHT, MINI_PREVIEW_MIN_WIDTH);
253 gl_mini_preview_set_draw_arrow (GL_MINI_PREVIEW (this->priv->preview), TRUE);
254 gl_mini_preview_set_rotate (GL_MINI_PREVIEW (this->priv->preview), FALSE);
255 gtk_container_add (GTK_CONTAINER (this->priv->preview_vbox), this->priv->preview);
256
257 gtk_assistant_set_forward_page_func (GTK_ASSISTANT (this), (GtkAssistantPageFunc)forward_page_function, this, NULL);
258
259 g_signal_connect_swapped (G_OBJECT(this), "cancel", G_CALLBACK(cancel_cb), this);
260 g_signal_connect_swapped (G_OBJECT(this), "apply", G_CALLBACK(apply_cb), this);
261 g_signal_connect_swapped (G_OBJECT(this), "close", G_CALLBACK(close_cb), this);
262
263 g_signal_connect_swapped (G_OBJECT (this->priv->combo), "changed", G_CALLBACK (combo_changed_cb), this);
264 g_signal_connect_swapped (G_OBJECT (this->priv->normal_radio), "toggled", G_CALLBACK (rotate_toggled_cb), this);
265 g_signal_connect_swapped (G_OBJECT (this->priv->rotated_radio), "toggled", G_CALLBACK (rotate_toggled_cb), this);
266
267 combo_changed_cb (this);
268
269 gl_debug (DEBUG_FILE, "END");
270 }
271
272
273 /*****************************************************************************/
274 /* Finalize Function. */
275 /*****************************************************************************/
276 static void
gl_new_label_dialog_finalize(GObject * object)277 gl_new_label_dialog_finalize (GObject *object)
278 {
279 glNewLabelDialog* this = GL_NEW_LABEL_DIALOG (object);;
280
281 gl_debug (DEBUG_FILE, "START");
282
283 g_return_if_fail (object != NULL);
284 g_return_if_fail (GL_IS_NEW_LABEL_DIALOG (this));
285 g_return_if_fail (this->priv != NULL);
286
287 g_object_unref (G_OBJECT (this->priv->builder));
288 g_free (this->priv);
289
290 G_OBJECT_CLASS (gl_new_label_dialog_parent_class)->finalize (object);
291
292 gl_debug (DEBUG_FILE, "END");
293
294 }
295
296
297 /*****************************************************************************/
298 /* NEW object properties dialog. */
299 /*****************************************************************************/
300 GtkWidget *
gl_new_label_dialog_new(GtkWindow * win)301 gl_new_label_dialog_new (GtkWindow *win)
302 {
303 GtkWidget *this;
304
305 gl_debug (DEBUG_FILE, "");
306
307 this = GTK_WIDGET (g_object_new (GL_TYPE_NEW_LABEL_DIALOG, NULL));
308
309 gtk_window_set_transient_for (GTK_WINDOW (this), win);
310
311 return this;
312 }
313
314
315 /*--------------------------------------------------------------------------*/
316 /* PRIVATE. Handle non-linear forward traversal. */
317 /*--------------------------------------------------------------------------*/
318 static gint
forward_page_function(gint current_page,glNewLabelDialog * this)319 forward_page_function (gint current_page,
320 glNewLabelDialog *this)
321 {
322 gchar *name;
323 lglTemplate *template;
324 const lglTemplateFrame *frame;
325 gdouble w, h;
326
327 switch (current_page)
328 {
329 case TEMPLATE_PAGE_NUM:
330 name = gl_media_select_get_name (GL_MEDIA_SELECT (this->priv->combo));
331 if ( name != NULL )
332 {
333 template = lgl_db_lookup_template_from_name (name);
334 frame = (lglTemplateFrame *)template->frames->data;
335 lgl_template_frame_get_size (frame, &w, &h);
336
337 if ( w == h )
338 {
339 /* Skip rotate page for square and circular labels. */
340 return CONFIRM_PAGE_NUM;
341 }
342 }
343 return ROTATE_PAGE_NUM;
344
345 case ROTATE_PAGE_NUM:
346 return CONFIRM_PAGE_NUM;
347
348 case CONFIRM_PAGE_NUM:
349 default:
350 return -1;
351 }
352
353 return -1;
354 }
355
356
357 /*--------------------------------------------------------------------------*/
358 /* PRIVATE. cancel callback. */
359 /*--------------------------------------------------------------------------*/
360 static void
cancel_cb(glNewLabelDialog * this)361 cancel_cb (glNewLabelDialog *this)
362 {
363
364 gtk_widget_destroy (GTK_WIDGET(this));
365
366 }
367
368
369 /*--------------------------------------------------------------------------*/
370 /* PRIVATE. apply callback */
371 /*--------------------------------------------------------------------------*/
372 static void
apply_cb(glNewLabelDialog * this)373 apply_cb (glNewLabelDialog *this)
374 {
375
376 g_signal_emit (G_OBJECT (this), signals[COMPLETE], 0);
377
378 }
379
380
381 /*--------------------------------------------------------------------------*/
382 /* PRIVATE. close callback */
383 /*--------------------------------------------------------------------------*/
384 static void
close_cb(glNewLabelDialog * this)385 close_cb (glNewLabelDialog *this)
386 {
387
388 gtk_widget_destroy (GTK_WIDGET(this));
389
390 }
391
392
393 /*---------------------------------------------------------------------------*/
394 /* PRIVATE. Template changed callback. */
395 /*---------------------------------------------------------------------------*/
396 static void
combo_changed_cb(glNewLabelDialog * this)397 combo_changed_cb (glNewLabelDialog *this)
398 {
399 gchar *name;
400
401 gl_debug (DEBUG_FILE, "START");
402
403 name = gl_media_select_get_name (GL_MEDIA_SELECT (this->priv->combo));
404
405 gl_mini_label_preview_set_by_name (GL_MINI_LABEL_PREVIEW (this->priv->normal_preview), name, FALSE);
406 gl_mini_label_preview_set_by_name (GL_MINI_LABEL_PREVIEW (this->priv->rotated_preview), name, TRUE);
407 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->normal_radio), TRUE);
408
409 gl_mini_preview_set_by_name (GL_MINI_PREVIEW (this->priv->preview), name);
410 set_info (this, name);
411
412 gtk_assistant_set_page_complete (GTK_ASSISTANT (this), this->priv->template_page_vbox, (name != NULL));
413
414 g_free (name);
415
416 gl_debug (DEBUG_FILE, "END");
417 }
418
419
420 /*---------------------------------------------------------------------------*/
421 /* PRIVATE. Rotate toggled callback. */
422 /*---------------------------------------------------------------------------*/
423 static void
rotate_toggled_cb(glNewLabelDialog * this)424 rotate_toggled_cb (glNewLabelDialog *this)
425 {
426 gboolean state;
427
428 gl_debug (DEBUG_FILE, "START");
429
430 state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (this->priv->rotated_radio));
431 gl_mini_preview_set_rotate (GL_MINI_PREVIEW (this->priv->preview), state);
432
433 gl_debug (DEBUG_FILE, "END");
434 }
435
436
437 /*---------------------------------------------------------------------------*/
438 /* PRIVATE. Set information labels. */
439 /*---------------------------------------------------------------------------*/
440 static void
set_info(glNewLabelDialog * this,const gchar * name)441 set_info (glNewLabelDialog *this,
442 const gchar *name)
443 {
444 lglTemplate *template;
445 lglTemplateFrame *frame;
446 lglVendor *vendor;
447 lglUnits units;
448 gchar *page_size_string;
449 gchar *label_size_string;
450 gchar *layout_string;
451 GList *list, *p;
452 GString *list_string;
453
454 template = lgl_db_lookup_template_from_name (name);
455 frame = template->frames->data;
456 vendor = lgl_db_lookup_vendor_from_name (template->brand);
457
458 units = gl_prefs_model_get_units (gl_prefs);
459
460 page_size_string = lgl_db_lookup_paper_name_from_id (template->paper_id);
461 label_size_string = lgl_template_frame_get_size_description (frame, units);
462 layout_string = lgl_template_frame_get_layout_description (frame);
463
464 gtk_label_set_text (GTK_LABEL (this->priv->desc_label), template->description);
465 gtk_label_set_text (GTK_LABEL (this->priv->page_size_label), page_size_string);
466 gtk_label_set_text (GTK_LABEL (this->priv->label_size_label), label_size_string);
467 gtk_label_set_text (GTK_LABEL (this->priv->layout_label), layout_string);
468
469 if ( vendor && vendor->url )
470 {
471 gchar *escaped_url;
472 gchar *markup;
473
474 escaped_url = g_markup_escape_text (vendor->url, -1);
475 markup = g_strdup_printf ("<a href='%s'>%s</a>", escaped_url, vendor->name);
476 gtk_label_set_markup (GTK_LABEL (this->priv->vendor_label), markup);
477 gtk_widget_set_tooltip_text (this->priv->vendor_label, escaped_url);
478 g_free (escaped_url);
479 g_free (markup);
480 }
481 else
482 {
483 /* FIXME: Using set_markup instead of set_text to clear out previous link. */
484 gtk_label_set_markup (GTK_LABEL (this->priv->vendor_label), template->brand);
485 gtk_widget_set_has_tooltip (this->priv->vendor_label, FALSE);
486 }
487
488 if ( template->product_url )
489 {
490 gchar *escaped_url;
491 gchar *markup;
492
493 escaped_url = g_markup_escape_text (template->product_url, -1);
494 markup = g_strdup_printf ("<a href='%s'>%s</a>", escaped_url, template->part);
495 gtk_label_set_markup (GTK_LABEL (this->priv->part_label), markup);
496 gtk_widget_set_tooltip_text (this->priv->part_label, escaped_url);
497 g_free (escaped_url);
498 g_free (markup);
499 }
500 else
501 {
502 /* FIXME: Using set_markup instead of set_text to clear out previous link. */
503 gtk_label_set_markup (GTK_LABEL (this->priv->part_label), template->part);
504 gtk_widget_set_has_tooltip (this->priv->part_label, FALSE);
505 }
506
507 list = lgl_db_get_similar_template_name_list (name);
508 list_string = g_string_new ("");
509 for ( p = list; p; p = p->next )
510 {
511 g_string_append (list_string, (char *)p->data);
512 if ( p->next )
513 {
514 g_string_append (list_string, "\n");
515 }
516 }
517 gtk_label_set_text (GTK_LABEL (this->priv->similar_label), list_string->str);
518
519 lgl_db_free_template_name_list (list);
520 g_string_free (list_string, TRUE);
521
522 g_free (page_size_string);
523 g_free (label_size_string);
524 g_free (layout_string);
525 }
526
527
528 /*****************************************************************************/
529 /* Get template name. */
530 /*****************************************************************************/
531 gchar *
gl_new_label_dialog_get_template_name(glNewLabelDialog * this)532 gl_new_label_dialog_get_template_name (glNewLabelDialog *this)
533 {
534 gchar *name;
535
536 name = gl_media_select_get_name (GL_MEDIA_SELECT (this->priv->combo));
537
538 return name;
539 }
540
541
542 /*****************************************************************************/
543 /* Set template name. */
544 /*****************************************************************************/
545 void
gl_new_label_dialog_set_template_name(glNewLabelDialog * this,gchar * name)546 gl_new_label_dialog_set_template_name (glNewLabelDialog *this,
547 gchar *name)
548 {
549 gl_mini_preview_set_by_name (GL_MINI_PREVIEW (this->priv->preview), name);
550 gl_media_select_set_name (GL_MEDIA_SELECT (this->priv->combo), name);
551 set_info (this, name);
552 }
553
554
555 /*****************************************************************************/
556 /* Get current filter parameters. */
557 /*****************************************************************************/
558 void
gl_new_label_dialog_get_filter_parameters(glNewLabelDialog * this,gchar ** page_size_id,gchar ** category_id)559 gl_new_label_dialog_get_filter_parameters (glNewLabelDialog *this,
560 gchar **page_size_id,
561 gchar **category_id)
562 {
563 }
564
565
566 /*****************************************************************************/
567 /* Set current filter parameters. */
568 /*****************************************************************************/
569 void
gl_new_label_dialog_set_filter_parameters(glNewLabelDialog * this,const gchar * page_size_id,const gchar * category_id)570 gl_new_label_dialog_set_filter_parameters (glNewLabelDialog *this,
571 const gchar *page_size_id,
572 const gchar *category_id)
573 {
574 }
575
576
577 /*****************************************************************************/
578 /* Get rotate state. */
579 /*****************************************************************************/
580 gboolean
gl_new_label_dialog_get_rotate_state(glNewLabelDialog * this)581 gl_new_label_dialog_get_rotate_state (glNewLabelDialog *this)
582 {
583 return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (this->priv->rotated_radio));
584 }
585
586
587 /*****************************************************************************/
588 /* Set rotate state. */
589 /*****************************************************************************/
590 void
gl_new_label_dialog_set_rotate_state(glNewLabelDialog * this,gboolean state)591 gl_new_label_dialog_set_rotate_state (glNewLabelDialog *this,
592 gboolean state)
593 {
594 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->rotated_radio), state);
595 gl_mini_preview_set_rotate (GL_MINI_PREVIEW (this->priv->preview), state);
596 }
597
598
599
600 /*
601 * Local Variables: -- emacs
602 * mode: C -- emacs
603 * c-basic-offset: 8 -- emacs
604 * tab-width: 8 -- emacs
605 * indent-tabs-mode: nil -- emacs
606 * End: -- emacs
607 */
608