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.
tderadio/kradio3/plugins/gui-standard-display/radioview.cpp

808 lines
23 KiB

/***************************************************************************
radioview.cpp - description
-------------------
begin : Mit Mai 28 2003
copyright : (C) 2003 by Martin Witte
email : 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 <tqwidgetstack.h>
#include <tqlayout.h>
#include <tqtoolbutton.h>
#include <tqslider.h>
#include <tqfile.h>
#include <tqtooltip.h>
#include <tqcheckbox.h>
#include <tqimage.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kapplication.h>
#include <kwin.h>
#include <kconfig.h>
#include <kpopupmenu.h>
#include "../../src/include/radiodevice_interfaces.h"
#include "../../src/include/radiostation.h"
#include "../../src/include/stationlist.h"
#include "../../src/include/pluginmanager.h"
#include "../../src/include/plugin_configuration_dialog.h"
#include "../../src/include/aboutwidget.h"
#include "radioview.h"
#include "radioview_frequencyradio.h"
#include "radioview_volume.h"
#include "radioview_frequencyseeker.h"
#include "radioview-configuration.h"
#include <kaboutdata.h>
#define POPUP_ID_START_RECORDING_DEFAULT 0
#define POPUP_ID_STOP_RECORDING_BASE 100
///////////////////////////////////////////////////////////////////////
PLUGIN_LIBRARY_FUNCTIONS(RadioView, "kradio-gui-standard-display", i18n("Standard Display for KRadio"));
///////////////////////////////////////////////////////////////////////
bool RadioView::ElementCfg::operator == (const ElementCfg &x) const
{
if (!x.element || !element)
return x.cfg == cfg;
if (!x.cfg || !cfg)
return x.element == element;
return element == x.element && cfg == x.cfg;
}
///////////////////////////////////////////////////////////////////////
RadioView::RadioView(const TQString &name)
: TQWidget(NULL, name.ascii()),
WidgetPluginBase(name, i18n("Radio Display")),
enableToolbarFlag(false),
btnPower(NULL),
btnConfigure(NULL),
btnQuit(NULL),
btnRecording(NULL),
btnSnooze(NULL),
btnPlugins(NULL),
comboStations(NULL),
currentDevice(NULL),
m_RecordingMenu(NULL),
m_NextRecordingMenuID(POPUP_ID_STOP_RECORDING_BASE),
m_PluginMenu(NULL)
{
for (int i = 0; i < clsClassMAX; ++i)
maxUsability[i] = 0;
TQBoxLayout *l01 = new TQBoxLayout(this, TQBoxLayout::LeftToRight, /*spacing=*/3);
l01->setMargin(1);
l01->setSpacing(2);
widgetStacks[clsRadioSound] = new TQWidgetStack (this);
l01->addWidget(widgetStacks[clsRadioSound]);
TQBoxLayout *l02 = new TQBoxLayout(l01, TQBoxLayout::Down);
TQBoxLayout *l03 = new TQBoxLayout(l02, TQBoxLayout::LeftToRight);
comboStations = new KComboBox (this);
l02->addWidget (comboStations);
TQBoxLayout *l05 = new TQBoxLayout(l03, TQBoxLayout::Down);
widgetStacks[clsRadioDisplay] = new TQWidgetStack (this);
l05->addWidget(widgetStacks[clsRadioDisplay]);
widgetStacks[clsRadioSeek] = new TQWidgetStack (this);
l05->addWidget(widgetStacks[clsRadioSeek]);
TQGridLayout *l04 = new TQGridLayout (l03, /*rows=*/ 3, /*cols=*/ 2);
btnPower = new TQToolButton(this);
btnPower->setToggleButton(true);
btnRecording = new TQToolButton(this);
btnRecording->setToggleButton(true);
btnConfigure = new TQToolButton(this);
btnConfigure->setToggleButton(true);
btnQuit = new TQToolButton(this);
btnSnooze = new TQToolButton(this);
btnSnooze->setToggleButton(true);
btnPlugins = new TQToolButton(this);
btnPlugins->setPopupDelay(1);
l04->addWidget (btnPower, 0, 0);
l04->addWidget (btnRecording, 0, 1);
l04->addWidget (btnConfigure, 1, 0);
l04->addWidget (btnQuit, 1, 1);
l04->addWidget (btnSnooze, 2, 0);
l04->addWidget (btnPlugins, 2, 1);
m_pauseMenu = new KPopupMenu(btnPower);
m_pauseMenu->insertItem(SmallIcon("kradio_pause"),
i18n("Pause KRadio"),
this, TQT_SLOT(slotPause()));
btnPower->setPopupDelay(200);
m_RecordingMenu = new KPopupMenu(btnRecording);
m_RecordingMenu->insertItem(SmallIcon("kradio_record"),
i18n("Start Recording"),
POPUP_ID_START_RECORDING_DEFAULT);
TQObject::connect(m_RecordingMenu, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(slotRecordingMenu(int)));
btnRecording->setPopup(m_RecordingMenu);
m_SnoozeMenu = new KPopupMenu(btnSnooze);
m_SnoozeMenu->insertItem(i18n("5 min"), this, TQT_SLOT(slotSnooze(int)), 0, 5);
m_SnoozeMenu->insertItem(i18n("10 min"), this, TQT_SLOT(slotSnooze(int)), 0, 10);
m_SnoozeMenu->insertItem(i18n("15 min"), this, TQT_SLOT(slotSnooze(int)), 0, 15);
m_SnoozeMenu->insertItem(i18n("30 min"), this, TQT_SLOT(slotSnooze(int)), 0, 30);
m_SnoozeMenu->insertItem(i18n("60 min"), this, TQT_SLOT(slotSnooze(int)), 0, 60);
btnSnooze->setPopup(m_SnoozeMenu);
btnSnooze->setPopupDelay(200);
// Plugin-Button/Menu
m_PluginMenu = new KPopupMenu(btnPlugins);
if (m_manager)
m_manager->addWidgetPluginMenuItems(m_PluginMenu, m_Plugins2MenuID);
btnPlugins->setPopup(m_PluginMenu);
// ICONS
btnPower->setIconSet(SmallIconSet("kradio_muteon"));
btnRecording->setIconSet(SmallIconSet("kradio_record"));
btnConfigure->setIconSet(SmallIconSet("configure"));
btnQuit->setIconSet(SmallIconSet("exit"));
btnSnooze->setIconSet(SmallIconSet("kradio_zzz"));
btnPlugins->setIconSet(SmallIconSet("kradio_plugins"));
widgetStacks[clsRadioSound] ->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Preferred));
widgetStacks[clsRadioDisplay]->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Preferred));
widgetStacks[clsRadioSeek] ->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed));
comboStations ->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed));
comboStations->setMinimumHeight(28);
TQObject::connect(btnPower, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(slotPower(bool)));
TQObject::connect(btnQuit, TQT_SIGNAL(clicked()),
kapp, TQT_SLOT(quit()));
TQObject::connect(btnConfigure, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(slotConfigure(bool)));
TQObject::connect(btnRecording, TQT_SIGNAL(clicked()),
this, TQT_SLOT(slotRecord()));
TQObject::connect(btnSnooze, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(slotSnooze(bool)));
TQObject::connect(comboStations, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(slotComboStationSelected(int)));
TQObject::connect(btnPlugins, TQT_SIGNAL(clicked()),
this, TQT_SLOT(slotBtnPluginsClicked()));
// tooltips
TQToolTip::add(btnConfigure, i18n("Configure KRadio"));
TQToolTip::add(btnPower, i18n("Power On/Off"));
TQToolTip::add(btnQuit, i18n("Quit KRadio Application"));
TQToolTip::add(btnRecording, i18n("Start/Stop Recording"));
TQToolTip::add(btnSnooze, i18n("Start/Stop Sleep Countdown"));
TQToolTip::add(btnPlugins, i18n("Show/Hide Plugins"));
TQToolTip::add(comboStations, i18n("Select a Radio Station"));
// testing
addElement (new RadioViewFrequencyRadio (this, TQString()));
addElement (new RadioViewVolume(this, TQString()));
addElement (new RadioViewFrequencySeeker(this, TQString()));
autoSetCaption();
}
RadioView::~RadioView ()
{
TQPtrListIterator<TQObject> it(configPages);
while (configPages.first()) {
delete configPages.first();
}
configPages.clear();
}
bool RadioView::addElement (RadioViewElement *e)
{
if (!e) return false;
RadioViewClass cls = e->getClass();
if (cls < 0 || cls >= clsClassMAX)
return false;
e->reparent(this, TQPoint(0, 0), true);
TQObject::connect(e, TQT_SIGNAL(destroyed(TQObject*)),
this, TQT_SLOT(removeElement(TQObject*)));
elements.append(e);
widgetStacks[cls]->addWidget(e);
// connect Element with device, disconnect doesn't matter (comp. removeElement)
// other devices follow if currentDevice changes
if (currentDevice)
e->connectI(currentDevice);
e->connectI(getSoundStreamServer());
TQPtrListIterator<TQObject> it(configPages);
for (; it.current(); ++it) {
addConfigurationTabFor(e, (TQTabWidget *)it.current());
}
selectTopWidgets();
return true;
}
bool RadioView::removeElement (TQObject *_e)
{
RadioViewElement *e = dynamic_cast<RadioViewElement*>(_e);
if (!e)
return false;
ElementCfgListIterator it;
while ((it = elementConfigPages.find(e)) != elementConfigPages.end()) {
delete (*it).cfg;
// it must not used behind, the element will be deleted automatically
// by slotElementConfigPageDeleted
}
e->disconnectI(getSoundStreamServer());
if (currentDevice)
e->disconnectI(currentDevice);
RadioViewClass cls = e->getClass();
TQObject::disconnect(e, TQT_SIGNAL(destroyed(TQObject*)),
this, TQT_SLOT(removeElement(TQObject*)));
widgetStacks[cls]->removeWidget(e);
elements.remove(e);
selectTopWidgets();
return true;
}
void RadioView::selectTopWidgets()
{
for (int i = 0; i < clsClassMAX; ++i)
maxUsability[i] = 0;
for (ElementListIterator i(elements); i.current(); ++i) {
RadioViewElement *e = i.current();
RadioViewClass cls = e->getClass();
float u = e->getUsability(currentDevice);
if (u > maxUsability[cls]) {
maxUsability[cls] = u;
widgetStacks[cls]->raiseWidget(e);
}
}
// adjustLayout!?
}
// IRadioClient
bool RadioView::noticePowerChanged(bool on)
{
btnPower->setIconSet(SmallIconSet( on ? "kradio_muteoff" : "kradio_muteon"));
btnPower->setOn(on);
if (on) {
btnPower->setPopup(m_pauseMenu);
} else {
btnPower->setPopup(NULL);
}
autoSetCaption();
return true;
}
bool RadioView::noticeStationChanged (const RadioStation &, int idx)
{
// add 1 for "no preset defined" entry
comboStations->setCurrentItem(idx + 1);
autoSetCaption();
bool r = false;
SoundFormat sf;
queryIsRecordingRunning(queryCurrentSoundStreamID(), r, sf);
m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, !r);
return true;
}
bool RadioView::noticeStationsChanged(const StationList &sl)
{
const RawStationList &list = sl.all();
comboStations->clear();
comboStations->insertItem("<" + i18n("no preset defined") + ">");
for (RawStationList::Iterator i(list); i.current(); ++i) {
RadioStation *stn = i.current();
TQString icon = stn->iconName();
if (icon.length() && TQFile(icon).exists()) {
TQImage img(icon);
int h = img.height();
float f = (float)(comboStations->height() - 4) / (h ? (float)h : 1.0);
comboStations->insertItem(img.smoothScale((int)(img.width()*f), (int)(h * f)), stn->name());
} else {
comboStations->insertItem(stn->name());
}
}
noticeStationChanged(queryCurrentStation(), queryCurrentStationIdx());
return true;
}
bool RadioView::noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/)
{
// FIXME: perhaps do something
return false;
}
// IRadioDevicePoolClient
bool RadioView::noticeActiveDeviceChanged(IRadioDevice *newDevice)
{
IRadioDevice *oldDevice = currentDevice;
currentDevice = newDevice;
for (ElementListIterator i(elements); i.current(); ++i) {
RadioViewElement *e = i.current();
if (oldDevice)
e->disconnectI(oldDevice);
if (newDevice)
e->connectI(currentDevice);
}
selectTopWidgets();
return true;
}
// Interface
bool RadioView::connectI(Interface *i)
{
bool a = IRadioClient::connectI(i);
bool b = IRadioDevicePoolClient::connectI(i);
bool c = PluginBase::connectI(i);
bool d = ITimeControlClient::connectI(i);
// Callbacks for ISoundStreamClient
bool e = ISoundStreamClient::connectI(i);
return a || b || c || d || e;
}
bool RadioView::disconnectI(Interface *i)
{
bool a = IRadioClient::disconnectI(i);
bool b = IRadioDevicePoolClient::disconnectI(i);
bool c = PluginBase::disconnectI(i);
bool d = ITimeControlClient::disconnectI(i);
bool e = ISoundStreamClient::disconnectI(i);
if (e) {
// special task for soundstreamclient, different from radio device pool
for (ElementListIterator it(elements); it.current(); ++it) {
RadioViewElement *e = it.current();
e->disconnectI(i);
}
}
return a || b || c || d || e;
}
void RadioView::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
{
ISoundStreamClient::noticeConnectedI(s, pointer_valid);
if (s && pointer_valid) {
s->register4_sendStartRecordingWithFormat(this);
s->register4_sendStopRecording (this);
s->register4_notifySoundStreamChanged (this);
// special task for soundstreamclient, different from radio device pool
for (ElementListIterator it(elements); it.current(); ++it) {
RadioViewElement *e = it.current();
e->connectI(s);
}
}
}
// ISoundStreamClient
bool RadioView::startRecordingWithFormat(
SoundStreamID id,
const SoundFormat &/*proposed_format*/,
SoundFormat &/*real_format*/)
{
if (!id.isValid() || id != queryCurrentSoundStreamID() || m_StreamID2MenuID.contains(id))
return false;
TQString descr;
querySoundStreamDescription(id, descr);
int menu_id = m_NextRecordingMenuID++;
m_RecordingMenu->insertItem(SmallIcon("kradio_record"),
i18n("Stop Recording of %1").arg(descr),
menu_id);
m_MenuID2StreamID.insert(menu_id, id);
m_StreamID2MenuID.insert(id, menu_id);
btnRecording->setOn(true);
if (id == queryCurrentSoundStreamID())
m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, false);
return false; // this is only a "hook" that does not initiate the recording so don't say that we handled the event
}
bool RadioView::stopRecording (SoundStreamID id)
{
if (!id.isValid() || !m_StreamID2MenuID.contains(id))
return false;
int menu_id = m_StreamID2MenuID[id];
m_RecordingMenu->removeItem(menu_id);
m_MenuID2StreamID.remove(menu_id);
m_StreamID2MenuID.remove(id);
btnRecording->setOn(m_StreamID2MenuID.count() > 0);
if (id == queryCurrentSoundStreamID())
m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, true);
return false;
}
bool RadioView::noticeSoundStreamChanged(SoundStreamID id)
{
if (m_StreamID2MenuID.contains(id)) {
TQString descr;
querySoundStreamDescription(id, descr);
m_RecordingMenu->changeItem(m_StreamID2MenuID[id],
SmallIcon("kradio_record"),
i18n("Stop Recording of %1").arg(descr));
return true;
}
return false;
}
// ITimeControl
bool RadioView::noticeCountdownStarted(const TQDateTime &)
{
btnSnooze->setOn(true);
return true;
}
bool RadioView::noticeCountdownStopped()
{
btnSnooze->setOn(false);
return true;
}
bool RadioView::noticeCountdownZero()
{
btnSnooze->setOn(false);
return true;
}
// WidgetPluginBase
void RadioView::saveState (KConfig *config) const
{
config->setGroup(TQString("radioview-") + name());
config->writeEntry("enableToobarFlag", enableToolbarFlag);
WidgetPluginBase::saveState(config);
for (ElementListIterator i(elements); i.current(); ++i) {
RadioViewElement *e = i.current();
e->saveState(config);
}
}
void RadioView::restoreState (KConfig *config)
{
config->setGroup(TQString("radioview-") + name());
enableToolbarFlag = config->readBoolEntry("enableToolbarFlag", false);
WidgetPluginBase::restoreState(config);
for (ElementListIterator i(elements); i.current(); ++i) {
RadioViewElement *e = i.current();
e->restoreState(config);
}
}
ConfigPageInfo RadioView::createConfigurationPage()
{
RadioViewConfiguration *c = new RadioViewConfiguration();
//addCommonConfigurationTab(c);
for (ElementListIterator i(elements); i.current(); ++i) {
addConfigurationTabFor(i.current(), c);
}
configPages.append(TQT_TQOBJECT(c));
TQObject::connect(c, TQT_SIGNAL(destroyed(TQObject *)),
this, TQT_SLOT(slotConfigPageDeleted(TQObject *)));
return ConfigPageInfo(
c,
i18n("Display"),
i18n("Display Configuration"),
"openterm"
);
}
void RadioView::addConfigurationTabFor(RadioViewElement *e, TQTabWidget *c)
{
if (!e || !c)
return;
ConfigPageInfo inf = e->createConfigurationPage();
if (inf.page) {
if (inf.iconName.length()) {
c->addTab(inf.page, TQIconSet(SmallIconSet(inf.iconName)), inf.itemName);
} else {
c->addTab(inf.page, inf.itemName);
}
elementConfigPages.push_back(ElementCfg(e, TQT_TQOBJECT(inf.page)));
TQObject::connect(inf.page, TQT_SIGNAL(destroyed(TQObject *)),
this, TQT_SLOT(slotElementConfigPageDeleted(TQObject *)));
}
}
void RadioView::addCommonConfigurationTab(TQTabWidget *c)
{
if (!c)
return;
TQFrame *f = new TQFrame(c);
TQVBoxLayout *l = new TQVBoxLayout(f, 10);
l->addWidget(new TQCheckBox(i18n("set Toolbar-Flag for Display"), f));
l->addItem(new TQSpacerItem(1, 3, TQSizePolicy::Fixed, TQSizePolicy::Expanding));
c->addTab(f, i18n("Common"));
elementConfigPages.push_back(ElementCfg(TQT_TQOBJECT(f)));
TQObject::connect(f, TQT_SIGNAL(destroyed(TQObject *)),
this, TQT_SLOT(slotElementConfigPageDeleted(TQObject *)));
}
AboutPageInfo RadioView::createAboutPage()
{
/* KAboutData aboutData("kradio",
NULL,
NULL,
I18N_NOOP("Standard Radio Display 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("Display"),
i18n("Standard Radio Display for KRadio"),
"openterm"
);*/
return AboutPageInfo();
}
void RadioView::noticeWidgetPluginShown(WidgetPluginBase *p, bool shown)
{
if (!m_manager || !p)
return;
if ((WidgetPluginBase*)m_manager->getConfigDialog() == p) {
btnConfigure->blockSignals(true);
btnConfigure->setOn(shown);
btnConfigure->blockSignals(false);
}
if (m_Plugins2MenuID.contains(p)) {
m_manager->updateWidgetPluginMenuItem(p, m_PluginMenu, m_Plugins2MenuID, shown);
}
}
// own Stuff
void RadioView::noticePluginsChanged(const PluginList &/*l*/)
{
m_Plugins2MenuID.clear();
m_PluginMenu->clear();
if (m_manager)
m_manager->addWidgetPluginMenuItems(m_PluginMenu, m_Plugins2MenuID);
}
void RadioView::slotPower(bool on)
{
on ? sendPowerOn() : sendPowerOff();
btnPower->setOn(queryIsPowerOn());
}
void RadioView::slotPause()
{
if (queryIsPowerOn()) {
sendPausePlayback(queryCurrentSoundStreamID());
}
}
void RadioView::slotConfigure(bool b)
{
TQWidget *w = m_manager ? m_manager->getConfigDialog() : NULL;
if (w) b ? w->show() : w->hide();
if (!w)
btnConfigure->setOn(false);
}
void RadioView::slotRecord()
{
SoundStreamID id = queryCurrentSoundStreamID();
bool b = btnRecording->isOn();
bool r = false;
SoundFormat sf;
queryIsRecordingRunning(id, r, sf);
if (!r && b /*!m_StreamID2MenuID.contains(id)*/) {
if (!queryIsPowerOn())
sendPowerOn();
sendStartRecording(id);
} else if (r && !b) {
sendStopRecording(id);
}
}
void RadioView::slotRecordingMenu(int i)
{
if (i == POPUP_ID_START_RECORDING_DEFAULT) {
SoundStreamID id = queryCurrentSoundStreamID();
bool r = false;
SoundFormat sf;
queryIsRecordingRunning(id, r, sf);
if (!r) {
if (!queryIsPowerOn())
sendPowerOn();
sendStartRecording(id);
}
} else if (m_MenuID2StreamID.contains(i)) {
sendStopRecording(m_MenuID2StreamID[i]);
}
}
void RadioView::slotSnooze(bool on)
{
if (on)
sendStartCountdown();
else
sendStopCountdown();
}
void RadioView::slotSnooze(int n)
{
sendCountdownSeconds(n*60);
sendStartCountdown();
}
void RadioView::slotComboStationSelected(int idx)
{
if (idx > 0) {
sendActivateStation(idx - 1);
} else {
comboStations->setCurrentItem(queryCurrentStationIdx() + 1);
}
}
void RadioView::slotBtnPluginsClicked()
{
btnPlugins->openPopup();
}
void RadioView::slotConfigPageDeleted(TQObject *o)
{
configPages.remove(o);
}
void RadioView::slotElementConfigPageDeleted(TQObject *o)
{
ElementCfgListIterator it;
while ((it = elementConfigPages.find(o)) != elementConfigPages.end()) {
elementConfigPages.remove(it);
}
}
void RadioView::show()
{
if (enableToolbarFlag)
KWin::setType(winId(), NET::Toolbar);
else
KWin::setType(winId(), NET::Normal);
WidgetPluginBase::pShow();
TQWidget::show();
}
void RadioView::showOnOrgDesktop()
{
WidgetPluginBase::pShowOnOrgDesktop();
//TQWidget::show();
}
void RadioView::hide()
{
WidgetPluginBase::pHide();
TQWidget::hide();
}
void RadioView::showEvent(TQShowEvent *e)
{
TQWidget::showEvent(e);
WidgetPluginBase::pShowEvent(e);
}
void RadioView::hideEvent(TQHideEvent *e)
{
TQWidget::hideEvent(e);
WidgetPluginBase::pHideEvent(e);
}
void RadioView::autoSetCaption()
{
const RadioStation &rs = queryCurrentStation();
setCaption((queryIsPowerOn() && rs.isValid()) ? rs.longName() : TQString("KRadio"));
}
#include "radioview.moc"