1 /***************************************************************************
2 * Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de *
3 * (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 // application specific includes
22 #include "kmouth.h"
23
24 // include files for Qt
25 #include <QMenu>
26 #include <QMenuBar>
27 #include <QPrintDialog>
28 #include <QStandardPaths>
29 #include <QStatusBar>
30
31 // include files for KDE
32 #include <KActionCollection>
33 #include <KConfigGroup>
34 #include <KLocalizedString>
35 #include <KStandardAction>
36 #include <KStandardShortcut>
37 #include <KToggleAction>
38 #include <KToolBar>
39 #include <KXMLGUIFactory>
40
41 #include "phraselist.h"
42 #include "phrasebook/phrasebook.h"
43 #include "phrasebook/phrasebookdialog.h"
44 #include "optionsdialog.h"
45 #include "configwizard.h"
46
KMouthApp(QWidget *,const QString & name)47 KMouthApp::KMouthApp(QWidget* , const QString& name): KXmlGuiWindow(nullptr)
48 {
49 setWindowIcon(QIcon::fromTheme(QStringLiteral("kmouth")));
50 setObjectName(name);
51 isConfigured = false;
52
53 ///////////////////////////////////////////////////////////////////
54 // call inits to invoke all other construction parts
55 initStatusBar();
56 initPhraseList();
57 initActions();
58 optionsDialog = new OptionsDialog(this);
59 connect(optionsDialog, &OptionsDialog::configurationChanged,
60 this, &KMouthApp::slotConfigurationChanged);
61 connect(optionsDialog, &OptionsDialog::configurationChanged,
62 phraseList, &PhraseList::configureCompletion);
63
64 phrases = new KActionCollection(static_cast<QWidget*>(this));
65
66 readOptions();
67 ConfigWizard *wizard = new ConfigWizard(this);
68 if (wizard->configurationNeeded()) {
69 if (wizard->requestConfiguration()) {
70 isConfigured = true;
71 saveOptions();
72 wizard->saveConfig();
73 readOptions();
74 } else
75 isConfigured = false;
76 } else
77 isConfigured = true;
78 delete wizard;
79
80 if (isConfigured) {
81 phraseList->configureCompletion();
82 }
83
84 ///////////////////////////////////////////////////////////////////
85 // disable actions at startup
86 fileSaveAs->setEnabled(false);
87 filePrint->setEnabled(false);
88
89 printer = nullptr;
90 }
91
~KMouthApp()92 KMouthApp::~KMouthApp()
93 {
94 delete printer;
95 }
96
configured()97 bool KMouthApp::configured()
98 {
99 return isConfigured;
100 }
101
initActions()102 void KMouthApp::initActions()
103 {
104 // The "File" menu
105 fileOpen = actionCollection()->addAction(QStringLiteral("file_open"));
106 fileOpen->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
107 fileOpen->setText(i18n("&Open as History..."));
108 actionCollection()->setDefaultShortcuts(fileOpen, KStandardShortcut::open());
109 connect(fileOpen, &QAction::triggered, this, &KMouthApp::slotFileOpen);
110 fileOpen->setToolTip(i18n("Opens an existing file as history"));
111 fileOpen->setWhatsThis(i18n("Opens an existing file as history"));
112
113 fileSaveAs = actionCollection()->addAction(QStringLiteral("file_save_as"));
114 fileSaveAs->setIcon(QIcon::fromTheme(QStringLiteral("document-save")));
115 fileSaveAs->setText(i18n("Save &History As..."));
116 actionCollection()->setDefaultShortcuts(fileSaveAs, KStandardShortcut::save());
117 connect(fileSaveAs, &QAction::triggered, this, &KMouthApp::slotFileSaveAs);
118 fileSaveAs->setToolTip(i18n("Saves the actual history as..."));
119 fileSaveAs->setWhatsThis(i18n("Saves the actual history as..."));
120
121 filePrint = actionCollection()->addAction(QStringLiteral("file_print"));
122 filePrint->setIcon(QIcon::fromTheme(QStringLiteral("document-print")));
123 filePrint->setText(i18n("&Print History..."));
124 actionCollection()->setDefaultShortcuts(filePrint, KStandardShortcut::print());
125 connect(filePrint, &QAction::triggered, this, &KMouthApp::slotFilePrint);
126 filePrint->setToolTip(i18n("Prints out the actual history"));
127 filePrint->setWhatsThis(i18n("Prints out the actual history"));
128
129 fileQuit = KStandardAction::quit(this, SLOT(slotFileQuit()), actionCollection());
130 fileQuit->setToolTip(i18n("Quits the application"));
131 fileQuit->setWhatsThis(i18n("Quits the application"));
132
133 // The "Edit" menu
134 editCut = KStandardAction::cut(phraseList, SLOT(cut()), actionCollection());
135 editCut->setToolTip(i18n("Cuts the selected section and puts it to the clipboard"));
136 editCut->setWhatsThis(i18n("Cuts the selected section and puts it to the clipboard. If there is some text selected in the edit field it is placed it on the clipboard. Otherwise the selected sentences in the history (if any) are placed on the clipboard."));
137
138 editCopy = KStandardAction::copy(phraseList, SLOT(copy()), actionCollection());
139 editCopy->setToolTip(i18n("Copies the selected section to the clipboard"));
140 editCopy->setWhatsThis(i18n("Copies the selected section to the clipboard. If there is some text selected in the edit field it is copied to the clipboard. Otherwise the selected sentences in the history (if any) are copied to the clipboard."));
141
142 editPaste = KStandardAction::paste(phraseList, SLOT(paste()), actionCollection());
143 editPaste->setToolTip(i18n("Pastes the clipboard contents to current position"));
144 editPaste->setWhatsThis(i18n("Pastes the clipboard contents at the current cursor position into the edit field."));
145
146 editSpeak = actionCollection()->addAction(QStringLiteral("edit_speak"));
147 editSpeak->setIcon(QIcon::fromTheme(QStringLiteral("text-speak")));
148 editSpeak->setText(i18nc("Start speaking", "&Speak"));
149 connect(editSpeak, &QAction::triggered, phraseList, &PhraseList::speak);
150 editSpeak->setToolTip(i18n("Speaks the currently active sentence(s)"));
151 editSpeak->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."));
152
153 // The "Phrase book" menu
154 phrasebookEdit = actionCollection()->addAction(QStringLiteral("phrasebook_edit"));
155 phrasebookEdit->setText(i18n("&Edit..."));
156 connect(phrasebookEdit, &QAction::triggered, this, &KMouthApp::slotEditPhrasebook);
157
158 // The "Options" menu
159 viewMenuBar = KStandardAction::showMenubar(this, SLOT(slotViewMenuBar()), actionCollection());
160 // FIXME: Disable so it will compile.
161 // viewToolBar = KStandardAction::showToolbar(this, SLOT(slotViewToolBar()), actionCollection());
162 // viewToolBar->setToolTip(i18n("Enables/disables the toolbar"));
163 // viewToolBar->setWhatsThis (i18n("Enables/disables the toolbar"));
164
165 viewPhrasebookBar = actionCollection()->add<KToggleAction>(QStringLiteral("showPhrasebookBar"));
166 viewPhrasebookBar->setText(i18n("Show P&hrasebook Bar"));
167 connect(viewPhrasebookBar, &QAction::triggered, this, &KMouthApp::slotViewPhrasebookBar);
168 viewPhrasebookBar->setToolTip(i18n("Enables/disables the phrasebook bar"));
169 viewPhrasebookBar->setWhatsThis(i18n("Enables/disables the phrasebook bar"));
170
171 viewStatusBar = KStandardAction::showStatusbar(this, SLOT(slotViewStatusBar()), actionCollection());
172 viewStatusBar->setToolTip(i18n("Enables/disables the statusbar"));
173 viewStatusBar->setWhatsThis(i18n("Enables/disables the statusbar"));
174
175 configureTTS = actionCollection()->addAction(QStringLiteral("configureTTS"));
176 configureTTS->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
177 configureTTS->setText(i18n("&Configure KMouth..."));
178 connect(configureTTS, &QAction::triggered, this, &KMouthApp::slotConfigureTTS);
179 configureTTS->setToolTip(i18n("Opens the configuration dialog"));
180 configureTTS->setWhatsThis(i18n("Opens the configuration dialog"));
181
182 // The "Help" menu
183 // The "Help" menu will automatically get created.
184
185 // The popup menu of the list of spoken sentences
186 phraseListSpeak = actionCollection()->addAction(QStringLiteral("phraselist_speak"));
187 phraseListSpeak->setIcon(QIcon::fromTheme(QStringLiteral("text-speak")));
188 phraseListSpeak->setText(i18n("&Speak"));
189 phraseListSpeak->setToolTip(i18n("Speaks the currently selected phrases in the history"));
190 connect(phraseListSpeak, &QAction::triggered, phraseList, &PhraseList::speakListSelection);
191 phraseListSpeak->setWhatsThis(i18n("Speaks the currently selected phrases in the history"));
192
193 phraseListRemove = actionCollection()->addAction(QStringLiteral("phraselist_remove"));
194 phraseListRemove->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
195 phraseListRemove->setText(i18n("&Delete"));
196 connect(phraseListRemove, &QAction::triggered, phraseList, &PhraseList::removeListSelection);
197 phraseListRemove->setToolTip(i18n("Deletes the currently selected phrases from the history"));
198 phraseListRemove->setWhatsThis(i18n("Deletes the currently selected phrases from the history"));
199
200 phraseListCut = actionCollection()->addAction(QStringLiteral("phraselist_cut"));
201 phraseListCut->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut")));
202 phraseListCut->setText(i18n("Cu&t"));
203 connect(phraseListCut, &QAction::triggered, phraseList, &PhraseList::cutListSelection);
204 phraseListCut->setToolTip(i18n("Cuts the currently selected phrases from the history and puts them to the clipboard"));
205 phraseListCut->setWhatsThis(i18n("Cuts the currently selected phrases from the history and puts them to the clipboard"));
206
207 phraseListCopy = actionCollection()->addAction(QStringLiteral("phraselist_copy"));
208 phraseListCopy->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
209 phraseListCopy->setText(i18n("&Copy"));
210 connect(phraseListCopy, &QAction::triggered, phraseList, &PhraseList::copyListSelection);
211 phraseListCut->setToolTip(i18n("Copies the currently selected phrases from the history to the clipboard"));
212 phraseListCut->setWhatsThis(i18n("Copies the currently selected phrases from the history to the clipboard"));
213
214 phraselistSelectAll = actionCollection()->addAction(QStringLiteral("phraselist_select_all"));
215 phraselistSelectAll->setText(i18n("Select &All Entries"));
216 connect(phraselistSelectAll, &QAction::triggered, phraseList, &PhraseList::selectAllEntries);
217 phraselistSelectAll->setToolTip(i18n("Selects all phrases in the history"));
218 phraselistSelectAll->setWhatsThis(i18n("Selects all phrases in the history"));
219
220 phraselistDeselectAll = actionCollection()->addAction(QStringLiteral("phraselist_deselect_all"));
221 phraselistDeselectAll->setText(i18n("D&eselect All Entries"));
222 connect(phraselistDeselectAll, &QAction::triggered, phraseList, &PhraseList::deselectAllEntries);
223 phraselistDeselectAll->setToolTip(i18n("Deselects all phrases in the history"));
224 phraselistDeselectAll->setWhatsThis(i18n("Deselects all phrases in the history"));
225
226 // The popup menu of the edit field
227 // The popup menu of the edit field will automatically get created.
228
229 // use the absolute path to your kmouthui.rc file for testing purpose in createGUI();
230 createGUI();
231 }
232
initStatusBar()233 void KMouthApp::initStatusBar()
234 {
235 ///////////////////////////////////////////////////////////////////
236 // STATUSBAR
237 // TODO: add your own items you need for displaying current application status.
238 m_statusLabel = new QLabel(i18nc("The job is done", "Ready."));
239 statusBar()->addPermanentWidget(m_statusLabel);
240 }
241
initPhraseList()242 void KMouthApp::initPhraseList()
243 {
244 ////////////////////////////////////////////////////////////////////
245 // create the main widget here that is managed by KTMainWindow's view-region and
246 // connect the widget to your document to display document contents.
247
248 phraseList = new PhraseList(this);
249 setCentralWidget(phraseList);
250 }
251
openDocumentFile(const QUrl & url)252 void KMouthApp::openDocumentFile(const QUrl &url)
253 {
254 slotStatusMsg(i18n("Opening file..."));
255
256 phraseList->open(url);
257 slotStatusMsg(i18nc("The job is done", "Ready."));
258 }
259
saveOptions()260 void KMouthApp::saveOptions()
261 {
262 if (isConfigured) {
263 KConfigGroup cg(KSharedConfig::openConfig(), "General Options");
264 cg.writeEntry("Geometry", size());
265 cg.writeEntry("Show Menubar", viewMenuBar->isChecked());
266 // FIXME: Toolbar disabled so it will compile.
267 // cg.writeEntry("Show Toolbar", viewToolBar->isChecked());
268 cg.writeEntry("Show Phrasebook Bar", viewPhrasebookBar->isChecked());
269 cg.writeEntry("Show Statusbar", viewStatusBar->isChecked());
270 // FIXME: KToolBar no longer has barPos() method.
271 // cg.writeEntry("ToolBarPos", (int) toolBar("mainToolBar")->barPos());
272
273 if (phraseList != nullptr)
274 phraseList->saveCompletionOptions();
275 optionsDialog->saveOptions();
276 KConfigGroup cg2(KSharedConfig::openConfig(), "mainToolBar");
277 toolBar(QStringLiteral("mainToolBar"))->saveSettings(cg2);
278 KConfigGroup cg3(KSharedConfig::openConfig(), "phrasebookBar");
279 toolBar(QStringLiteral("phrasebookBar"))->saveSettings(cg);
280 }
281 }
282
283
readOptions()284 void KMouthApp::readOptions()
285 {
286 KConfigGroup cg(KSharedConfig::openConfig(), "General Options");
287
288 // bar status settings
289 bool bViewMenubar = cg.readEntry("Show Menubar", true);
290 viewMenuBar->setChecked(bViewMenubar);
291 slotViewMenuBar();
292
293 // FIXME: Toolbar disabled so it will compile.
294 // bool bViewToolbar = cg.readEntry("Show Toolbar", QVariant(true)).toBool();
295 // viewToolBar->setChecked(bViewToolbar);
296 // slotViewToolBar();
297
298 bool bViewPhrasebookbar = cg.readEntry("Show Phrasebook Bar", true);
299 viewPhrasebookBar->setChecked(bViewPhrasebookbar);
300
301 bool bViewStatusbar = cg.readEntry("Show Statusbar", true);
302 viewStatusBar->setChecked(bViewStatusbar);
303 slotViewStatusBar();
304
305 // bar position settings
306 // FIXME:
307 // KToolBar::BarPosition toolBarPos;
308 // toolBarPos=(KToolBar::BarPosition) cg.readEntry("ToolBarPos", int(KToolBar::Top));
309 // toolBar("mainToolBar")->setBarPos(toolBarPos);
310
311 QSize size = cg.readEntry("Geometry", QSize());
312 if (!size.isEmpty()) {
313 resize(size);
314 }
315
316 optionsDialog->readOptions();
317
318 toolBar(QStringLiteral("mainToolBar"))->applySettings(KSharedConfig::openConfig()->group("mainToolBar"));
319 toolBar(QStringLiteral("phrasebookBar"))->applySettings(KSharedConfig::openConfig()->group("phrasebookBar"));
320
321 slotPhrasebookConfirmed();
322 if (phraseList != nullptr)
323 phraseList->readCompletionOptions();
324 }
325
queryClose()326 bool KMouthApp::queryClose()
327 {
328 saveOptions();
329 return true;
330 }
331
enableMenuEntries(bool existSelectedEntries,bool existDeselectedEntries)332 void KMouthApp::enableMenuEntries(bool existSelectedEntries, bool existDeselectedEntries)
333 {
334 bool existEntries = existSelectedEntries | existDeselectedEntries;
335 fileSaveAs->setEnabled(existEntries);
336 filePrint->setEnabled(existEntries);
337
338 phraselistSelectAll->setEnabled(existDeselectedEntries);
339
340 phraselistDeselectAll->setEnabled(existSelectedEntries);
341 phraseListSpeak->setEnabled(existSelectedEntries);
342 phraseListRemove->setEnabled(existSelectedEntries);
343 phraseListCut->setEnabled(existSelectedEntries);
344 phraseListCopy->setEnabled(existSelectedEntries);
345 }
346
347 /////////////////////////////////////////////////////////////////////
348 // SLOT IMPLEMENTATION
349 /////////////////////////////////////////////////////////////////////
350
slotFileOpen()351 void KMouthApp::slotFileOpen()
352 {
353 slotStatusMsg(i18n("Opening file..."));
354
355 phraseList->open();
356
357 slotStatusMsg(i18nc("The job is done", "Ready."));
358 }
359
slotFileSaveAs()360 void KMouthApp::slotFileSaveAs()
361 {
362 slotStatusMsg(i18n("Saving history with a new filename..."));
363
364 phraseList->save();
365
366 slotStatusMsg(i18nc("The job is done", "Ready."));
367 }
368
slotFilePrint()369 void KMouthApp::slotFilePrint()
370 {
371 slotStatusMsg(i18n("Printing..."));
372
373 if (printer == nullptr) {
374 printer = new QPrinter();
375 }
376
377 QPrintDialog *printDialog = new QPrintDialog(printer, nullptr);
378
379 if (printDialog->exec()) {
380 phraseList->print(printer);
381 }
382
383 slotStatusMsg(i18nc("The job is done", "Ready."));
384 }
385
slotFileQuit()386 void KMouthApp::slotFileQuit()
387 {
388 slotStatusMsg(i18nc("Shutting down the application", "Exiting..."));
389 saveOptions();
390 // close the first window, the list makes the next one the first again.
391 // This ensures that queryClose() is called on each window to ask for closing
392 KMainWindow* w;
393 if (!memberList().isEmpty()) {
394 for (int i = 0; i < memberList().size(); ++i) {
395 // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog,
396 // the window and the application stay open.
397 w = memberList().at(i);
398 if (!w->close())
399 break;
400 #ifdef __GNUC__
401 #warning "kde4: how remove it ?.???"
402 #endif
403 //memberList()->removeRef(w);
404 }
405 }
406 }
407
slotEditPhrasebook()408 void KMouthApp::slotEditPhrasebook()
409 {
410 PhraseBookDialog *phraseBookDialog = PhraseBookDialog::get();
411 // As we do not know whether the we are already connected to the slot,
412 // we first disconnect and then connect again.
413 disconnect(phraseBookDialog, &PhraseBookDialog::phrasebookConfirmed,
414 this, &KMouthApp::slotPhrasebookConfirmed);
415 connect(phraseBookDialog, &PhraseBookDialog::phrasebookConfirmed,
416 this, &KMouthApp::slotPhrasebookConfirmed);
417
418 // As we do not know whether the phrase book edit window is already open,
419 // we first open and then raise it, so that it is surely the top window.
420 phraseBookDialog->show();
421 phraseBookDialog->raise();
422 }
423
slotViewMenuBar()424 void KMouthApp::slotViewMenuBar()
425 {
426 slotStatusMsg(i18n("Toggling menubar..."));
427
428 if (!viewMenuBar->isChecked())
429 menuBar()->hide();
430 else
431 menuBar()->show();
432
433 slotStatusMsg(i18nc("The job is done", "Ready."));
434 }
435
slotViewToolBar()436 void KMouthApp::slotViewToolBar()
437 {
438 slotStatusMsg(i18n("Toggling toolbar..."));
439 ///////////////////////////////////////////////////////////////////
440 // turn Toolbar on or off
441 if (!viewToolBar->isChecked()) {
442 toolBar(QStringLiteral("mainToolBar"))->hide();
443 } else {
444 toolBar(QStringLiteral("mainToolBar"))->show();
445 }
446
447 slotStatusMsg(i18nc("The job is done", "Ready."));
448 }
449
slotViewPhrasebookBar()450 void KMouthApp::slotViewPhrasebookBar()
451 {
452 slotStatusMsg(i18n("Toggling phrasebook bar..."));
453 ///////////////////////////////////////////////////////////////////
454 // turn Toolbar on or off
455 if (!viewPhrasebookBar->isChecked()) {
456 toolBar(QStringLiteral("phrasebookBar"))->hide();
457 } else {
458 toolBar(QStringLiteral("phrasebookBar"))->show();
459 }
460
461 slotStatusMsg(i18nc("The job is done", "Ready."));
462 }
463
slotViewStatusBar()464 void KMouthApp::slotViewStatusBar()
465 {
466 slotStatusMsg(i18n("Toggle the statusbar..."));
467 ///////////////////////////////////////////////////////////////////
468 //turn Statusbar on or off
469 if (!viewStatusBar->isChecked()) {
470 statusBar()->hide();
471 } else {
472 statusBar()->show();
473 }
474
475 slotStatusMsg(i18nc("The job is done", "Ready."));
476 }
477
slotConfigureTTS()478 void KMouthApp::slotConfigureTTS()
479 {
480 phraseList->saveWordCompletion();
481 optionsDialog->show();
482 }
483
484
slotStatusMsg(const QString & text)485 void KMouthApp::slotStatusMsg(const QString &text)
486 {
487 ///////////////////////////////////////////////////////////////////
488 // change status message permanently
489 m_statusLabel->setText(text);
490 }
491
slotPhrasebookConfirmed()492 void KMouthApp::slotPhrasebookConfirmed()
493 {
494 QString standardBook = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("standard.phrasebook"));
495 if (!standardBook.isEmpty()) {
496 PhraseBook book;
497 book.open(QUrl::fromLocalFile(standardBook));
498 QString name = QStringLiteral("phrasebooks");
499 QMenu *popup = (QMenu *)factory()->container(name, this);
500 KToolBar *toolbar = toolBar(QStringLiteral("phrasebookBar"));
501
502 delete phrases;
503 phrases = new KActionCollection(actionCollection());
504 book.addToGUI(popup, toolbar, phrases, this, SLOT(slotPhraseSelected(QString)));
505 }
506 }
507
slotConfigurationChanged()508 void KMouthApp::slotConfigurationChanged()
509 {
510 optionsDialog->saveOptions();
511 }
512
slotPhraseSelected(const QString & phrase)513 void KMouthApp::slotPhraseSelected(const QString &phrase)
514 {
515 phraseList->insert(phrase);
516 if (optionsDialog->isSpeakImmediately())
517 phraseList->speak();
518 }
519
getTTSSystem() const520 TextToSpeechSystem *KMouthApp::getTTSSystem() const
521 {
522 return optionsDialog->getTTSSystem();
523 }
524
525