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