// -*- C++ -*- /* * GChemPaint text plugin * fragmenttool.cc * * Copyright (C) 2003-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 "fragmenttool.h" #include "lib/fragment.h" #include "lib/document.h" #include "lib/application.h" #include "lib/settings.h" #include "lib/theme.h" #include "lib/window.h" #include extern xmlDocPtr pXmlDoc; using namespace gcu; gcpFragmentTool::gcpFragmentTool (gcpApplication *App): gcpTextTool (App, "Fragment") { } gcpFragmentTool::~gcpFragmentTool () { if (ClipboardData) xmlFree (ClipboardData); } static void on_get_data (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gcpFragmentTool* tool) { tool->OnGetData (clipboard, selection_data, info); } bool gcpFragmentTool::OnClicked () { if (m_Active && ((m_pObject == NULL) || (m_pObject->GetType() != FragmentType) || (m_Active != g_object_get_data (G_OBJECT (m_pData->Items[m_pObject]), "fragment")))) { if (!Unselect ()) return false; } gcpDocument* pDoc = m_pView->GetDoc (); if (!m_pObject) { gcpTheme *pTheme = pDoc->GetTheme (); gcpFragment *fragment = new gcpFragment (m_x0 / pTheme->GetZoomFactor (), m_y0 / pTheme->GetZoomFactor ()); pDoc->AddFragment (fragment); pDoc->AbortOperation (); pDoc->EmptyTranslationTable (); m_pObject = fragment; } struct GnomeCanvasPangoSelBounds bounds; bool need_update = false; gcpFragment *pFragment = NULL; if (m_pObject) { switch(m_pObject->GetType ()) { case AtomType: { gcpAtom* pAtom = (gcpAtom*) m_pObject; if (pAtom->GetTotalBondsNumber () > 1) return false; double x, y; pAtom->GetCoords (&x, &y); gcpMolecule *pMol = (gcpMolecule*) pAtom->GetMolecule (); map::iterator i; gcpBond *pBond = (gcpBond*) pAtom->GetFirstBond (i); pFragment = new gcpFragment (x, y); gcpAtom* pFragAtom = (gcpAtom*) pFragment->m_Atom; map::iterator ie; Object* electron = pAtom->GetFirstChild (ie); while (electron) { m_pView->Remove (electron); delete electron; electron = pAtom->GetNextChild (ie); } pMol->Remove (pAtom); pAtom->SetParent (NULL); pMol->AddFragment (pFragment); pDoc->AddFragment (pFragment); pDoc->AbortOperation (); gcpOperation* pOp = pDoc->GetNewOperation (GCP_MODIFY_OPERATION); pOp->AddObject (pAtom, 0); if (pBond) pOp->AddObject (pBond, 0); m_pView->Remove (pAtom); pFragAtom->SetZ (pAtom->GetZ ()); pFragAtom->SetId ((gchar*) pAtom->GetId ()); int n = pAtom->GetAttachedHydrogens (); if (n) { char* buf; if (n > 1) buf = g_strdup_printf ("H%d", n); else buf = g_strdup ("H"); bounds.start = bounds.cur = ((pAtom->GetBestSide ())? strlen (pAtom->GetSymbol ()): 0); pFragment->OnSelChanged (&bounds); gcp_pango_layout_replace_text (pFragment->GetLayout (), bounds.cur, 0, buf, pDoc->GetPangoAttrList ()); bounds.cur += strlen (buf); need_update = true; g_free (buf); } delete pAtom; if (pBond) { pBond->ReplaceAtom (pAtom, pFragAtom); pFragAtom->AddBond (pBond); pOp->AddObject (pBond, 1); } pOp->AddObject (pFragment, 1); pDoc->FinishOperation (); pDoc->EmptyTranslationTable (); m_pObject = pFragment; break; } case BondType: return false; case FragmentType: break; default: return false; } m_pObject->SetSelected (m_pWidget, SelStateUpdating); m_Active = GNOME_CANVAS_PANGO (g_object_get_data (G_OBJECT (m_pData->Items[m_pObject]), "fragment")); if (need_update) { gnome_canvas_pango_set_selection_bounds (m_Active, bounds.cur, bounds.cur); pFragment->AnalContent ((unsigned) bounds.start, (unsigned&) bounds.cur); pFragment->OnChanged (false); } m_pView->SetGnomeCanvasPangoActive (m_Active); g_object_set (G_OBJECT (m_Active), "editing", true, NULL); m_CurNode = ((gcpFragment*) m_pObject)->SaveSelected (); m_InitNode = ((gcpFragment*) m_pObject)->SaveSelected (); pDoc->GetWindow ()->ActivateActionWidget ("/MainMenu/FileMenu/SaveAsImage", false); } return true; } bool gcpFragmentTool::Deactivate () { if (m_Active && !Unselect ()) return false; return true; } void gcpFragmentTool::Activate () { } bool gcpFragmentTool::OnEvent (GdkEvent* event) { if (m_Active) { if ((event->type == GDK_KEY_PRESS) || (event->type == GDK_KEY_RELEASE)) { if (event->key.state & GDK_CONTROL_MASK) { switch(event->key.keyval) { case GDK_Right: case GDK_Left: case GDK_Up: case GDK_Down: case GDK_End: case GDK_Home: case GDK_Delete: case GDK_KP_Delete: case GDK_BackSpace: break; case GDK_z: m_pView->GetDoc ()->OnUndo (); return true; case GDK_Z: m_pView->GetDoc ()->OnRedo (); return true; case GDK_c: CopySelection (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); return true; case GDK_v: PasteSelection (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); return true; case GDK_x: CutSelection (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); return true; default: return false; } } if (event->key.keyval == GDK_KP_Enter || event->key.keyval == GDK_Return || event->key.keyval == GDK_space) return true; if (!g_utf8_validate (((GdkEventKey*) event)->string, -1, NULL)) { gsize r, w; gchar* newstr = g_locale_to_utf8 (((GdkEventKey*) event)->string, ((GdkEventKey*) event)->length, &r, &w, NULL); g_free (((GdkEventKey*) event)->string); ((GdkEventKey*) event)->string = newstr; ((GdkEventKey*) event)->length = w; } gnome_canvas_item_grab_focus ((GnomeCanvasItem*) m_Active); GnomeCanvasItemClass* klass = GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (m_Active)); klass->event ((GnomeCanvasItem*) m_Active, event); return true; } } return false; } bool gcpFragmentTool::CopySelection (GtkClipboard *clipboard) { if (!m_Active) return false; unsigned start, end; gcpFragment *fragment = (gcpFragment*) g_object_get_data (G_OBJECT (m_Active), "object"); fragment->GetSelectionBounds (start, end); if (start == end) return false; m_pData->Copy (clipboard); //To clean the xmlDoc xmlDocPtr pDoc = m_pData->GetXmlDoc (clipboard); if (!pDoc) return false; pDoc->children = xmlNewDocNode (pDoc, NULL, (xmlChar*) "chemistry", NULL); xmlNsPtr ns = xmlNewNs (pDoc->children, (xmlChar*) "http://www.nongnu.org/gchempaint", (xmlChar*) "gcp"); xmlSetNs (pDoc->children, ns); xmlNodePtr node = fragment->SaveSelection (pDoc); if (node) xmlAddChild (pDoc->children, node); else return false; gtk_clipboard_set_with_data (clipboard, targets, ClipboardFormats, (GtkClipboardGetFunc) on_get_data, (GtkClipboardClearFunc) on_clear_data, this); gtk_clipboard_request_contents (clipboard, gdk_atom_intern ("TARGETS", FALSE), (GtkClipboardReceivedFunc) on_receive_targets, m_pApp); return true; } bool gcpFragmentTool::CutSelection (GtkClipboard *clipboard) { if (!CopySelection (clipboard)) return false; return DeleteSelection (); } /** * This method does nothing and always return false because pasting something inside * a fragment is somewhat unsafe and will not be implemented in a foreseable future. */ bool gcpFragmentTool::OnReceive (GtkClipboard *clipboard, GtkSelectionData *data, int type) { return false; } bool gcpFragmentTool::Unselect () { if (!m_Active) return true; gcpFragment *fragment = (gcpFragment*) g_object_get_data (G_OBJECT (m_Active), "object"); if (fragment->Validate ()) return gcpTextTool::Unselect (); return false; } void gcpFragmentTool::OnGetData (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info) { xmlDocPtr pDoc = gcpWidgetData::GetXmlDoc (clipboard); if (ClipboardData) { xmlFree (ClipboardData); ClipboardData = NULL; } ClipboardDataType = info; gint size; if (info) { ClipboardData = xmlNodeGetContent (pDoc->children->children); size = strlen ((char*) ClipboardData); gtk_selection_data_set_text (selection_data, (const gchar*) ClipboardData, size); } else { xmlDocDumpFormatMemory (pDoc, &ClipboardData, &size, info); gtk_selection_data_set (selection_data, gdk_atom_intern (GCHEMPAINT_ATOM_NAME, FALSE), 8, (const guchar*) ClipboardData, size); } cleared = false; if (clipboard == gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)) m_pApp->ActivateWindowsActionWidget ("/MainMenu/EditMenu/Paste", true); }