SVN_SILENT made messages (.desktop file)
[kdeaccessibility.git] / kmouth / phrasebook / phrasebook.cpp
blobdf36ac04183ee57b91b2ed3901bd512f32009a67
1 /***************************************************************************
2 phrasebook.cpp - description
3 -------------------
4 begin : Don Sep 19 2002
5 copyright : (C) 2002 by Gunnar Schmi Dt
6 email : kmouth@schmi-dt.de
7 ***************************************************************************/
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 ***************************************************************************/
18 #include "phrasebook.h"
19 #include "phrasebookparser.h"
21 #include <QPrinter>
22 #include <QPainter>
23 #include <QFile>
24 #include <QtXml>
25 #include <QRegExp>
26 #include <qstack.h>
27 #include <QTextStream>
28 #include <QMenu>
29 #include <kactionmenu.h>
30 #include <kactioncollection.h>
31 #include <klocale.h>
32 #include <kaction.h>
33 #include <kmenu.h>
34 #include <ktoolbar.h>
35 #include <ktemporaryfile.h>
36 #include <kio/netaccess.h>
37 #include <kfiledialog.h>
38 #include <kmessagebox.h>
39 #include <kglobalsettings.h>
41 Phrase::Phrase() {
42 this->phrase = "";
43 this->shortcut = "";
46 Phrase::Phrase (const QString &phrase) {
47 this->phrase = phrase;
48 this->shortcut = "";
51 Phrase::Phrase (const QString &phrase, const QString &shortcut) {
52 this->phrase = phrase;
53 this->shortcut = shortcut;
56 QString Phrase::getPhrase() const {
57 return phrase;
60 QString Phrase::getShortcut() const {
61 return shortcut;
64 void Phrase::setPhrase (const QString &phrase) {
65 this->phrase = phrase;
68 void Phrase::setShortcut (const QString &shortcut) {
69 this->shortcut = shortcut;
72 // ***************************************************************************
74 PhraseBookEntry::PhraseBookEntry () {
75 phrase = Phrase();
76 level = 1;
77 isPhraseValue = false;
80 PhraseBookEntry::PhraseBookEntry (Phrase phrase, int level, bool isPhrase) {
81 this->phrase = phrase;
82 this->level = level;
83 isPhraseValue = isPhrase;
86 bool PhraseBookEntry::isPhrase() const {
87 return isPhraseValue;
90 Phrase PhraseBookEntry::getPhrase() const {
91 return phrase;
94 int PhraseBookEntry::getLevel() const {
95 return level;
98 // ***************************************************************************
100 void PhraseBook::print(KPrinter *pPrinter) {
101 QPainter printpainter;
102 printpainter.begin(pPrinter);
104 QRect size = printpainter.viewport ();
105 int x = size.x();
106 int y = size.y();
107 int w = size.width();
108 printpainter.setFont (QFont (KGlobalSettings::generalFont().family(), 12));
109 QFontMetrics metrics = printpainter.fontMetrics();
111 PhraseBookEntryList::iterator it;
112 for (it = begin(); it != end(); ++it) {
113 QRect rect = metrics.boundingRect (x+16*(*it).getLevel(), y,
114 w-16*(*it).getLevel(), 0,
115 Qt::AlignJustify | Qt::TextWordWrap,
116 (*it).getPhrase().getPhrase());
118 if (y+rect.height() > size.height()) {
119 pPrinter->newPage();
120 y = 0;
122 printpainter.drawText (x+16*(*it).getLevel(),y,
123 w-16*(*it).getLevel(),rect.height(),
124 Qt::AlignJustify | Qt::TextWordWrap,
125 (*it).getPhrase().getPhrase());
126 y += rect.height();
129 printpainter.end();
132 bool PhraseBook::decode (const QString &xml) {
133 QXmlInputSource source;
134 source.setData (xml);
135 return decode (source);
138 bool PhraseBook::decode (QXmlInputSource &source) {
139 PhraseBookParser parser;
140 QXmlSimpleReader reader;
141 reader.setFeature ("http://trolltech.com/xml/features/report-start-end-entity", true);
142 reader.setContentHandler (&parser);
144 if (reader.parse(source)) {
145 PhraseBookEntryList::clear();
146 *(PhraseBookEntryList *)this += parser.getPhraseList();
147 return true;
149 else
150 return false;
153 QByteArray encodeString (const QString str) {
154 QByteArray res = "";
155 for (int i = 0; i < (int)str.length(); i++) {
156 QChar ch = str.at(i);
157 ushort uc = ch.unicode();
158 QByteArray number; number.setNum(uc);
159 if ((uc>127) || (uc<32) || (ch=='<') || (ch=='>') || (ch=='&') || (ch==';'))
160 res = res + "&#" + number + ';';
161 else
162 res = res + (char)uc;
164 return res;
167 QString PhraseBook::encode () {
168 QString result;
169 result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
170 result += "<!DOCTYPE phrasebook>\n";
171 result += "<phrasebook>\n";
173 PhraseBookEntryList::iterator it;
174 int level = 0;
175 for (it = begin(); it != end(); ++it) {
176 int newLevel = (*it).getLevel();
177 while (level < newLevel) {
178 result += "<phrasebook>\n";
179 level++;
181 while (level > newLevel) {
182 result += "</phrasebook>\n";
183 level--;
186 if ((*it).isPhrase()) {
187 Phrase phrase = (*it).getPhrase();
188 result += "<phrase shortcut=\"" + encodeString(phrase.getShortcut());
189 result += "\">" + encodeString(phrase.getPhrase()) + "</phrase>\n";
191 else {
192 Phrase phrase = (*it).getPhrase();
193 result += "<phrasebook name=\"" + encodeString(phrase.getPhrase()) + "\">\n";
194 level++;
197 while (level > 0) {
198 result += "</phrasebook>\n";
199 level--;
201 result += "</phrasebook>";
202 return result;
205 QStringList PhraseBook::toStringList () {
206 QStringList result;
208 PhraseBook::iterator it;
209 for (it = begin(); it != end(); ++it) {
210 if ((*it).isPhrase())
211 result += (*it).getPhrase().getPhrase();
213 return result;
216 bool PhraseBook::save (const KUrl &url) {
217 QRegExp pattern("*.phrasebook", Qt::CaseSensitive, QRegExp::Wildcard);
218 return save (url, pattern.exactMatch(url.fileName()));
222 void PhraseBook::save (QTextStream &stream, bool asPhrasebook) {
223 if (asPhrasebook)
224 stream << encode();
225 else
226 stream << toStringList().join("\n");
229 bool PhraseBook::save (const KUrl &url, bool asPhrasebook) {
230 if (url.isLocalFile()) {
231 QFile file(url.path());
232 if(!file.open(QIODevice::WriteOnly))
233 return false;
235 QTextStream stream(&file);
236 save (stream, asPhrasebook);
237 file.close();
239 if (file.error() != QFile::NoError)
240 return false;
241 else
242 return true;
244 else {
245 KTemporaryFile tempFile;
246 tempFile.open();
248 QTextStream ts(&tempFile);
249 save (ts, asPhrasebook);
250 ts.flush();
252 return KIO::NetAccess::upload(tempFile.fileName(), url, 0L);
256 int PhraseBook::save (QWidget *parent, const QString &title, KUrl &url, bool phrasebookFirst) {
257 // KFileDialog::getSaveUrl(...) is not useful here as we need
258 // to know the requested file type.
260 QString filters;
261 if (phrasebookFirst)
262 filters = i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files");
263 else
264 filters = i18n("*.txt|Plain Text Files (*.txt)\n*.phrasebook|Phrase Books (*.phrasebook)\n*|All Files");
266 KFileDialog fdlg(QString(),filters, parent);
267 fdlg.setCaption(title);
268 fdlg.setOperationMode( KFileDialog::Saving );
270 if (fdlg.exec() != QDialog::Accepted) {
271 return 0;
274 url = fdlg.selectedUrl();
276 if (url.isEmpty() || !url.isValid()) {
277 return -1;
280 if (KIO::NetAccess::exists(url, KIO::NetAccess::DestinationSide, 0L)) {
281 if (KMessageBox::warningContinueCancel(0,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
282 "Do you want to overwrite it?", url.url())),i18n("File Exists"),KGuiItem(i18n("&Overwrite")))==KMessageBox::Cancel) {
283 return 0;
287 bool result;
288 if (fdlg.currentFilter() == "*.phrasebook") {
289 if (url.fileName (false).contains('.') == 0) {
290 url.setFileName (url.fileName(false) + ".phrasebook");
292 else if (url.fileName (false).right (11).contains (".phrasebook", Qt::CaseInsensitive) == 0) {
293 int filetype = KMessageBox::questionYesNoCancel (0,QString("<qt>%1</qt>").arg(i18n("Your chosen filename <i>%1</i> has a different extension than <i>.phrasebook</i>. "
294 "Do you wish to add <i>.phrasebook</i> to the filename?", url.fileName())),i18n("File Extension"),KGuiItem(i18n("Add")),KGuiItem(i18n("Do Not Add")));
295 if (filetype == KMessageBox::Cancel) {
296 return 0;
298 if (filetype == KMessageBox::Yes) {
299 url.setFileName (url.fileName(false) + ".phrasebook");
302 result = save (url, true);
304 else if (fdlg.currentFilter() == "*.txt") {
305 if (url.fileName (false).right (11).contains (".phrasebook", Qt::CaseInsensitive) == 0) {
306 result = save (url, false);
308 else {
309 int filetype = KMessageBox::questionYesNoCancel (0,QString("<qt>%1</qt>").arg(i18n("Your chosen filename <i>%1</i> has the extension <i>.phrasebook</i>. "
310 "Do you wish to save in phrasebook format?", url.fileName())),i18n("File Extension"),KGuiItem(i18n("As Phrasebook")),KGuiItem(i18n("As Plain Text")));
311 if (filetype == KMessageBox::Cancel) {
312 return 0;
314 if (filetype == KMessageBox::Yes) {
315 result = save (url, true);
317 else {
318 result = save (url, false);
322 else // file format "All files" requested, so decide by extension
323 result = save (url);
325 if (result)
326 return 1;
327 else
328 return -1;
331 bool PhraseBook::open (const KUrl &url) {
332 QString tempFile;
333 KUrl fileUrl = url;
335 QString protocol = fileUrl.protocol();
336 if (protocol.isEmpty() || protocol.isNull()) {
337 fileUrl.setProtocol ("file");
338 fileUrl.setPath (url.url());
341 if (KIO::NetAccess::download (fileUrl, tempFile, 0L)) {
342 QStringList list = QStringList();
344 // First: try to load it as a normal phrase book
345 QFile file(tempFile);
346 QXmlInputSource source (&file);
347 bool error = !decode (source);
349 // Second: if the file does not contain a phrase book, load it as
350 // a plain text file
351 if (error) {
352 // Load each line of the plain text file as a new phrase
354 QFile file(tempFile);
355 if (file.open(QIODevice::ReadOnly)) {
356 QTextStream stream(&file);
358 while (!stream.atEnd()) {
359 QString s = stream.readLine();
360 if (!(s.isNull() || s.isEmpty()))
361 *this += PhraseBookEntry(Phrase(s, ""), 0, true);
363 file.close();
364 error = false;
366 else
367 error = true;
369 KIO::NetAccess::removeTempFile (tempFile);
371 return !error;
373 return false;
376 void PhraseBook::addToGUI (QMenu *popup, KToolBar *toolbar, KActionCollection *phrases,
377 QObject *receiver, const char *slot) const {
378 if ((popup != 0) || (toolbar != 0)) {
379 QStack<QWidget*> stack;
380 QWidget *parent = popup;
381 int level = 0;
383 QList<PhraseBookEntry>::ConstIterator it;
384 for (it = begin(); it != end(); ++it) {
385 int newLevel = (*it).getLevel();
386 while (newLevel > level) {
387 KActionMenu *menu = phrases->add<KActionMenu>("phrasebook");
388 menu->setDelayed(false);
389 if (parent == popup)
390 toolbar->addAction(menu);
391 if (parent != 0)
393 parent->addAction(menu);
394 stack.push (parent);
396 parent = menu->menu();
397 level++;
399 while (newLevel < level && (parent != popup)) {
400 parent = stack.pop();
401 level--;
403 if ((*it).isPhrase()) {
404 Phrase phrase = (*it).getPhrase();
405 KAction *action = new PhraseAction (phrase.getPhrase(),
406 phrase.getShortcut(), receiver, slot, phrases);
407 if (parent == popup)
408 toolbar->addAction(action);
409 if (parent != 0)
410 parent->addAction(action);
412 else {
413 Phrase phrase = (*it).getPhrase();
414 KActionMenu *menu = phrases->add<KActionMenu>("phrasebook");
415 menu->setText(phrase.getPhrase());
416 menu->setDelayed(false);
417 if (parent == popup)
418 toolbar->addAction(menu);
419 parent->addAction(menu);
420 stack.push (parent);
421 parent = menu->menu();
422 level++;
428 void PhraseBook::insert (const QString &name, const PhraseBook &book) {
429 *this += PhraseBookEntry(Phrase(name), 0, false);
431 QList<PhraseBookEntry>::ConstIterator it;
432 for (it = book.begin(); it != book.end(); ++it) {
433 *this += PhraseBookEntry ((*it).getPhrase(), (*it).getLevel()+1, (*it).isPhrase());
437 // ***************************************************************************
439 PhraseBookDrag::PhraseBookDrag (PhraseBook *book, QWidget *dragSource, const char *name)
440 : Q3DragObject (dragSource, name)
442 setBook (book);
445 PhraseBookDrag::PhraseBookDrag (QWidget *dragSource, const char *name)
446 : Q3DragObject (dragSource, name)
448 setBook (0);
451 PhraseBookDrag::~PhraseBookDrag () {
454 void PhraseBookDrag::setBook (PhraseBook *book) {
455 if (book == 0) {
456 isEmpty = true;
457 xmlphrasebook.setText(QString());
458 xml.setText(QString());
459 plain.setText(QString());
461 else {
462 isEmpty = false;
463 xmlphrasebook.setText(book->encode());
464 xml.setText(book->encode());
465 plain.setText(book->toStringList().join("\n"));
467 xmlphrasebook.setSubtype("x-xml-phrasebook");
468 xml.setSubtype("xml");
469 plain.setSubtype("plain");
472 const char *PhraseBookDrag::format (int i) const {
473 if (isEmpty)
474 return plain.format(i);
475 else if (i%3 == 0)
476 return plain.format(i/3);
477 else if (i%3 == 1)
478 return xml.format(i/3);
479 else
480 return xmlphrasebook.format(i/3);
483 QByteArray PhraseBookDrag::encodedData (const char* mime) const {
484 QByteArray m(mime);
485 m = m.toLower();
486 if (m.contains("xml-phrasebook"))
487 return xmlphrasebook.encodedData(mime);
488 else if (m.contains("xml"))
489 return xml.encodedData(mime);
490 else
491 return plain.encodedData(mime);
494 bool PhraseBookDrag::canDecode (const QMimeSource* e) {
495 return Q3TextDrag::canDecode(e);
498 bool PhraseBookDrag::decode (const QMimeSource *e, PhraseBook *book) {
499 QString string;
500 QString subtype1 = "x-xml-phrasebook";
501 QString subtype2 = "xml";
503 if (!Q3TextDrag::decode(e, string, subtype1))
504 if (!Q3TextDrag::decode(e, string, subtype2)) {
505 if (Q3TextDrag::decode(e, string)) {
506 *book += PhraseBookEntry(Phrase(string, ""), 0, true);
507 return true;
509 else return false;
512 return book->decode(string);
515 #include "phrasebook.moc"