Fix bug with app crash on exit. Add keyboard support in wordList, DictTypeSelectDialo...
[mdictionary] / src / mdictionary / gui / WordListWidget.cpp
1
2 /*******************************************************************************
3
4     This file is part of mDictionary.
5
6     mDictionary is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     mDictionary is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with mDictionary.  If not, see <http://www.gnu.org/licenses/>.
18
19     Copyright 2010 Comarch S.A.
20
21 *******************************************************************************/
22
23 /*! \file WordListwidget.cpp
24     \brief Displays list of words found in dictionaries
25
26     \author Mateusz Półrola <mateusz.polrola@comarch.pl>
27 */
28
29 #include "WordListWidget.h"
30 #include "WordListProxyStyle.h"
31 #include "../../include/translation.h"
32 #include <QKeyEvent>
33
34
35 WordListWidget::WordListWidget(QWidget *parent):
36     QTreeView(parent) {
37
38     _isBookmarkModeActive = false;
39
40     //creating new model to store words and stars
41 #ifdef Q_WS_MAEMO_5
42     model = new QStandardItemModel(this);
43     setModel(model);
44
45     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
46
47     //set our custom style to draw checkboxes as stars
48     proxyStyle = new WordListProxyStyle();
49     setStyle(proxyStyle);
50
51     //for future use, set checkbox icons for maemo
52 //    ctxt->setContextProperty("CheckedPath", "qrc:/icons/96x96/staron.png");
53 //    ctxt->setContextProperty("UncheckedPath", "qrc:/icons/96x96/staroff.png");
54 #else
55
56     listModel = new WordListModel(this);
57
58     verticalLayout = new QVBoxLayout;
59     setLayout(verticalLayout);
60
61     qmlView = new QDeclarativeView(this);
62
63     ctxt = qmlView->rootContext();
64
65     ctxt->setContextProperty("wordModel", &(*listModel));
66     ctxt->setContextProperty("CheckedPath", "qrc:/icons/16x16/staron.png");
67     ctxt->setContextProperty("UncheckedPath", "qrc:/icons/16x16/staroff.png");
68
69     qmlView->setSource(QUrl::fromLocalFile("/usr/share/mdictionary/qml/WordListWidget.qml"));
70
71     QGraphicsObject *rootObject = qmlView->rootObject();
72
73     qmlView->setResizeMode(QDeclarativeView::SizeRootObjectToView);
74
75     verticalLayout->addWidget(qmlView);
76
77     connect(rootObject, SIGNAL(wordSelected(QString)), this, SLOT(wordClicked(QString)));
78     connect(rootObject, SIGNAL(wordSelectedByIndex(int)), this, SLOT(wordClickedByIndex(int)));
79     connect(listModel, SIGNAL(addToBookmarks(QString)), this, SLOT(addToBookmarks(QString)));
80     connect(listModel, SIGNAL(removeFromBookmarks(QString)), this, SLOT(removeFromBookmarks(QString)));
81
82     connect(this, SIGNAL(setWordListState(QVariant)), rootObject, SLOT(setEnabled(QVariant)));
83     connect(this, SIGNAL(setWordListEmpty(QVariant)), rootObject, SLOT(setWordListEmpty(QVariant)));
84     connect(this, SIGNAL(setFocusOnQML()), rootObject, SLOT(setFocus()));
85
86 #endif
87
88     setHeaderHidden(true);
89     setRootIsDecorated(false);
90
91     //setting size of star in pixels, on maemo checboxes are much bigger
92     #ifdef Q_WS_MAEMO_5
93         checkBoxWidth = 70;
94     #else
95         checkBoxWidth = 25;
96     #endif
97 }
98
99
100 WordListWidget::~WordListWidget() {
101 #ifdef Q_WS_MAEMO_5
102     if(proxyStyle)
103         delete proxyStyle;
104 #endif
105 }
106
107 void WordListWidget::addWord(QString word, int row) {
108     QStandardItem* item = new QStandardItem(word);
109
110     //we don't want to allow user to edit word
111     item->setFlags(item->flags() ^ Qt::ItemIsEditable);
112
113     QStandardItem* itemCheckBox = new QStandardItem();
114     //creating checkbox item
115     itemCheckBox->setFlags((itemCheckBox->flags() ^ Qt::ItemIsEditable) |
116                            Qt::ItemIsUserCheckable);
117
118     /*checking if word is already in bookmarks, information about that is
119     stored in its translation object (not all translations have to be in
120     bookmarks)*/
121     bool bookmark = false;
122     Translation* t;
123     foreach(t, searchResult[word]) {
124         if(t->isBookmark()) {
125             bookmark = true;
126             break;
127         }
128     }
129
130     if(bookmark)
131         itemCheckBox->setCheckState(Qt::Checked);
132     else
133         itemCheckBox->setCheckState(Qt::Unchecked);
134
135     //add item to model
136     model->setItem(row,0, item);
137     model->setItem(row,1, itemCheckBox);
138 }
139
140
141 void WordListWidget::showSearchResults(
142         QHash<QString, QList<Translation *> > result) {
143
144     clear();
145     searchResult = result;
146
147 #ifdef Q_WS_MAEMO
148     if(searchResult.count()>0) {
149         setEnabled(true);
150         model->setColumnCount(2);
151         model->setRowCount(result.count());
152
153         int row=0;
154         QHash<QString, QList<Translation*> >::iterator i;
155         for(i = searchResult.begin(); i != searchResult.end(); i++) {
156                addWord(i.key(), row++);
157         }
158
159         model->sort(0);
160         resizeColumns();
161     }
162     else {
163         QStandardItem* item = new QStandardItem(tr("Can't find any matching words"));
164         item->setFlags(item->flags() ^ Qt::ItemIsEditable);
165         item->setTextAlignment(Qt::AlignCenter);
166         setEnabled(false);
167
168         model->setItem(0,item);
169     }
170 #else
171
172     QHash<QString, bool> wordsInBookmarks;
173     QHashIterator<QString, QList<Translation *> > i(result);
174     while (i.hasNext()){
175         i.next();
176
177         bool bookmark = false;
178         Translation* t;
179         foreach(t, searchResult[i.key()]) {
180             if(t->isBookmark()) {
181                 bookmark = true;
182                 break;
183             }
184         }
185         wordsInBookmarks.insert(i.key(), bookmark);
186     }
187
188     if (result.count() == 0){
189         //result.insert("!@#$%", QList<Translation*>());
190 //        wordsInBookmarks.insert("!@#$%", false);
191         Q_EMIT setWordListState(false);
192         Q_EMIT setWordListEmpty(true);
193     } else {
194         Q_EMIT setWordListEmpty(false);
195     }
196
197     if (listModel == 0){
198         listModel = new WordListModel(this);
199     }
200
201     listModel->setBookmarkModeActive(_isBookmarkModeActive);
202     _isBookmarkModeActive = false;
203     listModel->setTranslations(result, wordsInBookmarks);
204
205 #endif
206
207     setFocus();
208 }
209
210 #ifdef Q_WS_MAEMO
211 void WordListWidget::wordClicked(QModelIndex index) {
212     //we're getting translation based on data in index
213     Q_EMIT showTranslation(
214             searchResult[index.data().toString()]);
215 }
216
217 void WordListWidget::wordChecked(QModelIndex index) {
218
219     //save new item state
220     Qt::CheckState state =
221             Qt::CheckState(index.data(Qt::CheckStateRole).toInt());
222
223
224     //getting index of item which contains word which should be added/removed
225     //from bookmarks
226     QModelIndex item = selectedIndexes().at(0);
227     if(!item.isValid()) return;
228
229     //to shorten lag between clicking on a star and its change
230     repaint();
231
232     //depending on new state emit suitable signal
233     if(state == Qt::Checked) {
234         Q_EMIT addBookmark(searchResult[item.data().toString()]);
235     }
236     else {
237         Q_EMIT removeBookmark(searchResult[item.data().toString()]);
238
239         Translation* t;
240         bool onlyBookmarks = true;
241         foreach(t, searchResult[item.data().toString()]) {
242             if(t->isBookmark() == 1 || t->isBookmark()==0) {
243
244                 onlyBookmarks = false;
245                 t->setBookmark(0);
246             }
247             else {
248                 searchResult[item.data().toString()].removeAt(searchResult[item.data().toString()].indexOf(t));
249             }
250         }
251
252         if(onlyBookmarks) {
253             searchResult.remove(item.data().toString());
254             model->removeRow(item.row());
255         }
256     }
257 }
258
259 void WordListWidget::mouseReleaseEvent(QMouseEvent *event) {
260
261     //firstly we normally handle this event
262     QTreeView::mouseReleaseEvent(event);
263
264     //then we check at which item user clicked
265     QModelIndex index = indexAt(event->pos());
266     if(!index.isValid()) return;
267
268     /*if there are no selected items we return, that occurs sometimes
269     on maemo, when user is scrolling list and clicks to stop the scroll,
270     system doesn't select item but emits mouseReleaseEvent*/
271     if(selectedIndexes().count() == 0) return;
272
273     //if user doesn't click either on a word or on a star, return
274     if(selectedIndexes().at(0) != index && selectedIndexes().at(1) != index)
275         return;
276
277     int c = index.column();
278     if(c==0)
279         //if column is 0 user clicked on a word
280         wordClicked(index);
281     else
282         //else user clicked on a star
283         wordChecked(index);
284 }
285
286 void WordListWidget::resizeEvent(QResizeEvent *event) {
287     resizeColumns();
288     QTreeView::resizeEvent(event);
289 }
290
291 void WordListWidget::keyPressEvent(QKeyEvent *event) {
292     QTreeView::keyPressEvent(event);
293
294     if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
295         if(selectedIndexes().count() == 0) return;
296
297         wordClicked(selectedIndexes().at(0));
298     }
299 }
300 #else
301     void WordListWidget::wordClicked(QString word){
302         emit showTranslation(searchResult[word]);
303     }
304
305     void WordListWidget::addToBookmarks(QString word){
306         emit addBookmark(searchResult[word]);
307     }
308
309     void WordListWidget::removeFromBookmarks(QString word){
310         emit removeBookmark(searchResult[word]);
311     }
312
313     void WordListWidget::wordClickedByIndex(int index){
314         emit showTranslation(searchResult[listModel->wordOnPosition(index)]);
315     }
316
317     void WordListWidget::setFocusOnElement(){
318         setFocus();
319         qmlView->setFocus();
320         Q_EMIT setFocusOnQML();
321     }
322
323 #endif
324
325 void WordListWidget::resizeColumns() {
326     setColumnWidth(0, viewport()->width() -checkBoxWidth - 5);
327     setColumnWidth(1, checkBoxWidth);
328 }
329
330 void WordListWidget::lockList() {
331 #ifdef Q_WS_MAEMO_5
332     setEnabled(false);
333 #else
334     Q_EMIT setWordListState(false);
335 #endif
336 }
337
338 void WordListWidget::unlockList() {
339 #ifdef Q_WS_MAEMO_5
340     setEnabled(true);
341 #else
342     Q_EMIT setWordListState(true);
343 #endif
344 }
345
346 void WordListWidget::clear() {
347 #ifdef Q_WS_MAEMO_5
348     model->clear();
349 #else
350     if (listModel != 0){
351         listModel->clear();
352     }
353 #endif
354
355     QHash<QString, QList<Translation*> >::iterator i;
356     for(i = searchResult.begin(); i != searchResult.end(); i++) {
357            Translation*t;
358            foreach(t, i.value()) {
359                delete t;
360            }
361     }
362     searchResult.clear();
363 }
364
365 void WordListWidget::bookmarkModeActive(){
366     _isBookmarkModeActive = true;
367 }