Warning, file /multimedia/amarok/src/browsers/BrowserCategoryList.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) 2009 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 #define DEBUG_PREFIX "BrowserCategoryList" 0018 0019 #include "BrowserCategoryList.h" 0020 0021 #include "App.h" 0022 #include "core/support/Debug.h" 0023 #include "InfoProxy.h" 0024 #include "PaletteHandler.h" 0025 #include "widgets/PrettyTreeView.h" 0026 #include "widgets/PrettyTreeDelegate.h" 0027 #include "widgets/SearchWidget.h" 0028 0029 #include <Qt> 0030 #include <QComboBox> 0031 #include <QFile> 0032 #include <QStackedWidget> 0033 #include <QStandardPaths> 0034 #include <QTreeView> 0035 #include <QVBoxLayout> 0036 0037 #include <KLocalizedString> 0038 0039 0040 BrowserCategoryList::BrowserCategoryList( const QString &name, QWidget* parent, bool sort ) 0041 : BrowserCategory( name, parent ) 0042 , m_categoryListModel( new BrowserCategoryListModel( this ) ) 0043 , m_sorting( sort ) 0044 { 0045 // -- the widget stack 0046 m_widgetStack = new QStackedWidget( this ); 0047 0048 QWidget* mainWidget = new QWidget( m_widgetStack ); 0049 QVBoxLayout* vLayout = new QVBoxLayout( mainWidget ); 0050 mainWidget->setLayout( vLayout ); 0051 0052 // -- the search widget 0053 m_searchWidget = new SearchWidget( this, false ); 0054 m_searchWidget->setClickMessage( i18n( "Filter Music Sources" ) ); 0055 vLayout->addWidget( m_searchWidget ); 0056 0057 connect( m_searchWidget, &SearchWidget::filterChanged, this, &BrowserCategoryList::setFilter ); 0058 0059 // -- the main list view 0060 m_categoryListView = new Amarok::PrettyTreeView(); 0061 m_categoryListView->setFrameShape( QFrame::NoFrame ); 0062 0063 m_proxyModel = new BrowserCategoryListSortFilterProxyModel( this ); 0064 m_proxyModel->setSourceModel( m_categoryListModel ); 0065 0066 m_categoryListView->setItemDelegate( new PrettyTreeDelegate( m_categoryListView ) ); 0067 m_categoryListView->setHeaderHidden( true ); 0068 m_categoryListView->setRootIsDecorated( false ); 0069 m_categoryListView->setModel( m_proxyModel ); 0070 m_categoryListView->setMouseTracking ( true ); 0071 0072 if( sort ) 0073 { 0074 m_proxyModel->setSortRole( Qt::DisplayRole ); 0075 m_categoryListView->setSortingEnabled( true ); 0076 m_categoryListView->sortByColumn( 0, Qt::AscendingOrder ); 0077 } 0078 0079 connect( m_categoryListView, &Amarok::PrettyTreeView::activated, 0080 this, &BrowserCategoryList::categoryActivated ); 0081 0082 connect( m_categoryListView, &Amarok::PrettyTreeView::entered, 0083 this, &BrowserCategoryList::categoryEntered ); 0084 0085 vLayout->addWidget( m_categoryListView ); 0086 m_widgetStack->addWidget( mainWidget ); 0087 } 0088 0089 BrowserCategoryList::~BrowserCategoryList() 0090 { } 0091 0092 0093 void 0094 BrowserCategoryList::categoryActivated( const QModelIndex &index ) 0095 { 0096 DEBUG_BLOCK 0097 BrowserCategory * category = nullptr; 0098 0099 if( index.data( CustomCategoryRoles::CategoryRole ).canConvert<BrowserCategory *>() ) 0100 category = index.data( CustomCategoryRoles::CategoryRole ).value<BrowserCategory *>(); 0101 else 0102 return; 0103 0104 if( category ) 0105 { 0106 debug() << "Show service: " << category->name(); 0107 setActiveCategory( category ); 0108 } 0109 } 0110 0111 void 0112 BrowserCategoryList::home() 0113 { 0114 DEBUG_BLOCK 0115 if( activeCategory() ) 0116 { 0117 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( activeCategory() ); 0118 if( childList ) 0119 childList->home(); 0120 0121 activeCategory()->clearAdditionalItems(); 0122 m_widgetStack->setCurrentIndex( 0 ); 0123 0124 Q_EMIT( viewChanged() ); 0125 } 0126 } 0127 0128 0129 QMap<QString, BrowserCategory*> 0130 BrowserCategoryList::categories() 0131 { 0132 return m_categories; 0133 } 0134 0135 void 0136 BrowserCategoryList::addCategory( BrowserCategory *category ) 0137 { 0138 Q_ASSERT( category ); 0139 0140 category->setParentList( this ); 0141 0142 //insert service into service map 0143 category->setParent( this ); 0144 m_categories[category->name()] = category; 0145 m_categoryListModel->addCategory( category ); 0146 m_widgetStack->addWidget( category ); 0147 0148 //if this is also a category list, watch it for changes as we need to report 0149 //these down the tree 0150 0151 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( category ); 0152 if ( childList ) 0153 connect( childList, &BrowserCategoryList::viewChanged, this, &BrowserCategoryList::childViewChanged ); 0154 0155 category->polish(); // service categories do an additional construction in polish 0156 0157 if( m_sorting ) 0158 { 0159 m_proxyModel->sort( 0 ); 0160 } 0161 Q_EMIT( viewChanged() ); 0162 } 0163 0164 0165 void 0166 BrowserCategoryList::removeCategory( BrowserCategory *category ) 0167 { 0168 Q_ASSERT( category ); 0169 0170 if( m_widgetStack->indexOf( category ) == -1 ) 0171 return; // no such category 0172 0173 if( m_widgetStack->currentWidget() == category ) 0174 home(); 0175 0176 m_categories.remove( category->name() ); 0177 m_categoryListModel->removeCategory( category ); 0178 m_widgetStack->removeWidget( category ); 0179 delete category; 0180 0181 m_categoryListView->reset(); 0182 0183 Q_EMIT( viewChanged() ); 0184 } 0185 0186 BrowserCategory* 0187 BrowserCategoryList::activeCategory() const 0188 { 0189 return qobject_cast<BrowserCategory*>(m_widgetStack->currentWidget()); 0190 } 0191 0192 void BrowserCategoryList::setActiveCategory( BrowserCategory* category ) 0193 { 0194 DEBUG_BLOCK; 0195 0196 if( m_widgetStack->indexOf( category ) == -1 ) 0197 return; // no such category 0198 0199 if( !category || activeCategory() == category ) 0200 return; // nothing to do 0201 0202 if( activeCategory() ) 0203 activeCategory()->clearAdditionalItems(); 0204 category->setupAddItems(); 0205 0206 m_widgetStack->setCurrentWidget( category ); 0207 0208 Q_EMIT( viewChanged() ); 0209 } 0210 0211 void BrowserCategoryList::back() 0212 { 0213 DEBUG_BLOCK 0214 0215 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( activeCategory() ); 0216 if( childList ) 0217 { 0218 if( childList->activeCategory() != nullptr ) 0219 { 0220 childList->back(); 0221 return; 0222 } 0223 } 0224 0225 home(); 0226 } 0227 0228 void BrowserCategoryList::childViewChanged() 0229 { 0230 DEBUG_BLOCK 0231 Q_EMIT( viewChanged() ); 0232 } 0233 0234 QString BrowserCategoryList::navigate( const QString & target ) 0235 { 0236 DEBUG_BLOCK 0237 debug() << "target: " << target; 0238 QStringList categories = target.split( QLatin1Char('/') ); 0239 if ( categories.isEmpty() ) 0240 return QString(); 0241 0242 //remove our own name if present, before passing on... 0243 if ( categories.at( 0 ) == name() ) 0244 { 0245 debug() << "removing own name (" << categories.at( 0 ) << ") from path"; 0246 categories.removeFirst(); 0247 0248 if ( categories.isEmpty() ) 0249 { 0250 //nothing else left, make sure this category is visible 0251 home(); 0252 return QString(); 0253 } 0254 } 0255 0256 QString childName = categories.at( 0 ); 0257 debug() << "looking for child category " << childName; 0258 if ( !m_categories.contains( childName ) ) 0259 return target; 0260 0261 0262 debug() << "got it!"; 0263 setActiveCategory( m_categories[childName] ); 0264 0265 //check if this category is also BrowserCategoryList.target 0266 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( activeCategory() ); 0267 0268 if ( childList == nullptr ) 0269 { 0270 debug() << "child is not a list..."; 0271 if ( categories.size() > 1 ) 0272 { 0273 categories.removeFirst(); 0274 QString leftover = categories.join( QLatin1Char('/') ); 0275 return leftover; 0276 } 0277 return QString(); 0278 0279 } 0280 0281 //check if there are more arguments in the navigate string. 0282 if ( categories.size() == 1 ) 0283 { 0284 debug() << "Child is a list but path ends here..."; 0285 //only one name, but since the category we switched to is also 0286 //a category list, make sure that it is reset to home 0287 childList->home(); 0288 return QString(); 0289 } 0290 0291 categories.removeFirst(); 0292 debug() << "passing remaining path to child: " << categories.join( QLatin1Char('/') ); 0293 return childList->navigate( categories.join( QLatin1Char('/') ) ); 0294 0295 } 0296 0297 QString BrowserCategoryList::path() 0298 { 0299 DEBUG_BLOCK 0300 QString pathString = name(); 0301 0302 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( activeCategory() ); 0303 0304 if( childList ) 0305 pathString += '/' + childList->path(); 0306 else if( activeCategory() ) 0307 pathString += '/' + activeCategory()->name(); 0308 0309 debug() << "path: " << pathString; 0310 return pathString; 0311 } 0312 0313 void BrowserCategoryList::categoryEntered( const QModelIndex & index ) 0314 { 0315 //get the long description for this item and pass it to info proxy. 0316 0317 BrowserCategory *category = nullptr; 0318 0319 if ( index.data( CustomCategoryRoles::CategoryRole ).canConvert<BrowserCategory *>() ) 0320 category = index.data( CustomCategoryRoles::CategoryRole ).value<BrowserCategory *>(); 0321 else 0322 return; 0323 0324 if( category ) 0325 { 0326 0327 //instead of just throwing out raw text, let's format the long description and the 0328 //icon into a nice html page. 0329 0330 if ( m_infoHtmlTemplate.isEmpty() ) 0331 { 0332 0333 QString dataPath = QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/data/"), QStandardPaths::LocateDirectory ); 0334 0335 //load html 0336 QString htmlPath = dataPath + "/hover_info_template.html"; 0337 QFile file( htmlPath ); 0338 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text) ) 0339 { 0340 debug() << "error opening file:" << file.fileName() << "Error: " << file.error(); 0341 return; 0342 } 0343 m_infoHtmlTemplate = file.readAll(); 0344 file.close(); 0345 0346 m_infoHtmlTemplate.replace( QLatin1String("{background_color}"), The::paletteHandler()->highlightColor().lighter( 150 ).name() ); 0347 m_infoHtmlTemplate.replace( QLatin1String("{border_color}"), The::paletteHandler()->highlightColor().lighter( 150 ).name() ); 0348 m_infoHtmlTemplate.replace( QLatin1String("{text_color}"), pApp->palette().brush( QPalette::Text ).color().name() ); 0349 QColor highlight( pApp->palette().highlight().color() ); 0350 highlight.setHsvF( highlight.hueF(), 0.3, .95, highlight.alphaF() ); 0351 m_infoHtmlTemplate.replace( QLatin1String("{header_background_color}"), highlight.name() ); 0352 0353 } 0354 0355 QString currentHtml = m_infoHtmlTemplate; 0356 0357 currentHtml.replace( QLatin1String("%%NAME%%"), category->prettyName() ); 0358 currentHtml.replace( QLatin1String("%%DESCRIPTION%%"), category->longDescription() ); 0359 currentHtml.replace( QLatin1String("%%IMAGE_PATH%%"), "file://" + category->imagePath() ); 0360 0361 QVariantMap variantMap; 0362 variantMap[QStringLiteral("main_info")] = QVariant( currentHtml ); 0363 The::infoProxy()->setInfo( variantMap ); 0364 } 0365 } 0366 0367 QString BrowserCategoryList::css() 0368 { 0369 QString style = 0370 "<style type='text/css'>" 0371 "body" 0372 "{" 0373 " text-align:center;" 0374 " background-color: {background_color};" 0375 "}" 0376 "#main" 0377 " {" 0378 " text-align: center;" 0379 " }" 0380 "" 0381 "#text-border" 0382 " {" 0383 " display: block;" 0384 " margin-left: 0;" 0385 " margin-right: 0;" 0386 " padding: 4px;" 0387 " border: 4px solid {border_color};" 0388 " -webkit-border-radius: 4px;" 0389 " -khtml-border-radius: 4px;" 0390 " -moz-border-radius: 4px;" 0391 " border-radius: 4px;" 0392 " font-size: 94%;" 0393 " text-align: center;" 0394 " word-wrap: normal;" 0395 " background-color: {content_background_color};" 0396 " color: {text_color};" 0397 " }" 0398 "</style>"; 0399 0400 return style; 0401 } 0402 0403 BrowserCategory *BrowserCategoryList::activeCategoryRecursive() 0404 { 0405 BrowserCategory *category = activeCategory(); 0406 0407 if( !category ) 0408 return this; 0409 0410 BrowserCategoryList *childList = qobject_cast<BrowserCategoryList*>( category ); 0411 if( childList ) 0412 return childList->activeCategoryRecursive(); 0413 0414 return category; 0415 } 0416 0417 void BrowserCategoryList::setFilter( const QString &filter ) 0418 { 0419 m_proxyModel->setFilterFixedString( filter ); 0420 } 0421