Use QMenu
[kdeaccessibility.git] / kmouth / phrasebook / phrasebook.cpp
blob15b87be10652edcffab9c5a8fd46100749a0bdec
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 <qprinter.h>
19 #include <qpainter.h>
20 #include <qfile.h>
21 #include <qxml.h>
22 #include <qregexp.h>
23 #include <q3ptrstack.h>
24 #include <QTextStream>
25 #include <Q3PopupMenu>
27 #include <klocale.h>
28 #include <kaction.h>
29 #include <kmenu.h>
30 #include <ktoolbar.h>
31 #include <ktempfile.h>
32 #include <kio/netaccess.h>
33 #include <kfiledialog.h>
34 #include <kmessagebox.h>
35 #include <kglobalsettings.h>
37 #include "phrasebookparser.h"
38 #include "phrasebook.h"
40 Phrase::Phrase() {
41 this->phrase = "";
42 this->shortcut = "";
45 Phrase::Phrase (const QString &phrase) {
46 this->phrase = phrase;
47 this->shortcut = "";
50 Phrase::Phrase (const QString &phrase, const QString &shortcut) {
51 this->phrase = phrase;
52 this->shortcut = shortcut;
55 QString Phrase::getPhrase() const {
56 return phrase;
59 QString Phrase::getShortcut() const {
60 return shortcut;
63 void Phrase::setPhrase (const QString &phrase) {
64 this->phrase = phrase;
67 void Phrase::setShortcut (const QString &shortcut) {
68 this->shortcut = shortcut;
71 // ***************************************************************************
73 PhraseBookEntry::PhraseBookEntry () {
74 phrase = Phrase();
75 level = 1;
76 isPhraseValue = false;
79 PhraseBookEntry::PhraseBookEntry (Phrase phrase, int level, bool isPhrase) {
80 this->phrase = phrase;
81 this->level = level;
82 isPhraseValue = isPhrase;
85 bool PhraseBookEntry::isPhrase() const {
86 return isPhraseValue;
89 Phrase PhraseBookEntry::getPhrase() const {
90 return phrase;
93 int PhraseBookEntry::getLevel() const {
94 return level;
97 // ***************************************************************************
99 void PhraseBook::print(KPrinter *pPrinter) {
100 QPainter printpainter;
101 printpainter.begin(pPrinter);
103 QRect size = printpainter.viewport ();
104 int x = size.x();
105 int y = size.y();
106 int w = size.width();
107 printpainter.setFont (QFont (KGlobalSettings::generalFont().family(), 12));
108 QFontMetrics metrics = printpainter.fontMetrics();
110 PhraseBookEntryList::iterator it;
111 for (it = begin(); it != end(); ++it) {
112 QRect rect = metrics.boundingRect (x+16*(*it).getLevel(), y,
113 w-16*(*it).getLevel(), 0,
114 Qt::AlignJustify | Qt::TextWordWrap,
115 (*it).getPhrase().getPhrase());
117 if (y+rect.height() > size.height()) {
118 pPrinter->newPage();
119 y = 0;
121 printpainter.drawText (x+16*(*it).getLevel(),y,
122 w-16*(*it).getLevel(),rect.height(),
123 Qt::AlignJustify | Qt::TextWordWrap,
124 (*it).getPhrase().getPhrase());
125 y += rect.height();
128 printpainter.end();
131 bool PhraseBook::decode (const QString &xml) {
132 QXmlInputSource source;
133 source.setData (xml);
134 return decode (source);
137 bool PhraseBook::decode (QXmlInputSource &source) {
138 PhraseBookParser parser;
139 QXmlSimpleReader reader;
140 reader.setFeature ("http://trolltech.com/xml/features/report-start-end-entity", true);
141 reader.setContentHandler (&parser);
143 if (reader.parse(source)) {
144 PhraseBookEntryList::clear();
145 *(PhraseBookEntryList *)this += parser.getPhraseList();
146 return true;
148 else
149 return false;
152 QByteArray encodeString (const QString str) {
153 QByteArray res = "";
154 for (int i = 0; i < (int)str.length(); i++) {
155 QChar ch = str.at(i);
156 ushort uc = ch.unicode();
157 QByteArray number; number.setNum(uc);
158 if ((uc>127) || (uc<32) || (ch=='<') || (ch=='>') || (ch=='&') || (ch==';'))
159 res = res + "&#" + number + ";";
160 else
161 res = res + (char)uc;
163 return res;
166 QString PhraseBook::encode () {
167 QString result;
168 result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
169 result += "<!DOCTYPE phrasebook>\n";
170 result += "<phrasebook>\n";
172 PhraseBookEntryList::iterator it;
173 int level = 0;
174 for (it = begin(); it != end(); ++it) {
175 int newLevel = (*it).getLevel();
176 while (level < newLevel) {
177 result += "<phrasebook>\n";
178 level++;
180 while (level > newLevel) {
181 result += "</phrasebook>\n";
182 level--;
185 if ((*it).isPhrase()) {
186 Phrase phrase = (*it).getPhrase();
187 result += "<phrase shortcut=\"" + encodeString(phrase.getShortcut());
188 result += "\">" + encodeString(phrase.getPhrase()) + "</phrase>\n";
190 else {
191 Phrase phrase = (*it).getPhrase();
192 result += "<phrasebook name=\"" + encodeString(phrase.getPhrase()) + "\">\n";
193 level++;
196 while (level > 0) {
197 result += "</phrasebook>\n";
198 level--;
200 result += "</phrasebook>";
201 return result;
204 QStringList PhraseBook::toStringList () {
205 QStringList result;
207 PhraseBook::iterator it;
208 for (it = begin(); it != end(); ++it) {
209 if ((*it).isPhrase())
210 result += (*it).getPhrase().getPhrase();
212 return result;
215 bool PhraseBook::save (const KURL &url) {
216 QRegExp pattern("*.phrasebook",true,true);
217 return save (url, pattern.exactMatch(url.fileName()));
221 void PhraseBook::save (QTextStream &stream, bool asPhrasebook) {
222 if (asPhrasebook)
223 stream << encode();
224 else
225 stream << toStringList().join("\n");
228 bool PhraseBook::save (const KURL &url, bool asPhrasebook) {
229 if (url.isLocalFile()) {
230 QFile file(url.path());
231 if(!file.open(QIODevice::WriteOnly))
232 return false;
234 QTextStream stream(&file);
235 save (stream, asPhrasebook);
236 file.close();
238 if (file.status() != IO_Ok)
239 return false;
240 else
241 return true;
243 else {
244 KTempFile tempFile;
245 tempFile.setAutoDelete(true);
247 save (*tempFile.textStream(), asPhrasebook);
248 tempFile.close();
250 return KIO::NetAccess::upload(tempFile.name(), url);
254 int PhraseBook::save (QWidget *parent, const QString &title, KURL &url, bool phrasebookFirst) {
255 // KFileDialog::getSaveURL(...) is not useful here as we need
256 // to know the requested file type.
258 QString filters;
259 if (phrasebookFirst)
260 filters = i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files");
261 else
262 filters = i18n("*.txt|Plain Text Files (*.txt)\n*.phrasebook|Phrase Books (*.phrasebook)\n*|All Files");
264 KFileDialog fdlg(QString::null,filters, parent, "filedialog", true);
265 fdlg.setCaption(title);
266 fdlg.setOperationMode( KFileDialog::Saving );
268 if (fdlg.exec() != QDialog::Accepted) {
269 return 0;
272 url = fdlg.selectedURL();
274 if (url.isEmpty() || !url.isValid()) {
275 return -1;
278 if (KIO::NetAccess::exists(url)) {
279 if (KMessageBox::warningContinueCancel(0,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
280 "Do you want to overwrite it?").arg(url.url())),i18n("File Exists"),i18n("&Overwrite"))==KMessageBox::Cancel) {
281 return 0;
285 bool result;
286 if (fdlg.currentFilter() == "*.phrasebook") {
287 if (url.fileName (false).contains('.') == 0) {
288 url.setFileName (url.fileName(false) + ".phrasebook");
290 else if (url.fileName (false).right (11).contains (".phrasebook", false) == 0) {
291 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>. "
292 "Do you wish to add <i>.phrasebook</i> to the filename?").arg(url.fileName())),i18n("File Extension"),i18n("Add"),i18n("Do Not Add"));
293 if (filetype == KMessageBox::Cancel) {
294 return 0;
296 if (filetype == KMessageBox::Yes) {
297 url.setFileName (url.fileName(false) + ".phrasebook");
300 result = save (url, true);
302 else if (fdlg.currentFilter() == "*.txt") {
303 if (url.fileName (false).right (11).contains (".phrasebook", false) == 0) {
304 result = save (url, false);
306 else {
307 int filetype = KMessageBox::questionYesNoCancel (0,QString("<qt>%1</qt>").arg(i18n("Your chosen filename <i>%1</i> has the extension <i>.phrasebook</i>. "
308 "Do you wish to save in phrasebook format?").arg(url.fileName())),i18n("File Extension"),i18n("As Phrasebook"),i18n("As Plain Text"));
309 if (filetype == KMessageBox::Cancel) {
310 return 0;
312 if (filetype == KMessageBox::Yes) {
313 result = save (url, true);
315 else {
316 result = save (url, false);
320 else // file format "All files" requested, so decide by extension
321 result = save (url);
323 if (result)
324 return 1;
325 else
326 return -1;
329 bool PhraseBook::open (const KURL &url) {
330 QString tempFile;
331 KURL fileUrl = url;
333 QString protocol = fileUrl.protocol();
334 if (protocol.isEmpty() || protocol.isNull()) {
335 fileUrl.setProtocol ("file");
336 fileUrl.setPath (url.url());
339 if (KIO::NetAccess::download (fileUrl, tempFile)) {
340 QStringList list = QStringList();
342 // First: try to load it as a normal phrase book
343 QFile file(tempFile);
344 QXmlInputSource source (&file);
345 bool error = !decode (source);
347 // Second: if the file does not contain a phrase book, load it as
348 // a plain text file
349 if (error) {
350 // Load each line of the plain text file as a new phrase
352 QFile file(tempFile);
353 if (file.open(QIODevice::ReadOnly)) {
354 QTextStream stream(&file);
356 while (!stream.atEnd()) {
357 QString s = stream.readLine();
358 if (!(s.isNull() || s.isEmpty()))
359 *this += PhraseBookEntry(Phrase(s, ""), 0, true);
361 file.close();
362 error = false;
364 else
365 error = true;
367 KIO::NetAccess::removeTempFile (tempFile);
369 return !error;
371 else
372 return false;
375 void PhraseBook::addToGUI (QMenu *popup, KToolBar *toolbar, KActionCollection *phrases,
376 QObject *receiver, const char *slot) const {
377 if ((popup != 0) || (toolbar != 0)) {
378 Q3PtrStack<QWidget> stack;
379 QWidget *parent = popup;
380 int level = 0;
382 QList<PhraseBookEntry>::ConstIterator it;
383 for (it = begin(); it != end(); ++it) {
384 int newLevel = (*it).getLevel();
385 while (newLevel > level) {
386 KActionMenu *menu = new KActionMenu("", "phrasebook");
387 menu->setDelayed(false);
388 phrases->insert(menu);
389 menu->plug (parent);
390 if (parent == popup)
391 menu->plug (toolbar);
392 if (parent != 0)
393 stack.push (parent);
394 parent = menu->popupMenu();
395 level++;
397 while (newLevel < level && (parent != popup)) {
398 parent = stack.pop();
399 level--;
401 if ((*it).isPhrase()) {
402 Phrase phrase = (*it).getPhrase();
403 KAction *action = new PhraseAction (phrase.getPhrase(),
404 phrase.getShortcut(), receiver, slot, phrases);
405 if (parent == popup)
406 action->plug (toolbar);
407 if (parent != 0)
408 action->plug(parent);
410 else {
411 Phrase phrase = (*it).getPhrase();
412 KActionMenu *menu = new KActionMenu(phrase.getPhrase(), "phrasebook");
413 menu->setDelayed(false);
414 phrases->insert(menu);
415 if (parent == popup)
416 menu->plug (toolbar);
417 if (parent != 0)
418 menu->plug (parent);
419 stack.push (parent);
420 parent = menu->popupMenu();
421 level++;
427 void PhraseBook::insert (const QString &name, const PhraseBook &book) {
428 *this += PhraseBookEntry(Phrase(name), 0, false);
430 QList<PhraseBookEntry>::ConstIterator it;
431 for (it = book.begin(); it != book.end(); ++it) {
432 *this += PhraseBookEntry ((*it).getPhrase(), (*it).getLevel()+1, (*it).isPhrase());
436 // ***************************************************************************
438 PhraseBookDrag::PhraseBookDrag (PhraseBook *book, QWidget *dragSource, const char *name)
439 : Q3DragObject (dragSource, name)
441 setBook (book);
444 PhraseBookDrag::PhraseBookDrag (QWidget *dragSource, const char *name)
445 : Q3DragObject (dragSource, name)
447 setBook (0);
450 PhraseBookDrag::~PhraseBookDrag () {
453 void PhraseBookDrag::setBook (PhraseBook *book) {
454 if (book == 0) {
455 isEmpty = true;
456 xmlphrasebook.setText(QString::null);
457 xml.setText(QString::null);
458 plain.setText(QString::null);
460 else {
461 isEmpty = false;
462 xmlphrasebook.setText(book->encode());
463 xml.setText(book->encode());
464 plain.setText(book->toStringList().join("\n"));
466 xmlphrasebook.setSubtype("x-xml-phrasebook");
467 xml.setSubtype("xml");
468 plain.setSubtype("plain");
471 const char *PhraseBookDrag::format (int i) const {
472 if (isEmpty)
473 return plain.format(i);
474 else if (i%3 == 0)
475 return plain.format(i/3);
476 else if (i%3 == 1)
477 return xml.format(i/3);
478 else
479 return xmlphrasebook.format(i/3);
482 QByteArray PhraseBookDrag::encodedData (const char* mime) const {
483 QByteArray m(mime);
484 m = m.toLower();
485 if (m.contains("xml-phrasebook"))
486 return xmlphrasebook.encodedData(mime);
487 else if (m.contains("xml"))
488 return xml.encodedData(mime);
489 else
490 return plain.encodedData(mime);
493 bool PhraseBookDrag::canDecode (const QMimeSource* e) {
494 return Q3TextDrag::canDecode(e);
497 bool PhraseBookDrag::decode (const QMimeSource *e, PhraseBook *book) {
498 QString string;
499 QString subtype1 = "x-xml-phrasebook";
500 QString subtype2 = "xml";
502 if (!Q3TextDrag::decode(e, string, subtype1))
503 if (!Q3TextDrag::decode(e, string, subtype2)) {
504 if (Q3TextDrag::decode(e, string)) {
505 *book += PhraseBookEntry(Phrase(string, ""), 0, true);
506 return true;
508 else return false;
511 return book->decode(string);
514 #include "phrasebook.moc"