| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | 
							- /*=========================================================================
 
-   Library:   CTK
 
-   Copyright (c) Kitware Inc.
 
-   Licensed under the Apache License, Version 2.0 (the "License");
 
-   you may not use this file except in compliance with the License.
 
-   You may obtain a copy of the License at
 
-       http://www.apache.org/licenses/LICENSE-2.0.txt
 
-   Unless required by applicable law or agreed to in writing, software
 
-   distributed under the License is distributed on an "AS IS" BASIS,
 
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-   See the License for the specific language governing permissions and
 
-   limitations under the License.
 
- =========================================================================*/
 
- // Qt includes
 
- #include <QApplication>
 
- #include <QAbstractItemView>
 
- #include <QCleanlooksStyle>
 
- #include <QDebug>
 
- #include <QDesktopWidget>
 
- #include <QItemDelegate>
 
- #include <QLayout>
 
- #include <QMouseEvent>
 
- #include <QMenu>
 
- #include <QPainter>
 
- #include <QPointer>
 
- #include <QPushButton>
 
- #include <QStandardItemModel>
 
- #include <QStyle>
 
- #include <QStyleOptionButton>
 
- #include <QStylePainter>
 
- #include <QToolBar>
 
- // CTK includes
 
- #include "ctkCheckableComboBox.h"
 
- #include <ctkCheckableModelHelper.h>
 
- // Similar to QComboBoxDelegate
 
- class ctkComboBoxDelegate : public QItemDelegate
 
- {
 
- public:
 
-     ctkComboBoxDelegate(QObject *parent, QComboBox *cmb)
 
-       : QItemDelegate(parent), ComboBox(cmb)
 
-     {}
 
-     static bool isSeparator(const QModelIndex &index)
 
-     {
 
-       return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
 
-     }
 
-     static void setSeparator(QAbstractItemModel *model, const QModelIndex &index)
 
-     {
 
-       model->setData(index, QString::fromLatin1("separator"), Qt::AccessibleDescriptionRole);
 
-       if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model))
 
-         {
 
-         if (QStandardItem *item = m->itemFromIndex(index))
 
-           {
 
-           item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
 
-           }
 
-         }
 
-     }
 
- protected:
 
-     void paint(QPainter *painter,
 
-                const QStyleOptionViewItem &option,
 
-                const QModelIndex &index) const
 
-     {
 
-       if (isSeparator(index))
 
-         {
 
-         QRect rect = option.rect;
 
-         if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&option))
 
-           {
 
-           if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(v3->widget))
 
-             {
 
-             rect.setWidth(view->viewport()->width());
 
-             }
 
-           }
 
-         QStyleOption opt;
 
-         opt.rect = rect;
 
-         this->ComboBox->style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, painter, this->ComboBox);
 
-         }
 
-       else
 
-         {
 
-         QItemDelegate::paint(painter, option, index);
 
-         }
 
-     }
 
-     QSize sizeHint(const QStyleOptionViewItem &option,
 
-                    const QModelIndex &index) const
 
-     {
 
-       if (isSeparator(index))
 
-         {
 
-         int pm = this->ComboBox->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this->ComboBox);
 
-         return QSize(pm, pm);
 
-         }
 
-       return this->QItemDelegate::sizeHint(option, index);
 
-     }
 
- private:
 
-     QComboBox* ComboBox;
 
- };
 
- //-----------------------------------------------------------------------------
 
- class ctkCheckableComboBoxPrivate
 
- {
 
-   Q_DECLARE_PUBLIC(ctkCheckableComboBox);
 
- protected:
 
-   ctkCheckableComboBox* const q_ptr;
 
-   QModelIndexList checkedIndexes()const;
 
-   QModelIndexList uncheckedIndexes()const;
 
- public:
 
-   ctkCheckableComboBoxPrivate(ctkCheckableComboBox& object);
 
-   void init();
 
-   QModelIndexList cachedCheckedIndexes()const;
 
-   void updateCheckedList();
 
-   ctkCheckableModelHelper* CheckableModelHelper;
 
-   bool MouseButtonPressed;
 
- private:
 
-   QModelIndexList persistentIndexesToModelIndexes(
 
-     const QList<QPersistentModelIndex>& persistentModels)const;
 
-   QList<QPersistentModelIndex> modelIndexesToPersistentIndexes(
 
-     const QModelIndexList& modelIndexes)const;
 
-   mutable QList<QPersistentModelIndex> CheckedList;
 
- };
 
- //-----------------------------------------------------------------------------
 
- ctkCheckableComboBoxPrivate::ctkCheckableComboBoxPrivate(ctkCheckableComboBox& object)
 
-   : q_ptr(&object)
 
