merge branches/work/kaction-cleanup-branch: Simplify and clean up KShortcut
[kdeaccessibility.git] / kmouth / phrasebook / phrasetree.cpp
blobb16b3d8b1ee8cf9f4842d5b4b456cea3021eee9c
1 /***************************************************************************
2 phrasetree.cpp - description
3 -------------------
4 begin : Don Okt 24 2002
5 copyright : (C) 2002 by Gunnar Schmi Dt
6 email : kmouth@schmi-dt.de
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <klocale.h>
19 #include <kconfig.h>
20 #include <kaction.h>
21 #include <kstdaccel.h>
22 #include <kiconloader.h>
23 #include <kmessagebox.h>
24 #include <kactionmenu.h>
25 #include <ktoolbarpopupaction.h>
26 #include "phrasetree.h"
27 #include "phrasebookdialog.h"
28 #include "phrasebook.h"
29 //Added by qt3to4:
30 #include <QPixmap>
31 #include <QKeyEvent>
32 #include <QDropEvent>
34 PhraseTreeItem::PhraseTreeItem (Q3ListView *parent, Q3ListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon)
35 : K3ListViewItem (parent, after, phrase)
37 isPhraseValue = true;
38 cutValue = shortcut;
39 setText(1, cutValue.toString());
40 setPixmap(0, icon);
41 setExpandable (false);
44 PhraseTreeItem::PhraseTreeItem (Q3ListViewItem *parent, Q3ListViewItem *after, QString phrase, KShortcut shortcut, QPixmap icon)
45 : K3ListViewItem (parent, after, phrase)
47 isPhraseValue = true;
48 cutValue = shortcut;
49 setText(1, cutValue.toString());
50 setPixmap(0, icon);
51 setExpandable (false);
53 PhraseTreeItem::PhraseTreeItem (Q3ListView *parent, Q3ListViewItem *after, QString name, QPixmap icon)
54 : K3ListViewItem (parent, after, name)
56 isPhraseValue = false;
57 setPixmap(0, icon);
58 setExpandable (true);
60 PhraseTreeItem::PhraseTreeItem (Q3ListViewItem *parent, Q3ListViewItem *after, QString name, QPixmap icon)
61 : K3ListViewItem (parent, after, name)
63 isPhraseValue = false;
64 setPixmap(0, icon);
65 setExpandable (true);
67 bool PhraseTreeItem::isPhrase () {
68 return isPhraseValue;
70 KShortcut PhraseTreeItem::cut () {
71 return cutValue;
73 void PhraseTreeItem::setCut (KShortcut cut) {
74 cutValue = cut;
75 setText(1, cut.toString());
78 // ***************************************************************************
80 PhraseTree::PhraseTree (QWidget *parent, const char *name)
81 : K3ListView (parent)
83 Q_UNUSED(name);
84 phrasebook_open = KGlobal::iconLoader()->loadIcon("phrasebook", K3Icon::Small);
85 phrasebook_closed = KGlobal::iconLoader()->loadIcon("phrasebook_closed", K3Icon::Small);
86 phrase = KGlobal::iconLoader()->loadIcon("phrase", K3Icon::Small);
88 connect (this, SIGNAL(expanded (Q3ListViewItem *)), this, SLOT(itemExpanded (Q3ListViewItem *)));
89 connect (this, SIGNAL(collapsed (Q3ListViewItem *)), this, SLOT(itemCollapsed (Q3ListViewItem *)));
92 PhraseTree::~PhraseTree (){
95 namespace PhraseTreePrivate {
96 Q3ListViewItem *prevSibling (Q3ListViewItem *item) {
97 Q3ListViewItem *parent = item->parent();
98 Q3ListViewItem *above = item->itemAbove();
100 if (above == parent)
101 return 0;
103 while (above->parent() != parent)
104 above = above->parent();
106 return above;
109 bool findAbovePosition (Q3ListViewItem *item,
110 Q3ListViewItem **newParent,
111 Q3ListViewItem **newAbove)
113 if (item == 0)
114 return false;
116 Q3ListViewItem *parent = item->parent();
117 Q3ListViewItem *above = item->itemAbove();
119 if (above == 0)
120 return false;
121 else if (above == parent) {
122 *newParent = parent->parent();
123 *newAbove = prevSibling (parent);
124 return true;
126 else if (above->parent() == parent) {
127 *newParent = parent;
128 *newAbove = prevSibling (above);
129 return true;
131 else {
132 while (above->parent()->parent() != parent)
133 above = above->parent();
134 *newParent = above->parent();
135 *newAbove = above;
136 return true;
140 bool findBelowPosition (Q3ListViewItem *item,
141 Q3ListViewItem **newParent,
142 Q3ListViewItem **newAbove)
144 if (item == 0)
145 return false;
147 Q3ListViewItem *parent = item->parent();
148 Q3ListViewItem *below = item->nextSibling();
150 if (parent == 0 && below == 0)
151 return false;
152 else if (parent != 0 && below == 0) {
153 *newParent = parent->parent();
154 *newAbove = parent;
155 return true;
157 else if (below->isOpen()) {
158 *newParent = below;
159 *newAbove = 0;
160 return true;
162 else {
163 *newParent = parent;
164 *newAbove = below;
165 return true;
169 bool findRightPosition (Q3ListViewItem *item,
170 Q3ListViewItem **newParent,
171 Q3ListViewItem **newAbove)
173 if (item == 0)
174 return false;
176 Q3ListViewItem *above = prevSibling (item);
178 if (above == 0)
179 return false;
180 else if (((PhraseTreeItem *)above)->isPhrase())
181 return false;
182 else {
183 above->setOpen(true);
184 *newParent = above;
185 *newAbove = 0;
186 above = (*newParent)->firstChild();
187 while (above != 0) {
188 *newAbove = above;
189 above = above->nextSibling();
191 return true;
195 bool findLeftPosition (Q3ListViewItem *item,
196 Q3ListViewItem **newParent,
197 Q3ListViewItem **newAbove)
199 if (item == 0)
200 return false;
202 Q3ListViewItem *parent = item->parent();
204 if (parent == 0)
205 return false;
206 else {
207 *newParent = parent->parent();
208 *newAbove = parent;
209 return true;
214 void PhraseTree::moveItem (Q3ListViewItem *item,
215 Q3ListViewItem *parent,
216 Q3ListViewItem *above)
218 if (item != 0) {
219 if (item->parent() == 0)
220 takeItem (item);
221 else
222 item->parent()->takeItem (item);
224 if (parent == 0)
225 insertItem (item);
226 else
227 parent->insertItem (item);
229 item->moveItem(above);
233 bool PhraseTree::hasSelectedItems() {
234 Q3ListViewItem *i = firstChild();
235 if ( !i )
236 return false;
237 int level = 0;
238 do {
239 if (i->isSelected())
240 return true;
242 if (i->firstChild() != 0) {
243 i = i->firstChild();
244 level++;
246 else {
247 while ((i != 0) && (i->nextSibling() == 0)) {
248 i = i->parent();
249 level--;
251 if (i != 0)
252 i = i->nextSibling();
255 while (i != 0);
257 return false;
260 void PhraseTree::deleteSelectedItems() {
261 Q3ListViewItem *i = firstChild();
262 if ( !i )
263 return;
264 Q3ListViewItem *deleteItem = 0;
265 do {
266 if (i->isSelected())
267 deleteItem = i;
269 if ((i->firstChild() != 0) && (!i->isSelected())) {
270 i = i->firstChild();
272 else {
273 while ((i != 0) && (i->nextSibling() == 0)) {
274 i = i->parent();
276 if (i != 0)
277 i = i->nextSibling();
279 if (deleteItem != 0) {
280 delete deleteItem;
281 deleteItem = 0;
284 while (i != 0);
287 void PhraseTree::keyPressEvent (QKeyEvent *e) {
288 if (e->modifiers() & Qt::AltModifier) {
289 if (e->key() == Qt::Key_Up) {
290 Q3ListViewItem *item = currentItem();
291 if ((item != 0) && (item->isSelected())) {
292 Q3ListViewItem *parent;
293 Q3ListViewItem *above;
295 if (PhraseTreePrivate::findAbovePosition (item, &parent, &above)) {
296 moveItem(item, parent, above);
297 setCurrentItem (item);
298 item->setSelected(true);
301 e->accept();
302 return;
304 else if (e->key() == Qt::Key_Down) {
305 Q3ListViewItem *item = currentItem();
306 if ((item != 0) && (item->isSelected())) {
307 Q3ListViewItem *parent;
308 Q3ListViewItem *above;
310 if (PhraseTreePrivate::findBelowPosition (item, &parent, &above)) {
311 moveItem(item, parent, above);
312 setCurrentItem (item);
313 item->setSelected(true);
316 e->accept();
317 return;
319 else if (e->key() == Qt::Key_Left) {
320 Q3ListViewItem *item = currentItem();
321 if ((item != 0) && (item->isSelected())) {
322 Q3ListViewItem *parent;
323 Q3ListViewItem *above;
325 if (PhraseTreePrivate::findLeftPosition (item, &parent, &above)) {
326 moveItem(item, parent, above);
327 setCurrentItem (item);
328 item->setSelected(true);
331 e->accept();
332 return;
334 else if (e->key() == Qt::Key_Right) {
335 Q3ListViewItem *item = currentItem();
336 if ((item != 0) && (item->isSelected())) {
337 Q3ListViewItem *parent;
338 Q3ListViewItem *above;
340 if (PhraseTreePrivate::findRightPosition (item, &parent, &above)) {
341 moveItem(item, parent, above);
342 setCurrentItem (item);
343 item->setSelected(true);
346 e->accept();
347 return;
350 K3ListView::keyPressEvent(e);
353 PhraseTreeItem *PhraseTree::insertPhrase (Q3ListViewItem *parent, Q3ListViewItem *after, QString phrase, QString shortcut) {
354 KShortcut cut = KShortcut(shortcut);
355 if (isKeyPresent (cut, 0, false))
356 cut = KShortcut(QString());
358 if (parent == 0)
359 return new PhraseTreeItem (this, after, phrase, cut, this->phrase);
360 else
361 return new PhraseTreeItem (parent, after, phrase, cut, this->phrase);
364 PhraseTreeItem *PhraseTree::insertBook (Q3ListViewItem *parent, Q3ListViewItem *after, QString name) {
365 if (parent == 0)
366 return new PhraseTreeItem (this, after, name, phrasebook_closed);
367 else
368 return new PhraseTreeItem (parent, after, name, phrasebook_closed);
371 Q3ListViewItem *PhraseTree::addBook (Q3ListViewItem *parent, Q3ListViewItem *after, PhraseBook *book) {
372 Q3ListViewItem *last = after;
373 int level = 0;
374 PhraseBookEntryList::iterator it;
375 for (it = book->begin(); it != book->end(); ++it) {
376 int newLevel = (*it).getLevel();
377 while (level < newLevel) {
378 parent = insertBook(parent, last, "");
379 last = 0;
380 level++;
382 while (level > newLevel) {
383 last = parent;
384 if (parent != 0)
385 parent = parent->parent();
386 level--;
389 if ((*it).isPhrase()) {
390 Phrase phrase = (*it).getPhrase();
391 last = insertPhrase (parent, last, phrase.getPhrase(), phrase.getShortcut());
393 else {
394 Phrase phrase = (*it).getPhrase();
395 parent = insertBook(parent, last, phrase.getPhrase());
396 last = 0;
397 level++;
400 while (level > 0) {
401 last = parent;
402 if (parent != 0)
403 parent = parent->parent();
404 level--;
406 return last;
409 void PhraseTree::fillBook (PhraseBook *book, bool respectSelection) {
410 Q3ListViewItem *i = firstChild();
411 int level = 0;
412 if ( !i )
413 return;
414 do {
415 if (i->isSelected() || !respectSelection || level > 0) {
416 PhraseTreeItem *it = (PhraseTreeItem *)i;
417 Phrase phrase(it->text(0), it->cut().toString());
418 *book += PhraseBookEntry(phrase, level, it->isPhrase());
421 if (i->firstChild() != 0) {
422 if (i->isSelected() || !respectSelection || level > 0)
423 level++;
424 i = i->firstChild();
426 else {
427 while ((i != 0) && (i->nextSibling() == 0)) {
428 i = i->parent();
429 if (level > 0)
430 level--;
432 if (i != 0)
433 i = i->nextSibling();
436 while (i != 0);
439 Q3DragObject *PhraseTree::dragObject () {
440 return dragObject (true);
443 Q3DragObject *PhraseTree::dragObject (bool isDependent) {
444 PhraseBook book;
445 fillBook (&book, true);
446 if (isDependent)
447 return new PhraseBookDrag(&book, viewport());
448 return new PhraseBookDrag(&book);
451 bool PhraseTree::acceptDrag (QDropEvent* event) const {
452 if (K3ListView::acceptDrag (event))
453 return true;
454 else
455 return PhraseBookDrag::canDecode(event);
458 // Returns iSeq index if cut2 has a sequence of equal or higher priority
459 // to a sequence in cut, else -1
460 static int keyConflict (const KShortcut& cut, const KShortcut& cut2) {
461 int nbCut = cut.count();
462 int nbCut2 = cut2.count();
463 for (int iSeq = 0; iSeq < nbCut; iSeq++) {
464 for (int iSeq2 = 0; iSeq2 <= iSeq && iSeq2 < nbCut2; iSeq2++) {
465 if (cut[iSeq] == cut2[iSeq2])
466 return iSeq;
469 return -1;
472 void PhraseTree::_warning (const QKeySequence& cut, QString sAction, const QString &sTitle) {
473 sAction = sAction.trimmed();
475 QString s =
476 i18n("The '%1' key combination has already been allocated "
477 "to %2.\n"
478 "Please choose a unique key combination.",
479 cut.toString(), sAction);
481 KMessageBox::sorry( this, s, sTitle );
484 bool PhraseTree::isStdAccelPresent (const KShortcut& cut, bool warnUser) {
485 for (int iSeq = 0; iSeq < cut.count(); iSeq++) {
486 const QKeySequence& seq = cut[iSeq];
488 KStdAccel::StdAccel id = KStdAccel::findStdAccel( seq );
489 if( id != KStdAccel::AccelNone
490 && keyConflict (cut, KStdAccel::shortcut(id)) > -1)
492 if (warnUser)
493 _warning (cut[iSeq],
494 i18n("the standard \"%1\" action", KStdAccel::label(id)),
495 i18n("Conflict with Standard Application Shortcut"));
496 return true;
499 return false;
502 bool PhraseTree::isGlobalKeyPresent (const KShortcut& cut, bool warnUser) {
503 QMap<QString, QString> mapEntry = KGlobal::config()->entryMap ("Global Shortcuts");
504 QMap<QString, QString>::Iterator it;
505 for (it = mapEntry.begin(); it != mapEntry.end(); ++it) {
506 int iSeq = keyConflict (cut, KShortcut(*it));
507 if (iSeq > -1) {
508 if (warnUser)
509 _warning (cut[iSeq],
510 i18n("the global \"%1\" action", it.key()),
511 i18n("Conflict with Global Shortcuts"));
512 return true;
515 return false;
518 bool PhraseTree::isPhraseKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser) {
519 for (Q3ListViewItemIterator it(this); it.current(); ++it) {
520 PhraseTreeItem* item = dynamic_cast<PhraseTreeItem*>(it.current());
521 if ((item != 0) && (item != cutItem)) {
522 int iSeq = keyConflict (cut, item->cut());
523 if (iSeq > -1) {
524 if (warnUser)
525 _warning (cut[iSeq],
526 i18n("an other phrase"),
527 i18n("Key Conflict"));
528 return true;
532 return false;
535 bool PhraseTree::isKeyPresent (const KShortcut& cut, PhraseTreeItem* cutItem, bool warnUser) {
536 if (isStdAccelPresent (cut, warnUser))
537 return true;
539 if (isGlobalKeyPresent (cut, warnUser))
540 return true;
542 if (isPhraseKeyPresent (cut, cutItem, warnUser))
543 return true;
545 return false;
548 void PhraseTree::itemExpanded (Q3ListViewItem *item) {
549 PhraseTreeItem *i = (PhraseTreeItem *)item;
550 if (!i->isPhrase())
551 i->setPixmap(0, phrasebook_open);
554 void PhraseTree::itemCollapsed (Q3ListViewItem *item) {
555 PhraseTreeItem *i = (PhraseTreeItem *)item;
556 if (!i->isPhrase())
557 i->setPixmap(0, phrasebook_closed);
560 // ***************************************************************************
562 #include "phrasetree.moc"