// static void ModuleManager::Initialize(CommandHandler &cmdHandler) { wxArrayString audacityPathList = wxGetApp().audacityPathList; wxArrayString pathList; wxArrayString files; wxString pathVar; size_t i; // Code from LoadLadspa that might be useful in load modules. pathVar = wxGetenv(wxT("AUDACITY_MODULES_PATH")); if (pathVar != wxT("")) wxGetApp().AddMultiPathsToPathList(pathVar, pathList); for (i = 0; i < audacityPathList.GetCount(); i++) { wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH; wxGetApp().AddUniquePathToPathList(prefix + wxT("modules"), pathList); } #if defined(__WXMSW__) wxGetApp().FindFilesInPathList(wxT("*.dll"), pathList, files); #else wxGetApp().FindFilesInPathList(wxT("*.so"), pathList, files); #endif wxString saveOldCWD = ::wxGetCwd(); for (i = 0; i < files.GetCount(); i++) { // As a courtesy to some modules that might be bridges to // open other modules, we set the current working // directory to be the module's directory. wxString prefix = ::wxPathOnly(files[i]); ::wxSetWorkingDirectory(prefix); #ifdef EXPERIMENTAL_MODULE_PREFS int iModuleStatus = ModulePrefs::GetModuleStatus( files[i] ); if( iModuleStatus == kModuleDisabled ) continue; if( iModuleStatus == kModuleFailed ) continue; // New module? You have to go and explicitly enable it. if( iModuleStatus == kModuleNew ){ // To ensure it is noted in config file and so // appears on modules page. ModulePrefs::SetModuleStatus( files[i], kModuleNew); continue; } if( iModuleStatus == kModuleAsk ) #endif // JKC: I don't like prompting for the plug-ins individually // I think it would be better to show the module prefs page, // and let the user decide for each one. { wxString ShortName = wxFileName( files[i] ).GetName(); wxString msg; msg.Printf(_("Module \"%s\" found."), ShortName.c_str()); msg += _("\n\nOnly use modules from trusted sources"); const wxChar *buttons[] = {_("Yes"), _("No"), NULL}; // could add a button here for 'yes and remember that', and put it into the cfg file. Needs more thought. int action; action = ShowMultiDialog(msg, _("Audacity Module Loader"), buttons, _("Try and load this module?"), false); #ifdef EXPERIMENTAL_MODULE_PREFS // If we're not prompting always, accept the answer permanantly if( iModuleStatus == kModuleNew ){ iModuleStatus = (action==1)?kModuleDisabled : kModuleEnabled; ModulePrefs::SetModuleStatus( files[i], iModuleStatus ); } #endif if(action == 1){ // "No" continue; } } #ifdef EXPERIMENTAL_MODULE_PREFS // Before attempting to load, we set the state to bad. // That way, if we crash, we won't try again. ModulePrefs::SetModuleStatus( files[i], kModuleFailed ); #endif Module *module = new Module(files[i]); if (module->Load()) // it will get rejected if there are version problems { Get().mModules.Add(module); // We've loaded and initialised OK. // So look for special case functions: wxLogNull logNo; // Don't show wxWidgets errors if we can't do these. (Was: Fix bug 544.) // (a) for scripting. if( scriptFn == NULL ) scriptFn = (tpRegScriptServerFunc)(module->GetSymbol(wxT(scriptFnName))); // (b) for hijacking the entire Audacity panel. if( pPanelHijack==NULL ) { pPanelHijack = (tPanelFn)(module->GetSymbol(wxT(mainPanelFnName))); } #ifdef EXPERIMENTAL_MODULE_PREFS // Loaded successfully, restore the status. ModulePrefs::SetModuleStatus( files[i], iModuleStatus); #endif } else { // No need to save status, as we already set kModuleFailed. delete module; } } ::wxSetWorkingDirectory(saveOldCWD); // After loading all the modules, we may have a registered scripting function. if(scriptFn) { ScriptCommandRelay::SetCommandHandler(cmdHandler); ScriptCommandRelay::SetRegScriptServerFunc(scriptFn); NonGuiThread::StartChild(&ScriptCommandRelay::Run); } }
void ModuleManager::Initialize(CommandHandler &cmdHandler) { wxArrayString audacityPathList = wxGetApp().audacityPathList; wxArrayString pathList; wxArrayString files; wxString pathVar; size_t i; // Code from LoadLadspa that might be useful in load modules. pathVar = wxGetenv(wxT("AUDACITY_MODULES_PATH")); if (pathVar != wxT("")) wxGetApp().AddMultiPathsToPathList(pathVar, pathList); for (i = 0; i < audacityPathList.GetCount(); i++) { wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH; wxGetApp().AddUniquePathToPathList(prefix + wxT("modules"), pathList); } #if defined(__WXMSW__) wxGetApp().FindFilesInPathList(wxT("*.dll"), pathList, files); #else wxGetApp().FindFilesInPathList(wxT("*.so"), pathList, files); #endif for (i = 0; i < files.GetCount(); i++) { // As a courtesy to some modules that might be bridges to // open other modules, we set the current working // directory to be the module's directory. wxString saveOldCWD = ::wxGetCwd(); wxString prefix = ::wxPathOnly(files[i]); ::wxSetWorkingDirectory(prefix); #ifdef EXPERIMENTAL_MODULE_PREFS if( !IsAllowedModule( files[i] ) ) // don't try and check the in-date-ness before this as that means loading the module to call it's GetVersionString, which could do anything. #endif { wxString ShortName = wxFileName( files[i] ).GetName(); wxString msg; msg.Printf(_("Module \"%s\" found."), ShortName.c_str()); msg += _("\n\nOnly use modules from trusted sources"); const wxChar *buttons[] = {_("Yes"), _("No"), NULL}; // could add a button here for 'yes and remember that', and put it into the cfg file. Needs more thought. int action; action = ShowMultiDialog(msg, _("Module Loader"), buttons, _("Try and load this module?"), false); if(action == 1) // "No" continue; } Module *module = new Module(files[i]); if (module->Load()) // it will get rejected if there are version problems { mInstance->mModules.Add(module); // We've loaded and initialised OK. // So look for special case functions: wxLogNull logNo; // Don't show wxWidgets errors if we can't do these. (Was: Fix bug 544.) // (a) for scripting. if( scriptFn == NULL ) scriptFn = (tpRegScriptServerFunc)(module->GetSymbol(wxT(scriptFnName))); // (b) for hijacking the entire Audacity panel. if( pPanelHijack==NULL ) { pPanelHijack = (tPanelFn)(module->GetSymbol(wxT(mainPanelFnName))); } } else { delete module; } ::wxSetWorkingDirectory(saveOldCWD); } // After loading all the modules, we may have a registered scripting function. if(scriptFn) { ScriptCommandRelay::SetCommandHandler(cmdHandler); ScriptCommandRelay::SetRegScriptServerFunc(scriptFn); NonGuiThread::StartChild(&ScriptCommandRelay::Run); } }
int DirManager::ProjectFSCK(bool forceerror, bool silentlycorrect) { // get a rough guess of how many blockfiles will be found/processed // at each step by looking at the size of the blockfile hash int blockcount=blockFileHash.size(); int ret=0; int ndx; // enumerate *all* files in the project directory wxArrayString fnameList; wxArrayString orphanList; BlockHash missingAliasList; BlockHash missingAliasFiles; BlockHash missingSummaryList; BlockHash missingDataList; // this function is finally a misnomer rm_dash_rf_enumerate_prompt((projFull != wxT("")? projFull: mytemp), fnameList,wxEmptyString,1,0,blockcount, _("Inspecting project file data...")); // enumerate orphaned blockfiles BlockHash diskFileHash; for(ndx=0;ndx<(int)fnameList.GetCount();ndx++){ wxFileName fullname = fnameList[ndx]; wxString basename=fullname.GetName(); diskFileHash[basename.c_str()]=0; // just needs to be defined if(blockFileHash.find(basename) == blockFileHash.end()){ // the blockfile on disk is orphaned orphanList.Add(fullname.GetFullPath()); if (!silentlycorrect) wxLogWarning(_("Orphaned blockfile: (%s)"), fullname.GetFullPath().c_str()); } } // enumerate missing alias files BlockHash::iterator i=blockFileHash.begin(); while(i != blockFileHash.end()) { wxString key=i->first; BlockFile *b=i->second; if(b->IsAlias()){ wxFileName aliasfile=((AliasBlockFile *)b)->GetAliasedFile(); if(aliasfile.GetFullPath()!=wxEmptyString && !wxFileExists(aliasfile.GetFullPath())){ missingAliasList[key]=b; missingAliasFiles[aliasfile.GetFullPath().c_str()]=0; // simply must be defined } } i++; } if (!silentlycorrect) { i=missingAliasFiles.begin(); while(i != missingAliasFiles.end()) { wxString key=i->first; wxLogWarning(_("Missing alias file: (%s)"),key.c_str()); i++; } } // enumerate missing summary blockfiles i=blockFileHash.begin(); while(i != blockFileHash.end()) { wxString key=i->first; BlockFile *b=i->second; if(b->IsAlias()){ /* don't look in hash; that might find files the user moved that the Blockfile abstraction can't find itself */ wxFileName file=MakeBlockFilePath(key); file.SetName(key); file.SetExt(wxT("auf")); if(!wxFileExists(file.GetFullPath().c_str())){ missingSummaryList[key]=b; if (!silentlycorrect) wxLogWarning(_("Missing summary file: (%s.auf)"), key.c_str()); } } i++; } // enumerate missing data blockfiles i=blockFileHash.begin(); while(i != blockFileHash.end()) { wxString key=i->first; BlockFile *b=i->second; if(!b->IsAlias()){ wxFileName file=MakeBlockFilePath(key); file.SetName(key); file.SetExt(wxT("au")); if(!wxFileExists(file.GetFullPath().c_str())){ missingDataList[key]=b; if (!silentlycorrect) wxLogWarning(_("Missing data file: (%s.au)"), key.c_str()); } } i++; } // First, pop the log so the user can see what be up. if(forceerror || (!orphanList.IsEmpty() || !missingAliasList.empty() || !missingDataList.empty() || !missingSummaryList.empty()) && !silentlycorrect){ wxLogWarning(_("Project check found inconsistencies inspecting the loaded project data;\nclick 'Details' for a complete list of errors, or 'OK' to proceed to more options.")); wxLog::GetActiveTarget()->Flush(); // Flush is both modal // (desired) and will clear the log (desired) } // report, take action // If in "silently correct" mode, leave orphaned blockfiles alone // (they will be deleted when project is saved the first time) if(!orphanList.IsEmpty() && !silentlycorrect){ wxString promptA = _("Project check found %d orphaned blockfile[s]. These files are\nunused and probably left over from a crash or some other bug.\nThey should be deleted to avoid disk contention."); wxString prompt; prompt.Printf(promptA,(int)orphanList.GetCount()); const wxChar *buttons[]={_("Delete orphaned files [safe and recommended]"), _("Continue without deleting; silently work around the extra files"), _("Close project immediately with no changes"),NULL}; int action = ShowMultiDialog(prompt, _("Warning"), buttons); if(action==2)return (ret | FSCKstatus_CLOSEREQ); if(action==0){ ret |= FSCKstatus_CHANGED; for(ndx=0;ndx<(int)orphanList.GetCount();ndx++){ wxRemoveFile(orphanList[ndx]); } } } // Deal with any missing aliases if(!missingAliasList.empty()){ int action; if (silentlycorrect) { // In "silently correct" mode, we always create silent blocks. This // makes sure the project is complete even if we open it again. action = 0; } else { wxString promptA = _("Project check detected %d input file[s] being used in place\n('alias files') are now missing. There is no way for Audacity\nto recover these files automatically; you may choose to\npermanently fill in silence for the missing files, temporarily\nfill in silence for this session only, or close the project now\nand try to restore the missing files by hand."); wxString prompt; prompt.Printf(promptA,missingAliasFiles.size()); const wxChar *buttons[]={_("Replace missing data with silence [permanent upon save]"), _("Temporarily replace missing data with silence [this session only]"), _("Close project immediately with no further changes"),NULL}; action = ShowMultiDialog(prompt, _("Warning"), buttons); if(action==2)return (ret | FSCKstatus_CLOSEREQ); } BlockHash::iterator i=missingAliasList.begin(); while(i != missingAliasList.end()) { AliasBlockFile *b = (AliasBlockFile *)i->second; //this is //safe, we checked that it's an alias block file earlier if(action==0){ // silence the blockfiles by yanking the filename wxFileName dummy; dummy.Clear(); b->ChangeAliasedFile(dummy); b->Recover(); ret |= FSCKstatus_CHANGED; }else if(action==1){ // silence the log for this session b->SilenceAliasLog(); } i++; } } // Summary regeneration must happen after alias checking. if(!missingSummaryList.empty()){ int action; if (silentlycorrect) { // In "silently correct" mode we just recreate the summary files action = 0; } else { wxString promptA = _("Project check detected %d missing summary file[s] (.auf).\nAudacity can fully regenerate these summary files from the\noriginal audio data in the project."); wxString prompt; prompt.Printf(promptA,missingSummaryList.size()); const wxChar *buttons[]={_("Regenerate summary files [safe and recommended]"), _("Fill in silence for missing display data [this session only]"), _("Close project immediately with no further changes"),NULL}; action = ShowMultiDialog(prompt, _("Warning"), buttons); if(action==2)return (ret | FSCKstatus_CLOSEREQ); } BlockHash::iterator i=missingSummaryList.begin(); while(i != missingSummaryList.end()) { BlockFile *b = i->second; if(action==0){ //regenerate from data b->Recover(); ret |= FSCKstatus_CHANGED; }else if (action==1){ b->SilenceLog(); } i++; } } // Deal with any missing SimpleBlockFiles if(!missingDataList.empty()){ int action; if (silentlycorrect) { // In "silently correct" mode, we always create silent blocks. This // makes sure the project is complete even if we open it again. action = 0; } else { wxString promptA = _("Project check detected %d missing audio data blockfile[s] (.au), \nprobably due to a bug, system crash or accidental deletion.\nThere is no way for Audacity to recover this lost data\nautomatically; you may choose to permanently fill in silence\nfor the missing data, temporarily fill in silence for this\nsession only, or close the project now and try to restore the\nmissing data by hand."); wxString prompt; prompt.Printf(promptA,missingDataList.size()); const wxChar *buttons[]={_("Replace missing data with silence [permanent immediately]"), _("Temporarily replace missing data with silence [this session only]"), _("Close project immediately with no further changes"),NULL}; action = ShowMultiDialog(prompt, _("Warning"), buttons); if(action==2)return (ret | FSCKstatus_CLOSEREQ); } BlockHash::iterator i=missingDataList.begin(); while(i != missingDataList.end()) { BlockFile *b = i->second; if(action==0){ //regenerate with zeroes b->Recover(); ret |= FSCKstatus_CHANGED; }else if(action==1){ b->SilenceLog(); } i++; } } // clean up any empty directories fnameList.Clear(); rm_dash_rf_enumerate_prompt((projFull != wxT("")? projFull: mytemp), fnameList,wxEmptyString,0,1,blockcount, _("Cleaning up unused directories in project data...")); rm_dash_rf_execute(fnameList,0,0,1,0); return ret; }