playlist.cpp

来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· C++ 代码 · 共 2,005 行 · 第 1/5 页

CPP
2,005
字号
/* Copyright 2002-2004 Mark Kretschmann, Max Howell, Christian Muehlhaeuser * Copyright 2005-2006 Seb Ruiz, Mike Diehl, Ian Monroe, Gábor Lehel, Alexandre Pereira de Oliveira * Licensed as described in the COPYING file found in the root of this distribution * Maintainer: Max Howell <max.howell@methylblue.com> * NOTES * * The PlaylistWindow handles some Playlist events. Thanks! * This class has a QOBJECT but it's private so you can only connect via PlaylistWindow::PlaylistWindow * Mostly it's sensible to implement playlist functionality in this class * TODO Obtaining information about the playlist is currently hard, we need the playlist to be globally *      available and have some more useful public functions */#define DEBUG_PREFIX "Playlist"#include <config.h>#include "amarok.h"#include "amarokconfig.h"#include "app.h"#include "debug.h"#include "collectiondb.h"#include "collectionbrowser.h"#include "columnlist.h"#include "deletedialog.h"#include "enginecontroller.h"#include "expression.h"#include "k3bexporter.h"#include "metabundle.h"#include "mountpointmanager.h"#include "osd.h"#include "playerwindow.h"#include "playlistitem.h"#include "playlistbrowser.h"#include "playlistbrowseritem.h" //for stream editor dialog#include "playlistloader.h"#include "playlistselection.h"#include "queuemanager.h"#include "prettypopupmenu.h"#include "scriptmanager.h"#include "sliderwidget.h"#include "starmanager.h"#include "statusbar.h"       //for status messages#include "tagdialog.h"#include "threadmanager.h"#include "xspfplaylist.h"#include <cmath> //for pow() in playNextTrack()#include <qbuffer.h>#include <qclipboard.h>      //copyToClipboard(), slotMouseButtonPressed()#include <qcolor.h>#include <qevent.h>#include <qfile.h>           //undo system#include <qheader.h>         //eventFilter()#include <qlabel.h>          //showUsageMessage()#include <qpainter.h>#include <qpen.h>            //slotGlowTimer()#include <qsimplerichtext.h> //toolTipText()#include <qsortedlist.h>#include <qtimer.h>#include <qtooltip.h>#include <qvaluelist.h>      //addHybridTracks()#include <qvaluevector.h>    //playNextTrack()#include <qlayout.h>#include <kaction.h>#include <kapplication.h>#include <kcursor.h>         //setOverrideCursor()#include <kdialogbase.h>#include <kglobalsettings.h> //rename()#include <kiconeffect.h>#include <kiconloader.h>     //slotShowContextMenu()#include <kio/job.h>         //deleteSelectedFiles()#include <klineedit.h>       //setCurrentTrack()#include <klocale.h>#include <kmessagebox.h>#include <kpopupmenu.h>#include <krandomsequence.h> //random Mode#include <kstandarddirs.h>   //KGlobal::dirs()#include <kstdaction.h>#include <kstringhandler.h>  //::showContextMenu()#include <kurldrag.h>#include <cstdlib> // absextern "C"{    #if KDE_VERSION < KDE_MAKE_VERSION(3,3,91)    #include <X11/Xlib.h>    //ControlMask in contentsDragMoveEvent()    #endif}#include "playlist.h"namespace Amarok{    const DynamicMode *dynamicMode() { return Playlist::instance() ? Playlist::instance()->dynamicMode() : 0; }}typedef PlaylistIterator MyIt;///////////////////////////////////////////////////////////////////////////////////////////// CLASS TagWriter : Threaded tag-updating//////////////////////////////////////////////////////////////////////////////////////////class TagWriter : public ThreadManager::Job{ //TODO make this do all tags at once when you split playlist.cpp uppublic:    TagWriter( PlaylistItem*, const QString &oldTag, const QString &newTag, const int, const bool updateView = true );   ~TagWriter();    bool doJob();    void completeJob();private:    PlaylistItem* const m_item;    bool m_failed;    QString m_oldTagString;    QString m_newTagString;    int     m_tagType;    bool    m_updateView;};///////////////////////////////////////////////////////////////////////////////////////////// Glow//////////////////////////////////////////////////////////////////////////////////////////namespace Glow{    namespace Text    {        static float dr, dg, db;        static int    r, g, b;    }    namespace Base    {        static float dr, dg, db;        static int    r, g, b;    }    static const uint STEPS = 13;    static uint counter;    static QTimer timer;    inline void startTimer()    {        counter = 0;        timer.start( 40 );    }    inline void reset()    {        counter = 0;        timer.stop();    }}///////////////////////////////////////////////////////////////////////////////////////////// CLASS Playlist//////////////////////////////////////////////////////////////////////////////////////////QMutex* Playlist::s_dynamicADTMutex = new QMutex();Playlist *Playlist::s_instance = 0;Playlist::Playlist( QWidget *parent )        : KListView( parent, "ThePlaylist" )        , EngineObserver( EngineController::instance() )        , m_startupTime_t( QDateTime::currentDateTime().toTime_t() )        , m_oldestTime_t( CollectionDB::instance()->query( "SELECT MIN( createdate ) FROM statistics;" ).first().toInt() )        , m_currentTrack( 0 )        , m_marker( 0 )        , m_hoveredRating( 0 )        , m_firstColumn( 0 )        , m_totalCount( 0 )        , m_totalLength( 0 )        , m_selCount( 0 )        , m_selLength( 0 )        , m_visCount( 0 )        , m_visLength( 0 )        , m_total( 0 )        , m_itemCountDirty( false )        , m_undoButton( 0 )        , m_redoButton( 0 )        , m_clearButton( 0 )        , m_undoDir( Amarok::saveLocation( "undo/" ) )        , m_undoCounter( 0 )        , m_dynamicMode( 0 )        , m_stopAfterTrack( 0 )        , m_stopAfterMode( DoNotStop )        , m_showHelp( true )        , m_dynamicDirt( false )        , m_queueDirt( false )        , m_undoDirt( false )        , m_insertFromADT( 0 )        , m_itemToReallyCenter( 0 )        , m_renameItem( 0 )        , m_lockStack( 0 )        , m_columnFraction( PlaylistItem::NUM_COLUMNS, 0 )        , m_oldRandom( 0 )        , m_oldRepeat( 0 )        , m_playlistName( i18n( "Untitled" ) )        , m_proposeOverwriting( false )        , m_urlIndex( &PlaylistItem::url ){    s_instance = this;    connect( CollectionDB::instance(), SIGNAL(fileMoved(const QString&,            const QString&, const QString&)), SLOT(updateEntriesUrl(const QString&,            const QString&, const QString&)) );    connect( CollectionDB::instance(), SIGNAL(uniqueIdChanged(const QString&,            const QString&, const QString&)), SLOT(updateEntriesUniqueId(const QString&,            const QString&, const QString&)) );    connect( CollectionDB::instance(), SIGNAL(fileDeleted(const QString&,            const QString&)), SLOT(updateEntriesStatusDeleted(const QString&, const QString&)) );    connect( CollectionDB::instance(), SIGNAL(fileAdded(const QString&,            const QString&)), SLOT(updateEntriesStatusAdded(const QString&, const QString&)) );    connect( CollectionDB::instance(), SIGNAL(filesAdded(const QMap<QString,QString>&)),            SLOT(updateEntriesStatusAdded(const QMap<QString,QString>&)) );    initStarPixmaps();    EngineController* const ec = EngineController::instance();    connect( ec, SIGNAL(orderPrevious()), SLOT(playPrevTrack()) );    connect( ec, SIGNAL(orderNext( const bool )),     SLOT(playNextTrack( const bool )) );    connect( ec, SIGNAL(orderCurrent()),  SLOT(playCurrentTrack()) );    connect( this, SIGNAL( itemCountChanged( int, int, int, int, int, int ) ), ec, SLOT( playlistChanged() ) );    setShowSortIndicator( true );    setDropVisualizer( false );   //we handle the drawing for ourselves    setDropVisualizerWidth( 3 );    // FIXME: This doesn't work, and steals focus when an item is clicked twice.    //setItemsRenameable( true );    setAcceptDrops( true );    setSelectionMode( QListView::Extended );    setAllColumnsShowFocus( true );    //setItemMargin( 1 ); //aesthetics    setMouseTracking( true );    #if KDE_IS_VERSION( 3, 3, 91 )    setShadeSortColumn( true );    #endif    for( int i = 0; i < MetaBundle::NUM_COLUMNS; ++i )    {        addColumn( PlaylistItem::prettyColumnName( i ), 0 );        switch( i )        {            case PlaylistItem::Title:            case PlaylistItem::Artist:            case PlaylistItem::Composer:            case PlaylistItem::Year:            case PlaylistItem::Album:            case PlaylistItem::DiscNumber:            case PlaylistItem::Track:            case PlaylistItem::Bpm:            case PlaylistItem::Genre:            case PlaylistItem::Comment:            case PlaylistItem::Score:            case PlaylistItem::Rating:                setRenameable( i, true );                continue;            default:                setRenameable( i, false );        }    }    setColumnWidth( PlaylistItem::Title,  200 );    setColumnWidth( PlaylistItem::Artist, 100 );    setColumnWidth( PlaylistItem::Album,  100 );    setColumnWidth( PlaylistItem::Length, 80 );    if( AmarokConfig::showMoodbar() )        setColumnWidth( PlaylistItem::Mood, 120 );    if( AmarokConfig::useRatings() )        setColumnWidth( PlaylistItem::Rating, PlaylistItem::ratingColumnWidth() );    setColumnAlignment( PlaylistItem::Length,     Qt::AlignRight  );    setColumnAlignment( PlaylistItem::Track,      Qt::AlignCenter );    setColumnAlignment( PlaylistItem::DiscNumber, Qt::AlignCenter );    setColumnAlignment( PlaylistItem::Bpm,        Qt::AlignRight  );    setColumnAlignment( PlaylistItem::Year,       Qt::AlignCenter );    setColumnAlignment( PlaylistItem::Bitrate,    Qt::AlignCenter );    setColumnAlignment( PlaylistItem::SampleRate, Qt::AlignCenter );    setColumnAlignment( PlaylistItem::Filesize,   Qt::AlignCenter );    setColumnAlignment( PlaylistItem::Score,      Qt::AlignCenter );    setColumnAlignment( PlaylistItem::Type,       Qt::AlignCenter );    setColumnAlignment( PlaylistItem::PlayCount,  Qt::AlignCenter );    connect( this,     SIGNAL( doubleClicked( QListViewItem* ) ),             this,       SLOT( doubleClicked( QListViewItem* ) ) );    connect( this,     SIGNAL( returnPressed( QListViewItem* ) ),             this,       SLOT( activate( QListViewItem* ) ) );    connect( this,     SIGNAL( mouseButtonPressed( int, QListViewItem*, const QPoint&, int ) ),             this,       SLOT( slotMouseButtonPressed( int, QListViewItem*, const QPoint&, int ) ) );    connect( this,     SIGNAL( queueChanged(     const PLItemList &, const PLItemList & ) ),             this,       SLOT( slotQueueChanged( const PLItemList &, const PLItemList & ) ) );    connect( this,     SIGNAL( itemRenamed( QListViewItem*, const QString&, int ) ),             this,       SLOT( writeTag( QListViewItem*, const QString&, int ) ) );    connect( this,     SIGNAL( aboutToClear() ),             this,       SLOT( saveUndoState() ) );    connect( CollectionDB::instance(), SIGNAL( scoreChanged( const QString&, float ) ),             this,       SLOT( scoreChanged( const QString&, float ) ) );    connect( CollectionDB::instance(), SIGNAL( ratingChanged( const QString&, int ) ),             this,       SLOT( ratingChanged( const QString&, int ) ) );    connect( CollectionDB::instance(), SIGNAL( fileMoved( const QString&, const QString& ) ),             this,       SLOT( fileMoved( const QString&, const QString& ) ) );    connect( header(), SIGNAL( indexChange( int, int, int ) ),             this,       SLOT( columnOrderChanged() ) ),    connect( &Glow::timer, SIGNAL(timeout()), SLOT(slotGlowTimer()) );    KActionCollection* const ac = Amarok::actionCollection();    KAction *copy = KStdAction::copy( this, SLOT( copyToClipboard() ), ac, "playlist_copy" );    KStdAction::selectAll( this, SLOT( selectAll() ), ac, "playlist_select_all" );    m_clearButton = new KAction( i18n( "clear playlist", "&Clear" ), Amarok::icon( "playlist_clear" ), 0, this, SLOT( clear() ), ac, "playlist_clear" );    m_undoButton  = KStdAction::undo( this, SLOT( undo() ), ac, "playlist_undo" );    m_redoButton  = KStdAction::redo( this, SLOT( redo() ), ac, "playlist_redo" );    m_undoButton ->setIcon( Amarok::icon( "undo" ) );    m_redoButton ->setIcon( Amarok::icon( "redo" ) );    new KAction( i18n( "&Repopulate" ), Amarok::icon( "playlist_refresh" ), 0, this, SLOT( repopulate() ), ac, "repopulate" );    new KAction( i18n( "S&huffle" ), "rebuild", CTRL+Key_H, this, SLOT( shuffle() ), ac, "playlist_shuffle" );    KAction *gotoCurrent = new KAction( i18n( "&Go To Current Track" ), Amarok::icon( "music" ), CTRL+Key_J, this, SLOT( showCurrentTrack() ), ac, "playlist_show" );    new KAction( i18n( "&Remove Duplicate && Dead Entries" ), 0, this, SLOT( removeDuplicates() ), ac, "playlist_remove_duplicates" );    new KAction( i18n( "&Queue Selected Tracks" ), Amarok::icon( "queue_track" ), CTRL+Key_D, this, SLOT( queueSelected() ), ac, "queue_selected" );    KToggleAction *stopafter = new KToggleAction( i18n( "&Stop Playing After Track" ), Amarok::icon( "stop" ), CTRL+ALT+Key_V,                            this, SLOT( toggleStopAfterCurrentItem() ), ac, "stop_after" );    { // KAction idiocy -- shortcuts don't work until they've been plugged into a menu        KPopupMenu asdf;        copy->plug( &asdf );        stopafter->plug( &asdf );        gotoCurrent->plug( &asdf );        copy->unplug( &asdf );        stopafter->unplug( &asdf );        gotoCurrent->unplug( &asdf );    }    //ensure we update action enabled states when repeat Playlist is toggled    connect( ac->action( "repeat" ), SIGNAL(activated( int )), SLOT(updateNextPrev()) );    connect( ac->action( "repeat" ), SIGNAL( activated( int ) ), SLOT( generateInfo() ) );    connect( ac->action( "favor_tracks" ), SIGNAL( activated( int ) ), SLOT( generateInfo() ) );    connect( ac->action( "random_mode" ), SIGNAL( activated( int ) ), SLOT( generateInfo() ) );    // undostates are written in chronological order, so this is a clever way to get them back in the correct order :)    QStringList undos = m_undoDir.entryList( QString("*.xml"), QDir::Files, QDir::Time );    foreach( undos )        m_undoList.append( m_undoDir.absPath() + '/' + (*it) );    m_undoCounter = m_undoList.count();    m_undoButton->setEnabled( !m_undoList.isEmpty() );    m_redoButton->setEnabled( false );    engineStateChanged( EngineController::engine()->state() ); //initialise state of UI    paletteChange( palette() ); //sets up glowColors    restoreLayout( KGlobal::config(), "PlaylistColumnsLayout" );    // Sorting must be disabled when current.xml is being loaded. See BUG 113042    KListView::setSorting( NO_SORT ); //use base so we don't saveUndoState() too    setDynamicMode( 0 );    m_smartResizing = Amarok::config( "PlaylistWindow" )->readBoolEntry( "Smart Resizing", true );    columnOrderChanged();    //cause the column fractions to be updated, but in a safe way, ie no specific column    columnResizeEvent( header()->count(), 0, 0 );    //do after you resize all the columns    connect( header(), SIGNAL(sizeChange( int, int, int )), SLOT(columnResizeEvent( int, int, int )) );    connect( this, SIGNAL( contentsMoving( int, int ) ), SLOT( slotContentsMoving() ) );    connect( App::instance(), SIGNAL( useScores( bool ) ), this, SLOT( slotUseScores( bool ) ) );    connect( App::instance(), SIGNAL( useRatings( bool ) ), this, SLOT( slotUseRatings( bool ) ) );    connect( App::instance(), SIGNAL( moodbarPrefs(     bool, bool, int, bool ) ),             this,            SLOT(   slotMoodbarPrefs( bool, bool, int, bool ) ) );    Amarok::ToolTip::add( this, viewport() );    header()->installEventFilter( this );    renameLineEdit()->installEventFilter( this );    setTabOrderedRenaming( false );    m_filtertimer = new QTimer( this );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?