File indexing completed on 2024-05-05 04:48:45
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "ProgressiveSearchWidget.h" 0018 0019 #include "core/support/Debug.h" 0020 #include "playlist/PlaylistModel.h" 0021 0022 #include <KColorScheme> 0023 #include <KConfigGroup> 0024 #include <KLocalizedString> 0025 0026 #include <QAction> 0027 #include <QHBoxLayout> 0028 #include <QVBoxLayout> 0029 #include <QKeyEvent> 0030 #include <QLabel> 0031 #include <QMenu> 0032 #include <QToolBar> 0033 #include <QToolButton> 0034 0035 namespace Playlist 0036 { 0037 0038 ProgressiveSearchWidget::ProgressiveSearchWidget( QWidget * parent ) 0039 : BoxWidget( true, parent ) 0040 { 0041 DEBUG_BLOCK 0042 0043 readConfig(); 0044 0045 BoxWidget *searchBox = new BoxWidget( false, this ); 0046 0047 m_searchEdit = new Amarok::LineEdit( searchBox ); 0048 m_searchEdit->setPlaceholderText( i18n( "Search playlist" ) ); 0049 m_searchEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); 0050 m_searchEdit->setClearButtonEnabled( true ); 0051 m_searchEdit->setFrame( true ); 0052 m_searchEdit->setToolTip( i18n( "Start typing to progressively search through the playlist" ) ); 0053 m_searchEdit->setFocusPolicy( Qt::ClickFocus ); // Without this, the widget goes into text input mode directly on startup 0054 0055 connect( m_searchEdit, &Amarok::LineEdit::textChanged, this, &ProgressiveSearchWidget::slotFilterChanged ); 0056 connect( m_searchEdit, &Amarok::LineEdit::returnPressed, this, &ProgressiveSearchWidget::activateFilterResult ); 0057 connect( m_searchEdit, &Amarok::LineEdit::returnPressed, this, &ProgressiveSearchWidget::slotFilterClear ); 0058 connect( m_searchEdit, &Amarok::LineEdit::returnPressed, this, &ProgressiveSearchWidget::defocus ); 0059 connect( m_searchEdit, &Amarok::LineEdit::downPressed, this, &ProgressiveSearchWidget::downPressed ); 0060 connect( m_searchEdit, &Amarok::LineEdit::upPressed, this, &ProgressiveSearchWidget::upPressed ); 0061 0062 m_nextAction = new QAction( QIcon::fromTheme( QStringLiteral("go-down") ), i18n( "&Next" ), this ); 0063 connect( m_nextAction, &QAction::triggered, this, &ProgressiveSearchWidget::slotNext ); 0064 0065 m_previousAction = new QAction( QIcon::fromTheme( QStringLiteral("go-up") ), i18n( "&Previous" ), this ); 0066 connect( m_previousAction, &QAction::triggered, this, &ProgressiveSearchWidget::slotPrevious ); 0067 0068 m_nextAction->setEnabled( false ); 0069 m_previousAction->setEnabled( false ); 0070 0071 m_menu = new QMenu( this ); 0072 0073 QAction * searchTracksAction = new QAction( i18n( "Tracks" ), this ); 0074 searchTracksAction->setCheckable( true ); 0075 connect( searchTracksAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchTracks ); 0076 if( m_searchFieldsMask & Playlist::MatchTrack ) 0077 searchTracksAction->setChecked( true ); 0078 m_menu->addAction( searchTracksAction ); 0079 0080 QAction * searchAlbumsAction = new QAction( i18n( "Albums" ), this ); 0081 searchAlbumsAction->setCheckable( true ); 0082 connect( searchAlbumsAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchAlbums ); 0083 if( m_searchFieldsMask & Playlist::MatchAlbum ) 0084 searchAlbumsAction->setChecked( true ); 0085 m_menu->addAction( searchAlbumsAction ); 0086 0087 QAction * searchArtistsAction = new QAction( i18n( "Artists" ), this ); 0088 searchArtistsAction->setCheckable( true ); 0089 connect( searchArtistsAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchArtists ); 0090 if( m_searchFieldsMask & Playlist::MatchArtist ) 0091 searchArtistsAction->setChecked( true ); 0092 m_menu->addAction( searchArtistsAction ); 0093 0094 QAction * searchGenreAction = new QAction( i18n( "Genre" ), this ); 0095 searchGenreAction->setCheckable( true ); 0096 connect( searchGenreAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchGenre ); 0097 if( m_searchFieldsMask & Playlist::MatchGenre ) 0098 searchGenreAction->setChecked( true ); 0099 m_menu->addAction( searchGenreAction ); 0100 0101 QAction * searchComposersAction = new QAction( i18n( "Composers" ), this ); 0102 searchComposersAction->setCheckable( true ); 0103 connect( searchComposersAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchComposers ); 0104 if( m_searchFieldsMask & Playlist::MatchComposer ) 0105 searchComposersAction->setChecked( true ); 0106 m_menu->addAction( searchComposersAction ); 0107 0108 QAction * searchRatingAction = new QAction( i18n( "Rating" ), this ); 0109 searchRatingAction->setCheckable( true ); 0110 connect( searchRatingAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchRating ); 0111 if( m_searchFieldsMask & Playlist::MatchRating ) 0112 searchRatingAction->setChecked( true ); 0113 m_menu->addAction( searchRatingAction ); 0114 0115 QAction * searchYearsAction = new QAction( i18n( "Years" ), this ); 0116 searchYearsAction->setCheckable( true ); 0117 connect( searchYearsAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotSearchYears ); 0118 if( m_searchFieldsMask & Playlist::MatchYear) 0119 searchYearsAction->setChecked( true ); 0120 m_menu->addAction( searchYearsAction ); 0121 0122 m_menu->addSeparator(); 0123 0124 QAction * showOnlyMatchesAction = new QAction( i18n( "Show only matches" ), this ); 0125 showOnlyMatchesAction->setCheckable( true ); 0126 connect( showOnlyMatchesAction, &QAction::toggled, this, &ProgressiveSearchWidget::slotShowOnlyMatches ); 0127 0128 m_toolBar = new QToolBar( searchBox ); 0129 showOnlyMatchesAction->setChecked( m_showOnlyMatches ); 0130 m_menu->addAction( showOnlyMatchesAction ); 0131 slotShowOnlyMatches( m_showOnlyMatches ); 0132 0133 m_nextAction->setVisible( !m_showOnlyMatches ); 0134 m_previousAction->setVisible( !m_showOnlyMatches ); 0135 0136 QAction *searchMenuAction = new QAction( QIcon::fromTheme( QStringLiteral("preferences-other") ), i18n( "Search Preferences" ), this ); 0137 searchMenuAction->setMenu( m_menu ); 0138 0139 m_toolBar->addAction( searchMenuAction ); 0140 0141 QToolButton *tbutton = qobject_cast<QToolButton*>( m_toolBar->widgetForAction( searchMenuAction ) ); 0142 if( tbutton ) 0143 tbutton->setPopupMode( QToolButton::InstantPopup ); 0144 0145 m_toolBar->setFixedHeight( m_searchEdit->sizeHint().height() ); 0146 0147 //make sure that this edit is cleared when the playlist is cleared: 0148 connect( Amarok::actionCollection()->action( QStringLiteral("playlist_clear") ), &QAction::triggered, this, &ProgressiveSearchWidget::slotFilterClear ); 0149 } 0150 0151 void ProgressiveSearchWidget::slotFilterChanged( const QString & filter ) 0152 { 0153 DEBUG_BLOCK 0154 0155 //when the clear button is pressed, we get 2 calls to this slot... filter this out as it messes with 0156 //resetting the view: 0157 if ( filter == m_lastFilter ) 0158 return; 0159 0160 debug() << "New filter: " << filter; 0161 0162 m_lastFilter = filter; 0163 0164 if( filter.isEmpty() ) 0165 { 0166 m_nextAction->setEnabled( false ); 0167 m_previousAction->setEnabled( false ); 0168 0169 QPalette p = m_searchEdit->palette(); 0170 p.setColor( QPalette::Base, palette().color( QPalette::Base ) ); 0171 m_searchEdit->setPalette( p ); 0172 0173 Q_EMIT( filterCleared() ); 0174 0175 return; 0176 } 0177 0178 Q_EMIT( filterChanged( filter, m_searchFieldsMask, m_showOnlyMatches ) ); 0179 } 0180 0181 void ProgressiveSearchWidget::slotNext() 0182 { 0183 DEBUG_BLOCK 0184 Q_EMIT( next( m_searchEdit->text(), m_searchFieldsMask ) ); 0185 } 0186 0187 void ProgressiveSearchWidget::slotPrevious() 0188 { 0189 DEBUG_BLOCK 0190 Q_EMIT( previous( m_searchEdit->text(), m_searchFieldsMask ) ); 0191 } 0192 0193 void ProgressiveSearchWidget::match() 0194 { 0195 m_nextAction->setEnabled( true ); 0196 m_previousAction->setEnabled( true ); 0197 0198 QPalette p = m_searchEdit->palette(); 0199 p.setColor( QPalette::Base, palette().color( QPalette::Base ) ); 0200 m_searchEdit->setPalette( p ); 0201 } 0202 0203 void ProgressiveSearchWidget::noMatch() 0204 { 0205 m_nextAction->setEnabled( false ); 0206 m_previousAction->setEnabled( false ); 0207 0208 const KStatefulBrush backgroundBrush( KColorScheme::View, KColorScheme::NegativeBackground ); 0209 0210 QPalette p = m_searchEdit->palette(); 0211 p.setColor( QPalette::Base, backgroundBrush.brush( p ).color() ); 0212 m_searchEdit->setPalette( p ); 0213 } 0214 0215 void ProgressiveSearchWidget::slotSearchTracks( bool search ) 0216 { 0217 if( search ) 0218 m_searchFieldsMask |= Playlist::MatchTrack; 0219 else 0220 m_searchFieldsMask ^= Playlist::MatchTrack; 0221 0222 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchTrack", search ); 0223 0224 if( !m_searchEdit->text().isEmpty() ) 0225 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0226 } 0227 0228 void ProgressiveSearchWidget::slotSearchArtists( bool search ) 0229 { 0230 if( search ) 0231 m_searchFieldsMask |= Playlist::MatchArtist; 0232 else 0233 m_searchFieldsMask ^= Playlist::MatchArtist; 0234 0235 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchArtist", search ); 0236 0237 if( !m_searchEdit->text().isEmpty() ) 0238 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0239 } 0240 0241 void ProgressiveSearchWidget::slotSearchAlbums( bool search ) 0242 { 0243 if( search ) 0244 m_searchFieldsMask |= Playlist::MatchAlbum; 0245 else 0246 m_searchFieldsMask ^= Playlist::MatchAlbum; 0247 0248 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchAlbum", search ); 0249 0250 if( !m_searchEdit->text().isEmpty() ) 0251 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0252 } 0253 0254 void ProgressiveSearchWidget::slotSearchGenre( bool search ) 0255 { 0256 if( search ) 0257 m_searchFieldsMask |= Playlist::MatchGenre; 0258 else 0259 m_searchFieldsMask ^= Playlist::MatchGenre; 0260 0261 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchGenre", search ); 0262 0263 if( !m_searchEdit->text().isEmpty() ) 0264 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0265 } 0266 0267 void ProgressiveSearchWidget::slotSearchComposers( bool search ) 0268 { 0269 if( search ) 0270 m_searchFieldsMask |= Playlist::MatchComposer; 0271 else 0272 m_searchFieldsMask ^= Playlist::MatchComposer; 0273 0274 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchComposer", search ); 0275 0276 if( !m_searchEdit->text().isEmpty() ) 0277 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0278 } 0279 0280 void ProgressiveSearchWidget::slotSearchRating( bool search ) 0281 { 0282 if( search ) 0283 m_searchFieldsMask |= Playlist::MatchRating; 0284 else 0285 m_searchFieldsMask ^= Playlist::MatchRating; 0286 0287 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchRating", search ); 0288 0289 if( !m_searchEdit->text().isEmpty() ) 0290 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0291 } 0292 0293 void ProgressiveSearchWidget::slotSearchYears( bool search ) 0294 { 0295 if( search ) 0296 m_searchFieldsMask |= Playlist::MatchYear; 0297 else 0298 m_searchFieldsMask ^= Playlist::MatchYear; 0299 0300 Amarok::config( QStringLiteral("Playlist Search") ).writeEntry( "MatchYear", search ); 0301 0302 if( !m_searchEdit->text().isEmpty() ) 0303 Q_EMIT( filterChanged( m_searchEdit->text(), m_searchFieldsMask, m_showOnlyMatches ) ); 0304 } 0305 0306 void ProgressiveSearchWidget::readConfig() 0307 { 0308 m_searchFieldsMask = 0; 0309 0310 KConfigGroup config = Amarok::config(QStringLiteral("Playlist Search")); 0311 0312 if( config.readEntry( "MatchTrack", true ) ) 0313 m_searchFieldsMask |= Playlist::MatchTrack; 0314 if( config.readEntry( "MatchArtist", true ) ) 0315 m_searchFieldsMask |= Playlist::MatchArtist; 0316 if( config.readEntry( "MatchAlbum", true ) ) 0317 m_searchFieldsMask |= Playlist::MatchAlbum; 0318 if( config.readEntry( "MatchGenre", false ) ) 0319 m_searchFieldsMask |= Playlist::MatchGenre; 0320 if( config.readEntry( "MatchComposer", false ) ) 0321 m_searchFieldsMask |= Playlist::MatchComposer; 0322 if( config.readEntry( "MatchRating", false ) ) 0323 m_searchFieldsMask |= Playlist::MatchRating; 0324 if( config.readEntry( "MatchYear", false ) ) 0325 m_searchFieldsMask |= Playlist::MatchYear; 0326 0327 m_showOnlyMatches = config.readEntry( "ShowOnlyMatches", false ); 0328 } 0329 0330 void ProgressiveSearchWidget::slotShowOnlyMatches( bool onlyMatches ) 0331 { 0332 DEBUG_BLOCK 0333 0334 if( onlyMatches ) 0335 { 0336 m_toolBar->removeAction( m_previousAction ); 0337 m_toolBar->removeAction( m_nextAction ); 0338 } 0339 else 0340 { 0341 m_toolBar->insertAction( m_menu->menuAction(), m_nextAction ); 0342 m_toolBar->insertAction( m_nextAction, m_previousAction ); 0343 } 0344 0345 m_showOnlyMatches = onlyMatches; 0346 m_nextAction->setVisible( !onlyMatches ); 0347 m_previousAction->setVisible( !onlyMatches ); 0348 0349 KConfigGroup cg = Amarok::config( QStringLiteral("Playlist Search") ); 0350 cg.writeEntry( "ShowOnlyMatches", m_showOnlyMatches ); 0351 cg.sync(); 0352 0353 Q_EMIT( showOnlyMatches( onlyMatches ) ); 0354 } 0355 0356 void 0357 ProgressiveSearchWidget::keyPressEvent( QKeyEvent *event ) 0358 { 0359 if( event->matches( QKeySequence::FindNext ) ) 0360 { 0361 event->accept(); 0362 slotNext(); 0363 } 0364 else if( event->matches( QKeySequence::FindPrevious ) ) 0365 { 0366 event->accept(); 0367 slotPrevious(); 0368 } 0369 else 0370 { 0371 event->ignore(); 0372 BoxWidget::keyPressEvent( event ); 0373 } 0374 } 0375 0376 void 0377 ProgressiveSearchWidget::focusInputLine() 0378 { 0379 m_searchEdit->setFocus(); 0380 } 0381 0382 void ProgressiveSearchWidget::slotFilterClear() 0383 { 0384 DEBUG_BLOCK 0385 m_searchEdit->setText( QString() ); 0386 } 0387 0388 } //namespace Playlist 0389