• Skip to content
  • Skip to link menu
KDE 4.3 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     p.end();
00062     setExtendPixmap( pixmap );
00063 
00064     pixmap.fill( QColor( Qt::transparent ) );
00065     p.begin( &pixmap );
00066     QApplication::style()->drawPrimitive( QStyle::PE_IndicatorArrowDown, &option, &p );
00067     p.end();
00068     setContractPixmap( pixmap );
00069 
00070     parent->installEventFilter(this);
00071 
00072     // Listen to activation signals
00073     // connect(parent, SIGNAL(activated(QModelIndex)), this, SLOT(itemActivated(QModelIndex)));
00074     connect(parent, SIGNAL(clicked(QModelIndex)), this, SLOT(itemActivated(QModelIndex)));
00075 
00076     // Listen to collapse signals
00077     connect(parent, SIGNAL(collapsed(QModelIndex)), this, SLOT(itemCollapsed(QModelIndex)));
00078 }
00079 
00080 
00081 void KShortcutsEditorDelegate::stealShortcut(
00082     const QKeySequence &seq,
00083     KAction *action)
00084 {
00085     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00086 
00087     // Iterate over all items
00088     QTreeWidgetItemIterator it(view, QTreeWidgetItemIterator::NoChildren);
00089 
00090     for (; (*it); ++it) {
00091         KShortcutsEditorItem* item = dynamic_cast<KShortcutsEditorItem *>(*it);
00092         if (item && item->data(0, ObjectRole).value<QObject*>() == action) {
00093 
00094             // We found the action, snapshot the current state. Steal the
00095             // shortcut. We will save the change later.
00096             KShortcut cut = action->shortcut();
00097             if (   cut.primary().matches(seq) != QKeySequence::NoMatch
00098                 || seq.matches(cut.primary()) != QKeySequence::NoMatch) {
00099                 item->setKeySequence(LocalPrimary, QKeySequence());
00100             }
00101 
00102             if (   cut.alternate().matches(seq) != QKeySequence::NoMatch
00103                 || seq.matches(cut.alternate()) != QKeySequence::NoMatch) {
00104                 item->setKeySequence(LocalAlternate, QKeySequence());
00105             }
00106             break;
00107         }
00108     }
00109 
00110 }
00111 
00112 
00113 QSize KShortcutsEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
00114                                          const QModelIndex &index) const
00115 {
00116     QSize ret(KExtendableItemDelegate::sizeHint(option, index));
00117     ret.rheight() += 4;
00118     return ret;
00119 }
00120 
00121 
00122 //slot
00123 void KShortcutsEditorDelegate::itemActivated(QModelIndex index)
00124 {
00125     //As per our constructor our parent *is* a QTreeWidget
00126     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00127 
00128     KShortcutsEditorItem *item = KShortcutsEditorPrivate::itemFromIndex(view, index);
00129     if (!item) {
00130         //that probably was a non-leaf (type() !=ActionItem) item
00131         return;
00132     }
00133 
00134     int column = index.column();
00135     if (column == Name) {
00136         // If user click in the name column activate the (Global|Local)Primary
00137         // column if possible.
00138         if (!view->header()->isSectionHidden(LocalPrimary)) {
00139             column = LocalPrimary;
00140         } else if (!view->header()->isSectionHidden(GlobalPrimary)) {
00141             column = GlobalPrimary;
00142         } else {
00143             // do nothing.
00144         }
00145         index = index.sibling(index.row(), column);
00146         view->selectionModel()->select(index, QItemSelectionModel::SelectCurrent);
00147     }
00148 
00149     // Check if the models wants us to edit the item at index
00150     if (!index.data(ShowExtensionIndicatorRole).value<bool>()) {
00151         return;
00152     }
00153 
00154     if (!isExtended(index)) {
00155         //we only want maximum ONE extender open at any time.
00156         if (m_editingIndex.isValid()) {
00157             KShortcutsEditorItem *oldItem = KShortcutsEditorPrivate::itemFromIndex(view, 
00158                                                                                     m_editingIndex);
00159             Q_ASSERT(oldItem); //here we really expect nothing but a real KShortcutsEditorItem
00160 
00161             oldItem->setNameBold(false);
00162             contractItem(m_editingIndex);
00163         }
00164 
00165         m_editingIndex = index;
00166         QWidget *viewport = static_cast<QAbstractItemView*>(parent())->viewport();
00167 
00168         if (column >= LocalPrimary && column <= GlobalAlternate) {
00169             ShortcutEditWidget *editor = new ShortcutEditWidget(viewport,
00170                       index.data(DefaultShortcutRole).value<QKeySequence>(),
00171                       index.data(ShortcutRole).value<QKeySequence>(),
00172                       m_allowLetterShortcuts);
00173             if (column==GlobalPrimary) {
00174                 QObject *action = index.data(ObjectRole).value<QObject*>();
00175                 connect(
00176                     action, SIGNAL(globalShortcutChanged(QKeySequence)),
00177                     editor, SLOT(setKeySequence(QKeySequence)));
00178                 editor->setMultiKeyShortcutsAllowed(false);
00179                 KAction *kaction = qobject_cast<KAction*>(action);
00180                 if (kaction) {
00181                     editor->setComponentName(kaction->d->componentData.componentName());
00182                 }
00183             }
00184 
00185             m_editor = editor;
00186             // For global shortcuts check against the kde standard shortcuts
00187             if (column == GlobalPrimary || column == GlobalAlternate) {
00188                 editor->setCheckForConflictsAgainst(
00189                         KKeySequenceWidget::LocalShortcuts
00190                             | KKeySequenceWidget::GlobalShortcuts
00191                             | KKeySequenceWidget::StandardShortcuts );
00192             }
00193 
00194             editor->setCheckActionCollections(m_checkActionCollections);
00195 
00196             connect(m_editor, SIGNAL(keySequenceChanged(const QKeySequence &)),
00197                     this, SLOT(keySequenceChanged(const QKeySequence &)));
00198             connect(m_editor, SIGNAL(stealShortcut(const QKeySequence &, KAction*)),
00199                     this, SLOT(stealShortcut(const QKeySequence&, KAction*)));
00200 
00201         } else if (column == RockerGesture) {
00202             m_editor = new QLabel("A lame placeholder", viewport);
00203 
00204         } else if (column == ShapeGesture) {
00205             m_editor = new QLabel("<i>A towel</i>", viewport);
00206 
00207         } else
00208             return;
00209 
00210         m_editor->installEventFilter(this);
00211         item->setNameBold(true);
00212         extendItem(m_editor, index);
00213 
00214     } else {
00215         //the item is extended, and clicking on it again closes it
00216         item->setNameBold(false);
00217         contractItem(index);
00218         view->selectionModel()->select(index, QItemSelectionModel::Clear);
00219         m_editingIndex = QModelIndex();
00220         m_editor = 0;
00221     }
00222 }
00223 
00224 
00225 //slot
00226 void KShortcutsEditorDelegate::itemCollapsed(QModelIndex index)
00227 {
00228     if (!m_editingIndex.isValid()) {
00229         return;
00230     }
00231 
00232     const QAbstractItemModel *model = index.model();
00233     for (int row = 0; row < model->rowCount(index); ++row) {
00234         QModelIndex rowIndex = model->index(row, 0, index);
00235 
00236         for (int col = 0; col < index.model()->columnCount(index); ++col) {
00237             QModelIndex colIndex = model->index(row, col, index);
00238 
00239             if (colIndex == m_editingIndex) {
00240                 itemActivated(m_editingIndex); //this will *close* the item's editor because it's already open
00241             }
00242         }
00243     }
00244 }
00245 
00246 
00247 //slot
00248 void KShortcutsEditorDelegate::hiddenBySearchLine(QTreeWidgetItem *item, bool hidden)
00249 {
00250     if (!hidden || !item) {
00251         return;
00252     }
00253     QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00254     QTreeWidgetItem *editingItem = KShortcutsEditorPrivate::itemFromIndex(view, m_editingIndex);
00255     if (editingItem == item) {
00256         itemActivated(m_editingIndex); //this will *close* the item's editor because it's already open
00257     }
00258 }
00259 
00260 
00261 bool KShortcutsEditorDelegate::eventFilter(QObject *o, QEvent *e)
00262 {
00263     if (o == m_editor) {
00264         //Prevent clicks in the empty part of the editor widget from closing the editor
00265         //because they would propagate to the itemview and be interpreted as a click in
00266         //an item's rect. That in turn would lead to an itemActivated() call, closing
00267         //the current editor.
00268 
00269         switch (e->type()) {
00270         case QEvent::MouseButtonPress:
00271         case QEvent::MouseButtonRelease:
00272         case QEvent::MouseButtonDblClick:
00273             return true;
00274         default:
00275             return false;
00276         }
00277     } else if (o == parent()) {
00278         // Make left/right cursor keys switch items instead of operate the scroll bar
00279         // (subclassing QtreeView/Widget would be cleaner but much more of a hassle)
00280         // Note that in our case we know that the selection mode is SingleSelection,
00281         // so we don't have to ask QAbstractItemView::selectionCommand() et al.
00282 
00283         if (e->type() != QEvent::KeyPress) {
00284             return false;
00285         }
00286         QKeyEvent *ke = static_cast<QKeyEvent *>(e);
00287         QTreeWidget *view = static_cast<QTreeWidget *>(parent());
00288         QItemSelectionModel *selection = view->selectionModel();
00289         QModelIndex index = selection->currentIndex();
00290 
00291         switch (ke->key()) {
00292         case Qt::Key_Space:
00293         case Qt::Key_Select:
00294             // we are not using the standard "open editor" mechanism of QAbstractItemView,
00295             // so let's emulate that here.
00296             itemActivated(index);
00297             return true;
00298         case Qt::Key_Left:
00299             index = index.sibling(index.row(), index.column() - 1);
00300             break;
00301         case Qt::Key_Right:
00302             index = index.sibling(index.row(), index.column() + 1);
00303             break;
00304 // bug fixed in Qt 4.5.1, TT task 246699
00305 #if QT_VERSION < 0x040501
00306         case Qt::Key_Up:
00307         case Qt::Key_Down: {
00308             // unfortunately Qt's implementation "forgets" the column we were in, so
00309             // we have to save and restore it.
00310 
00311             QTreeWidgetHack *hView = static_cast<QTreeWidgetHack *>(view);
00312             QTreeWidgetItem *item = hView->itemFromIndex(index);
00313             int column = index.column();
00314             if (ke->key() == Qt::Key_Up) {
00315                 item = hView->itemAbove(item);
00316             } else {
00317                 item = hView->itemBelow(item);
00318             }
00319             if (!item) {
00320                 break;
00321             }
00322             do {
00323                 index = hView->indexFromItem(item, column--);
00324             } while (!index.isValid() && column >= 0);
00325 
00326             break; }
00327 #endif
00328         default:
00329             return false;
00330         }
00331         // a cursor key was pressed
00332         if (index.isValid()) {
00333             selection->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00334             //### using PositionAtCenter for now;
00335             // EnsureVisible has no effect which seems to be a bug.
00336             view->scrollTo(index, QAbstractItemView::PositionAtCenter);
00337         }
00338         return true;
00339     }
00340     return false;
00341 }
00342 
00343 
00344 //slot
00345 void KShortcutsEditorDelegate::keySequenceChanged(const QKeySequence &seq)
00346 {
00347     QVariant ret = QVariant::fromValue(seq);
00348     emit shortcutChanged(ret, m_editingIndex);
00349 }
00350 
00351 
00352 void KShortcutsEditorDelegate::setCheckActionCollections(
00353     const QList<KActionCollection*> checkActionCollections )
00354 {
00355     m_checkActionCollections = checkActionCollections;
00356 }
00357 
00358 //slot
00359 void KShortcutsEditorDelegate::shapeGestureChanged(const KShapeGesture &gest)
00360 {
00361     //this is somewhat verbose because the gesture types are not "built in" to QVariant
00362     QVariant ret = QVariant::fromValue(gest);
00363     emit shortcutChanged(ret, m_editingIndex);
00364 }
00365 
00366 
00367 //slot
00368 void KShortcutsEditorDelegate::rockerGestureChanged(const KRockerGesture &gest)
00369 {
00370     QVariant ret = QVariant::fromValue(gest);
00371     emit shortcutChanged(ret, m_editingIndex);
00372 }
00373 

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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