File indexing completed on 2025-01-19 06:54:50
0001 // 0002 // C++ Implementation: cpluginmanager 0003 // 0004 // Description: plug-in manager 0005 // 0006 /* 0007 Copyright 2006-2011 Tomas Mecir <kmuddy@kmuddy.com> 0008 0009 This program is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU General Public License as 0011 published by the Free Software Foundation; either version 2 of 0012 the License, or (at your option) any later version. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include "cpluginmanager.h" 0024 0025 #include "cactionmanager.h" 0026 #include "cplugin.h" 0027 0028 #include <QDebug> 0029 #include <QDialog> 0030 #include <KLocalizedString> 0031 #include <KPluginWidget> 0032 #include <KPluginFactory> 0033 0034 #include <list> 0035 #include <KConfigGroup> 0036 #include <QDialogButtonBox> 0037 #include <QPushButton> 0038 #include <QVBoxLayout> 0039 0040 using namespace std; 0041 0042 cPluginManager *cPluginManager::_self = nullptr; 0043 0044 cPluginManager *cPluginManager::self () 0045 { 0046 if (!_self) 0047 _self = new cPluginManager; 0048 return _self; 0049 } 0050 0051 cPluginManager::cPluginManager () : cActionBase ("pluginmanager", 0) 0052 { 0053 findPlugins (); 0054 activeSess = 0; 0055 lastGagged = false; 0056 pluginDialog = nullptr; 0057 0058 // global objects receive events from all sessions, hence this will work well 0059 addEventHandler ("send-command", 20, PT_STRING); 0060 addEventHandler ("raw-data", 20, PT_STRING); 0061 addEventHandler ("raw-data-comp", 20, PT_STRING); 0062 addEventHandler ("got-prompt", 20, PT_TEXTCHUNK); 0063 addEventHandler ("got-line", 20, PT_TEXTCHUNK); 0064 addEventHandler ("got-line-after-triggers", 20, PT_TEXTCHUNK); 0065 addEventHandler ("will-gag", 20, PT_NOTHING); 0066 addEventHandler ("connected", 20, PT_NOTHING); 0067 addEventHandler ("disconnected", 20, PT_NOTHING); 0068 addEventHandler ("save", 20, PT_NOTHING); 0069 addEventHandler ("session-activated", 20, PT_INT); 0070 addEventHandler ("session-created", 20, PT_INT); 0071 addEventHandler ("session-destroyed", 20, PT_INT); 0072 } 0073 0074 0075 cPluginManager::~cPluginManager () 0076 { 0077 //unload plug-ins 0078 unloadAll (); 0079 0080 removeEventHandler ("raw-data"); 0081 removeEventHandler ("raw-data-comp"); 0082 removeEventHandler ("send-command"); 0083 removeEventHandler ("raw-data"); 0084 removeEventHandler ("raw-data-comp"); 0085 removeEventHandler ("got-prompt"); 0086 removeEventHandler ("got-line"); 0087 removeEventHandler ("got-line-after-triggers"); 0088 removeEventHandler ("will-gag"); 0089 removeEventHandler ("connected"); 0090 removeEventHandler ("disconnected"); 0091 removeEventHandler ("save"); 0092 removeEventHandler ("session-activated"); 0093 removeEventHandler ("session-created"); 0094 removeEventHandler ("session-destroyed"); 0095 0096 _self = nullptr; 0097 } 0098 0099 void cPluginManager::eventIntHandler (QString event, int, int par1, int) 0100 { 0101 if (event == "session-activated") { 0102 passSessionSwitch (par1); 0103 } 0104 if (event == "session-created") { 0105 passSessionAdd (par1); 0106 } 0107 if (event == "session-destroyed") { 0108 passSessionRemove (par1); 0109 } 0110 } 0111 0112 void cPluginManager::eventStringHandler (QString event, int session, QString &par1, const QString &) 0113 { 0114 if (event == "send-command") { 0115 passCommand (session, par1); 0116 } 0117 else if (event == "raw-data-comp") { 0118 QByteArray par1Data = par1.toLatin1(); 0119 char *data = par1Data.data(); 0120 passRawData (session, data); 0121 par1 = data; // make changes take effect 0122 } 0123 else if (event == "raw-data") { 0124 QByteArray par1Data = par1.toLatin1(); 0125 char *data = par1Data.data(); 0126 passRawData (session, data); 0127 par1 = data; // make changes take effect 0128 } 0129 } 0130 0131 void cPluginManager::eventNothingHandler (QString event, int session) 0132 { 0133 if (event == "will-gag") { 0134 lastGagged = true; 0135 } 0136 else if (event == "connected") { 0137 passConnected (session); 0138 } 0139 else if (event == "disconnected") { 0140 passDisconnected (session); 0141 } 0142 else if (event == "save") { 0143 passSave (session); 0144 } 0145 } 0146 0147 void cPluginManager::eventChunkHandler (QString event, int session, cTextChunk *par) 0148 { 0149 if (event == "got-prompt") { 0150 passPrompt (session, par); 0151 } 0152 if (event == "got-line") { 0153 passInput (session, 1, par, false); 0154 } 0155 if (event == "got-line-after-triggers") { 0156 passInput (session, 2, par, lastGagged); 0157 lastGagged = false; 0158 } 0159 } 0160 0161 void cPluginManager::findPlugins () 0162 { 0163 pluginInfo.clear (); 0164 QVector< KPluginMetaData > pi = KPluginMetaData::findPlugins ("kmuddy"); 0165 for (auto pinfo : pi) { 0166 QString name = pinfo.name(); 0167 qDebug() << "Found plugin: " << name; 0168 pluginInfo[name] = pinfo; 0169 } 0170 } 0171 0172 bool cPluginManager::loadPlugin (const QString &name) 0173 { 0174 if (isLoaded (name)) //plug-in is already loaded! 0175 return false; 0176 if (!(pluginInfo.count (name))) //we know nothing of that plug-in 0177 return false; 0178 0179 KPluginFactory::Result<cPlugin> res = KPluginFactory::instantiatePlugin<cPlugin>(pluginInfo[name]); 0180 if (!res) { 0181 qDebug() << "Failed to load plugin: " << name; 0182 return false; 0183 } 0184 0185 cPlugin *plugin = res.plugin; 0186 0187 loadedPlugins[name] = plugin; 0188 plugins.insert (pair<int, cPlugin *>(plugin->priority(), plugin)); 0189 0190 // call plugin's session loading for each active session - the plugin can load the data and 0191 // the like here 0192 cActionManager *am = cActionManager::self(); 0193 map<int, bool>::iterator sit; 0194 for (sit = sessions.begin(); sit != sessions.end(); ++sit) { 0195 plugin->sessionAdd (sit->first, false); 0196 cActionBase *conn = am->object ("connection", sit->first); 0197 if (conn && conn->attrib ("connected")) 0198 plugin->connected (sit->first); // if the session is connected, notify the plugin of that 0199 } 0200 plugin->setActiveSession (activeSess); 0201 plugin->sessionSwitch (activeSess); 0202 qDebug() << "Loaded plugin: " << name; 0203 return true; 0204 } 0205 0206 bool cPluginManager::unloadPlugin (const QString &name) 0207 { 0208 if (!(isLoaded (name))) //plug-in is not loaded! 0209 return false; 0210 cPlugin *p = loadedPlugins[name]; 0211 loadedPlugins.erase (name); 0212 //remove plugin from the priority list 0213 for (it = plugins.begin(); it != plugins.end(); ++it) 0214 if (it->second == p) 0215 { 0216 plugins.erase (it); 0217 break; 0218 } 0219 0220 // call plugin's session unloading for each active session - the plugin can save the data and 0221 // the like here 0222 map<int, bool>::iterator sit; 0223 for (sit = sessions.begin(); sit != sessions.end(); ++sit) { 0224 p->sessionRemove (sit->first, false); 0225 } 0226 0227 qDebug() << "Unloaded plugin: " << name; 0228 0229 delete p; 0230 return true; 0231 } 0232 0233 bool cPluginManager::isLoaded (const QString &name) 0234 { 0235 return (loadedPlugins.count (name) != 0); 0236 } 0237 0238 void cPluginManager::loadAll () 0239 { 0240 for (auto e : pluginInfo) 0241 if (e.second.isEnabled(pluginConfig)) 0242 loadPlugin (e.first); 0243 } 0244 0245 void cPluginManager::unloadUnwanted () 0246 { 0247 for (auto e : pluginInfo) 0248 if (isLoaded(e.first) && (!e.second.isEnabled(pluginConfig))) 0249 unloadPlugin (e.first); 0250 } 0251 0252 void cPluginManager::unloadAll () 0253 { 0254 //unloading a plug-in modifies the map, invalidating iterators... 0255 //I therefore have to create a list of loaded plug-in names and use that instead 0256 list<QString> loadedList; 0257 map<QString, cPlugin *>::iterator lpi; 0258 for (lpi = loadedPlugins.begin(); lpi != loadedPlugins.end(); ++lpi) 0259 loadedList.push_back (lpi->first); 0260 list<QString>::iterator it; 0261 for (it = loadedList.begin(); it != loadedList.end(); ++it) 0262 unloadPlugin (*it); 0263 } 0264 0265 void cPluginManager::showPluginsDialog () 0266 { 0267 pluginDialog = new QDialog (nullptr); 0268 pluginDialog->setWindowTitle (i18n ("Plugins")); 0269 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); 0270 QVBoxLayout *mainLayout = new QVBoxLayout; 0271 pluginDialog->setLayout(mainLayout); 0272 pluginSelector = new KPluginWidget (pluginDialog); 0273 pluginSelector->setConfig(pluginConfig); 0274 mainLayout->addWidget(pluginSelector); 0275 pluginDialog->connect(buttonBox, &QDialogButtonBox::accepted, this, &cPluginManager::closeDialog); 0276 pluginDialog->connect(buttonBox, &QDialogButtonBox::rejected, this, &cPluginManager::closeDialog); 0277 mainLayout->addWidget(buttonBox); 0278 pluginDialog->resize (QSize (400, 300)); 0279 0280 0281 connect (pluginSelector, &KPluginWidget::changed, this, &cPluginManager::applyPluginDialog); 0282 0283 QVector<KPluginMetaData> list; 0284 map<QString, KPluginMetaData>::iterator itp; 0285 for (itp = pluginInfo.begin(); itp != pluginInfo.end(); ++itp) 0286 list.append (itp->second); 0287 pluginSelector->addPlugins (list, QString("KMuddy")); 0288 pluginSelector->load(); 0289 0290 pluginDialog->exec (); 0291 0292 delete pluginDialog; 0293 pluginDialog = nullptr; 0294 } 0295 0296 void cPluginManager::applyPluginDialog () 0297 { 0298 // unload unwanted plug-ins, load newly wanted ones 0299 pluginSelector->save(); 0300 unloadUnwanted (); 0301 loadAll (); 0302 } 0303 0304 void cPluginManager::closeDialog() 0305 { 0306 pluginDialog->close(); 0307 delete pluginDialog; 0308 pluginDialog = nullptr; 0309 } 0310 0311 void cPluginManager::passSessionAdd (int sess) 0312 { 0313 for (it = plugins.begin(); it != plugins.end(); ++it) 0314 it->second->sessionAdd (sess, true); 0315 sessions[sess] = true; 0316 } 0317 0318 void cPluginManager::passSessionRemove (int sess) 0319 { 0320 for (it = plugins.begin(); it != plugins.end(); ++it) 0321 it->second->sessionRemove (sess, true); 0322 sessions.erase (sess); 0323 } 0324 0325 void cPluginManager::passSessionSwitch (int sess) 0326 { 0327 for (it = plugins.begin(); it != plugins.end(); ++it) 0328 { 0329 it->second->sessionSwitch (sess); 0330 it->second->setActiveSession (sess); 0331 } 0332 activeSess = sess; 0333 } 0334 0335 void cPluginManager::passConnected (int sess) 0336 { 0337 for (it = plugins.begin(); it != plugins.end(); ++it) 0338 it->second->connected (sess); 0339 } 0340 0341 void cPluginManager::passDisconnected (int sess) 0342 { 0343 for (it = plugins.begin(); it != plugins.end(); ++it) 0344 it->second->disconnected (sess); 0345 } 0346 0347 void cPluginManager::passSave (int sess) 0348 { 0349 for (it = plugins.begin(); it != plugins.end(); ++it) 0350 it->second->save (sess); 0351 } 0352 0353 void cPluginManager::passRawData (int sess, char *data) 0354 { 0355 for (it = plugins.begin(); it != plugins.end(); ++it) 0356 it->second->rawData (sess, data); 0357 } 0358 0359 void cPluginManager::passDecompressedData (int sess, char *data) 0360 { 0361 for (it = plugins.begin(); it != plugins.end(); ++it) 0362 it->second->decompressedData (sess, data); 0363 } 0364 0365 void cPluginManager::passInput (int sess, int phase, cTextChunk *chunk, bool gagged) 0366 { 0367 for (it = plugins.begin(); it != plugins.end(); ++it) 0368 it->second->processInput (sess, phase, chunk, gagged); 0369 } 0370 0371 void cPluginManager::passPrompt (int sess, cTextChunk *chunk) 0372 { 0373 for (it = plugins.begin(); it != plugins.end(); ++it) 0374 it->second->processPrompt (sess, chunk); 0375 } 0376 0377 void cPluginManager::passCommand (int sess, QString &command) 0378 { 0379 bool dontSend = false; 0380 for (it = plugins.begin(); it != plugins.end(); ++it) { 0381 it->second->processCommand (sess, command, dontSend); 0382 if (dontSend) break; 0383 } 0384 if (dontSend) command = QString(); 0385 } 0386 0387 #include "moc_cpluginmanager.cpp"