aboutsummaryrefslogblamecommitdiff
path: root/src/plugins/Input/aac/aacfile.cpp
blob: 6d1a67f487441cdb10f4261f50456f16cfa8f2fa (plain) (tree)




















                                                                             

                     





                      
                            


                                                                                                                     
                                             
 
                      

                  
                     
                
















                                                           
 

                                            
     
                                    




                                                    
                         














                                                                                   
                         
     


                   
  










                          




                             









                                                       

                         
                                                


                             





























                                                                                                 
                                                                   

















                                                                           
                                                  










                                                                       
 
                          
 














                                                           
                    














                                                                          
 
 








                                                                         
 










                                                                                
 
/***************************************************************************
 *   Copyright (C) 2008 by Ilya Kotov                                      *
 *   forkotov02@hotmail.ru                                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QIODevice>
#include <QBuffer>
#include <QTextCodec>

#include <neaacdec.h>

#include "aacfile.h"

#define MAX_CHANNELS 6
#define AAC_BUFFER_SIZE 4096

static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0};

AACFile::AACFile(QIODevice *i, bool metaData)
{
    m_isValid = false;
    m_length = 0;
    m_bitrate = 0;
    m_samplerate = 0;
    m_input = i;
    uchar buf[AAC_BUFFER_SIZE];
    qint64 buf_at = i->peek((char *) buf, AAC_BUFFER_SIZE);

    int tag_size = 0;
    if (!memcmp(buf, "ID3", 3)) //TODO parse id3 tag
    {
        /* high bit is not used */
        tag_size = (buf[6] << 21) | (buf[7] << 14) |
                   (buf[8] <<  7) | (buf[9] <<  0);

        tag_size += 10;
        if (buf_at - tag_size < 4)
        {
            qWarning("AACFile: invalid tag size");
            return;
        }
        memmove (buf, buf + tag_size, buf_at - tag_size);

        if (metaData)
            parseID3v2(); //parse id3v2 tags
    }
    //try to determnate header type;
    if (buf[0] == 0xff && ((buf[1] & 0xf6) == 0xf0))
    {
        qDebug("AACFile: ADTS header found");
        if (!i->isSequential())
            parseADTS();
        m_isValid = true;
    }
    else if (memcmp(buf, "ADIF", 4) == 0)
    {
        qDebug("AACFile: ADIF header found");
        int skip_size = (buf[4] & 0x80) ? 9 : 0;
        m_bitrate = ((buf[4 + skip_size] & 0x0F)<<19) |
                    (buf[5 + skip_size]<<11) |
                    (buf[6 + skip_size]<<3) |
                    (buf[7 + skip_size] & 0xE0);

        if (!i->isSequential ())
            m_length = (qint64) (((float)i->size()*8.f)/((float)m_bitrate) + 0.5f);
        else
            m_length = 0;
        m_bitrate = (int)((float)m_bitrate/1000.0f + 0.5f);
        m_isValid = true;
    }
}

AACFile::~AACFile()
{}

qint64 AACFile::length()
{
    return m_length;
}

quint32 AACFile::bitrate()
{
    return m_bitrate;
}

quint32 AACFile::samplerate()
{
    return m_samplerate;
}

bool AACFile::isValid()
{
    return m_isValid;
}

const QMap<Qmmp::MetaData, QString> AACFile::metaData()
{
    return m_metaData;
}

