Improve speed of conjugating.
[mverbiste] / mainwindow.cpp
1 #include "mainwindow.h"
2 #include "ui_mainwindow.h"
3 #include "gui/conjugation.h"
4
5 #include <QtCore/QCoreApplication>
6
7 MainWindow::MainWindow(QWidget *parent)
8     : QMainWindow(parent), ui(new Ui::MainWindow)
9 {
10 #ifdef Q_WS_MAEMO_5
11     this->setAttribute(Qt::WA_Maemo5StackedWindow);
12     this->setWindowFlags(Qt::Window);
13 #endif
14     ui->setupUi(this);
15     setupcodedUI();
16     initverbiste();
17 }
18
19 void MainWindow::setupcodedUI()
20 {
21     cent = centralWidget();
22     mlayout = new QVBoxLayout;
23     btlayout = new QHBoxLayout;
24
25     resultPages = new QTabWidget;
26     resultPages->setTabPosition(QTabWidget::West);
27     mlayout->addWidget(resultPages);
28
29     btnClear = new QPushButton;
30     btnClear->setIcon(QIcon("/usr/share/icons/hicolor/64x64/hildon/general_delete.png"));
31     wordinput = new QLineEdit;
32     btlayout->addWidget(btnClear);
33     btlayout->addWidget(wordinput);
34     btnLookup = new QPushButton;  // Lookup button
35     btnLookup->setIcon(QIcon("/usr/share/icons/hicolor/64x64/hildon/general_search.png"));
36     btlayout->addWidget(btnLookup);
37
38     mlayout->addLayout(btlayout);
39     cent->setLayout(mlayout);
40
41     // Clear the word input when Clear button is tapped
42     connect(btnClear, SIGNAL(clicked()), this, SLOT(startAgain()));
43
44     connect(wordinput, SIGNAL(returnPressed()), this, SLOT(startLookup()));
45     connect(btnLookup, SIGNAL(clicked()), this, SLOT(startLookup()));
46 }
47
48 MainWindow::~MainWindow()
49 {
50     delete ui;
51     delete freVerbDic;
52 }
53
54 void MainWindow::setOrientation(ScreenOrientation orientation)
55 {
56 #if defined(Q_OS_SYMBIAN)
57     // If the version of Qt on the device is < 4.7.2, that attribute won't work
58     if (orientation != ScreenOrientationAuto) {
59         const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
60         if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
61             qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
62             return;
63         }
64     }
65 #endif // Q_OS_SYMBIAN
66
67     Qt::WidgetAttribute attribute;
68     switch (orientation) {
69 #if QT_VERSION < 0x040702
70     // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
71     case ScreenOrientationLockPortrait:
72         attribute = static_cast<Qt::WidgetAttribute>(128);
73         break;
74     case ScreenOrientationLockLandscape:
75         attribute = static_cast<Qt::WidgetAttribute>(129);
76         break;
77     default:
78     case ScreenOrientationAuto:
79         attribute = static_cast<Qt::WidgetAttribute>(130);
80         break;
81 #else // QT_VERSION < 0x040702
82     case ScreenOrientationLockPortrait:
83         attribute = Qt::WA_LockPortraitOrientation;
84         break;
85     case ScreenOrientationLockLandscape:
86         attribute = Qt::WA_LockLandscapeOrientation;
87         break;
88     default:
89     case ScreenOrientationAuto:
90         attribute = Qt::WA_AutoOrientation;
91         break;
92 #endif // QT_VERSION < 0x040702
93     };
94     setAttribute(attribute, true);
95 }
96
97 void MainWindow::showExpanded()
98 {
99 #if defined(Q_OS_SYMBIAN) || defined(Q_WS_SIMULATOR)
100     showFullScreen();
101 #elif defined(Q_WS_MAEMO_5)
102     showMaximized();
103 #else
104     show();
105 #endif
106     wordinput->setFocus();
107 }
108
109 void  MainWindow::initverbiste()
110 {
111     langCode = "fr";
112
113     FrenchVerbDictionary::Language lang = FrenchVerbDictionary::parseLanguageCode(langCode);
114     if (lang != FrenchVerbDictionary::FRENCH)
115     {
116         // TODO: If lang code is not supported?
117     }
118
119     /* Create verb dictionary, accept non-accent input */
120     freVerbDic = new FrenchVerbDictionary(true);
121 }
122
123 void MainWindow::startLookup()
124 {
125     QString input = wordinput->text().trimmed();
126     if (input.isEmpty()) {
127         return;
128     }
129
130     btnLookup->setText(tr("Please wait..."));
131     btnLookup->setEnabled(false);
132     clearResults();
133     /* Pending the lookup job to the next event loop (redraw the button right now) */
134     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
135
136     /* Get input word to look up */
137     const std::string word = input.toLower().toUtf8().constData();
138
139     /*
140      *  For each possible deconjugation, take the infinitive form and
141      *  obtain its complete conjugation.
142      */
143     std::vector<InflectionDesc> infles;
144     bool includePronouns = FALSE;    // TODO: Will get this value from external
145     bool isItalian = FALSE;          // TODO: Will get this value from external
146
147     freVerbDic->deconjugate(word, infles);
148
149     resultPages->setUpdatesEnabled(false);
150     std::string prevUTF8Infinitive, prevTemplateName; /* Remember found word
151     to avoid conjugating again */
152
153     for (std::vector<InflectionDesc>::const_iterator it = infles.begin();
154          it != infles.end(); it++)
155     {
156         const InflectionDesc &d = *it;
157
158 #ifndef QT_NO_DEBUG
159         qDebug() << ">> Infinitive " << d.infinitive.c_str();
160         qDebug() << "   Template " << d.templateName.c_str();
161 #endif
162         /* If this infinitive has been conjugated, we skip to the next infinitive */
163         if (d.infinitive == prevUTF8Infinitive && d.templateName == prevTemplateName) {
164             continue;
165         }
166         /* FIXME:
167          * In original source (Verbiste), this checking is done later,
168          * after getConjugation(). I place it here to avoid calling again
169          * multitimes getConjugation(), which is very slow.
170          * We need to test more to see which place is more correct.
171          */
172
173         VVVS conjug;
174         getConjugation(freVerbDic, d.infinitive, d.templateName, conjug, includePronouns);
175
176         if (conjug.size() == 0           // if no tenses
177             || conjug[0].size() == 0     // if no infinitive tense
178             || conjug[0][0].size() == 0  // if no person in inf. tense
179             || conjug[0][0][0].empty())  // if infinitive string empty
180         {
181             continue;
182         }
183
184         std::string utf8Infinitive = conjug[0][0][0];
185 #ifndef QT_NO_DEBUG
186         qDebug() << "   getConjugation() returns:";
187         qDebug() << "     Infinitive " << utf8Infinitive.c_str() << " at " << timer.elapsed();
188         qDebug() << "     Template " << d.templateName.c_str();
189 #endif
190
191         /* Add result to GUI (not show yet) */
192         ResultPage *rsp = addResultPage(utf8Infinitive);
193
194         /* Get modes and tenses of the verb */
195         int i = 0;
196         for (VVVS::const_iterator t = conjug.begin();
197              t != conjug.end(); t++, i++) {
198             if (i == 1)
199                 i = 4;
200             else if (i == 11)
201                 i = 12;
202             assert(i >= 0 && i < 16);
203
204             int row = i / 4;
205             int col = i % 4;
206
207             std::string utf8TenseName = getTenseNameForTableCell(row, col, isItalian);
208             if (utf8TenseName.empty())
209                 continue;
210
211             QVBoxLayout *cell = makeResultCell(*t, utf8TenseName, word, freVerbDic);
212             rsp->grid->addLayout(cell, row, col);
213         }
214         /* Show the result on GUI */
215         rsp->packContent();
216         prevUTF8Infinitive = utf8Infinitive;
217         prevTemplateName = d.templateName;
218     }
219     /* Enable the button again */
220     btnLookup->setEnabled(true);
221     btnLookup->setText("");
222     resultPages->setUpdatesEnabled(true);
223 }
224
225 ResultPage* MainWindow::addResultPage(const std::string &labelText)
226 {
227     ResultPage *rp = new ResultPage();
228     QString label = QString::fromUtf8(labelText.c_str());
229     resultPages->addTab(rp->page, label);
230     return rp;
231 }
232
233 void MainWindow::clearResults()
234 {
235     while (resultPages->count()) {
236         int lastIndex = resultPages->count() - 1;
237         resultPages->widget(lastIndex)->deleteLater();
238         resultPages->removeTab(lastIndex);
239     }
240 }
241
242 void MainWindow::startAgain()
243 {
244     wordinput->clear();
245     clearResults();
246     wordinput->setFocus();
247     btnLookup->setEnabled(true);
248 }
249
250 QVBoxLayout* MainWindow::makeResultCell(const VVS &tenseIterator,
251                                         const std::string &tenseName,
252                                         const std::string &inputWord,
253                                         FrenchVerbDictionary *verbDict)
254 {
255     /* Mode & Tense name */
256     QLabel *tenseLabel = new QLabel();
257     tenseLabel->setText(QString::fromUtf8(tenseName.c_str()));
258     tenseLabel->setStyleSheet("QLabel {background-color: #44A51C; "
259                               "padding-left: 10px; padding-right: 10px}");
260
261     /* Conjugaison */
262     QVBoxLayout *vbox = new QVBoxLayout();
263     vbox->addWidget(tenseLabel);
264     QVector<QString> persons = qgetConjugates(*verbDict, tenseIterator,inputWord,
265                                               "<font color='#D20020'>", "</font>");
266     for (int i = 0; i < persons.size(); ++i) {
267         QLabel *lb = new QLabel(persons.at(i));
268         lb->setMargin(4);
269         vbox->addWidget(lb, 1);
270     }
271     return vbox;
272 }
273
274 /**** For ResultPage class ****/
275 ResultPage::ResultPage()
276     : page(new QScrollArea),
277       grid(new QGridLayout)
278 {
279 }
280
281 void ResultPage::packContent()
282 {
283     QWidget *immediate = new QWidget();
284     immediate->setLayout(grid);
285     page->setWidget(immediate);
286 }
287