// -*- C++ -*-
/*
* GChemPaint text plugin
* fragmenttool.cc
*
* Copyright (C) 2003-2006 Jean Bréfort <jean.brefort@normalesup.org>
*
* 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 <gdk/gdkkeysyms.h>
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<Atom*, Bond*>::iterator i;
gcpBond *pBond = (gcpBond*) pAtom->GetFirstBond (i);
pFragment = new gcpFragment (x, y);
gcpAtom* pFragAtom = (gcpAtom*) pFragment->m_Atom;
map<string, Object*>::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);
}
syntax highlighted by Code2HTML, v. 0.9.1