1 /***************************************************************************
2 phrasebook.cpp - description
4 begin : Don Sep 19 2002
5 copyright : (C) 2002 by Gunnar Schmi Dt
6 email : kmouth@schmi-dt.de
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
18 #include "phrasebook.h"
19 #include "phrasebookparser.h"
27 #include <QTextStream>
29 #include <kactionmenu.h>
30 #include <kactioncollection.h>
35 #include <ktemporaryfile.h>
36 #include <kio/netaccess.h>
37 #include <kfiledialog.h>
38 #include <kmessagebox.h>
39 #include <kglobalsettings.h>
46 Phrase::Phrase (const QString
&phrase
) {
47 this->phrase
= phrase
;
51 Phrase::Phrase (const QString
&phrase
, const QString
&shortcut
) {
52 this->phrase
= phrase
;
53 this->shortcut
= shortcut
;
56 QString
Phrase::getPhrase() const {
60 QString
Phrase::getShortcut() const {
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 () {
77 isPhraseValue
= false;
80 PhraseBookEntry::PhraseBookEntry (Phrase phrase
, int level
, bool isPhrase
) {
81 this->phrase
= phrase
;
83 isPhraseValue
= isPhrase
;
86 bool PhraseBookEntry::isPhrase() const {
90 Phrase
PhraseBookEntry::getPhrase() const {
94 int PhraseBookEntry::getLevel() const {
98 // ***************************************************************************
100 void PhraseBook::print(KPrinter
*pPrinter
) {
101 QPainter printpainter
;
102 printpainter
.begin(pPrinter
);
104 QRect size
= printpainter
.viewport ();
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()) {
122 printpainter
.drawText (x
+16*(*it
).getLevel(),y
,
123 w
-16*(*it
).getLevel(),rect
.height(),
124 Qt::AlignJustify
| Qt::TextWordWrap
,
125 (*it
).getPhrase().getPhrase());
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();
153 QByteArray
encodeString (const QString str
) {
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
+ ';';
162 res
= res
+ (char)uc
;
167 QString
PhraseBook::encode () {
169 result
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
170 result
+= "<!DOCTYPE phrasebook>\n";
171 result
+= "<phrasebook>\n";
173 PhraseBookEntryList::iterator it
;
175 for (it
= begin(); it
!= end(); ++it
) {
176 int newLevel
= (*it
).getLevel();
177 while (level
< newLevel
) {
178 result
+= "<phrasebook>\n";
181 while (level
> newLevel
) {
182 result
+= "</phrasebook>\n";
186 if ((*it
).isPhrase()) {
187 Phrase phrase
= (*it
).getPhrase();
188 result
+= "<phrase shortcut=\"" + encodeString(phrase
.getShortcut());
189 result
+= "\">" + encodeString(phrase
.getPhrase()) + "</phrase>\n";
192 Phrase phrase
= (*it
).getPhrase();
193 result
+= "<phrasebook name=\"" + encodeString(phrase
.getPhrase()) + "\">\n";
198 result
+= "</phrasebook>\n";
201 result
+= "</phrasebook>";
205 QStringList
PhraseBook::toStringList () {
208 PhraseBook::iterator it
;
209 for (it
= begin(); it
!= end(); ++it
) {
210 if ((*it
).isPhrase())
211 result
+= (*it
).getPhrase().getPhrase();
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
) {
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
))
235 QTextStream
stream(&file
);
236 save (stream
, asPhrasebook
);
239 if (file
.error() != QFile::NoError
)
245 KTemporaryFile tempFile
;
248 QTextStream
ts(&tempFile
);
249 save (ts
, asPhrasebook
);
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.
262 filters
= i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files");
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
) {
274 url
= fdlg
.selectedUrl();
276 if (url
.isEmpty() || !url
.isValid()) {
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
) {
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
) {
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);
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
) {
314 if (filetype
== KMessageBox::Yes
) {
315 result
= save (url
, true);
318 result
= save (url
, false);
322 else // file format "All files" requested, so decide by extension
331 bool PhraseBook::open (const KUrl
&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
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);
369 KIO::NetAccess::removeTempFile (tempFile
);
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
;
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);
390 toolbar
->addAction(menu
);
393 parent
->addAction(menu
);
396 parent
= menu
->menu();
399 while (newLevel
< level
&& (parent
!= popup
)) {
400 parent
= stack
.pop();
403 if ((*it
).isPhrase()) {
404 Phrase phrase
= (*it
).getPhrase();
405 KAction
*action
= new PhraseAction (phrase
.getPhrase(),
406 phrase
.getShortcut(), receiver
, slot
, phrases
);
408 toolbar
->addAction(action
);
410 parent
->addAction(action
);
413 Phrase phrase
= (*it
).getPhrase();
414 KActionMenu
*menu
= phrases
->add
<KActionMenu
>("phrasebook");
415 menu
->setText(phrase
.getPhrase());
416 menu
->setDelayed(false);
418 toolbar
->addAction(menu
);
419 parent
->addAction(menu
);
421 parent
= menu
->menu();
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
)
445 PhraseBookDrag::PhraseBookDrag (QWidget
*dragSource
, const char *name
)
446 : Q3DragObject (dragSource
, name
)
451 PhraseBookDrag::~PhraseBookDrag () {
454 void PhraseBookDrag::setBook (PhraseBook
*book
) {
457 xmlphrasebook
.setText(QString());
458 xml
.setText(QString());
459 plain
.setText(QString());
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 {
474 return plain
.format(i
);
476 return plain
.format(i
/3);
478 return xml
.format(i
/3);
480 return xmlphrasebook
.format(i
/3);
483 QByteArray
PhraseBookDrag::encodedData (const char* mime
) const {
486 if (m
.contains("xml-phrasebook"))
487 return xmlphrasebook
.encodedData(mime
);
488 else if (m
.contains("xml"))
489 return xml
.encodedData(mime
);
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
) {
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);
512 return book
->decode(string
);
515 #include "phrasebook.moc"