/* * * Copyright (C) 2004 Luca Padovani * Copyright (C) 2005 Martin Sevior * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifdef ABI_PLUGIN_BUILTIN #define abi_plugin_register abipgn_abigochart_register #define abi_plugin_unregister abipgn_abigochart_unregister #define abi_plugin_supports_version abipgn_abigochart_supports_version #endif #include "pd_Document.h" #include "pp_Property.h" #include "pp_AttrProp.h" #include "ut_mbtowc.h" #include "gr_Painter.h" #include "gr_Image.h" #include "xad_Document.h" #include "xap_Module.h" #include "ap_App.h" #include "ie_imp_GOChart.h" #include "ie_imp.h" #include "ie_impGraphic.h" #include "ut_assert.h" #include "ut_debugmsg.h" #include "xap_Module.h" #include "xap_App.h" #include "xap_Frame.h" #include "fp_Run.h" #include "fv_View.h" #include "ap_Menu_Id.h" #include "ev_Menu_Actions.h" #include "ev_Menu.h" #include "ev_Menu_Layouts.h" #include "ev_Menu_Labels.h" #include "ev_EditMethod.h" #include "xap_Menu_Layouts.h" #include "ie_exp.h" #include "ie_types.h" #include "xap_Dialog_Id.h" #include "ap_Dialog_Id.h" #include "xap_Dlg_FileOpenSaveAs.h" #include "xap_DialogFactory.h" #include "xap_Dlg_MessageBox.h" #include "ap_Strings.h" #include "ap_Dialog_Latex.h" #include "ut_mbtowc.h" #include "xap_UnixFrameImpl.h" #include "ut_locale.h" #include "ut_sleep.h" #include "AbiGOChart.h" #include "gr_UnixImage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ut_sleep.h" #include #include #ifdef WIN32 #include #else #include #include #include #include "ut_files.h" #endif #include "gr_UnixGraphics.h" #include "xap_UnixGnomePrintGraphics.h" // // AbiContolGui object // #define ABI_CONTROL_GUI_TYPE (abi_control_gui_get_type ()) #define ABI_CONTROL_GUI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ABI_CONTROL_GUI_TYPE, AbiControlGUI)) #define IS_ABI_CONTROL_GUI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), ABI_CONTROL_GUI_TYPE)) class AbiGO_LocaleTransactor { public: AbiGO_LocaleTransactor (int category, const char * locale); ~AbiGO_LocaleTransactor (); private: int mCategory; char * mOldLocale; }; AbiGO_LocaleTransactor::AbiGO_LocaleTransactor (int category, const char * locale) : mCategory (category), mOldLocale (0) { mOldLocale = UT_strdup(setlocale(category, NULL)); go_setlocale (category, locale); // TODO: win32 may need to free old_locale } AbiGO_LocaleTransactor::~AbiGO_LocaleTransactor () { go_setlocale (mCategory, mOldLocale); FREEP(mOldLocale); } typedef struct _AbiControlGUI { GObject base; char *object_id; PD_Document * pDoc; GOChartView * pView; }; typedef struct _AbiControlGUI AbiControlGUI; typedef GObjectClass AbiControlGUIClass; static GType abi_control_gui_get_type (); // // GOCmdContext interface implementation for AbiControlGUI // // we should implement it at least for errors reporting /*static void abi_cmd_context_init (GOCmdContextClass *iface) { iface->get_password = abi_get_password; iface->set_sensitive = abi_set_sensitive; iface->error.error = abi_error_error; iface->error.error_info = abi_error_error_info; iface->progress_set = abi_progress_set; iface->progress_message_set = abi_progress_message_set; }*/ // // GogDataAllocator interface implementation for AbiControlGUI // static void abi_data_allocator_allocate (GogDataAllocator *dalloc, GogPlot *plot) { // SheetControlGUI *scg = wbcg_cur_scg (WORKBOOK_CONTROL_GUI (dalloc)); // sv_selection_to_plot (sc_view (SHEET_CONTROL (scg)), plot); } typedef struct { GtkEntry *entry; GogDataset *dataset; int dim_i; GogDataType data_type; } GraphDimEditor; static void cb_graph_dim_editor_update (GtkEntry *gee, GraphDimEditor *editor) { /* Ignore changes while we are insensitive. useful for displaying * values, without storing then as Data. Also ignore updates if the * dataset has been cleared via the weakref handler */ if (!GTK_WIDGET_SENSITIVE (gee) || editor->dataset == NULL) return; GOData *data = NULL; double val; char sep[2], col_sep[2], *end; sep[0] = format_get_arg_sep (); col_sep[0] = format_get_col_sep (); sep[1] = col_sep[1]= 0; char const* str = gtk_entry_get_text (gee); if (str == NULL) return; data = NULL; switch (editor->data_type) { case GOG_DATA_SCALAR: if (!*str) break; val = g_ascii_strtod (str, &end); if (*end == 0) data = go_data_scalar_val_new (val); else data = go_data_scalar_str_new (g_strdup (str), TRUE); break; case GOG_DATA_VECTOR: { // try to get values, but on error, get strings data = go_data_vector_val_new (NULL, 0, NULL); if (go_data_from_str (data, str)) break; g_object_unref (data); data = go_data_vector_str_new (NULL, 0, NULL); if (go_data_from_str (data, str)) break; g_object_unref (data); data = NULL; } break; case GOG_DATA_MATRIX: data = go_data_matrix_val_new (NULL, 0, 0, NULL); if (go_data_from_str (data, str)) break; g_object_unref (data); data = NULL; } if (!data) { /* display "Invalid Data message" */ } else gog_dataset_set_dim (editor->dataset, editor->dim_i, data, NULL); } static void cb_graph_dim_entry_unmap (GtkEntry *gee, GraphDimEditor *editor) { cb_graph_dim_editor_update (gee, /*FALSE, */editor); } static void cb_graph_dim_entry_unrealize (GtkEntry *gee, GraphDimEditor *editor) { cb_graph_dim_editor_update (gee, /*FALSE, */editor); } static void cb_dim_editor_weakref_notify (GraphDimEditor *editor, GogDataset *dataset) { g_return_if_fail (editor->dataset == dataset); editor->dataset = NULL; } static void graph_dim_editor_free (GraphDimEditor *editor) { if (editor->dataset) g_object_weak_unref (G_OBJECT (editor->dataset), (GWeakNotify) cb_dim_editor_weakref_notify, editor); g_free (editor); } static gpointer abi_data_allocator_editor (GogDataAllocator *dalloc, GogDataset *dataset, int dim_i, GogDataType data_type) { AbiControlGUI *acg = ABI_CONTROL_GUI (dalloc); GraphDimEditor *editor; GOData *val; editor = g_new (GraphDimEditor, 1); editor->dataset = dataset; editor->dim_i = dim_i; editor->data_type = data_type; editor->entry = GTK_ENTRY (gtk_entry_new ()); g_object_weak_ref (G_OBJECT (editor->dataset), (GWeakNotify) cb_dim_editor_weakref_notify, editor); // gnm_expr_entry_set_update_policy (editor->entry, // GTK_UPDATE_DISCONTINUOUS); val = gog_dataset_get_dim (dataset, dim_i); if (val != NULL) { char *txt = go_data_as_str (val); gtk_entry_set_text (editor->entry, txt); g_free (txt); } // gnm_expr_entry_set_flags (editor->entry, // GNM_EE_ABS_COL|GNM_EE_ABS_ROW, GNM_EE_MASK); /* g_signal_connect (G_OBJECT (editor->entry), "update", G_CALLBACK (cb_graph_dim_editor_update), editor);*/ g_signal_connect (G_OBJECT (editor->entry), "activate", G_CALLBACK (cb_graph_dim_editor_update), editor); g_signal_connect (G_OBJECT (editor->entry), "unmap", G_CALLBACK (cb_graph_dim_entry_unmap), editor); g_signal_connect (G_OBJECT (editor->entry), "unrealize", G_CALLBACK (cb_graph_dim_entry_unrealize), editor); g_object_set_data_full (G_OBJECT (editor->entry), "editor", editor, (GDestroyNotify) graph_dim_editor_free); return editor->entry; } static void abi_go_plot_data_allocator_init (GogDataAllocatorClass *iface) { iface->allocate = abi_data_allocator_allocate; iface->editor = abi_data_allocator_editor; } static void abi_control_gui_init (GObject *object) { AbiControlGUI *control = ABI_CONTROL_GUI (object); control->object_id = NULL; } static void abi_control_gui_finalize (GObject *object) { AbiControlGUI *control = ABI_CONTROL_GUI (object); if (control->object_id) g_free (control->object_id); } static void abi_control_gui_class_init (GObjectClass *klass) { klass->finalize = abi_control_gui_finalize; } GSF_CLASS_FULL (AbiControlGUI, abi_control_gui, NULL, NULL, abi_control_gui_class_init, NULL, abi_control_gui_init, G_TYPE_OBJECT, 0, GSF_INTERFACE (abi_go_plot_data_allocator_init, GOG_DATA_ALLOCATOR_TYPE); /*GSF_INTERFACE (abi_cmd_context_init, GO_CMD_CONTEXT_TYPE)*/) /* static void cb_graph_guru_done (WorkbookControlGUI *wbcg) { wbcg_edit_detach_guru (wbcg); wbcg_edit_finish (wbcg, WBC_EDIT_REJECT, NULL); } void sheet_object_graph_guru (WorkbookControlGUI *wbcg, GogGraph *graph, GClosure *closure) { GtkWidget *dialog = gog_guru (graph, GOG_DATA_ALLOCATOR (wbcg), GO_CMD_CONTEXT (wbcg), wbcg_toplevel (wbcg), closure); wbcg_edit_attach_guru (wbcg, dialog); g_object_set_data_full (G_OBJECT (dialog), "guru", wbcg, (GDestroyNotify) cb_graph_guru_done); }*/ // // AbiGOChart_addToMenus // ----------------------- // Adds "Object" "Gnome Office Chart" options to AbiWord's Main Menu. // static bool AbiGOChart_FileInsert(AV_View* v, EV_EditMethodCallData *d); static bool AbiGOChart_Create(AV_View* v, EV_EditMethodCallData *d); // FIXME make these translatable strings static const char * Object_MenuLabelObject = "Object"; static const char * Object_MenuTooltipObject = "Insert Embeddable Object"; static const char* AbiGOChart_MenuLabelInsert = "Gnome Office Chart"; static const char* AbiGOChart_MenuTooltipInsert = "Create a chart"; /* static const char * AbiMathView_MenuLabelEquation = NULL; static const char * AbiMathView_MenuTooltipEquation = NULL; static const char* AbiMathView_MenuLabelFileInsert = NULL; static const char* AbiMathView_MenuTooltipFileInsert = NULL; static const char* AbiMathView_MenuLabelLatexInsert = NULL; static const char* AbiMathView_MenuTooltipLatexInsert = NULL; */ static void AbiGOChart_addToMenus() { // First we need to get a pointer to the application itself. XAP_App *pApp = XAP_App::getApp(); // // Translated Strings // // const XAP_StringSet * pSS = pApp->getStringSet(); // AbiMathView_MenuLabelEquation= pSS->getValue(AP_STRING_ID_MENU_LABEL_INSERT_EQUATION); // AbiMathView_MenuTooltipEquation = pSS->getValue(AP_STRING_ID_MENU_LABEL_TOOLTIP_INSERT_EQUATION); // AbiMathView_MenuLabelFileInsert = pSS->getValue(AP_STRING_ID_MENU_LABEL_INSERT_EQUATION_FILE); // AbiMathView_MenuTooltipFileInsert = pSS->getValue(AP_STRING_ID_MENU_LABEL_TOOLTIP_INSERT_EQUATION_FILE); // Create an EditMethod that will link our method's name with // it's callback function. This is used to link the name to // the callback. EV_EditMethod *myEditMethodFile = new EV_EditMethod( "AbiGOChart_Create", // name of callback function AbiGOChart_Create, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); // Now we need to get the EditMethod container for the application. // This holds a series of Edit Methods and links names to callbacks. EV_EditMethodContainer* pEMC = pApp->getEditMethodContainer(); // We have to add our EditMethod to the application's EditMethodList // so that the application will know what callback to call when a call // to "AbiMathView_FileInsert" is received. pEMC->addEditMethod(myEditMethodFile); // Now we need to grab an ActionSet. This is going to be used later // on in our for loop. Take a look near the bottom. EV_Menu_ActionSet* pActionSet = pApp->getMenuActionSet(); // We need to go through and add the menu element to each "frame" // of the application. We can iterate through the frames by doing // XAP_App::getFrameCount() to tell us how many frames there are, // then calling XAP_App::getFrame(i) to get the i-th frame. int frameCount = pApp->getFrameCount(); XAP_Menu_Factory * pFact = pApp->getMenuFactory(); // Look to see if "Object" has been loaded already.. XAP_Menu_Id newObjectID= 0; /* XAP_Menu_Id newObjectID= pFact->addNewMenuAfter("Main",NULL,"Object",EV_MLF_BeginSubMenu); UT_DEBUGMSG(("newObjectID %d \n",newObjectID)); */ bool bObjectExists = true; if(newObjectID <= 0) { // Put it after Insert Picture in the Main menu // FIXME put it before! bObjectExists = false; newObjectID= pFact->addNewMenuBefore("Main",NULL,"&Picture",EV_MLF_BeginSubMenu); } UT_DEBUGMSG(("newObjectID %d \n",newObjectID)); pFact->addNewLabel(NULL,newObjectID,Object_MenuLabelObject, Object_MenuTooltipObject); // Create the Action that will be called. EV_Menu_Action* myObjectAction = new EV_Menu_Action( newObjectID, // id that the layout said we could use 1, // yes, we have a sub menu. 0, // no, we don't raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you NULL, // no callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); // Now what we need to do is add this particular action to the ActionSet // of the application. This forms the link between our new ID that we // got for this particular frame with the EditMethod that knows how to // call our callback function. pActionSet->addAction(myObjectAction); XAP_Menu_Id InsertGOChartID= pFact->addNewMenuAfter("Main",NULL,"Object",EV_MLF_Normal); UT_DEBUGMSG(("GOChart ID %d \n",InsertGOChartID)); pFact->addNewLabel(NULL, InsertGOChartID,AbiGOChart_MenuLabelInsert, AbiGOChart_MenuTooltipInsert); // Create the Action that will be called. EV_Menu_Action* myFileAction = new EV_Menu_Action( InsertGOChartID, // id that the layout said we could use 0, // no, we don't have a sub menu. 1, // yes, we raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you "AbiGOChart_Create", // name of callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); // Now what we need to do is add this particular action to the ActionSet // of the application. This forms the link between our new ID that we // got for this particular frame with the EditMethod that knows how to // call our callback function. pActionSet->addAction(myFileAction); if(!bObjectExists) { XAP_Menu_Id endObjectID= pFact->addNewMenuAfter("Main",NULL,AbiGOChart_MenuLabelInsert,EV_MLF_EndSubMenu); UT_DEBUGMSG(("End Object ID %d \n",endObjectID)); pFact->addNewLabel(NULL,endObjectID,NULL,NULL); // Create the Action that will be called. EV_Menu_Action* myEndObjectAction = new EV_Menu_Action( endObjectID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no, we raise a dialog. 0, // no, we don't have a checkbox. 0, // no radio buttons for me, thank you NULL, // name of callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); pActionSet->addAction(myEndObjectAction); } for(int i = 0;i < frameCount;++i) { // Get the current frame that we're iterating through. XAP_Frame* pFrame = pApp->getFrame(i); pFrame->rebuildMenus(); } } static void AbiGOChart_removeFromMenus () { // First we need to get a pointer to the application itself. XAP_App *pApp = XAP_App::getApp(); // remove the edit method EV_EditMethodContainer* pEMC = pApp->getEditMethodContainer() ; EV_EditMethod * pEM = ev_EditMethod_lookup ( "AbiGOChart_Create" ) ; pEMC->removeEditMethod ( pEM ) ; DELETEP( pEM ) ; // now remove crap from the menus int frameCount = pApp->getFrameCount(); XAP_Menu_Factory * pFact = pApp->getMenuFactory(); pFact->removeMenuItem("Main",NULL,AbiGOChart_MenuLabelInsert); for(int i = 0;i < frameCount;++i) { // Get the current frame that we're iterating through. XAP_Frame* pFrame = pApp->getFrame(i); pFrame->rebuildMenus(); } } XAP_Dialog_MessageBox::tAnswer s_CouldNotLoadFileMessage(XAP_Frame * pFrame, const char * pNewFile, UT_Error errorCode) { XAP_String_Id String_id; switch (errorCode) { case -301: String_id = AP_STRING_ID_MSG_IE_FileNotFound; break; case -302: String_id = AP_STRING_ID_MSG_IE_NoMemory; break; case -303: String_id = AP_STRING_ID_MSG_IE_UnsupportedType; //AP_STRING_ID_MSG_IE_UnknownType; break; case -304: String_id = AP_STRING_ID_MSG_IE_BogusDocument; break; case -305: String_id = AP_STRING_ID_MSG_IE_CouldNotOpen; break; case -306: String_id = AP_STRING_ID_MSG_IE_CouldNotWrite; break; case -307: String_id = AP_STRING_ID_MSG_IE_FakeType; break; case -311: String_id = AP_STRING_ID_MSG_IE_UnsupportedType; break; default: String_id = AP_STRING_ID_MSG_ImportError; } return pFrame->showMessageBox(String_id, XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK, pNewFile); } static bool s_AskForGOChartPathname(XAP_Frame * pFrame, char ** ppPathname, IEGraphicFileType * iegft) { // raise the file-open dialog for inserting a MathML equation. // return a_OK or a_CANCEL depending on which button // the user hits. // return a pointer a UT_strdup()'d string containing the // pathname the user entered -- ownership of this goes // to the caller (so free it when you're done with it). UT_DEBUGMSG(("s_AskForGOChartPathname: frame %p\n", pFrame)); UT_return_val_if_fail (ppPathname, false); *ppPathname = NULL; pFrame->raise(); XAP_DialogFactory * pDialogFactory = static_cast(pFrame->getDialogFactory()); XAP_Dialog_FileOpenSaveAs * pDialog = static_cast(pDialogFactory->requestDialog(XAP_DIALOG_ID_INSERTOBJECT)); UT_return_val_if_fail (pDialog, false); pDialog->setCurrentPathname(NULL); pDialog->setSuggestFilename(false); // to fill the file types popup list, we need to convert AP-level // ImpGraphic descriptions, suffixes, and types into strings. UT_uint32 filterCount = IE_ImpGraphic::getImporterCount(); const char ** szDescList = static_cast(UT_calloc(filterCount + 1, sizeof(char *))); const char ** szSuffixList = static_cast(UT_calloc(filterCount + 1, sizeof(char *))); IEGraphicFileType * nTypeList = (IEGraphicFileType *) UT_calloc(filterCount + 1, sizeof(IEGraphicFileType)); UT_uint32 k = 0; while (IE_ImpGraphic::enumerateDlgLabels(k, &szDescList[k], &szSuffixList[k], &nTypeList[k])) k++; pDialog->setFileTypeList(szDescList, szSuffixList, static_cast(nTypeList)); if (iegft != NULL) pDialog->setDefaultFileType(*iegft); pDialog->runModal(pFrame); XAP_Dialog_FileOpenSaveAs::tAnswer ans = pDialog->getAnswer(); bool bOK = (ans == XAP_Dialog_FileOpenSaveAs::a_OK); if (bOK) { const char * szResultPathname = pDialog->getPathname(); UT_DEBUGMSG(("OBJECT Path Name selected = %s \n",szResultPathname)); if (szResultPathname && *szResultPathname) UT_cloneString(*ppPathname,szResultPathname); UT_sint32 type = pDialog->getFileType(); // If the number is negative, it's a special type. // Some operating systems which depend solely on filename // suffixes to identify type (like Windows) will always // want auto-detection. if (type < 0) switch (type) { case XAP_DIALOG_FILEOPENSAVEAS_FILE_TYPE_AUTO: // do some automagical detecting *iegft = IEGFT_Unknown; break; default: // it returned a type we don't know how to handle UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } else *iegft = static_cast(pDialog->getFileType()); } FREEP(szDescList); FREEP(szSuffixList); FREEP(nTypeList); pDialogFactory->releaseDialog(pDialog); return bOK; } // // AbiMathView_FileInsert // ------------------- // This is the function that we actually call to insert the MathML. // bool AbiGOChart_FileInsert(AV_View* v, EV_EditMethodCallData *d) { // Get the current view that the user is in. XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); FV_View* pView = static_cast(pFrame->getCurrentView()); PD_Document * pDoc = static_cast(pFrame->getCurrentDoc()); char* pNewFile = NULL; IEGraphicFileType iegft = IEGFT_Unknown; bool bOK = s_AskForGOChartPathname(pFrame,&pNewFile,&iegft); if (!bOK || !pNewFile) { UT_DEBUGMSG(("ARRG! bOK = %d pNewFile = %x \n",bOK,pNewFile)); return false; } UT_UTF8String sNewFile = pNewFile; // we own storage for pNewFile and must free it. FREEP(pNewFile); UT_DEBUGMSG(("fileInsertObject: loading [%s]\n",sNewFile.utf8_str())); IE_Imp_Object * pImpObject = new IE_Imp_Object(pDoc); UT_Error errorCode = pImpObject->importFile(sNewFile.utf8_str()); if(errorCode != UT_OK) { s_CouldNotLoadFileMessage(pFrame, sNewFile.utf8_str(), errorCode); DELETEP(pImpObject); return false; } // Insert the object const char* mimetypeGOChart = "application/x-goffice-graph"; const char * szProps = "embed-type: GOChart"; UT_ByteBuf * pBuf = pImpObject->getByteBuf(); pView->cmdInsertEmbed(pBuf,pView->getPoint(),mimetypeGOChart,szProps); DELETEP(pImpObject); return true; } // // AbiMathView_FileInsert // ------------------- // This is the function that we actually call to create the Chart. // static void graph_user_config_free_data (gpointer data, GClosure *closure) { closure->data = NULL; } static void cb_update_graph (GogGraph *graph, gpointer data) { g_return_if_fail (IS_GOG_GRAPH (graph)); AbiControlGUI *acg = ABI_CONTROL_GUI (data); acg->pView->SetGuru (NULL); AbiGO_LocaleTransactor tn(LC_NUMERIC, "C"); AbiGO_LocaleTransactor tm(LC_MONETARY, "C"); GsfOutput* output = gsf_output_memory_new (); GsfXMLOut* xml = gsf_xml_out_new (output); gog_object_write_xml_sax(GOG_OBJECT (graph), xml); UT_Byte const *bytes = gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (output)); UT_ByteBuf myByteBuf; myByteBuf.append(bytes, gsf_output_size (output)); FV_View* pView = acg->pView->getRun ()->getBlock ()->getView (); const char* mimetypeGOChart = "application/x-goffice-graph"; const char * szProps="embed-type: GOChart"; UT_DEBUGMSG(("Doing Embed Update from GOG callback \n")); pView->cmdUpdateEmbed(acg->pView->getRun (), &myByteBuf,mimetypeGOChart,szProps); g_object_unref (xml); g_object_unref (output); g_object_unref (acg); } static void guru_destroyed_cb (GOChartView *pView) { pView->SetGuru (NULL); } bool AbiGOChart_Create(AV_View* v, EV_EditMethodCallData *d) { XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); XAP_UnixFrameImpl *pFrameImpl = static_cast(pFrame->getFrameImpl()); FV_View* pView = static_cast(pFrame->getCurrentView()); UT_ByteBuf myByteBuf; static unsigned id = 0; AbiControlGUI *acg = ABI_CONTROL_GUI (g_object_new (ABI_CONTROL_GUI_TYPE, NULL)); acg->pDoc = static_cast(pFrame->getCurrentDoc()); GogGraph *graph = (GogGraph *) g_object_new (GOG_GRAPH_TYPE, NULL); /* by default, create one chart and add it to the graph */ gog_object_add_by_name (GOG_OBJECT (graph), "Chart", NULL); GsfOutput* output = gsf_output_memory_new (); GsfXMLOut* xml = gsf_xml_out_new (output); { AbiGO_LocaleTransactor tn(LC_NUMERIC, "C"); AbiGO_LocaleTransactor tm(LC_NUMERIC, "C"); gog_object_write_xml_sax (GOG_OBJECT (graph), xml); } UT_Byte const *bytes = gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (output)); myByteBuf.append(bytes, gsf_output_size (output)); const char* mimetypeGOChart = "application/x-goffice-graph"; const char * szProps="embed-type: GOChart"; PT_DocPosition pos = pView->getPoint(); pView->cmdInsertEmbed(&myByteBuf,pView->getPoint(),mimetypeGOChart,szProps); pView->cmdSelect(pos,pos+1); acg->pView = GR_GOChartManager::last_created_view; GtkWidget *dialog = gog_guru (graph, GOG_DATA_ALLOCATOR (acg), NULL /*GO_CMD_CONTEXT (wbcg)*/, GTK_WINDOW(pFrameImpl->getTopLevelWindow()), g_cclosure_new (G_CALLBACK (cb_update_graph), acg, (GClosureNotify) graph_user_config_free_data)); acg->pView->SetGuru (dialog); g_signal_connect_swapped (G_OBJECT (dialog), "destroy", G_CALLBACK (guru_destroyed_cb), acg->pView); g_object_unref (xml); g_object_unref (output); g_object_unref (G_OBJECT (graph)); return true; } GR_AbiGOChartItems::GR_AbiGOChartItems(void): m_iAPI(0), m_bHasSnapshot(false) { } GR_AbiGOChartItems::~GR_AbiGOChartItems(void) { } GR_GOChartManager::GR_GOChartManager(GR_Graphics* pG) : GR_EmbedManager(pG), m_CurrentUID(-1), m_pDoc(NULL) { m_vecGOChartView.clear(); m_vecItems.clear(); } GR_GOChartManager::~GR_GOChartManager() { UT_VECTOR_PURGEALL(GR_AbiGOChartItems *,m_vecItems); UT_VECTOR_PURGEALL(GOChartView *,m_vecGOChartView); } GR_EmbedManager * GR_GOChartManager::create(GR_Graphics * pG) { return static_cast(new GR_GOChartManager(pG)); } const char * GR_GOChartManager::getObjectType(void) const { return "GOChart"; } GOChartView * GR_GOChartManager::last_created_view = NULL; void GR_GOChartManager::initialize(void) { // Load the GOChart library } /*! * Create a specific GOChart view and associate it with a UID. */ UT_sint32 GR_GOChartManager::_makeGOChartView(void) { last_created_view = new GOChartView(this); m_vecGOChartView.addItem(last_created_view); return static_cast(m_vecGOChartView.getItemCount()-1); } void GR_GOChartManager::_loadGOChartXML(UT_sint32 uid, UT_UTF8String & sGOChartBuf) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); UT_return_if_fail(pGOChartView); pGOChartView->loadBuffer(sGOChartBuf); } void GR_GOChartManager::setDefaultFontSize(UT_sint32 uid, UT_sint32 iSize) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); UT_return_if_fail(pGOChartView); pGOChartView->setDefaultFontSize(iSize); } UT_sint32 GR_GOChartManager::makeEmbedView(AD_Document * pDoc, UT_uint32 api, const char * szDataID) { if(m_pDoc == NULL) { m_pDoc = static_cast(pDoc); } else { UT_ASSERT(m_pDoc == static_cast(pDoc)); } UT_sint32 iNew = _makeGOChartView(); GR_AbiGOChartItems * pItem = new GR_AbiGOChartItems(); pItem->m_iAPI = api; pItem->m_bHasSnapshot = false; m_vecItems.addItem(pItem); UT_ASSERT(static_cast(m_vecItems.getItemCount()) == (iNew+1)); return iNew; } void GR_GOChartManager::makeSnapShot(UT_sint32 uid, UT_Rect & rec) { if(!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)) { return; } GR_AbiGOChartItems * pItem = m_vecItems.getNthItem(uid); UT_return_if_fail(pItem); const PP_AttrProp * pSpanAP = NULL; PT_AttrPropIndex api = pItem->m_iAPI; bool bHaveProp = m_pDoc->getAttrProp(api, &pSpanAP); UT_return_if_fail(bHaveProp); const char * pszDataID = NULL; bool bFoundDataID = pSpanAP->getAttribute("dataid", pszDataID); if(pItem->m_bHasSnapshot) { updatePNGSnapshot(static_cast(m_pDoc),rec,pszDataID); } else { createPNGSnapshot(static_cast(m_pDoc),rec,pszDataID); pItem->m_bHasSnapshot = true; } } bool GR_GOChartManager::isDefault(void) { return false; } bool GR_GOChartManager::createPNGSnapshot(AD_Document * pDoc, UT_Rect & rec, const char * szDataID) { if(isDefault()) { return false; } if((rec.width == 0) || (rec.height ==0)) { return false; } GR_Painter painter(getGraphics()); GR_Image * pImage = painter.genImageFromRectangle(rec); if(pImage == NULL) { return false; } UT_ByteBuf * pBuf = NULL; pImage->convertToBuffer(&pBuf); UT_UTF8String sID = "snapshot-png-"; sID += szDataID; const char* mimetypePNG = NULL; mimetypePNG = UT_strdup("image/png"); pDoc->createDataItem(sID.utf8_str(),false,reinterpret_cast< const UT_ByteBuf *>(pBuf),mimetypePNG,NULL); delete pBuf; delete pImage; return true; } bool GR_GOChartManager::updatePNGSnapshot(AD_Document * pDoc, UT_Rect & rec, const char * szDataID) { if(isDefault()) { return false; } GR_Painter painter(getGraphics()); GR_Image * pImage = painter.genImageFromRectangle(rec); if(pImage == NULL) { return false; } UT_ByteBuf * pBuf = NULL; pImage->convertToBuffer(&pBuf); UT_UTF8String sID = "snapshot-png-"; sID += szDataID; pDoc->replaceDataItem(sID.utf8_str(),reinterpret_cast< const UT_ByteBuf *>(pBuf)); delete pBuf; delete pImage; return true; } bool GR_GOChartManager::modify(UT_sint32 uid) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); pGOChartView->modify(); return false; } bool GR_GOChartManager::isEdittable(UT_sint32 uid) { return true; } void GR_GOChartManager::initializeEmbedView(UT_sint32 uid) { // FIXME write code for this. } void GR_GOChartManager::loadEmbedData(UT_sint32 uid) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); UT_return_if_fail(pGOChartView); const PP_AttrProp * pSpanAP = NULL; GR_AbiGOChartItems * pItem = m_vecItems.getNthItem(uid); UT_return_if_fail(pItem); PT_AttrPropIndex api = pItem->m_iAPI; bool bHaveProp = m_pDoc->getAttrProp(api, &pSpanAP); UT_return_if_fail(bHaveProp); const char * pszDataID = NULL; bool bFoundDataID = pSpanAP->getAttribute("dataid", pszDataID); UT_UTF8String sGOChartXML; if (bFoundDataID && pszDataID) { const UT_ByteBuf * pByteBuf = NULL; bFoundDataID = m_pDoc->getDataItemDataByName(pszDataID, const_cast(&pByteBuf), NULL, NULL); if (bFoundDataID) { UT_UCS4_mbtowc myWC; sGOChartXML.appendBuf( *pByteBuf, myWC); } } UT_return_if_fail(bFoundDataID); UT_return_if_fail(pszDataID); UT_DEBUGMSG(("GO Chart string is... \n %s \n",sGOChartXML.utf8_str())); _loadGOChartXML(uid, sGOChartXML); } UT_sint32 GR_GOChartManager::getWidth(UT_sint32 uid) { // FIXME write code this draws a square return 5000; } UT_sint32 GR_GOChartManager::getAscent(UT_sint32 uid) { // FIXME write code this draws a square return 5000; } UT_sint32 GR_GOChartManager::getDescent(UT_sint32 uid) { // FIXME write code return 0; } void GR_GOChartManager::setColor(UT_sint32 uid, UT_RGBColor c) { // FIXME write code } /*! * This method renders the GOChart identified by uid onto the screen * rectangle given by rec */ void GR_GOChartManager::render(UT_sint32 uid, UT_Rect & rec) { // FIXME write code GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); UT_return_if_fail(pGOChartView); pGOChartView->render(rec); } void GR_GOChartManager::releaseEmbedView(UT_sint32 uid) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); delete pGOChartView; m_vecGOChartView.setNthItem(uid,NULL,NULL); //NULL it out so we don't affect the other uid's } bool GR_GOChartManager::convert(UT_uint32 iConType, UT_ByteBuf & From, UT_ByteBuf & To) { return false; } void GR_GOChartManager::setRun(UT_sint32 uid, fp_Run *pRun) { GOChartView * pGOChartView = m_vecGOChartView.getNthItem(uid); pGOChartView->SetRun (pRun); } GOChartView::GOChartView(GR_GOChartManager * pGOMan): m_pGOMan(pGOMan) { m_Graph = NULL; m_Image = NULL; m_Renderer = GOG_RENDERER (g_object_new (GOG_RENDERER_PIXBUF_TYPE, NULL)); pix_width = pix_height = 0; width = height = 0; m_Guru = NULL; } GOChartView::~GOChartView(void) { g_object_unref (m_Renderer); if (m_Graph) g_object_unref (m_Graph); if (m_Image) delete m_Image; if (m_Guru) gtk_widget_destroy (m_Guru); } void GOChartView::render(UT_Rect & rec) { if((rec.width == 0) || (rec.height ==0)) { return; } if (m_pGOMan->getGraphics()->queryProperties(GR_Graphics::DGP_PAPER)) { XAP_UnixGnomePrintGraphics * pUGG = static_cast< XAP_UnixGnomePrintGraphics *>(m_pGOMan->getGraphics()); GnomePrintContext *ctx = pUGG->getGnomePrintContext(); UT_sint32 myWidth = pUGG->tdu(rec.width); UT_sint32 myHeight = pUGG->tdu(rec.height); UT_sint32 x = pUGG->tdu(rec.left); UT_sint32 y = pUGG->tdu(rec.top); // // gnome_print places y = 0 at the bottom of the page // and as y increases, it gets placed further from the bottom. // // This is the opposite of AbiWord where y = 0 is the top // and y > 0 is further from the top. // // scale_ydir fixes this (and gets the landscape/portrait right // too). // y = pUGG->scale_ydir(y); gnome_print_gsave (ctx); gnome_print_translate (ctx, x, y+myHeight); gog_graph_print_to_gnome_print(m_Graph,ctx,myWidth,myHeight); gnome_print_grestore(ctx); } else { GR_Graphics *pUGG = m_pGOMan->getGraphics(); UT_sint32 _width = pUGG->tdu(rec.width); UT_sint32 _height = pUGG->tdu(rec.height); UT_sint32 x = pUGG->tdu(rec.left); UT_sint32 y = pUGG->tdu(rec.top); UT_sint32 zoom = pUGG->getZoomPercentage (); UT_sint32 real_width = _width * 100 / zoom; UT_sint32 real_height = _height * 100 / zoom; if (real_width != width || real_height != height) { width = real_width; height = real_height; gog_graph_set_size (m_Graph, width, height); } if (_width != pix_width || _height != pix_height) { GdkPixbuf *pixbuf; pix_width = _width; pix_height = _height; gog_renderer_pixbuf_update (GOG_RENDERER_PIXBUF (m_Renderer), _width, _height, 1.0); if (m_Image) delete m_Image; pixbuf = gog_renderer_pixbuf_get (GOG_RENDERER_PIXBUF (m_Renderer)); m_Image = new GR_UnixImage(NULL, pixbuf); g_object_ref(pixbuf); m_Image->scaleImageTo(m_pGOMan->getGraphics(),rec); } GR_Painter painter(m_pGOMan->getGraphics()); painter.drawImage (m_Image, rec.left, rec.top - rec.height); } } void GOChartView::loadBuffer(UT_UTF8String & sGOChartXML) { if (m_Graph) g_object_unref (m_Graph); AbiGO_LocaleTransactor tn(LC_NUMERIC, "C"); AbiGO_LocaleTransactor tm(LC_MONETARY, "C"); xmlDocPtr xml = xmlParseMemory((const char*)sGOChartXML.utf8_str(), sGOChartXML.byteLength()); m_Graph = GOG_GRAPH (gog_object_new_from_xml (NULL, xml->children)); if (m_Graph) g_object_set (G_OBJECT (m_Renderer), "model", m_Graph, NULL); width = height = 0; // force pixbuf update } void GOChartView::setDefaultFontSize( UT_sint32 iSize) { } void GOChartView::modify() { XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); XAP_UnixFrameImpl *pFrameImpl = static_cast(pFrame->getFrameImpl()); AbiControlGUI *acg = ABI_CONTROL_GUI (g_object_new (ABI_CONTROL_GUI_TYPE, NULL)); acg->pDoc = static_cast(pFrame->getCurrentDoc()); acg->pView = this; GtkWidget *dialog = gog_guru (m_Graph, GOG_DATA_ALLOCATOR (acg), NULL /*GO_CMD_CONTEXT (wbcg)*/, GTK_WINDOW(pFrameImpl->getTopLevelWindow()), g_cclosure_new (G_CALLBACK (cb_update_graph), acg, (GClosureNotify) graph_user_config_free_data)); acg->pView->SetGuru (dialog); g_signal_connect_swapped (G_OBJECT (dialog), "destroy", G_CALLBACK (guru_destroyed_cb), acg->pView); } static UT_uint32 GOChartManagerUID = 0; static GR_GOChartManager *pGOChartManager = NULL; // we use a reference-counted sniffer static IE_Imp_Object_Sniffer * m_impSniffer = 0; ABI_PLUGIN_DECLARE(AbiGOChart) // ----------------------------------------------------------------------- // // Abiword Plugin Interface // // ----------------------------------------------------------------------- ABI_FAR_CALL int abi_plugin_register (XAP_ModuleInfo * mi) { mi->name = "AbiGOChart"; mi->desc = "The plugin enables Gnome Office Charts to be displayed in AbiWord"; mi->version = ABI_VERSION_STRING; mi->author = "Martin Sevior "; mi->usage = "No Usage"; // Add to AbiWord's plugin importers m_impSniffer = new IE_Imp_Object_Sniffer(); IE_Imp::registerImporter (m_impSniffer); // Add to AbiWord's plugin listeners XAP_App * pApp = XAP_App::getApp(); pGOChartManager = new GR_GOChartManager(NULL); GOChartManagerUID = pApp->registerEmbeddable(pGOChartManager); // the message below makes valgrind scream because there is only one parameter where // 2 are expected. disabled. xxx_UT_DEBUGMSG(("Class %x created! Listener Id %d \n", GOChartManagerUID)); // Add to AbiWord's menus. AbiGOChart_addToMenus(); /* Initialize libgoffice */ libgoffice_init (); /* Initialize plugins manager */ go_plugins_init (NULL, NULL, NULL, NULL, TRUE, GO_PLUGIN_LOADER_MODULE_TYPE); /* Ensure some types are created */ GO_DATA_SCALAR_STR_TYPE; GO_DATA_VECTOR_STR_TYPE; GO_DATA_SCALAR_VAL_TYPE; GO_DATA_VECTOR_VAL_TYPE; GO_DATA_MATRIX_VAL_TYPE; return 1; } ABI_FAR_CALL int abi_plugin_unregister (XAP_ModuleInfo * mi) { mi->name = 0; mi->desc = 0; mi->version = 0; mi->author = 0; mi->usage = 0; IE_Imp::unregisterImporter (m_impSniffer); if (!m_impSniffer->unref()) { m_impSniffer = 0; } XAP_App * pApp = XAP_App::getApp(); pApp->unRegisterEmbeddable(GOChartManagerUID); DELETEP(pGOChartManager); AbiGOChart_removeFromMenus(); return 1; } ABI_FAR_CALL int abi_plugin_supports_version (UT_uint32 major, UT_uint32 minor, UT_uint32 release) { return 1; }