/** Resets all highlighting in this layer. Helper function for * highlight_reset_all */ static void highlight_reset_objects(GList *objects, Diagram *dia) { for (; objects != NULL; objects = g_list_next(objects)) { DiaObject *object = (DiaObject*)objects->data; highlight_object_off(object, dia); if (IS_GROUP(object)) { highlight_reset_objects(group_objects(object), dia); } } }
void diagram_ungroup_selected(Diagram *dia) { DiaObject *group; GList *group_list; GList *selected, *selection_copy; int group_index; int any_groups = 0; if (g_list_length(dia->data->selected) < 1) { message_error("Trying to ungroup with no selected objects."); return; } selection_copy = g_list_copy(dia->data->selected); selected = selection_copy; while (selected != NULL) { group = (DiaObject *)selected->data; if (IS_GROUP(group)) { Change *change; /* Fix selection */ diagram_unselect_object(dia, group); group_list = group_objects(group); group_index = layer_object_get_index(dia->data->active_layer, group); change = undo_ungroup_objects(dia, group_list, group, group_index); (change->apply)(change, dia); diagram_select_list(dia, group_list); any_groups = 1; } selected = g_list_next(selected); } g_list_free(selection_copy); if (any_groups) { diagram_modified(dia); diagram_flush(dia); undo_set_transactionpoint(dia->undo); } }
static void read_connections(GList *objects, xmlNodePtr layer_node, GHashTable *objects_hash) { ObjectNode obj_node; GList *list; xmlNodePtr connections; xmlNodePtr connection; char *handlestr; char *tostr; char *connstr; int handle, conn; DiaObject *to; list = objects; obj_node = layer_node->xmlChildrenNode; while ((list != NULL) && (obj_node != NULL)) { DiaObject *obj = (DiaObject *) list->data; /* the obj and there node must stay in sync to properly setup connections */ while (obj_node && (xmlIsBlankNode(obj_node) || XML_COMMENT_NODE == obj_node->type)) obj_node = obj_node->next; if (!obj_node) break; if IS_GROUP(obj) { read_connections(group_objects(obj), obj_node, objects_hash); } else { gboolean broken = FALSE; /* an invalid bounding box is a good sign for some need of corrections */ gboolean wants_update = obj->bounding_box.right >= obj->bounding_box.left || obj->bounding_box.top >= obj->bounding_box.bottom; connections = obj_node->xmlChildrenNode; while ((connections!=NULL) && (xmlStrcmp(connections->name, (const xmlChar *)"connections")!=0)) connections = connections->next; if (connections != NULL) { connection = connections->xmlChildrenNode; while (connection != NULL) { char *donestr; if (xmlIsBlankNode(connection)) { connection = connection->next; continue; } handlestr = (char * )xmlGetProp(connection, (const xmlChar *)"handle"); tostr = (char *) xmlGetProp(connection, (const xmlChar *)"to"); connstr = (char *) xmlGetProp(connection, (const xmlChar *)"connection"); handle = atoi(handlestr); conn = strtol(connstr, &donestr, 10); if (*donestr != '\0') { /* Didn't convert it all -- use string */ conn = -1; } to = g_hash_table_lookup(objects_hash, tostr); if (to == NULL) { message_error(_("Error loading diagram.\n" "Linked object not found in document.")); broken = TRUE; } else if (handle < 0 || handle >= obj->num_handles) { message_error(_("Error loading diagram.\n" "Connection handle %d does not exist on '%s'."), handle, to->type->name); broken = TRUE; } else { if (conn >= 0 && conn < to->num_connections) { object_connect(obj, obj->handles[handle], to->connections[conn]); /* force an update on the connection, helpful with (incomplete) generated files */ if (wants_update) { #if 0 obj->ops->move_handle(obj, obj->handles[handle], &to->connections[conn]->pos, to->connections[conn], HANDLE_MOVE_CONNECTED,0); #endif } } else { message_error(_("Error loading diagram.\n" "Connection point %d does not exist on '%s'."), conn, to->type->name); broken = TRUE; } } if (handlestr) xmlFree(handlestr); if (tostr) xmlFree(tostr); if (connstr) xmlFree(connstr); connection = connection->next; } /* Fix positions of the connection object for (de)generated files. * Only done for the last point connected otherwise the intermediate posisitions * may screw the auto-routing algorithm. */ if (!broken && obj && obj->ops->set_props && wants_update) { /* called for it's side-effect of update_data */ obj->ops->move(obj,&obj->position); for (handle = 0; handle < obj->num_handles; ++handle) { if (obj->handles[handle]->connected_to) obj->ops->move_handle(obj, obj->handles[handle], &obj->handles[handle]->pos, obj->handles[handle]->connected_to, HANDLE_MOVE_CONNECTED,0); } } } } /* Now set up parent relationships. */ connections = obj_node->xmlChildrenNode; while ((connections!=NULL) && (xmlStrcmp(connections->name, (const xmlChar *)"childnode")!=0)) connections = connections->next; if (connections != NULL) { tostr = (char *)xmlGetProp(connections, (const xmlChar *)"parent"); if (tostr) { obj->parent = g_hash_table_lookup(objects_hash, tostr); if (obj->parent == NULL) { message_error(_("Can't find parent %s of %s object\n"), tostr, obj->type->name); } else { obj->parent->children = g_list_prepend(obj->parent->children, obj); } } } list = g_list_next(list); obj_node = obj_node->next; }
/** * Recursive function to read objects from a specific level in the xml. * * Nowadays there are quite a few of them : * - Layers : a diagram may have different layers, but this function does *not* * add the created objects to them as it does not know on which nesting level it * is called. So the topmost caller must add the returned objects to the layer. * - Groups : groups in itself can have an arbitrary nesting level including other * groups or objects or both of them. A group not containing any objects is by * definition useless. So it is not created. This is to avoid trouble with some older * diagrams which happen to be saved with empty groups. * - Parents : if the parent relations would have been there from the beginning of * Dias file format they probably would have been added as nesting level * themselves. But to maintain forward compatibility (allow to let older versions * of Dia to see as much as possible) they were added all on the same level and * the parent child relation is reconstructed from additional attributes. */ static GList * read_objects(xmlNodePtr objects, GHashTable *objects_hash,const char *filename, DiaObject *parent, GHashTable *unknown_objects_hash) { GList *list; DiaObjectType *type; DiaObject *obj; ObjectNode obj_node; char *typestr; char *versionstr; char *id; int version; xmlNodePtr child_node; list = NULL; obj_node = objects->xmlChildrenNode; while ( obj_node != NULL) { if (xmlIsBlankNode(obj_node)) { obj_node = obj_node->next; continue; } if (!obj_node) break; if (xmlStrcmp(obj_node->name, (const xmlChar *)"object")==0) { typestr = (char *) xmlGetProp(obj_node, (const xmlChar *)"type"); versionstr = (char *) xmlGetProp(obj_node, (const xmlChar *)"version"); id = (char *) xmlGetProp(obj_node, (const xmlChar *)"id"); version = 0; if (versionstr != NULL) { version = atoi(versionstr); xmlFree(versionstr); } type = object_get_type((char *)typestr); if (!type) { if (g_utf8_validate (typestr, -1, NULL) && NULL == g_hash_table_lookup(unknown_objects_hash, typestr)) g_hash_table_insert(unknown_objects_hash, g_strdup(typestr), 0); } else { obj = type->ops->load(obj_node, version, filename); list = g_list_append(list, obj); if (parent) { obj->parent = parent; parent->children = g_list_append(parent->children, obj); } g_hash_table_insert(objects_hash, g_strdup((char *)id), obj); child_node = obj_node->children; while(child_node) { if (xmlStrcmp(child_node->name, (const xmlChar *)"children") == 0) { GList *children_read = read_objects(child_node, objects_hash, filename, obj, unknown_objects_hash); list = g_list_concat(list, children_read); break; } child_node = child_node->next; } } if (typestr) xmlFree(typestr); if (id) xmlFree (id); } else if (xmlStrcmp(obj_node->name, (const xmlChar *)"group")==0 && obj_node->children) { /* don't create empty groups */ obj = group_create(read_objects(obj_node, objects_hash, filename, NULL, unknown_objects_hash)); #ifdef USE_NEWGROUP /* Old group objects had objects recursively inside them. Since * objects are now done with parenting, we need to extract those objects, * make a newgroup object, set parent-child relationships, and add * all of them to the diagram. */ { DiaObject *newgroup; GList *objects; Point lower_right; type = object_get_type("Misc - NewGroup"); lower_right = obj->position; newgroup = type->ops->create(&lower_right, NULL, NULL, NULL); list = g_list_append(list, newgroup); for (objects = group_objects(obj); objects != NULL; objects = g_list_next(objects)) { DiaObject *subobj = (DiaObject *) objects->data; list = g_list_append(list, subobj); subobj->parent = newgroup; newgroup->children = g_list_append(newgroup->children, subobj); if (subobj->bounding_box.right > lower_right.x) { lower_right.x = subobj->bounding_box.right; } if (subobj->bounding_box.bottom > lower_right.y) { lower_right.y = subobj->bounding_box.bottom; } } newgroup->ops->move_handle(newgroup, newgroup->handles[7], &lower_right, NULL, HANDLE_MOVE_CREATE_FINAL, 0); /* We've used the info from the old group, destroy it */ group_destroy_shallow(obj); } #else list = g_list_append(list, obj); #endif } else { /* silently ignore other nodes */ } obj_node = obj_node->next; } return list; }
/* * renderer methods */ static void draw_object(DiaRenderer *self, DiaObject *object, DiaMatrix *matrix) { DrsRenderer *renderer = DRS_RENDERER (self); DiaMatrix *m = g_queue_peek_tail (renderer->matrices); xmlNodePtr node; g_queue_push_tail (renderer->parents, renderer->root); renderer->root = node = xmlNewChild(renderer->root, NULL, (const xmlChar *)"object", NULL); xmlSetProp(node, (const xmlChar *)"type", (xmlChar *)object->type->name); /* if it looks like intdata store it as well */ if ((int)object->type->default_user_data > 0 && (int)object->type->default_user_data < 0xFF) { gchar buffer[30]; g_snprintf(buffer, sizeof(buffer), "%d", (int)object->type->default_user_data); xmlSetProp(node, (const xmlChar *)"intdata", (xmlChar *)buffer); } if (renderer->save_props) { xmlNodePtr props_node; props_node = xmlNewChild(node, NULL, (const xmlChar *)"properties", NULL); object_save_props (object, props_node, renderer->ctx); } if (matrix) { DiaMatrix *m2 = g_new (DiaMatrix, 1); if (m) dia_matrix_multiply (m2, matrix, m); else *m2 = *matrix; g_queue_push_tail (renderer->matrices, m2); /* lazy creation of our transformer */ if (!renderer->transformer) renderer->transformer = dia_transform_renderer_new (self); } /* special handling for group objects: * - for the render branch use DiaTransformRenderer, but not it's draw_object, * to see all the children's draw_object ourself * - for the object branch we rely on this draw_object being called so need * to inline group_draw here * - to maintain the correct transform build our own queue of matrices like * the DiaTransformRenderer would do through it's draw_object */ { g_queue_push_tail (renderer->parents, renderer->root); renderer->root = node = xmlNewChild(renderer->root, NULL, (const xmlChar *)"render", NULL); if (renderer->transformer) { DiaMatrix *m = g_queue_peek_tail (renderer->matrices); if (IS_GROUP (object)) { /* reimplementation of group_draw to use this draw_object method */ GList *list; DiaObject *obj; list = group_objects (object); while (list != NULL) { obj = (DiaObject *) list->data; DIA_RENDERER_GET_CLASS(self)->draw_object(self, obj, m); list = g_list_next(list); } } else { /* just the leaf */ DIA_RENDERER_GET_CLASS(renderer->transformer)->draw_object(renderer->transformer, object, m); } } else { object->ops->draw(object, DIA_RENDERER (renderer)); } renderer->root = g_queue_pop_tail (renderer->parents); } renderer->root = g_queue_pop_tail (renderer->parents); if (matrix) g_queue_pop_tail (renderer->matrices); /* one lost demand destruction */ if (renderer->transformer && g_queue_is_empty (renderer->matrices)) { g_object_unref (renderer->transformer); renderer->transformer = NULL; } }
void read_connections(GList *objects, xmlNodePtr layer_node, GHashTable *objects_hash) { ObjectNode obj_node; GList *list; xmlNodePtr connections; xmlNodePtr connection; char *handlestr; char *tostr; char *connstr; int handle, conn; Object *to; list = objects; obj_node = layer_node->childs; while (list != NULL) { Object *obj = (Object *) list->data; if IS_GROUP(obj) { read_connections(group_objects(obj), obj_node, objects_hash); } else { connections = obj_node->childs; while ((connections!=NULL) && (strcmp(connections->name, "connections")!=0)) connections = connections->next; if (connections != NULL) { connection = connections->childs; while (connection != NULL) { handlestr = xmlGetProp(connection, "handle"); tostr = xmlGetProp(connection, "to"); connstr = xmlGetProp(connection, "connection"); handle = atoi(handlestr); conn = atoi(connstr); to = g_hash_table_lookup(objects_hash, tostr); if (handlestr) free(handlestr); if (connstr) free(connstr); if (tostr) free(tostr); if (to == NULL) { message_error(_("Error loading diagram.\n" "Linked object not found in document.")); } else if (conn >= 0 && conn >= to->num_connections) { message_error(_("Error loading diagram.\n" "connection point does not exist.")); } else if (handle >= 0 && handle >= obj->num_handles) { message_error(_("Error loading diagram.\n" "connection handle does not exist.")); } else { object_connect(obj, obj->handles[handle], to->connections[conn]); } connection = connection->next; } } } list = g_list_next(list); obj_node = obj_node->next; }