1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16  */
17 
18 #include <config.h>
19 
20 #ifdef HAVE_UNISTD_H
21 #  include <unistd.h>
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <math.h>
28 #include <glib.h>
29 
30 #ifdef GNOME
31 #undef GTK_DISABLE_DEPRECATED
32 #  include <gnome.h>
33 #endif
34 
35 #include <gdk-pixbuf/gdk-pixbuf.h>
36 #include <gtk/gtk.h>
37 
38 #include <textedit.h>
39 #include <focus.h>
40 #include "confirm.h"
41 
42 /** Functions called on menu selects.
43  *  Note that GTK (at least up to 2.12) doesn't disable the keyboard shortcuts
44  *  when the menu is made insensitive, so we have to check the constrains again
45  *  in the functions.
46  */
47 #ifdef G_OS_WIN32
48 /*
49  * Instead of polluting the Dia namespace with windoze headers, declare the
50  * required prototype here. This is bad style, but not as bad as namespace
51  * clashes to be resolved without C++   --hb
52  */
53 long __stdcall
54 ShellExecuteA (long        hwnd,
55                const char* lpOperation,
56                const char* lpFile,
57                const char* lpParameters,
58                const char* lpDirectory,
59                int         nShowCmd);
60 #endif
61 
62 #include "intl.h"
63 #include "commands.h"
64 #include "app_procs.h"
65 #include "diagram.h"
66 #include "display.h"
67 #include "object_ops.h"
68 #include "cut_n_paste.h"
69 #include "interface.h"
70 #include "load_save.h"
71 #include "utils.h"
72 #include "message.h"
73 #include "grid.h"
74 #include "properties-dialog.h"
75 #include "propinternals.h"
76 #include "preferences.h"
77 #include "layer_dialog.h"
78 #include "connectionpoint_ops.h"
79 #include "undo.h"
80 #include "pagesetup.h"
81 #include "text.h"
82 #include "dia_dirs.h"
83 #include "focus.h"
84 #include <gdk/gdk.h>
85 #include <gdk/gdkkeysyms.h>
86 #include "lib/properties.h"
87 #include "lib/parent.h"
88 #include "dia-props.h"
89 #include "diagram_tree_window.h"
90 #include "authors.h"                /* master contributors data */
91 
92 void
file_quit_callback(GtkAction * action)93 file_quit_callback (GtkAction *action)
94 {
95   app_exit();
96 }
97 
98 void
file_pagesetup_callback(GtkAction * action)99 file_pagesetup_callback (GtkAction *action)
100 {
101   Diagram *dia;
102 
103   dia = ddisplay_active_diagram();
104   if (!dia) return;
105   create_page_setup_dlg(dia);
106 }
107 
108 void
file_print_callback(GtkAction * _action)109 file_print_callback (GtkAction *_action)
110 {
111   Diagram *dia;
112   DDisplay *ddisp;
113   GtkAction *action;
114 
115   dia = ddisplay_active_diagram();
116   if (!dia) return;
117   ddisp = ddisplay_active();
118   if (!ddisp) return;
119 
120   action = menus_get_action ("FilePrintGTK");
121   if (!action)
122     action = menus_get_action ("FilePrintGDI");
123   if (!action)
124     action = menus_get_action ("FilePrintPS");
125 
126   if (action) {
127     if (confirm_export_size (dia, GTK_WINDOW(ddisp->shell), CONFIRM_PRINT|CONFIRM_PAGES))
128       gtk_action_activate (action);
129   } else {
130     message_error (_("No print plug-in found!"));
131   }
132 }
133 
134 void
file_close_callback(GtkAction * action)135 file_close_callback (GtkAction *action)
136 {
137   /* some people use tear-off menus and insist to close non existing displays */
138   if (ddisplay_active())
139     ddisplay_close(ddisplay_active());
140 }
141 
142 void
file_new_callback(GtkAction * action)143 file_new_callback (GtkAction *action)
144 {
145   Diagram *dia;
146   DDisplay *ddisp;
147   static int untitled_nr = 1;
148   gchar *name, *filename;
149 
150   name = g_strdup_printf(_("Diagram%d.dia"), untitled_nr++);
151   filename = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
152   dia = new_diagram(filename);
153   ddisp = new_display(dia);
154   diagram_tree_add(diagram_tree(), dia);
155   g_free (name);
156   g_free (filename);
157 }
158 
159 void
file_preferences_callback(GtkAction * action)160 file_preferences_callback (GtkAction *action)
161 {
162   prefs_show();
163 }
164 
165 
166 
167 /* Signal handler for getting the clipboard contents */
168 /* Note that the clipboard is for M$-style cut/copy/paste copying, while
169    the selection is for Unix-style mark-and-copy.  We can't really do
170    mark-and-copy.
171 */
172 
173 static void
insert_text(DDisplay * ddisp,Focus * focus,const gchar * text)174 insert_text(DDisplay *ddisp, Focus *focus, const gchar *text)
175 {
176   ObjectChange *change = NULL;
177   int modified = FALSE, any_modified = FALSE;
178   DiaObject *obj = focus_get_object(focus);
179 
180   while (text != NULL) {
181     gchar *next_line = g_utf8_strchr(text, -1, '\n');
182     if (next_line != text) {
183       gint len = g_utf8_strlen(text, (next_line-text));
184       modified = (*focus->key_event)(focus, GDK_A, text, len, &change);
185     }
186     if (next_line != NULL) {
187       modified = (*focus->key_event)(focus, GDK_Return, "\n", 1, &change);
188       text = g_utf8_next_char(next_line);
189     } else {
190       text = NULL;
191     }
192     { /* Make sure object updates its data: */
193       Point p = obj->position;
194       (obj->ops->move)(obj,&p);  }
195 
196     /* Perhaps this can be improved */
197     object_add_updates(obj, ddisp->diagram);
198 
199     if (modified && (change != NULL)) {
200       undo_object_change(ddisp->diagram, obj, change);
201       any_modified = TRUE;
202     }
203 
204     diagram_flush(ddisp->diagram);
205   }
206 
207   if (any_modified) {
208     diagram_modified(ddisp->diagram);
209     diagram_update_extents(ddisp->diagram);
210     undo_set_transactionpoint(ddisp->diagram->undo);
211   }
212 }
213 
214 
215 static void
received_clipboard_handler(GtkClipboard * clipboard,const gchar * text,gpointer data)216 received_clipboard_handler(GtkClipboard *clipboard,
217 			   const gchar *text,
218 			   gpointer data) {
219   DDisplay *ddisp = (DDisplay *)data;
220   Focus *focus = get_active_focus((DiagramData *) ddisp->diagram);
221 
222   if (text == NULL) return;
223 
224   if ((focus == NULL) || (!focus->has_focus)) return;
225 
226   if (!g_utf8_validate(text, -1, NULL)) {
227     message_error("Not valid UTF8");
228     return;
229   }
230 
231   insert_text(ddisp, focus, text);
232 }
233 
234 static PropDescription text_prop_singleton_desc[] = {
235     { "text", PROP_TYPE_TEXT },
236     PROP_DESC_END};
237 
238 static void
make_text_prop_singleton(GPtrArray ** props,TextProperty ** prop)239 make_text_prop_singleton(GPtrArray **props, TextProperty **prop)
240 {
241   *props = prop_list_from_descs(text_prop_singleton_desc,pdtpp_true);
242   g_assert((*props)->len == 1);
243 
244   *prop = g_ptr_array_index((*props),0);
245   g_free((*prop)->text_data);
246   (*prop)->text_data = NULL;
247 }
248 
249 
250 void
edit_copy_callback(GtkAction * action)251 edit_copy_callback (GtkAction *action)
252 {
253   GList *copy_list;
254   DDisplay *ddisp;
255 
256   ddisp = ddisplay_active();
257   if (!ddisp) return;
258   if (textedit_mode(ddisp)) {
259     Focus *focus = get_active_focus((DiagramData *) ddisp->diagram);
260     DiaObject *obj = focus_get_object(focus);
261     GPtrArray *textprops;
262     TextProperty *prop;
263 
264     if (obj->ops->get_props == NULL)
265       return;
266 
267     make_text_prop_singleton(&textprops,&prop);
268     /* Get the first text property */
269     obj->ops->get_props(obj, textprops);
270 
271     /* GTK docs claim the selection clipboard is ignored on Win32.
272      * The "clipboard" clipboard is mostly ignored in Unix
273      */
274 #ifdef G_OS_WIN32
275     gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
276 			   prop->text_data, -1);
277 #else
278     gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
279 			   prop->text_data, -1);
280 #endif
281     prop_list_free(textprops);
282   } else {
283     copy_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
284 
285     cnp_store_objects(object_copy_list(copy_list), 1);
286     g_list_free(copy_list);
287 
288     ddisplay_do_update_menu_sensitivity(ddisp);
289   }
290 }
291 
292 void
edit_cut_callback(GtkAction * action)293 edit_cut_callback (GtkAction *action)
294 {
295   GList *cut_list;
296   DDisplay *ddisp;
297   Change *change;
298 
299   ddisp = ddisplay_active();
300   if (!ddisp) return;
301 
302   if (textedit_mode(ddisp)) {
303   } else {
304     diagram_selected_break_external(ddisp->diagram);
305 
306     cut_list = parent_list_affected(diagram_get_sorted_selected(ddisp->diagram));
307 
308     cnp_store_objects(object_copy_list(cut_list), 0);
309 
310     change = undo_delete_objects_children(ddisp->diagram, cut_list);
311     (change->apply)(change, ddisp->diagram);
312 
313     ddisplay_do_update_menu_sensitivity(ddisp);
314     diagram_flush(ddisp->diagram);
315 
316     diagram_modified(ddisp->diagram);
317     diagram_update_extents(ddisp->diagram);
318     undo_set_transactionpoint(ddisp->diagram->undo);
319   }
320 }
321 
322 void
edit_paste_callback(GtkAction * action)323 edit_paste_callback (GtkAction *action)
324 {
325   GList *paste_list;
326   DDisplay *ddisp;
327   Point paste_corner;
328   Point delta;
329   Change *change;
330   int generation = 0;
331 
332   ddisp = ddisplay_active();
333   if (!ddisp) return;
334   if (textedit_mode(ddisp)) {
335 #ifdef G_OS_WIN32
336     gtk_clipboard_request_text(gtk_clipboard_get(GDK_NONE),
337 			       received_clipboard_handler, ddisp);
338 #else
339     gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
340 			       received_clipboard_handler, ddisp);
341 #endif
342   } else {
343     if (!cnp_exist_stored_objects()) {
344       message_warning(_("No existing object to paste.\n"));
345       return;
346     }
347 
348     paste_list = cnp_get_stored_objects(&generation); /* Gets a copy */
349 
350     paste_corner = object_list_corner(paste_list);
351 
352     delta.x = ddisp->visible.left - paste_corner.x;
353     delta.y = ddisp->visible.top - paste_corner.y;
354 
355     /* Move down some 10% of the visible area. */
356     delta.x += (ddisp->visible.right - ddisp->visible.left) * 0.1 * generation;
357     delta.y += (ddisp->visible.bottom - ddisp->visible.top) * 0.1 * generation;
358 
359     if (generation)
360       object_list_move_delta(paste_list, &delta);
361 
362     change = undo_insert_objects(ddisp->diagram, paste_list, 0);
363     (change->apply)(change, ddisp->diagram);
364 
365     diagram_modified(ddisp->diagram);
366     undo_set_transactionpoint(ddisp->diagram->undo);
367 
368     diagram_remove_all_selected(ddisp->diagram, TRUE);
369     diagram_select_list(ddisp->diagram, paste_list);
370 
371     diagram_update_extents(ddisp->diagram);
372     diagram_flush(ddisp->diagram);
373   }
374 }
375 
376 /*
377  * ALAN: Paste should probably paste to different position, feels
378  * wrong somehow.  ALAN: The offset should increase a little each time
379  * if you paste/duplicate several times in a row, because it is
380  * clearer what is happening than if you were to piling them all in
381  * one place.
382  *
383  * completely untested, basically it is copy+paste munged together
384  */
385 void
edit_duplicate_callback(GtkAction * action)386 edit_duplicate_callback (GtkAction *action)
387 {
388   GList *duplicate_list;
389   DDisplay *ddisp;
390   Point duplicate_corner;
391   Point delta;
392   Change *change;
393 
394   ddisp = ddisplay_active();
395   if (!ddisp || textedit_mode(ddisp)) return;
396   duplicate_list = object_copy_list(diagram_get_sorted_selected(ddisp->diagram));
397   duplicate_corner = object_list_corner(duplicate_list);
398 
399   /* Move down some 10% of the visible area. */
400   delta.x = (ddisp->visible.right - ddisp->visible.left)*0.05;
401   delta.y = (ddisp->visible.bottom - ddisp->visible.top)*0.05;
402 
403   object_list_move_delta(duplicate_list, &delta);
404 
405   change = undo_insert_objects(ddisp->diagram, duplicate_list, 0);
406   (change->apply)(change, ddisp->diagram);
407 
408   diagram_modified(ddisp->diagram);
409   undo_set_transactionpoint(ddisp->diagram->undo);
410 
411   diagram_remove_all_selected(ddisp->diagram, TRUE);
412   diagram_select_list(ddisp->diagram, duplicate_list);
413 
414   diagram_flush(ddisp->diagram);
415 
416   ddisplay_do_update_menu_sensitivity(ddisp);
417 }
418 
419 void
objects_move_up_layer(GtkAction * action)420 objects_move_up_layer(GtkAction *action)
421 {
422   DDisplay *ddisp = ddisplay_active();
423   GList *selected_list;
424   Change *change;
425 
426   if (!ddisp || textedit_mode(ddisp)) return;
427   selected_list = diagram_get_sorted_selected(ddisp->diagram);
428 
429   change = undo_move_object_other_layer(ddisp->diagram, selected_list, TRUE);
430 
431   (change->apply)(change, ddisp->diagram);
432 
433   diagram_modified(ddisp->diagram);
434   undo_set_transactionpoint(ddisp->diagram->undo);
435 
436   diagram_flush(ddisp->diagram);
437 
438   ddisplay_do_update_menu_sensitivity(ddisp);
439 }
440 
441  void
objects_move_down_layer(GtkAction * action)442 objects_move_down_layer(GtkAction *action)
443 {
444   DDisplay *ddisp = ddisplay_active();
445   GList *selected_list;
446   Change *change;
447 
448   if (!ddisp || textedit_mode(ddisp)) return;
449   selected_list = diagram_get_sorted_selected(ddisp->diagram);
450 
451   /* Must check if move is legal here */
452 
453   change = undo_move_object_other_layer(ddisp->diagram, selected_list, FALSE);
454 
455   (change->apply)(change, ddisp->diagram);
456 
457   diagram_modified(ddisp->diagram);
458   undo_set_transactionpoint(ddisp->diagram->undo);
459 
460   diagram_flush(ddisp->diagram);
461 
462   ddisplay_do_update_menu_sensitivity(ddisp);
463 }
464 
465 void
edit_copy_text_callback(GtkAction * action)466 edit_copy_text_callback (GtkAction *action)
467 {
468   Focus *focus;
469   DDisplay *ddisp = ddisplay_active();
470   DiaObject *obj;
471   GPtrArray *textprops;
472   TextProperty *prop;
473 
474   if (ddisp == NULL) return;
475 
476   focus = get_active_focus((DiagramData *) ddisp->diagram);
477 
478   if ((focus == NULL) || (!focus->has_focus)) return;
479 
480   obj = focus_get_object(focus);
481 
482   if (obj->ops->get_props == NULL)
483     return;
484 
485   make_text_prop_singleton(&textprops,&prop);
486   /* Get the first text property */
487   obj->ops->get_props(obj, textprops);
488 
489   /* GTK docs claim the selection clipboard is ignored on Win32.
490    * The "clipboard" clipboard is mostly ignored in Unix
491    */
492 #ifdef G_OS_WIN32
493   gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
494 			 prop->text_data, -1);
495 #else
496   gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
497 			 prop->text_data, -1);
498 #endif
499   prop_list_free(textprops);
500 }
501 
502 void
edit_cut_text_callback(GtkAction * action)503 edit_cut_text_callback (GtkAction *action)
504 {
505   Focus *focus;
506   DDisplay *ddisp;
507   DiaObject *obj;
508   Text *text;
509   GPtrArray *textprops;
510   TextProperty *prop;
511   ObjectChange *change;
512 
513   ddisp = ddisplay_active();
514   if (!ddisp) return;
515 
516   focus = get_active_focus((DiagramData *) ddisp->diagram);
517   if ((focus == NULL) || (!focus->has_focus)) return;
518 
519   obj = focus_get_object(focus);
520   text = (Text*)focus->user_data;
521 
522   if (obj->ops->get_props == NULL)
523     return;
524 
525   make_text_prop_singleton(&textprops,&prop);
526   /* Get the first text property */
527   obj->ops->get_props(obj, textprops);
528 
529   /* GTK docs claim the selection clipboard is ignored on Win32.
530    * The "clipboard" clipboard is mostly ignored in Unix
531    */
532 #ifdef G_OS_WIN32
533   gtk_clipboard_set_text(gtk_clipboard_get(GDK_NONE),
534 			 prop->text_data, -1);
535 #else
536   gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
537 			 prop->text_data, -1);
538 #endif
539 
540   prop_list_free(textprops);
541 
542   if (text_delete_all(text, &change)) {
543     object_add_updates(obj, ddisp->diagram);
544     undo_object_change(ddisp->diagram, obj, change);
545     undo_set_transactionpoint(ddisp->diagram->undo);
546     diagram_modified(ddisp->diagram);
547     diagram_flush(ddisp->diagram);
548   }
549 }
550 
551 void
edit_paste_text_callback(GtkAction * action)552 edit_paste_text_callback (GtkAction *action)
553 {
554   DDisplay *ddisp;
555 
556   ddisp = ddisplay_active();
557   if (!ddisp) return;
558 
559 #ifdef G_OS_WIN32
560   gtk_clipboard_request_text(gtk_clipboard_get(GDK_NONE),
561 			     received_clipboard_handler, ddisp);
562 #else
563   gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
564 			     received_clipboard_handler, ddisp);
565 #endif
566 }
567 
568 void
edit_delete_callback(GtkAction * action)569 edit_delete_callback (GtkAction *action)
570 {
571   GList *delete_list;
572   DDisplay *ddisp;
573 
574   /* Avoid crashing while moving or resizing and deleting ... */
575   if (gdk_pointer_is_grabbed ()) {
576     gdk_beep ();    /* ... no matter how much sense it makes. */
577     return;
578   }
579 
580   ddisp = ddisplay_active();
581   if (!ddisp) return;
582   if (textedit_mode(ddisp)) {
583     ObjectChange *change = NULL;
584     Focus *focus = get_active_focus((DiagramData *) ddisp->diagram);
585     if (!text_delete_key_handler(focus, &change)) {
586       return;
587     }
588     object_add_updates(focus->obj, ddisp->diagram);
589   } else {
590     Change *change = NULL;
591     diagram_selected_break_external(ddisp->diagram);
592 
593     delete_list = diagram_get_sorted_selected(ddisp->diagram);
594     change = undo_delete_objects_children(ddisp->diagram, delete_list);
595     g_list_free(delete_list);
596     (change->apply)(change, ddisp->diagram);
597   }
598   diagram_modified(ddisp->diagram);
599   diagram_update_extents(ddisp->diagram);
600 
601   ddisplay_do_update_menu_sensitivity(ddisp);
602   diagram_flush(ddisp->diagram);
603 
604   undo_set_transactionpoint(ddisp->diagram->undo);
605 }
606 
607 void
edit_undo_callback(GtkAction * action)608 edit_undo_callback (GtkAction *action)
609 {
610   Diagram *dia;
611 
612   dia = ddisplay_active_diagram();
613   if (!dia) return;
614 
615 /* Handle text undo edit here! */
616   undo_revert_to_last_tp(dia->undo);
617   diagram_modified(dia);
618   diagram_update_extents(dia);
619 
620   diagram_flush(dia);
621 }
622 
623 void
edit_redo_callback(GtkAction * action)624 edit_redo_callback (GtkAction *action)
625 {
626   Diagram *dia;
627 
628 /* Handle text undo edit here! */
629   dia = ddisplay_active_diagram();
630   if (!dia) return;
631 
632   undo_apply_to_next_tp(dia->undo);
633   diagram_modified(dia);
634   diagram_update_extents(dia);
635 
636   diagram_flush(dia);
637 }
638 
639 void
help_manual_callback(GtkAction * action)640 help_manual_callback (GtkAction *action)
641 {
642 #ifdef GNOME
643   gnome_help_display("dia", NULL, NULL);
644 #else
645   char *helpdir, *helpindex = NULL, *command;
646   guint bestscore = G_MAXINT;
647   GDir *dp;
648   const char *dentry;
649   GError *error = NULL;
650 
651   helpdir = dia_get_data_directory("help");
652   if (!helpdir) {
653     message_warning(_("Could not find help directory"));
654     return;
655   }
656 
657   /* search through helpdir for the helpfile that matches the user's locale */
658   dp = g_dir_open (helpdir, 0, &error);
659   if (!dp) {
660     message_warning(_("Could not open help directory:\n%s"),
661                     error->message);
662     g_error_free (error);
663     return;
664   }
665 
666   while ((dentry = g_dir_read_name(dp)) != NULL) {
667     guint score;
668 
669     score = intl_score_locale(dentry);
670     if (score < bestscore) {
671       if (helpindex)
672 	g_free(helpindex);
673 #ifdef G_OS_WIN32
674       /* use HTML Help on win32 if available */
675       helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
676 			      G_DIR_SEPARATOR_S "dia-manual.chm", NULL);
677       if (!g_file_test(helpindex, G_FILE_TEST_EXISTS)) {
678 	helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
679 			      G_DIR_SEPARATOR_S "index.html", NULL);
680       }
681 #else
682       helpindex = g_strconcat(helpdir, G_DIR_SEPARATOR_S, dentry,
683 			      G_DIR_SEPARATOR_S "index.html", NULL);
684 #endif
685       bestscore = score;
686     }
687   }
688   g_dir_close (dp);
689   g_free(helpdir);
690   if (!helpindex) {
691     message_warning(_("Could not find help directory"));
692     return;
693   }
694 
695 #ifdef G_OS_WIN32
696 # define SW_SHOWNORMAL 1
697   ShellExecuteA (0, "open", helpindex, NULL, helpdir, SW_SHOWNORMAL);
698 #else
699   command = getenv("BROWSER");
700   command = g_strdup_printf("%s 'file://%s' &", command ? command : "xdg-open", helpindex);
701   system(command);
702   g_free(command);
703 #endif
704 
705   g_free(helpindex);
706 #endif
707 }
708 
709 static void
activate_url(GtkAboutDialog * about,const gchar * link,gpointer data)710 activate_url (GtkAboutDialog *about,
711               const gchar    *link,
712 	      gpointer        data)
713 {
714 #ifdef G_OS_WIN32
715   ShellExecuteA (0, "open", link, NULL, NULL, SW_SHOWNORMAL);
716 #else
717   gchar *command = getenv("BROWSER");
718   command = g_strdup_printf("%s '%s' &", command ? command : "xdg-open", link);
719   system(command);
720   g_free(command);
721 #endif
722 }
723 
724 void
help_about_callback(GtkAction * action)725 help_about_callback (GtkAction *action)
726 {
727   const gchar *translators = _("translator_credits-PLEASE_ADD_YOURSELF_HERE");
728   const gchar *license = _(
729 	"This program is free software; you can redistribute it and/or modify\n"
730 	"it under the terms of the GNU General Public License as published by\n"
731 	"the Free Software Foundation; either version 2 of the License, or\n"
732 	"(at your option) any later version.\n"
733 	"\n"
734 	"This program is distributed in the hope that it will be useful,\n"
735 	"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
736 	"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
737 	"GNU General Public License for more details.\n"
738 	"\n"
739 	"You should have received a copy of the GNU General Public License\n"
740 	"along with this program; if not, write to the Free Software\n"
741 	"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
742 
743   gchar *dirname = dia_get_data_directory("");
744   gchar *filename = g_build_filename (dirname, "dia-splash.png", NULL);
745   GdkPixbuf *logo = gdk_pixbuf_new_from_file(filename, NULL);
746 
747   gtk_about_dialog_set_url_hook (activate_url, NULL, NULL);
748   gtk_show_about_dialog (NULL,
749 	"logo", logo,
750         "name", "Dia",
751 	"version", VERSION,
752 	"comments", _("A program for drawing structured diagrams."),
753 	"copyright", "(C) 1998-2009 The Free Software Foundation and the authors",
754 	"website", "http://live.gnome.org/Dia",
755 	"authors", authors,
756 	"documenters", documentors,
757 	"translator-credits", strcmp (translators, "translator_credits-PLEASE_ADD_YOURSELF_HERE")
758 			? translators : NULL,
759 	"license", license,
760 	NULL);
761   g_free (dirname);
762   g_free (filename);
763   if (logo)
764     g_object_unref (logo);
765 }
766 
767 void
view_zoom_in_callback(GtkAction * action)768 view_zoom_in_callback (GtkAction *action)
769 {
770   DDisplay *ddisp;
771   Point middle;
772   Rectangle *visible;
773 
774   ddisp = ddisplay_active();
775   if (!ddisp) return;
776   visible = &ddisp->visible;
777   middle.x = visible->left*0.5 + visible->right*0.5;
778   middle.y = visible->top*0.5 + visible->bottom*0.5;
779 
780   ddisplay_zoom(ddisp, &middle, M_SQRT2);
781 }
782 
783 void
view_zoom_out_callback(GtkAction * action)784 view_zoom_out_callback (GtkAction *action)
785 {
786   DDisplay *ddisp;
787   Point middle;
788   Rectangle *visible;
789 
790   ddisp = ddisplay_active();
791   if (!ddisp) return;
792   visible = &ddisp->visible;
793   middle.x = visible->left*0.5 + visible->right*0.5;
794   middle.y = visible->top*0.5 + visible->bottom*0.5;
795 
796   ddisplay_zoom(ddisp, &middle, M_SQRT1_2);
797 }
798 
799 void
view_zoom_set_callback(GtkAction * action)800 view_zoom_set_callback (GtkAction *action)
801 {
802   int factor;
803   /* HACK the actual factor is a suffix to the action name */
804   factor = atoi (gtk_action_get_name (action) + strlen ("ViewZoom"));
805   view_zoom_set (factor);
806 }
807 
808 void
view_show_cx_pts_callback(GtkToggleAction * action)809 view_show_cx_pts_callback (GtkToggleAction *action)
810 {
811   DDisplay *ddisp;
812   int old_val;
813 
814   ddisp = ddisplay_active();
815   if (!ddisp) return;
816 
817   old_val = ddisp->show_cx_pts;
818   ddisp->show_cx_pts = gtk_toggle_action_get_active (action);
819 
820   if (old_val != ddisp->show_cx_pts) {
821     ddisplay_add_update_all(ddisp);
822     ddisplay_flush(ddisp);
823   }
824 }
825 
826 void
view_unfullscreen(void)827 view_unfullscreen (void)
828 {
829   DDisplay *ddisp;
830   GtkToggleAction *item;
831 
832   ddisp = ddisplay_active();
833   if (!ddisp) return;
834 
835   /* find the menuitem */
836   item = GTK_TOGGLE_ACTION (menus_get_action ("ViewFullscreen"));
837   if (item && gtk_toggle_action_get_active (item)) {
838     gtk_toggle_action_set_active (item, FALSE);
839   }
840 }
841 
842 void
view_fullscreen_callback(GtkToggleAction * action)843 view_fullscreen_callback (GtkToggleAction *action)
844 {
845   DDisplay *ddisp;
846   int fs;
847 
848   ddisp = ddisplay_active();
849   if (!ddisp) return;
850 
851   fs = gtk_toggle_action_get_active (action);
852 
853   if (fs) /* it is already toggled */
854     gtk_window_fullscreen(GTK_WINDOW(ddisp->shell));
855   else
856     gtk_window_unfullscreen(GTK_WINDOW(ddisp->shell));
857 }
858 
859 void
view_aa_callback(GtkToggleAction * action)860 view_aa_callback (GtkToggleAction *action)
861 {
862   DDisplay *ddisp;
863   int aa;
864 
865   ddisp = ddisplay_active();
866   if (!ddisp) return;
867 
868   aa = gtk_toggle_action_get_active (action);
869 
870   if (aa != ddisp->aa_renderer) {
871     ddisplay_set_renderer(ddisp, aa);
872     ddisplay_add_update_all(ddisp);
873     ddisplay_flush(ddisp);
874   }
875 }
876 
877 void
view_visible_grid_callback(GtkToggleAction * action)878 view_visible_grid_callback (GtkToggleAction *action)
879 {
880   DDisplay *ddisp;
881   guint old_val;
882 
883   ddisp = ddisplay_active();
884   if (!ddisp) return;
885 
886   old_val = ddisp->grid.visible;
887   ddisp->grid.visible = gtk_toggle_action_get_active (action);
888 
889   if (old_val != ddisp->grid.visible) {
890     ddisplay_add_update_all(ddisp);
891     ddisplay_flush(ddisp);
892   }
893 }
894 
895 void
view_snap_to_grid_callback(GtkToggleAction * action)896 view_snap_to_grid_callback (GtkToggleAction *action)
897 {
898   DDisplay *ddisp;
899 
900   ddisp = ddisplay_active();
901   if (!ddisp) return;
902 
903   ddisplay_set_snap_to_grid(ddisp, gtk_toggle_action_get_active (action));
904 }
905 
906 void
view_snap_to_objects_callback(GtkToggleAction * action)907 view_snap_to_objects_callback (GtkToggleAction *action)
908 {
909   DDisplay *ddisp;
910 
911   ddisp = ddisplay_active();
912   if (!ddisp) return;
913 
914   ddisplay_set_snap_to_objects(ddisp, gtk_toggle_action_get_active (action));
915 }
916 
917 void
view_toggle_rulers_callback(GtkToggleAction * action)918 view_toggle_rulers_callback (GtkToggleAction *action)
919 {
920   DDisplay *ddisp;
921 
922   ddisp = ddisplay_active();
923   if (!ddisp) return;
924 
925   if (!gtk_toggle_action_get_active (action)) {
926     if (display_get_rulers_showing(ddisp)) {
927       display_rulers_hide (ddisp);
928     }
929   } else {
930     if (!display_get_rulers_showing(ddisp)) {
931       display_rulers_show (ddisp);
932     }
933   }
934 }
935 
936 extern void
view_new_view_callback(GtkAction * action)937 view_new_view_callback (GtkAction *action)
938 {
939   Diagram *dia;
940 
941   dia = ddisplay_active_diagram();
942   if (!dia) return;
943 
944   new_display(dia);
945 }
946 
947 extern void
view_clone_view_callback(GtkAction * action)948 view_clone_view_callback (GtkAction *action)
949 {
950   DDisplay *ddisp;
951 
952   ddisp = ddisplay_active();
953   if (!ddisp) return;
954 
955   copy_display(ddisp);
956 }
957 
958 void
view_show_all_callback(GtkAction * action)959 view_show_all_callback (GtkAction *action)
960 {
961   DDisplay *ddisp;
962 
963   ddisp = ddisplay_active();
964   if (!ddisp) return;
965 
966   ddisplay_show_all (ddisp);
967 }
968 
969 void
view_redraw_callback(GtkAction * action)970 view_redraw_callback (GtkAction *action)
971 {
972   DDisplay *ddisp;
973   ddisp = ddisplay_active();
974   if (!ddisp) return;
975   ddisplay_add_update_all(ddisp);
976   ddisplay_flush(ddisp);
977 }
978 
979 void
view_diagram_properties_callback(GtkAction * action)980 view_diagram_properties_callback (GtkAction *action)
981 {
982   DDisplay *ddisp;
983 
984   ddisp = ddisplay_active();
985   if (!ddisp) return;
986   diagram_properties_show(ddisp->diagram);
987 }
988 
989 void
view_main_toolbar_callback(GtkAction * action)990 view_main_toolbar_callback (GtkAction *action)
991 {
992   if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(action)) == TRUE)
993   {
994     integrated_ui_main_toolbar_show ();
995   }
996   else
997   {
998     integrated_ui_main_toolbar_hide ();
999   }
1000 }
1001 
1002 void
view_main_statusbar_callback(GtkAction * action)1003 view_main_statusbar_callback (GtkAction *action)
1004 {
1005   if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(action)) == TRUE)
1006   {
1007     integrated_ui_main_statusbar_show ();
1008   }
1009   else
1010   {
1011     integrated_ui_main_statusbar_hide ();
1012   }
1013 }
1014 
1015 void
view_layers_callback(GtkAction * action)1016 view_layers_callback (GtkAction *action)
1017 {
1018   if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(action)) == TRUE)
1019   {
1020     integrated_ui_layer_view_show ();
1021   }
1022   else
1023   {
1024     integrated_ui_layer_view_hide ();
1025   }
1026 }
1027 
1028 void
layers_add_layer_callback(GtkAction * action)1029 layers_add_layer_callback (GtkAction *action)
1030 {
1031   Diagram *dia;
1032 
1033   dia = ddisplay_active_diagram();
1034   if (!dia) return;
1035 
1036   diagram_edit_layer (dia, NULL);
1037 }
1038 
1039 void
layers_rename_layer_callback(GtkAction * action)1040 layers_rename_layer_callback (GtkAction *action)
1041 {
1042   Diagram *dia;
1043 
1044   dia = ddisplay_active_diagram();
1045   if (!dia) return;
1046 
1047   diagram_edit_layer (dia, dia->data->active_layer);
1048 }
1049 
1050 void
objects_place_over_callback(GtkAction * action)1051 objects_place_over_callback (GtkAction *action)
1052 {
1053   diagram_place_over_selected(ddisplay_active_diagram());
1054 }
1055 
1056 void
objects_place_under_callback(GtkAction * action)1057 objects_place_under_callback (GtkAction *action)
1058 {
1059   diagram_place_under_selected(ddisplay_active_diagram());
1060 }
1061 
1062 void
objects_place_up_callback(GtkAction * action)1063 objects_place_up_callback (GtkAction *action)
1064 {
1065   diagram_place_up_selected(ddisplay_active_diagram());
1066 }
1067 
1068 void
objects_place_down_callback(GtkAction * action)1069 objects_place_down_callback (GtkAction *action)
1070 {
1071   DDisplay *ddisp = ddisplay_active();
1072   if (!ddisp || textedit_mode(ddisp)) return;
1073 
1074   diagram_place_down_selected(ddisplay_active_diagram());
1075 }
1076 
1077 void
objects_parent_callback(GtkAction * action)1078 objects_parent_callback (GtkAction *action)
1079 {
1080   DDisplay *ddisp = ddisplay_active();
1081   if (!ddisp || textedit_mode(ddisp)) return;
1082 
1083   diagram_parent_selected(ddisplay_active_diagram());
1084 }
1085 
1086 void
objects_unparent_callback(GtkAction * action)1087 objects_unparent_callback (GtkAction *action)
1088 {
1089   DDisplay *ddisp = ddisplay_active();
1090   if (!ddisp || textedit_mode(ddisp)) return;
1091 
1092   diagram_unparent_selected(ddisplay_active_diagram());
1093 }
1094 
1095 void
objects_unparent_children_callback(GtkAction * action)1096 objects_unparent_children_callback (GtkAction *action)
1097 {
1098   DDisplay *ddisp = ddisplay_active();
1099   if (!ddisp || textedit_mode(ddisp)) return;
1100 
1101   diagram_unparent_children_selected(ddisplay_active_diagram());
1102 }
1103 
1104 void
objects_group_callback(GtkAction * action)1105 objects_group_callback (GtkAction *action)
1106 {
1107   DDisplay *ddisp = ddisplay_active();
1108   if (!ddisp || textedit_mode(ddisp)) return;
1109 
1110   diagram_group_selected(ddisplay_active_diagram());
1111   ddisplay_do_update_menu_sensitivity(ddisp);
1112 }
1113 
1114 void
objects_ungroup_callback(GtkAction * action)1115 objects_ungroup_callback (GtkAction *action)
1116 {
1117   DDisplay *ddisp = ddisplay_active();
1118   if (!ddisp || textedit_mode(ddisp)) return;
1119 
1120   diagram_ungroup_selected(ddisplay_active_diagram());
1121   ddisplay_do_update_menu_sensitivity(ddisp);
1122 }
1123 
1124 void
dialogs_properties_callback(GtkAction * action)1125 dialogs_properties_callback (GtkAction *action)
1126 {
1127   Diagram *dia;
1128   DiaObject *selected;
1129 
1130   dia = ddisplay_active_diagram();
1131   if (!dia || textedit_mode(ddisplay_active())) return;
1132 
1133   if (dia->data->selected != NULL) {
1134     object_list_properties_show(dia, dia->data->selected);
1135   } else {
1136     diagram_properties_show(dia);
1137   }
1138 }
1139 
1140 void
dialogs_layers_callback(GtkAction * action)1141 dialogs_layers_callback (GtkAction *action)
1142 {
1143   layer_dialog_set_diagram(ddisplay_active_diagram());
1144   layer_dialog_show();
1145 }
1146 
1147 
1148 void
objects_align_h_callback(GtkAction * action)1149 objects_align_h_callback (GtkAction *action)
1150 {
1151   const gchar *a;
1152   int align = DIA_ALIGN_LEFT;
1153   Diagram *dia;
1154   GList *objects;
1155 
1156   DDisplay *ddisp = ddisplay_active();
1157   if (!ddisp || textedit_mode(ddisp)) return;
1158 
1159   /* HACK align is suffix to action name */
1160   a = gtk_action_get_name (action) + strlen ("ObjectsAlign");
1161   if (0 == strcmp ("Left", a)) {
1162 	align = DIA_ALIGN_LEFT;
1163   }
1164   else if (0 == strcmp ("Center", a)) {
1165 	align = DIA_ALIGN_CENTER;
1166   }
1167   else if (0 == strcmp ("Right", a)) {
1168 	align = DIA_ALIGN_RIGHT;
1169   }
1170   else if (0 == strcmp ("Spreadouthorizontally", a)) {
1171 	align = DIA_ALIGN_EQUAL;
1172   }
1173   else if (0 == strcmp ("Adjacent", a)) {
1174 	align = DIA_ALIGN_ADJACENT;
1175   }
1176   else {
1177 	g_warning ("objects_align_v_callback() called without appropriate align");
1178 	return;
1179   }
1180 
1181   dia = ddisplay_active_diagram();
1182   if (!dia) return;
1183   objects = dia->data->selected;
1184 
1185   object_add_updates_list(objects, dia);
1186   object_list_align_h(objects, dia, align);
1187   diagram_update_connections_selection(dia);
1188   object_add_updates_list(objects, dia);
1189   diagram_modified(dia);
1190   diagram_flush(dia);
1191 
1192   undo_set_transactionpoint(dia->undo);
1193 }
1194 
1195 void
objects_align_v_callback(GtkAction * action)1196 objects_align_v_callback (GtkAction *action)
1197 {
1198   const gchar *a;
1199   int align;
1200   Diagram *dia;
1201   GList *objects;
1202 
1203   DDisplay *ddisp = ddisplay_active();
1204   if (!ddisp || textedit_mode(ddisp)) return;
1205 
1206   /* HACK align is suffix to action name */
1207   a = gtk_action_get_name (action) + strlen ("ObjectsAlign");
1208   if (0 == strcmp ("Top", a)) {
1209 	align = DIA_ALIGN_TOP;
1210   }
1211   else if (0 == strcmp ("Middle", a)) {
1212 	align = DIA_ALIGN_CENTER;
1213   }
1214   else if (0 == strcmp ("Bottom", a)) {
1215 	align = DIA_ALIGN_BOTTOM;
1216   }
1217   else if (0 == strcmp ("Spreadoutvertically", a)) {
1218 	align = DIA_ALIGN_EQUAL;
1219   }
1220   else if (0 == strcmp ("Stacked", a)) {
1221 	align = DIA_ALIGN_ADJACENT;
1222   }
1223   else {
1224 	g_warning ("objects_align_v_callback() called without appropriate align");
1225 	return;
1226   }
1227 
1228   dia = ddisplay_active_diagram();
1229   if (!dia) return;
1230   objects = dia->data->selected;
1231 
1232   object_add_updates_list(objects, dia);
1233   object_list_align_v(objects, dia, align);
1234   diagram_update_connections_selection(dia);
1235   object_add_updates_list(objects, dia);
1236   diagram_modified(dia);
1237   diagram_flush(dia);
1238 
1239   undo_set_transactionpoint(dia->undo);
1240 }
1241 
1242 
1243