playermanager.cpp 9.77 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/***************************************************************************
                          playermanager.cpp
                             -------------------
    begin                : Sat Feb 14 2004
    copyright            : (C) 2004 by Scott Wheeler
    email                : wheeler@kde.org
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kactioncollection.h>
#include <kmainwindow.h>
#include <kapplication.h>
#include <kdebug.h>

#include <qslider.h>
24
#include <qtimer.h>
25 26 27

#include "playermanager.h"
#include "slideraction.h"
28
#include "statuslabel.h"
29 30 31 32 33 34 35 36 37 38 39 40

PlayerManager *PlayerManager::m_instance = 0;

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

PlayerManager::PlayerManager() :
    QObject(0, "PlayerManager"),
    Player(),
    m_actionCollection(0),
    m_sliderAction(0),
41
    m_playlistInterface(0),
42
    m_statusLabel(0),
43 44 45
    m_player(0),
    m_timer(0),
    m_noSeek(false)
46 47 48 49 50 51
{
    setup();
}

PlayerManager::~PlayerManager()
{
52
    delete m_player;
53 54 55 56 57 58 59 60 61 62 63 64 65
}

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

PlayerManager *PlayerManager::instance() // static
{
    if(!m_instance)
        m_instance = new PlayerManager;
    return m_instance;
}

66 67
bool PlayerManager::playing() const
{
68
    if(!player())
69 70
        return false;

71
    return player()->playing();
72 73 74 75
}

bool PlayerManager::paused() const
{
76
    if(!player())
77 78
        return false;

79
    return player()->paused();
80 81 82 83
}

float PlayerManager::volume() const
{
84
    if(!player())
85 86
        return 0;

87
    return player()->volume();
88 89 90 91
}

long PlayerManager::totalTime() const
{
92
    if(!player())
93 94
        return 0;

95
    return player()->totalTime();
96 97 98
}

long PlayerManager::currentTime() const
99
{
100
    if(!player())
101 102
        return 0;

103
    return player()->currentTime();
104 105 106 107
}

int PlayerManager::position() const
{
108
    if(!player())
109 110
        return 0;

111
    return player()->position();
112 113
}

114
void PlayerManager::setPlaylistInterface(PlaylistInterface *interface)
115 116 117 118
{
    m_playlistInterface = interface;
}

119 120 121 122 123
void PlayerManager::setStatusLabel(StatusLabel *label)
{
    m_statusLabel = label;
}

124 125 126 127 128 129
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

void PlayerManager::play(const QString &fileName)
{
130
    if(!player() || !m_playlistInterface)
131 132
        return;

133
    if(fileName.isNull()) {
134 135 136 137
	if(player()->paused())
            player()->play();
        if(player()->playing())
            player()->seekPosition(0);
138
        else
139
            player()->play(m_playlistInterface->nextFile());
140 141
    }
    else {
142 143 144
        if(player()->paused())
            player()->stop();
        player()->play(fileName);
145
    }
146

147
    // Make sure that the player() actually starts before doing anything.
148

149
    if(!player()->playing()) {
150 151 152
        stop();
        return;
    }
153

154 155 156 157
    m_actionCollection->action("pause")->setEnabled(true);
    m_actionCollection->action("stop")->setEnabled(true);
    m_actionCollection->action("forward")->setEnabled(true);
    m_actionCollection->action("back")->setEnabled(true);
158

159 160
    m_sliderAction->trackPositionSlider()->setValue(0);
    m_sliderAction->trackPositionSlider()->setEnabled(true);
161 162

    m_timer->start(m_pollInterval);
163 164 165 166
}

void PlayerManager::pause()
{
167
    if(!player())
168 169
        return;

170 171 172 173 174 175 176 177 178
    if(player()->paused()) {
        play();
        return;
    }

    m_timer->stop();
    m_actionCollection->action("pause")->setEnabled(false);

    player()->pause();
179 180 181 182
}

void PlayerManager::stop()
{
183
    if(!player())
184 185
        return;

186 187 188 189 190 191 192 193 194 195 196 197 198
    m_timer->stop();

    m_actionCollection->action("pause")->setEnabled(false);
    m_actionCollection->action("stop")->setEnabled(false);
    m_actionCollection->action("back")->setEnabled(false);
    m_actionCollection->action("forward")->setEnabled(false);

    m_sliderAction->trackPositionSlider()->setValue(0);
    m_sliderAction->trackPositionSlider()->setEnabled(false);

    m_statusLabel->clear();

    player()->stop();
199 200
}

Laurent Montel's avatar
Laurent Montel committed
201
void PlayerManager::setVolume(float volume)
202
{
203
    if(!player())
204 205
        return;

206
    player()->setVolume(volume);
207 208
}

209
void PlayerManager::seek(long seekTime)
210
{
211
    if(!player())
212
        return;
213

214
    player()->seek(seekTime);
215 216
}

217
void PlayerManager::seekPosition(int position)
218
{
219 220 221 222
    if(!player())
        return;

    if(!player()->playing() || m_noSeek)
223
        return;
224

225 226
    slotUpdateTime(position);
    player()->seekPosition(position);
227 228
}

229 230 231
////////////////////////////////////////////////////////////////////////////////
// private slots
////////////////////////////////////////////////////////////////////////////////
232

233
void PlayerManager::slotPollPlay()
234
{
235
    if(!player() || !m_playlistInterface)
236
        return;
237

238
    m_noSeek = true;
239

240
    if(!player()->playing()) {
241 242 243 244
        m_timer->stop();
        play(m_playlistInterface->nextFile());
    }
    else if(!m_sliderAction->dragging()) {
245
        m_sliderAction->trackPositionSlider()->setValue(player()->position());
246

247 248 249 250
        if(m_statusLabel) {
            m_statusLabel->setItemTotalTime(player()->totalTime());
            m_statusLabel->setItemCurrentTime(player()->currentTime());
        }
251
    }
252

253 254 255 256
    // Ok, this is weird stuff, but it works pretty well.  Ordinarily we don't
    // need to check up on our playing time very often, but in the span of the
    // last interval, we want to check a lot -- to figure out that we've hit the
    // end of the song as soon as possible.
257

258 259 260
    if(player()->playing() &&
       player()->totalTime() > 0 &&
       float(player()->totalTime() - player()->currentTime()) < m_pollInterval * 2)
261 262 263
    {
        m_timer->changeInterval(50);
    }
264

265
    m_noSeek = false;
266 267
}

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
void PlayerManager::slotSetOutput(int system)
{
    stop();
    delete m_player;
    m_player = Player::createPlayer(system);
}

void PlayerManager::slotSetVolume(int volume)
{
    setVolume(float(volume) / float(m_sliderAction->volumeSlider()->maxValue()));
}

void PlayerManager::slotUpdateTime(int position)
{
    if(!m_statusLabel)
        return;

    float positionFraction = float(position) / m_sliderAction->trackPositionSlider()->maxValue();
    float totalTime = float(m_player->totalTime());
    long seekTime = long(positionFraction * totalTime + 0.5); // "+0.5" for rounding

    m_statusLabel->setItemCurrentTime(seekTime);
}

292 293 294 295
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

296 297 298 299 300 301 302 303
Player *PlayerManager::player() const
{
    if(!m_player)
        instance()->setup();

    return m_player;
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
void PlayerManager::setup()
{
    // Since we're doing a little wizardry to keep the interaction and API
    // requirements as light as possible we want to check everything we're
    // going to need to make sure that everything's in order.

    KMainWindow *mainWindow = dynamic_cast<KMainWindow *>(kapp->mainWidget());

    if(!mainWindow) {
        kdWarning(65432) << k_funcinfo << "Could not find main window." << endl;
        return;
    }

    m_actionCollection = mainWindow->actionCollection();

    if(!m_actionCollection) {
        kdWarning(65432) << k_funcinfo << "Action collection is null." << endl;
        return;
    }

    // All of the actions required by this class should be listed here.

    if(!m_actionCollection->action("pause") ||
       !m_actionCollection->action("stop") ||
       !m_actionCollection->action("back") ||
       !m_actionCollection->action("forward") ||
       !m_actionCollection->action("trackPositionAction"))

    {
        kdWarning(65432) << k_funcinfo << "Could not find all of the required actions." << endl;
        return;
    }

337 338
    // initialize action states

339 340 341 342 343
    m_actionCollection->action("pause")->setEnabled(false);
    m_actionCollection->action("stop")->setEnabled(false);
    m_actionCollection->action("back")->setEnabled(false);
    m_actionCollection->action("forward")->setEnabled(false);

344 345
    // setup sliders

346
    m_sliderAction = static_cast<SliderAction *>(m_actionCollection->action("trackPositionAction"));
347

348 349 350 351 352 353 354
    connect(m_sliderAction, SIGNAL(signalPositionChanged(int)),
            this, SLOT(seekPosition(int)));
    connect(m_sliderAction->trackPositionSlider(), SIGNAL(valueChanged(int)),
            this, SLOT(slotUpdateTime(int)));
    connect(m_sliderAction->volumeSlider(), SIGNAL(valueChanged(int)),
            this, SLOT(slotSetVolume(int)));

355 356 357 358 359
    KAction *outputAction = m_actionCollection->action("outputSelect");

    if(outputAction) {
        int mediaSystem = static_cast<KSelectAction *>(outputAction)->currentItem();
        m_player = Player::createPlayer(mediaSystem);
360
        connect(outputAction, SIGNAL(activated(int)), this, SLOT(setOutputSystem(int)));
361 362 363
    }
    else
        m_player = Player::createPlayer();
364

365 366 367 368 369 370
    float volume =
        float(m_sliderAction->volumeSlider()->value()) /
	float(m_sliderAction->volumeSlider()->maxValue());

    m_player->setVolume(volume);

371 372
    m_timer = new QTimer(this, "play timer");
    connect(m_timer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
373 374 375
}

#include "playermanager.moc"