/* AbiCollab- Code to enable the modification of remote documents. * Copyright (C) 2005 by 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. */ #ifndef ABI_COLLABRECORDINTERFACE_H #define ABI_COLLABRECORDINTERCACE_H #include "ut_assert.h" #include "ut_debugmsg.h" #include "xap_Module.h" #include "xap_App.h" #include "xap_Frame.h" #include "fv_View.h" #include "xav_View.h" #include "xav_Listener.h" #include "ut_assert.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 "ut_types.h" #include "ut_misc.h" #include "ut_units.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 #include #include "RecordPackets.h" #include "AbiCollabRecord_Interface.h" // FIXME make these translatable strings static const char * szRecordFile = "Record"; static const char * szRecordFileTip = "Record edits to file"; static const char * szReplayFile = "Replay from file"; static const char * szReplayFileTip = "Replay a file containing a record of previous edits"; const char * AbiCollabRecord_addToMenus(const char * szLastMenu) { // 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(); // it's callback function. This is used to link the name to // the callback. EV_EditMethod *myEditMethodRecordFile = new EV_EditMethod( "AbiCollab_RecordFile", // name of callback function AbiCollabRecord_RecordFile, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); EV_EditMethod *myEditMethodReplayFile = new EV_EditMethod( "AbiCollab_ReplayFile", // name of callback function AbiCollabRecord_ReplayFile, // callback function itself. 0, // no additional data required. "" // description -- allegedly never used for anything ); EV_EditMethodContainer* pEMC = pApp->getEditMethodContainer(); pEMC->addEditMethod(myEditMethodRecordFile); pEMC->addEditMethod(myEditMethodReplayFile); // 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 newRecordIDFile= 0; XAP_Menu_Id newReplayIDFile= 0; UT_DEBUGMSG(("LastMenu label |%s| \n",szLastMenu)); newRecordIDFile= pFact->addNewMenuAfter("Main",NULL,szLastMenu,EV_MLF_Normal); pFact->addNewLabel(NULL,newRecordIDFile,szRecordFile, szRecordFileTip); UT_DEBUGMSG(("Record File ID %d \n",newRecordIDFile)); newReplayIDFile= pFact->addNewMenuAfter("Main",NULL,szRecordFile,EV_MLF_Normal); pFact->addNewLabel(NULL,newReplayIDFile,szReplayFile, szReplayFileTip); UT_DEBUGMSG(("ReplayFile ID %d \n",newReplayIDFile)); EV_Menu_Action* myActionRecordFile = new EV_Menu_Action( newRecordIDFile, // 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 "AbiCollab_RecordFile", // name of callback function to call. NULL, // don't know/care what this is for NULL // don't know/care what this is for ); EV_Menu_Action* myActionReplayFile = new EV_Menu_Action( newReplayIDFile, // 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 "AbiCollab_ReplayFile", // 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(myActionRecordFile); pActionSet->addAction(myActionReplayFile); // return the last menu item we added return szReplayFile; } void AbiCollabRecord_removeFromMenus() { // First we need to get a pointer to the application itself. XAP_App *pApp = XAP_App::getApp(); EV_EditMethodContainer* pEMC = pApp->getEditMethodContainer() ; EV_EditMethod * pEM = ev_EditMethod_lookup ( "AbiCollab_RecordFile" ) ; pEMC->removeEditMethod ( pEM ) ; DELETEP( pEM ) ; pEM = ev_EditMethod_lookup ( "AbiCollab_ReplayFile" ) ; 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,szRecordFile); pFact->removeMenuItem("Main",NULL,szReplayFile); } static bool s_AskForRecordPathname(XAP_Frame * pFrame, char ** ppPathname) { // 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 g_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_AskForRecordToPathname: 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_RECORDTOFILE)); UT_return_val_if_fail (pDialog, false); pDialog->setCurrentPathname(NULL); pDialog->setSuggestFilename(false); 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(("MATHML Path Name selected = %s \n",szResultPathname)); if (szResultPathname && *szResultPathname) *ppPathname = g_strdup(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 break; default: // it returned a type we don't know how to handle UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } } else { /* todo */ } } pDialogFactory->releaseDialog(pDialog); return bOK; } static bool s_AskForReplayPathname(XAP_Frame * pFrame, char ** ppPathname) { // 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 g_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_AskForMathMLPathname: 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_REPLAYFROMFILE)); UT_return_val_if_fail (pDialog, false); pDialog->setCurrentPathname(NULL); pDialog->setSuggestFilename(false); /* TODO: add a "MathML (.xml)" entry to the file type list, and set is as the default file type pDialog->setFileTypeList(szDescList, szSuffixList, static_cast(nTypeList)); */ 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(("MATHML Path Name selected = %s \n",szResultPathname)); if (szResultPathname && *szResultPathname) *ppPathname = g_strdup(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 break; default: // it returned a type we don't know how to handle UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } } else { /* todo */ } } pDialogFactory->releaseDialog(pDialog); return bOK; } bool AbiCollabRecord_RecordFile(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()); UT_DEBUGMSG(("Attaching export to file listener to document %x \n",pDoc)); UT_uint32 lid = 0; char* pNewFile = NULL; bool bOK = s_AskForRecordPathname(pFrame,&pNewFile); if (!bOK) { // we own storage for pNewFile and must free it. FREEP(pNewFile); return false; } char * szFile = pNewFile; if (strncmp (pNewFile, "file://", 7) == 0) szFile += 7; else if (strncmp (pNewFile, "file:", 5) == 0) szFile += 5; UT_UTF8String sFileName = szFile; // we own storage for pNewFile and must free it. FREEP(pNewFile); UT_UTF8String sID(""); AbiCollab * pCollab = s_CollabFactoryContainer.createRecorder(pDoc,sID,false,&sFileName,NULL); pCollab->setDocument(pDoc); pCollab->setDocListenerId(lid); return true; } /** * Replay an exported description of an editing session from a file. */ bool AbiCollabRecord_ReplayFile(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()); UT_DEBUGMSG(("Importing from file into document %x \n",pDoc)); // // TODO fire up the openfile menu // char* pNewFile = NULL; bool bOK = s_AskForReplayPathname(pFrame, &pNewFile); if(!bOK) { // we own storage for pNewFile and must free it. FREEP(pNewFile); return false; } char * szFile = pNewFile; if (strncmp (pNewFile, "file://", 7) == 0) szFile += 7; else if (strncmp (pNewFile, "file:", 5) == 0) szFile += 5; UT_UTF8String sImport = szFile; UT_UTF8String sID(""); AbiCollabRecord * pCollab = static_cast(s_CollabFactoryContainer.createRecorder(pDoc,sID,false,NULL,&sImport)); pCollab->setDocument(pDoc); // // Replay the file // pCollab->replayFile(); // // Remove Listener for the document // if (!pDoc->removeListener(pCollab->getDocListenerId())) { UT_DEBUGMSG(("Eeeek, couldn't remove document listener!\n")); } // // Now delete the AbiCollab // s_CollabFactoryContainer.destroy(pDoc,sID); // we own storage for pNewFile and must free it. FREEP(pNewFile); return true; } #endif