/* * playlist.cpp * * Copyright (C) 2003-2005 Jürgen Kofler * Copyright (C) 2005-2006 Christophe Thommeret * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "googlefetcher.h" #include "mrl.h" #include "playlistimport.h" #include "playlistitem.h" #include "playlist.h" #include "playlist.moc" RollTitle::RollTitle( TQWidget *parent ) : TQLabel( "I", parent ) { TQColorGroup cg = parentWidget()->colorGroup(); TQColor base = cg.base(); TQColor selection = cg.highlight(); int r = (base.red() + selection.red()) / 2; int b = (base.blue() + selection.blue()) / 2; int g = (base.green() + selection.green()) / 2; back = TQColor(r, g, b); fore = parentWidget()->colorGroup().text(); setPaletteBackgroundColor( back ); setPaletteForegroundColor( fore ); setFrameStyle( TQFrame::StyledPanel | TQFrame::Sunken ); title = " ##### "; titleOffset = 0; setTitle( title ); connect( &titleTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( rollTitle() ) ); titleTimer.start( 50 ); } void RollTitle::setTitle( MRL mrl ) { title = " ##### "; TQString s1 = mrl.artist().stripWhiteSpace(); TQString s2 = mrl.album().stripWhiteSpace(); TQString s3 = mrl.title().stripWhiteSpace(); if ( !s1.isEmpty() ) title+= s1+" - "; if ( !s2.isEmpty() ) title+= s2+" - "; if ( s3.isEmpty() ) title+= mrl.url(); else title+= s3; titleOffset = 0; setTitle( title ); } void RollTitle::setTitle( TQString t ) { TQLabel *lab = new TQLabel( t, this ); lab->setFrameStyle( TQFrame::StyledPanel | TQFrame::Sunken ); lab->resize( lab->sizeHint() ); int x = 2*lab->frameWidth(); titlePix = TQPixmap( lab->width()-x, height()-x, -1, TQPixmap::BestOptim ); delete lab; TQPainter p( &titlePix ); p.fillRect( 0, 0, titlePix.width(), titlePix.height(), back ); p.setPen( fore ); p.setFont( font() ); p.drawText( TQRect(0,(titlePix.height()-TQFontInfo(font()).pointSize())/2,titlePix.width(),TQFontInfo(font()).pointSize()*2), TQt::AlignAuto|TQt::SingleLine, t ); p.end(); } void RollTitle::rollTitle() { int w = 2*frameWidth(); TQPixmap pix( width()-w, height()-w, -1, TQPixmap::BestOptim ); TQPainter p1( &pix ); p1.fillRect( 0, 0, pix.width(), pix.height(), back ); p1.end(); int x = titlePix.width()-titleOffset; bitBlt( &pix, 0, 0, &titlePix, titleOffset, 0, x, titlePix.height(), CopyROP ); while ( xtitlePix.width() ) titleOffset = 0; bitBlt( this, w/2, w/2, &pix, 0, 0, width()-w, height()-w, CopyROP ); } void RollTitle::paintEvent( TQPaintEvent *pe ) { TQLabel::paintEvent( pe ); TQColorGroup cg = parentWidget()->colorGroup(); TQColor base = cg.base(); TQColor selection = cg.highlight(); int r = (base.red() + selection.red()) / 2; int b = (base.blue() + selection.blue()) / 2; int g = (base.green() + selection.green()) / 2; back=TQColor(r,g,b); setPaletteBackgroundColor( back ); fore = parentWidget()->colorGroup().text(); setPaletteForegroundColor( fore ); setTitle( title ); } struct CoverPopup : public TQWidget { CoverPopup(const TQPixmap &image, const TQPoint &p) : TQWidget(0, 0, WDestructiveClose | WX11BypassWM) { TQHBoxLayout *layout = new TQHBoxLayout(this); TQLabel *label = new TQLabel(this); layout->addWidget(label); label->setFrameStyle(TQFrame::Box | TQFrame::Raised); label->setLineWidth(1); label->setPixmap(image); setGeometry(p.x(), p.y(), label->width(), label->height()); show(); } virtual void leaveEvent(TQEvent *) { close(); } virtual void mouseReleaseEvent(TQMouseEvent *) { close(); } }; CoverFrame::CoverFrame( TQWidget *parent ) : TQFrame( parent ) { imagePath = ""; TQString path = locate("appdata", "nocover.png"); if ( !path ) path = locate("data", "kaffeine/nocover.png"); noCoverPix.convertFromImage( TQImage(path) ); setPaletteBackgroundPixmap( noCoverPix ); } CoverFrame::~CoverFrame() { } void CoverFrame::setCoverPixmap( const TQString &path ) { TQPixmap pix; TQImage img; img = TQImage( path ); if ( !img.isNull() ) { img = img.smoothScale( 80, 80 ); pix.convertFromImage( img ); setPaletteBackgroundPixmap( pix ); imagePath = path; } else { setPaletteBackgroundPixmap( noCoverPix ); imagePath = ""; } } void CoverFrame::popup( const TQPixmap &pix ) const { TQPoint mouse = TQCursor::pos(); TQRect desktop = TDEApplication::desktop()->screenGeometry(mouse); int x = mouse.x(); int y = mouse.y(); int height = pix.height() + 4; int width = pix.width() + 4; // Detect the right direction to pop up (always towards the center of the // screen), try to pop up with the mouse pointer 10 pixels into the image in // both directions. If we're too close to the screen border for this margin, // show it at the screen edge, accounting for the four pixels (two on each // side) for the window border. if(x - desktop.x() < desktop.width() / 2) x = (x - desktop.x() < 10) ? desktop.x() : (x - 10); else x = (x - desktop.x() > desktop.width() - 10) ? desktop.width() - width +desktop.x() : (x - width + 10); if(y - desktop.y() < desktop.height() / 2) y = (y - desktop.y() < 10) ? desktop.y() : (y - 10); else y = (y - desktop.y() > desktop.height() - 10) ? desktop.height() - height + desktop.y() : (y - height + 10); new CoverPopup( pix, TQPoint(x, y) ); } void CoverFrame::mousePressEvent( TQMouseEvent *e ) { int i; TQPixmap pix; switch ( e->button() ) { case Qt::LeftButton: { if ( imagePath.isEmpty() ) break; pix.convertFromImage( TQImage( imagePath ) ); if ( !pix.isNull() ) popup( pix ); break; } case Qt::RightButton: { TQPopupMenu pop( this ); pop.insertItem( i18n("Choose a Cover..."), 1 ); pop.insertItem( i18n("Gallery..."), 2 ); i = pop.exec( TQCursor::pos() ); if ( i==1 ) emit changeCurrentCover(); else if ( i==2 ) emit gallery(); break; } default: break; } } PlayList::PlayList( TQWidget* parent, TQObject *objParent, const char *name ) : KaffeineInput(objParent , name), m_playTime(0), m_playTimeVisible(0), m_countVisible(0), m_searchSelection(false), m_metaOnLoading(true), m_sortAscending(true), m_currentEntry(NULL), m_currentRandomListEntry(-1), m_endless(false), m_random(false), m_useAlternateEncoding(false), m_alternateEncoding("ISO 8859-1") { google = NULL; mainWidget = new TQVBox( parent ); //mainWidget->setSizePolicy( TQSizePolicy (TQSizePolicy::Preferred, TQSizePolicy::Preferred) ); hSplit = new TQSplitter( mainWidget ); hSplit->setOpaqueResize( true ); panel = new TQVBox( hSplit ); playlist = new TQWidget( hSplit ); hSplit->moveToFirst( panel ); hSplit->setResizeMode( panel, TQSplitter::KeepSize ); vSplit = new TQSplitter( Qt::Vertical, panel ); vSplit->setOpaqueResize( true ); TQWidget *vb = new TQWidget( vSplit ); TDEToolBar *tb = new TDEToolBar( vb ); TQVBoxLayout *v = new TQVBoxLayout( vb, 0, 0 ); v->addWidget( tb ); tb->setIconSize( 16 ); browserComb = new KURLComboBox( KURLComboBox::Directories, true, vb ); browserComb->setCompletionObject( new KURLCompletion( KURLCompletion::DirCompletion ) ); browserComb->setAutoDeleteCompletionObject( true ); browserComb->setMaxItems( 10 ); browserComb->setFocusPolicy(TQWidget::ClickFocus); /* if (!m_medium) m_combo->lineEdit()->setText( location->path() ); else m_combo->lineEdit()->setText( "/" );*/ TQVBoxLayout *v1 = new TQVBoxLayout( 0, 3, 3 ); v1->addWidget( browserComb ); fileBrowser = new KDirOperator( KURL("/"), vb ); fileBrowser->setupMenu( KDirOperator::SortActions|KDirOperator::NavActions|KDirOperator::ViewActions ); view = new KFileIconView( fileBrowser, "view" ); view->setSelectionMode( KFile::Multi ); fileBrowser->setMode( KFile::Files ); fileBrowser->setView( view ); fileBrowser->setViewConfig( TDEGlobal::config(), "PlaylistFileBrowser" ); fileBrowser->setOnlyDoubleClickSelectsFiles( true ); v1->addWidget( fileBrowser ); v->addLayout( v1 ); TDEActionCollection *col = fileBrowser->actionCollection(); col->action( "up" )->plug( tb ); col->action( "back" )->plug( tb ); col->action( "forward" )->plug( tb ); col->action( "reload" )->plug( tb ); col->action( "home" )->plug( tb ); vSplit->moveToFirst( vb ); playerBox = new TQVBox( vSplit ); playerBox->setMinimumHeight( 50 ); playerBox->setMinimumWidth( 200 ); vSplit->moveToLast( playerBox ); m_playlistDirectory = locateLocal("appdata", "playlists"); m_playlistDirectory.append("/"); TDEIO::NetAccess::mkdir(m_playlistDirectory, mainWidget); kdDebug() << "PLAYLIST" << endl; TQGridLayout* layout = new TQGridLayout( playlist, 4, 2, 3 ); m_list = new UrlListView(playlist); mainWidget->setAcceptDrops(true); m_list->setHScrollBarMode(TDEListView::AlwaysOff); m_list->setItemMargin(2); m_list->setMargin(0); m_list->setSelectionMode(TQListView::Extended); m_list->addColumn(""); m_list->addColumn(i18n("Title")); m_list->addColumn(i18n("Artist")); m_list->addColumn(i18n("Album")); m_list->addColumn(i18n("Track")); m_list->addColumn(i18n("Length")); m_list->setShowToolTips(true); m_list->setColumnWidthMode(MIME_COLUMN, TQListView::Manual); m_list->setColumnWidthMode(TITLE_COLUMN, TQListView::Manual); m_list->setColumnWidthMode(ARTIST_COLUMN, TQListView::Manual); m_list->setColumnWidthMode(ALBUM_COLUMN, TQListView::Manual); m_list->setColumnWidthMode(TRACK_COLUMN, TQListView::Manual); m_list->setColumnWidthMode(LENGTH_COLUMN, TQListView::Manual); m_list->setResizeMode(TQListView::NoColumn); TDEConfig* config = kapp->config(); m_list->restoreLayout(config, "Playlist Layout"); m_list->setFullWidth(true); m_list->setSorting(-1); m_list->setDragEnabled(true); m_list->setAcceptDrops(true); m_list->setDropVisualizer(true); m_list->setItemsMovable(true); m_list->setItemsRenameable(true); m_list->setRenameable(TITLE_COLUMN); m_list->setRenameable(ARTIST_COLUMN); m_list->setRenameable(ALBUM_COLUMN); m_list->setRenameable(TRACK_COLUMN); m_list->setAllColumnsShowFocus(true); m_list->setShowSortIndicator(true); layout->addMultiCellWidget(m_list, 3, 3, 0, 1); coverFrame = new CoverFrame( playlist ); coverFrame->setFixedWidth( 80 ); coverFrame->setFixedHeight( 80 ); layout->addMultiCellWidget(coverFrame, 0, 2, 0, 0); TQHBoxLayout *h1 = new TQHBoxLayout(); searchBtn = new TQToolButton( playlist ); searchBtn->setAutoRaise( true ); TQToolTip::add( searchBtn, i18n("Search")); searchBtn->setIconSet( TDEGlobal::iconLoader()->loadIconSet("locationbar_erase", TDEIcon::Small) ); h1->addWidget( searchBtn ); TQLabel* filterLabel = new TQLabel(i18n("Filter") + ":", playlist); h1->addWidget(filterLabel); m_playlistFilter = new KLineEdit(playlist); m_playlistFilter->setFocusPolicy(TQWidget::ClickFocus); h1->addWidget(m_playlistFilter); layout->addLayout( h1, 2, 1 ); TQHBoxLayout *h2 = new TQHBoxLayout(); TQLabel* playlistLabel = new TQLabel(i18n("Playlist:"), playlist); h2->addWidget(playlistLabel); m_playlistSelector = new KComboBox( playlist ); m_playlistSelector->setMinimumWidth(10); m_playlistSelector->setSizePolicy( TQSizePolicy (TQSizePolicy::MinimumExpanding, TQSizePolicy::Preferred) ); m_playlistSelector->setEditable(true); m_playlistSelector->setDuplicatesEnabled(false); m_playlistSelector->setFocusPolicy(TQWidget::ClickFocus); TQToolTip::add(m_playlistSelector, i18n("Select the active playlist. To change playlist name edit it and confirm with 'Return'.")); h2->addWidget(m_playlistSelector); layout->addLayout( h2, 1, 1 ); roller = new RollTitle( playlist ); layout->addWidget( roller, 0, 1 ); TDEAccel* accel = new TDEAccel(mainWidget); accel->insert("Delete selected", TQt::Key_Delete, this, TQT_SLOT(slotRemoveSelected())); m_isCurrentEntry = UserIcon("playing"); m_cdPixmap = TDEGlobal::iconLoader()->loadIcon("application-x-cda", TDEIcon::Small); setXMLFile("kaffeineplaylist.rc"); setupActions(); TQStrList formats = TQImageIO::outputFormats(); coverImageFormat = "PNG"; for (int i=0; i<(int)formats.count(); i++ ) { if ( TQString(formats.at(i))=="JPEG" ) { coverImageFormat = "JPEG"; break; } } loadConfig( TDEGlobal::config() ); connect(coverFrame, TQT_SIGNAL(changeCurrentCover()), this, TQT_SLOT(chooseCurrentCover())); connect(coverFrame, TQT_SIGNAL(gallery()), this, TQT_SLOT(showGallery())); connect(browserComb, TQT_SIGNAL(urlActivated( const KURL& )), this, TQT_SLOT(setBrowserURL( const KURL& ))); connect(browserComb, TQT_SIGNAL(returnPressed( const TQString& )), this, TQT_SLOT(setBrowserURL( const TQString& ))); connect(fileBrowser, TQT_SIGNAL(urlEntered( const KURL& )), this, TQT_SLOT(browserURLChanged( const KURL& ))); connect(fileBrowser, TQT_SIGNAL(fileSelected(const KFileItem*)), this, TQT_SLOT(fileSelected(const KFileItem*))); connect(m_playlistFilter, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotFindText(const TQString&))); connect( searchBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(resetSearch()) ); connect(m_playlistSelector, TQT_SIGNAL(returnPressed(const TQString&)), this, TQT_SLOT(slotNewPlaylistName(const TQString&))); connect(m_playlistSelector, TQT_SIGNAL(activated(int)),this, TQT_SLOT(slotPlaylistActivated(int))); connect(m_list, TQT_SIGNAL(dropped(TQDropEvent*, TQListViewItem*)), this, TQT_SLOT(slotDropEvent(TQDropEvent*, TQListViewItem*))); connect(m_list, TQT_SIGNAL(aboutToMove()), this, TQT_SLOT(slotPreDropEvent())); connect(m_list, TQT_SIGNAL(doubleClicked(TQListViewItem*)), this, TQT_SLOT(slotPlayDirect(TQListViewItem*))); connect(m_list, TQT_SIGNAL(returnPressed(TQListViewItem*)), this, TQT_SLOT(slotPlayDirect(TQListViewItem*))); connect(m_list, TQT_SIGNAL(signalCut()), this, TQT_SLOT(slotCut())); connect(m_list, TQT_SIGNAL(signalCopy()), this, TQT_SLOT(slotCopy())); connect(m_list, TQT_SIGNAL(signalPaste()), this, TQT_SLOT(slotPaste())); connect(m_list, TQT_SIGNAL(signalSelectAll()), this, TQT_SLOT(slotSelectAll())); connect(m_list, TQT_SIGNAL(signalPlayItem(TQListViewItem*)), this, TQT_SLOT(slotPlayDirect(TQListViewItem*))); connect(m_list, TQT_SIGNAL(signalPlaylistFromSelected()), this, TQT_SLOT(slotPlaylistFromSelected())); connect(m_list, TQT_SIGNAL(signalAddToQueue(MRL)), this, TQT_SLOT(slotAddToQueue(MRL))); connect(m_list->header(), TQT_SIGNAL(clicked(int)), this, TQT_SLOT(slotSort(int))); } void PlayList::togglePanel() { if ( panel->isHidden() ) panel->show(); else panel->hide(); } void PlayList::getTargets( TQStringList &uiNames, TQStringList &iconNames, TQStringList &targetNames ) { uiNames.append( i18n("Play Playlist") ); iconNames.append( "view_text" ); targetNames.append( "PLAYLIST" ); } bool PlayList::execTarget( const TQString &target ) { if ( target=="PLAYLIST" ) { emit showMe( this ); TQTimer::singleShot( 100, this, TQT_SLOT(startPlaylist()) ); return true; } return false; } void PlayList::setFileFilter( const TQString& filter ) { m_fileFilter = filter; fileBrowser->setNameFilter( m_fileFilter ); } PlayList::~PlayList() { delete m_list; } void PlayList::setupActions() { m_repeat = new TDEToggleAction(i18n("&Repeat"), 0 , CTRL|Key_E, this, TQT_SLOT(slotRepeat()), actionCollection(),"playlist_repeat"); m_repeat->setStatusText(i18n("Loop playlist")); m_shuffle = new TDEToggleAction(i18n("Sh&uffle"), 0 , CTRL|Key_R, this, TQT_SLOT(slotShuffle()), actionCollection(),"playlist_shuffle"); m_shuffle->setStatusText(i18n("Play items in random order")); m_autoCover = new TDEToggleAction(i18n("Autodownload covers"), 0 , 0, this, TQT_SLOT(slotAutoCover()), actionCollection(),"playlist_autocover"); m_autoCover->setStatusText(i18n("Automatic dowloading of covers")); m_showPlayer = new TDEToggleAction(i18n("Don't switch to player window"), 0 , 0, this, TQT_SLOT(slotShowPlayer()), actionCollection(),"playlist_showplayer"); m_showPlayer->setStatusText(i18n("Don't switch automatically to player window")); new TDEAction(i18n("&Clear Current Playlist"), "eraser", 0, this, TQT_SLOT(slotClearList()), actionCollection(), "playlist_clear"); new TDEAction(i18n("Ne&w Playlist"), "document-new", 0, this, TQT_SLOT(slotNewList()), actionCollection(), "playlist_new"); new TDEAction(i18n("&Import Playlist..."), "project_open", 0, this, TQT_SLOT(slotPlaylistLoad()), actionCollection(), "playlist_load"); new TDEAction(i18n("&Save Current Playlist As..."), "document-save-as", 0, this, TQT_SLOT(slotPlaylistSaveAs()), actionCollection(), "playlist_save_as"); new TDEAction(i18n("Re&move Current Playlist"), "window-close", 0, this, TQT_SLOT(slotPlaylistRemove()), actionCollection(), "playlist_remove"); } void PlayList::slotClearList() { clearList(); } void PlayList::slotRepeat() { setEndless(m_repeat->isChecked()); } void PlayList::slotShuffle() { setRandom(m_shuffle->isChecked()); } void PlayList::slotAutoCover() { m_cover = m_autoCover->isChecked(); } void PlayList::slotShowPlayer() { } void PlayList::slotToggleShuffle() { m_shuffle->setChecked(!m_shuffle->isChecked()); slotShuffle(); } void PlayList::slotPlaylistLoad() { TQString path = KFileDialog::getOpenFileName(":kaffeine_openPlaylist", TQString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n*.*|" + i18n("All Files"), 0, i18n("Open Playlist")); if (path.isEmpty() || (!path.contains(".kaffeine", false))) return; loadPlaylist(path); } void PlayList::slotPlaylistSaveAs() { TQString startPath = ":kaffeine_savePlaylist"; //if (!lastPlaylist.isEmpty()) startPath = lastPlaylist; TQString path = KFileDialog::getSaveFileName(startPath, TQString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n" + TQString("*.m3u|") + i18n("M3U Playlists") + "\n" + TQString("*.pls|") + i18n("PLS Playlists") + "\n" + "*.*|" + i18n("All Files"), 0, i18n("Save Playlist")); if ( path.isEmpty() ) return; if ( path.right(4).lower() == ".m3u" ) { exportM3UPlaylist(path); } else if ( path.right(4).lower() == ".pls" ) { exportPLSPlaylist(path); } else if ( path.right(9).lower() == ".kaffeine" ) { savePlaylist(path); } else { path.append(".kaffeine"); savePlaylist(path); } } void PlayList::slotPlaylistRemove() { removeCurrentPlaylist(); } TQWidget* PlayList::wantPlayerWindow() { return playerBox; } TQWidget* PlayList::inputMainWidget() { return mainWidget; } void PlayList::loadConfig(TDEConfig* config) { TQValueList sl; bool b; config->setGroup("Playlist"); b = config->readBoolEntry("Endless Mode", false); m_repeat->setChecked(b); setEndless(b); b = config->readBoolEntry("Random Mode", false); m_shuffle->setChecked(b); setRandom(b); b = config->readBoolEntry("AutoCover", false); m_autoCover->setChecked(b); m_cover = b; b = config->readBoolEntry("DontShowPlayer", false); m_showPlayer->setChecked(b); sl = config->readIntListEntry("HSplitSizes"); if ( sl.count() ) hSplit->setSizes( sl ); else { sl.append( 200 ); sl.append( 200 ); hSplit->setSizes( sl ); } vSplit->setSizes( config->readIntListEntry("VSplitSizes") ); TQStringList list; list = config->readListEntry("Playlists"); if (!list.count()) { list.append(i18n("Playlist") + "1"); } int lastRegularPlaylist = list.count(); list.append(i18n("NEW")); m_playlistSelector->insertStringList(list); m_currentPlaylist = config->readNumEntry("Current", 0); if (m_currentPlaylist > lastRegularPlaylist) m_currentPlaylist = 0; m_playlistSelector->setCurrentItem(m_currentPlaylist); add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL); m_nextPlaylistNumber = config->readNumEntry("Next Playlist", 2); TQString currentEntry = config->readEntry("Current Entry", TQString()); if ((!currentEntry.isEmpty()) && (m_list->childCount())) { TQListViewItem* tmp = findByURL(currentEntry); if (tmp) setCurrentEntry(tmp, false); } fileBrowser->readConfig( config, "PlaylistFileBrowser" ); fileBrowser->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )), true ); browserComb->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )) ); } void PlayList::saveConfig() { saveConfig( TDEGlobal::config() ); } void PlayList::saveConfig(TDEConfig* config) { saveCurrentPlaylist(); config->setGroup("Playlist"); config->writeEntry("Endless Mode", m_repeat->isChecked()); config->writeEntry("Random Mode", m_shuffle->isChecked()); config->writeEntry("AutoCover", m_autoCover->isChecked()); config->writeEntry("DontShowPlayer", m_showPlayer->isChecked()); config->writeEntry( "HSplitSizes", hSplit->sizes() ); config->writeEntry( "VSplitSizes", vSplit->sizes() ); TQStringList list; TQString text; for (uint i=0; i < m_playlistSelector->listBox()->count(); i++) { text = m_playlistSelector->text(i); if ( text != i18n("NEW") ) list.append(text); } config->writeEntry("Playlists", list); config->writeEntry("Current", m_currentPlaylist); config->writeEntry("Next Playlist", m_nextPlaylistNumber); config->writeEntry("Current Entry", m_currentEntryMRL.url()); m_list->saveLayout(config, "Playlist Layout"); fileBrowser->writeConfig( config, "PlaylistFileBrowser" ); config->writeEntry( "FileBrowserURL", fileBrowser->url().url() ); } void PlayList::closeEvent(TQCloseEvent* ce) { kdDebug() << "Playlist: close Event" << endl; ce->ignore(); } /****************************************** * get the urls from playlist ******************************************/ void PlayList::startPlaylist() { MRL mrl; if ( trackNumber( 1, mrl ) ) emit play( mrl, this ); } bool PlayList::currentTrack( MRL &mrl ) { mrl = getCurrent(); if ( !mrl.isEmpty() ) return true; else return false; } MRL PlayList::getCurrent() { if (isQueueMode()) { m_queue.clear(); updateStatus(); } if (m_random) { if (m_currentRandomListEntry == -1) return MRL(); setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); return m_currentEntryMRL; } if (!m_currentEntry) if (m_list->childCount() > 0) { if (m_list->firstChild()->isVisible()) setCurrentEntry(m_list->firstChild()); else { if (m_list->firstChild()->itemBelow()) setCurrentEntry(m_list->firstChild()->itemBelow()); else return MRL(); } } else return MRL(); setCurrentEntry(m_currentEntry); return m_currentEntryMRL; } bool PlayList::playbackFinished( MRL &mrl ) { return nextTrack( mrl ); } bool PlayList::nextTrack( MRL &mrl ) { if (isQueueMode()) { mrl = m_queue.first(); m_queue.remove(m_queue.begin()); updateStatus(); return true; } if (!m_currentEntry) { mrl = getCurrent(); if ( !mrl.isEmpty() ) return true; else return false; } if (m_random) { if ((m_currentRandomListEntry+1) < (int)m_randomList.count()) m_currentRandomListEntry += 1; else { if (m_endless) m_currentRandomListEntry = 0; else return false; } setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); mrl = m_currentEntryMRL; return true; } TQListViewItem* tmpItem; tmpItem = m_currentEntry->itemBelow(); if (tmpItem) { setCurrentEntry(tmpItem); mrl = m_currentEntryMRL; return true; } else { if (m_endless) { setCurrentEntry(m_list->firstChild()); mrl = m_currentEntryMRL; return true; } else return false; } } bool PlayList::previousTrack( MRL &mrl ) { if (isQueueMode()) { m_queue.clear(); updateStatus(); } if (!m_currentEntry) { mrl = getCurrent(); if ( !mrl.isEmpty() ) return true; else return false; } if (m_random) { if (m_currentRandomListEntry > 0) m_currentRandomListEntry -= 1; else { if (m_endless) m_currentRandomListEntry = m_randomList.count()-1; else return false; } setCurrentEntry(m_randomList.at(m_currentRandomListEntry)); mrl = m_currentEntryMRL; return true; } TQListViewItem* tmpItem; tmpItem = m_currentEntry->itemAbove(); if (tmpItem) { setCurrentEntry(tmpItem); mrl = m_currentEntryMRL; return true; } else { if (m_endless) { setCurrentEntry(getLast()); mrl = m_currentEntryMRL; return true; } else return false; } } bool PlayList::trackNumber( int number, MRL &mrl ) { if (number > m_list->childCount()) return false; TQListViewItem * item = m_list->firstChild(); for (int i = 1; i < number; i++) item = item->nextSibling(); setCurrentEntry(item); mrl = m_currentEntryMRL; return true; } TQListViewItem* PlayList::getLast() { return m_list->lastItem(); } TQListViewItem* PlayList::getFirst() { return m_list->firstChild(); } TQListViewItem* PlayList::findByURL(const TQString& url) { TQListViewItemIterator it(m_list); while (it.current()) { if (dynamic_cast(*it)->url() == url) { return (*it); } ++it; } /* fallback */ return getFirst(); } /********* set current entry (with play icon) ****************/ void PlayList::setCurrentEntry(TQListViewItem* item, bool playIcon) { PlaylistItem* newItem = dynamic_cast(item); PlaylistItem* oldItem = dynamic_cast(m_currentEntry); if (m_currentEntry) { oldItem->setPlaying(false); m_currentEntry->setPixmap(TITLE_COLUMN, TQPixmap()); } if (playIcon) { newItem->setPlaying(true); item->setPixmap(TITLE_COLUMN, m_isCurrentEntry); } m_currentEntry = item; if (m_random) m_currentRandomListEntry = m_randomList.find(item); m_currentEntryMRL = newItem->toMRL(); roller->setTitle( m_currentEntryMRL ); m_list->setCurrentItem(m_currentEntry); m_list->ensureVisible(10, m_list->itemPos(m_currentEntry), 10, 30); } TQListViewItem* PlayList::insertItem(TQListViewItem* after, const MRL& m) { PlaylistItem* tmp = NULL; MRL mrl(m); m_list->setSorting(-1); TQListViewItemIterator it(m_list); while (it.current()) { if (dynamic_cast(*it)->url() == mrl.url()) { kdDebug() << "PlayList: Source '" << mrl.url() << "' still exists. Skipped." << endl; return after; } ++it; } if (mrl.mime().isNull()) { KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); mrl.setMime(mime->name()); } tmp = new PlaylistItem(m_list, dynamic_cast(after), mrl); if (!tmp) return after; if ((mrl.mime() == "video/dvd") || (mrl.mime() == "video/vcd") || (mrl.mime() == "audio/cd")) tmp->setPixmap(MIME_COLUMN, m_cdPixmap); else tmp->setPixmap(MIME_COLUMN, KMimeType::mimeType(mrl.mime())->pixmap(TDEIcon::Small)); if (tmp->length().contains(':')) m_playTime += timeStringToMs(tmp->length()); if (m_searchSelection) { TQString text = m_playlistFilter->text(); if ((!tmp->title().contains(text, false)) && (!tmp->url().contains(text, false)) && (!tmp->artist().contains(text, false)) && (!tmp->album().contains(text, false))) { tmp->setVisible(false); } } if (tmp->isVisible()) { if (tmp->length().contains(':')); m_playTimeVisible += timeStringToMs(tmp->length()); m_countVisible++; } return tmp; } void PlayList::fileSelected( const KFileItem *item ) { if ( !item ) return; add( TQStringList( item->url().path() ), NULL ); TQListViewItem* tmp = findByURL(item->url().path()); if (tmp) { setCurrentEntry(tmp); emit play(m_currentEntryMRL, this); } } void PlayList::setBrowserURL( const TQString &path ) { fileBrowser->setURL( KURL(path), true ); } void PlayList::setBrowserURL( const KURL &path ) { fileBrowser->setURL( path, true ); } void PlayList::browserURLChanged( const KURL &u ) { TQString url; if ( u.isLocalFile() ) url = u.path(); else url = u.prettyURL(); TQStringList urls = browserComb->urls(); urls.remove( url ); // do not duplicate urls.prepend( url ); browserComb->setURLs( urls, KURLComboBox::RemoveBottom ); } void PlayList::add(const TQString& url, TQListViewItem* after) { add(TQStringList(url), after); } void PlayList::add(const TQStringList& urlList, TQListViewItem* after) { TQListViewItem* tmp = NULL; TQStringList urls(urlList); TQString ext; TQString subtitleURL; TQStringList subs; KURL tmpKURL; bool playlist; MRL mrl; TQValueList mrlList; TQString mediadevice=""; KProgressDialog* progress = NULL; progress = new KProgressDialog(mainWidget, "importprogress", TQString(), i18n("Importing media resources...")); progress->progressBar()->setTotalSteps(urls.count()); progress->show(); kdDebug() << "PlayList: add " << urls.count() << " items to playlist" << endl; for (uint i = 0; i < urls.count(); i++) { mrl = MRL(urls[i]); TQString url(mrl.kurl().prettyURL()); if (mrl.kurl().protocol() == "media" || url.startsWith("system:/media/")) { TQString mediaName; if (url.startsWith("system:/media/")) mediaName = url.mid(14); else mediaName = url.mid(7); int slash = mediaName.find("/"); TQString filePath(mediaName.mid(slash)); if (filePath == "/") filePath = ""; mediaName = mediaName.left(slash); DCOPRef mediamanager("kded","mediamanager"); DCOPReply reply = mediamanager.call("properties(TQString)",mediaName); if (reply.isValid()) { TQStringList properties = reply; if (properties.isEmpty()) break; url = properties[6] + filePath; if (filePath.isEmpty()) { if (properties[10] == "media/audiocd") { mediadevice = properties[5]; delete progress; emit signalRequestForAudioCD(mediadevice); return; } if (properties[10] == "media/dvdvideo" || properties[10] == "media/blurayvideo") { mediadevice = properties[5]; delete progress; emit signalRequestForDVD(mediadevice); return; } if ((properties[10] == "media/vcd") || (properties[10] == "media/svcd")) { mediadevice = properties[5]; delete progress; emit signalRequestForVCD(mediadevice); return; } } mrl = MRL(url); } } if (mrl.kurl().isLocalFile()) { if (!TQFile::exists(mrl.kurl().path())) continue; mrl.setTitle(mrl.kurl().fileName()); mrl.setURL(mrl.kurl().path()); } else { mrl.setTitle(mrl.url()); } //kdDebug() << "PlayList: Check url " << mrl.url() << endl; /*********** determine extension and mime type ************/ ext = mrl.kurl().fileName(); ext = ext.remove(0 , ext.findRev('.') +1).lower(); // kdDebug() << "Extension: " << ext << endl; //kdDebug() << "PlayList: Try to determine mime of: " << mrl.url() << endl; KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); /* works only with path() (without protocol) e.g. http://www.somafm.com/indipop.pls path: /indipop.pls */ //kdDebug() << "Mime: " << mime->name() << endl; /*** check for kaffeine/noatun/pls/asx/m3u playlist ***/ mrl.setMime(mime->name()); /******** some special processing for local files! *******/ if (mrl.kurl().isLocalFile()) { /* playlist ? */ if ((mime->name() == "text/plain") || (mime->name() == "text/xml") || (mime->name() == "application/x-kaffeine") || (mime->name() == "audio/x-scpls") || (mime->name() == "audio/x-mpegurl" || (mime->name() == "audio/mpegurl") || (ext == "asx") || (ext == "asf") || (ext == "wvx") || (ext == "wax"))) /* windows meta files */ { kdDebug() << "PlayList: Check for kaffeine/noatun/m3u/pls/asx playlist\n"; mrlList.clear(); playlist = false; TQFile file(mrl.url()); file.open(IO_ReadOnly); TQTextStream stream(&file); TQString firstLine = stream.readLine(); TQString secondLine = stream.readLine(); file.close(); if (secondLine.contains("kaffeine", false)) { kdDebug() << "PlayList: Try loading kaffeine playlist\n"; playlist = PlaylistImport::kaffeine(mrl.url(), mrlList); if (!playlist) continue; } if (secondLine.contains("noatun", false)) { kdDebug() << "PlayList: Try loading noatun playlist\n"; playlist = PlaylistImport::noatun(mrl.url(), mrlList); } if (firstLine.contains("asx", false)) { kdDebug() << "PlayList: Try loading asx playlist\n"; playlist = PlaylistImport::asx(mrl.url(), mrlList); } if ( (firstLine.contains("[playlist]", false)) || (ext == "pls") ) { kdDebug() << "PlayList: Try loading pls playlist\n"; playlist = PlaylistImport::pls(mrl.url(), mrlList); } if (ext == "m3u") //identify by extension { kdDebug() << "PlayList: Try loading m3u playlist\n"; playlist = PlaylistImport::m3u(mrl.url(), mrlList); } if (playlist) { TQValueList::ConstIterator end(mrlList.end()); for (TQValueList::ConstIterator it = mrlList.begin(); it != end; ++it) after = insertItem(after, *it); continue; } } /* check for ram playlist */ if ( (ext == "ra") || (ext == "rm") || (ext == "ram") || (ext == "lsc") || (ext == "pl") ) { mrlList.clear(); kdDebug() << "PlayList: Try loading ram playlist\n"; if (PlaylistImport::ram(mrl, mrlList, mainWidget->parentWidget())) { TQValueList::ConstIterator end(mrlList.end()); for (TQValueList::ConstIterator it = mrlList.begin(); it != end; ++it) after = insertItem(after, *it); continue; } } /**** a directory ? ****/ if (mime->name() == "inode/directory") { kdDebug() << "PlayList: Add Directory: " << mrl.url() << endl; TQDir d(mrl.url()); uint x; /* subdirs */ TQStringList entryList = d.entryList(TQDir::Dirs, TQDir::Name); for (x = 0; x < entryList.count(); x++) { if (entryList[x][0] != '.') { urls.append(mrl.url() + "/" + entryList[x]); } } /* Media files */ /* Exclude subtitles because they are examined twice : */ /* Once for movie and once per subtitle - very annoying*/ TQString fileFilter = m_fileFilter; fileFilter.remove("*.srt",false); fileFilter.remove("*.ssa",false); fileFilter.remove("*.txt",false); fileFilter.remove("*.asc",false); fileFilter.remove("*.smi",false); fileFilter.remove("*.sub",false); entryList = d.entryList(fileFilter, TQDir::Files, TQDir::Name ); for (x = 0; x < entryList.count(); x++) { urls.append(mrl.url() + "/" + entryList[x]); } progress->progressBar()->setTotalSteps(urls.count()); continue; /* dont add directory to playlist */ } /*** append subtitle files to the movie ***/ if ((ext == "srt") || (ext == "ssa") || (ext == "txt") || (ext == "asc") || (ext == "smi") || (ext == "sub")) { TQStringList movies; TQString movieURL; TQListViewItemIterator it(m_list); while (it.current()) { if (dynamic_cast(*it)->mime().contains("video")) movies << dynamic_cast(*it)->url(); ++it; } if (movies.count() == 1) movieURL = movies[0]; else if (movies.count() >= 2) { MovieChooser *mc = new MovieChooser(movies, mrl.url(), mainWidget); if(mc->exec() == TQDialog::Accepted) movieURL = mc->getSelection(); delete mc; } it = m_list; while (it.current()) { if (dynamic_cast(*it)->url() == movieURL) { kdDebug() << "PlayList: adding subtitle to movie " << dynamic_cast(*it)->url() << endl; (dynamic_cast(*it))->addSubtitle(mrl.url()); break; } ++it; } continue; } /*** get meta tags ****/ if (m_metaOnLoading) getMetaInfo(mrl, mime->name()); /* Get all suported subs in movie dir, clear out * those starting with a different name than the movie, * prompt the user to select a sub */ if (mime->name().contains("video")) { kdDebug() << "PlayList: Check for subtitle files" << endl; subtitleURL = TQString(); TQDir *d = new TQDir(mrl.url().section('/',0,-2)); TQString filename = mrl.url().section('/',-1,-1); subs = TQStringList(); //Do a case insensitive search for subs TQStringList dirListing = d->entryList(TQDir::Files|TQDir::NoSymLinks); //cache directory listing bool matches = false; TQStringList::Iterator end(dirListing.end()); for(TQStringList::Iterator it = dirListing.begin(); it != end; ++it ) { if(startsWith(*it, filename.section('.',0,-2), false)) //If filenames (without extensions) match { if( endsWith(*it, ".srt", false) || endsWith(*it, ".ssa", false) || endsWith(*it, ".txt", false) || endsWith(*it, ".smi", false) || endsWith(*it, ".asc", false) || endsWith(*it, ".sub", false) ) matches = true; if(matches) { subs.append(*it); //This is a subtitle for our movie } matches = false; } } if((subs.count() > 1)) { subs.prepend(i18n("(no subtitles)")); subs.append(i18n("Other subtitle...")); subtitleURL = TQString(); SubtitleChooser *sc = new SubtitleChooser(subs, filename, mainWidget); THERE: if(sc->exec() == TQDialog::Accepted) { if((sc->getSelection() != i18n("(no subtitles)")) && (sc->getSelection() != i18n("Other subtitle..."))) subtitleURL = d->path()+"/"+sc->getSelection(); if((sc->getSelection() == i18n("Other subtitle..."))) { subtitleURL = KFileDialog::getOpenURL(d->path(), i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"), 0, i18n("Select Subtitle File")).path(); if(subtitleURL.isEmpty()) { subtitleURL = TQString(); goto THERE; } else //The user has selected another sub, so add this to the list { subs.clear(); subs.append(subtitleURL); } } } delete sc; subs.remove(i18n("(no subtitles)")); subs.remove(i18n("Other subtitle...")); } //Add the full path to the subtitle name for (unsigned int i = 0; i < subs.size(); i++ ) if(!subs[i].startsWith(d->path())) subs[i] = d->path()+"/"+subs[i]; mrl.setSubtitleFiles(subs); if ( subs.count()==1 ) subtitleURL = subs[0]; // Use this one. if (!subtitleURL.isNull()) { kdDebug() << "PlayList: Use subtitle file: " << subtitleURL << " for: " << mrl.url() << endl; mrl.setCurrentSubtitle(subs.findIndex(subtitleURL)); } } } /* if localFile() */ tmp = insertItem(after, mrl); if (tmp) after = tmp; if ( progress->wasCancelled() ) break; progress->progressBar()->setProgress(i+1); progress->setLabel(TQString::number(i+1) + " / " + TQString::number(progress->progressBar()->totalSteps()) + " " + i18n("Files")); TDEApplication::kApplication()->processEvents(); } delete progress; if (m_random) createRandomList(); updateStatus(); } void PlayList::add(const TQValueList& mrlList, TQListViewItem* after) { TQValueList::ConstIterator end(mrlList.end()); for (TQValueList::ConstIterator it = mrlList.begin(); it != end; ++it) after = insertItem(after, *it); updateStatus(); if (m_random) createRandomList(); } void PlayList::slotPlayDirect(TQListViewItem* item) { if (!item) return; setCurrentEntry(item); emit play(m_currentEntryMRL, this); } void PlayList::setEndless(bool e) { m_endless = e; } void PlayList::setRandom(bool r) { m_random = r; if (m_random) createRandomList(); } void PlayList::createRandomList() { kdDebug() << "PlayList: Create a random playlist" << endl; m_randomList.clear(); m_currentRandomListEntry = 0; TQListViewItem* tmpItem = NULL; tmpItem = m_list->firstChild(); if ( (tmpItem) && (!tmpItem->isVisible()) ) tmpItem = tmpItem->itemBelow(); while (tmpItem) { m_randomList.append(tmpItem); tmpItem = tmpItem->itemBelow(); } if (!(m_randomList.count() > 0)) { m_currentRandomListEntry = -1; return; } KRandomSequence r(TDEApplication::random()); r.randomize(&m_randomList); } void PlayList::clearList() { m_list->clear(); m_randomList.clear(); m_playTime = 0; m_playTimeVisible = 0; m_countVisible = 0; if (m_searchSelection) { m_playlistFilter->clear(); m_searchSelection = false; } updateStatus(); m_currentEntry = NULL; m_currentRandomListEntry = -1; } void PlayList::slotDropEvent(TQDropEvent* dev, TQListViewItem* after) { TQStringList urls ,newurls; m_list->setSorting(-1); if (TQUriDrag::decodeLocalFiles(dev, urls)) { if (urls.count()) { for (uint i=0; i < urls.count() ;i++) { //KURL url(TQUriDrag::unicodeUriToUri(urls[i])); //newurls << url.path(-1); //kdDebug() << "PlayList: Dropped " << url.path() << endl; newurls << urls[i]; kdDebug() << "PlayList: Dropped " << urls[i] << endl; } add(newurls, after); } else { TQUriDrag::decodeToUnicodeUris(dev, urls); if (urls.count()) add(urls, after); } } else if (strcmp(dev->format(), "text/x-moz-url") == 0) /* for mozilla drops */ { TQByteArray data = dev->encodedData("text/plain"); TQString md(data); add(md, after); } } void PlayList::slotPreDropEvent() { m_list->setSorting(-1); } void PlayList::slotSetAlternateColor( const TQColor& col ) { m_list->setAlternateBackground( col ); m_altCol = col; m_list->triggerUpdate(); } void PlayList::useAlternateEncoding(bool useEncoding) { m_useAlternateEncoding = useEncoding; } void PlayList::setAlternateEncoding(const TQString& encoding) { m_alternateEncoding = encoding; } void PlayList::getMetaInfo(MRL& mrl, const TQString& mimeName) { KFileMetaInfo* metaInfo = NULL; KFileMetaInfoGroup metaGroup; uint m, n; metaInfo = new KFileMetaInfo(mrl.url(), mimeName); TQStringList groups = metaInfo->groups(); TQStringList keys; TQString title; TQString artist; TQString album; TQTextCodec *altCodec; TQTextCodec *CodecUtf8; altCodec = TQTextCodec::codecForName(m_alternateEncoding.ascii()); CodecUtf8 = TQTextCodec::codecForName("UTF-8"); //kdDebug() << "playlist: locale " << Codec->name << " index: " << m_alternateEncoding << endl; for (m = 0; m < groups.count(); m++) { //kdDebug() << "Metainfo-Group: " << groups[m] << endl; metaGroup = metaInfo->group(groups[m]); keys = metaGroup.keys(); for (n = 0; n < keys.count(); n++) { //kdDebug() << "Metainfo-Key: " << keys[n] << endl; if (keys[n] == "Length") { mrl.setLength(TQTime().addSecs(metaGroup.item(keys[n]).value().toUInt())); } if (keys[n] == "Title") { title = metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace(); if ((!title.isEmpty()) && (title.contains(TQRegExp("\\w")) > 2) && (title.left(5).lower() != "track")) { if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(title.ascii(), title.length()) < 0)) { mrl.setTitle(altCodec->toUnicode(title.ascii())); //kdDebug() << "playlist: Convert, locale name: " << altCodec->name() << title << endl; } else { mrl.setTitle(title); //kdDebug() << "playlist: non Convert, locale name: " << CodecUtf8->name() << title << endl; } } } if (keys[n] == "Artist") { artist = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); if (!artist.isEmpty()) { if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(artist.ascii(),artist.length()) < 0 )) { mrl.setArtist(altCodec->toUnicode(artist.ascii())); } else { mrl.setArtist(artist); } } } if (keys[n] == "Album") { album = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); if (!album.isEmpty()) { if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(album.ascii(),album.length()) < 0 )) { mrl.setAlbum(altCodec->toUnicode(album.ascii())); } else { mrl.setAlbum(album); } } } if (keys[n] == "Tracknumber") mrl.setTrack(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); if (keys[n] == "Date") mrl.setYear(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); if (keys[n] == "Genre") mrl.setGenre(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace()); } } delete metaInfo; } void PlayList::mergeMeta(const MRL& mrl) { if (!m_currentEntry) return; PlaylistItem* tmp = dynamic_cast(m_currentEntry); bool addTime = (tmp->length() == TQString("00:00:00")); if ((tmp) && (tmp->url() == mrl.url())) { tmp->setTitle(mrl.title()); tmp->setArtist(mrl.artist()); tmp->setAlbum(mrl.album()); tmp->setTrack(mrl.track()); tmp->setYear(mrl.year()); tmp->setGenre(mrl.genre()); tmp->setLength(mrl.length().toString("h:mm:ss")); tmp->setCurrentSubtitle(mrl.currentSubtitle()); tmp->setSubtitles(mrl.subtitleFiles()); } if (addTime) { if (tmp->length().contains(':')); { m_playTime += timeStringToMs(tmp->length()); if (tmp->isVisible()) m_playTimeVisible += timeStringToMs(tmp->length()); updateStatus(); } } roller->setTitle( mrl ); setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace() ); } GalleryDialog::GalleryDialog( TQWidget *parent, GoogleFetcher *goog ) : KDialogBase( parent, TQString(i18n("Gallery")).latin1(), true, TQString(), Ok, NoDefault, true ) { google = goog; hbox = new TQHBox(this); imageFrame = new TQFrame( hbox ); imageFrame->setFixedSize(500,500); setMainWidget(hbox); connect( &next, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotNext()) ); next.start(1000,true); } void GalleryDialog::slotNext() { TQPixmap pix; bool end; actionButton(Ok)->setEnabled(false); loop: TQImage img = google->galleryNext( end ); if ( end ) { slotOk(); return; } if ( !img.isNull() ) { if ( img.width()>img.height() ) imageFrame->setFixedSize(500, 500*img.height()/img.width()); else imageFrame->setFixedSize(500*img.width()/img.height(), 500); img = img.smoothScale(imageFrame->width(),imageFrame->height()); pix.convertFromImage( img ); imageFrame->setPaletteBackgroundPixmap( pix ); } else goto loop; actionButton(Ok)->setEnabled(true); next.start(5000,true); } void GalleryDialog::slotOk() { if ( next.isActive() ) next.stop(); hide(); } void PlayList::showGallery() { if ( google ) return; TQString s = getCurrent().artist().stripWhiteSpace(); if ( s.isEmpty() ) return; google = new GoogleFetcher( s, "", true ); GalleryDialog dlg( 0, google ); dlg.exec(); delete google; google = NULL; } void PlayList::setCover( TQString s1, TQString s2, bool forceFetch ) { if ( s1.isEmpty() || s2.isEmpty() ) { coverFrame->setCoverPixmap( "" ); return; } TQString s = locateLocal("appdata", ""); TQImage img; TQPixmap pix; TQString fname = s1+"_"+s2; fname = fname.replace( TQChar( '/' ), "_" ); fname = fname.upper(); fname = s+"covers/"+fname; if ( !forceFetch && TQFile( fname ).exists() ) coverFrame->setCoverPixmap( fname ); else { if ( !forceFetch ) coverFrame->setCoverPixmap( "" ); if ( google ) return; if ( m_cover || forceFetch ) { google = new GoogleFetcher( s1, s2 ); pix = google->pixmap( forceFetch ); delete google; google = NULL; } if ( !TQDir( s+"covers" ).exists() ) TQDir().mkdir( s+"covers" ); if ( !pix.isNull() ) { img = pix.convertToImage(); img.save( fname, coverImageFormat.latin1() ); MRL mrl = getCurrent(); if ( s1==mrl.artist().stripWhiteSpace() && s2==mrl.album().stripWhiteSpace() ) coverFrame->setCoverPixmap( fname ); } else if ( !forceFetch && m_cover ) { TQString path = locate("appdata", "nocover.png"); if ( !path ) path = locate("data", "kaffeine/nocover.png"); TDEIO::file_copy( KURL::fromPathOrURL( path ), KURL::fromPathOrURL( fname ), -1, true ); } } } void PlayList::chooseCurrentCover() { MRL mrl = getCurrent(); setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace(), true ); } /************ sort playlist ******************/ void PlayList::slotSort(int section) { m_list->setSorting(section, m_sortAscending); m_list->sort(); m_sortAscending = !m_sortAscending; } /*** remove items ***/ void PlayList::slotRemoveSelected() { TQPtrList selected; if (m_currentEntry) if (m_currentEntry->isSelected()) { m_currentEntry = NULL; m_currentRandomListEntry = -1; } selected = m_list->selectedItems(); PlaylistItem* item = NULL; for(uint i = 0; itext(TITLE_COLUMN) << "\n"; item = dynamic_cast(selected.at(i)); if (item->length().contains(':')) { m_playTime -= timeStringToMs(item->length()); m_playTimeVisible -= timeStringToMs(item->length()); } m_countVisible--; delete selected.at(i); } if (m_random) createRandomList(); updateStatus(); } void PlayList::updateStatus() { TQString status; if (isQueueMode()) { TQTime total; TQValueList::ConstIterator end(m_queue.end()); for (TQValueList::ConstIterator it = m_queue.begin(); it != end; ++it) total = total.addSecs(TQTime().secsTo((*it).length())); status = i18n("Queue: %1 Entries, Playtime: %2").arg(m_queue.count()).arg(total.toString("h:mm:ss")); } else { //status = i18n("Entries: %1, Playtime: %2 (Total: %3, %4)").arg(TQString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)).arg(TQString::number(m_list->childCount())).arg(msToTimeString(m_playTime)); status = i18n("Entries: %1, Playtime: %2").arg(TQString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)); } emit statusBarMessage(status); } void PlayList::slotNewList() { m_list->setSorting(-1); saveCurrentPlaylist(); m_playlistSelector->insertItem(i18n("Playlist") + TQString::number(m_nextPlaylistNumber), 0); m_nextPlaylistNumber++; m_playlistSelector->setCurrentItem(0); m_currentPlaylist = 0; clearList(); } void PlayList::setPlaylist(const TQString& name, bool clear) { saveCurrentPlaylist(); if (clear) clearList(); int index = 0; if (m_playlistSelector->listBox()->findItem(name)) index = m_playlistSelector->listBox()->index(m_playlistSelector->listBox()->findItem(name)); else m_playlistSelector->insertItem(name, 0); m_playlistSelector->setCurrentItem(index); m_currentPlaylist = index; } void PlayList::nextPlaylist() { int nextPlaylist = m_playlistSelector->currentItem(); TQString pl = NULL; do { nextPlaylist++; if (nextPlaylist == m_playlistSelector->count()) nextPlaylist = 0; pl = m_playlistSelector->text(nextPlaylist); } while (nextPlaylist != m_playlistSelector->currentItem()); saveCurrentPlaylist(); clearList(); m_playlistSelector->setCurrentItem(nextPlaylist); m_currentPlaylist = nextPlaylist; add(m_playlistDirectory + pl + ".kaffeine", NULL); if (mainWidget->parentWidget()) mainWidget->parentWidget()->setFocus(); } void PlayList::slotPlaylistActivated(int index) { kdDebug() << "PlayList: Switch to playlist: " << m_playlistSelector->text(index) << endl; TQString pl = m_playlistSelector->text(index); saveCurrentPlaylist(); clearList(); m_currentPlaylist = index; add(m_playlistDirectory + pl + ".kaffeine", NULL); if (mainWidget->parentWidget()) mainWidget->parentWidget()->setFocus(); /* if (!isQueueMode()) { getCurrent(); emit signalPlay(m_currentEntryMRL); } */ } void PlayList::slotNewPlaylistName(const TQString& text) { if ((text.isEmpty()) || (text == m_playlistSelector->text(m_currentPlaylist))) return; if (m_playlistSelector->listBox()->findItem(text)) { kdDebug() << "PlayList: Name still exists!" << endl; return; } TQString oldPl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine"; kdDebug() << "Playlist: removing file: " << oldPl << endl; if (!TDEIO::NetAccess::del(oldPl, mainWidget)) kdError() << "Playlist: " << TDEIO::NetAccess::lastErrorString() << endl; kdDebug() << "PlayList: Set playlist name to: " << text << endl; m_playlistSelector->changeItem(text, m_currentPlaylist); saveCurrentPlaylist(); if (mainWidget->parentWidget()) mainWidget->parentWidget()->setFocus(); } TQString PlayList::queryCurrentPlaylist() { TQString pl = m_playlistSelector->text(m_currentPlaylist); return (m_playlistDirectory + pl + ".kaffeine"); } void PlayList::saveCurrentPlaylist() { TQString pl = m_playlistSelector->text(m_currentPlaylist); savePlaylist(m_playlistDirectory + pl + ".kaffeine"); } void PlayList::removeCurrentPlaylist() { int code = KMessageBox::warningContinueCancel(0, i18n("Remove '%1' from list and from disk?").arg(m_playlistSelector->text(m_currentPlaylist)),TQString(),KStdGuiItem::del()); if (code == KMessageBox::Continue) { TQString pl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine"; if (!TDEIO::NetAccess::del(pl, mainWidget)) kdError() << "Playlist: " << TDEIO::NetAccess::lastErrorString() << endl; m_playlistSelector->removeItem(m_currentPlaylist); m_currentPlaylist = m_playlistSelector->currentItem(); clearList(); add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL); } } void PlayList::loadPlaylist(const TQString& pl) { saveCurrentPlaylist(); TQString plName = KURL(pl).fileName(); plName = plName.remove(".kaffeine", false); if (m_playlistSelector->listBox()->findItem(plName)) { TQString plNewName = NULL; while (true) { bool ok; plNewName = TQInputDialog::getText(i18n("Playlist Name Already Exists"), i18n("Enter different playlist name:"), TQLineEdit::Normal, plName, &ok); if ((ok) && (!plNewName.isEmpty())) { if (m_playlistSelector->listBox()->findItem(plNewName)) continue; else break; } else { kdDebug() << "Playlist: Import aborted, playlist not added" << endl; return; } } plName = plNewName; } m_playlistSelector->insertItem(plName, 0); m_playlistSelector->setCurrentItem(0); m_currentPlaylist = 0; clearList(); add(pl, NULL); } /****************************************** * save xml playlist ******************************************/ void PlayList::savePlaylist(const TQString& pl) { TQDomDocument doc("playlist"); doc.setContent(TQString("")); TQDomElement root = doc.createElement("playlist"); root.setAttribute("client", "kaffeine"); doc.appendChild(root); TQDomElement entry; PlaylistItem * tmp = NULL; TQListViewItemIterator it(m_list); while (it.current()) { tmp = dynamic_cast(it.current()); entry = doc.createElement("entry"); entry.setAttribute("title", tmp->title()); entry.setAttribute("artist", tmp->artist()); entry.setAttribute("album", tmp->album()); entry.setAttribute("track", tmp->track()); entry.setAttribute("year", tmp->year()); entry.setAttribute("genre", tmp->genre()); entry.setAttribute("url", tmp->url()); entry.setAttribute("mime", tmp->mime()); entry.setAttribute("length", tmp->length()); if(!(tmp->subtitles().isEmpty())) { TQString subList; for(unsigned int i=0; isubtitles().count(); i++) subList += tmp->subtitles()[i] + "&"; entry.setAttribute("subs", subList); } entry.setAttribute("currentSub", TQString::number(tmp->currentSubtitle())); root.appendChild(entry); ++it; } TQFile file(pl); if (!file.open(IO_WriteOnly)) return; TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); stream << doc.toString(); file.close(); m_list->setCleared(false); } /**********************/ void PlayList::exportM3UPlaylist(const TQString& pl) { PlaylistItem * tmp = NULL; TQListViewItemIterator it(m_list); int length = -1; TQString m3uList = "#EXTM3U\n"; while (it.current()) { tmp = dynamic_cast(it.current()); length = timeStringToMs(tmp->length()) / 1000; if ( length == 0 ) length = -1; m3uList.append("#EXTINF:" + TQString::number(length) + "," + tmp->title()); if (tmp->artist().isEmpty() ) m3uList.append("\n"); else m3uList.append(" - " + tmp->artist() + "\n"); m3uList.append(tmp->url() + "\n"); ++it; } TQFile file(pl); if (!file.open(IO_WriteOnly)) return; TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); stream << m3uList; file.close(); } void PlayList::exportPLSPlaylist(const TQString& pl) { PlaylistItem * tmp = NULL; TQListViewItemIterator it(m_list); int counter = 0; int length = -1; TQString plsList = "[playlist]\n"; while (it.current()) { tmp = dynamic_cast(it.current()); ++counter; length = timeStringToMs(tmp->length()) / 1000; if ( length == 0 ) { length = -1; } plsList.append("File" + TQString::number(counter) + "=" + tmp->url() + "\n"); plsList.append("Title" + TQString::number(counter) + "=" + tmp->title()); if (tmp->artist().isEmpty() ) plsList.append("\n"); else plsList.append(" - " + tmp->artist() + "\n"); plsList.append("Length" + TQString::number(counter) + "=" + TQString::number(length) + "\n"); ++it; } plsList.append("NumberOfEntries=" + TQString::number(counter) + "\n"); plsList.append("Version=2"); TQFile file(pl); if (!file.open(IO_WriteOnly)) return; TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); stream << plsList; file.close(); } void PlayList::resetSearch() { m_playlistFilter->clear(); slotFindText( "" ); } void PlayList::slotFindText(const TQString& text) { if (text == i18n("Filter")) return; TQListViewItemIterator it(m_list); m_playTimeVisible = 0; m_countVisible = 0; PlaylistItem* tmp = NULL; while ( it.current() ) { tmp = dynamic_cast(it.current()); if (text.isEmpty() || tmp->title().contains(text, false) || tmp->url().contains(text, false) || tmp->artist().contains(text, false) || tmp->album().contains(text, false) ) { tmp->setVisible(true); if (tmp->length().contains(':')) m_playTimeVisible += timeStringToMs(tmp->length()); m_countVisible++; } else { tmp->setVisible(false); if (tmp == m_currentEntry) { tmp->setPixmap(TITLE_COLUMN, TQPixmap()); m_currentEntry = NULL; m_currentRandomListEntry = -1; } } ++it; } if (text.isEmpty()) m_searchSelection = false; else m_searchSelection = true; if (m_random) createRandomList(); updateStatus(); } /***************** cut/copy/paste *************************/ void PlayList::slotCut() { slotCopy(); slotRemoveSelected(); } void PlayList::slotPaste() { TQPtrList selected; selected = m_list->selectedItems(); TQListViewItem* lastSelected = NULL; if (selected.count()) lastSelected = selected.at(selected.count() - 1); else lastSelected = m_list->lastItem(); TQStrList list; if (TQUriDrag::decode(TQApplication::clipboard()->data(), list)) { TQStringList urls; for (TQStrListIterator it(list); *it; ++it) urls.append(TQUriDrag::uriToUnicodeUri(*it)); add(urls, lastSelected); return; } /** try to decode as text **/ TQString text; if (TQTextDrag::decode(TQApplication::clipboard()->data(), text)) { add(text, lastSelected); } } void PlayList::slotCopy() { TQPtrList selected; selected = m_list->selectedItems(); TQStrList urlList; for (uint i=0; i(selected.at(i))->url())); } TQApplication::clipboard()->setData(new TQUriDrag(urlList)); } void PlayList::slotSelectAll() { TQListViewItemIterator it(m_list); while (it.current()) { if ((*it)->isVisible()) m_list->setSelected(*it, true); ++it; } } void PlayList::slotPlaylistFromSelected() { TQPtrList selected; selected = m_list->selectedItems(); TQValueList mrlList; for (uint i=0; i(selected.at(i))->toMRL()); } if (mrlList.count()) { slotNewList(); add(mrlList, NULL); } } void PlayList::slotAddToQueue(MRL mrl) { m_queue.append(mrl); updateStatus(); } /**** helper ****/ TQString PlayList::msToTimeString(int msec) { /* TQTime t; t = t.addMSecs(msec); return t.toString("h:mm:ss"); */ /* can be >24h */ int hours; int min; int sec; int my_msec=msec; TQString tmp; TQString t; msec = msec/1000; //sec hours = msec/3600; my_msec -= hours*3600*1000; t = t.setNum(hours); t.append(":"); msec = msec - (hours*3600); min = msec / 60; my_msec -= min*60*1000; tmp = tmp.setNum(min); tmp = tmp.rightJustify(2, '0'); t.append(tmp); t.append(":"); sec = msec - (min*60); my_msec -= sec*1000; if(my_msec > 500) sec++; tmp = tmp.setNum(sec); tmp = tmp.rightJustify(2, '0'); t.append(tmp); return t; } int PlayList::timeStringToMs(const TQString& timeString) { int sec = 0; TQStringList tokens = TQStringList::split(':',timeString); bool ok = false; sec += tokens[0].toInt(&ok)*3600; //hours if (!ok) return 0; sec += tokens[1].toInt(&ok)*60; //minutes if (!ok) return 0; sec += tokens[2].toInt(&ok); //secs if (ok) return sec*1000; //return millisecs else return 0; } bool PlayList::endsWith(TQString s1, TQString s2, bool caseSensitive ) { if ( s1.isNull() || s2.isNull() ) return false; int startPos = s1.length() - s2.length(); for (unsigned int i = 0; i < s2.length(); i++ ) { if(caseSensitive) { if ( s1[startPos + i] != s2[i] ) return false; } else { if ( s1[startPos + i].lower() != s2[i].lower() ) return false; } } return true; } bool PlayList::startsWith(TQString s1, TQString s2, bool caseSensitive ) { if ( s1.isNull() || s2.isNull() ) return false; if(s2.length() > s1.length()) return false; for (unsigned int i = 0; i < s2.length(); i++ ) { if(caseSensitive) { if ( s1[i] != s2[i] ) return false; } else { if ( s1[i].lower() != s2[i].lower() ) return false; } } return true; } SubtitleChooser::SubtitleChooser(TQStringList values, TQString filename,TQWidget *parent, const char * name) : KDialogBase(parent,name,true,i18n("Select Subtitle"), Ok|Cancel, Ok, true) { TQVBox *page = makeVBoxMainWidget(); TQLabel *label = new TQLabel(page); label->setText("" + i18n("Media file:") + " " + filename + ""); table = new TQListBox(page); this->setMinimumSize(300,200); table->setFocus(); table->insertStringList(values); table->setSelected(0, true); } SubtitleChooser::~SubtitleChooser(){} TQString SubtitleChooser::getSelection() { return table->selectedItem()->text(); } MovieChooser::MovieChooser(TQStringList values, TQString filename,TQWidget *parent, const char * name) : KDialogBase(parent,name,true,i18n("Select Movie"), Ok|Cancel, Ok, true) { TQVBox *page = makeVBoxMainWidget(); TQLabel *label = new TQLabel(page); label->setText(" " + i18n("Subtitle file:") + " " + filename + ""); table = new TQListBox(page); this->setMinimumSize(450,200); table->setFocus(); table->insertStringList(values); table->setSelected(0, true); } MovieChooser::~MovieChooser(){} TQString MovieChooser::getSelection() { return table->selectedItem()->text(); }