You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmplayer/src/kmplayerpartbase.cpp

2055 lines
73 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/**
* Copyright (C) 2002-2003 by Koos Vriezen <koos.vriezen@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#ifdef KDE_USE_FINAL
#undef Always
#endif
#include <config.h>
#include <math.h>
#include <tqapplication.h>
#include <tqcstring.h>
#include <tqcursor.h>
#include <tqtimer.h>
#include <tqpair.h>
#include <tqpushbutton.h>
#include <tqpopupmenu.h>
#include <tqslider.h>
#include <tqfile.h>
#include <tqregexp.h>
#include <tqtextstream.h>
#include <tdemessagebox.h>
#include <tdeaboutdata.h>
#include <kdebug.h>
#include <kbookmarkmenu.h>
#include <kbookmarkmanager.h>
#include <tdeconfig.h>
#include <ksimpleconfig.h>
#include <tdeaction.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include <kmimetype.h>
#include <kprotocolinfo.h>
#include <tdeapplication.h>
#include <kstaticdeleter.h>
#include <tdeio/job.h>
#include <tdeio/jobclasses.h>
#include "kmplayerpartbase.h"
#include "kmplayerview.h"
#include "playlistview.h"
#include "viewarea.h"
#include "kmplayercontrolpanel.h"
#include "kmplayerconfig.h"
#include "kmplayerprocess.h"
#include "kmplayer_smil.h"
namespace KMPlayer {
class KMPLAYER_NO_EXPORT BookmarkOwner : public KBookmarkOwner {
public:
BookmarkOwner (PartBase *);
KDE_NO_CDTOR_EXPORT virtual ~BookmarkOwner () {}
void openBookmarkURL(const TQString& _url);
TQString currentTitle() const;
TQString currentURL() const;
private:
PartBase * m_player;
};
class KMPLAYER_NO_EXPORT BookmarkManager : public KBookmarkManager {
public:
BookmarkManager (const TQString &);
};
} // namespace
using namespace KMPlayer;
KDE_NO_CDTOR_EXPORT BookmarkOwner::BookmarkOwner (PartBase * player)
: m_player (player) {}
KDE_NO_EXPORT void BookmarkOwner::openBookmarkURL (const TQString & url) {
m_player->openURL (KURL (url));
}
KDE_NO_EXPORT TQString BookmarkOwner::currentTitle () const {
return m_player->source ()->prettyName ();
}
KDE_NO_EXPORT TQString BookmarkOwner::currentURL () const {
return m_player->source ()->url ().url ();
}
inline BookmarkManager::BookmarkManager(const TQString & bmfile)
: KBookmarkManager (bmfile, false) {
}
//-----------------------------------------------------------------------------
PartBase::PartBase (TQWidget * wparent, const char *wname,
TQObject * parent, const char *name, TDEConfig * config)
: KMediaPlayer::Player (wparent, wname ? wname : "kde_kmplayer_view", parent, name ? name : "kde_kmplayer_part"),
m_config (config),
m_view (new View (wparent, wname ? wname : "kde_kmplayer_view")),
m_settings (new Settings (this, config)),
m_recorder (0L),
m_source (0L),
m_bookmark_menu (0L),
m_record_timer (0),
m_update_tree_timer (0),
m_noresize (false),
m_auto_controls (true),
m_bPosSliderPressed (false),
m_in_update_tree (false)
{
MPlayer *mplayer = new MPlayer (this, m_settings);
m_players ["mplayer"] = mplayer;
m_process = mplayer;
Xine * xine = new Xine (this, m_settings);
m_players ["xine"] = xine;
m_players ["gstreamer"] = new GStreamer (this, m_settings);
m_recorders ["mencoder"] = new MEncoder (this, m_settings);
m_recorders ["mplayerdumpstream"] = new MPlayerDumpstream(this, m_settings);
m_recorders ["ffmpeg"] = new FFMpeg (this, m_settings);
m_recorders ["xine"] = xine;
m_sources ["urlsource"] = new URLSource (this);
TQString bmfile = locate ("data", "kmplayer/bookmarks.xml");
TQString localbmfile = locateLocal ("data", "kmplayer/bookmarks.xml");
if (localbmfile != bmfile) {
kdDebug () << "cp " << bmfile << " " << localbmfile << endl;
TDEProcess p;
p << "/bin/cp" << TQString(TQFile::encodeName (bmfile)) << TQString(TQFile::encodeName (localbmfile));
p.start (TDEProcess::Block);
}
m_bookmark_manager = new BookmarkManager (localbmfile);
m_bookmark_owner = new BookmarkOwner (this);
}
void PartBase::showConfigDialog () {
m_settings->show ("URLPage");
}
KDE_NO_EXPORT void PartBase::showPlayListWindow () {
// note, this is also the slot of application's view_playlist action, but
// anyhow, actions don't work for the fullscreen out-of-the-box, so ...
if (m_view->viewArea ()->isFullScreen ())
fullScreen ();
else if (m_view->viewArea ()->isMinimalMode ())
; //done by app: m_view->viewArea ()->minimalMode ();
else
m_view->toggleShowPlaylist ();
}
KDE_NO_EXPORT void PartBase::addBookMark (const TQString & t, const TQString & url) {
KBookmarkGroup b = m_bookmark_manager->root ();
b.addBookmark (m_bookmark_manager, t, KURL (url));
m_bookmark_manager->emitChanged (b);
}
void PartBase::init (TDEActionCollection * action_collection) {
KParts::Part::setWidget (m_view);
m_view->init (action_collection);
#ifdef HAVE_NSPR
m_players ["npp"] = new NpPlayer (this, m_settings, m_service);
#endif
connect(m_settings, TQT_SIGNAL(configChanged()), this, TQT_SLOT(settingsChanged()));
m_settings->readConfig ();
m_settings->applyColorSetting (false);
m_bookmark_menu = new KBookmarkMenu (m_bookmark_manager, m_bookmark_owner, m_view->controlPanel ()->bookmarkMenu (), action_collection, true, true);
connect (m_view, TQT_SIGNAL (urlDropped (const KURL::List &)), this, TQT_SLOT (openURL (const KURL::List &)));
connectPlaylist (m_view->playList ());
connectInfoPanel (m_view->infoPanel ());
new TDEAction (i18n ("Edit playlist &item"), 0, 0, TQT_TQOBJECT(m_view->playList ()), TQT_SLOT (editCurrent ()), action_collection, "edit_playlist_item");
}
void PartBase::connectPanel (ControlPanel * panel) {
panel->contrastSlider ()->setValue (m_settings->contrast);
panel->brightnessSlider ()->setValue (m_settings->brightness);
panel->hueSlider ()->setValue (m_settings->hue);
panel->saturationSlider ()->setValue (m_settings->saturation);
panel->volumeBar ()->setValue (m_settings->volume);
connect (panel->button (ControlPanel::button_playlist), TQT_SIGNAL (clicked ()), this, TQT_SLOT (showPlayListWindow ()));
connect (panel->button (ControlPanel::button_back), TQT_SIGNAL (clicked ()), this, TQT_SLOT (back ()));
connect (panel->button (ControlPanel::button_play), TQT_SIGNAL (clicked ()), this, TQT_SLOT (play ()));
connect (panel->button (ControlPanel::button_forward), TQT_SIGNAL (clicked ()), this, TQT_SLOT (forward ()));
connect (panel->button (ControlPanel::button_pause), TQT_SIGNAL (clicked ()), this, TQT_SLOT (pause ()));
connect (panel->button (ControlPanel::button_stop), TQT_SIGNAL (clicked ()), this, TQT_SLOT (stop ()));
connect (panel->button (ControlPanel::button_record), TQT_SIGNAL (clicked()), this, TQT_SLOT (record()));
connect (panel->volumeBar (), TQT_SIGNAL (volumeChanged (int)), this, TQT_SLOT (volumeChanged (int)));
connect (panel->positionSlider (), TQT_SIGNAL (valueChanged (int)), this, TQT_SLOT (positionValueChanged (int)));
connect (panel->positionSlider (), TQT_SIGNAL (sliderPressed()), this, TQT_SLOT (posSliderPressed()));
connect (panel->positionSlider (), TQT_SIGNAL (sliderReleased()), this, TQT_SLOT (posSliderReleased()));
connect (this, TQT_SIGNAL (positioned (int, int)), panel, TQT_SLOT (setPlayingProgress (int, int)));
connect (this, TQT_SIGNAL (loading(int)), panel, TQT_SLOT(setLoadingProgress(int)));
connect (panel->contrastSlider (), TQT_SIGNAL (valueChanged(int)), this, TQT_SLOT (contrastValueChanged(int)));
connect (panel->brightnessSlider (), TQT_SIGNAL (valueChanged(int)), this, TQT_SLOT (brightnessValueChanged(int)));
connect (panel->hueSlider (), TQT_SIGNAL (valueChanged(int)), this, TQT_SLOT (hueValueChanged(int)));
connect (panel->saturationSlider (), TQT_SIGNAL (valueChanged(int)), this, TQT_SLOT (saturationValueChanged(int)));
connect (this, TQT_SIGNAL (languagesUpdated(const TQStringList &, const TQStringList &)), panel, TQT_SLOT (setLanguages (const TQStringList &, const TQStringList &)));
connect (panel->audioMenu (), TQT_SIGNAL (activated (int)), this, TQT_SLOT (audioSelected (int)));
connect (panel->subtitleMenu (), TQT_SIGNAL (activated (int)), this, TQT_SLOT (subtitleSelected (int)));
connect (this, TQT_SIGNAL (audioIsSelected (int)), panel, TQT_SLOT (selectAudioLanguage (int)));
connect (this, TQT_SIGNAL (subtitleIsSelected (int)), panel, TQT_SLOT (selectSubtitle (int)));
panel->popupMenu()->connectItem (ControlPanel::menu_fullscreen, this, TQT_SLOT (fullScreen ()));
panel->popupMenu ()->connectItem (ControlPanel::menu_config,
this, TQT_SLOT (showConfigDialog ()));
panel->popupMenu ()->connectItem (ControlPanel::menu_video,
m_view, TQT_SLOT(toggleVideoConsoleWindow()));
panel->popupMenu ()->connectItem (ControlPanel::menu_playlist,
m_view, TQT_SLOT (toggleShowPlaylist ()));
panel->popupMenu ()->connectItem (ControlPanel::menu_minimal,
this, TQT_SLOT (minimalMode ()));
connect (this, TQT_SIGNAL (statusUpdated (const TQString &)),
panel->view (), TQT_SLOT (setStatusMessage (const TQString &)));
//connect (panel (), TQT_SIGNAL (clicked ()), m_settings, TQT_SLOT (show ()));
}
void PartBase::connectPlaylist (PlayListView * playlist) {
connect (playlist, TQT_SIGNAL (addBookMark (const TQString &, const TQString &)),
this, TQT_SLOT (addBookMark (const TQString &, const TQString &)));
connect (playlist, TQT_SIGNAL (executed (TQListViewItem *)),
this, TQT_SLOT (playListItemExecuted (TQListViewItem *)));
connect (playlist, TQT_SIGNAL (clicked (TQListViewItem *)),
this, TQT_SLOT (playListItemClicked (TQListViewItem *)));
connect (this, TQT_SIGNAL (treeChanged (int, NodePtr, NodePtr, bool, bool)),
playlist, TQT_SLOT (updateTree (int, NodePtr, NodePtr, bool, bool)));
connect (this, TQT_SIGNAL (treeUpdated ()),
playlist, TQT_SLOT (triggerUpdate ()));
}
void PartBase::connectInfoPanel (InfoWindow * infopanel) {
connect (this, TQT_SIGNAL (infoUpdated (const TQString &)),
infopanel->view (), TQT_SLOT (setInfoMessage (const TQString &)));
}
PartBase::~PartBase () {
kdDebug() << "PartBase::~PartBase" << endl;
m_view = (View*) 0;
stop ();
if (m_source)
m_source->deactivate ();
delete m_settings;
delete m_bookmark_menu;
delete m_bookmark_manager;
delete m_bookmark_owner;
}
void PartBase::settingsChanged () {
if (!m_view)
return;
if (m_settings->showcnfbutton)
m_view->controlPanel()->button (ControlPanel::button_config)->show();
else
m_view->controlPanel()->button (ControlPanel::button_config)->hide();
m_view->controlPanel()->enableRecordButtons (m_settings->showrecordbutton);
if (m_settings->showplaylistbutton)
m_view->controlPanel()->button (ControlPanel::button_playlist)->show();
else
m_view->controlPanel()->button (ControlPanel::button_playlist)->hide();
if (!m_settings->showbroadcastbutton)
m_view->controlPanel ()->broadcastButton ()->hide ();
keepMovieAspect (m_settings->sizeratio);
m_settings->applyColorSetting (true);
}
KMediaPlayer::View* PartBase::view () {
return m_view;
}
extern const char * strGeneralGroup;
bool PartBase::setProcess (Mrl *mrl) {
// determine backend, start with temp_backends
TQString p = temp_backends [m_source->name()];
bool remember_backend = p.isEmpty ();
bool changed = false;
if (p.isEmpty ()) {
// next try to find mimetype match from kmplayerrc
if (!mrl->mimetype.isEmpty ()) {
m_config->setGroup (mrl->mimetype);
p = m_config->readEntry ("player", "" );
remember_backend = !(!p.isEmpty () &&
m_players.contains (p) &&
m_players [p]->supports (m_source->name ()));
}
}
if (p.isEmpty ())
// try source match from kmplayerrc
p = m_settings->backends [m_source->name()];
if (p.isEmpty ()) {
// try source match from kmplayerrc by re-reading
m_config->setGroup (strGeneralGroup);
p = m_config->readEntry (m_source->name (), "");
}
if (p.isEmpty () ||
!m_players.contains (p) ||
!m_players [p]->supports (m_source->name ())) {
// finally find first supported player
p.truncate (0);
if (!m_process || !m_process->supports (m_source->name ())) {
ProcessMap::const_iterator i, e = m_players.end();
for (i = m_players.begin(); i != e; ++i)
if (i.data ()->supports (m_source->name ())) {
p = TQString (i.data ()->name ());
break;
}
} else
p = TQString (m_process->name ());
}
if (!p.isEmpty ()) {
if (!m_process || p != m_process->name ()) {
setProcess (p.ascii ());
updatePlayerMenu (m_view->controlPanel ());
changed = true;
}
if (remember_backend)
m_settings->backends [m_source->name()] = m_process->name ();
else
temp_backends.remove (m_source->name());
}
return changed;
}
void PartBase::setProcess (const char * name) {
Process * process = name ? m_players [name] : 0L;
if (m_process == process)
return;
if (!m_source)
m_source = m_sources ["urlsource"];
Process * old_process = m_process;
m_process = process;
if (old_process && old_process->state () > Process::NotRunning)
old_process->quit ();
if (!m_process)
return;
m_process->setSource (m_source);
if (m_process->playing ()) {
m_view->controlPanel ()->setPlaying (true);
m_view->controlPanel ()->showPositionSlider (!!m_source->length ());
m_view->controlPanel ()->enableSeekButtons (m_source->isSeekable ());
}
emit processChanged (name);
}
void PartBase::setRecorder (const char * name) {
Process * recorder = name ? m_recorders [name] : 0L;
if (m_recorder == recorder)
return;
if (m_recorder)
m_recorder->quit ();
m_recorder = recorder;
}
KDE_NO_EXPORT void PartBase::slotPlayerMenu (int id) {
bool playing = m_process->playing ();
const char * srcname = m_source->name ();
TQPopupMenu * menu = m_view->controlPanel ()->playerMenu ();
ProcessMap::const_iterator pi = m_players.begin(), e = m_players.end();
unsigned i = 0;
for (; pi != e && i < menu->count(); ++pi) {
Process * proc = pi.data ();
if (!proc->supports (srcname))
continue;
int menuid = menu->idAt (i);
menu->setItemChecked (menuid, menuid == id);
if (menuid == id) {
if (proc->name () != TQString ("npp"))
m_settings->backends [srcname] = proc->name ();
temp_backends [srcname] = proc->name ();
if (playing && strcmp (m_process->name (), proc->name ()))
m_process->quit ();
setProcess (proc->name ());
}
++i;
}
if (playing)
setSource (m_source); // re-activate
}
void PartBase::updatePlayerMenu (ControlPanel * panel) {
if (!m_view || !m_process)
return;
TQPopupMenu * menu = panel->playerMenu ();
menu->clear ();
if (!m_source)
return;
const ProcessMap::const_iterator e = m_players.end();
int id = 0; // if multiple parts, id's should be the same for all menu's
for (ProcessMap::const_iterator i = m_players.begin(); i != e; ++i) {
Process * p = i.data ();
if (p->supports (m_source->name ())) {
menu->insertItem (p->menuName (), this, TQT_SLOT (slotPlayerMenu (int)), 0, id++);
if (i.data() == m_process)
menu->setItemChecked (id-1, true);
}
}
}
void PartBase::connectSource (Source * old_source, Source * source) {
if (old_source) {
disconnect (old_source, TQT_SIGNAL(endOfPlayItems ()), this, TQT_SLOT(stop ()));
disconnect (old_source, TQT_SIGNAL (dimensionsChanged ()),
this, TQT_SLOT (sourceHasChangedAspects ()));
disconnect (old_source, TQT_SIGNAL (startPlaying ()),
this, TQT_SLOT (playingStarted ()));
disconnect (old_source, TQT_SIGNAL (stopPlaying ()),
this, TQT_SLOT (playingStopped ()));
}
if (source) {
connect (source, TQT_SIGNAL (endOfPlayItems ()), this, TQT_SLOT (stop ()));
connect (source, TQT_SIGNAL (dimensionsChanged ()),
this, TQT_SLOT (sourceHasChangedAspects ()));
connect (source, TQT_SIGNAL (startPlaying()), this, TQT_SLOT(playingStarted()));
connect (source, TQT_SIGNAL (stopPlaying ()), this, TQT_SLOT(playingStopped()));
}
}
void PartBase::setSource (Source * _source) {
Source * old_source = m_source;
if (m_source) {
m_source->deactivate ();
stop ();
if (m_view) {
m_view->reset ();
emit infoUpdated (TQString ());
}
disconnect (m_source, TQT_SIGNAL (startRecording ()),
this, TQT_SLOT (recordingStarted ()));
disconnect (this, TQT_SIGNAL (audioIsSelected (int)),
m_source, TQT_SLOT (setAudioLang (int)));
disconnect (this, TQT_SIGNAL (subtitleIsSelected (int)),
m_source, TQT_SLOT (setSubtitle (int)));
}
if (m_view) {
if (m_auto_controls)
m_view->controlPanel ()->setAutoControls (m_auto_controls);
m_view->controlPanel ()->enableRecordButtons (m_settings->showrecordbutton);
if (!m_settings->showcnfbutton)
m_view->controlPanel()->button(ControlPanel::button_config)->hide();
if (!m_settings->showplaylistbutton)
m_view->controlPanel()->button(ControlPanel::button_playlist)->hide();
}
m_source = _source;
connectSource (old_source, m_source);
m_process->setSource (m_source);
connect (m_source, TQT_SIGNAL(startRecording()), this,TQT_SLOT(recordingStarted()));
connect (this, TQT_SIGNAL (audioIsSelected (int)),
m_source, TQT_SLOT (setAudioLang (int)));
connect (this, TQT_SIGNAL (subtitleIsSelected (int)),
m_source, TQT_SLOT (setSubtitle (int)));
m_source->init ();
m_source->setIdentified (false);
if (m_view && m_view->viewer ()) {
updatePlayerMenu (m_view->controlPanel ());
m_view->viewer ()->setAspect (0.0);
}
if (m_source) TQTimer::singleShot (0, m_source, TQT_SLOT (activate ()));
updateTree (true, true);
emit sourceChanged (old_source, m_source);
}
KDE_NO_EXPORT void PartBase::changeURL (const TQString & url) {
emit urlChanged (url);
}
bool PartBase::isSeekable (void) const {
return m_source ? m_source->isSeekable () : false;
}
bool PartBase::hasLength () const {
return m_source ? m_source->hasLength () : false;
}
unsigned long PartBase::length () const {
return m_source ? m_source->length () : 0;
}
bool PartBase::openURL (const KURL & url) {
kdDebug () << "PartBase::openURL " << url.url() << url.isValid () << endl;
if (!m_view) return false;
stop ();
Source * src = (url.isEmpty () ? m_sources ["urlsource"] : (!url.protocol ().compare ("kmplayer") && m_sources.contains (url.host ()) ? m_sources [url.host ()] : m_sources ["urlsource"]));
src->setSubURL (KURL ());
src->setURL (url);
setSource (src);
return true;
}
bool PartBase::openURL (const KURL::List & urls) {
if (urls.size () == 1) {
openURL (urls[0]);
} else {
openURL (KURL ());
NodePtr d = m_source->document ();
if (d)
for (unsigned int i = 0; i < urls.size (); i++)
d->appendChild (new GenericURL (d, KURL::decode_string (urls [i].url ())));
}
return true;
}
bool PartBase::closeURL () {
stop ();
if (m_view) {
m_view->viewer ()->setAspect (0.0);
m_view->reset ();
}
return true;
}
bool PartBase::openFile () {
return false;
}
void PartBase::keepMovieAspect (bool b) {
if (m_view) {
m_view->setKeepSizeRatio (b);
if (m_source)
m_view->viewer ()->setAspect (b ? m_source->aspect () : 0.0);
}
}
void PartBase::recordingStarted () {
if (m_settings->replayoption == Settings::ReplayAfter)
m_record_timer = startTimer (1000 * m_settings->replaytime);
}
void PartBase::recordingStopped () {
killTimer (m_record_timer);
m_record_timer = 0;
Recorder * rec = dynamic_cast <Recorder*> (m_recorder);
if (rec) {
if (m_settings->replayoption == Settings::ReplayFinished ||
(m_settings->replayoption == Settings::ReplayAfter && !playing ()))
openURL (rec->recordURL ());
rec->setURL (KURL ());
}
setRecorder ("mencoder"); //FIXME see PartBase::record() checking playing()
}
void PartBase::timerEvent (TQTimerEvent * e) {
if (e->timerId () == m_record_timer) {
kdDebug () << "record timer event" << (m_recorder->playing () && !playing ()) << endl;
m_record_timer = 0;
if (m_recorder->playing () && !playing ()) {
Recorder * rec = dynamic_cast <Recorder*> (m_recorder);
if (rec) {
openURL (rec->recordURL ());
rec->setURL (KURL ());
}
}
} else if (e->timerId () == m_update_tree_timer) {
m_update_tree_timer = 0;
updateTree (m_update_tree_full, true);
}
killTimer (e->timerId ());
}
void PartBase::playingStarted () {
//m_view->viewer ()->setAspect (m_source->aspect ());
if (m_view) {
m_view->controlPanel ()->setPlaying (true);
m_view->controlPanel ()->showPositionSlider (!!m_source->length ());
m_view->controlPanel ()->enableSeekButtons (m_source->isSeekable ());
if (m_settings->autoadjustvolume && m_process)
m_process->volume(m_view->controlPanel()->volumeBar()->value(),true);
}
emit loading (100);
}
void PartBase::playingStopped () {
kdDebug () << "playingStopped " << this << endl;
if (m_view) {
m_view->controlPanel ()->setPlaying (false);
m_view->reset ();
}
m_bPosSliderPressed = false;
}
KDE_NO_EXPORT void PartBase::setPosition (int position, int length) {
if (m_view && !m_bPosSliderPressed)
emit positioned (position, length);
}
void PartBase::setLoaded (int percentage) {
emit loading (percentage);
}
unsigned long PartBase::position () const {
return m_source ? 100 * m_source->position () : 0;
}
void PartBase::pause () {
NodePtr doc = m_source ? m_source->document () : 0L;
if (doc) {
if (doc->state == Node::state_deferred)
doc->undefer ();
else
doc->defer ();
}
}
void PartBase::back () {
m_source->backward ();
}
void PartBase::forward () {
m_source->forward ();
}
KDE_NO_EXPORT void PartBase::playListItemClicked (TQListViewItem * item) {
if (!item)
return;
PlayListItem * vi = static_cast <PlayListItem *> (item);
RootPlayListItem * ri = vi->playListView ()->rootItem (item);
if (ri == item && vi->node) {
TQString src = ri->source;
//kdDebug() << "playListItemClicked " << src << " " << vi->node->nodeName() << endl;
Source * source = src.isEmpty() ? m_source : m_sources[src.ascii()];
if (vi->node->isPlayable ()) {
source->jump (vi->node); //may become !isPlayable by lazy loading
if (!vi->node->isPlayable ())
emit treeChanged (ri->id, vi->node, 0, false, true);
} else if (vi->firstChild ())
vi->listView ()->setOpen (vi, !vi->isOpen ());
} else if (!vi->node && !vi->m_attr)
updateTree (); // items already deleted
}
KDE_NO_EXPORT void PartBase::playListItemExecuted (TQListViewItem * item) {
if (m_in_update_tree) return;
if (m_view->editMode ()) return;
PlayListItem * vi = static_cast <PlayListItem *> (item);
RootPlayListItem * ri = vi->playListView ()->rootItem (item);
if (ri == item)
return; // both null or handled by playListItemClicked
if (vi->node) {
TQString src = ri->source;
//kdDebug() << "playListItemExecuted " << src << " " << vi->node->nodeName() << endl;
Source * source = src.isEmpty() ? m_source : m_sources[src.ascii()];
if (vi->node->isPlayable ()) {
source->jump (vi->node); //may become !isPlayable by lazy loading
if (!vi->node->isPlayable ())
emit treeChanged (ri->id, vi->node, 0, false, true);
} else if (vi->firstChild ())
vi->listView ()->setOpen (vi, !vi->isOpen ());
} else if (vi->m_attr) {
if (vi->m_attr->name () == StringPool::attr_src ||
vi->m_attr->name () == StringPool::attr_href ||
vi->m_attr->name () == StringPool::attr_url ||
vi->m_attr->name () == StringPool::attr_value ||
vi->m_attr->name () == "data") {
TQString src (vi->m_attr->value ());
if (!src.isEmpty ()) {
PlayListItem * pi = static_cast <PlayListItem*>(item->parent());
if (pi) {
for (NodePtr e = pi->node; e; e = e->parentNode ()) {
Mrl * mrl = e->mrl ();
if (mrl)
src = KURL (mrl->absolutePath (), src).url ();
}
KURL url (src);
if (url.isValid ())
openURL (url);
}
}
}
} else
emit treeChanged (ri->id, ri->node, 0L, false, false);
if (m_view)
m_view->viewArea ()->setFocus ();
}
void PartBase::updateTree (bool full, bool force) {
if (force) {
m_in_update_tree = true;
if (m_update_tree_full) {
if (m_source)
emit treeChanged (0, m_source->root (), m_source->current (), true, false);
} else
emit treeUpdated ();
m_in_update_tree = false;
if (m_update_tree_timer) {
killTimer (m_update_tree_timer);
m_update_tree_timer = 0;
}
} else if (!m_update_tree_timer) {
m_update_tree_timer = startTimer (100);
m_update_tree_full = full;
} else
m_update_tree_full |= full;
}
void PartBase::updateInfo (const TQString & msg) {
emit infoUpdated (msg);
}
void PartBase::updateStatus (const TQString & msg) {
emit statusUpdated (msg);
}
void PartBase::setLanguages (const TQStringList & al, const TQStringList & sl) {
emit languagesUpdated (al, sl);
}
KDE_NO_EXPORT void PartBase::audioSelected (int id) {
emit audioIsSelected (id);
}
KDE_NO_EXPORT void PartBase::subtitleSelected (int id) {
emit subtitleIsSelected (id);
}
void PartBase::record () {
if (m_view) m_view->setCursor (TQCursor (TQt::WaitCursor));
if (m_recorder->playing ()) {
m_recorder->stop ();
} else {
m_settings->show ("RecordPage");
m_view->controlPanel ()->setRecording (false);
}
if (m_view) m_view->setCursor (TQCursor (TQt::ArrowCursor));
}
void PartBase::play () {
if (!m_process || !m_view) return;
TQPushButton * pb = ::tqqt_cast <TQPushButton *> (sender ());
if (pb && !pb->isOn ()) {
stop ();
return;
}
if (m_update_tree_timer) {
killTimer (m_update_tree_timer);
m_update_tree_timer = 0;
}
if (m_process->state () == Process::NotRunning) {
PlayListItem * lvi = m_view->playList ()->currentPlayListItem ();
if (lvi) { // make sure it's in the first tree
TQListViewItem * pitem = lvi;
while (pitem->parent())
pitem = pitem->parent();
if (pitem != m_view->playList ()->firstChild ())
lvi = 0L;
}
if (!lvi)
lvi = static_cast<PlayListItem*>(m_view->playList()->firstChild());
if (lvi)
for (NodePtr n = lvi->node; n; n = n->parentNode ()) {
if (n->isPlayable ()) {
m_source->setCurrent (n);
break;
}
}
m_process->ready (m_view->viewer ());
} else if (m_process->state () == Process::Ready) {
m_source->playCurrent ();
} else
m_process->play (m_source, m_source->current ());
}
bool PartBase::playing () const {
return m_process && m_process->state () > Process::Ready;
}
void PartBase::stop () {
TQPushButton * b = m_view ? m_view->controlPanel ()->button (ControlPanel::button_stop) : 0L;
if (b) {
if (!b->isOn ())
b->toggle ();
m_view->setCursor (TQCursor (TQt::WaitCursor));
}
if (m_process)
m_process->quit ();
if (m_source)
m_source->reset ();
if (m_view) {
m_view->setCursor (TQCursor (TQt::ArrowCursor));
if (b->isOn ())
b->toggle ();
m_view->controlPanel ()->setPlaying (false);
setLoaded (100);
}
}
void PartBase::seek (unsigned long msec) {
if (m_process)
m_process->seek (msec/100, true);
}
void PartBase::adjustVolume (int incdec) {
m_process->volume (incdec, false);
}
void PartBase::increaseVolume () {
if (m_view)
m_view->controlPanel ()->volumeBar ()->setValue (m_view->controlPanel ()->volumeBar ()->value () + 2);
}
void PartBase::decreaseVolume () {
if (m_view)
m_view->controlPanel ()->volumeBar ()->setValue (m_view->controlPanel ()->volumeBar ()->value () - 2);
}
KDE_NO_EXPORT void PartBase::posSliderPressed () {
m_bPosSliderPressed=true;
}
KDE_NO_EXPORT void PartBase::posSliderReleased () {
m_bPosSliderPressed=false;
const TQSlider * posSlider = ::tqqt_cast<const TQSlider *> (sender ());
if (posSlider)
m_process->seek (posSlider->value(), true);
}
KDE_NO_EXPORT void PartBase::volumeChanged (int val) {
if (m_process) {
m_settings->volume = val;
m_process->volume (val, true);
}
}
KDE_NO_EXPORT void PartBase::contrastValueChanged (int val) {
m_settings->contrast = val;
m_process->contrast (val, true);
}
KDE_NO_EXPORT void PartBase::brightnessValueChanged (int val) {
m_settings->brightness = val;
m_process->brightness (val, true);
}
KDE_NO_EXPORT void PartBase::hueValueChanged (int val) {
m_settings->hue = val;
m_process->hue (val, true);
}
KDE_NO_EXPORT void PartBase::saturationValueChanged (int val) {
m_settings->saturation = val;
m_process->saturation (val, true);
}
KDE_NO_EXPORT void PartBase::sourceHasChangedAspects () {
if (m_view && m_source) {
//kdDebug () << "sourceHasChangedAspects " << m_source->aspect () << endl;
m_view->viewer ()->setAspect (m_source->aspect ());
m_view->updateLayout ();
}
emit sourceDimensionChanged ();
}
KDE_NO_EXPORT void PartBase::positionValueChanged (int pos) {
TQSlider * slider = ::tqqt_cast <TQSlider *> (sender ());
if (slider && slider->isEnabled ())
m_process->seek (pos, true);
}
KDE_NO_EXPORT void PartBase::fullScreen () {
if (m_view)
m_view->fullScreen ();
}
KDE_NO_EXPORT void PartBase::toggleFullScreen () {
m_view->fullScreen ();
}
KDE_NO_EXPORT void PartBase::minimalMode () {
emit toggleMinimalMode ();
}
KDE_NO_EXPORT bool PartBase::isPlaying () {
return playing ();
}
KDE_NO_EXPORT bool PartBase::isPaused () {
NodePtr doc = m_source ? m_source->document () : 0L;
return doc && doc->state == Node::state_deferred;
}
TDEAboutData* PartBase::createAboutData () {
KMessageBox::error(0L, "createAboutData", "KMPlayer");
return 0;
}
//-----------------------------------------------------------------------------
Source::Source (const TQString & name, PartBase * player, const char * n)
: TQObject (player, n),
m_name (name), m_player (player), m_identified (false), m_auto_play (true),
m_frequency (0), m_xvport (0), m_xvencoding (-1), m_doc_timer (0) {
init ();
}
Source::~Source () {
if (m_document)
m_document->document ()->dispose ();
m_document = 0L;
Q_ASSERT (m_current.ptr () == 0L);
}
void Source::init () {
//setDimensions (320, 240);
m_width = 0;
m_height = 0;
m_aspect = 0.0;
m_length = 0;
m_position = 0;
setLength (m_document, 0);
m_recordcmd.truncate (0);
}
KDE_NO_EXPORT void Source::setLanguages (const TQStringList & alang, const TQStringList & slang) {
m_player->setLanguages (alang, slang);
}
void Source::setDimensions (NodePtr node, int w, int h) {
Mrl * mrl = node ? node->mrl () : 0L;
if (mrl && mrl->view_mode == Mrl::WindowMode) {
mrl->width = w;
mrl->height = h;
float a = h > 0 ? 1.0 * w / h : 0.0;
mrl->aspect = a;
if (m_player->view ()) {
static_cast <View *> (m_player->view())->viewer()->setAspect(a);
static_cast <View *> (m_player->view ())->updateLayout ();
}
} else if (m_aspect < 0.001 || m_width != w || m_height != h) {
bool ev = (w > 0 && h > 0) ||
(h == 0 && m_height > 0) ||
(w == 0 && m_width > 0);
m_width = w;
m_height = h;
if (m_aspect < 0.001)
setAspect (node, h > 0 ? 1.0 * w / h : 0.0);
//kdDebug () << "setDimensions " << w << "x" << h << " a:" << m_aspect << endl;
if (ev)
emit dimensionsChanged ();
}
}
void Source::setAspect (NodePtr node, float a) {
//kdDebug () << "setAspect " << a << endl;
Mrl * mrl = node ? node->mrl () : 0L;
bool changed = false;
if (mrl) {
if (mrl->view_mode == Mrl::WindowMode)
changed |= (fabs (mrl->aspect - a) > 0.001);
mrl->aspect = a;
}
if (!mrl || mrl->view_mode == Mrl::SingleMode) {
changed |= (fabs (m_aspect - a) > 0.001);
m_aspect = a;
}
if (changed)
emit dimensionsChanged ();
}
void Source::setLength (NodePtr, int len) {
m_length = len;
m_player->setPosition (m_position, m_length);
}
KDE_NO_EXPORT void Source::setPosition (int pos) {
m_position = pos;
m_player->setPosition (pos, m_length);
}
KDE_NO_EXPORT void Source::setLoading (int percentage) {
m_player->setLoaded (percentage);
}
/*
static void printTree (NodePtr root, TQString off=TQString()) {
if (!root) {
kdDebug() << off << "[null]" << endl;
return;
}
kdDebug() << off << root->nodeName() << " " << (Element*)root << (root->isPlayable() ? root->mrl ()->src : TQString ("-")) << endl;
off += TQString (" ");
for (NodePtr e = root->firstChild(); e; e = e->nextSibling())
printTree(e, off);
}*/
void Source::setURL (const KURL & url) {
m_url = url;
m_back_request = 0L;
if (m_document && !m_document->hasChildNodes () &&
(m_document->mrl()->src.isEmpty () ||
m_document->mrl()->src == url.url ()))
// special case, mime is set first by plugin FIXME v
m_document->mrl()->src = url.url ();
else {
if (m_document)
m_document->document ()->dispose ();
m_document = new Document (url.url (), this);
}
if (m_player->process () && m_player->source () == this)
m_player->updateTree ();
//kdDebug() << name() << " setURL " << url << endl;
m_current = m_document;
}
void Source::setTitle (const TQString & title) {
emit titleChanged (title);
}
KDE_NO_EXPORT void Source::setAudioLang (int id) {
View * v = static_cast <View *> (m_player->view());
if (v && m_player->process ())
m_player->process ()->setAudioLang (id, v->controlPanel ()->audioMenu ()->text (id));
}
KDE_NO_EXPORT void Source::setSubtitle (int id) {
View * v = static_cast <View *> (m_player->view());
if (v && m_player->process ())
m_player->process ()->setSubtitle (id, v->controlPanel ()->subtitleMenu ()->text (id));
}
void Source::reset () {
if (m_document) {
//kdDebug() << "Source::first" << endl;
m_current = NodePtr ();
m_document->reset ();
m_player->updateTree ();
}
init ();
}
TQString Source::currentMrl () {
Mrl * mrl = m_current ? m_current->mrl () : 0L;
kdDebug() << "Source::currentMrl " << (m_current ? m_current->nodeName():"") << " src:" << (mrl ? mrl->absolutePath () : TQString ()) << endl;
return mrl ? mrl->absolutePath () : TQString ();
}
void Source::playCurrent () {
TQString url = currentMrl ();
m_player->changeURL (url);
m_width = m_height = 0;
m_aspect = 0.0;
if (m_player->view ())
static_cast <View *> (m_player->view ())->playingStop ();//show controls
if (m_document && !m_document->active ()) {
if (!m_current)
m_document->activate ();
else { // ugly code duplicate w/ back_request
for (NodePtr p = m_current->parentNode(); p; p = p->parentNode())
p->state = Element::state_activated;
m_current->activate ();
}
} else if (!m_current) {
emit endOfPlayItems ();
} else if (m_current->state == Element::state_deferred) {
// m_current->undefer ();
} else if (m_player->process ()->state () == Process::NotRunning) {
m_player->process ()->ready (static_cast <View *> (m_player->view ())->viewer ());
} else if (m_player->process ()) {
Mrl * mrl = m_back_request ? m_back_request->mrl () : m_current->mrl ();
if (mrl->view_mode == Mrl::SingleMode) {
// don't reset the dimensions if we have any
m_width = mrl->width;
m_height = mrl->height;
m_aspect = mrl->aspect;
}
m_back_request = 0L;
m_player->process ()->play (this, mrl->linkNode ());
}
//kdDebug () << "Source::playCurrent " << (m_current ? m_current->nodeName():" doc act:") << (m_document && !m_document->active ()) << " cur:" << (!m_current) << " cur act:" << (m_current && !m_current->active ()) << endl;
m_player->updateTree ();
emit dimensionsChanged ();
}
static NodePtr findDepthFirst (NodePtr elm) {
if (!elm)
return NodePtr ();
NodePtr tmp = elm;
for ( ; tmp; tmp = tmp->nextSibling ()) {
if (tmp->isPlayable ())
return tmp;
NodePtr tmp2 = findDepthFirst (tmp->firstChild ());
if (tmp2)
return tmp2;
}
return NodePtr ();
}
bool Source::requestPlayURL (NodePtr mrl) {
//kdDebug() << "Source::requestPlayURL " << mrl->mrl ()->src << endl;
if (m_player->process ()->state () > Process::Ready) {
if (m_player->process ()->mrl () == mrl->mrl ()->linkNode ())
return true;
m_back_request = mrl; // still playing, schedule it
m_player->process ()->stop ();
} else {
if (mrl->mrl ()->view_mode == Mrl::SingleMode)
m_current = mrl;
else
m_back_request = mrl;
m_player->updateTree ();
TQTimer::singleShot (0, this, TQT_SLOT (playCurrent ()));
}
m_player->setProcess (mrl->mrl ());
return true;
}
bool Source::resolveURL (NodePtr) {
return true;
}
void Source::setTimeout (int ms) {
//kdDebug () << "Source::setTimeout " << ms << endl;
if (m_doc_timer)
killTimer (m_doc_timer);
m_doc_timer = ms > -1 ? startTimer (ms) : 0;
}
void Source::timerEvent (TQTimerEvent * e) {
if (e->timerId () == m_doc_timer && m_document && m_document->active ())
m_document->document ()->timer (); // will call setTimeout()
else
killTimer (e->timerId ());
}
bool Source::setCurrent (NodePtr mrl) {
m_current = mrl;
return true;
}
void Source::stateElementChanged (Node * elm, Node::State os, Node::State ns) {
//kdDebug() << "Source::stateElementChanged " << elm->nodeName () << " state:" << (int) elm->state << " cur isPlayable:" << (m_current && m_current->isPlayable ()) << " elm==linkNode:" << (m_current && elm == m_current->mrl ()->linkNode ()) << " p state:" << m_player->process ()->state () << endl;
if (ns == Node::state_deactivated && elm == m_document && !m_back_request) {
emit endOfPlayItems (); // played all items
} else if ((ns == Node::state_deactivated || ns == Node::state_finished) &&
m_player->process ()->mrl() &&
elm == m_player->process ()->mrl ()->mrl ()->linkNode ()) {
if (m_player->process ()->state () > Process::Ready)
//a SMIL movies stopped by SMIL events rather than movie just ending
m_player->process ()->stop ();
if (m_player->view ()) // move away the video widget
TQTimer::singleShot (0, m_player->view (), TQT_SLOT (updateLayout ()));
} else if ((ns == Node::state_deferred ||
(os == Node::state_deferred && ns > Node::state_deferred)) &&
elm == m_document) {
m_player->process ()->pause ();
} else if (ns == Node::state_activated &&
elm->isPlayable () &&
elm->mrl ()->view_mode == Mrl::SingleMode) {
Node *p = elm->parentNode();
if (!p || !p->mrl () || p->mrl ()->view_mode == Mrl::SingleMode)
// make sure we don't set current to nested document
m_current = elm;
}
if (elm->expose ()) {
if (ns == Node::state_activated || ns == Node::state_deactivated)
m_player->updateTree ();
else if (ns == Node::state_began || os == Node::state_began)
m_player->updateTree (false);
}
}
SurfacePtr Source::getSurface (NodePtr n) {
if (m_player->view ())
return static_cast <View*>(m_player->view())->viewArea()->getSurface(n);
return 0L;
}
void Source::setInfoMessage (const TQString & msg) {
m_player->updateInfo (msg);
}
void Source::bitRates (int & preferred, int & maximal) {
preferred = 1024 * m_player->settings ()->prefbitrate;
maximal= 1024 * m_player->settings ()->maxbitrate;
}
void Source::insertURL (NodePtr node, const TQString & mrl, const TQString & title) {
if (!node || !node->mrl ()) // this should always be false
return;
TQString cur_url = node->mrl ()->absolutePath ();
KURL url (cur_url, mrl);
kdDebug() << "Source::insertURL " << KURL (cur_url) << " " << url << endl;
if (!url.isValid ())
kdError () << "try to append non-valid url" << endl;
else if (KURL (cur_url) == url)
kdError () << "try to append url to itself" << endl;
else {
int depth = 0; // cache this?
for (NodePtr e = node; e->parentNode (); e = e->parentNode ())
++depth;
if (depth < 40) {
node->appendChild (new GenericURL (m_document, KURL::decode_string (url.url ()), title.isEmpty() ? KURL::decode_string (mrl) : title));
m_player->updateTree ();
} else
kdError () << "insertURL exceeds depth limit" << endl;
}
}
void Source::play () {
m_player->updateTree ();
TQTimer::singleShot (0, m_player, TQT_SLOT (play ()));
//printTree (m_document);
}
void Source::backward () {
if (m_document->hasChildNodes ()) {
m_back_request = m_current;
if (!m_back_request || m_back_request == m_document) {
m_back_request = m_document->lastChild ();
while (m_back_request->lastChild () && !m_back_request->isPlayable ())
m_back_request = m_back_request->lastChild ();
if (m_back_request->isPlayable ())
return;
}
while (m_back_request && m_back_request != m_document) {
if (m_back_request->previousSibling ()) {
m_back_request = m_back_request->previousSibling ();
NodePtr e = findDepthFirst (m_back_request); // lastDepth..
if (e) {
m_back_request = e;
if (m_player->playing ())
m_player->process ()->stop ();
else if (m_current) {
m_document->reset ();
m_current = e;
TQTimer::singleShot (0, this, TQT_SLOT (playCurrent ()));
}
return;
}
} else
m_back_request = m_back_request->parentNode ();
}
m_back_request = 0L;
} else
m_player->process ()->seek (-1 * m_player->settings ()->seektime * 10, false);
}
void Source::forward () {
if (m_document->hasChildNodes ()) {
if (m_player->playing ())
m_player->process ()->stop ();
else if (m_current)
m_current->finish ();
} else
m_player->process ()->seek (m_player->settings()->seektime * 10, false);
}
void Source::jump (NodePtr e) {
if (e->isPlayable ()) {
if (m_player->playing ()) {
m_back_request = e;
m_player->process ()->stop ();
} else {
if (m_current)
m_document->reset ();
m_current = e;
TQTimer::singleShot (0, this, TQT_SLOT (playCurrent ()));
}
} else
m_player->updateTree ();
}
NodePtr Source::document () {
if (!m_document)
m_document = new Document (TQString (), this);
return m_document;
}
NodePtr Source::root () {
return document ();
}
bool Source::processOutput (const TQString &) {
return false;
}
TQString Source::filterOptions () {
Settings* m_settings = m_player->settings ();
TQString PPargs ("");
if (m_settings->postprocessing)
{
if (m_settings->pp_default)
PPargs = "-vf pp=de";
else if (m_settings->pp_fast)
PPargs = "-vf pp=fa";
else if (m_settings->pp_custom) {
PPargs = "-vf pp=";
if (m_settings->pp_custom_hz) {
PPargs += "hb";
if (m_settings->pp_custom_hz_aq && \
m_settings->pp_custom_hz_ch)
PPargs += ":ac";
else if (m_settings->pp_custom_hz_aq)
PPargs += ":a";
else if (m_settings->pp_custom_hz_ch)
PPargs += ":c";
PPargs += '/';
}
if (m_settings->pp_custom_vt) {
PPargs += "vb";
if (m_settings->pp_custom_vt_aq && \
m_settings->pp_custom_vt_ch)
PPargs += ":ac";
else if (m_settings->pp_custom_vt_aq)
PPargs += ":a";
else if (m_settings->pp_custom_vt_ch)
PPargs += ":c";
PPargs += '/';
}
if (m_settings->pp_custom_dr) {
PPargs += "dr";
if (m_settings->pp_custom_dr_aq && \
m_settings->pp_custom_dr_ch)
PPargs += ":ac";
else if (m_settings->pp_custom_dr_aq)
PPargs += ":a";
else if (m_settings->pp_custom_dr_ch)
PPargs += ":c";
PPargs += '/';
}
if (m_settings->pp_custom_al) {
PPargs += "al";
if (m_settings->pp_custom_al_f)
PPargs += ":f";
PPargs += '/';
}
if (m_settings->pp_custom_tn) {
PPargs += "tn";
/*if (1 <= m_settings->pp_custom_tn_s <= 3){
PPargs += ":";
PPargs += m_settings->pp_custom_tn_s;
}*/ //disabled 'cos this is wrong
PPargs += '/';
}
if (m_settings->pp_lin_blend_int) {
PPargs += "lb";
PPargs += '/';
}
if (m_settings->pp_lin_int) {
PPargs += "li";
PPargs += '/';
}
if (m_settings->pp_cub_int) {
PPargs += "ci";
PPargs += '/';
}
if (m_settings->pp_med_int) {
PPargs += "md";
PPargs += '/';
}
if (m_settings->pp_ffmpeg_int) {
PPargs += "fd";
PPargs += '/';
}
}
if (PPargs.endsWith("/"))
PPargs.truncate(PPargs.length()-1);
}
return PPargs;
}
bool Source::hasLength () {
return true;
}
bool Source::isSeekable () {
return true;
}
void Source::setIdentified (bool b) {
//kdDebug () << "Source::setIdentified " << m_identified << b <<endl;
m_identified = b;
}
static const TQString statemap [] = {
i18n ("Not Running"), i18n ("Ready"), i18n ("Buffering"), i18n ("Playing")
};
void Source::stateChange(Process *p, Process::State olds, Process::State news) {
if (!p || !p->viewer ()) return;
Recorder *rec = dynamic_cast <Recorder *> (p);
if (rec && !rec->recordURL ().isEmpty ()) {
kdDebug () << "recordState " << statemap[olds] << " -> " << statemap[news] << endl;
m_player->updateStatus (i18n ("Recorder %1 %2").arg (p->name ()).arg (statemap[news]));
p->viewer ()->view ()->controlPanel ()->setRecording (news > Process::Ready);
if (news == Process::Ready) {
if (olds > Process::Ready) {
p->quit ();
} else {
NodePtr n = current ();
if (!n)
n = document ();
p->play (this, n);
}
} else if (news > Process::Ready) {
emit startRecording ();
} else if (news == Process::NotRunning)
emit stopRecording ();
} else {
p->viewer()->view()->controlPanel()->setPlaying(news > Process::Ready);
kdDebug () << "processState " << statemap[olds] << " -> " << statemap[news] << endl;
m_player->updateStatus (i18n ("Player %1 %2").arg (p->name ()).arg (statemap[news]));
if (!p->mrl () && news > Process::Ready) {
p->stop (); // reschedule for Ready state
} else if (news == Process::Playing) {
if (p->mrl ()->state == Element::state_deferred)
p->mrl ()->undefer ();
p->viewer ()->view ()->playingStart ();
emit startPlaying ();
} else if (news == Process::NotRunning) {
if (hasLength () && position () > length ())
setLength (m_document, position ());
setPosition (0);
if (p == m_player->process ())
emit stopPlaying ();
// else changed process
} else if (news == Process::Ready) {
if (olds > Process::Ready) {
NodePtr node = p->mrl (); // p->mrl is weak, needs check
Mrl * mrl = node ? node->mrl () : 0L;
if (m_back_request && m_back_request->isPlayable ()) {
if (m_back_request->mrl ()->view_mode == Mrl::SingleMode)
// jump in pl
m_current = m_back_request;
else if (mrl)
// overlapping SMIL audio/video
mrl->endOfFile ();
if (m_current->id >= SMIL::id_node_first &&
m_current->id < SMIL::id_node_last) {
playCurrent (); // just play back_request
} else {
// sanitize pl having all parents of current activated
m_document->reset (); // deactivate everything
for (NodePtr p = m_current->parentNode(); p; p = p->parentNode())
p->state = Element::state_activated;
m_current->activate (); // calls requestPlayUrl
}
m_back_request = 0L;
} else if(mrl)
{
mrl->endOfFile (); // set node to finished
}
if (m_player->view() &&
(!mrl || mrl->view_mode != Mrl::WindowMode))
static_cast<View*>(m_player->view())->viewArea()->repaint();
} else
TQTimer::singleShot (0, this, TQT_SLOT (playCurrent ()));
} else if (news == Process::Buffering) {
if (p->mrl ()->mrl ()->view_mode != Mrl::SingleMode)
p->mrl ()->defer (); // paused the SMIL
}
}
}
TQString Source::plugin (const TQString &mime) const {
m_player->config ()->setGroup (mime);
return m_player->config ()->readEntry ("plugin", "" );
}
TQString Source::prettyName () {
return i18n ("Unknown");
}
//-----------------------------------------------------------------------------
URLSource::URLSource (PartBase * player, const KURL & url)
: Source (i18n ("URL"), player, "urlsource"), activated (false) {
setURL (url);
//kdDebug () << "URLSource::URLSource" << endl;
}
URLSource::~URLSource () {
//kdDebug () << "URLSource::~URLSource" << endl;
}
void URLSource::init () {
Source::init ();
}
void URLSource::dimensions (int & w, int & h) {
if (!m_player->mayResize () && m_player->view ()) {
w = static_cast <View *> (m_player->view ())->viewer ()->width ();
h = static_cast <View *> (m_player->view ())->viewer ()->height ();
} else
Source::dimensions (w, h);
}
bool URLSource::hasLength () {
return !!length ();
}
KDE_NO_EXPORT void URLSource::activate () {
if (activated)
return;
activated = true;
if (url ().isEmpty () && (!m_document || !m_document->hasChildNodes ())) {
m_player->updateTree ();
return;
}
if (m_auto_play)
play ();
}
KDE_NO_EXPORT void URLSource::stopResolving () {
if (m_resolve_info) {
for (SharedPtr <ResolveInfo> ri = m_resolve_info; ri; ri = ri->next)
ri->job->kill ();
m_resolve_info = 0L;
m_player->updateStatus (i18n ("Disconnected"));
m_player->setLoaded (100);
}
}
void URLSource::reset () {
stopResolving ();
Source::reset ();
}
void URLSource::forward () {
stopResolving ();
Source::forward ();
}
void URLSource::backward () {
stopResolving ();
Source::backward ();
}
void URLSource::jump (NodePtr e) {
stopResolving ();
Source::jump (e);
}
void URLSource::deactivate () {
activated = false;
reset ();
getSurface (0L);
}
TQString URLSource::prettyName () {
if (m_url.isEmpty ())
return i18n ("URL");
if (m_url.url ().length () > 50) {
TQString newurl = m_url.protocol () + TQString ("://");
if (m_url.hasHost ())
newurl += m_url.host ();
if (m_url.port ())
newurl += TQString (":%1").arg (m_url.port ());
TQString file = m_url.fileName ();
int len = newurl.length () + file.length ();
KURL path = KURL (m_url.directory ());
bool modified = false;
while (path.url ().length () + len > 50 && path != path.upURL ()) {
path = path.upURL ();
modified = true;
}
TQString dir = path.directory ();
if (!dir.endsWith (TQString ("/")))
dir += '/';
if (modified)
dir += TQString (".../");
newurl += dir + file;
return i18n ("URL - %1").arg (newurl);
}
return i18n ("URL - %1").arg (m_url.prettyURL ());
}
static bool isPlayListMime (const TQString & mime) {
TQString m (mime);
int plugin_pos = m.find ("-plugin");
if (plugin_pos > 0)
m.truncate (plugin_pos);
const char * mimestr = m.ascii ();
return mimestr && (!strcmp (mimestr, "audio/mpegurl") ||
!strcmp (mimestr, "audio/x-mpegurl") ||
!strncmp (mimestr, "video/x-ms", 10) ||
!strncmp (mimestr, "audio/x-ms", 10) ||
//!strcmp (mimestr, "video/x-ms-wmp") ||
//!strcmp (mimestr, "video/x-ms-asf") ||
//!strcmp (mimestr, "video/x-ms-wmv") ||
//!strcmp (mimestr, "video/x-ms-wvx") ||
//!strcmp (mimestr, "video/x-msvideo") ||
!strcmp (mimestr, "audio/x-scpls") ||
!strcmp (mimestr, "audio/x-pn-realaudio") ||
!strcmp (mimestr, "audio/vnd.rn-realaudio") ||
!strcmp (mimestr, "audio/m3u") ||
!strcmp (mimestr, "audio/x-m3u") ||
!strncmp (mimestr, "text/", 5) ||
(!strncmp (mimestr, "application/", 12) &&
strstr (mimestr + 12,"+xml")) ||
!strncasecmp (mimestr, "application/smil", 16) ||
!strncasecmp (mimestr, "application/xml", 15) ||
//!strcmp (mimestr, "application/rss+xml") ||
//!strcmp (mimestr, "application/atom+xml") ||
!strcmp (mimestr, "application/x-mplayer2"));
}
KDE_NO_EXPORT void URLSource::read (NodePtr root, TQTextStream & textstream) {
TQString line;
do {
line = textstream.readLine ();
} while (!line.isNull () && line.stripWhiteSpace ().isEmpty ());
if (!line.isNull ()) {
NodePtr cur_elm = root;
if (cur_elm->isPlayable ())
cur_elm = cur_elm->mrl ()->linkNode ();
if (cur_elm->mrl ()->mimetype == TQString ("audio/x-scpls")) {
bool groupfound = false;
int nr = -1;
struct Entry {
TQString url, title;
} * entries = 0L;
do {
line = line.stripWhiteSpace ();
if (!line.isEmpty ()) {
if (line.startsWith (TQString ("[")) && line.endsWith (TQString ("]"))) {
if (!groupfound && line.mid (1, line.length () - 2).stripWhiteSpace () == TQString ("playlist"))
groupfound = true;
else
break;
kdDebug () << "Group found: " << line << endl;
} else if (groupfound) {
int eq_pos = line.find (TQChar ('='));
if (eq_pos > 0) {
if (line.lower ().startsWith (TQString ("numberofentries"))) {
nr = line.mid (eq_pos + 1).stripWhiteSpace ().toInt ();
kdDebug () << "numberofentries : " << nr << endl;
if (nr > 0 && nr < 1024)
entries = new Entry[nr];
else
nr = 0;
} else if (nr > 0) {
TQString ll = line.lower ();
if (ll.startsWith (TQString ("file"))) {
int i = line.mid (4, eq_pos-4).toInt ();
if (i > 0 && i <= nr)
entries[i-1].url = line.mid (eq_pos + 1).stripWhiteSpace ();
} else if (ll.startsWith (TQString ("title"))) {
int i = line.mid (5, eq_pos-5).toInt ();
if (i > 0 && i <= nr)
entries[i-1].title = line.mid (eq_pos + 1).stripWhiteSpace ();
}
}
}
}
}
line = textstream.readLine ();
} while (!line.isNull ());
for (int i = 0; i < nr; i++)
if (!entries[i].url.isEmpty ())
cur_elm->appendChild (new GenericURL (m_document, KURL::decode_string (entries[i].url), entries[i].title));
delete [] entries;
} else if (line.stripWhiteSpace ().startsWith (TQChar ('<'))) {
readXML (cur_elm, textstream, line);
//cur_elm->normalize ();
if (m_document && m_document->firstChild ()) {
// SMIL documents have set its size of root-layout
Mrl * mrl = m_document->firstChild ()->mrl ();
if (mrl)
Source::setDimensions (m_document->firstChild (), mrl->width, mrl->height);
}
} else if (line.lower () != TQString ("[reference]")) do {
TQString mrl = line.stripWhiteSpace ();
if (line == TQString ("--stop--"))
break;
if (mrl.lower ().startsWith (TQString ("asf ")))
mrl = mrl.mid (4).stripWhiteSpace ();
if (!mrl.isEmpty () && !mrl.startsWith (TQChar ('#')))
cur_elm->appendChild (new GenericURL (m_document, mrl));
line = textstream.readLine ();
} while (!line.isNull ()); /* TODO && m_document.size () < 1024 / * support 1k entries * /);*/
}
}
KDE_NO_EXPORT void URLSource::kioData (TDEIO::Job * job, const TQByteArray & d) {
SharedPtr <ResolveInfo> rinfo = m_resolve_info;
while (rinfo && rinfo->job != job)
rinfo = rinfo->next;
if (!rinfo) {
kdWarning () << "Spurious kioData" << endl;
return;
}
int size = rinfo->data.size ();
int newsize = size + d.size ();
if (!size) { // first data
int accuraty = 0;
KMimeType::Ptr mime = KMimeType::findByContent (d, &accuraty);
if (!mime ||
!mime->name ().startsWith (TQString ("text/")) ||
(newsize > 4 && !strncmp (d.data (), "RIFF", 4))) {
newsize = 0;
kdDebug () << "URLSource::kioData: " << mime->name () << accuraty << endl;
}
}
//kdDebug () << "URLSource::kioData: " << newsize << endl;
if (newsize <= 0 || newsize > 200000) {
rinfo->data.resize (0);
rinfo->job->kill (false);
m_player->setLoaded (100);
} else {
rinfo->data.resize (newsize);
memcpy (rinfo->data.data () + size, d.data (), newsize - size);
m_player->setLoaded (++rinfo->progress);
}
}
KDE_NO_EXPORT void URLSource::kioMimetype (TDEIO::Job * job, const TQString & mimestr) {
SharedPtr <ResolveInfo> rinfo = m_resolve_info;
while (rinfo && rinfo->job != job)
rinfo = rinfo->next;
if (!rinfo) {
kdWarning () << "Spurious kioData" << endl;
return;
}
if (rinfo->resolving_mrl)
rinfo->resolving_mrl->mrl ()->mimetype = mimestr;
if (!rinfo->resolving_mrl || !isPlayListMime (mimestr))
job->kill (false);
}
KDE_NO_EXPORT void URLSource::kioResult (TDEIO::Job * job) {
SharedPtr <ResolveInfo> previnfo, rinfo = m_resolve_info;
while (rinfo && rinfo->job != job) {
previnfo = rinfo;
rinfo = rinfo->next;
}
if (!rinfo) {
kdWarning () << "Spurious kioData" << endl;
return;
}
m_player->updateStatus ("");
m_player->setLoaded (100);
if (previnfo)
previnfo->next = rinfo->next;
else
m_resolve_info = rinfo->next;
TQTextStream textstream (rinfo->data, IO_ReadOnly);
if (rinfo->resolving_mrl) {
if (isPlayListMime (rinfo->resolving_mrl->mrl ()->mimetype))
read (rinfo->resolving_mrl, textstream);
rinfo->resolving_mrl->mrl ()->resolved = true;
rinfo->resolving_mrl->undefer ();
}
static_cast <View *> (m_player->view())->controlPanel()->setPlaying (false);
}
void URLSource::playCurrent () {
Mrl *mrl = m_back_request
? m_back_request->mrl ()
: m_current ? m_current->mrl () : NULL;
if (mrl && mrl->active () && (!mrl->isPlayable () || !mrl->resolved))
// an async playCurrent() call (eg. backend is up & running), ignore
return;
Source::playCurrent ();
}
void URLSource::play () {
Source::play ();
}
bool URLSource::requestPlayURL (NodePtr mrl) {
if (m_document.ptr () != mrl->mrl ()->linkNode ()) {
KURL base = m_document->mrl ()->src;
KURL dest = mrl->mrl ()->linkNode ()->absolutePath ();
// check if some remote playlist tries to open something local, but
// do ignore unknown protocols because there are so many and we only
// want to cache local ones.
if (
#if 0
!KProtocolInfo::protocolClass (dest.protocol ()).isEmpty () &&
#else
dest.isLocalFile () &&
#endif
!kapp->authorizeURLAction ("redirect", base, dest)) {
kdWarning () << "requestPlayURL from document " << base << " to play " << dest << " is not allowed" << endl;
return false;
}
}
return Source::requestPlayURL (mrl);
}
void URLSource::setURL (const KURL & url) {
Source::setURL (url);
Mrl *mrl = document ()->mrl ();
if (!url.isEmpty () && url.isLocalFile () && mrl->mimetype.isEmpty ()) {
KMimeType::Ptr mimeptr = KMimeType::findByURL (url);
if (mimeptr)
mrl->mimetype = mimeptr->name ();
}
}
bool URLSource::resolveURL (NodePtr m) {
Mrl * mrl = m->mrl ();
if (!mrl || mrl->src.isEmpty ())
return true;
int depth = 0;
for (NodePtr e = m->parentNode (); e; e = e->parentNode ())
++depth;
if (depth > 40)
return true;
KURL url (mrl->absolutePath ());
TQString mimestr = mrl->mimetype;
if (mimestr == "application/x-shockwave-flash" ||
mimestr == "application/futuresplash")
return true; // FIXME
bool maybe_playlist = isPlayListMime (mimestr);
kdDebug () << "resolveURL " << mrl->absolutePath () << " " << mimestr << endl;
if (url.isLocalFile ()) {
TQFile file (url.path ());
if (!file.exists ()) {
kdWarning () << "resolveURL " << url.path() << " not found" << endl;
return true;
}
if (mimestr.isEmpty ()) {
KMimeType::Ptr mimeptr = KMimeType::findByURL (url);
if (mimeptr) {
mrl->mimetype = mimeptr->name ();
maybe_playlist = isPlayListMime (mrl->mimetype); // get new mime
}
}
if (maybe_playlist && file.size () < 2000000 && file.open (IO_ReadOnly)) {
char databuf [512];
int nr_bytes = file.readBlock (databuf, 512);
if (nr_bytes > 3) {
int accuraty = 0;
KMimeType::Ptr mime = KMimeType::findByContent (TQCString (databuf, nr_bytes), &accuraty);
if ((mime && !mime->name().startsWith (TQString("text/"))) ||
!strncmp (databuf, "RIFF", 4)) {
return true;
}
kdDebug () << "mime: " << (mime ? mime->name (): TQString("null")) << endl;
}
file.reset ();
TQTextStream textstream (&file);
read (m, textstream);
}
} else if ((maybe_playlist &&
url.protocol ().compare (TQString ("mms")) &&
url.protocol ().compare (TQString ("rtsp")) &&
url.protocol ().compare (TQString ("rtp"))) ||
(mimestr.isEmpty () &&
(url.protocol ().startsWith (TQString ("http")) ||
url.protocol () == TQString::fromLatin1 ("media") ||
url.protocol () == TQString::fromLatin1 ("remote")))) {
TDEIO::Job * job = TDEIO::get (url, false, false);
job->addMetaData ("PropagateHttpHeader", "true");
job->addMetaData ("errorPage", "false");
m_resolve_info = new ResolveInfo (m, job, m_resolve_info);
connect (m_resolve_info->job, TQT_SIGNAL(data(TDEIO::Job*,const TQByteArray&)),
this, TQT_SLOT (kioData (TDEIO::Job *, const TQByteArray &)));
//connect( m_job, TQT_SIGNAL(connected(TDEIO::Job*)),
// this, TQT_SLOT(slotConnected(TDEIO::Job*)));
connect(m_resolve_info->job, TQT_SIGNAL(mimetype(TDEIO::Job*,const TQString&)),
this, TQT_SLOT (kioMimetype (TDEIO::Job *, const TQString &)));
connect (m_resolve_info->job, TQT_SIGNAL (result (TDEIO::Job *)),
this, TQT_SLOT (kioResult (TDEIO::Job *)));
static_cast <View *> (m_player->view ())->controlPanel ()->setPlaying (true);
m_player->updateStatus (i18n ("Connecting"));
m_player->setLoaded (0);
return false; // wait for result ..
}
return true;
}
//-----------------------------------------------------------------------------
namespace KMPlayer {
static KStaticDeleter <DataCache> dataCacheDeleter;
static DataCache * memory_cache;
}
void DataCache::add (const TQString & url, const TQByteArray & data) {
TQByteArray bytes;
bytes.duplicate (data);
cache_map.insert (url, bytes);
preserve_map.erase (url);
emit preserveRemoved (url);
}
bool DataCache::get (const TQString & url, TQByteArray & data) {
DataMap::const_iterator it = cache_map.find (url);
if (it != cache_map.end ()) {
data.duplicate (it.data ());
return true;
}
return false;
}
bool DataCache::preserve (const TQString & url) {
PreserveMap::const_iterator it = preserve_map.find (url);
if (it == preserve_map.end ()) {
preserve_map.insert (url, true);
return true;
}
return false;
}
bool DataCache::isPreserved (const TQString & url) {
return preserve_map.find (url) != preserve_map.end ();
}
bool DataCache::unpreserve (const TQString & url) {
const PreserveMap::iterator it = preserve_map.find (url);
if (it == preserve_map.end ())
return false;
preserve_map.erase (it);
emit preserveRemoved (url);
return true;
}
RemoteObjectPrivate::RemoteObjectPrivate (RemoteObject * r)
: job (0L), remote_object (r), preserve_wait (false) {
if (!memory_cache)
dataCacheDeleter.setObject (memory_cache, new DataCache);
}
RemoteObjectPrivate::~RemoteObjectPrivate () {
clear ();
}
KDE_NO_EXPORT bool RemoteObjectPrivate::download (const TQString & str) {
url = str;
KURL kurl (str);
if (kurl.isLocalFile ()) {
TQFile file (kurl.path ());
if (file.exists () && file.open (IO_ReadOnly)) {
data = file.readAll ();
file.close ();
}
remote_object->remoteReady (data);
return true;
}
if (memory_cache->get (str, data)) {
//kdDebug () << "download found in cache " << str << endl;
remote_object->remoteReady (data);
return true;
}
if (memory_cache->preserve (str)) {
//kdDebug () << "downloading " << str << endl;
job = TDEIO::get (kurl, false, false);
connect (job, TQT_SIGNAL (data (TDEIO::Job *, const TQByteArray &)),
this, TQT_SLOT (slotData (TDEIO::Job *, const TQByteArray &)));
connect (job, TQT_SIGNAL (result (TDEIO::Job *)),
this, TQT_SLOT (slotResult (TDEIO::Job *)));
connect (job, TQT_SIGNAL (mimetype (TDEIO::Job *, const TQString &)),
this, TQT_SLOT (slotMimetype (TDEIO::Job *, const TQString &)));
} else {
//kdDebug () << "download preserved " << str << endl;
connect (memory_cache, TQT_SIGNAL (preserveRemoved (const TQString &)),
this, TQT_SLOT (cachePreserveRemoved (const TQString &)));
preserve_wait = true;
}
return false;
}
KDE_NO_EXPORT void RemoteObjectPrivate::clear () {
if (job) {
job->kill (); // quiet, no result signal
job = 0L;
memory_cache->unpreserve (url);
} else if (preserve_wait) {
disconnect (memory_cache, TQT_SIGNAL (preserveRemoved (const TQString &)),
this, TQT_SLOT (cachePreserveRemoved (const TQString &)));
preserve_wait = false;
}
}
KDE_NO_EXPORT void RemoteObjectPrivate::slotResult (TDEIO::Job * kjob) {
if (!kjob->error ())
memory_cache->add (url, data);
else
data.resize (0);
job = 0L; // signal TDEIO::Job::result deletes itself
remote_object->remoteReady (data);
}
KDE_NO_EXPORT
void RemoteObjectPrivate::cachePreserveRemoved (const TQString & str) {
if (str == url && !memory_cache->isPreserved (str)) {
preserve_wait = false;
disconnect (memory_cache, TQT_SIGNAL (preserveRemoved (const TQString &)),
this, TQT_SLOT (cachePreserveRemoved (const TQString &)));
download (str);
}
}
KDE_NO_EXPORT
void RemoteObjectPrivate::slotData (TDEIO::Job*, const TQByteArray& qb) {
if (qb.size ()) {
int old_size = data.size ();
data.resize (old_size + qb.size ());
memcpy (data.data () + old_size, qb.data (), qb.size ());
}
}
KDE_NO_EXPORT
void RemoteObjectPrivate::slotMimetype (TDEIO::Job *, const TQString & m) {
mime = m;
}
KDE_NO_CDTOR_EXPORT RemoteObject::RemoteObject ()
: d (new RemoteObjectPrivate (this)) {}
KDE_NO_CDTOR_EXPORT RemoteObject::~RemoteObject () {
delete d;
}
/**
* abort previous wget job
*/
KDE_NO_EXPORT void RemoteObject::killWGet () {
d->clear (); // assume data is invalid
}
/**
* Gets contents from url and puts it in m_data
*/
KDE_NO_EXPORT bool RemoteObject::wget (const TQString & url) {
clear ();
return d->download (url);
}
KDE_NO_EXPORT TQString RemoteObject::mimetype () {
if (d->data.size () > 0 && d->mime.isEmpty ()) {
int accuraty;
KMimeType::Ptr mime = KMimeType::findByContent (d->data, &accuraty);
if (mime)
d->mime = mime->name ();
}
return d->mime;
}
KDE_NO_EXPORT void RemoteObject::clear () {
killWGet ();
d->url.truncate (0);
d->mime.truncate (0);
d->data.resize (0);
}
KDE_NO_EXPORT bool RemoteObject::downloading () const {
return !!d->job;
}
//-----------------------------------------------------------------------------
#include "kmplayerpartbase.moc"
#include "kmplayersource.moc"