File indexing completed on 2024-05-05 04:48:44
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Téo Mrnjavac <teo@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 "PlaylistSortWidget.h" 0018 0019 #include "core/support/Debug.h" 0020 #include "PlaylistActions.h" 0021 #include "PlaylistModelStack.h" 0022 #include "proxymodels/SortScheme.h" 0023 0024 #include <KConfigGroup> 0025 #include <QStandardPaths> 0026 0027 namespace Playlist 0028 { 0029 0030 SortWidget::SortWidget( QWidget *parent ) 0031 : QWidget( parent ) 0032 { 0033 setFixedHeight( 28 ); 0034 setContentsMargins( 3, 0, 3, 0 ); 0035 0036 m_layout = new QHBoxLayout( this ); 0037 setLayout( m_layout ); 0038 m_layout->setSpacing( 0 ); 0039 m_layout->setContentsMargins( 0, 0, 0, 0 ); 0040 0041 BreadcrumbItemButton *rootItem = new BreadcrumbItemButton( 0042 QIcon( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/playlist-sorting-16.png" ) ) ), 0043 QString(), this ); 0044 rootItem->setToolTip( i18n( "Clear the playlist sorting configuration." ) ); 0045 m_layout->addWidget( rootItem ); 0046 connect( rootItem, &BreadcrumbItemButton::clicked, this, &SortWidget::trimToLevel ); 0047 0048 m_ribbon = new QHBoxLayout(); 0049 m_layout->addLayout( m_ribbon ); 0050 m_ribbon->setContentsMargins( 0, 0, 0, 0 ); 0051 m_ribbon->setSpacing( 0 ); 0052 0053 m_addButton = new BreadcrumbAddMenuButton( this ); 0054 m_addButton->setToolTip( i18n( "Add a playlist sorting level." ) ); 0055 m_layout->addWidget( m_addButton ); 0056 m_layout->addStretch( 10 ); 0057 0058 m_urlButton = new BreadcrumbUrlMenuButton( QStringLiteral("playlist"), this ); 0059 m_layout->addWidget( m_urlButton ); 0060 0061 connect( m_addButton->menu(), &BreadcrumbItemMenu::actionClicked, 0062 this, &SortWidget::addLevelAscending ); 0063 connect( m_addButton->menu(), &BreadcrumbItemMenu::shuffleActionClicked, 0064 The::playlistActions(), &Actions::shuffle ); 0065 0066 QString sortPath = Amarok::config( QStringLiteral("Playlist Sorting") ).readEntry( "SortPath", QString() ); 0067 readSortPath( sortPath ); 0068 } 0069 0070 SortWidget::~SortWidget() 0071 {} 0072 0073 void 0074 SortWidget::addLevel( const QString &internalColumnName, Qt::SortOrder sortOrder ) //private slot 0075 { 0076 BreadcrumbLevel *bLevel = new BreadcrumbLevel( internalColumnName ); 0077 BreadcrumbItem *item = new BreadcrumbItem( bLevel, this ); 0078 m_ribbon->addWidget( item ); 0079 connect( item, &BreadcrumbItem::clicked, this, &SortWidget::onItemClicked ); 0080 connect( item->menu(), &BreadcrumbItemMenu::actionClicked, this, &SortWidget::onItemSiblingClicked ); 0081 connect( item->menu(), &BreadcrumbItemMenu::shuffleActionClicked, this, &SortWidget::onShuffleSiblingClicked ); 0082 connect( item, &BreadcrumbItem::orderInverted, this, &SortWidget::updateSortScheme ); 0083 if( sortOrder != item->sortOrder() ) 0084 item->invertOrder(); 0085 m_addButton->updateMenu( levels() ); 0086 updateSortScheme(); 0087 } 0088 0089 void 0090 SortWidget::addLevelAscending ( const QString &internalColumnName ) 0091 { 0092 addLevel(internalColumnName, Qt::AscendingOrder); 0093 } 0094 0095 void 0096 SortWidget::trimToLevel( const int level ) 0097 { 0098 for( int i = m_ribbon->count() - 1 ; i > level; i-- ) 0099 { 0100 BreadcrumbItem *item = qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() ); 0101 m_ribbon->removeWidget( item ); 0102 item->deleteLater(); 0103 } 0104 updateSortScheme(); 0105 m_addButton->updateMenu( levels() ); 0106 } 0107 0108 QStringList 0109 SortWidget::levels() const 0110 { 0111 QStringList levels = QStringList(); 0112 for( int i = 0; i < m_ribbon->count(); ++i ) 0113 levels << qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->name(); 0114 return levels; 0115 } 0116 0117 void 0118 SortWidget::onItemClicked() 0119 { 0120 const int level = m_ribbon->indexOf( qobject_cast< QWidget * >( sender()->parent() ) ); 0121 trimToLevel( level ); 0122 } 0123 0124 void 0125 SortWidget::onItemSiblingClicked( const QString &internalColumnName ) 0126 { 0127 const int level = m_ribbon->indexOf( qobject_cast< QWidget * >( sender()->parent() ) ); 0128 trimToLevel( level - 1 ); 0129 addLevel( internalColumnName ); 0130 } 0131 0132 void 0133 SortWidget::onShuffleSiblingClicked() 0134 { 0135 const int level = m_ribbon->indexOf( qobject_cast< QWidget * >( sender()->parent() ) ); 0136 trimToLevel( level - 1 ); 0137 The::playlistActions()->shuffle(); 0138 } 0139 0140 void 0141 SortWidget::updateSortScheme() 0142 { 0143 SortScheme scheme = SortScheme(); 0144 for( int i = 0; i < m_ribbon->count(); ++i ) //could be faster if done with iterator 0145 { 0146 QString name( qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->name() ); 0147 Column category = columnForName( name ); 0148 Qt::SortOrder sortOrder = qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->sortOrder(); 0149 scheme.addLevel( SortLevel( category, sortOrder ) ); 0150 } 0151 ModelStack::instance()->sortProxy()->updateSortMap( scheme ); 0152 0153 KConfigGroup config = Amarok::config( QStringLiteral("Playlist Sorting") ); 0154 config.writeEntry( "SortPath", sortPath() ); 0155 } 0156 0157 QString 0158 SortWidget::sortPath() const 0159 { 0160 QString path; 0161 for( int i = 0; i < m_ribbon->count(); ++i ) //could be faster if done with iterator 0162 { 0163 QString name( qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->name() ); 0164 Qt::SortOrder sortOrder = qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->sortOrder(); 0165 QString level = name + '_' + ( sortOrder ? "des" : "asc" ); 0166 path.append( ( i == m_ribbon->count() - 1 ) ? level : ( level + '-' ) ); 0167 } 0168 return path; 0169 } 0170 0171 void 0172 SortWidget::readSortPath( const QString &sortPath ) 0173 { 0174 trimToLevel(); 0175 0176 QStringList levels = sortPath.split( QLatin1Char('-') ); 0177 foreach( const QString &level, levels ) 0178 { 0179 QStringList levelParts = level.split( '_' ); 0180 /* 0181 * Check whether the configuration is valid. If indexOf 0182 * returns -1, the entry is corrupted. We can't use columnForName 0183 * here, as it will do a static_cast, which is UB when indexOf is -1 0184 * as there's no corresponding enum value 0185 * (C++ standard 5.2.9 Static cast [expr.static.cast] paragraph 7) 0186 */ 0187 if( levelParts.count() > 2 0188 || ( Playlist::PlaylistColumnInfos::internalNames(). 0189 indexOf( levelParts.value(0) ) == -1) ) 0190 warning() << "Playlist sorting load error: Invalid sort level " << level; 0191 else if( levelParts.value( 1 ) == QStringLiteral( "asc" ) ) 0192 addLevel( levelParts.value( 0 ), Qt::AscendingOrder ); 0193 else if( levelParts.value( 1 ) == QStringLiteral( "des" ) ) 0194 addLevel( levelParts.value( 0 ), Qt::DescendingOrder ); 0195 else 0196 warning() << "Playlist sorting load error: Invalid sort order for level " << level; 0197 } 0198 } 0199 0200 QString 0201 SortWidget::prettySortPath() const 0202 { 0203 QString prettyPath; 0204 for( int i = 0; i < m_ribbon->count(); ++i ) //could be faster if done with iterator 0205 { 0206 QString prettyName( qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->prettyName() ); 0207 Qt::SortOrder sortOrder = qobject_cast< BreadcrumbItem * >( m_ribbon->itemAt( i )->widget() )->sortOrder(); 0208 QString prettyLevel = prettyName + ( sortOrder ? "↓" : "↑" ); 0209 prettyPath.append( ( i == m_ribbon->count() - 1 ) ? prettyLevel : ( prettyLevel + " > " ) ); 0210 //TODO: see how this behaves on RTL systems 0211 } 0212 return prettyPath; 0213 } 0214 0215 }