|
|
|
/***************************************************************************
|
|
|
|
radio.cpp - description
|
|
|
|
-------------------
|
|
|
|
begin : Sat March 29 2003
|
|
|
|
copyright : (C) 2003 by Klas Kalass, Ernst Martin Witte
|
|
|
|
email : klas@kde.org, witte@kawo1.rwth-aachen.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* 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 "../../src/include/radiostation.h"
|
|
|
|
#include "../../src/include/aboutwidget.h"
|
|
|
|
#include "../../src/include/radiodevice_interfaces.h"
|
|
|
|
#include "radio.h"
|
|
|
|
#include "radio-configuration.h"
|
|
|
|
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
#include <kaboutdata.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
|
|
|
|
#include "../../src/include/debug-profiler.h"
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
//// plugin library functions
|
|
|
|
|
|
|
|
PLUGIN_LIBRARY_FUNCTIONS(Radio, "kradio-radio", i18n("Central Radio Device Multiplexer"));
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
Radio::Radio(const TQString &name)
|
|
|
|
: PluginBase(name, i18n("Radio Multiplexer Plugin")),
|
|
|
|
IRadioDeviceClient(-1),
|
|
|
|
m_presetFile(locateLocal("data", "kradio/stations.krp")),
|
|
|
|
m_activeDevice (NULL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Radio::~Radio()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::connectI (Interface *i)
|
|
|
|
{
|
|
|
|
bool a = IRadio::connectI(i);
|
|
|
|
bool b = IRadioDeviceClient::connectI(i);
|
|
|
|
bool c = IRadioDevicePool::connectI(i);
|
|
|
|
bool d = PluginBase::connectI(i);
|
|
|
|
bool e = ISoundStreamClient::connectI(i);
|
|
|
|
|
|
|
|
// no "return IA::connectI() | return IB::connnectI to
|
|
|
|
// prevent "early termination" optimization in boolean expressions
|
|
|
|
return a || b || c || d || e;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::disconnectI (Interface *i)
|
|
|
|
{
|
|
|
|
bool a = IRadio::disconnectI(i);
|
|
|
|
bool b = IRadioDeviceClient::disconnectI(i);
|
|
|
|
bool c = IRadioDevicePool::disconnectI(i);
|
|
|
|
bool d = PluginBase::disconnectI(i);
|
|
|
|
bool e = ISoundStreamClient::disconnectI(i);
|
|
|
|
|
|
|
|
// no "return IA::disconnectI() | return IB::disconnnectI to
|
|
|
|
// prevent "early termination" optimization in boolean expressions
|
|
|
|
return a || b || c || d || e;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Radio::saveState (KConfig *config) const
|
|
|
|
{
|
|
|
|
config->setGroup(TQString("radio-") + name());
|
|
|
|
|
|
|
|
config->writeEntry("presetfile", m_presetFile);
|
|
|
|
|
|
|
|
m_stationList.writeXML(m_presetFile, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Radio::restoreState (KConfig *config)
|
|
|
|
{
|
|
|
|
config->setGroup(TQString("radio-") + name());
|
|
|
|
|
|
|
|
m_presetFile = config->readEntry("presetfile",
|
|
|
|
TQString());
|
|
|
|
bool first_restore = false;
|
|
|
|
if (m_presetFile.isNull() || m_presetFile.length() == 0) {
|
|
|
|
m_presetFile = locateLocal("data", "kradio/stations.krp");
|
|
|
|
first_restore = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_stationList.readXML(KURL(m_presetFile), *this, /*enable-messagebox*/ !first_restore);
|
|
|
|
|
|
|
|
notifyStationsChanged(m_stationList);
|
|
|
|
notifyPresetFileChanged(m_presetFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ConfigPageInfo Radio::createConfigurationPage()
|
|
|
|
{
|
|
|
|
RadioConfiguration *conf = new RadioConfiguration (NULL, *this);
|
|
|
|
connectI (conf);
|
|
|
|
return ConfigPageInfo(
|
|
|
|
conf,
|
|
|
|
i18n("Radio Stations"),
|
|
|
|
i18n("Setup Radio Stations"),
|
|
|
|
"kradio"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AboutPageInfo Radio::createAboutPage()
|
|
|
|
{
|
|
|
|
/* KAboutData aboutData("kradio",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
I18N_NOOP("Radio Device Multiplexer and Station Management for KRadio"),
|
|
|
|
KAboutData::License_GPL,
|
|
|
|
"(c) 2002-2005 Martin Witte, Klas Kalass",
|
|
|
|
0,
|
|
|
|
"http://sourceforge.net/projects/kradio",
|
|
|
|
0);
|
|
|
|
aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
|
|
|
|
aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de");
|
|
|
|
|
|
|
|
return AboutPageInfo(
|
|
|
|
new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
|
|
|
|
i18n("Device and Station Management"),
|
|
|
|
i18n("Radio Device Multiplexer and Station Management"),
|
|
|
|
"kradio"
|
|
|
|
);
|
|
|
|
*/
|
|
|
|
return AboutPageInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* IRadio Interface Methods
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* offer new station to current device.
|
|
|
|
if that does not accept, try all other devices.
|
|
|
|
Any device will be powered off if it does not accept the station
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool Radio::activateStation (const RadioStation &rs) {
|
|
|
|
|
|
|
|
if (sendActivateStation(rs)) { // first try activeDevice
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else { // hmm... active device did not want it. Try others...
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
for (IRadioDeviceClient::IFIterator it(IRadioDeviceClient::iConnections); it.current(); ++it) {
|
|
|
|
|
|
|
|
if (it.current()->activateStation(rs)) {
|
|
|
|
|
|
|
|
setActiveDevice(it.current()); // select new device
|
|
|
|
++n;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
it.current()->powerOff();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::activateStation(int index)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= m_stationList.count())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return activateStation(m_stationList.at(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::setStations(const StationList &sl)
|
|
|
|
{
|
|
|
|
if (true/*m_stationList != sl*/) {
|
|
|
|
BlockProfiler("Radio::setStations");
|
|
|
|
m_stationList = sl;
|
|
|
|
notifyStationsChanged(m_stationList);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Radio::setPresetFile(const TQString &presetFile)
|
|
|
|
{
|
|
|
|
if (m_presetFile != presetFile) {
|
|
|
|
m_presetFile = presetFile;
|
|
|
|
notifyPresetFileChanged(m_presetFile);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Radio::getStationIdx(const RadioStation &rs) const
|
|
|
|
{
|
|
|
|
RawStationList &sl = const_cast<RawStationList&>(m_stationList.all());
|
|
|
|
return sl.find(&rs);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Radio::getCurrentStationIdx() const
|
|
|
|
{
|
|
|
|
return getStationIdx(getCurrentStation());
|
|
|
|
}
|
|
|
|
|
|
|
|
SoundStreamID Radio::getCurrentSoundStreamID() const
|
|
|
|
{
|
|
|
|
return queryCurrentSoundStreamID();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* IRadioDevicePool Interface Methods
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::setActiveDevice(IRadioDevice *rd, bool keepPower)
|
|
|
|
{
|
|
|
|
// do nothing if old == new
|
|
|
|
if (m_activeDevice == rd)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// check if new station is in "connections"
|
|
|
|
// special case: rd == NULL: power off active device, new active device = NULL
|
|
|
|
|
|
|
|
if (!rd || IRadioDeviceClient::iConnections.containsRef(rd)) { // new device is ok
|
|
|
|
|
|
|
|
// save old power state and power off old device
|
|
|
|
bool oldPowerOn = false;
|
|
|
|
if (m_activeDevice) {
|
|
|
|
oldPowerOn = m_activeDevice->isPowerOn();
|
|
|
|
m_activeDevice->powerOff();
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup new active device && send notifications
|
|
|
|
m_activeDevice = rd;
|
|
|
|
|
|
|
|
// send notifications
|
|
|
|
notifyActiveDeviceChanged(m_activeDevice);
|
|
|
|
notifyCurrentSoundStreamIDChanged(queryCurrentSoundStreamID());
|
|
|
|
const RadioStation &rs = queryCurrentStation();
|
|
|
|
notifyStationChanged(rs, getStationIdx(rs));
|
|
|
|
|
|
|
|
if (keepPower)
|
|
|
|
oldPowerOn ? sendPowerOn() : sendPowerOff();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IRadioDevice *Radio::getActiveDevice() const
|
|
|
|
{
|
|
|
|
return m_activeDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const TQPtrList<IRadioDevice> &Radio::getDevices() const
|
|
|
|
{
|
|
|
|
return IRadioDeviceClient::iConnections;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const TQString &Radio::getDeviceDescription() const
|
|
|
|
{
|
|
|
|
return queryDescription();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* IRadioDeviceClient Interface Methods
|
|
|
|
|
|
|
|
Many things are overwritten, particularly all sending methods
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Radio::sendPowerOn() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->powerOn() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Radio::sendPowerOff() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->powerOff() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Radio::sendActivateStation (const RadioStation &rs) const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->activateStation(rs) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::queryIsPowerOn() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->isPowerOn() : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::queryIsPowerOff() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->isPowerOff() : true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const RadioStation & Radio::queryCurrentStation() const
|
|
|
|
{
|
|
|
|
if (m_activeDevice) {
|
|
|
|
RadioStation &rs = const_cast<RadioStation&>(m_activeDevice->getCurrentStation());
|
|
|
|
int idx = getStationIdx(rs);
|
|
|
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
rs.copyDescriptionFrom(m_stationList.at(idx));
|
|
|
|
} else {
|
|
|
|
rs.copyDescriptionFrom(undefinedRadioStation);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rs;
|
|
|
|
} else {
|
|
|
|
return undefinedRadioStation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static TQString qstrUnknown(I18N_NOOP("unknown"));
|
|
|
|
static TQString i18nqstrUnknown;
|
|
|
|
const TQString &Radio::queryDescription() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->getDescription() : (i18nqstrUnknown = i18n(qstrUnknown.ascii()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::noticePowerChanged (bool on, const IRadioDevice *sender)
|
|
|
|
{
|
|
|
|
if (on) {
|
|
|
|
setActiveDevice(const_cast<IRadioDevice*>(sender), false);
|
|
|
|
// false: do not set power state on new device
|
|
|
|
// constcast valid because power-state of sender is not changed
|
|
|
|
notifyPowerChanged(true);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (sender == m_activeDevice) {
|
|
|
|
sendStopCountdown();
|
|
|
|
notifyPowerChanged(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::noticeStationChanged (const RadioStation &_rs, const IRadioDevice *sender)
|
|
|
|
{
|
|
|
|
RadioStation &rs = const_cast<RadioStation&>(_rs);
|
|
|
|
int idx = getStationIdx(rs);
|
|
|
|
|
|
|
|
RadioStation &known = (idx >= 0) ? (RadioStation&)m_stationList.at(idx) :
|
|
|
|
(RadioStation&)undefinedRadioStation;
|
|
|
|
rs.copyDescriptionFrom(known);
|
|
|
|
|
|
|
|
if (sender == m_activeDevice)
|
|
|
|
notifyStationChanged(rs, idx);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::noticeDescriptionChanged (const TQString &s, const IRadioDevice *sender)
|
|
|
|
{
|
|
|
|
if (sender == m_activeDevice)
|
|
|
|
notifyDeviceDescriptionChanged(s);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::noticeCurrentSoundStreamIDChanged(SoundStreamID id, const IRadioDevice *sender)
|
|
|
|
{
|
|
|
|
if (sender == m_activeDevice)
|
|
|
|
notifyCurrentSoundStreamIDChanged(id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SoundStreamID Radio::queryCurrentSoundStreamID() const
|
|
|
|
{
|
|
|
|
return m_activeDevice ? m_activeDevice->getCurrentSoundStreamID() : SoundStreamID::InvalidID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Radio::noticeConnectedI(IRadioDeviceClient::cmplInterface *dev, bool pointer_valid)
|
|
|
|
{
|
|
|
|
IRadioDeviceClient::noticeConnectedI(dev, pointer_valid);
|
|
|
|
|
|
|
|
if (! m_activeDevice && pointer_valid)
|
|
|
|
setActiveDevice (dev, false);
|
|
|
|
|
|
|
|
notifyDevicesChanged(IRadioDeviceClient::iConnections);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Radio::noticeDisconnectI(IRadioDeviceClient::cmplInterface *rd, bool pointer_valid)
|
|
|
|
{
|
|
|
|
IRadioDeviceClient::noticeDisconnectI(rd, pointer_valid);
|
|
|
|
|
|
|
|
if (rd == m_activeDevice) {
|
|
|
|
|
|
|
|
// search a new active device
|
|
|
|
if (IRadioDeviceClient::iConnections.findRef(rd) >= 0) {
|
|
|
|
|
|
|
|
IRadioDevice *new_rd = NULL;
|
|
|
|
|
|
|
|
new_rd = IRadioDeviceClient::iConnections.next(); // choose next device as active device if next exists
|
|
|
|
if (!new_rd) {
|
|
|
|
IRadioDeviceClient::iConnections.findRef(rd);
|
|
|
|
new_rd = IRadioDeviceClient::iConnections.prev(); // otherwise try prev then, may be NULL (no connections)
|
|
|
|
}
|
|
|
|
setActiveDevice(new_rd);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// strange error occurred, m_activeDevice not in connections... set to first.
|
|
|
|
|
|
|
|
setActiveDevice(IRadioDeviceClient::iConnections.first());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
notifyDevicesChanged(IRadioDeviceClient::iConnections);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ITimeControlClient
|
|
|
|
|
|
|
|
bool Radio::noticeAlarm(const Alarm &a)
|
|
|
|
{
|
|
|
|
if (a.alarmType() == Alarm::StartPlaying ||
|
|
|
|
a.alarmType() == Alarm::StartRecording)
|
|
|
|
{
|
|
|
|
const RawStationList &sl = getStations().all();
|
|
|
|
const RadioStation &rs = sl.stationWithID(a.stationID());
|
|
|
|
activateStation(rs);
|
|
|
|
powerOn();
|
|
|
|
|
|
|
|
if (a.volumePreset() >= 0)
|
|
|
|
sendPlaybackVolume(getCurrentSoundStreamID(), a.volumePreset());
|
|
|
|
|
|
|
|
SoundStreamID id = getCurrentSoundStreamID();
|
|
|
|
bool r = false;
|
|
|
|
SoundFormat sf;
|
|
|
|
queryIsRecordingRunning(id, r, sf);
|
|
|
|
if (a.alarmType() == Alarm::StartRecording && !r)
|
|
|
|
sendStartRecording(id);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
powerOff();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Radio::noticeCountdownZero()
|
|
|
|
{
|
|
|
|
powerOff();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Radio::aboutToQuit()
|
|
|
|
{
|
|
|
|
sendPowerOff();
|
|
|
|
}
|
|
|
|
|