- {
 
-   this->CheckableModelHelper = 0;
 
-   this->MouseButtonPressed = false;
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBoxPrivate::init()
 
- {
 
-   Q_Q(ctkCheckableComboBox);
 
-   this->CheckableModelHelper = new ctkCheckableModelHelper(Qt::Horizontal, q);
 
-   this->CheckableModelHelper->setForceCheckability(true);
 
-   
 
-   q->setCheckableModel(q->model());
 
-   q->view()->installEventFilter(q);
 
-   q->view()->viewport()->installEventFilter(q);
 
-   // QCleanLooksStyle uses a delegate that doesn't show the checkboxes in the
 
-   // popup list.
 
-   q->setItemDelegate(new ctkComboBoxDelegate(q->view(), q));
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBoxPrivate::updateCheckedList()
 
- {
 
-   Q_Q(ctkCheckableComboBox);
 
-   QList<QPersistentModelIndex> newCheckedPersistentList =
 
-     this->modelIndexesToPersistentIndexes(this->checkedIndexes());
 
-   if (newCheckedPersistentList == this->CheckedList)
 
-     {
 
-     return;
 
-     }
 
-   this->CheckedList = newCheckedPersistentList;
 
-   emit q->checkedIndexesChanged();
 
- }
 
- //-----------------------------------------------------------------------------
 
- QList<QPersistentModelIndex> ctkCheckableComboBoxPrivate
 
- ::modelIndexesToPersistentIndexes(const QModelIndexList& indexes)const
 
- {
 
-   QList<QPersistentModelIndex> res;
 
-   foreach(const QModelIndex& index, indexes)
 
-     {
 
-     QPersistentModelIndex persistent(index);
 
-     if (persistent.isValid())
 
-       {
 
-       res << persistent;
 
-       }
 
-     }
 
-   return res;
 
- }
 
- //-----------------------------------------------------------------------------
 
- QModelIndexList ctkCheckableComboBoxPrivate
 
- ::persistentIndexesToModelIndexes(
 
-   const QList<QPersistentModelIndex>& indexes)const
 
- {
 
-   QModelIndexList res;
 
-   foreach(const QPersistentModelIndex& index, indexes)
 
-     {
 
-     if (index.isValid())
 
-       {
 
-       res << index;
 
-       }
 
-     }
 
-   return res;
 
- }
 
- //-----------------------------------------------------------------------------
 
- QModelIndexList ctkCheckableComboBoxPrivate::cachedCheckedIndexes()const
 
- {
 
-   return this->persistentIndexesToModelIndexes(this->CheckedList);
 
- }
 
- //-----------------------------------------------------------------------------
 
- QModelIndexList ctkCheckableComboBoxPrivate::checkedIndexes()const
 
- {
 
-   Q_Q(const ctkCheckableComboBox);
 
-   QModelIndex startIndex = q->model()->index(0,0, q->rootModelIndex());
 
-   return q->model()->match(
 
-     startIndex, Qt::CheckStateRole,
 
-     static_cast<int>(Qt::Checked), -1, Qt::MatchRecursive);
 
- }
 
- //-----------------------------------------------------------------------------
 
- QModelIndexList ctkCheckableComboBoxPrivate::uncheckedIndexes()const
 
- {
 
-   Q_Q(const ctkCheckableComboBox);
 
-   QModelIndex startIndex = q->model()->index(0,0, q->rootModelIndex());
 
-   return q->model()->match(
 
-     startIndex, Qt::CheckStateRole,
 
-     static_cast<int>(Qt::Unchecked), -1, Qt::MatchRecursive);
 
- }
 
- //-----------------------------------------------------------------------------
 
- ctkCheckableComboBox::ctkCheckableComboBox(QWidget* parentWidget)
 
-   : QComboBox(parentWidget)
 
-   , d_ptr(new ctkCheckableComboBoxPrivate(*this))
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   d->init();
 
- }
 
- //-----------------------------------------------------------------------------
 
- ctkCheckableComboBox::~ctkCheckableComboBox()
 
- {
 
- }
 
- //-----------------------------------------------------------------------------
 
- bool ctkCheckableComboBox::eventFilter(QObject *o, QEvent *e)
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   switch (e->type())
 
-     {
 
-     case QEvent::MouseButtonPress:
 
-       {
 
-       if (this->view()->isVisible())
 
-         {
 
-         d->MouseButtonPressed = true;
 
-         }
 
-       break;
 
-       }
 
-     case QEvent::MouseButtonRelease:
 
-       {
 
-       QMouseEvent *m = static_cast<QMouseEvent *>(e);
 
-       if (this->view()->isVisible() && 
 
-           this->view()->rect().contains(m->pos()) &&
 
-           this->view()->currentIndex().isValid()
 
-           //&& !blockMouseReleaseTimer.isActive()
 
-           && (this->view()->currentIndex().flags() & Qt::ItemIsEnabled)
 
-           && (this->view()->currentIndex().flags() & Qt::ItemIsSelectable))
 
-         {
 
-         // The signal to open the menu is fired when the mouse button is
 
-         // pressed, we don't want to toggle the item under the mouse cursor
 
-         // when the button used to open the popup is released.
 
-         if (d->MouseButtonPressed)
 
-           {
 
-           // make the item current, it will then call QComboBox::update (and
 
-           // repaint) when the current index data is changed (checkstate
 
-           // toggled fires dataChanged signal which is observed).
 
-           this->setCurrentIndex(this->view()->currentIndex().row());
 
-           d->CheckableModelHelper->toggleCheckState(this->view()->currentIndex());
 
-           }
 
-         d->MouseButtonPressed = false;
 
-         return true;
 
-         }
 
-       d->MouseButtonPressed = false;
 
-       break;
 
-       } 
 
-     default:
 
-         break;
 
-     }
 
-   return this->QComboBox::eventFilter(o, e);
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBox::setCheckableModel(QAbstractItemModel* newModel)
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   this->disconnect(this->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
 
-                    this, SLOT(onDataChanged(QModelIndex,QModelIndex)));
 
-   if (newModel != this->model())
 
-     {
 
-     this->setModel(newModel);
 
-     }
 
-   this->connect(this->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
 
-                 this, SLOT(onDataChanged(QModelIndex,QModelIndex)));
 
-   d->CheckableModelHelper->setModel(newModel);
 
-   d->updateCheckedList();
 
- }
 
