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