void AACFile::parseADTS()
{
    uchar buf[FAAD_MIN_STREAMSIZE*MAX_CHANNELS];
    qint64 buf_at = 0;
    int frames, frame_length;
    int t_framelength = 0;
    float frames_per_sec, bytes_per_frame;
    qint64 pos = m_input->pos();

    m_input->seek(0);

    buf_at = m_input->read((char *)buf, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);

    for (int i = 0; i < buf_at - 1; i++)
    {
        if (buf[i] == 0xff && (buf[i+1]&0xf6) == 0xf0)
        {
            memmove (buf, buf + i, buf_at - i);
            buf_at -= i;
            break;
        }
    }

    /* Read all frames to ensure correct time and bitrate */
    for (frames = 0; /* */; frames++)
    {
        //qDebug("frame header = %d", buf[0]);
        buf_at += m_input->read((char *)buf + buf_at, FAAD_MIN_STREAMSIZE*MAX_CHANNELS - buf_at);

        if (buf_at > 7)
        {
            /* check syncword */
            if (!((buf[0] == 0xFF)&&((buf[1] & 0xF6) == 0xF0)))
                break;

            if (frames == 0)
                m_samplerate = adts_sample_rates[(buf[2]&0x3c)>>2];

            frame_length = ((((unsigned int)buf[3] & 0x3)) << 11)
                           | (((unsigned int)buf[4]) << 3) | (buf[5] >> 5);

            t_framelength += frame_length;

            if (frame_length > buf_at)
                break;

            buf_at -= frame_length;
            memmove(buf, buf + frame_length, buf_at);
        }
        else
        {
            break;
        }
    }
    m_input->seek(pos);
    frames_per_sec = (float) m_samplerate/1024.0f;
    if (frames != 0)
        bytes_per_frame = (float)t_framelength/(float)(frames*1000);
    else
        bytes_per_frame = 0;
    m_bitrate = (quint32)(8. * bytes_per_frame * frames_per_sec + 0.5);

    if (frames_per_sec != 0)
        m_length = frames/frames_per_sec;
    else
        m_length = 1;
}

void AACFile::parseID3v2()
{
    QByteArray array = m_input->peek(2048);
    int offset = array.indexOf("ID3");
    if (offset < 0)
        return;
    ID3v2Tag taglib_tag(&array, offset);
    if (taglib_tag.isEmpty())
        return;

    TagLib::String album = taglib_tag.album();
    TagLib::String artist = taglib_tag.artist();
    TagLib::String comment = taglib_tag.comment();
    TagLib::String genre = taglib_tag.genre();
    TagLib::String title = taglib_tag.title();

    QTextCodec *codec = QTextCodec::codecForName ("UTF-8");
    bool utf = true;

    m_metaData.insert(Qmmp::ALBUM,
                      codec->toUnicode(album.toCString(utf)).trimmed());
    m_metaData.insert(Qmmp::ARTIST,
                      codec->toUnicode(artist.toCString(utf)).trimmed());
    m_metaData.insert(Qmmp::COMMENT,
                      codec->toUnicode(comment.toCString(utf)).trimmed());
    m_metaData.insert(Qmmp::GENRE,
                      codec->toUnicode(genre.toCString(utf)).trimmed());
    m_metaData.insert(Qmmp::TITLE,
                      codec->toUnicode(title.toCString(utf)).trimmed());
    m_metaData.insert(Qmmp::YEAR,
                      QString::number(taglib_tag.year()));
    m_metaData.insert(Qmmp::TRACK,
                      QString::number(taglib_tag.track()));
}

ID3v2Tag::ID3v2Tag(QByteArray *array, long offset) : TagLib::ID3v2::Tag()
{
    m_buf = new QBuffer(array);
    m_buf->open(QIODevice::ReadOnly);
    m_offset = offset;
    read();
}

void ID3v2Tag::read ()
{
    m_buf->seek(m_offset);
    uint to_read = TagLib::ID3v2::Header::size();
    if (to_read > AAC_BUFFER_SIZE - uint(m_offset))
        return;
    header()->setData(TagLib::ByteVector(m_buf->read(to_read).data(), to_read));
    to_read = header()->tagSize();
    if (!to_read ||  AAC_BUFFER_SIZE < m_offset + TagLib::ID3v2::Header::size())
        return;
    QByteArray array = m_buf->read(to_read);
    TagLib::ByteVector v(array.data(), array.size());
    parse(v);
}
"hl opt">); QAction* albumAct = sort_mode_menu->addAction (tr ("By Album")); connect (albumAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (albumAct, PlayListModel::ALBUM); QAction* discnumberAct = sort_mode_menu->addAction (tr ("By Disc Number")); connect (discnumberAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (discnumberAct, PlayListModel::DISCNUMBER); QAction* artistAct = sort_mode_menu->addAction (tr ("By Artist")); connect (artistAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (artistAct, PlayListModel::ARTIST); QAction* albumArtistAct = sort_mode_menu->addAction (tr ("By Album Artist")); connect (albumArtistAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (albumArtistAct, PlayListModel::ALBUMARTIST); QAction* nameAct = sort_mode_menu->addAction (tr ("By Filename")); connect (nameAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (nameAct, PlayListModel::FILENAME); QAction* pathnameAct = sort_mode_menu->addAction (tr ("By Path + Filename")); connect (pathnameAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (pathnameAct, PlayListModel::PATH_AND_FILENAME); QAction* dateAct = sort_mode_menu->addAction (tr ("By Date")); connect (dateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (dateAct, PlayListModel::DATE); QAction* trackAct = sort_mode_menu->addAction (tr("By Track Number")); connect (trackAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (trackAct, PlayListModel::TRACK); QAction* fileCreationDateAct = sort_mode_menu->addAction (tr("By File Creation Date")); connect (fileCreationDateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (fileCreationDateAct, PlayListModel::FILE_CREATION_DATE); QAction* fileModificationDateAct = sort_mode_menu->addAction (tr("By File Modification Date")); connect (fileModificationDateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (fileModificationDateAct, PlayListModel::FILE_MODIFICATION_DATE); QAction* groupAct = sort_mode_menu->addAction (tr("By Group")); connect (groupAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (groupAct, PlayListModel::GROUP); connect (signalMapper, SIGNAL (mapped (int)), m_pl_manager, SLOT (sort (int))); m_sortMenu->addMenu (sort_mode_menu); sort_mode_menu = new QMenu (tr("Sort Selection"), m_sortMenu); sort_mode_menu->setIcon(QIcon::fromTheme("view-sort-ascending")); signalMapper = new QSignalMapper (this); titleAct = sort_mode_menu->addAction (tr ("By Title")); connect (titleAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (titleAct, PlayListModel::TITLE); albumAct = sort_mode_menu->addAction (tr ("By Album")); connect (albumAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (albumAct, PlayListModel::ALBUM); discnumberAct = sort_mode_menu->addAction (tr ("By Disc Number")); connect (discnumberAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (discnumberAct, PlayListModel::DISCNUMBER); artistAct = sort_mode_menu->addAction (tr ("By Artist")); connect (artistAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (artistAct, PlayListModel::ARTIST); albumArtistAct = sort_mode_menu->addAction (tr ("By Album Artist")); connect (albumArtistAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (albumArtistAct, PlayListModel::ALBUMARTIST); nameAct = sort_mode_menu->addAction (tr ("By Filename")); connect (nameAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (nameAct, PlayListModel::FILENAME); pathnameAct = sort_mode_menu->addAction (tr ("By Path + Filename")); connect (pathnameAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (pathnameAct, PlayListModel::PATH_AND_FILENAME); dateAct = sort_mode_menu->addAction (tr ("By Date")); connect (dateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (dateAct, PlayListModel::DATE); trackAct = sort_mode_menu->addAction (tr ("By Track Number")); connect (trackAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (trackAct, PlayListModel::TRACK); fileCreationDateAct = sort_mode_menu->addAction (tr("By File Creation Date")); connect (fileCreationDateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (fileCreationDateAct, PlayListModel::FILE_CREATION_DATE); fileModificationDateAct = sort_mode_menu->addAction (tr("By File Modification Date")); connect (fileModificationDateAct, SIGNAL (triggered (bool)), signalMapper, SLOT (map())); signalMapper->setMapping (fileModificationDateAct, PlayListModel::FILE_MODIFICATION_DATE); connect (signalMapper, SIGNAL (mapped (int)), m_pl_manager, SLOT (sortSelection (int))); m_sortMenu->addMenu (sort_mode_menu); m_sortMenu->addSeparator(); m_sortMenu->addAction (QIcon::fromTheme("media-playlist-shuffle"), tr("Randomize List"), m_pl_manager, SLOT(randomizeList())); m_sortMenu->addAction (QIcon::fromTheme("view-sort-descending"), tr("Reverse List"), m_pl_manager, SLOT(reverseList())); m_sortMenu->addAction(SET_ACTION(ActionManager::PL_GROUP_TRACKS, m_ui_settings, SLOT(setGroupsEnabled(bool)))); m_sortMenu->addAction(ACTION(ActionManager::PL_SHOW_HEADER)); ACTION(ActionManager::PL_GROUP_TRACKS)->setChecked(m_ui_settings->isGroupsEnabled()); //playlist context menu m_listWidget->menu()->addAction(ActionManager::instance()->action(ActionManager::PL_SHOW_INFO)); m_listWidget->menu()->addSeparator(); m_listWidget->menu()->addActions (m_subMenu->actions().mid(0,3)); //use 3 first actions m_listWidget->menu()->addMenu(UiHelper::instance()->createMenu(UiHelper::PLAYLIST_MENU, tr("Actions"), this)); m_listWidget->menu()->addSeparator(); m_listWidget->menu()->addAction(SET_ACTION(ActionManager::PL_ENQUEUE, m_pl_manager, SLOT(addToQueue()))); //select menu m_selectMenu->addAction(SET_ACTION(ActionManager::PL_INVERT_SELECTION, m_pl_manager, SLOT(invertSelection ()))); m_selectMenu->addSeparator(); m_selectMenu->addAction(SET_ACTION(ActionManager::PL_CLEAR_SELECTION, m_pl_manager, SLOT(clearSelection ()))); m_selectMenu->addAction(SET_ACTION(ActionManager::PL_SELECT_ALL, m_pl_manager, SLOT(selectAll()))); //Playlist Menu m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_NEW, m_pl_manager, SLOT(createPlayList()))); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_CLOSE, this, SLOT(deletePlaylist()))); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_RENAME, this, SLOT(renamePlaylist()))); m_playlistMenu->addSeparator(); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_LOAD, this, SIGNAL(loadPlaylist()))); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_SAVE, this, SIGNAL(savePlaylist()))); m_playlistMenu->addSeparator(); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_SELECT_NEXT, m_pl_manager, SLOT(selectNextPlayList()))); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_SELECT_PREVIOUS, m_pl_manager, SLOT(selectPreviousPlayList()))); m_playlistMenu->addAction(SET_ACTION(ActionManager::PL_SHOW_MANAGER, this, SLOT(showPlayLists()))); } void PlayList::closeEvent (QCloseEvent *e) { writeSettings(); if (e->spontaneous ()) parentWidget()->close(); } void PlayList::paintEvent (QPaintEvent *) { int sx = (width()-275*m_ratio) /25; int sy = (height()-116*m_ratio) /29; QPainter paint(this); drawPixmap (&paint, 0, 20*m_ratio, m_skin->getPlPart (Skin::PL_LFILL)); for (int i = 1; i<sy+2*m_ratio; i++) { drawPixmap (&paint, 0, 20*m_ratio+29*i, m_skin->getPlPart (Skin::PL_LFILL)); } drawPixmap (&paint, 0, 78*m_ratio+29*sy, m_skin->getPlPart (Skin::PL_LSBAR)); for (int i = 0; i<sx; i++) { drawPixmap (&paint, 125*m_ratio+i*25,78*m_ratio+sy*29,m_skin->getPlPart (Skin::PL_SFILL1)); } drawPixmap (&paint,125*m_ratio+sx*25,78*m_ratio+sy*29,m_skin->getPlPart (Skin::PL_RSBAR)); } void PlayList::drawPixmap (QPainter *painter, int x, int y, const QPixmap &pix) { style()->drawItemPixmap(painter, QRect(x, y, pix.width(), pix.height()), Qt::AlignCenter, pix); } void PlayList::resizeEvent (QResizeEvent *) { updatePositions(); } void PlayList::mousePressEvent (QMouseEvent *e) { Q_UNUSED(e); if (m_resizeWidget->underMouse()) { m_resize = true; setCursor (m_skin->getCursor (Skin::CUR_PSIZE)); } else m_resize = false; } void PlayList::mouseMoveEvent (QMouseEvent *e) { if (m_resize) { #ifdef Q_OS_WIN int sx = (width()-275) /25; int sy = (height()-116) /29; if(width() < e->x() - 14) sx++; else if(width() > e->x() + 14) sx--; if(height() < e->y() - 14) sy++; else if(height() > e->y() + 14) sy--; resize (275+25*sx,116+29*sy); #else #ifdef Q_WS_X11 //avoid right corner moving during resize if(layoutDirection() == Qt::RightToLeft) WindowSystem::revertGravity(winId()); #endif resize (e->x() +25, e->y() +25); #endif } } void PlayList::mouseReleaseEvent (QMouseEvent *) { setCursor (m_skin->getCursor (Skin::CUR_PNORMAL)); /*if (m_resize) m_listWidget->updateList();*/ m_resize = false; Dock::instance()->updateDock(); } void PlayList::changeEvent (QEvent * event) { if (event->type() == QEvent::ActivationChange) { m_titleBar->setActive (isActiveWindow()); } } void PlayList::readSettings() { QSettings settings (Qmmp::configFile(), QSettings::IniFormat); if (settings.value("Skinned/pl_show_plalists", false).toBool()) { if(!m_pl_selector) m_pl_selector = new PlayListSelector(m_pl_manager, this); m_pl_selector->show(); m_listWidget->menu()->insertMenu(m_listWidget->menu()->actions().at(2),m_copySelectedMenu); } else { if(m_pl_selector) { m_pl_selector->deleteLater(); m_listWidget->menu()->removeAction(m_copySelectedMenu->menuAction()); } m_pl_selector = 0; } if (m_update) { m_listWidget->readSettings(); m_titleBar->readSettings(); if(m_pl_selector) m_pl_selector->readSettings(); updatePositions(); } else { move (settings.value ("Skinned/pl_pos", QPoint (100, 332)).toPoint()); //position m_update = true; } } #ifdef Q_WS_X11 bool PlayList::event (QEvent *event) { if(event->type() == QEvent::WinIdChange || event->type() == QEvent::Show) { WindowSystem::ghostWindow(winId()); WindowSystem::setWinHint(winId(), "playlist", "Qmmp"); } return QWidget::event(event); } #endif void PlayList::writeSettings() { QSettings settings (Qmmp::configFile(), QSettings::IniFormat); //position settings.setValue ("Skinned/pl_pos", this->pos()); } void PlayList::showAddMenu() { m_addMenu->exec (m_buttonAdd->mapToGlobal (QPoint (0,0))); } void PlayList::showSubMenu() { m_subMenu->exec (m_buttonSub->mapToGlobal (QPoint (0,0))); } void PlayList::showSelectMenu() { m_selectMenu->exec (m_selectButton->mapToGlobal (QPoint (0,0))); } void PlayList::showSortMenu() { m_sortMenu->exec (m_sortButton->mapToGlobal (QPoint (0,0))); } QString PlayList::formatTime (int sec) { if(sec >= 3600) sec /= 60; return QString("%1:%2").arg(sec/60, 2, 10, QChar('0')).arg(sec%60, 2, 10, QChar('0')); } void PlayList::setTime(qint64 time) { if (time < 0) m_current_time->display ("--:--"); else m_current_time->display (formatTime (time/1000)); m_current_time->update(); if (SoundCore::instance()) { QString str_length = formatTime (m_pl_manager->currentPlayList()->totalLength()) + "/" + formatTime (SoundCore::instance()->totalTime()/1000); m_length_totalLength->display (str_length); m_length_totalLength->update(); } } void PlayList::showPlaylistMenu() { m_playlistMenu->exec (m_playlistButton->mapToGlobal (QPoint (0,0))); } void PlayList::keyPressEvent (QKeyEvent *ke) { m_keyboardManager->handleKeyPress (ke); } void PlayList::updateSkin() { setCursor(m_skin->getCursor(Skin::CUR_PNORMAL)); // TODO shaded m_resizeWidget->setCursor(m_skin->getCursor (Skin::CUR_PSIZE)); if(m_ratio != m_skin->ratio()) { if(m_skin->ratio() < m_ratio) { setMinimumSize (275*m_skin->ratio(), (m_shaded ? 14 : 116)*m_skin->ratio()); resize(width()*m_skin->ratio() / m_ratio, height()*m_skin->ratio() / m_ratio); } m_ratio = m_skin->ratio(); } setMinimalMode(m_shaded); } void PlayList::deletePlaylist() { m_pl_manager->removePlayList(m_pl_manager->selectedPlayList()); } void PlayList::renamePlaylist() { bool ok = false; QString name = QInputDialog::getText (this, tr("Rename Playlist"), tr("Playlist name:"), QLineEdit::Normal, m_pl_manager->selectedPlayList()->name(), &ok); if(ok) m_pl_manager->selectedPlayList()->setName(name); } void PlayList::showPlayLists() { if(!m_pl_browser) { m_pl_browser = new PlayListBrowser(m_pl_manager, this); m_pl_browser->show(); } else m_pl_browser->show(); } void PlayList::generateCopySelectedMenu() { m_copySelectedMenu->clear(); QAction* action = m_copySelectedMenu->addAction (tr ("&New PlayList")); action->setIcon(QIcon::fromTheme("document-new")); m_copySelectedMenu->addSeparator(); foreach(QString name, m_pl_manager->playListNames()) { action = m_copySelectedMenu->addAction("&"+name.replace("&", "&&")); } } void PlayList::copySelectedMenuActionTriggered(QAction *action) { PlayListModel *targetPlayList = 0; QString actionText=action->text(); if(action == m_copySelectedMenu->actions().at(0))//actionText == tr ("&New PlayList")) { targetPlayList = m_pl_manager->createPlayList(m_pl_manager->selectedPlayList()->name()); } else { actionText.remove(0,1).replace("&&", "&"); foreach(PlayListModel *model, m_pl_manager->playLists()) { //if("&" + model->name().replace("&", "&&") == actionText) if(model->name() == actionText) { targetPlayList = model; break; } } } if(!targetPlayList) { qWarning("Error: Cannot find target playlist '%s'",qPrintable(actionText)); return; } QList <PlayListTrack *> theCopy; foreach(PlayListTrack *track, m_pl_manager->selectedPlayList()->selectedTracks()) { PlayListTrack *newItem = new PlayListTrack(*track); theCopy << newItem; } targetPlayList->add(theCopy); } void PlayList::setMinimalMode(bool b) { if(!m_shaded) m_height = height(); m_shaded = b; if(m_shaded) { m_height = height(); setSizeIncrement (25*m_ratio, 1); setMinimumSize (275*m_ratio, 14*m_ratio); resize(width(), 14*m_ratio); } else { setMinimumSize(275*m_ratio, 116*m_ratio); resize (width(), m_height); setSizeIncrement (25*m_ratio, 29*m_ratio); } updatePositions(); update(); }