init
[qstardict] / kdeplasma / applet / dict.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 "dict.h"
22
23 #include <QGraphicsProxyWidget>
24 #include <QGraphicsLinearLayout>
25 #include <QTimer>
26 // #include <QWebView>
27 #include <QTextBrowser>
28
29 #include <KDebug>
30 #include <KIcon>
31 #include <KStandardDirs>
32 #include <KLineEdit>
33 #include <KEditListBox>
34 #include <QListView>
35 #include <QTreeView>
36 #include <QStringListModel>
37
38 #include <KConfigDialog>
39 #include <KConfigGroup>
40
41 #include <Plasma/Animator>
42 #include <Plasma/IconWidget>
43 #include <Plasma/LineEdit>
44
45 #define AUTO_DEFINE_TIMEOUT 500
46
47 using namespace Plasma;
48
49
50
51 const char* translationCSS =
52     "body {\n"
53         "font-size: 10pt; }\n"
54     "font.dict_name {\n"
55         "color: blue;\n"
56         "font-style: italic; }\n"
57     "font.title {\n"
58         "font-size: 16pt;\n"
59         "font-weight: bold; }\n"
60     "font.explanation {\n"
61         "color: #7f7f7f;\n"
62         "font-style: italic; }\n"
63     "font.abbreviature {\n"
64         "font-style: italic; }\n"
65     "font.example {\n"
66         "font-style: italic; }\n"
67     "font.transcription {\n"
68         "font-weight: bold; }\n";
69
70
71 QStarDictApplet::QStarDictApplet(QObject *parent, const QVariantList &args)
72     : Plasma::Applet(parent, args)
73     , m_dictsModel(0)
74       //m_flash(0)
75 {
76     setHasConfigurationInterface(true);
77     setAspectRatioMode(Plasma::IgnoreAspectRatio);
78     resize(500,200);
79 }
80
81 QStarDictApplet::~QStarDictApplet()
82 {
83     m_defBrowser->deleteLater();
84 }
85
86 void QStarDictApplet::init()
87 {
88 //     KConfigGroup cg = config();
89
90     m_wordEdit = new LineEdit(this);
91     m_wordEdit->nativeWidget()->setClearButtonShown( true );
92     m_wordEdit->nativeWidget()->setClickMessage(i18n("Enter word to define here"));
93     m_wordEdit->show();
94     Plasma::Animator::self()->animateItem(m_wordEdit, Plasma::Animator::AppearAnimation);
95
96 //     m_defBrowser = new QWebView();
97     m_defBrowser = new QTextBrowser();
98     m_defBrowser->document()->setDefaultStyleSheet(QLatin1String(translationCSS));
99     m_defBrowserProxy = new QGraphicsProxyWidget(this);
100     m_defBrowserProxy->setWidget(m_defBrowser);
101     m_defBrowserProxy->hide();
102 //  Icon in upper-left corner
103         QString iconpath = KStandardDirs::locate("icon", "oxygen/scalable/apps/accessories-dictionary.svgz");
104     m_icon = new Plasma::IconWidget(this);
105     m_icon->setSvg(iconpath);
106
107 //  Position lineedits
108     //const int wordEditOffset = 40;
109     m_icon->setPos(12,3);
110     //m_wordProxyWidget->setPos(15 + wordEditOffset,7);
111     //m_wordProxyWidget->show();
112     // TODO m_wordEdit->setDefaultTextColor(Plasma::Theme::self()->color(Plasma::Theme::TextColor));
113
114 //  Timer for auto-define
115     m_timer = new QTimer(this);
116     m_timer->setInterval(AUTO_DEFINE_TIMEOUT);
117     m_timer->setSingleShot(true);
118     connect(m_timer, SIGNAL(timeout()), this, SLOT(define()));
119
120     m_horLayout = new QGraphicsLinearLayout(Qt::Horizontal);
121     m_horLayout->addItem(m_icon);
122     m_horLayout->addItem(m_wordEdit);
123     m_layout = new QGraphicsLinearLayout(Qt::Vertical);
124     m_layout->addItem(m_horLayout);
125     m_layout->addItem(m_defBrowserProxy);
126     setLayout(m_layout);
127
128     m_source.clear();
129     dataEngine("qstardict")->connectSource(m_source, this);
130     connect(m_wordEdit, SIGNAL(editingFinished()), this, SLOT(define()));
131     connect(m_wordEdit->nativeWidget(), SIGNAL(textChanged(const QString&)), this, SLOT(autoDefine(const QString&)));
132
133     dataEngine("qstardict")->connectSource("list-dictionaries", this);
134
135     //connect(m_defEdit, SIGNAL(linkActivated(const QString&)), this, SLOT(linkDefine(const QString&)));
136
137 //  This is the fix for links/selecting text
138     //QGraphicsItem::GraphicsItemFlags flags = m_defEdit->flags();
139     //flags ^= QGraphicsItem::ItemIsMovable;
140    // m_defEdit->setFlags(flags);
141
142     /*m_flash = new Plasma::Flash(this);
143     m_flash->setColor(Qt::gray);
144     QFont fnt = qApp->font();
145     fnt.setBold(true);
146     m_flash->setFont(fnt);
147     m_flash->setPos(25,-10);
148     m_flash->resize(QSize(200,20));*/
149
150
151
152     KConfigGroup cg = config();
153     m_dicts = cg.readEntry("KnownDictionaries", QStringList());
154     QStringList activeDictNames = cg.readEntry("ActiveDictionaries", QStringList());
155     for (QStringList::const_iterator i = m_dicts.constBegin(); i != m_dicts.constEnd(); ++i)
156         m_activeDicts[*i]=activeDictNames.contains(*i);
157 }
158
159
160 void QStarDictApplet::linkDefine(const QString &text)
161 {
162     kDebug() <<"ACTIVATED";
163     m_wordEdit->setText(text);
164     define();
165 }
166
167 void QStarDictApplet::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
168 {
169     if (source=="list-dictionaries")
170     {
171         QStringList newDicts=data["dictionaries"].toStringList();
172         bool changed=false;
173         for (QStringList::const_iterator i = newDicts.constBegin(); i != newDicts.constEnd(); ++i)
174         {
175             if (!m_dicts.contains(*i))
176             {
177                 m_dicts<<*i;
178                 m_activeDicts[*i]=true;
179                 changed=true;
180             }
181         }
182         QStringList::iterator it = m_dicts.begin();
183         while (it != m_dicts.end())
184         {
185             if (!newDicts.contains(*it))
186             {
187                 it=m_dicts.erase(it);
188                 changed=true;
189             }
190             else
191                 ++it;
192         }
193         if (changed)
194             configAccepted();
195 //             cg.writeEntry("KnownDictionaries", m_dicts);
196
197     }
198 //     Q_UNUSED(source);
199     /*if (m_flash) {
200         m_flash->kill();
201     }*/
202     if (!m_source.isEmpty()) {
203         m_defBrowserProxy->show();
204         // TODO Phase::self()->animateItem(m_defBrowserProxy, Phase::Appear);
205     }
206 /*    if (data.contains("gcide")) {
207         QString defHeader;
208         m_defList = data[QString("gcide")].toString().split("<!--PAGE START-->"); //<!--DEFINITION START-->
209         for (int n = 0; n < m_defList.size(); ++n)
210         {
211             if (m_defList[n].contains("<!--DEFINITION START-->") && m_defList[n].contains("<!--PERIOD-->")) {
212                 defHeader=m_defList[n];
213             } else if (m_defList[n].contains("<!--DEFINITION START-->")) {
214                 defHeader=m_defList.takeAt(n);
215             }
216             if (n < m_defList.size() && !m_defList[n].contains("<!--DEFINITION START-->"))
217                 m_defList[n].prepend(defHeader);
218         }
219         if (m_defList.size() > 1)
220             m_defList.removeAt(0);
221         m_i = m_defList.begin();
222         m_defEdit->setHtml(*m_i);
223         if (m_i != --m_defList.end())
224             m_rightArrow->show();
225         else
226             m_rightArrow->hide();
227         m_leftArrow->hide();
228     } */
229     if (data.contains("text")) {
230         m_defBrowser->setHtml(data[QString("text")].toString());
231 //         m_defBrowser->setHtml(wnToHtml(data[QString("wn")].toString()));
232     }
233     updateGeometry();
234 }
235
236 void QStarDictApplet::define()
237 {
238
239     if (m_timer->isActive())
240         m_timer->stop();
241
242     QString newSource=m_wordEdit->text();
243     QStringList dictsList;
244     for (QStringList::const_iterator i = m_dicts.constBegin(); i != m_dicts.constEnd(); ++i)
245         if (m_activeDicts.contains(*i) && m_activeDicts.value(*i))
246             dictsList<<*i;
247     if (!newSource.isEmpty() && !dictsList.isEmpty())
248         newSource.prepend(dictsList.join(",")+':');
249
250     if (newSource == m_source)
251         return;
252
253     dataEngine("qstardict")->disconnectSource(m_source, this);
254
255     qWarning()<<"here"<<newSource;
256
257     if (!newSource.isEmpty())
258     {   //get new definition
259         //m_flash->flash(i18n("Looking up ") + m_word);
260         m_source = newSource;
261         dataEngine("qstardict")->connectSource(m_source, this);
262         qWarning()<<"connectSource"<<m_source;
263     }
264     else
265     {    //make the definition box disappear
266         // TODO Phase::self()->animateItem(m_defBrowserProxy, Phase::Disappear);
267         m_defBrowserProxy->hide();
268     }
269
270     updateConstraints();
271 }
272
273 void QStarDictApplet::autoDefine(const QString &word)
274 {
275     Q_UNUSED(word)
276     m_timer->start();
277 }
278
279
280 class CheckableStringListModel: public QStringListModel
281 {
282 public:
283     CheckableStringListModel(QObject* parent, const QStringList& dicts, const QHash<QString,bool>& activeDicts_)
284         : QStringListModel(parent)
285         , activeDicts(activeDicts_)
286     {
287         setStringList(dicts);
288 /*        setHeaderData (0, Qt::Horizontal, "020", Qt::DisplayRole);
289         setHeaderData (0, Qt::Vertical, "020", Qt::DisplayRole);*/
290     }
291     QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const
292     {
293         if (role!=Qt::DisplayRole)
294             return QVariant();
295         return i18n("Dictionary");
296     }
297     Qt::DropActions supportedDropActions(){return Qt::MoveAction;}
298     Qt::ItemFlags flags(const QModelIndex& index) const
299     {
300         if (!index.isValid())
301             return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
302         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
303     }
304     bool setData (const QModelIndex& index, const QVariant& value, int role=Qt::EditRole)
305     {
306         if (role==Qt::CheckStateRole)
307         {
308             activeDicts[stringList().at(index.row())]=value.toInt()==Qt::Checked;
309             return true;
310         }
311         else
312             return QStringListModel::setData(index,value,role);
313     }
314     QVariant data(const QModelIndex& index, int role=Qt::EditRole) const
315     {
316         if (!index.isValid())
317             return QVariant();
318
319         if (role==Qt::CheckStateRole)
320             return (  activeDicts.contains(stringList().at(index.row()))&&activeDicts.value(stringList().at(index.row()))  )?Qt::Checked:Qt::Unchecked;
321         return QStringListModel::data(index,role);
322     }
323
324 public:
325     QHash<QString,bool> activeDicts;
326 };
327
328
329 void QStarDictApplet::createConfigurationInterface(KConfigDialog *parent)
330 {
331 //     KConfigGroup cg = config();
332
333     //QWidget *widget = new QWidget(parent);
334 //     QListView* widget=new KEditListBox(i18n("Dictionaries activation and order"),
335 //                            KEditListBox::CustomEditor::CustomEditor(),
336 //                            parent,
337 //                            "dict-order",
338 //                            false,
339 //                            KEditListBox::UpDown);
340 //     QListView* widget=new QListView(parent);
341     QTreeView* widget=new QTreeView(parent);
342     widget->setDragEnabled(true);
343     widget->setAcceptDrops(true);
344 //     widget->viewposrt()->setAcceptDrops(true);
345     widget->setDragDropMode(QAbstractItemView::InternalMove);
346     widget->setDropIndicatorShown(true);
347     widget->setItemsExpandable(false);
348     widget->setAllColumnsShowFocus(true);
349     widget->setRootIsDecorated(false);
350
351     delete m_dictsModel;
352     m_dictsModel=new CheckableStringListModel(parent,m_dicts,m_activeDicts);
353     widget->setModel(m_dictsModel);
354
355 //     parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
356     parent->addPage(widget, parent->windowTitle(), Applet::icon());
357     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
358     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
359 }
360
361 void QStarDictApplet::configAccepted()
362 {
363     if (m_dictsModel)
364     {
365         m_dicts=m_dictsModel->stringList();
366         m_activeDicts=m_dictsModel->activeDicts;
367     }
368     KConfigGroup cg = config();
369     cg.writeEntry("KnownDictionaries", m_dicts);
370
371     QStringList activeDictNames;
372     for (QStringList::const_iterator i = m_dicts.constBegin(); i != m_dicts.constEnd(); ++i)
373         if (m_activeDicts.contains(*i) && m_activeDicts.value(*i))
374             activeDictNames<<*i;
375
376     cg.writeEntry("ActiveDictionaries", activeDictNames);
377
378     define();
379     emit configNeedsSaving();
380 }
381
382 #include "dict.moc"