• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kshortcutseditordelegate.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1998 Mark Donohoe <donohoe@kde.org>
00003     Copyright (C) 1997 Nicolas Hadacek <hadacek@kde.org>
00004     Copyright (C) 1998 Matthias Ettrich <ettrich@kde.org>
00005     Copyright (C) 2001 Ellis Whitehead <ellis@kde.org>
00006     Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
00007     Copyright (C) 2007 Roberto Raggi <roberto@kdevelop.org>
00008     Copyright (C) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
00009     Copyright (C) 2008 Michael Jansen <kde@michael-jansen.biz>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Library General Public
00013     License as published by the Free Software Foundation; either
00014     version 2 of the License, or (at your option) any later version.
00015 
00016     This library is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     Library General Public License for more details.
00020 
00021     You should have received a copy of the GNU Library General Public License
00022     along with this library; see the file COPYING.LIB.  If not, write to
00023     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024     Boston, MA 02110-1301, USA.
00025 */
00026 
00027 
00028 
00029 #include "kshortcutsdialog_p.h"
00030 #include "kaction_p.h"
00031 
00032 #include <QApplication>
00033 #include <QHeaderView>
00034 #include <QKeyEvent>
00035 #include <QLabel>
00036 #include <QPainter>
00037 #include <QTreeWidgetItemIterator>
00038 
00039 #include "kaction.h"
00040 
00041 #include "kdebug.h"
00042 
00043 
00044 
00045 
00046 KShortcutsEditorDelegate::KShortcutsEditorDelegate(QTreeWidget *parent, bool allowLetterShortcuts)
00047  : KExtendableItemDelegate(parent),
00048    m_allowLetterShortcuts(allowLetterShortcuts),
00049    m_editor(0)
00050 {
00051     Q_ASSERT(qobject_cast<QAbstractItemView *>(parent));
00052 
00053     QPixmap pixmap( 16, 16 );
00054     pixmap.fill( QColor( Qt::transparent ) );
00055     QPainter p( &pixmap );
00056     QStyleOption option;
00057     option.rect = pixmap.rect();
00058 
00059     bool isRtl = QApplication::isRightToLeft();
00060     QApplication::style()->drawPrimitive( isRtl ? QStyle::PE_IndicatorArrowLeft : QStyle::PE_IndicatorArrowRight, &option, &p );
00061     setExtendPixmap( pixmap );
00062 
00063     pixmap.fill( QColor( Qt::transparent ) );
00064     QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowDown, &option, &p );
00065     setContractPixmap( pixmap );
00066 
00067     parent->installEventFilter(this);
00068 
00069     // Listen to activiation signals
00070     // connect(parent, SIGNAL(activated(QModelIndex)), this, SLOT(itemActivated(QModelIndex)));
00071     connect(parent, SIGNAL(clicked(QModelIndex)), this, SLOT(itemActivated(QModelIndex)));
00072 
00073     // Listen to collapse signals
00074     connect(parent, SIGNAL(collapsed(QModelIndex)), this, SLOT(itemCollapsed(QModelIndex)));
00075 }
00076 
00077 
00078 void KShortcutsEditorDelegate::stealShortcut(
00079     const QKeySequence &seq,
00080     KAction *action)
00081 {
00082     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00083 
00084     // Iterate over all items
00085     QTreeWidgetItemIterator it(view, QTreeWidgetItemIterator::NoChildren);
00086 
00087     for (; (*it); ++it) {
00088         KShortcutsEditorItem* item = dynamic_cast<KShortcutsEditorItem *>(*it);
00089         if (item && item->data(0, ObjectRole).value<QObject*>() == action) {
00090 
00091             // We found the action, snapshot the current state. Steal the
00092             // shortcut. We will save the change later.
00093             KShortcut cut = action->shortcut();
00094             if (   cut.primary().matches(seq) != QKeySequence::NoMatch
00095                 || seq.matches(cut.primary()) != QKeySequence::NoMatch) {
00096                 item->setKeySequence(LocalPrimary, QKeySequence());
00097             }
00098 
00099             if (   cut.alternate().matches(seq) != QKeySequence::NoMatch
00100                 || seq.matches(cut.alternate()) != QKeySequence::NoMatch) {
00101                 item->setKeySequence(LocalAlternate, QKeySequence());
00102             }
00103             break;
00104         }
00105     }
00106 
00107 }
00108 
00109 
00110 QSize KShortcutsEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
00111                                          const QModelIndex &index) const
00112 {
00113     QSize ret(KExtendableItemDelegate::sizeHint(option, index));
00114     ret.rheight() += 4;
00115     return ret;
00116 }
00117 
00118 
00119 //slot
00120 void KShortcutsEditorDelegate::itemActivated(QModelIndex index)
00121 {
00122     //As per our constructor our parent *is* a QTreeWidget
00123     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00124 
00125     KShortcutsEditorItem *item = KShortcutsEditorPrivate::itemFromIndex(view, index);
00126     if (!item) {
00127         //that probably was a non-leaf (type() !=ActionItem) item
00128         return;
00129     }
00130 
00131     int column = index.column();
00132     if (column == Name) {
00133         // If user click in the name column activate the (Global|Local)Primary
00134         // column if possible.
00135         if (!view->header()->isSectionHidden(LocalPrimary)) {
00136             column = LocalPrimary;
00137         } else if (!view->header()->isSectionHidden(GlobalPrimary)) {
00138             column = GlobalPrimary;
00139         } else {
00140             // do nothing.
00141         }
00142         index = index.sibling(index.row(), column);
00143         view->selectionModel()->select(index, QItemSelectionModel::SelectCurrent);
00144     }
00145 
00146     // Check if the models wants us to edit the item at index
00147     if (!index.data(ShowExtensionIndicatorRole).value<bool>()) {
00148         return;
00149     }
00150 
00151     if (!isExtended(index)) {
00152         //we only want maximum ONE extender open at any time.
00153         if (m_editingIndex.isValid()) {
00154             QModelIndex idx = index.sibling(m_editingIndex.row(), Name);
00155             KShortcutsEditorItem *oldItem = KShortcutsEditorPrivate::itemFromIndex(view, idx);
00156             Q_ASSERT(oldItem); //here we really expect nothing but a real KShortcutsEditorItem
00157 
00158             oldItem->setNameBold(false);
00159             contractItem(m_editingIndex);
00160         }
00161 
00162         m_editingIndex = index;
00163         QWidget *viewport = static_cast<QAbstractItemView*>(parent())->viewport();
00164 
00165         if (column >= LocalPrimary && column <= GlobalAlternate) {
00166             ShortcutEditWidget *editor = new ShortcutEditWidget(viewport,
00167                       index.data(DefaultShortcutRole).value<QKeySequence>(),
00168                       index.data(ShortcutRole).value<QKeySequence>(),
00169                       m_allowLetterShortcuts);
00170             if (column==GlobalPrimary) {
00171                 QObject *action = index.data(ObjectRole).value<QObject*>();
00172                 connect(
00173                     action, SIGNAL(globalShortcutChanged(QKeySequence)),
00174                     editor, SLOT(setKeySequence(QKeySequence)));
00175                 editor->setMultiKeyShortcutsAllowed(false);
00176                 KAction *kaction = qobject_cast<KAction*>(action);
00177                 if (kaction) {
00178                     editor->setComponentName(kaction->d->componentData.componentName());
00179                 }
00180             }
00181 
00182             m_editor = editor;
00183             // For global shortcuts check against the kde standard shortcuts
00184             if (column == GlobalPrimary || column == GlobalAlternate) {
00185                 editor->setCheckForConflictsAgainst(
00186                         KKeySequenceWidget::LocalShortcuts
00187                             | KKeySequenceWidget::GlobalShortcuts
00188                             | KKeySequenceWidget::StandardShortcuts );
00189             }
00190 
00191             editor->setCheckActionCollections(m_checkActionCollections);
00192 
00193             connect(m_editor, SIGNAL(keySequenceChanged(const QKeySequence &)),
00194                     this, SLOT(keySequenceChanged(const QKeySequence &)));
00195             connect(m_editor, SIGNAL(stealShortcut(const QKeySequence &, KAction*)),
00196                     this, SLOT(stealShortcut(const QKeySequence&, KAction*)));
00197 
00198         } else if (column == RockerGesture) {
00199             m_editor = new QLabel("A lame placeholder", viewport);
00200 
00201         } else if (column == ShapeGesture) {
00202             m_editor = new QLabel("<i>A towel</i>", viewport);
00203 
00204         } else
00205             return;
00206 
00207         m_editor->installEventFilter(this);
00208         item->setNameBold(true);
00209         extendItem(m_editor, index);
00210 
00211     } else {
00212         //the item is extended, and clicking on it again closes it
00213         item->setNameBold(false);
00214         contractItem(index);
00215         view->selectionModel()->select(index, QItemSelectionModel::Clear);
00216         m_editingIndex = QModelIndex();
00217         m_editor = 0;
00218     }
00219 }
00220 
00221 
00222 //slot
00223 void KShortcutsEditorDelegate::itemCollapsed(QModelIndex index)
00224 {
00225     if (!m_editingIndex.isValid())
00226         return;
00227 
00228     const QAbstractItemModel *model = index.model();
00229     for (int row=0; row<model->rowCount(index);++row) {
00230         QModelIndex rowIndex = model->index(row,0,index);
00231 
00232         for (int col=0; col<index.model()->columnCount(index);++col) {
00233             QModelIndex colIndex = model->index(row,col,index);
00234 
00235             if (colIndex == m_editingIndex) {
00236                 itemActivated(m_editingIndex); //this will *close* the item's editor because it's already open
00237             }
00238 
00239         }
00240 
00241     }
00242 
00243 }
00244 
00245 
00246 //slot
00247 void KShortcutsEditorDelegate::hiddenBySearchLine(QTreeWidgetItem *item, bool hidden)
00248 {
00249     if (!hidden || !item) {
00250         return;
00251     }
00252     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00253     QTreeWidgetItem *editingItem = KShortcutsEditorPrivate::itemFromIndex(view, m_editingIndex);
00254     if (editingItem == item) {
00255         itemActivated(m_editingIndex); //this will *close* the item's editor because it's already open
00256     }
00257 }
00258 
00259 
00260 bool KShortcutsEditorDelegate::eventFilter(QObject *o, QEvent *e)
00261 {
00262     if (o == m_editor) {
00263         //Prevent clicks in the empty part of the editor widget from closing the editor
00264         //because they would propagate to the itemview and be interpreted as a click in
00265         //an item's rect. That in turn would lead to an itemActivated() call, closing
00266         //the current editor.
00267 
00268         switch (e->type()) {
00269         case QEvent::MouseButtonPress:
00270         case QEvent::MouseButtonRelease:
00271         case QEvent::MouseButtonDblClick:
00272             return true;
00273         default:
00274             return false;
00275         }
00276     } else if (o == parent()) {
00277         // Make left/right cursor keys switch items instead of operate the scroll bar
00278         // (subclassing QtreeView/Widget would be cleaner but much more of a hassle)
00279         // Note that in our case we know that the selection mode is SingleSelection,
00280         // so we don't have to ask QAbstractItemView::selectionCommand() et al.
00281 
00282         if (e->type() != QEvent::KeyPress) {
00283             return false;
00284         }
00285         QKeyEvent *ke = static_cast<QKeyEvent *>(e);
00286         QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00287         QItemSelectionModel *selection = view->selectionModel();
00288         QModelIndex index = selection->currentIndex();
00289 
00290         switch (ke->key()) {
00291         case Qt::Key_Space:
00292         case Qt::Key_Select:
00293             // we are not using the standard "open editor" mechanism of QAbstractItemView,
00294             // so let's emulate that here.
00295             itemActivated(index);
00296             return true;
00297         case Qt::Key_Left:
00298             index = index.sibling(index.row(), index.column() - 1);
00299             break;
00300         case Qt::Key_Right:
00301             index = index.sibling(index.row(), index.column() + 1);
00302             break;
00303         case Qt::Key_Up:
00304         case Qt::Key_Down: {
00305             // unfortunately Qt's implementation "forgets" the column we were in, so
00306             // we have to save and restore it.
00307 
00308             QTreeWidgetHack *hView = static_cast<QTreeWidgetHack *>(view);
00309             QTreeWidgetItem *item = hView->itemFromIndex(index);
00310             int column = index.column();
00311             if (ke->key() == Qt::Key_Up) {
00312                 item = hView->itemAbove(item);
00313             } else {
00314                 item = hView->itemBelow(item);
00315             }
00316             if (!item) {
00317                 break;
00318             }
00319             do {
00320                 index = hView->indexFromItem(item, column--);
00321             } while (!index.isValid() && column >= 0);
00322 
00323             break; }
00324         default:
00325             return false;
00326         }
00327         // a cursor key was pressed
00328         if (index.isValid()) {
00329             selection->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00330             //### using PositionAtCenter for now;
00331             // EnsureVisible has no effect which seems to be a bug.
00332             view->scrollTo(index, QAbstractItemView::PositionAtCenter);
00333         }
00334         return true;
00335     }
00336     return false;
00337 }
00338 
00339 
00340 //slot
00341 void KShortcutsEditorDelegate::keySequenceChanged(const QKeySequence &seq)
00342 {
00343     QVariant ret = QVariant::fromValue(seq);
00344     emit shortcutChanged(ret, m_editingIndex);
00345 }
00346 
00347 
00348 void KShortcutsEditorDelegate::setCheckActionCollections(
00349     const QList<KActionCollection*> checkActionCollections )
00350 {
00351     m_checkActionCollections = checkActionCollections;
00352 }
00353 
00354 //slot
00355 void KShortcutsEditorDelegate::shapeGestureChanged(const KShapeGesture &gest)
00356 {
00357     //this is somewhat verbose because the gesture types are not "built in" to QVariant
00358     QVariant ret = QVariant::fromValue(gest);
00359     emit shortcutChanged(ret, m_editingIndex);
00360 }
00361 
00362 
00363 //slot
00364 void KShortcutsEditorDelegate::rockerGestureChanged(const KRockerGesture &gest)
00365 {
00366     QVariant ret = QVariant::fromValue(gest);
00367     emit shortcutChanged(ret, m_editingIndex);
00368 }
00369 

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal