metabundle.cpp

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

CPP
1,884
字号
        case Bitrate:    setBitrate(    newText.toInt() );   break;        case SampleRate: setSampleRate( newText.toInt() );   break;        case Score:      setScore(      newText.toFloat() ); break;        case Rating:     setRating(     newText.toInt() );   break;        case PlayCount:  setPlayCount(  newText.toInt() );   break;        case LastPlayed: setLastPlay(   newText.toInt() );   break;        case Filesize:   setFilesize(   newText.toInt() );   break;        case Type:       setFileType(   newText.toInt() );   break;        default: warning() << "Tried to set the text of an immutable or nonexistent column! [" << column << endl;   }}QString MetaBundle::exactText( int column, bool ensureCached ) const{    switch( column )    {        case Filename:   return filename();        case Title:      return title();        case Artist:     return artist();        case AlbumArtist: return albumArtist();        case Composer:   return composer();        case Year:       return QString::number( year() );        case Album:      return album();        case DiscNumber: return QString::number( discNumber() );        case Track:      return QString::number( track() );        case Bpm:        return QString::number( bpm() );        case Genre:      return genre();        case Comment:    return comment();        case Directory:  return directory();        case Type:       return QString::number( fileType() );        case Length:     return QString::number( length() );        case Bitrate:    return QString::number( bitrate() );        case SampleRate: return QString::number( sampleRate() );        case Score:      return QString::number( score( ensureCached ) );        case Rating:     return QString::number( rating( ensureCached ) );        case PlayCount:  return QString::number( playCount( ensureCached ) );        case LastPlayed: return QString::number( lastPlay( ensureCached ) );        case Filesize:   return QString::number( filesize() );        case Mood:       return QString();        default: warning() << "Tried to get the text of a nonexistent column! [" << column << endl;    }    return QString(); //shouldn't happen}QString MetaBundle::prettyText( int column ) const{    QString text;    switch( column )    {        case Filename:   text = isFile() ? MetaBundle::prettyTitle(filename()) : url().prettyURL();  break;        case Title:      text = title().isEmpty() ? MetaBundle::prettyTitle( filename() ) : title(); break;        case Artist:     text = artist();                                                            break;        case AlbumArtist: text = albumArtist();                                                      break;        case Composer:   text = composer();                                                          break;        case Year:       text = year() ? QString::number( year() ) : QString::null;                  break;        case Album:      text = album();                                                             break;        case DiscNumber: text = discNumber() ? QString::number( discNumber() ) : QString::null;      break;        case Bpm:        text = bpm() ? QString::number( bpm() ) : QString::null;                    break;        case Track:      text = track() ? QString::number( track() ) : QString::null;                break;        case Genre:      text = genre();                                                             break;        case Comment:    text = comment();                                                           break;        case Directory:  text = url().isEmpty() ? QString() : directory();                           break;        case Type:       text = url().isEmpty() ? QString() : type();                                break;        case Length:     text = prettyLength( length(), true );                                      break;        case Bitrate:    text = prettyBitrate( bitrate() );                                          break;        case SampleRate: text = prettySampleRate();                                                  break;        case Score:      text = QString::number( static_cast<int>( score() ) );                      break;        case Rating:     text = prettyRating();                                                      break;        case PlayCount:  text = QString::number( playCount() );                                      break;        case LastPlayed: text = Amarok::verboseTimeSince( lastPlay() );                              break;        case Filesize:   text = prettyFilesize();                                                    break;        case Mood:          text = moodbar_const().state() == Moodbar::JobRunning ? i18n( "Calculating..." )               : moodbar_const().state() == Moodbar::JobQueued  ? i18n( "Queued..." )               : QString::null;        break;        default: warning() << "Tried to get the text of a nonexistent column!" << endl;              break;    }    return text.stripWhiteSpace();}bool MetaBundle::matchesSimpleExpression( const QString &expression, const QValueList<int> &columns ) const{    const QStringList terms = QStringList::split( ' ', expression.lower() );    bool matches = true;    for( uint x = 0; matches && x < terms.count(); ++x )    {        uint y = 0, n = columns.count();        for(; y < n; ++y )            if ( prettyText( columns[y] ).lower().contains( terms[x] ) )                break;        matches = ( y < n );    }    return matches;}void MetaBundle::reactToChanges( const QValueList<int>& columns){    // mark search dirty if we need to    for (uint i = 0; !m_isSearchDirty && i < columns.count(); i++)        if ((m_searchColumns & (1 << columns[i])) > 0)            m_isSearchDirty = true;}bool MetaBundle::matchesFast(const QStringList &terms, ColumnMask columnMask) const{    // simple search for rating, last played, etc. makes no sense and it hurts us a    // lot if we have to fetch it from the db. so zero them out    columnMask &= ~( 1<<Score | 1<<Rating | 1<<PlayCount | 1<<LastPlayed | 1<<Mood );    if (m_isSearchDirty || m_searchColumns != columnMask) {        // assert the size of ColumnMask is large enough. In the absence of        // a compile assert mechanism, this is pretty much as good for        // optimized code (ie, free)        if ( sizeof(ColumnMask) < (NUM_COLUMNS / 8) ) {            warning() << "ColumnMask is not big enough!\n";        }        // recompute search text        // There is potential for mishap here if matchesFast gets called from multiple        // threads, but it's *highly* unlikely that something bad will happen        m_isSearchDirty = false;        m_searchColumns = columnMask;        m_searchStr.setLength(0);        for (int i = 0; i < NUM_COLUMNS; i++) {            if ((columnMask & (1 << i)) > 0) {                if (!m_searchStr.isEmpty()) m_searchStr += ' ';                m_searchStr += prettyText(i).lower();            }        }    }    // now search    for (uint i = 0; i < terms.count(); i++) {        if (!m_searchStr.contains(terms[i])) return false;    }    return true;}bool MetaBundle::matchesExpression( const QString &expression, const QValueList<int> &defaultColumns ) const{    return matchesParsedExpression( ExpressionParser::parse( expression ), defaultColumns );}bool MetaBundle::matchesParsedExpression( const ParsedExpression &data, const QValueList<int> &defaults ) const{    for( uint i = 0, n = data.count(); i < n; ++i ) //check each part for matchiness    {        bool b = false; //whether at least one matches        for( uint ii = 0, count = data[i].count(); ii < count; ++ii )        {            expression_element e = data[i][ii];            int column = -1;            if( !e.field.isEmpty() )            {                QString field = e.field.lower();                column = columnIndex( field );                if( column == -1 )                {                    column = -2;                    if( field == "size" )                        field = "filesize";                    else if( field == "filetype" )                        field = "type";                    else if( field == "disc" )                        field = "discnumber";                    else                        column = -1;                    if( column == -2 )                        column = columnIndex( field );                }            }            if( column >= 0 ) //a field was specified and it exists            {                QString q = e.text, v = prettyText( column ).lower(), w = q.lower();                //q = query, v = contents of the field, w = match against it                bool condition; //whether it matches, not taking e.negateation into account                bool numeric;                switch( column )                {                    case Year:                    case DiscNumber:                    case Track:                    case Bpm:                    case Bitrate:                    case SampleRate:                    case Score:                    case PlayCount:                    case LastPlayed:                    case Filesize:                        numeric = true;                        break;                    default:                        numeric = false;                }                if( column == Filesize )                {                    v = QString::number( filesize() );                    if( w.endsWith( "m" ) )                        w = QString::number( w.left( w.length()-1 ).toLong() * 1024 * 1024 );                    else if( w.endsWith( "k" ) )                        w = QString::number( w.left( w.length()-1 ).toLong() * 1024 );                }                if( e.match == expression_element::More )                {                    if( numeric )                        condition = v.toInt() > w.toInt();                    else if( column == Rating )                        condition = v.toFloat() > w.toFloat();                    else if( column == Length )                    {                        int g = v.find( ':' ), h = w.find( ':' );                        condition = v.left( g ).toInt() > w.left( h ).toInt() ||                                    ( v.left( g ).toInt() == w.left( h ).toInt() &&                                      v.mid( g + 1 ).toInt() > w.mid( h + 1 ).toInt() );                    }                    else                        condition = v > w; //compare the strings                }                else if( e.match == expression_element::Less )                {                    if( numeric )                        condition = v.toInt() < w.toInt();                    else if( column == Rating )                        condition = v.toFloat() < w.toFloat();                    else if( column == Length )                    {                        int g = v.find( ':' ), h = w.find( ':' );                        condition = v.left( g ).toInt() < w.left( h ).toInt() ||                                    ( v.left( g ).toInt() == w.left( h ).toInt() &&                                      v.mid( g + 1 ).toInt() < w.mid( h + 1 ).toInt() );                    }                    else                        condition = v < w;                }                else                {                    if( numeric )                        condition = v.toInt() == w.toInt();                    else if( column == Rating )                        condition = v.toFloat() == w.toFloat();                    else if( column == Length )                    {                        int g = v.find( ':' ), h = w.find( ':' );                        condition = v.left( g ).toInt() == w.left( h ).toInt() &&                                    v.mid( g + 1 ).toInt() == w.mid( h + 1 ).toInt();                    }                    else                        condition = v.contains( q, false );                }                if( condition == ( e.negate ? false : true ) )                {                    b = true;                    break;                }            }            else //check just the default fields            {                for( int it = 0, end = defaults.size(); it != end; ++it )                {                    b = prettyText( defaults[it] ).contains( e.text, false ) == ( e.negate ? false : true );                    if( ( e.negate && !b ) || ( !e.negate && b ) )                        break;                }                if( b )                    break;            }        }        if( !b )            return false;    }    return true;}QStringMetaBundle::prettyTitle() const{    QString s = artist();    //NOTE this gets regressed often, please be careful!    //     whatever you do, handle the stream case, streams have no artist but have an excellent title    //FIXME doesn't work for resume playback    if( s.isEmpty() )        s = title();    else        s = i18n("%1 - %2").arg( artist(), title() );    if( s.isEmpty() ) s = prettyTitle( filename() );    return s;}QStringMetaBundle::veryNiceTitle() const{    QString s;    //NOTE I'm not sure, but the notes and FIXME's in the prettyTitle function should be fixed now.    //     If not then they do apply to this function also!    if( !title().isEmpty() )    {        if( !artist().isEmpty() )            s = i18n( "%1 by %2" ).arg( title(), artist() );        else            s = title();    }    else    {        s = prettyTitle( filename() );    }    return s;}QStringMetaBundle::prettyTitle( const QString &filename ) //static{    QString s = filename; //just so the code is more readable    //remove .part extension if it exists    if (s.endsWith( ".part" ))        s = s.left( s.length() - 5 );    //remove file extension, s/_/ /g and decode %2f-like sequences    s = s.left( s.findRev( '.' ) ).replace( '_', ' ' );    s = KURL::decode_string( s );    return s;}QStringMetaBundle::prettyLength( int seconds, bool showHours ) //static{    if( seconds > 0 ) return prettyTime( seconds, showHours );    if( seconds == Undetermined ) return "?";    if( seconds == Irrelevant  ) return "-";    return QString(); //Unavailable = ""}QStringMetaBundle::prettyTime( uint seconds, bool showHours ) //static{    QString s = QChar( ':' );    s.append( zeroPad( seconds % 60 ) ); //seconds    seconds /= 60;    if( showHours && seconds >= 60)    {        s.prepend( zeroPad( seconds % 60 ) ); //minutes        s.prepend( ':' );        seconds /= 60;    }    //don't zeroPad the last one, as it can be greater than 2 digits    s.prepend( QString::number( seconds ) ); //hours or minutes depending on above if block    return s;}QStringMetaBundle::veryPrettyTime( int time ){    if( time == Undetermined )        return i18n( "?" );

⌨️ 快捷键说明

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