781a76a81f8f400ec35661d1025c6054f0cc0f0f
[mverbiste] / gui / conjugation.cpp
1 /*  $Id: conjugation.cpp,v 1.12 2011/01/25 02:29:44 sarrazip Exp $
2     conjugation.cpp - Generic conjugation interface
3
4     verbiste - French conjugation system
5     Copyright (C) 2003-2006 Pierre Sarrazin <http://sarrazip.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
9     as published by the Free Software Foundation; either version 2
10     of 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, write to the Free Software
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20     02111-1307, USA.
21 */
22
23 #include "conjugation.h"
24
25 #include <libintl.h>
26 #define _(x) gettext(x)
27 #define N_(x) (x)
28
29 #include <iostream>
30 #include <string.h>
31
32 using namespace std;
33 using namespace verbiste;
34
35
36 void
37 getConjugation(const FrenchVerbDictionary &fvd,
38                         const string &infinitive,
39                         const string &tname,
40                         VVVS &dest,
41                #ifndef QT_NO_DEBUG
42                QElapsedTimer &timer,
43                #endif
44                         bool includePronouns)
45 {
46 #ifndef QT_NO_DEBUG
47         qDebug() << " *>> Inside getConjugation " << timer.elapsed();
48 #endif
49     const TemplateSpec *templ = fvd.getTemplate(tname);
50     if (templ == NULL)
51         return;
52
53     try
54     {
55         static const struct { Mode m; Tense t; } table[] =
56         {
57             { INFINITIVE_MODE, PRESENT_TENSE },
58             { INDICATIVE_MODE, PRESENT_TENSE },
59             { INDICATIVE_MODE, IMPERFECT_TENSE },
60             { INDICATIVE_MODE, FUTURE_TENSE },
61             { INDICATIVE_MODE, PAST_TENSE },
62             { CONDITIONAL_MODE, PRESENT_TENSE },
63             { SUBJUNCTIVE_MODE, PRESENT_TENSE },
64             { SUBJUNCTIVE_MODE, IMPERFECT_TENSE },
65             { IMPERATIVE_MODE, PRESENT_TENSE },
66             { PARTICIPLE_MODE, PRESENT_TENSE },
67             { PARTICIPLE_MODE, PAST_TENSE },
68             { GERUND_MODE, PRESENT_TENSE },  // italian only
69             { INVALID_MODE, INVALID_TENSE }  // marks the end
70         };
71
72
73         string radical = FrenchVerbDictionary::getRadical(infinitive, tname);
74
75         bool isItalian = (fvd.getLanguage() == FrenchVerbDictionary::ITALIAN);
76
77         for (int j = 0; table[j].m != INVALID_MODE; j++)
78         {
79             if (table[j].m == GERUND_MODE && !isItalian)
80                 continue;
81
82             dest.push_back(VVS());
83             VVS &tenseDest = dest.back();
84
85             VVS conjug;
86             fvd.generateTense(radical, *templ, table[j].m, table[j].t, conjug,
87                                 includePronouns,
88                                 fvd.isVerbStartingWithAspirateH(infinitive),
89                                 isItalian);
90
91             for (VVS::const_iterator p = conjug.begin(); p != conjug.end(); p++)
92             {
93                 tenseDest.push_back(VS());
94                 for (VS::const_iterator i = p->begin(); i != p->end(); i++)
95                 {
96                     string s = *i;
97                     tenseDest.back().push_back(s);
98                 }
99             }
100         }
101     }
102     catch (logic_error &e)
103     {
104         dest.clear();
105         return;
106     }
107 }
108
109
110 static const char *tn[16] =
111 {
112     N_("inf. pres."),
113     "",
114     "",
115     "",
116     N_("ind. pres."),
117     N_("ind. imperf."),
118     N_("ind. fut."),
119     N_("ind. past"),
120     N_("cond. pres."),
121     N_("subj. pres."),
122     N_("subj. imperf."),
123     "",
124     N_("imp. pres."),
125     N_("part. pres."),
126     N_("part. past"),
127     N_("gerund pres."),  // italian only
128 };
129
130
131 string getTenseNameForTableCell(int row, int col, bool isItalian)
132 {
133     if (row < 0 || row > 3 || col < 0 || col > 3)
134     {
135         assert(false);
136         return "";
137     }
138
139     if (row == 3 && col == 3 && !isItalian)
140         return string();
141
142     return _(tn[row * 4 + col]);
143 }
144
145
146 static
147 string
148 removePronoun(const string &s)
149 {
150     string::size_type start = 0;
151     if (s.find("que ") == 0)
152         start = 4;
153     else if (s.find("qu'") == 0)
154         start = 3;
155     else if (s.find("che ") == 0)  // Italian
156         start = 4;
157
158     static const char *pronouns[] =
159     {
160         "je ", "j'", "tu ", "il ", "nous ", "vous ", "ils ",
161         "io ", "tu ", "egli ", "noi ", "voi ", "essi ",  // Italian
162         NULL
163     };
164
165     for (size_t i = 0; pronouns[i] != NULL; i++)
166     {
167         size_t len = strlen(pronouns[i]);
168         if (s.find(pronouns[i], start) == start)
169         {
170             start += len;
171             break;
172         }
173     }
174
175     return string(s, start, string::npos);
176 }
177
178
179 string
180 createTableCellText(verbiste::FrenchVerbDictionary &fvd,
181                     const VVS &tense,
182                     const string &lowerCaseUTF8UserText,
183                     const string &openMark,
184                     const string &closeMark)
185 {
186     string userTextWOAccents = fvd.removeUTF8Accents(lowerCaseUTF8UserText);
187
188     string persons;
189     for (VVS::const_iterator it = tense.begin(); it != tense.end(); it++)
190     {
191         const VS &person = *it;
192
193         if (it != tense.begin())
194             persons += "\n";
195
196         for (VS::const_iterator i = person.begin(); i != person.end(); i++)
197         {
198             if (i != person.begin())
199                 persons += ", ";
200
201             string inflection = fvd.removeUTF8Accents(removePronoun(*i));
202             if (inflection == userTextWOAccents)
203                 persons += openMark + *i + closeMark;
204             else
205                 persons += *i;
206         }
207     }
208     return persons;
209 }
210
211
212 /**
213  * Qt version of createTableCellText() above.
214  * Return a vertor of QStrings, which are conjugations.
215  **/
216 QVector<QString> qgetConjugates(verbiste::FrenchVerbDictionary &fvd,
217                                 const VVS &tense,
218                                 const string &lowerCaseUTF8UserText,
219                                 const string &openMark,
220                                 const string &closeMark)
221 {
222     string userTextWOAccents = fvd.removeUTF8Accents(lowerCaseUTF8UserText);
223     QVector<QString> persons(0);
224     for (VVS::const_iterator it = tense.begin(); it != tense.end(); it++)
225     {
226         const VS &person = *it;
227         QString ver;
228
229 //        if (it != tense.begin())
230 //            persons += "\n";
231
232         for (VS::const_iterator i = person.begin(); i != person.end(); i++)
233         {
234             if (i != person.begin())
235                 ver.append(", ");
236
237             string inflection = fvd.removeUTF8Accents(removePronoun(*i));
238             if (inflection == userTextWOAccents) {
239                 const std::string wrapped = openMark + *i + closeMark;
240                 ver.append(QString::fromUtf8(wrapped.c_str()));
241             }
242             else {
243                 const char *str = (*i).c_str();
244                 ver.append(QString::fromUtf8(str));
245             }
246         }
247         persons.append(ver);
248     }
249     return persons;
250 }