// -*- C++ -*- /* * GChemPaint library * widgetdata.cc * * Copyright (C) 2002-2006 Jean Bréfort * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "gchempaint-config.h" #include "widgetdata.h" #include "view.h" #include "settings.h" #include "document.h" #include "application.h" #include "operation.h" #include "theme.h" #include static xmlDocPtr pXmlDoc = NULL, pXmlDoc1 = NULL; xmlChar* ClipboardData = NULL; guint ClipboardDataType, ClipboardDataType1; bool cleared = true; char *ClipboardTextData = NULL; GtkTargetEntry const export_targets[] = { {(char *) GCHEMPAINT_ATOM_NAME, 0, 0}, {(char *) "image/svg", 0, 1}, {(char *) "image/svg+xml", 0, 2}, {(char *) "image/png", 0, 3}, {(char *) "image/jpeg", 0, 4}, {(char *) "image/bmp", 0, 5}, {(char *) "UTF8_STRING", 0, 6}, {(char *) "STRING", 0, 7} }; void on_receive_targets (GtkClipboard *clipboard, GtkSelectionData *selection_data, gcpApplication *App) { GtkClipboard* sel_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); guint *DataType = (clipboard == sel_clipboard)? &ClipboardDataType: &ClipboardDataType1; if (selection_data->target == gdk_atom_intern ("TARGETS", FALSE)) { static char const *formats [] = { GCHEMPAINT_ATOM_NAME, "image/svg", "image/svg+xml", "image/png", "image/jpeg", "image/bmp", "UTF8_STRING", "STRING", NULL }; GdkAtom const *targets = (GdkAtom *) selection_data->data; unsigned const atom_count = (selection_data->length / sizeof (GdkAtom)); unsigned i, j; /* Nothing on clipboard? */ if (selection_data->length < 0) { if (clipboard == sel_clipboard) App->ActivateWindowsActionWidget ("/MainMenu/EditMenu/Paste", false); return; } gchar* name; *DataType = 7; for ( j = 0; j < atom_count ; j++) { name = gdk_atom_name (targets [j]); for (i = 0; i < *DataType; i++) if (!strcmp (name, formats[i])) { *DataType = i; break; } g_free (name); } } if (clipboard == sel_clipboard && App != NULL) App->ActivateWindowsActionWidget ("/MainMenu/EditMenu/Paste", ClipboardDataType == 0 || ClipboardDataType == 5 || ClipboardDataType == 6); } static void on_get_data(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gcpApplication *App) { xmlDocPtr pDoc = (clipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))? pXmlDoc: pXmlDoc1; guint *DataType = (clipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))? &ClipboardDataType: &ClipboardDataType1; g_return_if_fail(pDoc); if (ClipboardData) { xmlFree (ClipboardData); } ClipboardData = NULL; g_free (ClipboardTextData); ClipboardTextData = NULL; *DataType = info; int size; switch (info) { case 0: xmlDocDumpFormatMemory (pDoc, &ClipboardData, &size, info); gtk_selection_data_set(selection_data, gdk_atom_intern (GCHEMPAINT_ATOM_NAME, FALSE), 8, (const guchar*) ClipboardData, size); break; case 1: case 2: { gcpDocument *Doc = new gcpDocument (NULL, true); gcpView *pView = Doc->GetView (); pView->CreateNewWidget (); // force canvas creation Doc->ParseXMLTree (pDoc); xmlDocPtr doc = pView->BuildSVG (); xmlDocDumpFormatMemory (doc, &ClipboardData, &size, info); gtk_selection_data_set (selection_data, gdk_atom_intern (export_targets[info].target, FALSE), 8, (const guchar*) ClipboardData, size); xmlFreeDoc (doc); delete Doc; break; } case 3: { gcpDocument *Doc = new gcpDocument (NULL, true); gcpView *pView = Doc->GetView (); gsize size; pView->CreateNewWidget (); // force canvas creation Doc->ParseXMLTree (pDoc); GdkPixbuf *pixbuf = pView->BuildPixbuf (-1); // copy with zoom == 1 gdk_pixbuf_save_to_buffer (pixbuf, &ClipboardTextData, &size, "png", NULL, NULL); gtk_selection_data_set (selection_data, gdk_atom_intern (export_targets[info].target, FALSE), 8, (const guchar*) ClipboardTextData, size); g_object_unref (pixbuf); delete Doc; break; } case 4: { gcpDocument *Doc = new gcpDocument (NULL, true); gcpView *pView = Doc->GetView (); gsize size; pView->CreateNewWidget (); // force canvas creation Doc->ParseXMLTree (pDoc); GdkPixbuf *pixbuf = pView->BuildPixbuf (-1); // copy with zoom == 1 gdk_pixbuf_save_to_buffer (pixbuf, &ClipboardTextData, &size, "jpg", NULL, NULL); gtk_selection_data_set (selection_data, gdk_atom_intern (export_targets[info].target, FALSE), 8, (const guchar*) ClipboardTextData, size); g_object_unref (pixbuf); delete Doc; break; } case 5: { gcpDocument *Doc = new gcpDocument (NULL, true); gcpView *pView = Doc->GetView (); gsize size; pView->CreateNewWidget (); // force canvas creation Doc->ParseXMLTree (pDoc); GdkPixbuf *pixbuf = pView->BuildPixbuf (-1); // copy with zoom == 1 gdk_pixbuf_save_to_buffer (pixbuf, &ClipboardTextData, &size, "bmp", NULL, NULL); gtk_selection_data_set (selection_data, gdk_atom_intern (export_targets[info].target, FALSE), 8, (const guchar*) ClipboardTextData, size); g_object_unref (pixbuf); delete Doc; break; } default: xmlDocDumpFormatMemory (pDoc, &ClipboardData, &size, info); gtk_selection_data_set_text (selection_data, (const gchar*) ClipboardData, size); break; } cleared = false; if (clipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)) App->ActivateWindowsActionWidget ("/MainMenu/EditMenu/Paste", true); } void on_clear_data(GtkClipboard *clipboard, gcpApplication *App) { if (ClipboardData) { xmlFree(ClipboardData); ClipboardData = NULL; g_free (ClipboardTextData); ClipboardTextData = NULL; } cleared =true; gtk_clipboard_request_contents(clipboard, gdk_atom_intern ("TARGETS", FALSE), (GtkClipboardReceivedFunc)on_receive_targets, App); } bool gcpWidgetData::IsSelected(Object *obj) { std::list::iterator i; Object* pGroup = obj->GetGroup (); for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) if ((*i == obj) || (*i == pGroup)) return true; return false; } void gcpWidgetData::Unselect(Object* obj) { SelectedObjects.remove(obj); obj->SetSelected(Canvas, SelStateUnselected); View->Update(obj); } void gcpWidgetData::UnselectAll() { Object* obj; while (!SelectedObjects.empty()) { obj = SelectedObjects.front(); SelectedObjects.pop_front(); obj->SetSelected(Canvas, SelStateUnselected); View->Update(obj);//FIXME: is it really useful } } void gcpWidgetData::SetSelected(Object* obj) { if (!IsSelected (obj)) { SelectedObjects.push_front(obj); obj->SetSelected(Canvas, SelStateSelected); } } void gcpWidgetData::MoveSelectedItems(double dx, double dy) { std::list::iterator i; for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) MoveItems(*i, dx, dy); } void gcpWidgetData::MoveItems(Object* obj, double dx, double dy) { Object* pObject; GnomeCanvasGroup* group; if ((group = Items[obj])) gnome_canvas_item_move((GnomeCanvasItem*)group, dx, dy); else Items.erase(obj); std::map::iterator i; pObject = obj->GetFirstChild(i); while (pObject) { MoveItems(pObject, dx, dy); pObject = obj->GetNextChild(i); } } void gcpWidgetData::MoveSelection(double dx, double dy) { std::list::iterator i; gcpDocument* pDoc = View->GetDoc(); gcpOperation* pOp = pDoc-> GetNewOperation(GCP_MODIFY_OPERATION); gcpTheme *pTheme = pDoc->GetTheme (); for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) { pOp->AddObject(*i,0); (*i)->Move(dx / pTheme->GetZoomFactor (), dy / pTheme->GetZoomFactor ()); View->Update(*i); pOp->AddObject(*i,1); } pDoc->FinishOperation(); } void gcpWidgetData::RotateSelection(double dx, double dy, double angle) { gcpTheme *pTheme = View->GetDoc ()->GetTheme (); std::list::iterator i; Matrix2D m(angle); for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) { (*i)->Transform2D (m, dx / pTheme->GetZoomFactor (), dy / pTheme->GetZoomFactor ()); View->Update(*i); } } void gcpWidgetData::Copy(GtkClipboard* clipboard) { /*First build the XML tree from current selection*/ xmlDocPtr *pDoc = (clipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))? &pXmlDoc: &pXmlDoc1; if (*pDoc) xmlFreeDoc(*pDoc); *pDoc = xmlNewDoc((xmlChar*)"1.0"); if (!*pDoc) return; if (SelectedObjects.empty()) return; xmlDocSetRootElement (*pDoc, xmlNewDocNode(*pDoc, NULL, (xmlChar*)"chemistry", NULL)); xmlNsPtr ns = xmlNewNs ((*pDoc)->children, (xmlChar*) "http://www.nongnu.org/gchempaint", (xmlChar*) "gcp"); xmlSetNs ((*pDoc)->children, ns); //FIXME: implement exception handling std::list::iterator i; xmlNodePtr child; for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) if ((child = (*i)->Save (pXmlDoc))) xmlAddChild ((*pDoc)->children, child); gcpApplication* App = View->GetDoc()->GetApplication(); gtk_clipboard_set_with_data (clipboard, export_targets, ClipboardFormats, (GtkClipboardGetFunc) on_get_data, (GtkClipboardClearFunc) on_clear_data, App); gtk_clipboard_request_contents (clipboard, gdk_atom_intern ("TARGETS", FALSE), (GtkClipboardReceivedFunc) on_receive_targets, App); } void gcpWidgetData::GetObjectBounds(Object* obj, ArtDRect &rect) { Object* pObject; GnomeCanvasGroup* group; double x1, y1, x2, y2; if ((group = Items[obj])) { gnome_canvas_item_get_bounds(GNOME_CANVAS_ITEM(group), &x1, &y1, &x2, &y2); if (rect.x0 < -9.) { rect.x0 = x1; rect.y0 = y1; rect.x1 = x2; rect.y1 = y2; } else { if (rect.x0 > x1) rect.x0 = x1; if (rect.y0 > y1) rect.y0 = y1; if (rect.x1 < x2) rect.x1 = x2; if (rect.y1 < y2) rect.y1 = y2; } } else Items.erase(obj); std::map::iterator i; pObject = obj->GetFirstChild(i); while (pObject) { GetObjectBounds(pObject, rect); pObject = obj->GetNextChild(i); } } void gcpWidgetData::GetSelectionBounds(ArtDRect &rect) { std::list::iterator i, j; rect.x0 = -10.; for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) GetObjectBounds(*i, rect); } void gcpWidgetData::GetObjectBounds(Object* obj, ArtDRect *rect) { rect->x0 = -10.; GetObjectBounds(obj, *rect); } void gcpWidgetData::SelectAll() { std::map::iterator i; Object *pObject; for (i = Items.begin(); i != Items.end(); i++) { pObject = (*i).first->GetGroup(); if (pObject) { if (!IsSelected(pObject)) SetSelected(pObject); } else if (!IsSelected((*i).first)) SetSelected((*i).first); } } xmlDocPtr gcpWidgetData::GetXmlDoc(GtkClipboard* clipboard) { return (clipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))? pXmlDoc: pXmlDoc1; } void gcpWidgetData::ShowSelection(bool state) { std::list::iterator i, j; for (i = SelectedObjects.begin(); i != SelectedObjects.end(); i++) (*i)->SetSelected(Canvas, (state)? SelStateSelected: SelStateUnselected); }