Warning, file /multimedia/amarok/src/widgets/SearchWidget.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Dan Meltzer <parallelgrapefruit@gmail.com> * 0003 * Copyright (c) 2011 Sven Krohlas <sven@asbest-online.de> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #include "SearchWidget.h" 0019 #include "core/support/Debug.h" 0020 #include "dialogs/EditFilterDialog.h" 0021 #include "widgets/BoxWidget.h" 0022 0023 #include <QAction> 0024 #include <QIcon> 0025 #include <QLineEdit> 0026 #include <QPushButton> 0027 #include <QStandardPaths> 0028 #include <QToolBar> 0029 #include <QVBoxLayout> 0030 0031 #include <KLocalizedString> 0032 #include <KStandardGuiItem> 0033 0034 0035 SearchWidget::SearchWidget( QWidget *parent, bool advanced ) 0036 : QWidget( parent ) 0037 , m_sw( nullptr ) 0038 , m_filterAction( nullptr ) 0039 , m_timeout( 500 ) 0040 , m_runningSearches( 0 ) 0041 { 0042 setContentsMargins( 0, 0, 0, 0 ); 0043 BoxWidget *searchBox = new BoxWidget( false ); 0044 searchBox->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); 0045 0046 m_sw = new Amarok::ComboBox( searchBox ); 0047 m_sw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); 0048 m_sw->setFrame( true ); 0049 m_sw->setCompletionMode( KCompletion::CompletionPopup ); 0050 m_sw->completionObject()->setIgnoreCase( true ); 0051 m_sw->setToolTip( i18n( "Enter space-separated terms to search." ) ); 0052 m_sw->addItem( KStandardGuiItem::find().icon(), QString() ); 0053 connect( m_sw, QOverload<int>::of(&QComboBox::activated), 0054 this, &SearchWidget::onComboItemActivated ); 0055 connect( m_sw, &Amarok::ComboBox::editTextChanged, this, &SearchWidget::resetFilterTimeout ); 0056 connect( m_sw, QOverload<const QString&>::of(&KComboBox::returnPressed), 0057 this, &SearchWidget::filterNow ); // filterNow() calls addCompletion() 0058 connect( m_sw, QOverload<const QString&>::of(&KComboBox::returnPressed), 0059 this, &SearchWidget::returnPressed ); 0060 connect( m_sw, &Amarok::ComboBox::downPressed, this, &SearchWidget::advanceFocus ); 0061 0062 QVBoxLayout *layout = new QVBoxLayout(); 0063 layout->addWidget( searchBox ); 0064 layout->setContentsMargins( 0, 0, 0, 0 ); 0065 setLayout( layout ); 0066 setClickMessage( i18n( "Enter search terms here" ) ); 0067 0068 m_toolBar = new QToolBar( searchBox ); 0069 m_toolBar->setFixedHeight( m_sw->sizeHint().height() ); 0070 0071 if( advanced ) 0072 { 0073 m_filterAction = new QAction( QIcon::fromTheme( "document-properties" ), i18n( "Edit filter" ), this ); 0074 m_filterAction->setObjectName( "filter" ); 0075 m_toolBar->addAction( m_filterAction ); 0076 0077 connect( m_filterAction, &QAction::triggered, this, &SearchWidget::slotShowFilterEditor ); 0078 } 0079 0080 m_filterTimer.setSingleShot( true ); 0081 connect( &m_filterTimer, &QTimer::timeout, this, &SearchWidget::filterNow ); 0082 0083 m_animationTimer.setInterval( 500 ); 0084 connect( &m_animationTimer, &QTimer::timeout, this, &SearchWidget::nextAnimationTick ); 0085 } 0086 0087 void 0088 SearchWidget::resetFilterTimeout() 0089 { 0090 m_filterTimer.start( m_timeout ); 0091 } 0092 0093 void 0094 SearchWidget::filterNow() 0095 { 0096 m_filterTimer.stop(); 0097 addCompletion( m_sw->currentText() ); 0098 Q_EMIT filterChanged( m_sw->currentText() ); 0099 } 0100 0101 void 0102 SearchWidget::advanceFocus() 0103 { 0104 focusNextChild(); 0105 } 0106 0107 void 0108 SearchWidget::addCompletion( const QString &text ) 0109 { 0110 int index = m_sw->findText( text ); 0111 if( index == -1 ) 0112 { 0113 m_sw->addItem( KStandardGuiItem::find().icon(), text ); 0114 m_sw->completionObject()->addItem( text ); 0115 } 0116 0117 index = m_sw->findText( text ); 0118 m_sw->setCurrentIndex( index ); 0119 } 0120 0121 void 0122 SearchWidget::onComboItemActivated( int index ) 0123 { 0124 // if data of UserRole exists, use that as the actual filter string 0125 const QString userFilter = m_sw->itemData( index ).toString(); 0126 if( userFilter.isEmpty() ) 0127 m_sw->setEditText( m_sw->itemText(index) ); 0128 else 0129 m_sw->setEditText( userFilter ); 0130 } 0131 0132 void 0133 SearchWidget::slotShowFilterEditor() 0134 { 0135 EditFilterDialog *fd = new EditFilterDialog( this, m_sw->currentText() ); 0136 fd->setAttribute( Qt::WA_DeleteOnClose ); 0137 m_filterAction->setEnabled( false ); 0138 0139 connect( fd, &EditFilterDialog::filterChanged, m_sw, &Amarok::ComboBox::setEditText ); 0140 connect( fd, &QDialog::finished, this, &SearchWidget::slotFilterEditorFinished ); 0141 0142 fd->show(); 0143 } 0144 0145 void 0146 SearchWidget::slotFilterEditorFinished( int result ) 0147 { 0148 m_filterAction->setEnabled( true ); 0149 0150 if( result && !m_sw->currentText().isEmpty() ) // result == QDialog::Accepted 0151 addCompletion( m_sw->currentText() ); 0152 } 0153 0154 QToolBar * 0155 SearchWidget::toolBar() 0156 { 0157 return m_toolBar; 0158 } 0159 0160 void 0161 SearchWidget::showAdvancedButton( bool show ) 0162 { 0163 if( show ) 0164 { 0165 if( m_filterAction != nullptr ) 0166 { 0167 m_filterAction = new QAction( QIcon::fromTheme( "document-properties" ), i18n( "Edit filter" ), this ); 0168 m_filterAction->setObjectName( "filter" ); 0169 m_toolBar->addAction( m_filterAction ); 0170 connect( m_filterAction, &QAction::triggered, this, &SearchWidget::slotShowFilterEditor ); 0171 } 0172 } 0173 else 0174 { 0175 delete m_filterAction; 0176 m_filterAction = nullptr; 0177 } 0178 } 0179 0180 void 0181 SearchWidget::setClickMessage( const QString &message ) 0182 { 0183 QLineEdit *edit = qobject_cast<QLineEdit*>( m_sw->lineEdit() ); 0184 edit->setPlaceholderText( message ); 0185 } 0186 0187 void 0188 SearchWidget::setTimeout( quint16 newTimeout ) 0189 { 0190 m_timeout = newTimeout; 0191 } 0192 0193 // public slots: 0194 0195 void 0196 SearchWidget::setSearchString( const QString &searchString ) 0197 { 0198 if( searchString != currentText() ) { 0199 m_sw->setEditText( searchString ); 0200 filterNow(); 0201 } 0202 } 0203 0204 void 0205 SearchWidget::searchStarted() 0206 { 0207 m_runningSearches++; 0208 0209 // start the animation 0210 if( !m_animationTimer.isActive() ) 0211 { 0212 m_sw->setItemIcon( m_sw->currentIndex(), QIcon( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading1.png" ) ) ); 0213 m_currentFrame = 0; 0214 m_animationTimer.start(); 0215 } 0216 0217 // If another search is running it might still have a part of the animation set as its icon. 0218 // As the currentIndex() has changed we don't know which one. We now have to iterate through 0219 // all of them and set the icon correctly. It's not as bad as it sounds: the number is quite 0220 // limited. 0221 0222 for( int i = 0; i < m_sw->count(); i++ ) 0223 { 0224 if( i != m_sw->currentIndex() ) // not the current one, which should be animated! 0225 m_sw->setItemIcon( i, KStandardGuiItem::find().icon() ); 0226 } 0227 } 0228 0229 void 0230 SearchWidget::searchEnded() 0231 { 0232 if( m_runningSearches > 0 ) // just to be sure... 0233 m_runningSearches--; 0234 0235 // stop the animation 0236 if( m_runningSearches == 0 ) 0237 { 0238 m_animationTimer.stop(); 0239 saveLineEditStatus(); 0240 m_sw->setItemIcon( m_sw->currentIndex(), KStandardGuiItem::find().icon() ); 0241 restoreLineEditStatus(); 0242 } 0243 } 0244 0245 0246 // private Q_SLOTS: 0247 0248 void 0249 SearchWidget::nextAnimationTick() 0250 { 0251 saveLineEditStatus(); 0252 0253 // switch frames 0254 if( m_currentFrame == 0 ) 0255 m_sw->setItemIcon( m_sw->currentIndex(), QIcon( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading2.png" ) ) ); 0256 else 0257 m_sw->setItemIcon( m_sw->currentIndex(), QIcon( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/loading1.png" ) ) ); 0258 0259 restoreLineEditStatus(); 0260 m_currentFrame = !m_currentFrame; 0261 } 0262 0263 0264 // private: 0265 0266 void 0267 SearchWidget::restoreLineEditStatus() 0268 { 0269 // restore text changes made by the user 0270 m_sw->setEditText( m_text ); 0271 0272 if( m_hasSelectedText ) 0273 m_sw->lineEdit()->setSelection( m_selectionStart, m_selectionLength ); // also sets cursor 0274 else 0275 m_sw->lineEdit()->setCursorPosition( m_cursorPosition ); 0276 } 0277 0278 void 0279 SearchWidget::saveLineEditStatus() 0280 { 0281 // save text changes made by the user 0282 m_text = m_sw->lineEdit()->text(); 0283 m_cursorPosition = m_sw->cursorPosition(); 0284 m_hasSelectedText = m_sw->lineEdit()->hasSelectedText(); 0285 m_selectionStart = m_sw->lineEdit()->selectionStart(); 0286 m_selectionLength = m_sw->lineEdit()->selectedText().length(); 0287 } 0288