File indexing completed on 2024-05-19 04:48:39

0001 /****************************************************************************************
0002  * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0003  * Copyright (c) 2010 Bart Cerneels <bart.cerneels@kde.org>                             *
0004  * Copyright (c) 2011 Ralf Engels <ralf-engels@gmx.de>                                  *
0005  *                                                                                      *
0006  * This program is free software; you can redistribute it and/or modify it under        *
0007  * the terms of the GNU General Public License as published by the Free Software        *
0008  * Foundation; either version 2 of the License, or (at your option) any later           *
0009  * version.                                                                             *
0010  *                                                                                      *
0011  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0013  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0014  *                                                                                      *
0015  * You should have received a copy of the GNU General Public License along with         *
0016  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0017  ****************************************************************************************/
0018 
0019 #define DEBUG_PREFIX "DynamicView"
0020 
0021 #include "DynamicView.h"
0022 #include "DynamicBiasDelegate.h"
0023 #include "DynamicBiasDialog.h"
0024 
0025 #include "core/support/Debug.h"
0026 #include "dynamic/Bias.h"
0027 #include "dynamic/DynamicModel.h"
0028 #include "dynamic/DynamicPlaylist.h"
0029 #include "dynamic/biases/SearchQueryBias.h"
0030 #include "playlist/PlaylistActions.h"
0031 
0032 #include "PopupDropperFactory.h"
0033 // #include "context/popupdropper/libpud/PopupDropperItem.h"
0034 // #include "context/popupdropper/libpud/PopupDropper.h"
0035 
0036 #include "PaletteHandler.h"
0037 
0038 #include <QAction>
0039 #include <QMenu>
0040 
0041 #include <QKeyEvent>
0042 #include <QMouseEvent>
0043 #include <QModelIndex>
0044 #include <QToolTip>
0045 
0046 PlaylistBrowserNS::DynamicView::DynamicView( QWidget *parent )
0047     : Amarok::PrettyTreeView( parent )
0048 {
0049     DEBUG_BLOCK
0050     setHeaderHidden( true );
0051     setSelectionMode( QAbstractItemView::SingleSelection );
0052     setModel( Dynamic::DynamicModel::instance() );
0053     setItemDelegate( new PlaylistBrowserNS::DynamicBiasDelegate(this) );
0054 
0055     setSelectionBehavior( QAbstractItemView::SelectItems );
0056     setDragDropMode( QAbstractItemView::DragDrop /*| QAbstractItemView::InternalMove*/ );
0057     setDragEnabled( true );
0058     setAcceptDrops( true );
0059     setDropIndicatorShown( true );
0060 
0061     setEditTriggers( QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed );
0062 
0063     // -- expanding the playlist should expand the whole tree
0064     connect( this, &DynamicView::expanded,
0065              this, &DynamicView::expandRecursive );
0066     connect( this, &DynamicView::collapsed,
0067              this, &DynamicView::collapseRecursive );
0068 }
0069 
0070 PlaylistBrowserNS::DynamicView::~DynamicView()
0071 {
0072 }
0073 
0074 void
0075 PlaylistBrowserNS::DynamicView::addPlaylist()
0076 {
0077     DEBUG_BLOCK;
0078     QModelIndex newIndex = Dynamic::DynamicModel::instance()->newPlaylist();
0079     selectionModel()->select( newIndex, QItemSelectionModel::ClearAndSelect );
0080 }
0081 
0082 void
0083 PlaylistBrowserNS::DynamicView::addToSelected()
0084 {
0085     DEBUG_BLOCK;
0086     QModelIndexList indexes = selectionModel()->selectedIndexes();
0087     if( indexes.isEmpty() )
0088         return;
0089 
0090     QModelIndex newIndex = Dynamic::DynamicModel::instance()->insertBias( 0, indexes.first(), Dynamic::BiasPtr( new Dynamic::SearchQueryBias() ) );
0091     selectionModel()->select( newIndex, QItemSelectionModel::ClearAndSelect );
0092 }
0093 
0094 void
0095 PlaylistBrowserNS::DynamicView::cloneSelected()
0096 {
0097     DEBUG_BLOCK;
0098     QModelIndexList indexes = selectionModel()->selectedIndexes();
0099     if( indexes.isEmpty() )
0100         return;
0101 
0102     QModelIndex newIndex = Dynamic::DynamicModel::instance()->cloneAt( indexes.first() );
0103     selectionModel()->select( newIndex, QItemSelectionModel::ClearAndSelect );
0104 }
0105 
0106 void
0107 PlaylistBrowserNS::DynamicView::editSelected()
0108 {
0109     DEBUG_BLOCK;
0110 
0111     QModelIndexList indexes = selectionModel()->selectedIndexes();
0112     if( indexes.isEmpty() )
0113         return;
0114 
0115     QVariant v = model()->data( indexes.first(), Dynamic::DynamicModel::PlaylistRole );
0116     if( v.isValid() )
0117     {
0118         edit( indexes.first() ); // call the normal editor
0119         return;
0120     }
0121 
0122     v = model()->data( indexes.first(), Dynamic::DynamicModel::BiasRole );
0123     if( v.isValid() )
0124     {
0125         Dynamic::AbstractBias* bias = qobject_cast<Dynamic::AbstractBias*>(v.value<QObject*>() );
0126         PlaylistBrowserNS::BiasDialog dialog( Dynamic::BiasPtr(bias), this);
0127         dialog.exec();
0128         return;
0129     }
0130 }
0131 
0132 void
0133 PlaylistBrowserNS::DynamicView::removeSelected()
0134 {
0135     DEBUG_BLOCK;
0136 
0137     QModelIndexList indexes = selectionModel()->selectedIndexes();
0138 
0139     if( indexes.isEmpty() )
0140         return;
0141 
0142     Dynamic::DynamicModel::instance()->removeAt( indexes.first() );
0143 }
0144 
0145 void
0146 PlaylistBrowserNS::DynamicView::expandRecursive(const QModelIndex &index)
0147 {
0148     for( int i = 0; i < index.model()->rowCount( index ); i++ )
0149         expand( index.model()->index( i, 0, index ) );
0150 }
0151 
0152 void
0153 PlaylistBrowserNS::DynamicView::collapseRecursive(const QModelIndex &index)
0154 {
0155     for( int i = 0; i < index.model()->rowCount( index ); i++ )
0156         collapse( index.model()->index( i, 0, index ) );
0157 }
0158 
0159 
0160 void
0161 PlaylistBrowserNS::DynamicView::keyPressEvent( QKeyEvent *event )
0162 {
0163     switch( event->key() )
0164     {
0165         case Qt::Key_Delete:
0166             removeSelected();
0167             return;
0168         case Qt::Key_Enter:
0169         case Qt::Key_Return:
0170             editSelected();
0171             return;
0172     }
0173     Amarok::PrettyTreeView::keyPressEvent( event );
0174 }
0175 
0176 void
0177 PlaylistBrowserNS::DynamicView::mouseDoubleClickEvent( QMouseEvent *event )
0178 {
0179     QModelIndex index = indexAt( event->pos() );
0180     if( index.isValid() )
0181     {
0182         // if the click was on a playlist
0183         QVariant v = model()->data( index, Dynamic::DynamicModel::PlaylistRole );
0184         if( v.isValid() )
0185         {
0186             Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
0187             model->setActivePlaylist( model->playlistIndex( qobject_cast<Dynamic::DynamicPlaylist*>(v.value<QObject*>() ) ) );
0188             The::playlistActions()->enableDynamicMode( true );
0189             event->accept();
0190             return;
0191         }
0192 
0193         // if the click was on a bias
0194         v = model()->data( index, Dynamic::DynamicModel::BiasRole );
0195         if( v.isValid() )
0196         {
0197             editSelected();
0198             event->accept();
0199             return;
0200         }
0201     }
0202 
0203     Amarok::PrettyTreeView::mouseDoubleClickEvent( event );
0204 }
0205 
0206 void
0207 PlaylistBrowserNS::DynamicView::contextMenuEvent( QContextMenuEvent *event )
0208 {
0209     QModelIndex index = indexAt( event->pos() );
0210     if( !index.isValid() )
0211         return;
0212 
0213     QList<QAction*> actions;
0214 
0215     // if the click was on a playlist
0216     QVariant v = model()->data( index, Dynamic::DynamicModel::PlaylistRole );
0217     if( v.isValid() )
0218     {
0219         Dynamic::DynamicPlaylist* playlist = qobject_cast<Dynamic::DynamicPlaylist*>(v.value<QObject*>() );
0220         Q_UNUSED( playlist );
0221         QAction* action;
0222 
0223         action = new QAction( QIcon::fromTheme( QStringLiteral("document-properties-amarok") ), i18n( "&Rename playlist" ), this );
0224         connect( action, &QAction::triggered, this, &DynamicView::editSelected );
0225         actions.append( action );
0226 
0227         action = new QAction( QIcon::fromTheme( QStringLiteral("document-new") ), i18n( "&Add new Bias" ), this );
0228         connect( action, &QAction::triggered, this, &DynamicView::addToSelected );
0229         actions.append( action );
0230 
0231         action = new QAction( QIcon::fromTheme( QStringLiteral("edit-copy") ), i18n( "&Clone Playlist" ), this );
0232         connect( action, &QAction::triggered, this, &DynamicView::cloneSelected );
0233         actions.append( action );
0234 
0235         action = new QAction( QIcon::fromTheme( QStringLiteral("edit-delete") ), i18n( "&Delete playlist" ), this );
0236         connect( action, &QAction::triggered, this, &DynamicView::removeSelected );
0237         actions.append( action );
0238     }
0239 
0240     // if the click was on a bias
0241     v = model()->data( index, Dynamic::DynamicModel::BiasRole );
0242     if( v.isValid() )
0243     {
0244         Dynamic::AbstractBias* bias = qobject_cast<Dynamic::AbstractBias*>(v.value<QObject*>() );
0245         Q_UNUSED( bias );
0246         Dynamic::AndBias* aBias = qobject_cast<Dynamic::AndBias*>(v.value<QObject*>() );
0247         QAction* action;
0248 
0249         action = new QAction( QIcon::fromTheme( QStringLiteral("document-properties-amarok") ), i18n( "&Edit bias..." ), this );
0250         connect( action, &QAction::triggered, this, &DynamicView::editSelected );
0251         actions.append( action );
0252 
0253         action = new QAction( QIcon::fromTheme( QStringLiteral("edit-copy") ), i18n( "&Clone bias" ), this );
0254         connect( action, &QAction::triggered, this, &DynamicView::cloneSelected );
0255         actions.append( action );
0256 
0257         // don't allow deleting a top bias unless it'a an and-bias containing at least one
0258         // other bias
0259         QModelIndex parentIndex = index.parent();
0260         QVariant parentV = model()->data( parentIndex, Dynamic::DynamicModel::PlaylistRole );
0261         if( !parentV.isValid() || (aBias && aBias->biases().count() > 0) )
0262         {
0263             action = new QAction( QIcon::fromTheme( QStringLiteral("edit-delete") ), i18n( "&Delete bias" ), this );
0264             connect( action, &QAction::triggered, this, &DynamicView::removeSelected );
0265             actions.append( action );
0266         }
0267 
0268         if( aBias )
0269         {
0270             action = new QAction( QIcon::fromTheme( QStringLiteral("document-new") ), i18n( "&Add new bias" ), this );
0271             connect( action, &QAction::triggered, this, &DynamicView::addToSelected );
0272             actions.append( action );
0273         }
0274     }
0275 
0276     if( actions.isEmpty() )
0277         return;
0278 
0279     QMenu menu;
0280     foreach( QAction *action, actions )
0281     {
0282         if( action )
0283             menu.addAction( action );
0284     }
0285 
0286     menu.exec( mapToGlobal( event->pos() ) );
0287 }
0288