1 /*****************************************************************************
2 * stardict.cpp - QStarDict, a StarDict clone written using Qt *
3 * Copyright (C) 2008 Alexander Rodin *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License along *
16 * with this program; if not, write to the Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
18 *****************************************************************************/
26 #include <QCoreApplication>
31 #include <glib/gmem.h>
32 #include <glib/gstrfuncs.h>
35 #include "settingsdialog.h"
39 void xdxf2html(QString &str);
40 QString whereDict(const QString &name, const QStringList &dictDirs);
41 const int MaxFuzzy = 24;
43 class StdList: public std::list<std::string>
47 : std::list<std::string>()
50 StdList(const QList<QString> &list)
51 : std::list<std::string>()
53 for (QList<QString>::const_iterator i = list.begin(); i != list.end(); ++i)
54 push_back(i->toUtf8().data());
57 StdList(const std::list<std::string> &list)
58 : std::list<std::string>(list)
61 QStringList toStringList() const
64 for (const_iterator i = begin(); i != end(); ++i)
65 list << QString::fromUtf8(i->c_str());
73 IfoListSetter(QStringList *list)
77 void operator ()(const std::string &filename, bool)
80 if (info.load_from_ifo_file(filename, false))
81 m_list->push_back(QString::fromUtf8(info.bookname.c_str()));
91 IfoFileFinder(const QString &name, QString *filename)
92 : m_name(name.toUtf8().data()),
96 void operator()(const std::string &filename, bool)
99 if (info.load_from_ifo_file(filename, false) && info.bookname == m_name) {
100 *m_filename = QString::fromUtf8(filename.c_str());
110 StarDict::StarDict(QObject *parent)
114 QSettings settings("qstardict","qstardict");
116 m_dictDirs = settings.value("StarDict/dictDirs", m_dictDirs).toStringList();
117 m_reformatLists = settings.value("StarDict/reformatLists", true).toBool();
118 m_expandAbbreviations = settings.value("StarDict/expandAbbreviations", true).toBool();
119 if (m_dictDirs.isEmpty())
122 m_dictDirs << "/usr/share/stardict/dic";
124 m_dictDirs << QCoreApplication::applicationDirPath() + "/dic";
126 m_dictDirs << QDir::homePath() + "/.stardict/dic";
130 StarDict::~StarDict()
132 QSettings settings("qstardict","qstardict");
133 settings.setValue("StarDict/dictDirs", m_dictDirs);
134 settings.setValue("StarDict/reformatLists", m_reformatLists);
135 settings.setValue("StarDict/expandAbbreviations", m_expandAbbreviations);
139 QStringList StarDict::availableDicts() const
142 IfoListSetter setter(&result);
143 for_each_file(StdList(m_dictDirs), ".ifo", StdList(), StdList(), setter);
148 void StarDict::setLoadedDicts(const QStringList &loadedDicts)
150 QStringList available = availableDicts();
152 for (QStringList::const_iterator i = available.begin(); i != available.end(); ++i)
154 if (! loadedDicts.contains(*i))
155 disabled.push_back(i->toUtf8().data());
157 m_sdLibs->reload(StdList(m_dictDirs), StdList(loadedDicts), disabled);
159 m_loadedDicts.clear();
160 for (int i = 0; i < m_sdLibs->ndicts(); ++i)
161 m_loadedDicts[QString::fromUtf8(m_sdLibs->dict_name(i).c_str())] = i;
164 StarDict::DictInfo StarDict::dictInfo(const QString &dict)
166 ::DictInfo nativeInfo;
167 nativeInfo.wordcount = 0;
168 if (! nativeInfo.load_from_ifo_file(whereDict(dict, m_dictDirs).toUtf8().data(), false)) {
171 DictInfo result(name(), dict);
172 result.setAuthor(QString::fromUtf8(nativeInfo.author.c_str()));
173 result.setDescription(QString::fromUtf8(nativeInfo.description.c_str()));
174 result.setWordsCount(nativeInfo.wordcount ? static_cast<long>(nativeInfo.wordcount) : -1);
178 bool StarDict::isTranslatable(const QString &dict, const QString &word)
180 if (! m_loadedDicts.contains(dict))
183 return m_sdLibs->SimpleLookupWord(word.toUtf8().data(), ind, m_loadedDicts[dict]);
186 StarDict::Translation StarDict::translate(const QString &dict, const QString &word)
188 if (! m_loadedDicts.contains(dict))
189 return Translation();
191 return Translation();
192 int dictIndex = m_loadedDicts[dict];
194 if (! m_sdLibs->SimpleLookupWord(word.toUtf8().data(), ind, m_loadedDicts[dict]))
195 return Translation();
196 return Translation(QString::fromUtf8(m_sdLibs->poGetWord(ind, dictIndex)),
197 QString::fromUtf8(m_sdLibs->dict_name(dictIndex).c_str()),
198 parseData(m_sdLibs->poGetWordData(ind, dictIndex), dictIndex, true,
199 m_reformatLists, m_expandAbbreviations));
202 QStringList StarDict::findSimilarWords(const QString &dict, const QString &word)
204 if (! m_loadedDicts.contains(dict))
205 return QStringList();
206 gchar *fuzzy_res[MaxFuzzy];
207 if (! m_sdLibs->LookupWithFuzzy(word.toUtf8().data(), fuzzy_res, MaxFuzzy, m_loadedDicts[dict]))
208 return QStringList();
210 for (gchar **p = fuzzy_res, **end = fuzzy_res + MaxFuzzy; p != end && *p; ++p)
212 result << QString::fromUtf8(*p);
218 int StarDict::execSettingsDialog(QWidget *parent)
220 ::SettingsDialog dialog(this, parent);
221 return dialog.exec();
224 QString StarDict::parseData(const char *data, int dictIndex, bool htmlSpaces, bool reformatLists, bool expandAbbreviations)
227 quint32 dataSize = *reinterpret_cast<const quint32*>(data);
228 const char *dataEnd = data + dataSize;
229 const char *ptr = data + sizeof(quint32);
230 while (ptr < dataEnd)
238 QString str = QString::fromUtf8(ptr);
239 ptr += str.toUtf8().length() + 1;
245 QString str = QString::fromUtf8(ptr);
246 ptr += str.toUtf8().length() + 1;
253 QString str = QString::fromUtf8(ptr);
254 ptr += str.toUtf8().length() + 1;
255 result += "<font class=\"example\">";
262 ptr += strlen(ptr) + 1;
268 ptr += *reinterpret_cast<const quint32*>(ptr) + sizeof(quint32);
276 if (expandAbbreviations)
278 QRegExp regExp("_\\S+[\\.:]");
280 while ((pos = regExp.indexIn(result, pos)) != -1)
283 if (m_sdLibs->SimpleLookupWord(result.mid(pos, regExp.matchedLength()).toUtf8().data(), ind, dictIndex))
285 QString expanded = "<font class=\"explanation\">";
286 expanded += parseData(m_sdLibs->poGetWordData(ind, dictIndex));
287 if (result[pos + regExp.matchedLength() - 1] == ':')
289 expanded += "</font>";
290 result.replace(pos, regExp.matchedLength(), expanded);
291 pos += expanded.length();
294 pos += regExp.matchedLength();
300 QStack<QChar> openedLists;
301 while (pos < result.length())
303 if (result[pos].isDigit())
306 while (result[pos + n].isDigit())
309 if (result[pos] == '&' && result.mid(pos + 1, 3) == "gt;")
310 result.replace(pos, 4, ">");
311 QChar marker = result[pos];
313 if (marker == '>' || marker == '.' || marker == ')')
315 if (n == 1 && result[pos - 1] == '1') // open new list
317 if (openedLists.contains(marker))
319 replacement = "</li></ol>";
320 while (openedLists.size() && openedLists.top() != marker)
322 replacement += "</li></ol>";
326 openedLists.push(marker);
327 replacement += "<ol>";
331 while (openedLists.size() && openedLists.top() != marker)
333 replacement += "</li></ol>";
336 replacement += "</li>";
338 replacement += "<li>";
341 while (result[pos - 1].isSpace())
343 while (result[n + 1].isSpace())
345 result.replace(pos, n - pos + 1, replacement);
346 pos += replacement.length();
354 while (openedLists.size())
356 result += "</li></ol>";
363 while (result[n].isSpace())
367 while (result[result.length() - 1 - n].isSpace())
369 result.remove(result.length() - n, n);
371 for (int pos = 0; pos < result.length();)
373 switch (result[pos].toAscii())
376 result.insert(pos, "<font class=\"transcription\">");
377 pos += 28 + 1; // sizeof "<font class=\"transcription\">" + 1
380 result.insert(pos + 1, "</font>");
381 pos += 7 + 1; // sizeof "</font>" + 1
384 result.insert(pos, " ");
385 pos += 24 + 1; // sizeof " " + 1
391 while (result[pos + n].isSpace())
393 if (result[pos + n] == '\n')
398 result.replace(pos, n, "</p><p>");
400 result.replace(pos, n, "<br>");
413 QString whereDict(const QString &name, const QStringList &dictDirs)
416 IfoFileFinder finder(name, &filename);
417 for_each_file(StdList(dictDirs), ".ifo", StdList(), StdList(), finder);
421 void xdxf2html(QString &str)
423 str.replace("<abr>", "<font class=\"abbreviature\">");
424 str.replace("<tr>", "<font class=\"transcription\">[");
425 str.replace("</tr>", "]</font>");
426 str.replace("<ex>", "<font class=\"example\">");
427 str.replace(QRegExp("<k>.*<\\/k>"), "");
428 str.replace(QRegExp("(<\\/abr>)|(<\\ex>)"), "</font");
433 Q_EXPORT_PLUGIN2(stardict, StarDict)
435 // vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab cindent textwidth=120 formatoptions=tc