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 ***************************************************************************/
23 #include <q3ptrstack.h>
24 #include <QTextStream>
25 #include <Q3PopupMenu>
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"
45 Phrase::Phrase (const QString
&phrase
) {
46 this->phrase
= phrase
;
50 Phrase::Phrase (const QString
&phrase
, const QString
&shortcut
) {
51 this->phrase
= phrase
;
52 this->shortcut
= shortcut
;
55 QString
Phrase::getPhrase() const {
59 QString
Phrase::getShortcut() const {
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 () {
76 isPhraseValue
= false;
79 PhraseBookEntry::PhraseBookEntry (Phrase phrase
, int level
, bool isPhrase
) {
80 this->phrase
= phrase
;
82 isPhraseValue
= isPhrase
;
85 bool PhraseBookEntry::isPhrase() const {
89 Phrase
PhraseBookEntry::getPhrase() const {
93 int PhraseBookEntry::getLevel() const {
97 // ***************************************************************************
99 void PhraseBook::print(KPrinter
*pPrinter
) {
100 QPainter printpainter
;
101 printpainter
.begin(pPrinter
);
103 QRect size
= printpainter
.viewport ();
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()) {
121 printpainter
.drawText (x
+16*(*it
).getLevel(),y
,
122 w
-16*(*it
).getLevel(),rect
.height(),
123 Qt::AlignJustify
| Qt::TextWordWrap
,
124 (*it
).getPhrase().getPhrase());
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();
152 QByteArray
encodeString (const QString str
) {
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
+ ";";
161 res
= res
+ (char)uc
;
166 QString
PhraseBook::encode () {
168 result
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
169 result
+= "<!DOCTYPE phrasebook>\n";
170 result
+= "<phrasebook>\n";
172 PhraseBookEntryList::iterator it
;
174 for (it
= begin(); it
!= end(); ++it
) {
175 int newLevel
= (*it
).getLevel();
176 while (level
< newLevel
) {
177 result
+= "<phrasebook>\n";
180 while (level
> newLevel
) {
181 result
+= "</phrasebook>\n";
185 if ((*it
).isPhrase()) {
186 Phrase phrase
= (*it
).getPhrase();
187 result
+= "<phrase shortcut=\"" + encodeString(phrase
.getShortcut());
188 result
+= "\">" + encodeString(phrase
.getPhrase()) + "</phrase>\n";
191 Phrase phrase
= (*it
).getPhrase();
192 result
+= "<phrasebook name=\"" + encodeString(phrase
.getPhrase()) + "\">\n";
197 result
+= "</phrasebook>\n";
200 result
+= "</phrasebook>";
204 QStringList
PhraseBook::toStringList () {
207 PhraseBook::iterator it
;
208 for (it
= begin(); it
!= end(); ++it
) {
209 if ((*it
).isPhrase())
210 result
+= (*it
).getPhrase().getPhrase();
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
) {
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
))
234 QTextStream
stream(&file
);
235 save (stream
, asPhrasebook
);
238 if (file
.status() != IO_Ok
)
245 tempFile
.setAutoDelete(true);
247 save (*tempFile
.textStream(), asPhrasebook
);
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.
260 filters
= i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files");
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
) {
272 url
= fdlg
.selectedURL();
274 if (url
.isEmpty() || !url
.isValid()) {
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
) {
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
) {
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);
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
) {
312 if (filetype
== KMessageBox::Yes
) {
313 result
= save (url
, true);
316 result
= save (url
, false);
320 else // file format "All files" requested, so decide by extension
329 bool PhraseBook::open (const KURL
&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
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);
367 KIO::NetAccess::removeTempFile (tempFile
);
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
;
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
);
391 menu
->plug (toolbar
);
394 parent
= menu
->popupMenu();
397 while (newLevel
< level
&& (parent
!= popup
)) {
398 parent
= stack
.pop();
401 if ((*it
).isPhrase()) {
402 Phrase phrase
= (*it
).getPhrase();
403 KAction
*action
= new PhraseAction (phrase
.getPhrase(),
404 phrase
.getShortcut(), receiver
, slot
, phrases
);
406 action
->plug (toolbar
);
408 action
->plug(parent
);
411 Phrase phrase
= (*it
).getPhrase();
412 KActionMenu
*menu
= new KActionMenu(phrase
.getPhrase(), "phrasebook");
413 menu
->setDelayed(false);
414 phrases
->insert(menu
);
416 menu
->plug (toolbar
);
420 parent
= menu
->popupMenu();
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
)
444 PhraseBookDrag::PhraseBookDrag (QWidget
*dragSource
, const char *name
)
445 : Q3DragObject (dragSource
, name
)
450 PhraseBookDrag::~PhraseBookDrag () {
453 void PhraseBookDrag::setBook (PhraseBook
*book
) {
456 xmlphrasebook
.setText(QString::null
);
457 xml
.setText(QString::null
);
458 plain
.setText(QString::null
);
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 {
473 return plain
.format(i
);
475 return plain
.format(i
/3);
477 return xml
.format(i
/3);
479 return xmlphrasebook
.format(i
/3);
482 QByteArray
PhraseBookDrag::encodedData (const char* mime
) const {
485 if (m
.contains("xml-phrasebook"))
486 return xmlphrasebook
.encodedData(mime
);
487 else if (m
.contains("xml"))
488 return xml
.encodedData(mime
);
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
) {
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);
511 return book
->decode(string
);
514 #include "phrasebook.moc"