From 00bb99ac80741fc50ef8a289719373032f2391eb Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeaccessibility@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kmouth/phrasebook/Makefile.am | 16 + kmouth/phrasebook/buttonboxui.ui | 107 +++++ kmouth/phrasebook/phrasebook.cpp | 512 +++++++++++++++++++++ kmouth/phrasebook/phrasebook.h | 195 ++++++++ kmouth/phrasebook/phrasebookdialog.cpp | 758 ++++++++++++++++++++++++++++++++ kmouth/phrasebook/phrasebookdialog.h | 234 ++++++++++ kmouth/phrasebook/phrasebookdialogui.rc | 64 +++ kmouth/phrasebook/phrasebookparser.cpp | 112 +++++ kmouth/phrasebook/phrasebookparser.h | 73 +++ kmouth/phrasebook/phrasetree.cpp | 556 +++++++++++++++++++++++ kmouth/phrasebook/phrasetree.h | 108 +++++ 11 files changed, 2735 insertions(+) create mode 100644 kmouth/phrasebook/Makefile.am create mode 100644 kmouth/phrasebook/buttonboxui.ui create mode 100644 kmouth/phrasebook/phrasebook.cpp create mode 100644 kmouth/phrasebook/phrasebook.h create mode 100644 kmouth/phrasebook/phrasebookdialog.cpp create mode 100644 kmouth/phrasebook/phrasebookdialog.h create mode 100644 kmouth/phrasebook/phrasebookdialogui.rc create mode 100644 kmouth/phrasebook/phrasebookparser.cpp create mode 100644 kmouth/phrasebook/phrasebookparser.h create mode 100644 kmouth/phrasebook/phrasetree.cpp create mode 100644 kmouth/phrasebook/phrasetree.h (limited to 'kmouth/phrasebook') 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 @@ + +ButtonBoxUI + + + ButtonBoxUI + + + + 0 + 0 + 278 + 141 + + + + Currently Selected Phrase or Phrase Book + + + + unnamed + + + 11 + + + 6 + + + + phrasebox + + + &Currently Selected Phrase or Phrase Book + + + + unnamed + + + 11 + + + 6 + + + + keyButtonPlace + + + + + lineEdit + + + With this line edit you define the name of a sub-phrasebook or the contents of a phrase. + + + + + noKey + + + &None + + + If you select this option then the selected phrase will not be reachable by a keyboard shortcut. + + + + + customKey + + + C&ustom + + + 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. + + + + + shortcutLabel + + + Shortcut for the phrase: + + + + + textLabel + + + Text of the &phrase: + + + lineEdit + + + With this line edit you define the name of a sub-phrasebook or the contents of a phrase. + + + + + + + + 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = "\n"; + result += "\n"; + result += "\n"; + + PhraseBookEntryList::iterator it; + int level = 0; + for (it = begin(); it != end(); ++it) { + int newLevel = (*it).getLevel(); + while (level < newLevel) { + result += "\n"; + level++; + } + while (level > newLevel) { + result += "\n"; + level--; + } + + if ((*it).isPhrase()) { + Phrase phrase = (*it).getPhrase(); + result += "" + encodeString(phrase.getPhrase()) + "\n"; + } + else { + Phrase phrase = (*it).getPhrase(); + result += "\n"; + level++; + } + } + while (level > 0) { + result += "\n"; + level--; + } + result += ""; + 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("%1").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("%1").arg(i18n("Your chosen filename %1 has a different extension than .phrasebook. " + "Do you wish to add .phrasebook 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("%1").arg(i18n("Your chosen filename %1 has the extension .phrasebook. " + "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 stack; + QWidget *parent = popup; + int level = 0; + + QValueListConstIterator 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 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 +#include +#include + +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// include files for KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 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 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("There are unsaved changes.
Do you want to apply the changes before closing the \"phrase book\" window or discard the changes?
"), + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 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 @@ + + + + + &File + + + + + + + + + + + + + + &Edit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 mapEntry = KGlobal::config()->entryMap ("Global Shortcuts"); + QMap::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(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 +#include +#include + +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 -- cgit v1.2.1