1 | /*************************************************************************** |
2 | phraselist.cpp - description |
3 | ------------------- |
4 | begin : Mit Sep 11 2002 |
5 | copyright : (C) 2002 by Gunnar Schmi Dt |
6 | email : kmouth@schmi-dt.de |
7 | ***************************************************************************/ |
8 | |
9 | /*************************************************************************** |
10 | * * |
11 | * This program is free software; you can redistribute it and/or modify * |
12 | * it under the terms of the GNU General Public License as published by * |
13 | * the Free Software Foundation; either version 2 of the License, or * |
14 | * (at your option) any later version. * |
15 | * * |
16 | ***************************************************************************/ |
17 | |
18 | // application specific includes |
19 | #include "phraselist.h" |
20 | #include "phraselistitem.h" |
21 | #include "phraseedit.h" |
22 | #include "kmouth.h" |
23 | #include "texttospeechsystem.h" |
24 | #include "phrasebook/phrasebook.h" |
25 | #include "wordcompletion/wordcompletion.h" |
26 | |
27 | // include files for Qt |
28 | #include <QtGui/QPainter> |
29 | #include <QtGui/QLayout> |
30 | #include <QtGui/QApplication> |
31 | #include <QtGui/QMenu> |
32 | #include <QtGui/QClipboard> |
33 | #include <QtGui/QVBoxLayout> |
34 | #include <QtGui/QHBoxLayout> |
35 | #include <QtGui/QKeyEvent> |
36 | |
37 | // include files for KDE |
38 | #include <klineedit.h> |
39 | #include <kcursor.h> |
40 | #include <kiconloader.h> |
41 | #include <klocale.h> |
42 | #include <kfiledialog.h> |
43 | #include <kcombobox.h> |
44 | #include <kmessagebox.h> |
45 | #include <kxmlguifactory.h> |
46 | |
47 | #include <stdlib.h> |
48 | |
49 | |
50 | PhraseList::PhraseList(QWidget *parent, const char *name) : QWidget(parent) { |
51 | Q_UNUSED(name); |
52 | isInSlot = false; |
53 | // FIXME: Remove or change PaletteBase to Qt::OpaqueMode? |
54 | // setBackgroundMode(PaletteBase); |
55 | QVBoxLayout *layout = new QVBoxLayout (this); |
56 | |
57 | listBox = new K3ListBox (this); |
58 | listBox->setFocusPolicy(Qt::NoFocus); |
59 | listBox->setSelectionMode (Q3ListBox::Extended); |
60 | listBox->setWhatsThis( i18n("This list contains the history of spoken sentences. You can select sentences and press the speak button for re-speaking." )); |
61 | layout->addWidget(listBox); |
62 | |
63 | QHBoxLayout *rowLayout = new QHBoxLayout (); |
64 | layout->addLayout(rowLayout); |
65 | |
66 | completion = new WordCompletion(); |
67 | |
68 | dictionaryCombo = new KComboBox (this); |
69 | configureCompletionCombo(completion->wordLists()); |
70 | rowLayout->addWidget(dictionaryCombo); |
71 | |
72 | lineEdit = new PhraseEdit (QLatin1String( "" ), this); |
73 | lineEdit->setFocusPolicy(Qt::StrongFocus); |
74 | lineEdit->setFrame(true); |
75 | lineEdit->setEchoMode(QLineEdit::Normal); |
76 | lineEdit->setCompletionObject (completion); |
77 | lineEdit->setAutoDeleteCompletionObject(true); |
78 | lineEdit->setWhatsThis( i18n("Into this edit field you can type a phrase. Click on the speak button in order to speak the entered phrase." )); |
79 | rowLayout->addWidget(lineEdit); |
80 | lineEdit->setFocus(); |
81 | |
82 | QIcon icon = KIconLoader::global()->loadIconSet(QLatin1String( "speak" ), KIconLoader::Small); |
83 | speakButton = new QPushButton (icon, i18n("&Speak" ), this); |
84 | speakButton->setFocusPolicy(Qt::NoFocus); |
85 | speakButton->setAutoDefault(false); |
86 | speakButton->setWhatsThis( i18n("Speaks the currently active sentence(s). If there is some text in the edit field it is spoken. Otherwise the selected sentences in the history (if any) are spoken." )); |
87 | rowLayout->addWidget(speakButton); |
88 | |
89 | connect(dictionaryCombo, SIGNAL (activated(QString)), completion, SLOT (setWordList(QString))); |
90 | connect(completion, SIGNAL (wordListsChanged(QStringList)), this, SLOT (configureCompletionCombo(QStringList))); |
91 | connect(listBox, SIGNAL(selectionChanged()), SLOT(selectionChanged())); |
92 | connect(listBox, SIGNAL(contextMenuRequested(Q3ListBoxItem*,QPoint)), SLOT(contextMenuRequested(Q3ListBoxItem*,QPoint))); |
93 | connect(lineEdit, SIGNAL(returnPressed(QString)), SLOT(lineEntered(QString))); |
94 | connect(lineEdit, SIGNAL(textChanged(QString)), SLOT(textChanged(QString))); |
95 | connect(speakButton, SIGNAL(clicked()), SLOT(speak())); |
96 | } |
97 | |
98 | PhraseList::~PhraseList() { |
99 | delete speakButton; |
100 | delete listBox; |
101 | delete lineEdit; |
102 | } |
103 | |
104 | void PhraseList::print(QPrinter *pPrinter) { |
105 | PhraseBook book; |
106 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
107 | book += PhraseBookEntry(Phrase(item->text())); |
108 | } |
109 | |
110 | book.print (pPrinter); |
111 | } |
112 | |
113 | QStringList PhraseList::getListSelection() { |
114 | QStringList res = QStringList(); |
115 | |
116 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
117 | if (item->isSelected()) |
118 | res += item->text(); |
119 | } |
120 | |
121 | return res; |
122 | } |
123 | |
124 | bool PhraseList::existListSelection() { |
125 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
126 | if (item->isSelected()) |
127 | return true; |
128 | } |
129 | |
130 | return false; |
131 | } |
132 | |
133 | bool PhraseList::existEditSelection() { |
134 | return lineEdit->hasSelectedText(); |
135 | } |
136 | |
137 | void PhraseList::() { |
138 | bool deselected = false; |
139 | bool selected = false; |
140 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
141 | if (item->isSelected()) |
142 | selected = true; |
143 | else |
144 | deselected = true; |
145 | } |
146 | KMouthApp *theApp=(KMouthApp *) parentWidget(); |
147 | theApp->enableMenuEntries (selected, deselected); |
148 | } |
149 | |
150 | void PhraseList::configureCompletion() { |
151 | completion->configure(); |
152 | } |
153 | |
154 | void PhraseList::configureCompletionCombo(const QStringList &list) { |
155 | QString current = completion->currentWordList(); |
156 | dictionaryCombo->clear(); |
157 | if (list.isEmpty()) |
158 | dictionaryCombo->hide(); |
159 | else if (list.count() == 1) { |
160 | dictionaryCombo->addItems (list); |
161 | dictionaryCombo->setCurrentIndex (0); |
162 | dictionaryCombo->hide(); |
163 | } |
164 | else { |
165 | dictionaryCombo->addItems (list); |
166 | dictionaryCombo->show(); |
167 | |
168 | QStringList::ConstIterator it; |
169 | int i = 0; |
170 | for (it = list.begin(), i = 0; it != list.end(); ++it, ++i) { |
171 | if (current == *it) { |
172 | dictionaryCombo->setCurrentIndex (i); |
173 | return; |
174 | } |
175 | } |
176 | } |
177 | } |
178 | |
179 | void PhraseList::saveCompletionOptions(KConfig *config) { |
180 | KConfigGroup cg(config,"General Options" ); |
181 | cg.writeEntry("Show speak button" , speakButton->isVisible() || !lineEdit->isVisible()); |
182 | |
183 | KConfigGroup cg2(config,"Completion" ); |
184 | cg2.writeEntry("Mode" , static_cast<int>(lineEdit->completionMode())); |
185 | cg2.writeEntry("List" , completion->currentWordList()); |
186 | } |
187 | |
188 | void PhraseList::readCompletionOptions(KConfig *config) { |
189 | KConfigGroup cg(config,"General Options" ); |
190 | if (!cg.readEntry("Show speak button" , true)) |
191 | speakButton->hide(); |
192 | |
193 | if (config->hasGroup ("Completion" )) { |
194 | KConfigGroup cg2(config, "Completion" ); |
195 | int mode = cg2.readEntry ("Mode" , int(KGlobalSettings::completionMode())); |
196 | lineEdit->setCompletionMode (static_cast<KGlobalSettings::Completion>(mode)); |
197 | |
198 | QString current = cg2.readEntry ("List" , QString()); |
199 | const QStringList list = completion->wordLists(); |
200 | QStringList::ConstIterator it; |
201 | int i = 0; |
202 | for (it = list.constBegin(), i = 0; it != list.constEnd(); ++it, ++i) { |
203 | if (current == *it) { |
204 | dictionaryCombo->setCurrentIndex (i); |
205 | return; |
206 | } |
207 | } |
208 | } |
209 | } |
210 | |
211 | void PhraseList::saveWordCompletion () { |
212 | completion->save(); |
213 | } |
214 | |
215 | |
216 | void PhraseList::selectAllEntries () { |
217 | listBox->selectAll (true); |
218 | } |
219 | |
220 | void PhraseList::deselectAllEntries () { |
221 | listBox->selectAll (false); |
222 | } |
223 | |
224 | void PhraseList::speak () { |
225 | QString phrase = lineEdit->text(); |
226 | if (phrase.isNull() || phrase.isEmpty()) |
227 | speakListSelection(); |
228 | else { |
229 | insertIntoPhraseList (phrase, true); |
230 | speakPhrase (phrase); |
231 | } |
232 | } |
233 | |
234 | void PhraseList::cut() { |
235 | if (lineEdit->hasSelectedText()) |
236 | lineEdit->cut(); |
237 | else |
238 | cutListSelection(); |
239 | } |
240 | |
241 | void PhraseList::copy() { |
242 | if (lineEdit->hasSelectedText()) |
243 | lineEdit->copy(); |
244 | else |
245 | copyListSelection(); |
246 | } |
247 | |
248 | void PhraseList::paste() { |
249 | lineEdit->paste(); |
250 | } |
251 | |
252 | void PhraseList::insert (const QString &s) { |
253 | setEditLineText(s); |
254 | } |
255 | |
256 | void PhraseList::speakListSelection () { |
257 | speakPhrase(getListSelection().join (QLatin1String( "\n" ))); |
258 | } |
259 | |
260 | void PhraseList::removeListSelection () { |
261 | Q3ListBoxItem *next; |
262 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = next) { |
263 | next = item->next(); |
264 | |
265 | if (item->isSelected()) { |
266 | listBox->removeItem(listBox->index(item)); |
267 | } |
268 | } |
269 | enableMenuEntries (); |
270 | } |
271 | |
272 | void PhraseList::cutListSelection () { |
273 | copyListSelection (); |
274 | removeListSelection (); |
275 | } |
276 | |
277 | void PhraseList::copyListSelection () { |
278 | QApplication::clipboard()->setText (getListSelection().join (QLatin1String( "\n" ))); |
279 | } |
280 | |
281 | void PhraseList::lineEntered (const QString &phrase) { |
282 | if (phrase.isNull() || phrase.isEmpty()) |
283 | speakListSelection(); |
284 | else { |
285 | insertIntoPhraseList (phrase, true); |
286 | speakPhrase (phrase); |
287 | } |
288 | } |
289 | |
290 | void PhraseList::speakPhrase (const QString &phrase) { |
291 | // QApplication::setOverrideCursor (KCursor::WaitCursor, false); |
292 | QApplication::setOverrideCursor (Qt::WaitCursor); |
293 | KMouthApp *theApp=(KMouthApp *) parentWidget(); |
294 | QString language = completion->languageOfWordList (completion->currentWordList()); |
295 | theApp->getTTSSystem()->speak(phrase, language); |
296 | QApplication::restoreOverrideCursor (); |
297 | } |
298 | |
299 | void PhraseList::insertIntoPhraseList (const QString &phrase, bool clearEditLine) { |
300 | int lastLine = listBox->count() - 1; |
301 | if ((lastLine == -1) || (phrase != listBox->text(lastLine))) { |
302 | listBox->insertItem(new PhraseListItem(phrase)); |
303 | if (clearEditLine) |
304 | completion->addSentence (phrase); |
305 | } |
306 | |
307 | if (clearEditLine) { |
308 | lineEdit->selectAll(); |
309 | line.clear(); |
310 | } |
311 | enableMenuEntries (); |
312 | } |
313 | |
314 | void PhraseList:: (Q3ListBoxItem *, const QPoint &pos) { |
315 | QString name; |
316 | if (existListSelection()) |
317 | name = QLatin1String( "phraselist_selection_popup" ); |
318 | else |
319 | name = QLatin1String( "phraselist_popup" ); |
320 | |
321 | KMouthApp *theApp=(KMouthApp *) parentWidget(); |
322 | KXMLGUIFactory *factory = theApp->factory(); |
323 | QMenu * = (QMenu *)factory->container(name,theApp); |
324 | if (popup != 0) { |
325 | popup->exec(pos, 0); |
326 | } |
327 | } |
328 | |
329 | void PhraseList::textChanged (const QString &s) { |
330 | if (!isInSlot) { |
331 | isInSlot = true; |
332 | line = s; |
333 | listBox->setCurrentItem (listBox->count() - 1); |
334 | listBox->clearSelection (); |
335 | isInSlot = false; |
336 | } |
337 | } |
338 | |
339 | void PhraseList::selectionChanged () { |
340 | if (!isInSlot) { |
341 | isInSlot = true; |
342 | |
343 | QStringList sel = getListSelection(); |
344 | |
345 | if (sel.empty()) |
346 | setEditLineText(line); |
347 | else if (sel.count() == 1) |
348 | setEditLineText(sel.first()); |
349 | else { |
350 | setEditLineText(QLatin1String( "" )); |
351 | } |
352 | isInSlot = false; |
353 | } |
354 | enableMenuEntries (); |
355 | } |
356 | |
357 | void PhraseList::setEditLineText(const QString &s) { |
358 | lineEdit->end(false); |
359 | while (!(lineEdit->text().isNull() || lineEdit->text().isEmpty())) |
360 | lineEdit->backspace(); |
361 | lineEdit->insert(s); |
362 | } |
363 | |
364 | void PhraseList::keyPressEvent (QKeyEvent *e) { |
365 | if (e->key() == Qt::Key_Up) { |
366 | bool selected = false; |
367 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
368 | if (item->isSelected()) { |
369 | selected = true; |
370 | } |
371 | } |
372 | |
373 | if (!selected) { |
374 | listBox->setCurrentItem (listBox->count() - 1); |
375 | listBox->setSelected (listBox->count() - 1, true); |
376 | listBox->ensureCurrentVisible (); |
377 | } |
378 | else { |
379 | int curr = listBox->currentItem(); |
380 | |
381 | if (curr == -1) { |
382 | isInSlot = true; |
383 | listBox->clearSelection(); |
384 | isInSlot = false; |
385 | curr = listBox->count() - 1; |
386 | listBox->setCurrentItem (curr); |
387 | listBox->setSelected (curr, true); |
388 | listBox->ensureCurrentVisible (); |
389 | } |
390 | else if (curr != 0) { |
391 | isInSlot = true; |
392 | listBox->clearSelection(); |
393 | isInSlot = false; |
394 | listBox->setCurrentItem (curr - 1); |
395 | listBox->setSelected (curr - 1, true); |
396 | listBox->ensureCurrentVisible (); |
397 | } |
398 | } |
399 | |
400 | e->accept(); |
401 | } |
402 | else if (e->key() == Qt::Key_Down) { |
403 | bool selected = false; |
404 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
405 | if (item->isSelected()) { |
406 | selected = true; |
407 | } |
408 | } |
409 | |
410 | if (selected) { |
411 | int curr = listBox->currentItem(); |
412 | |
413 | if (curr == (int)listBox->count() - 1) { |
414 | listBox->clearSelection(); |
415 | } |
416 | else if (curr != -1) { |
417 | isInSlot = true; |
418 | listBox->clearSelection(); |
419 | isInSlot = false; |
420 | listBox->setCurrentItem (curr + 1); |
421 | listBox->setSelected (curr + 1, true); |
422 | listBox->ensureCurrentVisible (); |
423 | } |
424 | } |
425 | e->accept(); |
426 | } |
427 | else if (e->modifiers() & Qt::ControlModifier) { |
428 | if (e->key() == Qt::Key_C) { |
429 | copy(); |
430 | e->accept(); |
431 | } |
432 | else if (e->key() == Qt::Key_X) { |
433 | cut(); |
434 | e->accept(); |
435 | } |
436 | } |
437 | else |
438 | e->ignore(); |
439 | } |
440 | |
441 | void PhraseList::save () { |
442 | // We want to save a history of spoken sentences here. However, as |
443 | // the class PhraseBook does already provide a method for saving |
444 | // phrase books in both the phrase book format and plain text file |
445 | // format we use that method here. |
446 | |
447 | PhraseBook book; |
448 | for (Q3ListBoxItem *item = listBox->firstItem(); item != 0; item = item->next()) { |
449 | book += PhraseBookEntry(Phrase(item->text())); |
450 | } |
451 | |
452 | KUrl url; |
453 | if (book.save (this, i18n("Save As" ), url, false) == -1) |
454 | KMessageBox::sorry(this,i18n("There was an error saving file\n%1" , url.url() )); |
455 | } |
456 | |
457 | void PhraseList::open () { |
458 | KUrl url=KFileDialog::getOpenUrl(KUrl(), |
459 | i18n("*|All Files\n*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)" ), this, i18n("Open File as History" )); |
460 | |
461 | if(!url.isEmpty()) |
462 | open (url); |
463 | } |
464 | |
465 | void PhraseList::open (KUrl url) { |
466 | // We want to open a history of spoken sentences here. However, as |
467 | // the class PhraseBook does already provide a method for opening |
468 | // both phrase books and plain text files we use that method here. |
469 | |
470 | PhraseBook book; |
471 | if (book.open (url)) { |
472 | // convert PhraseBookEntryList -> QStringList |
473 | QStringList list = book.toStringList(); |
474 | listBox->clear(); |
475 | QStringList::iterator it; |
476 | for (it = list.begin(); it != list.end(); ++it) |
477 | insertIntoPhraseList (*it, false); |
478 | } |
479 | else |
480 | KMessageBox::sorry(this,i18n("There was an error loading file\n%1" , url.url() )); |
481 | } |
482 | |
483 | #include "phraselist.moc" |
484 | |