2e9afb5218b33e59af35c8dd2f46e9e1de868ae9
[qstardict] / kdeplasma / dataengine / dictengine.cpp
1 /*
2  *   Copyright (C) 2008 Nick Shaforostoff <shaforostoff@kde.ru>
3  *
4  *   based on work by:
5  *   Copyright (C) 2007 Thomas Georgiou <TAGeorgiou@gmail.com> and Jeff Cooper <weirdsox11@gmail.com>
6  *
7  *   This program is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU General Public License as
9  *   published by the Free Software Foundation; either version 2 of 
10  *   the License, or (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "dictengine.h"
22 #include "dictplugin.h"
23 #include "config.h"
24
25 #include <QPluginLoader>
26 #include <QPointer>
27 #include <QMap>
28 #include <QTimer>
29 #include <QTime>
30 #include <QSettings>
31 #include <KDebug>
32 // #include <KLocale>
33
34 #include <Plasma/DataContainer>
35
36 #define MEMORYFREE_DELAY 60000
37
38
39 /**
40  * This class represents a dictionary provided by a plugin
41  */
42 class Dictionary
43 {
44     public:
45         Dictionary(const QString &plugin, const QString &name)
46             : m_plugin(plugin)
47             , m_name(name)
48         {}
49         Dictionary()
50         {}
51
52         const QString &plugin() const {return m_plugin;}
53         const QString &name() const {return m_name;}
54         void setPlugin(const QString &plugin) {m_plugin=plugin;}
55         void setName(const QString &name) {m_name=name;}
56         bool operator == (const Dictionary &dict) {return m_name==dict.m_name && m_plugin==dict.m_plugin;}
57
58     private:
59         QString m_plugin;
60         QString m_name;
61 };
62
63
64 struct QStarDictEngine::Private
65 {
66     QString currentWord;
67     QTimer timer;
68
69     QHash<QString, QPointer<QPluginLoader> > plugins; //name to pointer
70 //     QList<Dictionary> dicts;
71 //     QHash<QString, QString> dictToPlugin; //name to metastructure
72     QHash<QString, Dictionary> dicts; //name to metastructure
73
74 };
75
76
77
78
79
80
81 QStarDictEngine::QStarDictEngine(QObject* parent, const QVariantList& args)
82     : Plasma::DataEngine(parent, args)
83     , d(new Private)
84 {
85     Q_UNUSED(args)
86 //     QTime a;a.start();
87 #ifdef Q_OS_WIN
88     QFileInfoList files = QDir(QSTARDICT_PLUGINS_DIR).entryInfoList(QStringList("*0.dll"),QDir::Files|QDir::NoDotAndDotDot);
89     for (QFileInfoList::const_iterator i = files.begin(); i != files.end(); ++i)
90         d->plugins[i->fileName().left(i->fileName().length()-5))]=0;
91 #else
92     qWarning()<<QSTARDICT_PLUGINS_DIR;
93     QFileInfoList files = QDir(QSTARDICT_PLUGINS_DIR).entryInfoList(QStringList("lib*.so"),QDir::Files|QDir::NoDotAndDotDot);
94     for (QFileInfoList::const_iterator i = files.begin(); i != files.end(); ++i)
95         d->plugins[i->fileName().mid(3, i->fileName().length()-6)]=0;
96 #endif
97
98
99
100     // use cache to not load redudant plugins? 16->10 ms
101 //     QSettings settings("qstardict","qstardict");
102 //     m_dictDirs = settings.value("Multitran/dictDirs", m_dictDirs).toStringList();
103
104     d->timer.setInterval(MEMORYFREE_DELAY);
105     d->timer.setSingleShot(true);
106     connect(&d->timer, SIGNAL(timeout()), this, SLOT(unloadPlugins()));
107
108
109     QList<QString> plugins=d->plugins.keys();
110     for (QList<QString>::const_iterator i = plugins.constBegin(); i != plugins.constEnd(); ++i)
111     {
112 //         QStringList dicts = settings.value(*i+"/dicts", QStringList()).toStringList();
113 //         if (!dicts.isEmpty())
114 //         {
115             QStarDict::DictPlugin* plugin = dictPlugin(*i);
116             if (!plugin)
117                 continue;
118             QStringList dicts=plugin->availableDicts();
119 //             settings.setValue(*i+"/dicts", QVariant(dicts));
120 //            plugin->setdicts(dicts);
121 //         }
122         for (QStringList::const_iterator j = dicts.constBegin(); j != dicts.constEnd(); ++j)
123             d->dicts[*j]=Dictionary(*i, *j);
124 //             d->dicts<<Dictionary(*i, *j);
125     }
126 //     qWarning()<<a.elapsed();
127
128 }
129
130 QStarDictEngine::~QStarDictEngine()
131 {
132     unloadPlugins();
133     delete d;
134 }
135
136
137
138 QStarDict::DictPlugin* QStarDictEngine::dictPlugin(const QString &name)
139 {
140     if (! d->plugins.contains(name) )
141         return 0;
142     if (! d->plugins.value(name) )
143     {
144 #ifdef Q_OS_WIN
145         QString pluginFilename = QSTARDICT_PLUGINS_DIR "/" + name + "0.dll";
146 #else 
147         QString pluginFilename = QSTARDICT_PLUGINS_DIR "/" "lib" + name + ".so";
148 #endif
149         QPluginLoader* plugin = new QPluginLoader(pluginFilename);
150         if (! plugin->load())
151         {
152             kWarning() << plugin->errorString();
153             delete plugin;
154             return 0;
155         }
156         d->plugins[name]=plugin;
157     }
158
159     return qobject_cast<QStarDict::DictPlugin*>(d->plugins.value(name)->instance());
160 }
161
162 void QStarDictEngine::unloadPlugins()
163 {
164     for (QHash<QString, QPointer<QPluginLoader> >::iterator i = d->plugins.begin(); i != d->plugins.end(); ++i)
165     {
166         if (*i)
167         {
168             (*i)->instance()->deleteLater();
169             (*i)->deleteLater();
170         }
171     }
172
173 }
174
175 bool QStarDictEngine::sourceRequestEvent(const QString &word)
176 {
177     qWarning()<<"sourceRequestEvent"<<word;
178     d->timer.start();//delay freeing resources / activate delayed resources freeing
179
180     if (word=="list-dictionaries")
181     {
182         QStringList result;
183         int i=d->plugins.keys().size();
184         while (--i>=0)
185         {
186             QStarDict::DictPlugin* plugin = dictPlugin(d->plugins.keys().at(i));
187             if (!plugin)
188                 continue;
189             result << plugin->availableDicts();
190         }
191         setData("list-dictionaries", "dictionaries", result);
192         qWarning()<<result;
193         return true;
194     }
195
196     QString simplifiedWord;
197     QStringList queriedDicts;
198     int pos=word.indexOf(':');
199     if (pos!=-1)
200     {
201         queriedDicts=word.left(pos).split(',');
202         simplifiedWord=word.mid(pos+1).simplified();
203     }
204     else
205         simplifiedWord=word.simplified();
206     qWarning()<<"simplifiedWord"<<simplifiedWord;
207     qWarning()<<"queriedDicts"<<queriedDicts;
208
209     if (queriedDicts.isEmpty())
210         for (QHash<QString,Dictionary>::const_iterator i = d->dicts.constBegin(); i != d->dicts.constEnd(); ++i)
211             queriedDicts<<i->name();
212
213     d->currentWord = word;
214     QString result;
215
216     if (simplifiedWord.length() == 0)
217     {
218         setData(d->currentWord, "text", QString());
219         return true;
220     }
221
222     for (QStringList::const_iterator i = queriedDicts.constBegin(); i != queriedDicts.constEnd(); ++i)
223     {
224         if (!d->dicts.contains(*i))
225             continue;
226         QStarDict::DictPlugin* plugin = dictPlugin(d->dicts.value(*i).plugin());
227         if (!plugin)
228             continue;
229         QStringList ld=plugin->loadedDicts();
230         if (!ld.contains(*i))
231             plugin->setLoadedDicts(ld<<*i);
232         if ( !plugin->isTranslatable(*i, simplifiedWord))
233             continue;
234         QStarDict::DictPlugin::Translation translation = plugin->translate(*i, simplifiedWord);
235         if (translation.translation().isEmpty())
236             continue;
237         result += "<p>\n"
238             "<font class=\"dict_name\">" + translation.dictName() + "</font><br>\n"
239             "<font class=\"title\">" + translation.title() + "</font><br>\n"
240             + translation.translation() + "</p>\n";
241     }
242
243     setData(d->currentWord, "text", result);
244     return true;
245 }
246
247
248
249
250
251 #include "dictengine.moc"