File indexing completed on 2024-03-24 15:27:43

0001 /* This file is part of the KDE libraries
0002    Copyright (C) 2000 Reginald Stadlbauer <reggie@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License version 2 as published by the Free Software Foundation.
0007 
0008    This library is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011    Library General Public License for more details.
0012 
0013    You should have received a copy of the GNU Library General Public License
0014    along with this library; see the file COPYING.LIB.  If not, write to
0015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0016    Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "klistwidget.h"
0020 
0021 #include <kglobalsettings.h>
0022 #include <kdebug.h>
0023 
0024 #include <QTimer>
0025 #include <QKeyEvent>
0026 #include <QApplication>
0027 
0028 class Q_DECL_HIDDEN KListWidget::KListWidgetPrivate
0029 {
0030 public:
0031     KListWidgetPrivate(KListWidget *q)
0032         : q(q),
0033           m_pCurrentItem(nullptr),
0034           m_eventPos()
0035     {
0036     }
0037 
0038     void _k_slotItemEntered(QListWidgetItem *);
0039     void _k_slotOnViewport();
0040     void _k_slotSettingsChanged(int);
0041     void _k_slotAutoSelect();
0042     void _k_slotEmitExecute(QListWidgetItem *item);
0043 
0044     KListWidget *q;
0045     bool m_bUseSingle : 1;
0046     bool m_bChangeCursorOverItem : 1;
0047 
0048     QListWidgetItem *m_pCurrentItem;
0049     QTimer *m_pAutoSelect;
0050     int m_autoSelectDelay;
0051     QPoint m_eventPos;
0052 };
0053 
0054 KListWidget::KListWidget(QWidget *parent)
0055     : QListWidget(parent), d(new KListWidgetPrivate(this))
0056 {
0057     connect(this, SIGNAL(viewportEntered()),
0058             this, SLOT(_k_slotOnViewport()));
0059     connect(this, SIGNAL(itemEntered(QListWidgetItem*)),
0060             this, SLOT(_k_slotItemEntered(QListWidgetItem*)));
0061     d->_k_slotSettingsChanged(KGlobalSettings::SETTINGS_MOUSE);
0062     connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), SLOT(_k_slotSettingsChanged(int)));
0063 
0064     d->m_pAutoSelect = new QTimer(this);
0065     connect(d->m_pAutoSelect, SIGNAL(timeout()),
0066             this, SLOT(_k_slotAutoSelect()));
0067 }
0068 
0069 KListWidget::~KListWidget()
0070 {
0071     delete d;
0072 }
0073 
0074 void KListWidget::KListWidgetPrivate::_k_slotItemEntered(QListWidgetItem *item)
0075 {
0076     if (item && m_bChangeCursorOverItem && m_bUseSingle) {
0077         q->viewport()->setCursor(QCursor(Qt::OpenHandCursor));
0078     }
0079 
0080     if (item && (m_autoSelectDelay > -1) && m_bUseSingle) {
0081         m_pAutoSelect->setSingleShot(true);
0082         m_pAutoSelect->start(m_autoSelectDelay);
0083         m_pCurrentItem = item;
0084     }
0085 }
0086 
0087 void KListWidget::KListWidgetPrivate::_k_slotOnViewport()
0088 {
0089     if (m_bChangeCursorOverItem) {
0090         q->viewport()->unsetCursor();
0091     }
0092 
0093     m_pAutoSelect->stop();
0094     m_pCurrentItem = nullptr;
0095 }
0096 
0097 void KListWidget::KListWidgetPrivate::_k_slotSettingsChanged(int category)
0098 {
0099     if (category != KGlobalSettings::SETTINGS_MOUSE) {
0100         return;
0101     }
0102     m_bUseSingle = q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
0103 
0104     q->disconnect(q, SIGNAL(itemClicked(QListWidgetItem*)));
0105     q->disconnect(q, SIGNAL(itemDoubleClicked(QListWidgetItem*)));
0106 
0107     if (m_bUseSingle) {
0108         q->connect(q, SIGNAL(itemClicked(QListWidgetItem*)),
0109                    SLOT(_k_slotEmitExecute(QListWidgetItem*)));
0110     } else {
0111         q->connect(q, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
0112                    SLOT(_k_slotEmitExecute(QListWidgetItem*)));
0113     }
0114 
0115     m_bChangeCursorOverItem = KGlobalSettings::changeCursorOverIcon();
0116     m_autoSelectDelay = KGlobalSettings::autoSelectDelay();
0117 
0118     if (!m_bUseSingle || !m_bChangeCursorOverItem) {
0119         q->viewport()->unsetCursor();
0120     }
0121 }
0122 
0123 void KListWidget::KListWidgetPrivate::_k_slotAutoSelect()
0124 {
0125     // check that the item still exists
0126     if (q->row(m_pCurrentItem) == -1) {
0127         return;
0128     }
0129 
0130     //Give this widget the keyboard focus.
0131     if (!q->hasFocus()) {
0132         q->setFocus();
0133     }
0134 
0135     Qt::KeyboardModifiers keybstate = QApplication::keyboardModifiers();
0136 
0137     QListWidgetItem *previousItem = q->currentItem();
0138     q->setCurrentItem(m_pCurrentItem);
0139 
0140     if (m_pCurrentItem) {
0141         //Shift pressed?
0142         if ((keybstate & Qt::ShiftModifier)) {
0143             bool block = q->signalsBlocked();
0144             q->blockSignals(true);
0145 
0146             //No Ctrl? Then clear before!
0147             if (!(keybstate & Qt::ControlModifier)) {
0148                 q->clearSelection();
0149             }
0150 
0151             bool select = !m_pCurrentItem->isSelected();
0152             bool update = q->viewport()->updatesEnabled();
0153             q->viewport()->setUpdatesEnabled(false);
0154 
0155             bool down = q->row(previousItem) < q->row(m_pCurrentItem);
0156             QListWidgetItem *it = down ? previousItem : m_pCurrentItem;
0157 
0158             for (int i = q->row(it); i < q->count(); i++) {
0159                 if (down && q->item(i) == m_pCurrentItem) {
0160                     m_pCurrentItem->setSelected(select);
0161                     break;
0162                 }
0163 
0164                 if (!down && q->item(i) == previousItem) {
0165                     previousItem->setSelected(select);
0166                     break;
0167                 }
0168                 it->setSelected(select);
0169             }
0170 
0171             q->blockSignals(block);
0172             q->viewport()->setUpdatesEnabled(update);
0173 
0174             emit q->itemSelectionChanged();
0175 
0176             if (q->selectionMode() == QAbstractItemView::SingleSelection) {
0177                 q->emit itemSelectionChanged();
0178             }
0179         } else if ((keybstate & Qt::ControlModifier)) {
0180             m_pCurrentItem->setSelected(!m_pCurrentItem->isSelected());
0181         } else {
0182             bool block = q->signalsBlocked();
0183             q->blockSignals(true);
0184 
0185             if (!m_pCurrentItem->isSelected()) {
0186                 q->clearSelection();
0187             }
0188 
0189             q->blockSignals(block);
0190 
0191             m_pCurrentItem->setSelected(true);
0192         }
0193     } else {
0194         kDebug() << "That's not supposed to happen!!!!";
0195     }
0196 }
0197 
0198 void KListWidget::KListWidgetPrivate::_k_slotEmitExecute(QListWidgetItem *item)
0199 {
0200     Qt::KeyboardModifiers keybstate = QApplication::keyboardModifiers();
0201 
0202     m_pAutoSelect->stop();
0203 
0204     //Don't emit executed if in SC mode and Shift or Ctrl are pressed
0205     if (!(m_bUseSingle && ((keybstate & Qt::ShiftModifier) || (keybstate & Qt::ControlModifier)))) {
0206         emit q->executed(item);
0207         if (!m_eventPos.isNull()) {
0208             emit q->executed(item, m_eventPos);
0209         }
0210     }
0211 }
0212 
0213 //
0214 // 2000-16-01 Espen Sand
0215 // This widget is used in dialogs. It should ignore
0216 // F1 (and combinations) and Escape since these are used
0217 // to start help or close the dialog. This functionality
0218 // should be done in QListView but it is not (at least now)
0219 //
0220 void KListWidget::keyPressEvent(QKeyEvent *e)
0221 {
0222     if (e->key() == Qt::Key_Escape) {
0223         e->ignore();
0224     } else if (e->key() == Qt::Key_F1) {
0225         e->ignore();
0226     } else {
0227         QListWidget::keyPressEvent(e);
0228     }
0229 }
0230 
0231 void KListWidget::focusOutEvent(QFocusEvent *fe)
0232 {
0233     d->m_pAutoSelect->stop();
0234 
0235     QListWidget::focusOutEvent(fe);
0236 }
0237 
0238 void KListWidget::leaveEvent(QEvent *e)
0239 {
0240     d->m_pAutoSelect->stop();
0241 
0242     QListWidget::leaveEvent(e);
0243 }
0244 
0245 void KListWidget::mousePressEvent(QMouseEvent *e)
0246 {
0247     if ((selectionMode() == QAbstractItemView::ExtendedSelection) && (e->modifiers() & Qt::ShiftModifier) && !(e->modifiers() & Qt::ControlModifier)) {
0248         bool block = signalsBlocked();
0249         blockSignals(true);
0250 
0251         clearSelection();
0252 
0253         blockSignals(block);
0254     }
0255 
0256     QListWidget::mousePressEvent(e);
0257 }
0258 
0259 void KListWidget::mouseDoubleClickEvent(QMouseEvent *e)
0260 {
0261     QPoint oldPos = d->m_eventPos;
0262     d->m_eventPos = e->globalPos();
0263     QListWidget::mouseDoubleClickEvent(e);
0264     d->m_eventPos = oldPos;
0265 }
0266 
0267 void KListWidget::mouseReleaseEvent(QMouseEvent *e)
0268 {
0269     QPoint oldPos = d->m_eventPos;
0270     d->m_eventPos = e->globalPos();
0271     QListWidget::mouseReleaseEvent(e);
0272     d->m_eventPos = oldPos;
0273 }
0274 
0275 #include "moc_klistwidget.cpp"