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-docking-menu/docking.cpp

675 lines
20 KiB

/***************************************************************************
docking.cpp - description
-------------------
begin : Don M<>r 8 21:57:17 CET 2001
copyright : (C) 2002 by Ernst 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 <kiconloader.h>
#include <tqtooltip.h>
#include <kpopupmenu.h>
#include <kapplication.h>
#include <kaction.h>
#include <kdialogbase.h>
#include <kaboutdata.h>
#include <kconfig.h>
#include <twin.h>
#include "../../src/include/radiodevice_interfaces.h"
#include "../../src/include/stationlist.h"
#include "../../src/include/pluginmanager.h"
#include "../../src/include/widgetplugins.h"
#include "../../src/include/radiostation.h"
#include "../../src/include/aboutwidget.h"
#include "../../src/include/station-drag-object.h"
#include "docking.h"
#include "docking-configuration.h"
#define POPUP_ID_START_RECORDING_DEFAULT 0
#define POPUP_ID_STOP_RECORDING_BASE 100
///////////////////////////////////////////////////////////////////////
PLUGIN_LIBRARY_FUNCTIONS(RadioDocking, "kradio-gui-docking-menu", i18n("Tray Menu for KRadio"));
/////////////////////////////////////////////////////////////////////////////
RadioDocking::RadioDocking(const TQString &name)
: KSystemTray (NULL, name.ascii()),
PluginBase(name, i18n("Docking Plugin")),
m_pluginMenu(NULL),
m_recordingMenu(NULL),
m_NextRecordingMenuID(POPUP_ID_STOP_RECORDING_BASE),
m_leftClickAction(lcaShowHide)
{
setPixmap(BarIcon("kradio"));
m_menu = contextMenu();
TQObject::connect(m_menu, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(slotMenuItemActivated(int)));
buildContextMenu ();
show();
setAcceptDrops(true);
}
RadioDocking::~RadioDocking()
{
}
bool RadioDocking::connectI (Interface *i)
{
bool a = IRadioClient::connectI(i);
bool b = ITimeControlClient::connectI(i);
bool c = IRadioDevicePoolClient::connectI(i);
bool d = IStationSelection::connectI(i);
bool e = ISoundStreamClient::connectI(i);
bool f = PluginBase::connectI(i);
return a || b || c || d || e || f;
}
bool RadioDocking::disconnectI (Interface *i)
{
bool a = IRadioClient::disconnectI(i);
bool b = ITimeControlClient::disconnectI(i);
bool c = IRadioDevicePoolClient::disconnectI(i);
bool d = IStationSelection::disconnectI(i);
bool e = ISoundStreamClient::disconnectI(i);
bool f = PluginBase::disconnectI(i);
return a || b || c || d || e || f;
}
void RadioDocking::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);
}
}
bool RadioDocking::setStationSelection(const TQStringList &sl)
{
if (m_stationIDs != sl) {
m_stationIDs = sl;
buildContextMenu();
notifyStationSelectionChanged(m_stationIDs);
}
return true;
}
// PluginBase
void RadioDocking::restoreState (KConfig *config)
{
config->setGroup(TQString("radiodocking-") + name());
m_stationIDs.clear();
int nStations = config->readNumEntry("nStations", 0);
for (int i = 1; i <= nStations; ++i) {
TQString s = config->readEntry(TQString("stationID-") + TQString().setNum(i), TQString());
if (s.length())
m_stationIDs += s;
}
m_leftClickAction = (LeftClickAction)config->readNumEntry("left_click_action", lcaShowHide);
buildContextMenu();
notifyStationSelectionChanged(m_stationIDs);
int n = config->readNumEntry("show_hide_cache_entries", 0);
for (int i = 1; i <= n; ++i) {
TQString s = config->readEntry(TQString("show_hide_cache_id_%1").arg(i), TQString());
bool b = config->readBoolEntry(TQString("show_hide_cache_value_%1").arg(i), false);
if (!s.isNull()) {
m_widgetsShownCache.insert(s,b);
}
}
}
void RadioDocking::saveState (KConfig *config) const
{
config->setGroup(TQString("radiodocking-") + name());
config->writeEntry("nStations", m_stationIDs.size());
int i = 1;
TQStringList::const_iterator end = m_stationIDs.end();
for (TQStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++i) {
config->writeEntry(TQString("stationID-") + TQString().setNum(i), *it);
}
config->writeEntry("left_click_action", (int)m_leftClickAction);
config->writeEntry("show_hide_cache_entries", m_widgetsShownCache.count());
i = 1;
for (TQMapConstIterator<TQString, bool> it = m_widgetsShownCache.begin(); it != m_widgetsShownCache.end(); ++it, ++i) {
config->writeEntry(TQString("show_hide_cache_id_%1").arg(i), it.key());
config->writeEntry(TQString("show_hide_cache_value_%1").arg(i), *it);
}
}
ConfigPageInfo RadioDocking::createConfigurationPage()
{
DockingConfiguration *conf = new DockingConfiguration(this, NULL);
connectI (conf);
TQObject::connect(this, TQT_SIGNAL(sigLeftClickActionChanged(LeftClickAction)),
conf, TQT_SLOT(slotLeftClickActionChanged(LeftClickAction)));
return ConfigPageInfo(
conf,
i18n("Docking Menu"),
i18n("Docking Menu Configuration"),
"kmenuedit"
);
}
AboutPageInfo RadioDocking::createAboutPage()
{
/* KAboutData aboutData("kradio",
NULL,
NULL,
I18N_NOOP("Docking Menu 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("Docking Menu"),
i18n("Docking Menu Plugin"),
"kmenuedit"
);*/
return AboutPageInfo();
}
void RadioDocking::buildContextMenu()
{
m_menu->clear();
m_pluginMenu = NULL;
m_recordingMenu = NULL;
m_titleID = m_menu->insertTitle ("title-dummy");
buildStationList();
m_alarmID = m_menu->insertTitle ("alarm-dummy");
noticeNextAlarmChanged(queryNextAlarm());
m_sleepID = m_menu->insertItem(SmallIcon("kradio_zzz"), "sleep-dummy",
this, TQT_SLOT(slotSleepCountdown()));
noticeCountdownStarted(queryCountdownEnd());
m_seekfwID = m_menu->insertItem(SmallIcon("forward"), i18n("Search Next Station"),
this, TQT_SLOT(slotSeekFwd()));
m_seekbwID = m_menu->insertItem(SmallIcon("back"), i18n("Search Previous Station"),
this, TQT_SLOT(slotSeekBkwd()));
// recording menu
buildRecordingMenu();
m_menu->insertItem(i18n("Recording"), m_recordingMenu);
m_powerID = m_menu->insertItem(SmallIcon("kradio_muteoff"), "power-dummy",
this, TQT_SLOT(slotPower()));
m_pauseID = m_menu->insertItem(SmallIcon("kradio_pause"), i18n("Pause Radio"),
this, TQT_SLOT(slotPause()));
noticePowerChanged(queryIsPowerOn());
m_menu->insertSeparator();
m_menu->insertItem(SmallIcon("kradio"), i18n("&About"), this, TQT_SLOT(slotShowAbout()));
// build list of widgets for hide/show items
m_pluginMenu = new KPopupMenu(m_menu);
if (m_manager) {
m_manager->addWidgetPluginMenuItems(m_pluginMenu, m_widgetPluginIDs);
m_menu->insertItem(SmallIcon("kradio_plugins"), i18n("Show/Hide Plugins"), m_pluginMenu);
}
m_menu->insertSeparator();
m_menu->insertItem( SmallIcon("exit"), i18n("&Quit" ), kapp, TQT_SLOT(quit()) );
noticeStationChanged(queryCurrentStation(), -1);
}
void RadioDocking::buildStationList()
{
m_stationMenuIDs.clear();
const RawStationList &sl = queryStations().all();
const RadioStation &crs = queryCurrentStation();
int k = 0;
TQStringList::iterator end = m_stationIDs.end();
for (TQStringList::iterator it = m_stationIDs.begin(); it != end; ++it) {
const RadioStation &rs = sl.stationWithID(*it);
if (rs.isValid()) {
++k;
TQString shortcut = k < 10 ? "&"+TQString().setNum(k) : k == 10 ? "1&0" : TQString().setNum(k);
TQString name = rs.longName().replace("&", "&&");
TQString item = shortcut + " " + name;
int id = m_menu->insertItem(item);
m_stationMenuIDs.push_back(id);
m_menu->setItemChecked (id, rs.compare(crs) == 0);
} else {
m_stationMenuIDs.push_back(-1);
}
}
}
void RadioDocking::slotSeekFwd()
{
ISeekRadio *seeker = dynamic_cast<ISeekRadio*>(queryActiveDevice());
if (seeker)
seeker->startSeekUp();
}
void RadioDocking::slotSeekBkwd()
{
ISeekRadio *seeker = dynamic_cast<ISeekRadio*>(queryActiveDevice());
if (seeker)
seeker->startSeekUp();
}
void RadioDocking::slotShowAbout()
{
if (m_manager) {
KDialogBase *d = m_manager->getAboutDialog();
if (d) d->show();
}
}
void RadioDocking::slotPower()
{
if (queryIsPowerOn()) {
sendPowerOff();
} else {
sendPowerOn();
}
}
void RadioDocking::slotPause()
{
if (queryIsPowerOn()) {
sendPausePlayback(queryCurrentSoundStreamID());
}
}
void RadioDocking::slotSleepCountdown()
{
if (queryCountdownEnd().isValid()) {
sendStopCountdown();
} else {
sendStartCountdown();
}
}
bool RadioDocking::noticeNextAlarmChanged(const Alarm *a)
{
TQDateTime d;
if (a) d = a->nextAlarm();
if (d.isValid())
m_menu->changeTitle (m_alarmID, i18n("next alarm: %1").arg(d.toString()));
else
m_menu->changeTitle (m_alarmID, i18n("<no alarm pending>"));
return true;
}
bool RadioDocking::noticeCountdownStarted(const TQDateTime &end)
{
if (end.isValid())
m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Stop Sleep Countdown (running until %1)").arg(end.toString()));
else
m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown"));
return true;
}
bool RadioDocking::noticeCountdownStopped()
{
m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown"));
return true;
}
bool RadioDocking::noticeCountdownZero()
{
m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown"));
return true;
}
bool RadioDocking::noticePowerChanged(bool on)
{
m_menu->changeItem(m_powerID, SmallIcon(on ? "kradio_muteon" : "kradio_muteoff"),
on ? i18n("Power Off") : i18n("Power On"));
m_menu->setItemEnabled(m_pauseID, on);
return true;
}
bool RadioDocking::noticeCountdownSecondsChanged(int /*n*/)
{
return false;
}
bool RadioDocking::noticeStationChanged (const RadioStation &rs, int /*idx*/)
{
TQString s = i18n("invalid station");
if (rs.isValid())
s = rs.longName();
TQToolTip::add(this, s);
m_menu->changeTitle (m_titleID, i18n("KRadio: %1").arg(s));
// FIXME: title does not change in opened popupmenu
TQValueList<int>::iterator iit = m_stationMenuIDs.begin();
TQValueList<int>::iterator end = m_stationMenuIDs.end();
TQStringList::iterator sit = m_stationIDs.begin();
for (; iit != end; ++iit, ++sit) {
if (*iit != -1) {
bool on = rs.stationID() == *sit;
m_menu->setItemChecked (*iit, on);
}
}
bool r = false;
SoundFormat sf;
queryIsRecordingRunning(queryCurrentSoundStreamID(), r, sf);
m_recordingMenu->setItemEnabled(m_recordingID, !r);
return true;
}
bool RadioDocking::noticeStationsChanged(const StationList &/*sl*/)
{
buildContextMenu();
return true;
}
void RadioDocking::mousePressEvent( TQMouseEvent *e )
{
KSystemTray::mousePressEvent(e);
switch ( e->button() ) {
case Qt::LeftButton:
switch (m_leftClickAction) {
case lcaShowHide :
ShowHideWidgetPlugins();
// FIXME: [mcamen] According the KDE usability guidelines a left
// click on the systray icon should show/hide the
// application window
// TODO: [mcamen] Use KSystemtray::toggleActive and friends once we
// depend on KDE 3.3
break;
case lcaPowerOnOff :
if (queryIsPowerOn())
sendPowerOff();
else
sendPowerOn();
break;
default:
break;
}
break;
default:
// nothing
break;
}
}
void RadioDocking::ShowHideWidgetPlugins()
{
// nothing in cache => hide everything
if (!m_widgetsShownCache.count()) {
for (TQMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) {
WidgetPluginBase *p = it.key();
if (p) {
bool visible = p->isAnywhereVisible();
TQString name = p->name();
logDebug(TQString("visibility of %1: %2").arg(name).arg(visible));
m_widgetsShownCache.insert(name, visible);
p->getWidget()->hide();
}
}
}
else {
TQMap<TQString, bool> tmpCache = m_widgetsShownCache;
int d = KWin::currentDesktop();
for (TQMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) {
WidgetPluginBase *p = it.key();
TQString name = p ? p->name() : TQString();
if (p && tmpCache.contains(name) && tmpCache[name]) {
p->showOnOrgDesktop();
}
}
m_widgetsShownCache.clear();
KWin::setCurrentDesktop(d);
}
}
void RadioDocking::slotMenuItemActivated(int id)
{
const StationList &sl = queryStations();
TQValueList<int>::iterator iit = m_stationMenuIDs.begin();
TQValueList<int>::iterator end = m_stationMenuIDs.end();
TQStringList::iterator sit = m_stationIDs.begin();
for (; iit != end; ++iit, ++sit) {
if (*iit == id) {
const RadioStation &rs = sl.stationWithID(*sit);
if (rs.isValid())
sendActivateStation(rs);
}
}
}
void RadioDocking::noticeWidgetPluginShown(WidgetPluginBase *b, bool shown)
{
if (!m_manager || !b || !m_widgetPluginIDs.contains(b))
return;
m_manager->updateWidgetPluginMenuItem(b, m_pluginMenu, m_widgetPluginIDs, shown);
if (shown)
m_widgetsShownCache.clear();
}
void RadioDocking::noticePluginsChanged(const PluginList &/*l*/)
{
buildContextMenu();
}
// ISoundStreamClient
bool RadioDocking::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);
if (id == queryCurrentSoundStreamID())
m_recordingMenu->setItemEnabled(m_recordingID, false);
setPixmap(BarIcon("kradio_plus_rec"));
return false; // this is only a "hook" that does not initiate the recording so don't say that we handled the event
}
bool RadioDocking::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);
if (id == queryCurrentSoundStreamID())
m_recordingMenu->setItemEnabled(m_recordingID, true);
setPixmap(BarIcon("kradio"));
return false;
}
void RadioDocking::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 RadioDocking::buildRecordingMenu()
{
TQMap<TQString, SoundStreamID> streams;
queryEnumerateSoundStreams(streams);
KPopupMenu *m = new KPopupMenu(m_menu);
m_recordingID = m->insertItem(SmallIcon("kradio_record"), i18n("Start Recording"),
POPUP_ID_START_RECORDING_DEFAULT);
TQObject::connect(m, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(slotRecordingMenu(int)));
SoundStreamID currentID = queryCurrentSoundStreamID();
TQMapIterator<TQString, SoundStreamID> end = streams.end();
for (TQMapIterator<TQString, SoundStreamID> it = streams.begin(); it != end; ++it) {
SoundStreamID id = *it;
TQString descr = it.key();
bool r = false;
SoundFormat sf;
queryIsRecordingRunning(id, r, sf);
if (r) {
int menu_id = m_NextRecordingMenuID++;
m->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);
if (id == currentID)
m_recordingMenu->setItemEnabled(m_recordingID, false);
}
}
m_recordingMenu = m;
}
bool RadioDocking::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;
}
void RadioDocking::setLeftClickAction(LeftClickAction action)
{
if (m_leftClickAction != action) {
m_leftClickAction = action;
emit sigLeftClickActionChanged(m_leftClickAction);
}
}
void RadioDocking::dragEnterEvent(TQDragEnterEvent* event)
{
bool a = StationDragObject::canDecode(event);
if (a)
IErrorLogClient::staticLogDebug("contentsDragEnterEvent accepted");
else
IErrorLogClient::staticLogDebug("contentsDragEnterEvent rejected");
event->accept(a);
}
void RadioDocking::dropEvent(TQDropEvent* event)
{
TQStringList list;
if ( StationDragObject::decode(event, list) ) {
TQStringList l = getStationSelection();
for (TQValueListConstIterator<TQString> it = list.begin(); it != list.end(); ++it)
if (!l.contains(*it))
l.append(*it);
setStationSelection(l);
}
}
#include "docking.moc"