///////////////////////////////////////////////////////////////////////////// // Name: src/qt/choice.cpp // Author: Peter Most, Mariano Reingart // Copyright: (c) 2010 wxWidgets dev team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #include "wx/choice.h" #include "wx/qt/private/winevent.h" #include #include namespace { class LexicalSortProxyModel : public QSortFilterProxyModel { public: explicit LexicalSortProxyModel(QObject* owner) : QSortFilterProxyModel(owner) {} bool lessThan( const QModelIndex &left, const QModelIndex &right ) const wxOVERRIDE { const QVariant leftData = sourceModel()->data( left ); const QVariant rightData = sourceModel()->data( right ); if ( leftData.type() != QVariant::String ) return false; int insensitiveResult = QString::compare( leftData.value(), rightData.value(), Qt::CaseInsensitive ); if ( insensitiveResult == 0 ) { return QString::compare( leftData.value(), rightData.value() ) < 0; } return insensitiveResult < 0; } }; class wxQtChoice : public wxQtEventSignalHandler< QComboBox, wxChoice > { public: wxQtChoice( wxWindow *parent, wxChoice *handler ); private: void activated(int index); }; wxQtChoice::wxQtChoice( wxWindow *parent, wxChoice *handler ) : wxQtEventSignalHandler< QComboBox, wxChoice >( parent, handler ) { // the activated signal is overloaded, the following explicit cast is needed: connect(this, static_cast(&QComboBox::activated), this, &wxQtChoice::activated); } void wxQtChoice::activated(int WXUNUSED(index)) { wxChoice *handler = GetHandler(); if ( handler ) handler->SendSelectionChangedEvent(wxEVT_CHOICE); } } // anonymous namespace wxChoice::wxChoice() : m_qtComboBox(NULL) { } void wxChoice::QtInitSort( QComboBox *combo ) { QSortFilterProxyModel *proxyModel = new LexicalSortProxyModel(combo); proxyModel->setSourceModel(combo->model()); combo->model()->setParent(proxyModel); combo->setModel(proxyModel); } wxChoice::wxChoice( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, int n, const wxString choices[], long style, const wxValidator& validator, const wxString& name ) { Create( parent, id, pos, size, n, choices, style, validator, name ); } wxChoice::wxChoice( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, const wxArrayString& choices, long style, const wxValidator& validator, const wxString& name ) { Create( parent, id, pos, size, choices, style, validator, name ); } bool wxChoice::Create( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, const wxArrayString& choices, long style, const wxValidator& validator, const wxString& name ) { return Create( parent, id, pos, size, choices.size(), choices.size() ? &choices[ 0 ] : NULL, style, validator, name ); } bool wxChoice::Create( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, int n, const wxString choices[], long style, const wxValidator& validator, const wxString& name ) { m_qtComboBox = new wxQtChoice( parent, this ); QtInitSort( m_qtComboBox ); while ( n-- > 0 ) m_qtComboBox->addItem( wxQtConvertString( *choices++ )); return QtCreateControl( parent, id, pos, size, style, validator, name ); } wxSize wxChoice::DoGetBestSize() const { wxSize basesize = wxChoiceBase::DoGetBestSize(); wxSize size = wxControl::DoGetBestSize(); // mix calculated size by wx base prioritizing qt hint (max): if (size.GetWidth() < basesize.GetWidth()) size.SetWidth(basesize.GetWidth()); if (size.GetHeight() < basesize.GetHeight()) size.SetHeight(basesize.GetHeight()); return size; } unsigned wxChoice::GetCount() const { return m_qtComboBox->count(); } wxString wxChoice::GetString(unsigned int n) const { return wxQtConvertString( m_qtComboBox->itemText(n) ); } void wxChoice::SetString(unsigned int n, const wxString& s) { m_qtComboBox->setItemText(n, wxQtConvertString(s)); } void wxChoice::SetSelection(int n) { m_qtComboBox->blockSignals(true); m_qtComboBox->setCurrentIndex(n); m_qtComboBox->blockSignals(false); } int wxChoice::GetSelection() const { return m_qtComboBox->currentIndex(); } int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type) { InvalidateBestSize(); // Hack: to avoid resorting the model many times in DoInsertOneItem(), // which will be called for each item from DoInsertItemsInLoop(), reset the // wxCB_SORT style if we have it temporarily and only sort once at the end. bool wasSorted = false; if ( IsSorted() ) { wasSorted = true; ToggleWindowStyle(wxCB_SORT); } int n = DoInsertItemsInLoop(items, pos, clientData, type); if ( wasSorted ) { // Restore the flag turned off above. ToggleWindowStyle(wxCB_SORT); // And actually sort items now. m_qtComboBox->model()->sort(0); } return n; } int wxChoice::DoInsertOneItem(const wxString& item, unsigned int pos) { // Maintain unselected state const bool unselected = m_qtComboBox->currentIndex() == -1; m_qtComboBox->insertItem(pos, wxQtConvertString(item)); if ( IsSorted() ) m_qtComboBox->model()->sort(0); if ( unselected ) m_qtComboBox->setCurrentIndex(-1); return pos; } void wxChoice::DoSetItemClientData(unsigned int n, void *clientData) { QVariant variant = qVariantFromValue(clientData); m_qtComboBox->setItemData(n, variant); } void *wxChoice::DoGetItemClientData(unsigned int n) const { QVariant variant = m_qtComboBox->itemData(n); return variant.value(); } void wxChoice::DoClear() { m_qtComboBox->clear(); } void wxChoice::DoDeleteOneItem(unsigned int pos) { const int selection = GetSelection(); if ( selection >= 0 && static_cast(selection) == pos ) { SetSelection( wxNOT_FOUND ); } m_qtComboBox->removeItem(pos); } QWidget *wxChoice::GetHandle() const { return m_qtComboBox; }