playermanager.cpp 10.2 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
	if(player()->paused())
            player()->play();
136
        else if(player()->playing())
137
            player()->seekPosition(0);
138 139 140 141 142
        else {
            QString file = m_playlistInterface->currentFile();
            if(!file.isNull())
                player()->play(file);
	}
143
    }
144
    else
145
        player()->play(fileName);
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 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
void PlayerManager::forward()
{
    QString file = m_playlistInterface->nextFile();
    if(!file.isNull())
        play(file);
    else
        stop();
}

void PlayerManager::back()
{
    QString file = m_playlistInterface->previousFile();
    if(!file.isNull())
        play(file);
    else
        stop();
}

247 248 249
////////////////////////////////////////////////////////////////////////////////
// private slots
////////////////////////////////////////////////////////////////////////////////
250

251
void PlayerManager::slotPollPlay()
252
{
253
    if(!player() || !m_playlistInterface)
254
        return;
255

256
    m_noSeek = true;
257

258
    if(!player()->playing()) {
259
        m_timer->stop();
260 261 262 263 264
        QString nextFile = m_playlistInterface->nextFile();
        if(!nextFile.isNull())
            play();
        else
            stop();
265 266
    }
    else if(!m_sliderAction->dragging()) {
267
        m_sliderAction->trackPositionSlider()->setValue(player()->position());
268

269 270 271 272
        if(m_statusLabel) {
            m_statusLabel->setItemTotalTime(player()->totalTime());
            m_statusLabel->setItemCurrentTime(player()->currentTime());
        }
273
    }
274

275 276 277 278
    // 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.
279

280 281 282
    if(player()->playing() &&
       player()->totalTime() > 0 &&
       float(player()->totalTime() - player()->currentTime()) < m_pollInterval * 2)
283 284 285
    {
        m_timer->changeInterval(50);
    }
286

287
    m_noSeek = false;
288 289
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
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);
}

314 315 316 317
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

318 319 320 321 322 323 324 325
Player *PlayerManager::player() const
{
    if(!m_player)
        instance()->setup();

    return m_player;
}

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
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;
    }

359 360
    // initialize action states

361 362 363 364 365
    m_actionCollection->action("pause")->setEnabled(false);
    m_actionCollection->action("stop")->setEnabled(false);
    m_actionCollection->action("back")->setEnabled(false);
    m_actionCollection->action("forward")->setEnabled(false);

366 367
    // setup sliders

368
    m_sliderAction = static_cast<SliderAction *>(m_actionCollection->action("trackPositionAction"));
369

370 371 372 373 374 375 376
    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)));

377 378 379 380 381
    KAction *outputAction = m_actionCollection->action("outputSelect");

    if(outputAction) {
        int mediaSystem = static_cast<KSelectAction *>(outputAction)->currentItem();
        m_player = Player::createPlayer(mediaSystem);
Scott Wheeler's avatar
Scott Wheeler committed
382
        connect(outputAction, SIGNAL(activated(int)), this, SLOT(slotSetOutput(int)));
383 384 385
    }
    else
        m_player = Player::createPlayer();
386

387 388 389 390 391 392
    float volume =
        float(m_sliderAction->volumeSlider()->value()) /
	float(m_sliderAction->volumeSlider()->maxValue());

    m_player->setVolume(volume);

393 394
    m_timer = new QTimer(this, "play timer");
    connect(m_timer, SIGNAL(timeout()), this, SLOT(slotPollPlay()));
395 396 397
}

#include "playermanager.moc"