summaryrefslogtreecommitdiffstats
path: root/kmouth/phrasebook
diff options
context:
space:
mode:
Diffstat (limited to 'kmouth/phrasebook')
-rw-r--r--kmouth/phrasebook/Makefile.am16
-rw-r--r--kmouth/phrasebook/buttonboxui.ui107
-rw-r--r--kmouth/phrasebook/phrasebook.cpp512
-rw-r--r--kmouth/phrasebook/phrasebook.h195
-rw-r--r--kmouth/phrasebook/phrasebookdialog.cpp758
-rw-r--r--kmouth/phrasebook/phrasebookdialog.h234
-rw-r--r--kmouth/phrasebook/phrasebookdialogui.rc64
-rw-r--r--kmouth/phrasebook/phrasebookparser.cpp112
-rw-r--r--kmouth/phrasebook/phrasebookparser.h73
-rw-r--r--kmouth/phrasebook/phrasetree.cpp556
-rw-r--r--kmouth/phrasebook/phrasetree.h108
11 files changed, 2735 insertions, 0 deletions
diff --git a/kmouth/phrasebook/Makefile.am b/kmouth/phrasebook/Makefile.am
new file mode 100644
index 0000000..bc0b31c
--- /dev/null
+++ b/kmouth/phrasebook/Makefile.am
@@ -0,0 +1,16 @@
+####### kdevelop will overwrite this part!!! (begin)##########
+noinst_LIBRARIES = libphrasebook.a
+
+INCLUDES = $(all_includes)
+
+libphrasebook_a_METASOURCES = AUTO
+
+libphrasebook_a_SOURCES = buttonboxui.ui phrasetree.cpp phrasebookparser.cpp phrasebookdialog.cpp phrasebook.cpp
+
+
+EXTRA_DIST = phrasebook.cpp phrasebook.h phrasebookdialog.cpp phrasebookdialog.h phrasebookparser.cpp phrasebookparser.h phrasetree.cpp phrasetree.h phrasebookdialogui.rc buttonboxui.ui
+
+####### kdevelop will overwrite this part!!! (end)############
+
+rcdir = $(kde_datadir)/kmouth
+rc_DATA = phrasebookdialogui.rc
diff --git a/kmouth/phrasebook/buttonboxui.ui b/kmouth/phrasebook/buttonboxui.ui
new file mode 100644
index 0000000..abc999b
--- /dev/null
+++ b/kmouth/phrasebook/buttonboxui.ui
@@ -0,0 +1,107 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>ButtonBoxUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ButtonBoxUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>278</width>
+ <height>141</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Currently Selected Phrase or Phrase Book</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>phrasebox</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Currently Selected Phrase or Phrase Book</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QWidget" row="3" column="2">
+ <property name="name">
+ <cstring>keyButtonPlace</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>lineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>With this line edit you define the name of a sub-phrasebook or the contents of a phrase.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>noKey</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;None</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you select this option then the selected phrase will not be reachable by a keyboard shortcut.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="1">
+ <property name="name">
+ <cstring>customKey</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;ustom</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you select this option then the selected phrase will be reachable by a keyboard shortcut. You can change the shortcut with the button next to this option.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>shortcutLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Shortcut for the phrase:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Text of the &amp;phrase:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>lineEdit</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>With this line edit you define the name of a sub-phrasebook or the contents of a phrase.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmouth/phrasebook/phrasebook.cpp b/kmouth/phrasebook/phrasebook.cpp
new file mode 100644
index 0000000..0ec8da3
--- /dev/null
+++ b/kmouth/phrasebook/phrasebook.cpp
@@ -0,0 +1,512 @@
+/***************************************************************************
+ phrasebook.cpp - description
+ -------------------
+ begin : Don Sep 19 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qfile.h>
+#include <qxml.h>
+#include <qregexp.h>
+#include <qptrstack.h>
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <ktoolbar.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+
+#include "phrasebookparser.h"
+#include "phrasebook.h"
+
+Phrase::Phrase() {
+ this->phrase = "";
+ this->shortcut = "";
+}
+
+Phrase::Phrase (const QString &phrase) {
+ this->phrase = phrase;
+ this->shortcut = "";
+}
+
+Phrase::Phrase (const QString &phrase, const QString &shortcut) {
+ this->phrase = phrase;
+ this->shortcut = shortcut;
+}
+
+QString Phrase::getPhrase() const {
+ return phrase;
+}
+
+QString Phrase::getShortcut() const {
+ return shortcut;
+}
+
+void Phrase::setPhrase (const QString &phrase) {
+ this->phrase = phrase;
+}
+
+void Phrase::setShortcut (const QString &shortcut) {
+ this->shortcut = shortcut;
+}
+
+// ***************************************************************************
+
+PhraseBookEntry::PhraseBookEntry () {
+ phrase = Phrase();
+ level = 1;
+ isPhraseValue = false;
+}
+
+PhraseBookEntry::PhraseBookEntry (Phrase phrase, int level, bool isPhrase) {
+ this->phrase = phrase;
+ this->level = level;
+ isPhraseValue = isPhrase;
+}
+
+bool PhraseBookEntry::isPhrase() const {
+ return isPhraseValue;
+}
+
+Phrase PhraseBookEntry::getPhrase() const {
+ return phrase;
+}
+
+int PhraseBookEntry::getLevel() const {
+ return level;
+}
+
+// ***************************************************************************
+
+void PhraseBook::print(KPrinter *pPrinter) {
+ QPainter printpainter;
+ printpainter.begin(pPrinter);
+
+ QRect size = printpainter.viewport ();
+ int x = size.x();
+ int y = size.y();
+ int w = size.width();
+ printpainter.setFont (QFont (KGlobalSettings::generalFont().family(), 12));
+ QFontMetrics metrics = printpainter.fontMetrics();
+
+ PhraseBookEntryList::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ QRect rect = metrics.boundingRect (x+16*(*it).getLevel(), y,
+ w-16*(*it).getLevel(), 0,
+ Qt::AlignJustify | Qt::WordBreak,
+ (*it).getPhrase().getPhrase());
+
+ if (y+rect.height() > size.height()) {
+ pPrinter->newPage();
+ y = 0;
+ }
+ printpainter.drawText (x+16*(*it).getLevel(),y,
+ w-16*(*it).getLevel(),rect.height(),
+ Qt::AlignJustify | Qt::WordBreak,
+ (*it).getPhrase().getPhrase());
+ y += rect.height();
+ }
+
+ printpainter.end();
+}
+
+bool PhraseBook::decode (const QString &xml) {
+ QXmlInputSource source;
+ source.setData (xml);
+ return decode (source);
+}
+
+bool PhraseBook::decode (QXmlInputSource &source) {
+ PhraseBookParser parser;
+ QXmlSimpleReader reader;
+ reader.setFeature ("http://trolltech.com/xml/features/report-start-end-entity", true);
+ reader.setContentHandler (&parser);
+
+ if (reader.parse(source)) {
+ PhraseBookEntryList::clear();
+ *(PhraseBookEntryList *)this += parser.getPhraseList();
+ return true;
+ }
+ else
+ return false;
+}
+
+QCString encodeString (const QString str) {
+ QCString res = "";
+ for (int i = 0; i < (int)str.length(); i++) {
+ QChar ch = str.at(i);
+ ushort uc = ch.unicode();
+ QCString number; number.setNum(uc);
+ if ((uc>127) || (uc<32) || (ch=='<') || (ch=='>') || (ch=='&') || (ch==';'))
+ res = res + "&#" + number + ";";
+ else
+ res = res + (char)uc;
+ }
+ return res;
+}
+
+QString PhraseBook::encode () {
+ QString result;
+ result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ result += "<!DOCTYPE phrasebook>\n";
+ result += "<phrasebook>\n";
+
+ PhraseBookEntryList::iterator it;
+ int level = 0;
+ for (it = begin(); it != end(); ++it) {
+ int newLevel = (*it).getLevel();
+ while (level < newLevel) {
+ result += "<phrasebook>\n";
+ level++;
+ }
+ while (level > newLevel) {
+ result += "</phrasebook>\n";
+ level--;
+ }
+
+ if ((*it).isPhrase()) {
+ Phrase phrase = (*it).getPhrase();
+ result += "<phrase shortcut=\"" + encodeString(phrase.getShortcut());
+ result += "\">" + encodeString(phrase.getPhrase()) + "</phrase>\n";
+ }
+ else {
+ Phrase phrase = (*it).getPhrase();
+ result += "<phrasebook name=\"" + encodeString(phrase.getPhrase()) + "\">\n";
+ level++;
+ }
+ }
+ while (level > 0) {
+ result += "</phrasebook>\n";
+ level--;
+ }
+ result += "</phrasebook>";
+ return result;
+}
+
+QStringList PhraseBook::toStringList () {
+ QStringList result;
+
+ PhraseBook::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if ((*it).isPhrase())
+ result += (*it).getPhrase().getPhrase();
+ }
+ return result;
+}
+
+bool PhraseBook::save (const KURL &url) {
+ QRegExp pattern("*.phrasebook",true,true);
+ return save (url, pattern.exactMatch(url.filename()));
+}
+
+
+void PhraseBook::save (QTextStream &stream, bool asPhrasebook) {
+ if (asPhrasebook)
+ stream << encode();
+ else
+ stream << toStringList().join("\n");
+}
+
+bool PhraseBook::save (const KURL &url, bool asPhrasebook) {
+ if (url.isLocalFile()) {
+ QFile file(url.path());
+ if(!file.open(IO_WriteOnly))
+ return false;
+
+ QTextStream stream(&file);
+ save (stream, asPhrasebook);
+ file.close();
+
+ if (file.status() != IO_Ok)
+ return false;
+ else
+ return true;
+ }
+ else {
+ KTempFile tempFile;
+ tempFile.setAutoDelete(true);
+
+ save (*tempFile.textStream(), asPhrasebook);
+ tempFile.close();
+
+ return KIO::NetAccess::upload(tempFile.name(), url);
+ }
+}
+
+int PhraseBook::save (QWidget *parent, const QString &title, KURL &url, bool phrasebookFirst) {
+ // KFileDialog::getSaveURL(...) is not useful here as we need
+ // to know the requested file type.
+
+ QString filters;
+ if (phrasebookFirst)
+ filters = i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files");
+ else
+ filters = i18n("*.txt|Plain Text Files (*.txt)\n*.phrasebook|Phrase Books (*.phrasebook)\n*|All Files");
+
+ KFileDialog fdlg(QString::null,filters, parent, "filedialog", true);
+ fdlg.setCaption(title);
+ fdlg.setOperationMode( KFileDialog::Saving );
+
+ if (fdlg.exec() != QDialog::Accepted) {
+ return 0;
+ }
+
+ url = fdlg.selectedURL();
+
+ if (url.isEmpty() || !url.isValid()) {
+ return -1;
+ }
+
+ if (KIO::NetAccess::exists(url)) {
+ if (KMessageBox::warningContinueCancel(0,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
+ "Do you want to overwrite it?").arg(url.url())),i18n("File Exists"),i18n("&Overwrite"))==KMessageBox::Cancel) {
+ return 0;
+ }
+ }
+
+ bool result;
+ if (fdlg.currentFilter() == "*.phrasebook") {
+ if (url.fileName (false).contains('.') == 0) {
+ url.setFileName (url.fileName(false) + ".phrasebook");
+ }
+ else if (url.fileName (false).right (11).contains (".phrasebook", false) == 0) {
+ 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>. "
+ "Do you wish to add <i>.phrasebook</i> to the filename?").arg(url.filename())),i18n("File Extension"),i18n("Add"),i18n("Do Not Add"));
+ if (filetype == KMessageBox::Cancel) {
+ return 0;
+ }
+ if (filetype == KMessageBox::Yes) {
+ url.setFileName (url.fileName(false) + ".phrasebook");
+ }
+ }
+ result = save (url, true);
+ }
+ else if (fdlg.currentFilter() == "*.txt") {
+ if (url.fileName (false).right (11).contains (".phrasebook", false) == 0) {
+ result = save (url, false);
+ }
+ else {
+ int filetype = KMessageBox::questionYesNoCancel (0,QString("<qt>%1</qt>").arg(i18n("Your chosen filename <i>%1</i> has the extension <i>.phrasebook</i>. "
+ "Do you wish to save in phrasebook format?").arg(url.filename())),i18n("File Extension"),i18n("As Phrasebook"),i18n("As Plain Text"));
+ if (filetype == KMessageBox::Cancel) {
+ return 0;
+ }
+ if (filetype == KMessageBox::Yes) {
+ result = save (url, true);
+ }
+ else {
+ result = save (url, false);
+ }
+ }
+ }
+ else // file format "All files" requested, so decide by extension
+ result = save (url);
+
+ if (result)
+ return 1;
+ else
+ return -1;
+}
+
+bool PhraseBook::open (const KURL &url) {
+ QString tempFile;
+ KURL fileUrl = url;
+
+ QString protocol = fileUrl.protocol();
+ if (protocol.isEmpty() || protocol.isNull()) {
+ fileUrl.setProtocol ("file");
+ fileUrl.setPath (url.url());
+ }
+
+ if (KIO::NetAccess::download (fileUrl, tempFile)) {
+ QStringList list = QStringList();
+
+ // First: try to load it as a normal phrase book
+ QFile file(tempFile);
+ QXmlInputSource source (&file);
+ bool error = !decode (source);
+
+ // Second: if the file does not contain a phrase book, load it as
+ // a plain text file
+ if (error) {
+ // Load each line of the plain text file as a new phrase
+
+ QFile file(tempFile);
+ if (file.open(IO_ReadOnly)) {
+ QTextStream stream(&file);
+
+ while (!stream.atEnd()) {
+ QString s = stream.readLine();
+ if (!(s.isNull() || s.isEmpty()))
+ *this += PhraseBookEntry(Phrase(s, ""), 0, true);
+ }
+ file.close();
+ error = false;
+ }
+ else
+ error = true;
+ }
+ KIO::NetAccess::removeTempFile (tempFile);
+
+ return !error;
+ }
+ else
+ return false;
+}
+
+void PhraseBook::addToGUI (QPopupMenu *popup, KToolBar *toolbar, KActionCollection *phrases,
+ QObject *receiver, const char *slot) const {
+ if ((popup != 0) || (toolbar != 0)) {
+ QPtrStack<QWidget> stack;
+ QWidget *parent = popup;
+ int level = 0;
+
+ QValueListConstIterator<PhraseBookEntry> it;
+ for (it = begin(); it != end(); ++it) {
+ int newLevel = (*it).getLevel();
+ while (newLevel > level) {
+ KActionMenu *menu = new KActionMenu("", "phrasebook");
+ menu->setDelayed(false);
+ phrases->insert(menu);
+ menu->plug (parent);
+ if (parent == popup)
+ menu->plug (toolbar);
+ if (parent != 0)
+ stack.push (parent);
+ parent = menu->popupMenu();
+ level++;
+ }
+ while (newLevel < level && (parent != popup)) {
+ parent = stack.pop();
+ level--;
+ }
+ if ((*it).isPhrase()) {
+ Phrase phrase = (*it).getPhrase();
+ KAction *action = new PhraseAction (phrase.getPhrase(),
+ phrase.getShortcut(), receiver, slot, phrases);
+ if (parent == popup)
+ action->plug (toolbar);
+ if (parent != 0)
+ action->plug(parent);
+ }
+ else {
+ Phrase phrase = (*it).getPhrase();
+ KActionMenu *menu = new KActionMenu(phrase.getPhrase(), "phrasebook");
+ menu->setDelayed(false);
+ phrases->insert(menu);
+ if (parent == popup)
+ menu->plug (toolbar);
+ if (parent != 0)
+ menu->plug (parent);
+ stack.push (parent);
+ parent = menu->popupMenu();
+ level++;
+ }
+ }
+ }
+}
+
+void PhraseBook::insert (const QString &name, const PhraseBook &book) {
+ *this += PhraseBookEntry(Phrase(name), 0, false);
+
+ QValueListConstIterator<PhraseBookEntry> it;
+ for (it = book.begin(); it != book.end(); ++it) {
+ *this += PhraseBookEntry ((*it).getPhrase(), (*it).getLevel()+1, (*it).isPhrase());
+ }
+}
+
+// ***************************************************************************
+
+PhraseBookDrag::PhraseBookDrag (PhraseBook *book, QWidget *dragSource, const char *name)
+ : QDragObject (dragSource, name)
+{
+ setBook (book);
+}
+
+PhraseBookDrag::PhraseBookDrag (QWidget *dragSource, const char *name)
+ : QDragObject (dragSource, name)
+{
+ setBook (0);
+}
+
+PhraseBookDrag::~PhraseBookDrag () {
+}
+
+void PhraseBookDrag::setBook (PhraseBook *book) {
+ if (book == 0) {
+ isEmpty = true;
+ xmlphrasebook.setText(QString::null);
+ xml.setText(QString::null);
+ plain.setText(QString::null);
+ }
+ else {
+ isEmpty = false;
+ xmlphrasebook.setText(book->encode());
+ xml.setText(book->encode());
+ plain.setText(book->toStringList().join("\n"));
+ }
+ xmlphrasebook.setSubtype("x-xml-phrasebook");
+ xml.setSubtype("xml");
+ plain.setSubtype("plain");
+}
+
+const char *PhraseBookDrag::format (int i) const {
+ if (isEmpty)
+ return plain.format(i);
+ else if (i%3 == 0)
+ return plain.format(i/3);
+ else if (i%3 == 1)
+ return xml.format(i/3);
+ else
+ return xmlphrasebook.format(i/3);
+}
+
+QByteArray PhraseBookDrag::encodedData (const char* mime) const {
+ QCString m(mime);
+ m = m.lower();
+ if (m.contains("xml-phrasebook"))
+ return xmlphrasebook.encodedData(mime);
+ else if (m.contains("xml"))
+ return xml.encodedData(mime);
+ else
+ return plain.encodedData(mime);
+}
+
+bool PhraseBookDrag::canDecode (const QMimeSource* e) {
+ return QTextDrag::canDecode(e);
+}
+
+bool PhraseBookDrag::decode (const QMimeSource *e, PhraseBook *book) {
+ QString string;
+ QCString subtype1 = "x-xml-phrasebook";
+ QCString subtype2 = "xml";
+
+ if (!QTextDrag::decode(e, string, subtype1))
+ if (!QTextDrag::decode(e, string, subtype2)) {
+ if (QTextDrag::decode(e, string)) {
+ *book += PhraseBookEntry(Phrase(string, ""), 0, true);
+ return true;
+ }
+ else return false;
+ }
+
+ return book->decode(string);
+}
+
+#include "phrasebook.moc"
diff --git a/kmouth/phrasebook/phrasebook.h b/kmouth/phrasebook/phrasebook.h
new file mode 100644
index 0000000..83cb3a9
--- /dev/null
+++ b/kmouth/phrasebook/phrasebook.h
@@ -0,0 +1,195 @@
+/***************************************************************************
+ phrasebook.h - description
+ -------------------
+ begin : Don Sep 19 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PHRASEBOOK_H
+#define PHRASEBOOK_H
+
+#include <qobject.h>
+#include <qdragobject.h>
+#include <qxml.h>
+
+#include <kaction.h>
+#include <kprinter.h>
+
+class KURL;
+
+/**
+ * The class Phrase represents one phrase in a phrase book.
+ * @author Gunnar Schmi Dt
+ */
+class Phrase {
+ friend class PhraseBookParser;
+public:
+ Phrase();
+ Phrase (const QString &phrase);
+ Phrase (const QString &phrase, const QString &shortcut);
+
+ QString getPhrase() const;
+ QString getShortcut() const;
+
+ void setPhrase (const QString &phrase);
+ void setShortcut (const QString &shortcut);
+
+private:
+ QString phrase;
+ QString shortcut;
+};
+
+/**
+ * The class PhraseBookEntry implements a phrase book entry. That can be either
+ * a phrase or a start tag a sub phrase book.
+ * @author Gunnar Schmi Dt
+ */
+class PhraseBookEntry {
+public:
+ PhraseBookEntry ();
+ PhraseBookEntry (Phrase phrase, int level = 1, bool isPhrase = true);
+ ~PhraseBookEntry () {};
+
+ void setPhrase (Phrase phrase, int level = 1, bool isPhrase = true);
+
+ bool isPhrase() const;
+ Phrase getPhrase() const;
+ int getLevel() const;
+
+private:
+ bool isPhraseValue;
+ Phrase phrase;
+ int level;
+};
+
+typedef QValueList<PhraseBookEntry> PhraseBookEntryList;
+
+/**
+ * The class PhraseBook implements a phrase book. It mainly stores a
+ * token list where each token is a phrase book entry (either a phrase
+ * or a sub phrase book). The entries are placed into a tree structure
+ * as follows:
+ *
+ * The level of each entry tells the level in the tree (level=0 is the top
+ * level), each sub book in level i directly or indirectly contains all
+ * following entries until an entry of level at most i or the end of the
+ * token list.
+ *
+ * @author Gunnar Schmi Dt
+ */
+class PhraseBook : public PhraseBookEntryList {
+public:
+ PhraseBook() : PhraseBookEntryList() {};
+ ~PhraseBook() {};
+
+ /** opens a file containing a phrase book. Returns true if successful. */
+ bool open (const KURL &url);
+
+ /** decodes a phrase book. Returns true if successful. */
+ bool decode (const QString &xml);
+
+ /** decodes a phrase book. Returns true if successful. */
+ bool decode (QXmlInputSource &source);
+
+ /** Writes the phrases to a file. Returns true if successful. */
+ bool save (const KURL &url);
+
+ /** Writes the phrases to a file. Returns true if successful. */
+ bool save (const KURL &url, bool asPhrasebook);
+
+ /** Writes the phrases to a QTextStream. */
+ void save (QTextStream &stream, bool asPhrasebook);
+
+ /** Prints the phrases. */
+ void print (KPrinter *pPrinter);
+
+ /** Shows a file selector and writes the phrases to a file.
+ * @return 1, if the file got successfully written,
+ * 0, if the user canceled the operation,
+ * -1, if there was an error when saving the file.
+ */
+ int save (QWidget *parent, const QString &title, KURL &url, bool phrasebookFirst = true);
+
+ /** encodes the phrase book. Returns the encoded xml code. */
+ QString encode ();
+
+ /** Stores all entries in a QStringList. All hierarchy information and all
+ * shortcuts are ignored during this operation.
+ */
+ QStringList toStringList();
+
+ /** Adds the entries of the book to both the given popup menu and the given
+ * toolbar. The corresponding actions will be inserted into phrases.
+ */
+ void addToGUI (QPopupMenu *popup, KToolBar *toolbar,
+ KActionCollection *phrases,
+ QObject *receiver, const char *slot) const;
+
+ /** Inserts book into a new sub phrase book.
+ * @param name the name of the new sub phrase book.
+ * @param book the phrase book to insert.
+ */
+ void insert (const QString &name, const PhraseBook &book);
+};
+
+/**
+ * The class PhraseBookDrag implements drag and drop support for phrase books.
+ * @author Gunnar Schmi Dt
+ */
+class PhraseBookDrag: public QDragObject {
+ Q_OBJECT
+public:
+ PhraseBookDrag (PhraseBook *book, QWidget *dragSource = 0, const char *name = 0);
+ PhraseBookDrag (QWidget *dragSource = 0, const char *name = 0);
+ ~PhraseBookDrag ();
+
+ virtual void setBook (PhraseBook *book);
+
+ const char *format (int i) const;
+ virtual QByteArray encodedData (const char *) const;
+
+ static bool canDecode (const QMimeSource *e);
+ static bool decode (const QMimeSource *e, PhraseBook *book);
+
+private:
+ bool isEmpty;
+ QTextDrag xmlphrasebook;
+ QTextDrag xml;
+ QTextDrag plain;
+};
+
+class PhraseAction : public KAction {
+ Q_OBJECT
+public:
+ PhraseAction (const QString& phrase, const QString& cut, const QObject* receiver, const char* slot, KActionCollection* parent)
+ : KAction (phrase, "phrase", KShortcut(cut), 0, 0, parent, phrase.latin1()) {
+ this->phrase = phrase;
+ connect (this, SIGNAL(slotActivated (const QString &)), receiver, slot);
+ };
+ ~PhraseAction () {
+ }
+
+public slots:
+ void slotActivated () {
+ KAction::slotActivated();
+ emit slotActivated (phrase);
+ }
+
+signals:
+ void slotActivated (const QString &phrase);
+
+private:
+ QString phrase;
+};
+
+#endif
diff --git a/kmouth/phrasebook/phrasebookdialog.cpp b/kmouth/phrasebook/phrasebookdialog.cpp
new file mode 100644
index 0000000..cc79d2f
--- /dev/null
+++ b/kmouth/phrasebook/phrasebookdialog.cpp
@@ -0,0 +1,758 @@
+/***************************************************************************
+ phrasebookdialog.cpp - description
+ -------------------
+ begin : Don Sep 19 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// include files for QT
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qclipboard.h>
+#include <qradiobutton.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qgroupbox.h>
+#include <qpopupmenu.h>
+#include <qvaluestack.h>
+#include <qptrstack.h>
+#include <qwhatsthis.h>
+
+// include files for KDE
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <klistview.h>
+#include <kiconloader.h>
+#include <kguiitem.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kstandarddirs.h>
+#include <kdesktopfile.h>
+
+#include "phrasebookdialog.h"
+#include "buttonboxui.h"
+#include "phrasetree.h"
+
+namespace PhraseBookPrivate {
+ enum columns {
+ name = 1,
+ filename = 2
+ };
+}
+
+CheckBookItem::CheckBookItem (QListViewItem *parent, QListViewItem *last,
+ const QString &text, const QString &name, const QString &filename)
+ : QCheckListItem (parent, text, QCheckListItem::CheckBox)
+{
+ moveItem (last);
+ setText(PhraseBookPrivate::name, name);
+ setText(PhraseBookPrivate::filename, filename);
+ setSelectable(false);
+
+ if (filename.isNull() || filename.isEmpty())
+ numberOfBooks = 0;
+ else
+ numberOfBooks = 1;
+ selectedBooks = 0;
+ ((CheckBookItem*)parent)->childChange (numberOfBooks, selectedBooks);
+}
+
+CheckBookItem::CheckBookItem (QListView *parent, QListViewItem *last,
+ const QString &text, const QString &name, const QString &filename)
+ : QCheckListItem (parent, text, QCheckListItem::CheckBox)
+{
+ moveItem (last);
+ setText(PhraseBookPrivate::name, name);
+ setText(PhraseBookPrivate::filename, filename);
+ setSelectable(false);
+
+ if (filename.isNull() || filename.isEmpty())
+ numberOfBooks = 0;
+ else
+ numberOfBooks = 1;
+ selectedBooks = 0;
+}
+
+CheckBookItem::~CheckBookItem () {
+}
+
+void CheckBookItem::activate() {
+ QListView *lv = listView();
+
+ if ((lv != 0) && (!lv->isEnabled()) || (!isEnabled()))
+ return;
+
+ setOn (!isOn());
+ ignoreDoubleClick();
+}
+
+void CheckBookItem::stateChange (bool on) {
+ QListViewItem *item = firstChild();
+ if (item == 0) {
+ QListViewItem *parent = this->parent();
+ if (parent != 0) {
+ if (on)
+ ((CheckBookItem*)parent)->childChange (0, 1);
+ else
+ ((CheckBookItem*)parent)->childChange (0, -1);
+ }
+ }
+ else propagateStateChange();
+}
+
+void CheckBookItem::propagateStateChange () {
+ QListViewItem *item = firstChild();
+ while (item != 0) {
+ if (isOn() != ((QCheckListItem*)item)->isOn())
+ ((QCheckListItem*)item)->setOn (isOn());
+ else
+ ((CheckBookItem*)item)->propagateStateChange ();
+ item = item->nextSibling();
+ }
+}
+
+void CheckBookItem::childChange (int numberDiff, int selDiff) {
+ numberOfBooks += numberDiff;
+ selectedBooks += selDiff;
+ QListViewItem *parent = this->parent();
+ if (parent != 0)
+ ((CheckBookItem*)parent)->childChange (numberDiff, selDiff);
+
+ QString text = i18n(" (%1 of %2 books selected)");
+ text = text.arg(selectedBooks).arg(numberOfBooks);
+ setText(0, this->text(PhraseBookPrivate::name)+text);
+}
+
+/***************************************************************************/
+
+InitialPhraseBookWidget::InitialPhraseBookWidget (QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ QVBoxLayout *mainLayout = new QVBoxLayout (this, 0, KDialog::spacingHint());
+ QLabel *label = new QLabel (i18n("Please decide which phrase books you need:"), this, "booksTitle");
+ mainLayout->add (label);
+
+ books = new KListView (this, "books");
+ books->setSorting (-1);
+ books->setItemsMovable (false);
+ books->setDragEnabled (false);
+ books->setAcceptDrops (false);
+ books->addColumn (i18n("Book"));
+ books->setRootIsDecorated (true);
+ books->setAllColumnsShowFocus (true);
+ books->setSelectionMode (QListView::Multi);
+ mainLayout->add (books);
+
+ initStandardPhraseBooks();
+}
+
+InitialPhraseBookWidget::~InitialPhraseBookWidget () {
+}
+
+void InitialPhraseBookWidget::initStandardPhraseBooks() {
+ StandardBookList bookPaths = PhraseBookDialog::standardPhraseBooks();
+
+ QListViewItem *parent = 0;
+ QListViewItem *last = 0;
+ QStringList currentNamePath = "";
+ QPtrStack<QListViewItem> stack;
+ StandardBookList::iterator it;
+ for (it = bookPaths.begin(); it != bookPaths.end(); ++it) {
+ QString namePath = (*it).path;
+ QStringList dirs = QStringList::split("/", namePath);
+
+ QStringList::iterator it1=currentNamePath.begin();
+ QStringList::iterator it2=dirs.begin();
+ for (; (it1 != currentNamePath.end())
+ && (it1 != dirs.end()) && (*it1 == *it2); ++it1, ++it2);
+ for (; it1 != currentNamePath.end(); ++it1) {
+ last = parent;
+ parent = stack.pop();
+ }
+ for (; it2 != dirs.end(); ++it2) {
+ stack.push (parent);
+ QListViewItem *newParent;
+ if (parent == 0)
+ newParent = new CheckBookItem (books, last, *it2, *it2, QString::null);
+ else
+ newParent = new CheckBookItem (parent, last, *it2, *it2, QString::null);
+ parent = newParent;
+ last = 0;
+ }
+ currentNamePath = dirs;
+
+ QListViewItem *book;
+ if (parent == 0)
+ book = new CheckBookItem (books, last, (*it).name, (*it).name, (*it).filename);
+ else
+ book = new CheckBookItem (parent, last, (*it).name, (*it).name, (*it).filename);
+ last = book;
+ }
+}
+
+void InitialPhraseBookWidget::createBook () {
+ PhraseBook book;
+ QListViewItem *item = books->firstChild();
+ while (item != 0) {
+ if (item->firstChild() != 0) {
+ item = item->firstChild();
+ }
+ else {
+ if (((QCheckListItem*)item)->isOn()) {
+ PhraseBook localBook;
+ localBook.open(KURL( item->text(PhraseBookPrivate::filename )));
+ book += localBook;
+ }
+
+ while ((item != 0) && (item->nextSibling() == 0)) {
+ item = item->parent();
+ }
+ if (item != 0)
+ item = item->nextSibling();
+ }
+ }
+
+ QString bookLocation = KApplication::kApplication()->dirs()->saveLocation ("appdata", "/");
+ if (!bookLocation.isNull() && !bookLocation.isEmpty()) {
+ book.save (KURL( bookLocation + "standard.phrasebook" ));
+ }
+}
+
+/***************************************************************************/
+
+ButtonBoxWidget::ButtonBoxWidget (QWidget *parent, const char *name)
+: ButtonBoxUI (parent, name) {
+ keyButtonPlaceLayout = new QGridLayout (keyButtonPlace, 1, 1, 0, 0, "keyButtonPlaceLayout");
+
+ keyButton = new KKeyButton (keyButtonPlace, "key");
+ keyButtonPlaceLayout->addWidget (keyButton, 1,1);
+ QWhatsThis::add (keyButton, i18n("By clicking on this button you can select the keyboard shortcut associated with the selected phrase."));
+
+ group = new QButtonGroup (phrasebox);
+ group->hide();
+ group->setExclusive (true);
+ group->insert (noKey);
+ group->insert (customKey);
+}
+
+ButtonBoxWidget::~ButtonBoxWidget () {
+}
+
+/***************************************************************************/
+
+namespace PhraseBookPrivate {
+ PhraseBookDialog *instance = 0;
+}
+
+PhraseBookDialog::PhraseBookDialog ()
+ : KMainWindow (0, "phraseEditDialog")
+{
+ setCaption (i18n("Phrase Book"));
+ initGUI();
+ initActions();
+ initStandardPhraseBooks();
+ QString standardBook = KApplication::kApplication()->dirs()->findResource("appdata", "standard.phrasebook");
+ if (!standardBook.isNull() && !standardBook.isEmpty()) {
+ PhraseBook book;
+ book.open(KURL( standardBook ));
+ treeView->clear();
+ treeView->addBook(0, 0, &book);
+ treeView->setCurrentItem(treeView->firstChild());
+ selectionChanged();
+ phrasebookChanged = false;
+ }
+ // i18n("Edit Phrase Book")
+}
+
+PhraseBookDialog *PhraseBookDialog::get() {
+ if (PhraseBookPrivate::instance == 0)
+ PhraseBookPrivate::instance = new PhraseBookDialog();
+ return PhraseBookPrivate::instance;
+}
+
+PhraseBookDialog::~PhraseBookDialog() {
+ PhraseBookPrivate::instance = 0;
+}
+
+void PhraseBookDialog::initGUI () {
+ QWidget *page = new QWidget( this );
+ setCentralWidget(page);
+ QVBoxLayout *mainLayout = new QVBoxLayout (page, 0);
+
+ treeView = new PhraseTree (page, "phrasetree");
+ treeView->setSorting (-1);
+ treeView->setItemsMovable (true);
+ treeView->setDragEnabled (true);
+ treeView->setAcceptDrops (true);
+ treeView->addColumn (i18n("Phrase"));
+ treeView->addColumn (i18n("Shortcut"));
+ treeView->setRootIsDecorated (true);
+ treeView->setAllColumnsShowFocus (true);
+ treeView->setSelectionMode (QListView::Extended);
+ QWhatsThis::add (treeView, i18n("This list contains the current phrase book in a tree structure. You can select and modify individual phrases and sub phrase books"));
+ connect (treeView, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
+ connect (treeView, SIGNAL(contextMenuRequested (QListViewItem *, const QPoint &, int)), this, SLOT(contextMenuRequested (QListViewItem *, const QPoint &, int)));
+ connect (treeView, SIGNAL(dropped (QDropEvent *, QListViewItem *, QListViewItem *)), this, SLOT(slotDropped (QDropEvent *, QListViewItem *, QListViewItem *)));
+ connect (treeView, SIGNAL(moved (QListViewItem *, QListViewItem *, QListViewItem *)), this, SLOT(slotMoved (QListViewItem *, QListViewItem *, QListViewItem *)));
+ mainLayout->addWidget (treeView);
+
+ buttonBox = new ButtonBoxWidget (page, "buttonbox");
+ connect (buttonBox->lineEdit, SIGNAL(textChanged(const QString &)), SLOT(slotTextChanged(const QString &)));
+ connect (buttonBox->noKey, SIGNAL(clicked()), SLOT(slotNoKey()));
+ connect (buttonBox->customKey, SIGNAL(clicked()), SLOT(slotCustomKey()));
+ connect (buttonBox->keyButton, SIGNAL(capturedShortcut(const KShortcut&)), SLOT(capturedShortcut(const KShortcut&)));
+ mainLayout->addWidget (buttonBox);
+
+ treeView->setFocus();
+ selectionChanged();
+}
+
+void PhraseBookDialog::initActions() {
+// The file menu
+ fileNewPhrase = new KAction (i18n("&New Phrase"), "phrase_new", 0, this, SLOT(slotAddPhrase()), actionCollection(),"file_new_phrase");
+ fileNewPhrase->setStatusText(i18n("Adds a new phrase"));
+ fileNewPhrase->setWhatsThis (i18n("Adds a new phrase"));
+
+ fileNewBook = new KAction (i18n("New Phrase &Book"), "phrasebook_new", 0, this, SLOT(slotAddPhrasebook()), actionCollection(),"file_new_book");
+ fileNewBook->setStatusText(i18n("Adds a new phrase book into which other books and phrases can be placed"));
+ fileNewBook->setWhatsThis (i18n("Adds a new phrase book into which other books and phrases can be placed"));
+
+ fileSave = KStdAction::save(this, SLOT(slotSave()), actionCollection());
+ fileSave->setStatusText(i18n("Saves the phrase book onto the hard disk"));
+ fileSave->setWhatsThis (i18n("Saves the phrase book onto the hard disk"));
+
+ fileImport = new KAction (i18n("&Import..."), "phrasebook_open", 0, this, SLOT(slotImportPhrasebook()), actionCollection(),"file_import");
+ fileImport->setStatusText(i18n("Imports a file and adds its contents to the phrase book"));
+ fileImport->setWhatsThis (i18n("Imports a file and adds its contents to the phrase book"));
+
+ toolbarImport = new KToolBarPopupAction (i18n("&Import..."), "phrasebook_open", 0, this, SLOT(slotImportPhrasebook()), actionCollection(),"toolbar_import");
+ toolbarImport->setStatusText(i18n("Imports a file and adds its contents to the phrase book"));
+ toolbarImport->setWhatsThis (i18n("Imports a file and adds its contents to the phrase book"));
+
+ fileImportStandardBook = new KActionMenu (i18n("I&mport Standard Phrase Book"), "phrasebook_open", actionCollection(),"file_import_standard_book");
+ fileImportStandardBook->setStatusText(i18n("Imports a standard phrase book and adds its contents to the phrase book"));
+ fileImportStandardBook->setWhatsThis (i18n("Imports a standard phrase book and adds its contents to the phrase book"));
+
+ fileExport = new KAction (i18n("&Export..."), "phrasebook_save", 0, this, SLOT(slotExportPhrasebook()), actionCollection(),"file_export");
+ fileExport->setStatusText(i18n("Exports the currently selected phrase(s) or phrase book(s) into a file"));
+ fileExport->setWhatsThis (i18n("Exports the currently selected phrase(s) or phrase book(s) into a file"));
+
+ filePrint = KStdAction::print(this, SLOT(slotPrint()), actionCollection());
+ filePrint->setStatusText(i18n("Prints the currently selected phrase(s) or phrase book(s)"));
+ filePrint->setWhatsThis (i18n("Prints the currently selected phrase(s) or phrase book(s)"));
+
+ fileClose = KStdAction::close(this, SLOT(close()), actionCollection());
+ fileClose->setStatusText(i18n("Closes the window"));
+ fileClose->setWhatsThis (i18n("Closes the window"));
+
+// The edit menu
+ editCut = KStdAction::cut(this, SLOT(slotCut()), actionCollection());
+ editCut->setStatusText(i18n("Cuts the currently selected entries from the phrase book and puts it to the clipboard"));
+ editCut->setWhatsThis (i18n("Cuts the currently selected entries from the phrase book and puts it to the clipboard"));
+
+ editCopy = KStdAction::copy(this, SLOT(slotCopy()), actionCollection());
+ editCopy->setStatusText(i18n("Copies the currently selected entry from the phrase book to the clipboard"));
+ editCopy->setWhatsThis (i18n("Copies the currently selected entry from the phrase book to the clipboard"));
+
+ editPaste = KStdAction::paste(this, SLOT(slotPaste()), actionCollection());
+ editPaste->setStatusText(i18n("Pastes the clipboard contents to actual position"));
+ editPaste->setWhatsThis (i18n("Pastes the clipboard contents to actual position"));
+
+ editDelete = new KAction (i18n("&Delete"), "editdelete", 0, this, SLOT(slotRemove()), actionCollection(),"edit_delete");
+ editDelete->setStatusText(i18n("Deletes the selected entries from the phrase book"));
+ editDelete->setWhatsThis (i18n("Deletes the selected entries from the phrase book"));
+
+ // use the absolute path to your kmouthui.rc file for testing purpose in createGUI();
+ createGUI("phrasebookdialogui.rc");
+}
+
+QString PhraseBookDialog::displayPath (QString filename) {
+ QFileInfo file(filename);
+ QString path = file.dirPath();
+ QString dispPath = "";
+ uint position = path.find("/kmouth/books/")+QString("/kmouth/books/").length();
+
+ while (path.length() > position) {
+ file.setFile(path);
+
+ KDesktopFile *dirDesc = new KDesktopFile(path+"/.directory", true, "data");
+ QString name = dirDesc->readName();
+ delete dirDesc;
+
+ if (name.isNull() || name.isEmpty())
+ dispPath += "/" + file.fileName ();
+ else
+ dispPath += "/" + name;
+
+ path = file.dirPath();
+ }
+ return dispPath;
+}
+
+StandardBookList PhraseBookDialog::standardPhraseBooks() {
+ QStringList bookPaths = KGlobal::instance()->dirs()->findAllResources (
+ "data", "kmouth/books/*.phrasebook", true, true);
+ QStringList bookNames;
+ QMap<QString,StandardBook> bookMap;
+ QStringList::iterator it;
+ for (it = bookPaths.begin(); it != bookPaths.end(); ++it) {
+ PhraseBook pbook;
+ if (pbook.open (KURL( *it ))) {
+ StandardBook book;
+ book.name = (*pbook.begin()).getPhrase().getPhrase();
+
+ book.path = displayPath(*it);
+ book.filename = *it;
+
+ bookNames += book.path + "/" + book.name;
+ bookMap [book.path + "/" + book.name] = book;
+ }
+ }
+
+ bookNames.sort();
+
+ StandardBookList result;
+ for (it = bookNames.begin(); it != bookNames.end(); ++it)
+ result += bookMap [*it];
+
+ return result;
+}
+
+void PhraseBookDialog::initStandardPhraseBooks () {
+ StandardBookList bookPaths = standardPhraseBooks();
+
+ KActionMenu *parent = fileImportStandardBook;
+ QStringList currentNamePath = "x";
+ QPtrStack<KActionMenu> stack;
+ StandardBookList::iterator it;
+ for (it = bookPaths.begin(); it != bookPaths.end(); ++it) {
+ KURL url;
+ url.setPath((*it).filename);
+
+ QString namePath = "x/"+(*it).path;
+ QStringList dirs = QStringList::split("/", namePath);
+
+ QStringList::iterator it1=currentNamePath.begin();
+ QStringList::iterator it2=dirs.begin();
+ for (; (it1 != currentNamePath.end())
+ && (it1 != dirs.end()) && (*it1 == *it2); ++it1, ++it2);
+ for (; it1 != currentNamePath.end(); ++it1)
+ parent = stack.pop();
+ for (; it2 != dirs.end(); ++it2) {
+ stack.push (parent);
+ KActionMenu *newParent = new KActionMenu (*it2);
+ parent->insert(newParent);
+ if (parent == fileImportStandardBook)
+ newParent->plug(toolbarImport->popupMenu());
+ parent = newParent;
+ }
+ currentNamePath = dirs;
+
+ KAction *book = new StandardPhraseBookInsertAction (
+ url, (*it).name, this, SLOT(slotImportPhrasebook (const KURL &)), actionCollection());
+ parent->insert(book);
+ if (parent == fileImportStandardBook)
+ book->plug(toolbarImport->popupMenu());
+ }
+}
+
+PhraseTreeItem *selectedItem (QListView *treeView) {
+ PhraseTreeItem *currentItem = (PhraseTreeItem *)treeView->currentItem();
+ if ((currentItem == 0) || (!currentItem->isSelected()))
+ return 0;
+
+ QListViewItemIterator it(treeView);
+ while (it.current()) {
+ QListViewItem *item = it.current();
+ if (item->isSelected() && (item != currentItem))
+ return 0;
+ ++it;
+ }
+ return currentItem;
+}
+
+void PhraseBookDialog::selectionChanged () {
+ bool modified = phrasebookChanged;
+ PhraseTreeItem *currentItem = selectedItem (treeView);
+ if (currentItem == 0) {
+ buttonBox->textLabel->setText (i18n("Text of the &phrase:"));
+ buttonBox->textLabel->setEnabled(false);
+ buttonBox->group->setEnabled(false);
+ buttonBox->lineEdit->setText("");
+ buttonBox->lineEdit->setEnabled(false);
+ buttonBox->shortcutLabel->setEnabled(false);
+ buttonBox->keyButton->setShortcut("", false);
+ buttonBox->keyButton->setEnabled(false);
+ buttonBox->noKey->setChecked (false);
+ buttonBox->noKey->setEnabled (false);
+ buttonBox->customKey->setChecked (false);
+ buttonBox->customKey->setEnabled (false);
+ }
+ else if (currentItem->isPhrase()) {
+ buttonBox->textLabel->setText (i18n("Text of the &phrase:"));
+ buttonBox->textLabel->setEnabled(true);
+ buttonBox->group->setEnabled(true);
+ buttonBox->lineEdit->setText(currentItem->text(0));
+ buttonBox->lineEdit->setEnabled(true);
+ buttonBox->shortcutLabel->setEnabled(true);
+ QString shortcut = currentItem->text(1);
+ buttonBox->keyButton->setShortcut(currentItem->cut(), false);
+ if (shortcut.isEmpty() || shortcut.isNull()) {
+ buttonBox->noKey->setChecked (true);
+ buttonBox->customKey->setChecked (false);
+ }
+ else {
+ buttonBox->noKey->setChecked (false);
+ buttonBox->customKey->setChecked (true);
+ }
+ buttonBox->keyButton->setEnabled(true);
+ buttonBox->noKey->setEnabled(true);
+ buttonBox->customKey->setEnabled(true);
+ }
+ else {
+ buttonBox->textLabel->setText (i18n("Name of the &phrase book:"));
+ buttonBox->textLabel->setEnabled(true);
+ buttonBox->group->setEnabled(true);
+ buttonBox->lineEdit->setText(currentItem->text(0));
+ buttonBox->lineEdit->setEnabled(true);
+ buttonBox->shortcutLabel->setEnabled(false);
+ buttonBox->keyButton->setShortcut("", false);
+ buttonBox->keyButton->setEnabled(false);
+ buttonBox->noKey->setChecked (false);
+ buttonBox->noKey->setEnabled (false);
+ buttonBox->customKey->setChecked (false);
+ buttonBox->customKey->setEnabled (false);
+ }
+ phrasebookChanged = modified;
+}
+
+bool PhraseBookDialog::queryClose() {
+ if (phrasebookChanged) {
+ int answer = KMessageBox::questionYesNoCancel (this,
+ i18n("<qt>There are unsaved changes.<br>Do you want to apply the changes before closing the \"phrase book\" window or discard the changes?</qt>"),
+ i18n("Closing \"Phrase Book\" Window"),
+ KStdGuiItem::apply(), KStdGuiItem::discard(), "AutomaticSave");
+ if (answer == KMessageBox::Yes) {
+ slotSave();
+ return true;
+ }
+ return (answer == KMessageBox::No);
+ }
+ return true;
+}
+
+void PhraseBookDialog::slotTextChanged (const QString &s) {
+ PhraseTreeItem *currentItem = selectedItem (treeView);
+ if (currentItem != 0)
+ currentItem->setText(0, s);
+ phrasebookChanged = true;
+}
+
+void PhraseBookDialog::slotNoKey() {
+ buttonBox->noKey->setChecked (true);
+ buttonBox->customKey->setChecked (false);
+
+ PhraseTreeItem *currentItem = selectedItem (treeView);
+ if (currentItem != 0) {
+ currentItem->setCut (KShortcut(QString::null));
+ buttonBox->keyButton->setShortcut(currentItem->cut(), false);
+ }
+ phrasebookChanged = true;
+}
+
+void PhraseBookDialog::slotCustomKey() {
+ buttonBox->keyButton->captureShortcut();
+}
+
+void PhraseBookDialog::capturedShortcut (const KShortcut& cut) {
+ if (cut.isNull()) {
+ slotNoKey();
+ }
+ else
+ setShortcut (cut);
+ phrasebookChanged = true;
+}
+
+void PhraseBookDialog::setShortcut( const KShortcut& cut ) {
+ // Check whether the shortcut is valid
+ for (uint i = 0; i < cut.count(); i++) {
+ const KKeySequence& seq = cut.seq(i);
+ const KKey& key = seq.key(0);
+
+ if (key.modFlags() == 0 && key.sym() < 0x3000
+ && QChar(key.sym()).isLetterOrNumber())
+ {
+ QString s = i18n("In order to use the '%1' key as a shortcut, "
+ "it must be combined with the "
+ "Win, Alt, Ctrl, and/or Shift keys.").arg(QChar(key.sym()));
+ KMessageBox::sorry( this, s, i18n("Invalid Shortcut Key") );
+ return;
+ }
+ }
+
+ PhraseTreeItem *currentItem = selectedItem (treeView);
+ // If key isn't already in use,
+ if (!treeView->isKeyPresent (cut, currentItem, true)) {
+ // Set new key code
+ currentItem->setCut (cut);
+ // Update display
+ buttonBox->noKey->setChecked (false);
+ buttonBox->customKey->setChecked (true);
+ buttonBox->keyButton->setShortcut(currentItem->cut(), false);
+ }
+}
+
+QListViewItem *PhraseBookDialog::addBook (QListViewItem *parent, QListViewItem *after, PhraseBook *book) {
+ QListViewItem *newItem = treeView->addBook(parent, after, book);
+ if (newItem != 0) {
+ treeView->clearSelection();
+ treeView->ensureItemVisible(newItem);
+ treeView->setCurrentItem (newItem);
+ treeView->setSelected (newItem, true);
+ phrasebookChanged = true;
+ }
+ return newItem;
+}
+
+QListViewItem *PhraseBookDialog::addBook (QListViewItem *item, PhraseBook *book) {
+ if (item == 0)
+ return addBook(0, 0, book);
+ else if (((PhraseTreeItem *)item)->isPhrase() || !item->isOpen())
+ if (item->parent() != 0)
+ return addBook(item->parent(), item, book);
+ else
+ return addBook(0, item, book);
+ else
+ return addBook(item, 0, book);
+}
+
+void PhraseBookDialog::contextMenuRequested(QListViewItem *, const QPoint &pos, int) {
+ QString name;
+ if (treeView->hasSelectedItems())
+ name = "phrasebook_popup_sel";
+ else
+ name = "phrasebook_popup_nosel";
+
+ QPopupMenu *popup = (QPopupMenu *)factory()->container(name,this);
+ if (popup != 0) {
+ popup->popup(pos, 0);
+ }
+}
+
+void PhraseBookDialog::slotRemove () {
+ if (treeView->hasSelectedItems() != 0)
+ treeView->deleteSelectedItems();
+ selectionChanged();
+ phrasebookChanged = true;
+}
+
+void PhraseBookDialog::slotCut () {
+ slotCopy();
+ slotRemove();
+}
+
+void PhraseBookDialog::slotCopy () {
+ PhraseBook book;
+ treeView->fillBook (&book, true);
+ QApplication::clipboard()->setData(new PhraseBookDrag(&book));
+}
+
+void PhraseBookDialog::slotPaste () {
+ PhraseBook book;
+ if (PhraseBookDrag::decode(QApplication::clipboard()->data(), &book)) {
+ addBook (treeView->currentItem(), &book);
+ }
+}
+
+void PhraseBookDialog::slotDropped (QDropEvent *e, QListViewItem *parent, QListViewItem *after) {
+ PhraseBook book;
+ if (PhraseBookDrag::decode(e, &book)) {
+ addBook(parent, after, &book);
+ }
+}
+
+void PhraseBookDialog::slotMoved (QListViewItem *item, QListViewItem *, QListViewItem *) {
+ treeView->ensureItemVisible(item);
+ treeView->setSelected (item, true);
+ phrasebookChanged = true;
+}
+
+void PhraseBookDialog::slotAddPhrasebook () {
+ PhraseBook book;
+ Phrase phrase(i18n("(New Phrase Book)"), "");
+ book += PhraseBookEntry(phrase, 0, false);
+
+ QListViewItem *item = addBook (treeView->currentItem(), &book);
+ item->setOpen (true);
+ buttonBox->lineEdit->selectAll();
+ buttonBox->lineEdit->setFocus();
+}
+
+void PhraseBookDialog::slotAddPhrase () {
+ PhraseBook book;
+ Phrase phrase(i18n("(New Phrase)"), "");
+ book += PhraseBookEntry(phrase, 0, true);
+
+ addBook (treeView->currentItem(), &book);
+ buttonBox->lineEdit->selectAll();
+ buttonBox->lineEdit->setFocus();
+}
+
+void PhraseBookDialog::slotSave () {
+ book.clear();
+ treeView->fillBook (&book, false);
+ emit phrasebookConfirmed (book);
+ phrasebookChanged = false;
+}
+
+void PhraseBookDialog::slotImportPhrasebook () {
+ KURL url=KFileDialog::getOpenURL(QString::null,
+ i18n("*.phrasebook|Phrase Books (*.phrasebook)\n*.txt|Plain Text Files (*.txt)\n*|All Files"), this, i18n("Import Phrasebook"));
+
+ slotImportPhrasebook (url);
+}
+
+void PhraseBookDialog::slotImportPhrasebook (const KURL &url) {
+ if(!url.isEmpty()) {
+ PhraseBook book;
+ if (book.open (url))
+ addBook(treeView->currentItem(), &book);
+ else
+ KMessageBox::sorry(this,i18n("There was an error loading file\n%1").arg( url.url() ));
+ }
+}
+
+void PhraseBookDialog::slotExportPhrasebook () {
+ PhraseBook book;
+ treeView->fillBook (&book, treeView->hasSelectedItems());
+
+ KURL url;
+ if (book.save (this, i18n("Export Phrase Book"), url) == -1)
+ KMessageBox::sorry(this,i18n("There was an error saving file\n%1").arg( url.url() ));
+}
+
+void PhraseBookDialog::slotPrint()
+{
+ KPrinter printer;
+ if (printer.setup(this)) {
+ PhraseBook book;
+ treeView->fillBook (&book, treeView->hasSelectedItems());
+
+ book.print(&printer);
+ }
+}
+
+#include "phrasebookdialog.moc"
diff --git a/kmouth/phrasebook/phrasebookdialog.h b/kmouth/phrasebook/phrasebookdialog.h
new file mode 100644
index 0000000..774387f
--- /dev/null
+++ b/kmouth/phrasebook/phrasebookdialog.h
@@ -0,0 +1,234 @@
+/***************************************************************************
+ phrasebookdialog.h - description
+ -------------------
+ begin : Don Sep 19 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PHRASEBOOKDIALOG_H
+#define PHRASEBOOKDIALOG_H
+
+#include <qbutton.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlabel.h>
+#include <qlistview.h>
+#include <kmainwindow.h>
+#include <klineedit.h>
+#include <kkeybutton.h>
+#include <kurl.h>
+#include "phrasebook.h"
+#include "buttonboxui.h"
+
+class QListViewItem;
+class PhraseTreeItem;
+class PhraseTree;
+class QStringList;
+class QString;
+class KListView;
+
+struct StandardBook {
+ QString name;
+ QString path;
+ QString filename;
+};
+typedef QValueList<StandardBook> StandardBookList;
+
+/**The class PhraseTreeItem is an ListViewItem for either a phrase or a phrase book.
+ *@author Gunnar Schmi Dt
+ */
+
+class CheckBookItem : public QCheckListItem {
+public:
+ CheckBookItem (QListViewItem *parent, QListViewItem *last,
+ const QString &text, const QString &name, const QString &filename);
+ CheckBookItem (QListView *parent, QListViewItem *last,
+ const QString &text, const QString &name, const QString &filename);
+ ~CheckBookItem();
+
+protected:
+ virtual void activate ();
+ virtual void stateChange (bool);
+ virtual void propagateStateChange ();
+ virtual void childChange (int numberDiff, int selDiff);
+
+private:
+ int numberOfBooks;
+ int selectedBooks;
+};
+
+/**
+ * This class represents a widget for configuring the initial phrasebook.
+ * @author Gunnar Schmi Dt
+ */
+
+class InitialPhraseBookWidget : public QWidget {
+ Q_OBJECT
+public:
+ InitialPhraseBookWidget(QWidget *parent, const char *name);
+ ~InitialPhraseBookWidget();
+
+ void createBook();
+
+private:
+ /** initializes the list of standard phrase books */
+ void initStandardPhraseBooks ();
+
+ KListView *books;
+};
+
+/**
+ * The class StandardPhraseBookInsertAction implements an Action for
+ * inserting a standard phrase book.
+ * @author Gunnar Schmi Dt
+ */
+class StandardPhraseBookInsertAction : public KAction {
+ Q_OBJECT
+public:
+ StandardPhraseBookInsertAction (const KURL &url, const QString& name, const QObject* receiver, const char* slot, KActionCollection* parent)
+ : KAction (name, "phrasebook", 0, 0, 0, parent, 0) {
+ this->url = url;
+ connect (this, SIGNAL(slotActivated (const KURL &)), receiver, slot);
+ };
+ ~StandardPhraseBookInsertAction () {
+ };
+
+public slots:
+ void slotActivated () {
+ KAction::slotActivated();
+ emit slotActivated (url);
+ };
+
+signals:
+ void slotActivated (const KURL &url);
+
+private:
+ KURL url;
+};
+
+/**
+ * This class represents a widget holding the buttons of the phrase book
+ * edit window.
+ * @author Gunnar Schmi Dt
+ */
+class ButtonBoxWidget : public ButtonBoxUI {
+public:
+ ButtonBoxWidget (QWidget *parent = 0, const char *name = 0);
+ ~ButtonBoxWidget ();
+
+ KKeyButton *keyButton;
+ QButtonGroup *group;
+
+protected:
+ QGridLayout *keyButtonPlaceLayout;
+};
+
+/**
+ * The class PhraseBookDialog implements a dialog for editing phrase books.
+ * @author Gunnar Schmi Dt
+ */
+
+class PhraseBookDialog : public KMainWindow {
+ friend class InitialPhraseBookWidget;
+ Q_OBJECT
+private:
+ /** Constructor. It is private because this class implements the singleton
+ * pattern. For creating the instance of the dialog, use the get() method.
+ */
+ PhraseBookDialog ();
+
+ static QString displayPath (QString path);
+
+public:
+ /** Returns a pointer to the instance of this dialog. As a part off the
+ * singleton pattern it will make sure that there is at most one instance
+ * of the dialog at a given time.
+ */
+ static PhraseBookDialog *get();
+
+ /** Destructor. */
+ ~PhraseBookDialog();
+
+ bool queryClose ();
+
+public slots:
+ void slotTextChanged (const QString &s);
+ void slotNoKey();
+ void slotCustomKey();
+ void capturedShortcut (const KShortcut& cut);
+
+ void selectionChanged ();
+ void contextMenuRequested(QListViewItem *, const QPoint &pos, int);
+
+ void slotRemove ();
+ void slotCut ();
+ void slotCopy ();
+ void slotPaste ();
+
+ void slotAddPhrasebook ();
+ void slotAddPhrase ();
+
+ void slotSave ();
+ void slotImportPhrasebook ();
+ void slotImportPhrasebook (const KURL &url);
+ void slotExportPhrasebook ();
+ void slotPrint ();
+
+ void slotDropped (QDropEvent *e, QListViewItem *parent, QListViewItem *after);
+ void slotMoved (QListViewItem *item, QListViewItem *, QListViewItem *);
+
+signals:
+ void phrasebookConfirmed (PhraseBook &book);
+
+private:
+ static StandardBookList standardPhraseBooks ();
+
+ void initGUI();
+ /** initializes the KActions of the window */
+ void initActions();
+ /** initializes the list of standard phrase books */
+ void initStandardPhraseBooks ();
+
+ QListViewItem *addBook (QListViewItem *parent, QListViewItem *after, PhraseBook *book);
+ QListViewItem *addBook (QListViewItem *item, PhraseBook *book);
+
+ void setShortcut (const KShortcut &cut);
+
+ void _warning (const KKeySequence &cut, QString sAction, QString sTitle);
+
+ bool isGlobalKeyPresent (const KShortcut& cut, bool warnUser);
+ bool isPhraseKeyPresent (const KShortcut& cut, bool warnUser);
+ bool isKeyPresent (const KShortcut& cut, bool warnUser);
+
+ PhraseBook book;
+ bool phrasebookChanged;
+
+ PhraseTree *treeView;
+ ButtonBoxWidget *buttonBox;
+
+ KAction* fileNewPhrase;
+ KAction* fileNewBook;
+ KAction* fileSave;
+ KAction* fileImport;
+ KToolBarPopupAction* toolbarImport;
+ KActionMenu* fileImportStandardBook;
+ KAction* fileExport;
+ KAction* filePrint;
+ KAction* fileClose;
+ KAction* editCut;
+ KAction* editCopy;
+ KAction* editPaste;
+ KAction* editDelete;
+};
+
+#endif
diff --git a/kmouth/phrasebook/phrasebookdialogui.rc b/kmouth/phrasebook/phrasebookdialogui.rc
new file mode 100644
index 0000000..c5150fe
--- /dev/null
+++ b/kmouth/phrasebook/phrasebookdialogui.rc
@@ -0,0 +1,64 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kmouth" version="1">
+
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <Action name="file_new_phrase"/>
+ <Action name="file_new_book"/>
+ <Separator />
+ <Action name="file_save"/>
+ <Separator />
+ <Action name="file_import"/>
+ <Action name="file_import_standard_book"/>
+ <Action name="file_export"/>
+ <Separator />
+ <Action name="file_print"/>
+ <Separator />
+ <Action name="file_close"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_delete"/>
+ </Menu>
+</MenuBar>
+
+<Menu name="phrasebook_popup_nosel" noMerge="1">
+ <Action name="file_new_phrase"/>
+ <Action name="file_new_book"/>
+ <Separator />
+ <Action name="file_import"/>
+ <Action name="file_import_standard_book"/>
+ <Action name="file_export"/>
+ <Separator />
+ <Action name="edit_paste"/>
+</Menu>
+
+<Menu name="phrasebook_popup_sel" noMerge="1">
+ <Action name="file_new_phrase"/>
+ <Action name="file_new_book"/>
+ <Separator />
+ <Action name="file_import"/>
+ <Action name="file_import_standard_book"/>
+ <Action name="file_export"/>
+ <Separator />
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Separator />
+ <Action name="edit_delete"/>
+</Menu>
+
+<ToolBar name="mainToolBar" noMerge="1">
+ <Action name="file_new_phrase"/>
+ <Action name="file_new_book"/>
+ <Action name="file_save"/>
+ <Action name="toolbar_import"/>
+ <Action name="file_export"/>
+ <Action name="file_print"/>
+ <Separator />
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+</ToolBar>
+
+</kpartgui>
diff --git a/kmouth/phrasebook/phrasebookparser.cpp b/kmouth/phrasebook/phrasebookparser.cpp
new file mode 100644
index 0000000..9883e49
--- /dev/null
+++ b/kmouth/phrasebook/phrasebookparser.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ phrasebookparser.cpp - description
+ -------------------
+ begin : Don Sep 12 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "phrasebookparser.h"
+
+PhraseBookParser::PhraseBookParser() {
+}
+
+PhraseBookParser::~PhraseBookParser() {
+}
+
+bool PhraseBookParser::warning (const QXmlParseException &) {
+ return false;
+}
+
+bool PhraseBookParser::error (const QXmlParseException &) {
+ return false;
+}
+
+bool PhraseBookParser::fatalError (const QXmlParseException &) {
+ return false;
+}
+
+QString PhraseBookParser::errorString() {
+ return "";
+}
+
+bool PhraseBookParser::startDocument() {
+ list.clear ();
+ isInPhrase = false;
+ level = 0;
+ offset = 0;
+ starting = true;
+ return true;
+}
+
+bool PhraseBookParser::startElement (const QString &, const QString &,
+ const QString &name,
+ const QXmlAttributes &attributes)
+{
+ if (name == "phrase") {
+ if (isInPhrase)
+ return false;
+
+ phrase.phrase = "";
+ phrase.shortcut = attributes.value("shortcut");
+ isInPhrase = true;
+ }
+ else if (name == "phrasebook") {
+ if (isInPhrase)
+ return false;
+
+ phrase.phrase = attributes.value("name");
+ phrase.shortcut = "";
+ if ((phrase.phrase.isNull() || phrase.phrase.isEmpty()) && starting)
+ offset = -1;
+ else {
+ list += PhraseBookEntry (phrase, level, false);
+ level++;
+ }
+ starting = false;
+ }
+ return true;
+}
+
+bool PhraseBookParser::characters (const QString &ch) {
+ phrase.phrase += ch;
+ return true;
+}
+
+bool PhraseBookParser::ignorableWhitespace (const QString &ch) {
+ phrase.phrase += ch;
+ return true;
+}
+
+bool PhraseBookParser::endElement (const QString &, const QString &,
+ const QString &name)
+{
+ if (name == "phrase") {
+ list += PhraseBookEntry (phrase, level, true);
+ isInPhrase = false;
+ }
+ else if (name == "phrasebook") {
+ if (level == offset)
+ return false;
+
+ level--;
+ }
+ return true;
+}
+
+bool PhraseBookParser::endDocument() {
+ return (level == offset);
+}
+
+PhraseBookEntryList PhraseBookParser::getPhraseList() {
+ return list;
+}
diff --git a/kmouth/phrasebook/phrasebookparser.h b/kmouth/phrasebook/phrasebookparser.h
new file mode 100644
index 0000000..a6e436a
--- /dev/null
+++ b/kmouth/phrasebook/phrasebookparser.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ phrasebookparser.h - description
+ -------------------
+ begin : Don Sep 12 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PHRASEBOOKPARSER_H
+#define PHRASEBOOKPARSER_H
+
+#include <qxml.h>
+#include <qvaluestack.h>
+#include "phrasebook.h"
+
+/**
+ * This class implements a parser for both the phrase list and for phrase
+ * books. It is intended to be used together with the Qt SAX2 framework.
+ * @author Gunnar Schmi Dt
+ */
+
+class PhraseBookParser : public QXmlDefaultHandler {
+public:
+ PhraseBookParser();
+ ~PhraseBookParser();
+
+ bool warning (const QXmlParseException &exception);
+ bool error (const QXmlParseException &exception);
+ bool fatalError (const QXmlParseException &exception);
+ QString errorString();
+
+ /** Processes the start of the document. */
+ bool startDocument();
+
+ /** Processes the start tag of an element. */
+ bool startElement (const QString &, const QString &, const QString &name,
+ const QXmlAttributes &attributes);
+
+ /** Processes a chunk of normal character data. */
+ bool characters (const QString &ch);
+
+ /** Processes whitespace. */
+ bool ignorableWhitespace (const QString &ch);
+
+ /** Processes the end tag of an element. */
+ bool endElement (const QString &, const QString &, const QString &name);
+
+ /** Processes the end of the document. */
+ bool endDocument();
+
+ /** returns a list of phrase book entries */
+ PhraseBookEntryList getPhraseList();
+
+private:
+ bool isInPhrase;
+ bool starting;
+ int offset;
+ Phrase phrase;
+
+ PhraseBookEntryList list;
+ int level;
+};
+
+#endif
diff --git a/kmouth/phrasebook/phrasetree.cpp b/kmouth/phrasebook/phrasetree.cpp
new file mode 100644
index 0000000..57d4f5e
--- /dev/null
+++ b/kmouth/phrasebook/phrasetree.cpp
@@ -0,0 +1,556 @@
+/***************************************************************************
+ phrasetree.cpp - description
+ -------------------
+ begin : Don Okt 24 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kstdaccel.h>
+#include <kshortcutlist.h>
+#include <kactionshortcutlist.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#include "phrasetree.h"
+#include "phrasebookdialog.h"
+#include "phrasebook.h"
+
+PhraseTreeItem::PhraseTreeItem (QListView *parent, QListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon)
+ : KListViewItem (parent, after, phrase)
+{
+ isPhraseValue = true;
+ cutValue = shortcut;
+ setText(1, cutValue.toString());
+ setPixmap(0, icon);
+ setExpandable (false);
+}
+
+PhraseTreeItem::PhraseTreeItem (QListViewItem *parent, QListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon)
+ : KListViewItem (parent, after, phrase)
+{
+ isPhraseValue = true;
+ cutValue = shortcut;
+ setText(1, cutValue.toString());
+ setPixmap(0, icon);
+ setExpandable (false);
+}
+PhraseTreeItem::PhraseTreeItem (QListView *parent, QListViewItem *after, QString name, QPixmap icon)
+ : KListViewItem (parent, after, name)
+{
+ isPhraseValue = false;
+ setPixmap(0, icon);
+ setExpandable (true);
+}
+PhraseTreeItem::PhraseTreeItem (QListViewItem *parent, QListViewItem *after, QString name, QPixmap icon)
+ : KListViewItem (parent, after, name)
+{
+ isPhraseValue = false;
+ setPixmap(0, icon);
+ setExpandable (true);
+}
+bool PhraseTreeItem::isPhrase () {
+ return isPhraseValue;
+}
+KShortcut PhraseTreeItem::cut () {
+ return cutValue;
+}
+void PhraseTreeItem::setCut (KShortcut cut) {
+ cutValue = cut;
+ setText(1, cut.toString());
+}
+
+// ***************************************************************************
+
+PhraseTree::PhraseTree (QWidget *parent, const char *name)
+ : KListView (parent, name)
+{
+ phrasebook_open = KGlobal::iconLoader()->loadIcon("phrasebook", KIcon::Small);
+ phrasebook_closed = KGlobal::iconLoader()->loadIcon("phrasebook_closed", KIcon::Small);
+ phrase = KGlobal::iconLoader()->loadIcon("phrase", KIcon::Small);
+
+ connect (this, SIGNAL(expanded (QListViewItem *)), this, SLOT(itemExpanded (QListViewItem *)));
+ connect (this, SIGNAL(collapsed (QListViewItem *)), this, SLOT(itemCollapsed (QListViewItem *)));
+}
+
+PhraseTree::~PhraseTree (){
+}
+
+namespace PhraseTreePrivate {
+ QListViewItem *prevSibling (QListViewItem *item) {
+ QListViewItem *parent = item->parent();
+ QListViewItem *above = item->itemAbove();
+
+ if (above == parent)
+ return 0;
+
+ while (above->parent() != parent)
+ above = above->parent();
+
+ return above;
+ }
+
+ bool findAbovePosition (QListViewItem *item,
+ QListViewItem **newParent,
+ QListViewItem **newAbove)
+ {
+ if (item == 0)
+ return false;
+
+ QListViewItem *parent = item->parent();
+ QListViewItem *above = item->itemAbove();
+
+ if (above == 0)
+ return false;
+ else if (above == parent) {
+ *newParent = parent->parent();
+ *newAbove = prevSibling (parent);
+ return true;
+ }
+ else if (above->parent() == parent) {
+ *newParent = parent;
+ *newAbove = prevSibling (above);
+ return true;
+ }
+ else {
+ while (above->parent()->parent() != parent)
+ above = above->parent();
+ *newParent = above->parent();
+ *newAbove = above;
+ return true;
+ }
+ }
+
+ bool findBelowPosition (QListViewItem *item,
+ QListViewItem **newParent,
+ QListViewItem **newAbove)
+ {
+ if (item == 0)
+ return false;
+
+ QListViewItem *parent = item->parent();
+ QListViewItem *below = item->nextSibling();
+
+ if (parent == 0 && below == 0)
+ return false;
+ else if (parent != 0 && below == 0) {
+ *newParent = parent->parent();
+ *newAbove = parent;
+ return true;
+ }
+ else if (below->isOpen()) {
+ *newParent = below;
+ *newAbove = 0;
+ return true;
+ }
+ else {
+ *newParent = parent;
+ *newAbove = below;
+ return true;
+ }
+ }
+
+ bool findRightPosition (QListViewItem *item,
+ QListViewItem **newParent,
+ QListViewItem **newAbove)
+ {
+ if (item == 0)
+ return false;
+
+ QListViewItem *above = prevSibling (item);
+
+ if (above == 0)
+ return false;
+ else if (((PhraseTreeItem *)above)->isPhrase())
+ return false;
+ else {
+ above->setOpen(true);
+ *newParent = above;
+ *newAbove = 0;
+ above = (*newParent)->firstChild();
+ while (above != 0) {
+ *newAbove = above;
+ above = above->nextSibling();
+ }
+ return true;
+ }
+ }
+
+ bool findLeftPosition (QListViewItem *item,
+ QListViewItem **newParent,
+ QListViewItem **newAbove)
+ {
+ if (item == 0)
+ return false;
+
+ QListViewItem *parent = item->parent();
+
+ if (parent == 0)
+ return false;
+ else {
+ *newParent = parent->parent();
+ *newAbove = parent;
+ return true;
+ }
+ }
+}
+
+void PhraseTree::moveItem (QListViewItem *item,
+ QListViewItem *parent,
+ QListViewItem *above)
+{
+ if (item != 0) {
+ if (item->parent() == 0)
+ takeItem (item);
+ else
+ item->parent()->takeItem (item);
+
+ if (parent == 0)
+ insertItem (item);
+ else
+ parent->insertItem (item);
+
+ item->moveItem(above);
+ }
+}
+
+bool PhraseTree::hasSelectedItems() {
+ QListViewItem *i = firstChild();
+ if ( !i )
+ return false;
+ int level = 0;
+ do {
+ if (i->isSelected())
+ return true;
+
+ if (i->firstChild() != 0) {
+ i = i->firstChild();
+ level++;
+ }
+ else {
+ while ((i != 0) && (i->nextSibling() == 0)) {
+ i = i->parent();
+ level--;
+ }
+ if (i != 0)
+ i = i->nextSibling();
+ }
+ }
+ while (i != 0);
+
+ return false;
+}
+
+void PhraseTree::deleteSelectedItems() {
+ QListViewItem *i = firstChild();
+ if ( !i )
+ return;
+ QListViewItem *deleteItem = 0;
+ do {
+ if (i->isSelected())
+ deleteItem = i;
+
+ if ((i->firstChild() != 0) && (!i->isSelected())) {
+ i = i->firstChild();
+ }
+ else {
+ while ((i != 0) && (i->nextSibling() == 0)) {
+ i = i->parent();
+ }
+ if (i != 0)
+ i = i->nextSibling();
+ }
+ if (deleteItem != 0) {
+ delete deleteItem;
+ deleteItem = 0;
+ }
+ }
+ while (i != 0);
+}
+
+void PhraseTree::keyPressEvent (QKeyEvent *e) {
+ if ((e->state() & Qt::KeyButtonMask) == Qt::AltButton) {
+ if (e->key() == Qt::Key_Up) {
+ QListViewItem *item = currentItem();
+ if ((item != 0) && (item->isSelected())) {
+ QListViewItem *parent;
+ QListViewItem *above;
+
+ if (PhraseTreePrivate::findAbovePosition (item, &parent, &above)) {
+ moveItem(item, parent, above);
+ setCurrentItem (item);
+ item->setSelected(true);
+ }
+ }
+ e->accept();
+ return;
+ }
+ else if (e->key() == Qt::Key_Down) {
+ QListViewItem *item = currentItem();
+ if ((item != 0) && (item->isSelected())) {
+ QListViewItem *parent;
+ QListViewItem *above;
+
+ if (PhraseTreePrivate::findBelowPosition (item, &parent, &above)) {
+ moveItem(item, parent, above);
+ setCurrentItem (item);
+ item->setSelected(true);
+ }
+ }
+ e->accept();
+ return;
+ }
+ else if (e->key() == Qt::Key_Left) {
+ QListViewItem *item = currentItem();
+ if ((item != 0) && (item->isSelected())) {
+ QListViewItem *parent;
+ QListViewItem *above;
+
+ if (PhraseTreePrivate::findLeftPosition (item, &parent, &above)) {
+ moveItem(item, parent, above);
+ setCurrentItem (item);
+ item->setSelected(true);
+ }
+ }
+ e->accept();
+ return;
+ }
+ else if (e->key() == Qt::Key_Right) {
+ QListViewItem *item = currentItem();
+ if ((item != 0) && (item->isSelected())) {
+ QListViewItem *parent;
+ QListViewItem *above;
+
+ if (PhraseTreePrivate::findRightPosition (item, &parent, &above)) {
+ moveItem(item, parent, above);
+ setCurrentItem (item);
+ item->setSelected(true);
+ }
+ }
+ e->accept();
+ return;
+ }
+ }
+ KListView::keyPressEvent(e);
+}
+
+PhraseTreeItem *PhraseTree::insertPhrase (QListViewItem *parent, QListViewItem *after, QString phrase, QString shortcut) {
+ KShortcut cut = KShortcut(shortcut);
+ if (isKeyPresent (cut, 0, false))
+ cut = KShortcut(QString::null);
+
+ if (parent == 0)
+ return new PhraseTreeItem (this, after, phrase, cut, this->phrase);
+ else
+ return new PhraseTreeItem (parent, after, phrase, cut, this->phrase);
+}
+
+PhraseTreeItem *PhraseTree::insertBook (QListViewItem *parent, QListViewItem *after, QString name) {
+ if (parent == 0)
+ return new PhraseTreeItem (this, after, name, phrasebook_closed);
+ else
+ return new PhraseTreeItem (parent, after, name, phrasebook_closed);
+}
+
+QListViewItem *PhraseTree::addBook (QListViewItem *parent, QListViewItem *after, PhraseBook *book) {
+ QListViewItem *last = after;
+ int level = 0;
+ PhraseBookEntryList::iterator it;
+ for (it = book->begin(); it != book->end(); ++it) {
+ int newLevel = (*it).getLevel();
+ while (level < newLevel) {
+ parent = insertBook(parent, last, "");
+ last = 0;
+ level++;
+ }
+ while (level > newLevel) {
+ last = parent;
+ if (parent != 0)
+ parent = parent->parent();
+ level--;
+ }
+
+ if ((*it).isPhrase()) {
+ Phrase phrase = (*it).getPhrase();
+ last = insertPhrase (parent, last, phrase.getPhrase(), phrase.getShortcut());
+ }
+ else {
+ Phrase phrase = (*it).getPhrase();
+ parent = insertBook(parent, last, phrase.getPhrase());
+ last = 0;
+ level++;
+ }
+ }
+ while (level > 0) {
+ last = parent;
+ if (parent != 0)
+ parent = parent->parent();
+ level--;
+ }
+ return last;
+}
+
+void PhraseTree::fillBook (PhraseBook *book, bool respectSelection) {
+ QListViewItem *i = firstChild();
+ int level = 0;
+ if ( !i )
+ return;
+ do {
+ if (i->isSelected() || !respectSelection || level > 0) {
+ PhraseTreeItem *it = (PhraseTreeItem *)i;
+ Phrase phrase(it->text(0), it->cut().toStringInternal());
+ *book += PhraseBookEntry(phrase, level, it->isPhrase());
+ }
+
+ if (i->firstChild() != 0) {
+ if (i->isSelected() || !respectSelection || level > 0)
+ level++;
+ i = i->firstChild();
+ }
+ else {
+ while ((i != 0) && (i->nextSibling() == 0)) {
+ i = i->parent();
+ if (level > 0)
+ level--;
+ }
+ if (i != 0)
+ i = i->nextSibling();
+ }
+ }
+ while (i != 0);
+}
+
+QDragObject *PhraseTree::dragObject () {
+ return dragObject (true);
+}
+
+QDragObject *PhraseTree::dragObject (bool isDependent) {
+ PhraseBook book;
+ fillBook (&book, true);
+ if (isDependent)
+ return new PhraseBookDrag(&book, viewport());
+ return new PhraseBookDrag(&book);
+}
+
+bool PhraseTree::acceptDrag (QDropEvent* event) const {
+ if (KListView::acceptDrag (event))
+ return true;
+ else
+ return PhraseBookDrag::canDecode(event);
+}
+
+// Returns iSeq index if cut2 has a sequence of equal or higher priority
+// to a sequence in cut, else -1
+static int keyConflict (const KShortcut& cut, const KShortcut& cut2) {
+ for (uint iSeq = 0; iSeq < cut.count(); iSeq++) {
+ for (uint iSeq2 = 0; iSeq2 <= iSeq && iSeq2 < cut2.count(); iSeq2++) {
+ if (cut.seq(iSeq) == cut2.seq(iSeq2))
+ return iSeq;
+ }
+ }
+ return -1;
+}
+
+void PhraseTree::_warning (const KKeySequence& cut, QString sAction, QString sTitle) {
+ sAction = sAction.stripWhiteSpace();
+
+ QString s =
+ i18n("The '%1' key combination has already been allocated "
+ "to %2.\n"
+ "Please choose a unique key combination.").
+ arg(cut.toString()).arg(sAction);
+
+ KMessageBox::sorry( this, s, sTitle );
+}
+
+bool PhraseTree::isStdAccelPresent (const KShortcut& cut, bool warnUser) {
+ for (uint iSeq = 0; iSeq < cut.count(); iSeq++) {
+ const KKeySequence& seq = cut.seq(iSeq);
+
+ KStdAccel::StdAccel id = KStdAccel::findStdAccel( seq );
+ if( id != KStdAccel::AccelNone
+ && keyConflict (cut, KStdAccel::shortcut(id)) > -1)
+ {
+ if (warnUser)
+ _warning (cut.seq(iSeq),
+ i18n("the standard \"%1\" action").arg(KStdAccel::label(id)),
+ i18n("Conflict with Standard Application Shortcut"));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PhraseTree::isGlobalKeyPresent (const KShortcut& cut, bool warnUser) {
+ QMap<QString, QString> mapEntry = KGlobal::config()->entryMap ("Global Shortcuts");
+ QMap<QString, QString>::Iterator it;
+ for (it = mapEntry.begin(); it != mapEntry.end(); ++it) {
+ int iSeq = keyConflict (cut, KShortcut(*it));
+ if (iSeq > -1) {
+ if (warnUser)
+ _warning (cut.seq(iSeq),
+ i18n("the global \"%1\" action").arg(it.key()),
+ i18n("Conflict with Global Shortcuts"));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PhraseTree::isPhraseKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser) {
+ for (QListViewItemIterator it(this); it.current(); ++it) {
+ PhraseTreeItem* item = dynamic_cast<PhraseTreeItem*>(it.current());
+ if ((item != 0) && (item != cutItem)) {
+ int iSeq = keyConflict (cut, item->cut());
+ if (iSeq > -1) {
+ if (warnUser)
+ _warning (cut.seq(iSeq),
+ i18n("an other phrase"),
+ i18n("Key Conflict"));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool PhraseTree::isKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser) {
+ if (isStdAccelPresent (cut, warnUser))
+ return true;
+
+ if (isGlobalKeyPresent (cut, warnUser))
+ return true;
+
+ if (isPhraseKeyPresent (cut, cutItem, warnUser))
+ return true;
+
+ return false;
+}
+
+void PhraseTree::itemExpanded (QListViewItem *item) {
+ PhraseTreeItem *i = (PhraseTreeItem *)item;
+ if (!i->isPhrase())
+ i->setPixmap(0, phrasebook_open);
+}
+
+void PhraseTree::itemCollapsed (QListViewItem *item) {
+ PhraseTreeItem *i = (PhraseTreeItem *)item;
+ if (!i->isPhrase())
+ i->setPixmap(0, phrasebook_closed);
+}
+
+// ***************************************************************************
+
+#include "phrasetree.moc"
diff --git a/kmouth/phrasebook/phrasetree.h b/kmouth/phrasebook/phrasetree.h
new file mode 100644
index 0000000..bd0e1f5
--- /dev/null
+++ b/kmouth/phrasebook/phrasetree.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ phrasetree.h - description
+ -------------------
+ begin : Don Okt 24 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : kmouth@schmi-dt.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PHRASETREE_H
+#define PHRASETREE_H
+
+#include <qpixmap.h>
+#include <kshortcut.h>
+#include <klistview.h>
+
+class PhraseBook;
+class PhraseShortcutRequest;
+
+/**The class PhraseTreeItem is an ListViewItem for either a phrase or a phrase book.
+ *@author Gunnar Schmi Dt
+ */
+
+class PhraseTreeItem : public KListViewItem {
+ friend class PhraseTree;
+private:
+ /** Creates a phrase item within a sub phrase book */
+ PhraseTreeItem (QListView *parent, QListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon);
+ /** Creates a phrase item at the top level */
+ PhraseTreeItem (QListViewItem *parent, QListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon);
+ /** Creates a phrase book item within a sub phrase book */
+ PhraseTreeItem (QListView *parent, QListViewItem *after, QString name, QPixmap icon);
+ /** Creates a phrase book item at the top level */
+ PhraseTreeItem (QListViewItem *parent, QListViewItem *after, QString name, QPixmap icon);
+
+public:
+ bool isPhrase();
+ KShortcut cut();
+ void setCut(KShortcut cut);
+
+private:
+ bool isPhraseValue;
+ KShortcut cutValue;
+};
+
+/**
+ * The class PhraseTree represents the ListView of the phrase book edit
+ * dialog. It extends KListView for providing better drag-and-drop support.
+ * @author Gunnar Schmi Dt
+ */
+
+class PhraseTree : public KListView {
+ friend class PhraseTreeItem;
+ Q_OBJECT
+public:
+ PhraseTree (QWidget *parent = 0, const char *name = 0);
+ ~PhraseTree ();
+
+ void keyPressEvent (QKeyEvent *e);
+
+ PhraseTreeItem *insertPhrase (QListViewItem *parent, QListViewItem *after, QString phrase, QString shortcut);
+ PhraseTreeItem *insertBook (QListViewItem *parent, QListViewItem *after, QString name);
+
+ QListViewItem *addBook (QListViewItem *parent, QListViewItem *after, PhraseBook *book);
+ void fillBook (PhraseBook *book, bool respectSelection);
+
+ QDragObject *dragObject ();
+ QDragObject *dragObject (bool isDependent);
+
+ void moveItem (QListViewItem *item, QListViewItem *parent, QListViewItem *above);
+
+ bool hasSelectedItems();
+ void deleteSelectedItems();
+
+protected:
+ bool acceptDrag (QDropEvent* event) const;
+
+private:
+ void _warning (const KKeySequence& cut, QString sAction, QString sTitle);
+ bool isStdAccelPresent (const KShortcut& cut, bool warnUser);
+ bool isGlobalKeyPresent (const KShortcut& cut, bool warnUser);
+ bool isApplicationKeyPresent (const KShortcut& cut, bool warnUser);
+ bool isPhraseKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser);
+public:
+ bool isKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser);
+
+public slots:
+ void itemExpanded (QListViewItem *item);
+ void itemCollapsed (QListViewItem *item);
+
+signals:
+ void shortcutRequest (PhraseShortcutRequest *request);
+
+private:
+ QPixmap phrasebook_open;
+ QPixmap phrasebook_closed;
+ QPixmap phrase;
+};
+
+#endif