1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include <config.h>
20 
21 #include <assert.h>
22 #include <string.h>
23 
24 #include "intl.h"
25 #include "diagram.h"
26 #include "object.h"
27 #include "group.h"
28 #include "object_ops.h"
29 #include "focus.h"
30 #include "message.h"
31 #include "menus.h"
32 #include "preferences.h"
33 #include "properties-dialog.h"
34 #include "cut_n_paste.h"
35 #include "layer_dialog.h"
36 #include "app_procs.h"
37 #include "dia_dirs.h"
38 #include "load_save.h"
39 #include "recent_files.h"
40 #include "diagram_tree_window.h"
41 #include "autosave.h"
42 #include "dynamic_refresh.h"
43 #include "textedit.h"
44 #include "lib/diamarshal.h"
45 #include "parent.h"
46 
47 static GList *open_diagrams = NULL;
48 
49 struct _ObjectExtent
50 {
51   DiaObject *object;
52   Rectangle extent;
53 };
54 
55 typedef struct _ObjectExtent ObjectExtent;
56 
57 static gint diagram_parent_sort_cb(gconstpointer a, gconstpointer b);
58 
59 
60 static void diagram_class_init (DiagramClass *klass);
61 static gboolean diagram_init(Diagram *obj, const char *filename);
62 static void diagram_update_for_filename(Diagram *dia);
63 
64 enum {
65   SELECTION_CHANGED,
66   REMOVED,
67   LAST_SIGNAL
68 };
69 
70 static guint diagram_signals[LAST_SIGNAL] = { 0, };
71 static gpointer parent_class = NULL;
72 
73 GType
diagram_get_type(void)74 diagram_get_type (void)
75 {
76   static GType object_type = 0;
77 
78   if (!object_type)
79     {
80       static const GTypeInfo object_info =
81       {
82         sizeof (DiagramClass),
83         (GBaseInitFunc) NULL,
84         (GBaseFinalizeFunc) NULL,
85         (GClassInitFunc) diagram_class_init,
86         NULL,           /* class_finalize */
87         NULL,           /* class_data */
88         sizeof (Diagram),
89         0,              /* n_preallocs */
90 	NULL            /* init */
91       };
92 
93       object_type = g_type_register_static (DIA_TYPE_DIAGRAM_DATA,
94                                             "Diagram",
95                                             &object_info, 0);
96     }
97 
98   return object_type;
99 }
100 
101 static void
diagram_finalize(GObject * object)102 diagram_finalize(GObject *object)
103 {
104   Diagram *dia = DIA_DIAGRAM(object);
105 
106   assert(dia->displays==NULL);
107 
108   open_diagrams = g_list_remove(open_diagrams, dia);
109   layer_dialog_update_diagram_list();
110 
111   if (dia->undo)
112     undo_destroy(dia->undo);
113   dia->undo = NULL;
114 
115   diagram_tree_remove(diagram_tree(), dia);
116 
117   diagram_cleanup_autosave(dia);
118 
119   if (dia->filename)
120     g_free(dia->filename);
121   dia->filename = NULL;
122 
123   G_OBJECT_CLASS (parent_class)->finalize (object);
124 }
125 
126 static void
_diagram_removed(Diagram * dia)127 _diagram_removed (Diagram* dia)
128 {
129 }
130 
131 static void
_diagram_selection_changed(Diagram * dia,int n)132 _diagram_selection_changed (Diagram* dia, int n)
133 {
134 }
135 
136 static void
diagram_class_init(DiagramClass * klass)137 diagram_class_init (DiagramClass *klass)
138 {
139   GObjectClass *object_class = G_OBJECT_CLASS (klass);
140 
141   parent_class = g_type_class_peek_parent (klass);
142 
143   diagram_signals[REMOVED] =
144     g_signal_new ("removed",
145 	          G_TYPE_FROM_CLASS (klass),
146 	          G_SIGNAL_RUN_FIRST,
147 	          G_STRUCT_OFFSET (DiagramClass, removed),
148 	          NULL, NULL,
149 	          dia_marshal_VOID__VOID,
150 		  G_TYPE_NONE, 0);
151 
152   diagram_signals[SELECTION_CHANGED] =
153     g_signal_new ("selection_changed",
154 	          G_TYPE_FROM_CLASS (klass),
155 	          G_SIGNAL_RUN_FIRST,
156 	          G_STRUCT_OFFSET (DiagramClass, selection_changed),
157 	          NULL, NULL,
158 	          dia_marshal_VOID__INT,
159 		  G_TYPE_NONE, 1,
160 		  G_TYPE_INT);
161 
162   klass->removed = _diagram_removed;
163   klass->selection_changed = _diagram_selection_changed;
164 
165   object_class->finalize = diagram_finalize;
166 }
167 
168 GList *
dia_open_diagrams(void)169 dia_open_diagrams(void)
170 {
171   return open_diagrams;
172 }
173 
174 /** Initializes a diagram with standard info and sets it to be called
175  * 'filename'.
176  * Returns TRUE if everything went ok, FALSE otherwise.
177  * Will return FALSE if filename is not a legal string in the current
178  * encoding.
179  */
180 static gboolean
diagram_init(Diagram * dia,const char * filename)181 diagram_init(Diagram *dia, const char *filename)
182 {
183   gchar *newfilename = NULL;
184   GError *error = NULL;
185 
186   dia->data = &dia->parent_instance; /* compatibility */
187 
188   dia->pagebreak_color = prefs.new_diagram.pagebreak_color;
189 
190   get_paper_info (&dia->data->paper, -1, &prefs.new_diagram);
191 
192   dia->grid.width_x = prefs.grid.x;
193   dia->grid.width_y = prefs.grid.y;
194   dia->grid.width_w = prefs.grid.w;
195   dia->grid.hex_size = 1.0;
196   dia->grid.colour = prefs.new_diagram.grid_color;
197   dia->grid.hex = prefs.grid.hex;
198   dia->grid.visible_x = 1;
199   dia->grid.visible_y = 1;
200   dia->grid.dynamic = prefs.grid.dynamic;
201   dia->grid.major_lines = prefs.grid.major_lines;
202 
203   dia->guides.nhguides = 0;
204   dia->guides.hguides = NULL;
205   dia->guides.nvguides = 0;
206   dia->guides.vguides = NULL;
207 
208   if (dia->filename != NULL)
209     g_free(dia->filename);
210   /* Make sure the filename is absolute */
211   if (!g_path_is_absolute(filename)) {
212     gchar *pwd = g_get_current_dir();
213 
214     newfilename = g_build_filename(pwd, filename, NULL);
215     g_free(pwd);
216     filename = newfilename;
217   }
218   /* All Diagram functions assumes filename in filesystem encoding */
219 
220   dia->filename = g_filename_to_utf8(filename, -1, NULL, NULL, &error);
221   if (error != NULL) {
222     message_error(_("Couldn't convert filename '%s' to UTF-8: %s\n"),
223 		  dia_message_filename(filename), error->message);
224     g_error_free(error);
225     dia->filename = g_strdup(_("Error"));
226     return FALSE;
227   }
228 
229   dia->unsaved = TRUE;
230   dia->mollified = FALSE;
231   dia->autosavefilename = NULL;
232 
233   if (dia->undo)
234     undo_destroy(dia->undo);
235   dia->undo = new_undo_stack(dia);
236 
237   if (!g_list_find(open_diagrams, dia))
238     open_diagrams = g_list_prepend(open_diagrams, dia);
239 
240   if (app_is_interactive())
241     layer_dialog_update_diagram_list();
242 
243   g_free(newfilename);
244   return TRUE;
245 }
246 
247 int
diagram_load_into(Diagram * diagram,const char * filename,DiaImportFilter * ifilter)248 diagram_load_into(Diagram         *diagram,
249 		  const char      *filename,
250 		  DiaImportFilter *ifilter)
251 {
252   gboolean was_default = diagram->is_default;
253   if (!ifilter)
254     ifilter = filter_guess_import_filter(filename);
255   if (!ifilter)  /* default to native format */
256     ifilter = &dia_import_filter;
257 
258   if (ifilter->import_func(filename, diagram->data, ifilter->user_data)) {
259     if (ifilter != &dia_import_filter) {
260       /* When loading non-Dia files, change filename to reflect that saving
261        * will produce a Dia file. See bug #440093 */
262       if (strcmp (diagram->filename, filename) == 0) {
263 	/* not a real load into but initial load */
264 	gchar *old_filename = g_strdup (diagram->filename);
265         gchar *suffix_offset = g_utf8_strrchr(old_filename, -1, (gunichar)'.');
266         gchar *new_filename;
267         if (suffix_offset != NULL) {
268 	  new_filename = g_strndup(old_filename, suffix_offset - old_filename);
269 	  g_free(old_filename);
270 	} else {
271 	  new_filename = old_filename;
272 	}
273         old_filename = g_strconcat(new_filename, ".dia", NULL);
274         g_free(new_filename);
275         diagram_set_filename(diagram, old_filename);
276         g_free(old_filename);
277         diagram->unsaved = TRUE;
278 	diagram_update_for_filename (diagram);
279 	diagram_modified(diagram);
280       }
281     } else {
282       /* the initial diagram should have confirmed filename  */
283       diagram->unsaved =
284 	  strcmp(filename, diagram->filename) == 0 ? FALSE : was_default;
285     }
286     diagram_set_modified(diagram, TRUE);
287     return TRUE;
288   } else
289     return FALSE;
290 }
291 
292 Diagram *
diagram_load(const char * filename,DiaImportFilter * ifilter)293 diagram_load(const char *filename, DiaImportFilter *ifilter)
294 {
295   Diagram *diagram = NULL;
296   GList *diagrams;
297   gboolean was_default = FALSE;
298 
299   for (diagrams = open_diagrams; diagrams != NULL; diagrams = g_list_next(diagrams)) {
300     Diagram *old_diagram = (Diagram*)diagrams->data;
301     if (old_diagram->is_default) {
302       diagram = old_diagram;
303       was_default = TRUE;
304       break;
305     }
306   }
307 
308   /* TODO: Make diagram not be initialized twice */
309   if (diagram == NULL) {
310     diagram = new_diagram(filename);
311   }
312   if (diagram == NULL) return NULL;
313 
314   if (   !diagram_init(diagram, filename)
315       || !diagram_load_into (diagram, filename, ifilter)) {
316     if (!was_default) /* don't kill the default diagram on import failure */
317       diagram_destroy(diagram);
318     diagram = NULL;
319   } else {
320     /* not modifying 'diagram->unsaved' the state depends on the import filter used */
321     diagram_set_modified(diagram, FALSE);
322     if (app_is_interactive()) {
323       recent_file_history_add(filename);
324       diagram_tree_add(diagram_tree(), diagram);
325     }
326   }
327 
328   if (diagram != NULL && was_default && app_is_interactive()) {
329     diagram_update_for_filename(diagram);
330     diagram->is_default = FALSE;
331     if ( g_slist_length(diagram->displays) == 1 )
332       display_set_active (diagram->displays->data);
333   }
334 
335   return diagram;
336 }
337 
338 /** Create a new diagram with the given filename.
339  * If the diagram could not be created, e.g. because the filename is not
340  * a legal string in the current encoding, return NULL.
341  */
342 Diagram *
new_diagram(const char * filename)343 new_diagram(const char *filename)  /* Note: filename is copied */
344 {
345   Diagram *dia = g_object_new(DIA_TYPE_DIAGRAM, NULL);
346 
347   if (diagram_init(dia, filename)) {
348     return dia;
349   } else {
350     g_object_unref(dia);
351     return NULL;
352   }
353 }
354 
355 void
diagram_destroy(Diagram * dia)356 diagram_destroy(Diagram *dia)
357 {
358   g_signal_emit (dia, diagram_signals[REMOVED], 0);
359   g_object_unref(dia);
360 }
361 
362 /** Returns true if we consider the diagram modified.
363  */
364 gboolean
diagram_is_modified(Diagram * dia)365 diagram_is_modified(Diagram *dia)
366 {
367   return dia->mollified || !undo_is_saved(dia->undo);
368 }
369 
370 /** We might just have change the diagrams modified status.
371  * This doesn't set the status, but merely updates the display.
372  */
373 void
diagram_modified(Diagram * dia)374 diagram_modified(Diagram *dia)
375 {
376   GSList *displays;
377   gchar *dia_name = diagram_get_name(dia);
378   gchar *extra = g_path_get_dirname (dia->filename);
379   gchar *title = g_strdup_printf ("%s%s (%s)", diagram_is_modified(dia) ? "*" : "", dia_name, extra ? extra : " ");
380 
381   g_free (dia_name);
382   g_free (extra);
383   displays = dia->displays;
384   while (displays!=NULL) {
385     DDisplay *ddisp = (DDisplay *) displays->data;
386 
387     ddisplay_set_title(ddisp, title);
388 
389     displays = g_slist_next(displays);
390   }
391   if (diagram_is_modified(dia)) {
392     dia->autosaved = FALSE;
393     dia->is_default = FALSE;
394   }
395   /*  diagram_set_modified(dia, TRUE);*/
396   g_free (title);
397 }
398 
399 /** Set this diagram explicitly modified.  This should not be called
400  * by things that change the undo stack, as those modifications are
401  * noticed through changes in the undo stack.
402  */
403 void
diagram_set_modified(Diagram * dia,int modified)404 diagram_set_modified(Diagram *dia, int modified)
405 {
406   if (dia->mollified != modified)
407   {
408     dia->mollified = modified;
409   }
410   diagram_modified(dia);
411 }
412 
413 /* ************ Functions that check for menu sensitivity ********* */
414 
415 /* Suggested optimization: The loops take a lot of the time.  Collapse them
416  * into one, have them set flags for the things that have been found true.
417  * Harder to maintain.
418  */
419 static gboolean
diagram_selected_any_groups(Diagram * dia)420 diagram_selected_any_groups(Diagram *dia) {
421   GList *selected;
422 
423   for (selected = dia->data->selected;
424        selected != NULL; selected = selected->next) {
425     DiaObject *obj = (DiaObject*)selected->data;
426     if (IS_GROUP(obj)) return TRUE;
427   }
428   return FALSE;
429 }
430 
431 static gboolean
diagram_selected_any_parents(Diagram * dia)432 diagram_selected_any_parents(Diagram *dia) {
433   GList *selected;
434 
435   for (selected = dia->data->selected;
436        selected != NULL; selected = selected->next) {
437     DiaObject *obj = (DiaObject*)selected->data;
438     if (object_flags_set(obj, DIA_OBJECT_CAN_PARENT) && obj->children != NULL)
439       return TRUE;
440   }
441   return FALSE;
442 }
443 
444 static gboolean
diagram_selected_any_children(Diagram * dia)445 diagram_selected_any_children(Diagram *dia) {
446   GList *selected;
447 
448   for (selected = dia->data->selected;
449        selected != NULL; selected = selected->next) {
450     DiaObject *obj = (DiaObject*)selected->data;
451     if (obj->parent != NULL) return TRUE;
452   }
453   return FALSE;
454 }
455 
456 /** This is slightly more complex -- must see if any non-parented objects
457  * are within a parenting object.
458  */
459 static gboolean
diagram_selected_can_parent(Diagram * dia)460 diagram_selected_can_parent(Diagram *dia) {
461   GList *selected;
462   GList *parents = NULL;
463 
464   for (selected = dia->data->selected;
465        selected != NULL; selected = selected->next) {
466     DiaObject *obj = (DiaObject*)selected->data;
467     if (object_flags_set(obj, DIA_OBJECT_CAN_PARENT)) {
468       parents = g_list_prepend(parents, obj);
469     }
470   }
471   for (selected = dia->data->selected;
472        selected != NULL; selected = selected->next) {
473     DiaObject *obj = (DiaObject*)selected->data;
474     if (obj->parent == NULL) {
475       GList *parent_tmp;
476       for (parent_tmp = parents; parent_tmp != NULL; parent_tmp = parent_tmp->next) {
477 	if (object_within_parent(obj, (DiaObject*)parent_tmp->data)) {
478 	  g_list_free(parents);
479 	  return TRUE;
480 	}
481       }
482     }
483   }
484   g_list_free(parents);
485   return FALSE;
486 }
487 
488 /** Returns TRUE if an object is fully enclosed by a another object, which
489  * can be a parent */
490 gboolean
object_within_parent(DiaObject * obj,DiaObject * p)491 object_within_parent(DiaObject *obj, DiaObject *p)
492 {
493   Rectangle obj_bb = obj->bounding_box;
494   if (!object_flags_set(p, DIA_OBJECT_CAN_PARENT))
495     return FALSE;
496   if (p == obj)
497     return FALSE;
498   if (obj_bb.left > p->bounding_box.left &&
499       obj_bb.right < p->bounding_box.right &&
500       obj_bb.top > p->bounding_box.top &&
501       obj_bb.bottom < p->bounding_box.bottom)
502     return TRUE;
503   return FALSE;
504 }
505 
506 /*
507   This is the real implementation of the sensitivity update.
508   TODO: move it to the DDisplay as it belongs to it IMHO
509  */
510 void
diagram_update_menu_sensitivity(Diagram * dia)511 diagram_update_menu_sensitivity (Diagram *dia)
512 {
513   gint selected_count = g_list_length (dia->data->selected);
514   DDisplay *ddisp = ddisplay_active();
515   gboolean focus_active = (get_active_focus(dia->data) != NULL);
516   gboolean textedit_active = ddisp ? textedit_mode(ddisp) : FALSE;
517   GtkAction *action;
518 
519   /* Edit menu */
520   if ((action = menus_get_action ("EditUndo")) != NULL)
521     gtk_action_set_sensitive (action, dia ? undo_available(dia->undo, TRUE) : FALSE);
522   if ((action = menus_get_action ("EditRedo")) != NULL)
523     gtk_action_set_sensitive (action, dia ? undo_available(dia->undo, FALSE) : FALSE);
524   if ((action = menus_get_action ("EditCopy")) != NULL)
525     gtk_action_set_sensitive (action, textedit_active || selected_count > 0);
526   if ((action = menus_get_action ("EditCut")) != NULL)
527     gtk_action_set_sensitive (action, textedit_mode(ddisp) || selected_count > 0);
528   if ((action = menus_get_action ("EditPaste")) != NULL)
529     gtk_action_set_sensitive (action, textedit_active || cnp_exist_stored_objects());
530   if ((action = menus_get_action ("EditDelete")) != NULL)
531     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
532   if ((action = menus_get_action ("EditDuplicate")) != NULL)
533     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
534 
535   if ((action = menus_get_action ("EditCopytext")) != NULL)
536     gtk_action_set_sensitive (action, focus_active);
537   if ((action = menus_get_action ("EditCuttext")) != NULL)
538     gtk_action_set_sensitive (action, focus_active);
539   if ((action = menus_get_action ("EditPastetext")) != NULL)
540     gtk_action_set_sensitive (action, focus_active);
541 
542   /* Objects menu */
543   if ((action = menus_get_action ("ObjectsSendtoback")) != NULL)
544     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
545   if ((action = menus_get_action ("ObjectsBringtofront")) != NULL)
546     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
547   if ((action = menus_get_action ("ObjectsSendbackwards")) != NULL)
548     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
549   if ((action = menus_get_action ("ObjectsBringforwards")) != NULL)
550     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
551 
552   if ((action = menus_get_action ("ObjectsLayerAbove")) != NULL)
553     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
554   if ((action = menus_get_action ("ObjectsLayerBelow")) != NULL)
555     gtk_action_set_sensitive (action, !textedit_active && selected_count > 0);
556 
557   if ((action = menus_get_action ("ObjectsGroup")) != NULL)
558     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
559   if ((action = menus_get_action ("ObjectsUngroup")) != NULL)
560     gtk_action_set_sensitive (action, !textedit_active && diagram_selected_any_groups (dia));
561   if ((action = menus_get_action ("ObjectsParent")) != NULL)
562     gtk_action_set_sensitive (action, !textedit_active && diagram_selected_can_parent (dia));
563   if ((action = menus_get_action ("ObjectsUnparent")) != NULL)
564     gtk_action_set_sensitive (action, !textedit_active && diagram_selected_any_children (dia));
565   if ((action = menus_get_action ("ObjectsUnparentchildren")) != NULL)
566     gtk_action_set_sensitive (action, !textedit_active && diagram_selected_any_parents (dia));
567 
568   if ((action = menus_get_action ("ObjectsProperties")) != NULL)
569     gtk_action_set_sensitive (action, selected_count > 0);
570 
571   /* Objects->Align menu */
572   if ((action = menus_get_action ("ObjectsAlignLeft")) != NULL)
573     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
574   if ((action = menus_get_action ("ObjectsAlignCenter")) != NULL)
575     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
576   if ((action = menus_get_action ("ObjectsAlignRight")) != NULL)
577     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
578   if ((action = menus_get_action ("ObjectsAlignSpreadouthorizontally")) != NULL)
579     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
580   if ((action = menus_get_action ("ObjectsAlignAdjacent")) != NULL)
581     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
582   if ((action = menus_get_action ("ObjectsAlignTop")) != NULL)
583     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
584   if ((action = menus_get_action ("ObjectsAlignMiddle")) != NULL)
585     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
586   if ((action = menus_get_action ("ObjectsAlignBottom")) != NULL)
587     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
588   if ((action = menus_get_action ("ObjectsAlignSpreadoutvertically")) != NULL)
589     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
590   if ((action = menus_get_action ("ObjectsAlignStacked")) != NULL)
591     gtk_action_set_sensitive (action, !textedit_active && selected_count > 1);
592 
593   /* Select menu */
594   if ((action = menus_get_action ("SelectAll")) != NULL)
595     gtk_action_set_sensitive (action, !textedit_active);
596   if ((action = menus_get_action ("SelectNone")) != NULL)
597     gtk_action_set_sensitive (action, !textedit_active);
598   if ((action = menus_get_action ("SelectInvert")) != NULL)
599     gtk_action_set_sensitive (action, !textedit_active);
600   if ((action = menus_get_action ("SelectTransitive")) != NULL)
601     gtk_action_set_sensitive (action, !textedit_active);
602   if ((action = menus_get_action ("SelectConnected")) != NULL)
603     gtk_action_set_sensitive (action, !textedit_active);
604   if ((action = menus_get_action ("SelectSametype")) != NULL)
605     gtk_action_set_sensitive (action, !textedit_active);
606 
607   if ((action = menus_get_action ("SelectReplace")) != NULL)
608     gtk_action_set_sensitive (action, !textedit_active);
609   if ((action = menus_get_action ("SelectUnion")) != NULL)
610     gtk_action_set_sensitive (action, !textedit_active);
611   if ((action = menus_get_action ("SelectIntersection")) != NULL)
612     gtk_action_set_sensitive (action, !textedit_active);
613   if ((action = menus_get_action ("SelectRemove")) != NULL)
614     gtk_action_set_sensitive (action, !textedit_active);
615   if ((action = menus_get_action ("SelectInverse")) != NULL)
616     gtk_action_set_sensitive (action, !textedit_active);
617 
618   /* Tools menu */
619   {
620     /* Keep in sync with menus.c(tool_entries) */
621     static gchar * action_names[] = {
622       "ToolsModify", "ToolsMagnify",  "ToolsTextedit",  "ToolsScroll",
623       "ToolsText", "ToolsBox", "ToolsEllipse", "ToolsPolygon", "ToolsBeziergon",
624       "ToolsLine", "ToolsArc", "ToolsZigzagline", "ToolsPolyline","ToolsBezierline",
625       "ToolsImage", "ToolsOutline", NULL
626     };
627     int i;
628     for (i = 0; action_names[i] != NULL; ++i) {
629       if ((action = menus_get_action (action_names[i])) != NULL)
630         gtk_action_set_sensitive (action, !textedit_active);
631     }
632   }
633   /* View menu - should not need disabling yet */
634 }
635 
636 
637 void
diagram_add_ddisplay(Diagram * dia,DDisplay * ddisp)638 diagram_add_ddisplay(Diagram *dia, DDisplay *ddisp)
639 {
640   dia->displays = g_slist_prepend(dia->displays, ddisp);
641 }
642 
643 void
diagram_remove_ddisplay(Diagram * dia,DDisplay * ddisp)644 diagram_remove_ddisplay(Diagram *dia, DDisplay *ddisp)
645 {
646   dia->displays = g_slist_remove(dia->displays, ddisp);
647 
648   if (g_slist_length(dia->displays) == 0) {
649     if (!app_is_embedded()) {
650       /* Don't delete embedded diagram when last view is closed */
651       diagram_destroy(dia);
652     }
653   }
654 }
655 
656 void
diagram_add_object(Diagram * dia,DiaObject * obj)657 diagram_add_object(Diagram *dia, DiaObject *obj)
658 {
659   layer_add_object(dia->data->active_layer, obj);
660 
661   diagram_modified(dia);
662 
663   diagram_tree_add_object(diagram_tree(), dia, obj);
664 }
665 
666 void
diagram_add_object_list(Diagram * dia,GList * list)667 diagram_add_object_list(Diagram *dia, GList *list)
668 {
669   layer_add_objects(dia->data->active_layer, list);
670 
671   diagram_modified(dia);
672 
673   diagram_tree_add_objects(diagram_tree(), dia, list);
674 }
675 
676 void
diagram_selected_break_external(Diagram * dia)677 diagram_selected_break_external(Diagram *dia)
678 {
679   GList *list;
680   GList *connected_list;
681   DiaObject *obj;
682   DiaObject *other_obj;
683   int i,j;
684 
685   list = dia->data->selected;
686   while (list != NULL) {
687     obj = (DiaObject *)list->data;
688 
689     /* Break connections between this object and objects not selected: */
690     for (i=0;i<obj->num_handles;i++) {
691       ConnectionPoint *con_point;
692       con_point = obj->handles[i]->connected_to;
693 
694       if ( con_point == NULL )
695 	break; /* Not connected */
696 
697       other_obj = con_point->object;
698       if (g_list_find(dia->data->selected, other_obj) == NULL) {
699 	/* other_obj is not selected, break connection */
700 	Change *change = undo_unconnect(dia, obj, obj->handles[i]);
701 	(change->apply)(change, dia);
702 	object_add_updates(obj, dia);
703       }
704     }
705 
706     /* Break connections from non selected objects to this object: */
707     for (i=0;i<obj->num_connections;i++) {
708       connected_list = obj->connections[i]->connected;
709 
710       while (connected_list != NULL) {
711 	other_obj = (DiaObject *)connected_list->data;
712 
713 	if (g_list_find(dia->data->selected, other_obj) == NULL) {
714 	  /* other_obj is not in list, break all connections
715 	     to obj from other_obj */
716 
717 	  for (j=0;j<other_obj->num_handles;j++) {
718 	    ConnectionPoint *con_point;
719 	    con_point = other_obj->handles[j]->connected_to;
720 
721 	    if (con_point && (con_point->object == obj)) {
722 	      Change *change;
723 	      connected_list = g_list_previous(connected_list);
724 	      change = undo_unconnect(dia, other_obj,
725 					      other_obj->handles[j]);
726 	      (change->apply)(change, dia);
727 	      if (connected_list == NULL)
728 		connected_list = obj->connections[i]->connected;
729 	    }
730 	  }
731 	}
732 
733 	connected_list = g_list_next(connected_list);
734       }
735     }
736     diagram_tree_remove_object(diagram_tree(), obj);
737     list = g_list_next(list);
738   }
739 }
740 
741 void
diagram_remove_all_selected(Diagram * diagram,int delete_empty)742 diagram_remove_all_selected(Diagram *diagram, int delete_empty)
743 {
744   object_add_updates_list(diagram->data->selected, diagram);
745   textedit_remove_focus_all(diagram);
746   data_remove_all_selected(diagram->data);
747   g_signal_emit (diagram, diagram_signals[SELECTION_CHANGED], 0, g_list_length (diagram->data->selected));
748 }
749 
750 void
diagram_unselect_object(Diagram * diagram,DiaObject * obj)751 diagram_unselect_object(Diagram *diagram, DiaObject *obj)
752 {
753   object_add_updates(obj, diagram);
754   textedit_remove_focus(obj, diagram);
755   data_unselect(DIA_DIAGRAM_DATA(diagram), obj);
756   g_signal_emit (diagram, diagram_signals[SELECTION_CHANGED], 0,
757 		 g_list_length (DIA_DIAGRAM_DATA(diagram)->selected));
758 }
759 
760 void
diagram_unselect_objects(Diagram * dia,GList * obj_list)761 diagram_unselect_objects(Diagram *dia, GList *obj_list)
762 {
763   GList *list;
764   DiaObject *obj;
765 
766   /* otherwise we would signal objects step by step */
767   g_signal_handlers_block_by_func (dia, _diagram_selection_changed, NULL);
768   list = obj_list;
769   while (list != NULL) {
770     obj = (DiaObject *) list->data;
771 
772     if (g_list_find(dia->data->selected, obj) != NULL){
773       diagram_unselect_object(dia, obj);
774     }
775 
776     list = g_list_next(list);
777   }
778   g_signal_handlers_unblock_by_func (dia, _diagram_selection_changed, NULL);
779   g_signal_emit (dia, diagram_signals[SELECTION_CHANGED], 0, g_list_length (dia->data->selected));
780 }
781 
782 /** Make a single object selected.
783  * Note that an object inside a closed group cannot be made selected, nor
784  * can an object in a non-active layer.
785  * @param diagram The diagram that the object belongs to (sorta redundant now)
786  * @param obj The object that should be made selected.
787  */
788 void
diagram_select(Diagram * diagram,DiaObject * obj)789 diagram_select(Diagram *diagram, DiaObject *obj)
790 {
791   if (dia_object_is_selectable(obj)) {
792     data_select(diagram->data, obj);
793     obj->ops->selectf(obj, NULL, NULL);
794     object_add_updates(obj, diagram);
795     g_signal_emit (diagram, diagram_signals[SELECTION_CHANGED], 0,
796 		   g_list_length (diagram->data->selected));
797   }
798 }
799 
800 void
diagram_select_list(Diagram * dia,GList * list)801 diagram_select_list(Diagram *dia, GList *list)
802 {
803   g_return_if_fail (dia && list);
804   /* otherwise we would signal objects step by step */
805   g_signal_handlers_block_by_func (dia, _diagram_selection_changed, NULL);
806   while (list != NULL) {
807     DiaObject *obj = (DiaObject *)list->data;
808 
809     diagram_select(dia, obj);
810 
811     list = g_list_next(list);
812   }
813   if (get_active_focus((DiagramData*) dia) == NULL) {
814     textedit_activate_first(ddisplay_active());
815   }
816   g_signal_handlers_unblock_by_func (dia, _diagram_selection_changed, NULL);
817   g_signal_emit (dia, diagram_signals[SELECTION_CHANGED], 0, g_list_length (dia->data->selected));
818 }
819 
820 int
diagram_is_selected(Diagram * diagram,DiaObject * obj)821 diagram_is_selected(Diagram *diagram, DiaObject *obj)
822 {
823   return g_list_find(diagram->data->selected, obj) != NULL;
824 }
825 
826 void
diagram_redraw_all()827 diagram_redraw_all()
828 {
829   GList *list;
830   Diagram *dia;
831 
832   list = open_diagrams;
833 
834   while (list != NULL) {
835     dia = (Diagram *) list->data;
836 
837     diagram_add_update_all(dia);
838     diagram_flush(dia);
839 
840     list = g_list_next(list);
841   }
842   return;
843 }
844 
845 void
diagram_add_update_all(Diagram * dia)846 diagram_add_update_all(Diagram *dia)
847 {
848   GSList *l;
849   DDisplay *ddisp;
850 
851   l = dia->displays;
852   while (l!=NULL) {
853     ddisp = (DDisplay *) l->data;
854 
855     ddisplay_add_update_all(ddisp);
856 
857     l = g_slist_next(l);
858   }
859 }
860 
861 void
diagram_add_update(Diagram * dia,Rectangle * update)862 diagram_add_update(Diagram *dia, Rectangle *update)
863 {
864   GSList *l;
865   DDisplay *ddisp;
866 
867   l = dia->displays;
868   while (l!=NULL) {
869     ddisp = (DDisplay *) l->data;
870 
871     ddisplay_add_update(ddisp, update);
872 
873     l = g_slist_next(l);
874   }
875 }
876 
877 /** Add an update of the given rectangle, but with an additional
878  * border around it.  The pixels are added after the rectangle has
879  * been converted to pixel coords.
880  * Currently used for leaving room for highlighting.
881  * */
882 void
diagram_add_update_with_border(Diagram * dia,Rectangle * update,int pixel_border)883 diagram_add_update_with_border(Diagram *dia, Rectangle *update,
884 			       int pixel_border)
885 {
886   GSList *l;
887   DDisplay *ddisp;
888 
889   l = dia->displays;
890   while (l!=NULL) {
891     ddisp = (DDisplay *) l->data;
892 
893     ddisplay_add_update_with_border(ddisp, update, pixel_border);
894 
895     l = g_slist_next(l);
896   }
897 }
898 
899 void
diagram_add_update_pixels(Diagram * dia,Point * point,int pixel_width,int pixel_height)900 diagram_add_update_pixels(Diagram *dia, Point *point,
901 			  int pixel_width, int pixel_height)
902 {
903   GSList *l;
904   DDisplay *ddisp;
905 
906   l = dia->displays;
907   while (l!=NULL) {
908     ddisp = (DDisplay *) l->data;
909 
910     ddisplay_add_update_pixels(ddisp, point, pixel_width, pixel_height);
911 
912     l = g_slist_next(l);
913   }
914 }
915 
916 void
diagram_flush(Diagram * dia)917 diagram_flush(Diagram *dia)
918 {
919   GSList *l;
920   DDisplay *ddisp;
921   l = dia->displays;
922   while (l!=NULL) {
923     ddisp = (DDisplay *) l->data;
924 
925     ddisplay_flush(ddisp);
926 
927     l = g_slist_next(l);
928   }
929   dynobj_refresh_kick();
930 }
931 
932 DiaObject *
diagram_find_clicked_object(Diagram * dia,Point * pos,real maxdist)933 diagram_find_clicked_object(Diagram *dia, Point *pos,
934 			    real maxdist)
935 {
936   return layer_find_closest_object_except(dia->data->active_layer,
937 					  pos, maxdist, NULL);
938 }
939 
940 DiaObject *
diagram_find_clicked_object_except(Diagram * dia,Point * pos,real maxdist,GList * avoid)941 diagram_find_clicked_object_except(Diagram *dia, Point *pos,
942 				   real maxdist, GList *avoid)
943 {
944   return layer_find_closest_object_except(dia->data->active_layer, pos,
945 					  maxdist, avoid);
946 }
947 
948 /*
949  * Always returns the last handle in an object that has
950  * the closest distance
951  */
952 real
diagram_find_closest_handle(Diagram * dia,Handle ** closest,DiaObject ** object,Point * pos)953 diagram_find_closest_handle(Diagram *dia, Handle **closest,
954 			    DiaObject **object, Point *pos)
955 {
956   GList *l;
957   DiaObject *obj;
958   Handle *handle;
959   real mindist, dist;
960   int i;
961 
962   mindist = 1000000.0; /* Realy big value... */
963 
964   *closest = NULL;
965 
966   l = dia->data->selected;
967   while (l!=NULL) {
968     obj = (DiaObject *) l->data;
969 
970     for (i=0;i<obj->num_handles;i++) {
971       handle = obj->handles[i];
972       /* Note: Uses manhattan metric for speed... */
973       dist = distance_point_point_manhattan(pos, &handle->pos);
974       if (dist<=mindist) {
975 	mindist = dist;
976 	*closest = handle;
977 	*object = obj;
978       }
979     }
980 
981     l = g_list_next(l);
982   }
983 
984   return mindist;
985 }
986 
987 real
diagram_find_closest_connectionpoint(Diagram * dia,ConnectionPoint ** closest,Point * pos,DiaObject * notthis)988 diagram_find_closest_connectionpoint(Diagram *dia,
989 				     ConnectionPoint **closest,
990 				     Point *pos,
991 				     DiaObject *notthis)
992 {
993   real dist = 100000000.0;
994   guint i;
995   for (i=0;i<dia->data->layers->len;i++) {
996     Layer *layer = (Layer*)g_ptr_array_index(dia->data->layers, i);
997     ConnectionPoint *this_cp;
998     real this_dist;
999     if (layer->connectable) {
1000       this_dist = layer_find_closest_connectionpoint(layer,
1001 						     &this_cp, pos, notthis);
1002       if (this_dist < dist) {
1003 	dist = this_dist;
1004 	*closest = this_cp;
1005       }
1006     }
1007   }
1008   return dist;
1009 }
1010 
1011 void
diagram_update_extents(Diagram * dia)1012 diagram_update_extents(Diagram *dia)
1013 {
1014   gfloat cur_scale = dia->data->paper.scaling;
1015   /* anropar update_scrollbars() */
1016 
1017   if (data_update_extents(dia->data)) {
1018     /* Update scrollbars because extents were changed: */
1019     GSList *l;
1020     DDisplay *ddisp;
1021 
1022     l = dia->displays;
1023     while (l!=NULL) {
1024       ddisp = (DDisplay *) l->data;
1025 
1026       ddisplay_update_scrollbars(ddisp);
1027 
1028       l = g_slist_next(l);
1029     }
1030     if (cur_scale != dia->data->paper.scaling) {
1031       diagram_add_update_all(dia);
1032       diagram_flush(dia);
1033     }
1034   }
1035 }
1036 
1037 /* Remove connections from obj to objects outside created group. */
1038 static void
strip_connections(DiaObject * obj,GList * not_strip_list,Diagram * dia)1039 strip_connections(DiaObject *obj, GList *not_strip_list, Diagram *dia)
1040 {
1041   int i;
1042   Handle *handle;
1043   Change *change;
1044 
1045   for (i=0;i<obj->num_handles;i++) {
1046     handle = obj->handles[i];
1047     if ((handle->connected_to != NULL) &&
1048 	(g_list_find(not_strip_list, handle->connected_to->object)==NULL)) {
1049       change = undo_unconnect(dia, obj, handle);
1050       (change->apply)(change, dia);
1051     }
1052   }
1053 }
1054 
1055 
1056 /* GCompareFunc */
1057 static gint
diagram_parent_sort_cb(gconstpointer _a,gconstpointer _b)1058 diagram_parent_sort_cb(gconstpointer _a, gconstpointer _b)
1059 {
1060   ObjectExtent **a = (ObjectExtent **)_a;
1061   ObjectExtent **b = (ObjectExtent **)_b;
1062 
1063   if ((*a)->extent.left < (*b)->extent.left)
1064     return 1;
1065   else if ((*a)->extent.left > (*b)->extent.left)
1066     return -1;
1067   else
1068     if ((*a)->extent.top < (*b)->extent.top)
1069       return 1;
1070     else if ((*a)->extent.top > (*b)->extent.top)
1071       return -1;
1072     else
1073       return 0;
1074 }
1075 
1076 
1077 /* needs faster algorithm -- if we find that parenting is slow.
1078  * If it works, don't optimize it until it's a hotspot. */
diagram_parent_selected(Diagram * dia)1079 void diagram_parent_selected(Diagram *dia)
1080 {
1081   GList *list = dia->data->selected;
1082   int length = g_list_length(list);
1083   int idx, idx2;
1084   ObjectExtent *oe;
1085   gboolean any_parented = FALSE;
1086   GPtrArray *extents = g_ptr_array_sized_new(length);
1087   while (list)
1088   {
1089     oe = g_new(ObjectExtent, 1);
1090     oe->object = list->data;
1091     parent_handle_extents(list->data, &oe->extent);
1092     g_ptr_array_add(extents, oe);
1093     list = g_list_next(list);
1094   }
1095   /* sort all the objects by their left position */
1096   g_ptr_array_sort(extents, diagram_parent_sort_cb);
1097 
1098   for (idx = 0; idx < length; idx++)
1099   {
1100     ObjectExtent *oe1 = g_ptr_array_index(extents, idx);
1101     if (oe1->object->parent)
1102       continue;
1103 
1104     for (idx2 = idx + 1; idx2 < length; idx2++)
1105     {
1106       ObjectExtent *oe2 = g_ptr_array_index(extents, idx2);
1107       if (!object_flags_set(oe2->object, DIA_OBJECT_CAN_PARENT))
1108         continue;
1109 
1110       if (oe1->extent.right <= oe2->extent.right
1111         && oe1->extent.bottom <= oe2->extent.bottom)
1112       {
1113 	Change *change;
1114 	change = undo_parenting(dia, oe2->object, oe1->object, TRUE);
1115 	(change->apply)(change, dia);
1116 	any_parented = TRUE;
1117 	/*
1118         oe1->object->parent = oe2->object;
1119 	oe2->object->children = g_list_append(oe2->object->children, oe1->object);
1120 	*/
1121 	break;
1122       }
1123     }
1124   }
1125   g_ptr_array_free(extents, TRUE);
1126   if (any_parented) {
1127     diagram_modified(dia);
1128     diagram_flush(dia);
1129     undo_set_transactionpoint(dia->undo);
1130   }
1131 }
1132 
1133 /** Remove all selected objects from their parents (if any). */
diagram_unparent_selected(Diagram * dia)1134 void diagram_unparent_selected(Diagram *dia)
1135 {
1136   GList *list;
1137   DiaObject *obj, *parent;
1138   Change *change;
1139   gboolean any_unparented = FALSE;
1140 
1141   for (list = dia->data->selected; list != NULL; list = g_list_next(list))
1142   {
1143     obj = (DiaObject *) list->data;
1144     parent = obj->parent;
1145 
1146     if (!parent)
1147       continue;
1148 
1149     change = undo_parenting(dia, parent, obj, FALSE);
1150     (change->apply)(change, dia);
1151     any_unparented = TRUE;
1152     /*
1153     parent->children = g_list_remove(parent->children, obj);
1154     obj->parent = NULL;
1155     */
1156   }
1157   if (any_unparented) {
1158     diagram_modified(dia);
1159     diagram_flush(dia);
1160     undo_set_transactionpoint(dia->undo);
1161   }
1162 }
1163 
1164 /** Remove all children from the selected parents. */
diagram_unparent_children_selected(Diagram * dia)1165 void diagram_unparent_children_selected(Diagram *dia)
1166 {
1167   GList *list;
1168   DiaObject *obj, *child;
1169   gboolean any_unparented = FALSE;
1170   for (list = dia->data->selected; list != NULL; list = g_list_next(list))
1171   {
1172     obj = (DiaObject *) list->data;
1173     if (!object_flags_set(obj, DIA_OBJECT_CAN_PARENT) || !obj->children)
1174       continue;
1175 
1176     any_unparented = TRUE;
1177     /* Yes, this creates a whole bunch of Changes.  They're lightweight
1178      * structures, though, and it's easier to assure correctness this
1179      * way.  If needed, we can make a parent undo with a list of children.
1180      */
1181     while (obj->children != NULL) {
1182       Change *change;
1183       child = (DiaObject *) obj->children->data;
1184       change = undo_parenting(dia, obj, child, FALSE);
1185       /* This will remove one item from the list, so the while terminates. */
1186       (change->apply)(change, dia);
1187     }
1188     if (obj->children != NULL)
1189       printf("Obj still has %d children\n",
1190 	     g_list_length(obj->children));
1191   }
1192   if (any_unparented) {
1193     diagram_modified(dia);
1194     diagram_flush(dia);
1195     undo_set_transactionpoint(dia->undo);
1196   }
1197 }
1198 
diagram_group_selected(Diagram * dia)1199 void diagram_group_selected(Diagram *dia)
1200 {
1201   GList *list;
1202   GList *group_list;
1203   DiaObject *group;
1204   DiaObject *obj;
1205   GList *orig_list;
1206   Change *change;
1207 
1208   if (g_list_length(dia->data->selected) < 1) {
1209     message_error(_("Trying to group with no selected objects."));
1210     return;
1211   }
1212 
1213 #ifdef USE_NEWGROUP
1214   list = dia->data->selected;
1215   current_parent = ((DiaObject *) list->data)->parent;
1216   while (list != NULL) {
1217     obj = (DiaObject *)list->data;
1218     if (obj->parent != current_parent) {
1219       message_warning(_("You cannot group objects that belong to different groups or have different parents"));
1220       return;
1221     }
1222   }
1223 
1224   group = ...
1225 
1226   list = dia->data->selected;
1227   while (list != NULL) {
1228     obj = (DiaObject *)list->data;
1229 
1230   }
1231 #else
1232 #if 0
1233   /* the following is wrong as it screws up the selected list, see bug #153525
1234      * I just don't get what was originally intented so please speak up if you know  --hb
1235      */
1236   dia->data->selected = parent_list_affected(dia->data->selected);
1237 #endif
1238 
1239   orig_list = g_list_copy(dia->data->active_layer->objects);
1240 
1241   /* We have to rebuild the selection list so that it is the same
1242      order as in the Diagram list. */
1243   group_list = diagram_get_sorted_selected_remove(dia);
1244 
1245   list = group_list;
1246   while (list != NULL) {
1247     obj = (DiaObject *)list->data;
1248 
1249     /* Remove connections from obj to objects outside created group. */
1250     /* strip_connections sets up its own undo info. */
1251     /* The connections aren't reattached by ungroup. */
1252     strip_connections(obj, dia->data->selected, dia);
1253 
1254     list = g_list_next(list);
1255   }
1256 
1257   /* Remove list of selected objects */
1258   textedit_remove_focus_all(dia);
1259   data_remove_all_selected(dia->data);
1260 
1261   group = group_create(group_list);
1262   change = undo_group_objects(dia, group_list, group, orig_list);
1263   (change->apply)(change, dia);
1264 #endif
1265 
1266   /* Select the created group */
1267   diagram_select(dia, group);
1268 
1269   diagram_modified(dia);
1270   diagram_flush(dia);
1271 
1272   undo_set_transactionpoint(dia->undo);
1273 }
1274 
diagram_ungroup_selected(Diagram * dia)1275 void diagram_ungroup_selected(Diagram *dia)
1276 {
1277   DiaObject *group;
1278   GList *group_list;
1279   GList *selected, *selection_copy;
1280   int group_index;
1281   int any_groups = 0;
1282 
1283   if (g_list_length(dia->data->selected) < 1) {
1284     message_error("Trying to ungroup with no selected objects.");
1285     return;
1286   }
1287 
1288   selection_copy = g_list_copy(dia->data->selected);
1289   selected = selection_copy;
1290   while (selected != NULL) {
1291     group = (DiaObject *)selected->data;
1292 
1293     if (IS_GROUP(group)) {
1294       Change *change;
1295 
1296       /* Fix selection */
1297       diagram_unselect_object(dia, group);
1298 
1299       group_list = group_objects(group);
1300       diagram_select_list(dia, group_list);
1301 
1302       group_index = layer_object_index(dia->data->active_layer, group);
1303 
1304       change = undo_ungroup_objects(dia, group_list, group, group_index);
1305       (change->apply)(change, dia);
1306 
1307       any_groups = 1;
1308     }
1309     selected = g_list_next(selected);
1310   }
1311   g_list_free(selection_copy);
1312 
1313   if (any_groups) {
1314     diagram_modified(dia);
1315     diagram_flush(dia);
1316     undo_set_transactionpoint(dia->undo);
1317   }
1318 }
1319 
1320 GList *
diagram_get_sorted_selected(Diagram * dia)1321 diagram_get_sorted_selected(Diagram *dia)
1322 {
1323   return data_get_sorted_selected(dia->data);
1324 }
1325 
1326 /** Remove the currently selected objects from the diagram's object list.
1327  * Returns a newly created list of the selected objects, in order.
1328  */
1329 GList *
diagram_get_sorted_selected_remove(Diagram * dia)1330 diagram_get_sorted_selected_remove(Diagram *dia)
1331 {
1332   diagram_modified(dia);
1333 
1334   return data_get_sorted_selected_remove(dia->data);
1335 }
1336 
1337 void
diagram_place_under_selected(Diagram * dia)1338 diagram_place_under_selected(Diagram *dia)
1339 {
1340   GList *sorted_list;
1341   GList *orig_list;
1342 
1343   if (g_list_length (dia->data->selected) == 0)
1344     return;
1345 
1346   orig_list = g_list_copy(dia->data->active_layer->objects);
1347 
1348   sorted_list = diagram_get_sorted_selected_remove(dia);
1349   object_add_updates_list(sorted_list, dia);
1350   layer_add_objects_first(dia->data->active_layer, sorted_list);
1351 
1352   undo_reorder_objects(dia, g_list_copy(sorted_list), orig_list);
1353 
1354   diagram_modified(dia);
1355   diagram_flush(dia);
1356   undo_set_transactionpoint(dia->undo);
1357 }
1358 
1359 void
diagram_place_over_selected(Diagram * dia)1360 diagram_place_over_selected(Diagram *dia)
1361 {
1362   GList *sorted_list;
1363   GList *orig_list;
1364 
1365   if (g_list_length (dia->data->selected) == 0)
1366     return;
1367 
1368   orig_list = g_list_copy(dia->data->active_layer->objects);
1369 
1370   sorted_list = diagram_get_sorted_selected_remove(dia);
1371   object_add_updates_list(sorted_list, dia);
1372   layer_add_objects(dia->data->active_layer, sorted_list);
1373 
1374   undo_reorder_objects(dia, g_list_copy(sorted_list), orig_list);
1375 
1376   diagram_modified(dia);
1377   diagram_flush(dia);
1378   undo_set_transactionpoint(dia->undo);
1379 }
1380 
1381 void
diagram_place_up_selected(Diagram * dia)1382 diagram_place_up_selected(Diagram *dia)
1383 {
1384   GList *sorted_list;
1385   GList *orig_list;
1386   GList *tmp, *stmp;
1387   GList *new_list = NULL;
1388 
1389   if (g_list_length (dia->data->selected) == 0)
1390     return;
1391 
1392   orig_list = g_list_copy(dia->data->active_layer->objects);
1393 
1394   sorted_list = diagram_get_sorted_selected(dia);
1395   object_add_updates_list(orig_list, dia);
1396 
1397   new_list = g_list_copy(orig_list);
1398   stmp = g_list_last(sorted_list);
1399 
1400   for (tmp = g_list_last(new_list);
1401        tmp != NULL;
1402        tmp = g_list_previous(tmp)) {
1403     if (stmp == NULL) break;
1404     if (tmp->prev == NULL) break;
1405     if (tmp->data == stmp->data) {
1406       stmp = g_list_previous(stmp);
1407     } else if (tmp->prev->data == stmp->data) {
1408       void *swap = tmp->data;
1409       tmp->data = tmp->prev->data;
1410       tmp->prev->data = swap;
1411       stmp = g_list_previous(stmp);
1412     }
1413   }
1414 
1415   layer_set_object_list(dia->data->active_layer, new_list);
1416 
1417   undo_reorder_objects(dia, g_list_copy(sorted_list), orig_list);
1418 
1419   diagram_modified(dia);
1420   diagram_flush(dia);
1421   undo_set_transactionpoint(dia->undo);
1422 }
1423 
1424 void
diagram_place_down_selected(Diagram * dia)1425 diagram_place_down_selected(Diagram *dia)
1426 {
1427   GList *sorted_list;
1428   GList *orig_list;
1429   GList *tmp, *stmp;
1430   GList *new_list = NULL;
1431 
1432   if (g_list_length (dia->data->selected) == 0)
1433     return;
1434 
1435   orig_list = g_list_copy(dia->data->active_layer->objects);
1436 
1437   sorted_list = diagram_get_sorted_selected(dia);
1438   object_add_updates_list(orig_list, dia);
1439 
1440   /* Sanity check */
1441   g_assert(g_list_length (dia->data->selected) == g_list_length(sorted_list));
1442 
1443   new_list = g_list_copy(orig_list);
1444   tmp = new_list;
1445   stmp = sorted_list;
1446 
1447   for (tmp = new_list; tmp != NULL; tmp = g_list_next(tmp)) {
1448     if (stmp == NULL) break;
1449     if (tmp->next == NULL) break;
1450     if (tmp->data == stmp->data) {
1451       /* This just takes care of any starting matches */
1452       stmp = g_list_next(stmp);
1453     } else if (tmp->next->data == stmp->data) {
1454       /* This flips the non-selected element forwards, ala bubblesort */
1455       void *swap = tmp->data;
1456       tmp->data = tmp->next->data;
1457       tmp->next->data = swap;
1458       stmp = g_list_next(stmp);
1459     }
1460   }
1461 
1462   layer_set_object_list(dia->data->active_layer, new_list);
1463 
1464   undo_reorder_objects(dia, g_list_copy(sorted_list), orig_list);
1465 
1466   diagram_modified(dia);
1467   diagram_flush(dia);
1468   undo_set_transactionpoint(dia->undo);
1469 }
1470 
1471 void
diagram_set_filename(Diagram * dia,const char * filename)1472 diagram_set_filename(Diagram *dia, const char *filename)
1473 {
1474   g_free(dia->filename);
1475   dia->filename = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
1476 
1477   diagram_update_for_filename(dia);
1478 }
1479 
1480 /** Update the various areas that require updating when changing filename
1481  * This will ensure that all places that use the filename are updated:
1482  * Window titles, layer dialog, recent files, diagram tree.
1483  * @param dia The diagram whose filename has changed.
1484  */
1485 static void
diagram_update_for_filename(Diagram * dia)1486 diagram_update_for_filename(Diagram *dia)
1487 {
1488   GSList *l;
1489   DDisplay *ddisp;
1490   char *title;
1491 
1492   title = diagram_get_name(dia);
1493 
1494   l = dia->displays;
1495   while (l!=NULL) {
1496     ddisp = (DDisplay *) l->data;
1497 
1498     ddisplay_set_title(ddisp, title);
1499 
1500     l = g_slist_next(l);
1501   }
1502 
1503   g_free(title);
1504 
1505   layer_dialog_update_diagram_list();
1506 
1507   diagram_tree_update_name(diagram_tree(), dia);
1508 }
1509 
1510 /** Returns a string with a 'sensible' (human-readable) name for the
1511  * diagram.  The string should be freed after use.
1512  * This name may or may not be the same as the filename.
1513  */
1514 gchar *
diagram_get_name(Diagram * dia)1515 diagram_get_name(Diagram *dia)
1516 {
1517   return g_path_get_basename(dia->filename);
1518 }
1519 
diagram_modified_exists(void)1520 int diagram_modified_exists(void)
1521 {
1522   GList *list;
1523   Diagram *dia;
1524 
1525   list = open_diagrams;
1526 
1527   while (list != NULL) {
1528     dia = (Diagram *) list->data;
1529 
1530     if (diagram_is_modified(dia))
1531       return TRUE;
1532 
1533     list = g_list_next(list);
1534   }
1535   return FALSE;
1536 }
1537 
diagram_object_modified(Diagram * dia,DiaObject * object)1538 void diagram_object_modified(Diagram *dia, DiaObject *object)
1539 {
1540   diagram_tree_update_object(diagram_tree(), dia, object);
1541 }
1542