/* AbiWord Gremlin Plugin * Copyright (C) 2001 Andrew Dunbar, 2007 Ryan Pavlik * * 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_gremlin_register #define abi_plugin_unregister abipgn_gremlin_unregister #define abi_plugin_supports_version abipgn_gremlin_supports_version #endif #include "xap_Module.h" #include "xap_App.h" #include "xap_Frame.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 "ut_string_class.h" #include "xap_Dialog_Id.h" #include "xap_DialogFactory.h" #include "xap_Dlg_Language.h" // This "gremlin" plugin is intended for testing of AbiWord // features, in particular AbiCollab. It will make changes to // a document randomly, at random intervals, when enabled. // In case it is not obvious, this is a developer plugin - not // intended for general use. // Based on the FreeTranslation plugin. Very loosely. // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- inline static UT_UCSChar* Gremlin_asciiToUcs( const char* text, int& length ) { // blatently borrowed from scripthappy // calculate the length of our text so we can create a UCS-2 // buffer of equal size. length = strlen( text ) ; // allocate UCS-2 character buffer of same size, plus room for // a null terminator. UT_UCSChar* ret = new UT_UCSChar[ length+1 ] ; // convert ascii to UCS-2. This is simply a cast-loop really. for( int i = 0; i < length; ++i ) { ret[ i ] = static_cast(text[ i ]) ; } // remember to null terminate the string. ret[ length ] = 0 ; // now return the string. return ret ; } // Gremlin_tinker // Make a random change to the document // This should be called at random intervals when the plugin is enabled. static void Gremlin_tinker(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()); } // // Gremlin_invoke // ------------------- // This is the function that we actually call to invoke the // gremlins. // It should be called when the user selects from the tools menu // static bool Gremlin_invoke(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()); // do gremlin stuff here. // TODO: Call this function after random periods of time, ad infinitum. //Gremlin_tinker(v,d); // select (action) // case insert UT_UCSChar * stringToInsert; // is my count supposed to include a null terminator? int howMany=39; stringToInsert=Gremlin_asciiToUcs("Im in ur document doin gremlin bizniss.", howMany); pView->cmdCharInsert ( stringToInsert, howMany ); return true; } static const char * Gremlin_MenuLabel = "Enable &Gremlins"; static const char * Gremlin_MenuTooltip = "Unleash gremlins to randomly change the document"; // TODO: Is this necessary anymore? We don't unload plugins during runtime... static void Gremlin_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 ( "Gremlin_invoke" ) ; 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,Gremlin_MenuLabel); pFact->removeMenuItem("contextText",NULL,Gremlin_MenuLabel); 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 Gremlin_addToMenus() { // First we need to get a pointer to the application itself. XAP_App * pApp = XAP_App::getApp(); // 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 * myEditMethod = new EV_EditMethod( "Gremlin_invoke", // name of callback function Gremlin_invoke, // 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 "Gremlin_invoke" is received. pEMC->addEditMethod(myEditMethod); // 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(); // // Put it in the context menu. // XAP_Menu_Id newID = pFact->addNewMenuAfter("contextText", NULL, "Bullets and &Numbering", EV_MLF_Normal); pFact->addNewLabel(NULL, newID, Gremlin_MenuLabel, Gremlin_MenuTooltip); // */ // // Also put it under word count in the main menu, // pFact->addNewMenuAfter("Main", NULL, "&Word Count", EV_MLF_Normal, newID); // Create the Action that will be called. EV_Menu_Action * myAction = new EV_Menu_Action( newID, // id that the layout said we could use 0, // no, we don't have a sub menu. 0, // no dialog. 0, // no, we don't have a checkbox. 0, "Gremlin_invoke", // 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(myAction); for (int i = 0; i < frameCount; ++i) { // Get the current frame that we're iterating through. XAP_Frame * pFrame = pApp->getFrame(i); pFrame->rebuildMenus(); } } // ----------------------------------------------------------------------- // // Abiword Plugin Interface // // ----------------------------------------------------------------------- ABI_PLUGIN_DECLARE ("AbiGremlin") ABI_FAR_CALL int abi_plugin_register(XAP_ModuleInfo * mi) { mi->name = "Gremlin plugin"; mi->desc = "Plugin to mischievously change an AbiWord document. Useful for testing/'fuzzing'."; mi->version = ABI_VERSION_STRING; mi->author = "Ryan Pavlik"; mi->usage = "No Usage"; // Add the gremlins to AbiWord's menus. Gremlin_addToMenus(); 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; Gremlin_RemoveFromMenus (); return 1; } ABI_FAR_CALL int abi_plugin_supports_version(UT_uint32 major, UT_uint32 minor, UT_uint32 release) { return 1; } /* //////////////////////////////////////////////// */