- //-----------------------------------------------------------------------------
 
- QAbstractItemModel* ctkCheckableComboBox::checkableModel()const
 
- {
 
-   return this->model();
 
- }
 
- //-----------------------------------------------------------------------------
 
- QModelIndexList ctkCheckableComboBox::checkedIndexes()const
 
- {
 
-   Q_D(const ctkCheckableComboBox);
 
-   return d->cachedCheckedIndexes();
 
- }
 
- //-----------------------------------------------------------------------------
 
- bool ctkCheckableComboBox::allChecked()const
 
- {
 
-   Q_D(const ctkCheckableComboBox);
 
-   return d->uncheckedIndexes().count() == 0;
 
- }
 
- //-----------------------------------------------------------------------------
 
- bool ctkCheckableComboBox::noneChecked()const
 
- {
 
-   Q_D(const ctkCheckableComboBox);
 
-   return d->cachedCheckedIndexes().count() == 0;
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBox::setCheckState(const QModelIndex& index, Qt::CheckState check)
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   return d->CheckableModelHelper->setCheckState(index, check);
 
- }
 
- //-----------------------------------------------------------------------------
 
- Qt::CheckState ctkCheckableComboBox::checkState(const QModelIndex& index)const
 
- {
 
-   Q_D(const ctkCheckableComboBox);
 
-   return d->CheckableModelHelper->checkState(index);
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBox::onDataChanged(const QModelIndex& start, const QModelIndex& end)
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   Q_UNUSED(start);
 
-   Q_UNUSED(end);
 
-   d->updateCheckedList();
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCheckableComboBox::paintEvent(QPaintEvent *)
 
- {
 
-   Q_D(ctkCheckableComboBox);
 
-   QStylePainter painter(this);
 
-   painter.setPen(palette().color(QPalette::Text));
 
-   // draw the combobox frame, focusrect and selected etc.
 
-   QStyleOptionComboBox opt;
 
-   this->initStyleOption(&opt);
 
-   if (this->allChecked())
 
-     {
 
-     opt.currentText = "All";
 
-     opt.currentIcon = QIcon();
 
-     }
 
-   else if (this->noneChecked())
 
-     {
 
-     opt.currentText = "None";
 
-     opt.currentIcon = QIcon();
 
-     }
 
-   else
 
-     {
 
-     //search the checked items
 
-     QModelIndexList indexes = d->cachedCheckedIndexes();
 
-     if (indexes.count() == 1)
 
-       {
 
-       opt.currentText = this->model()->data(indexes[0], Qt::DisplayRole).toString();
 
-       opt.currentIcon = qvariant_cast<QIcon>(this->model()->data(indexes[0], Qt::DecorationRole));
 
-       }
 
-     else
 
-       {
 
-       QStringList indexesText;
 
-       foreach(QModelIndex checkedIndex, indexes)
 
-         {
 
-         indexesText << this->model()->data(checkedIndex, Qt::DisplayRole).toString();
 
-         }
 
-       opt.currentText = indexesText.join(", ");
 
-       opt.currentIcon = QIcon();
 
-       }
 
-     }
 
-   painter.drawComplexControl(QStyle::CC_ComboBox, opt);
 
-   // draw the icon and text
 
-   painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
 
- }
 
 
  |